]> git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxlwindow.cpp
093db74fa4ce1b8f052876e9e26f3dda5e4a1a42
[wxWidgets.git] / user / wxLayout / wxlwindow.cpp
1 /*-*- c++ -*-********************************************************
2 * wxLwindow.h : a scrolled Window for displaying/entering rich text*
3 * *
4 * (C) 1998, 1999 by Karsten Ballüder (Ballueder@usa.net) *
5 * *
6 * $Id$
7 *******************************************************************/
8
9 #ifdef __GNUG__
10 # pragma implementation "wxlwindow.h"
11 #endif
12
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 # pragma hdrstop
17 #endif
18
19 #include "Mpch.h"
20
21 #ifdef M_BASEDIR
22 # ifndef USE_PCH
23 # include "Mcommon.h"
24 # include "gui/wxMenuDefs.h"
25 # include "gui/wxMApp.h"
26 # endif // USE_PCH
27 # include "gui/wxlwindow.h"
28 # include "gui/wxlparser.h"
29 #else
30 # ifdef __WXMSW__
31 # include <windows.h>
32 # undef FindWindow
33 # undef GetCharWidth
34 # undef StartDoc
35 # endif
36
37 # include "wxlwindow.h"
38 # include "wxlparser.h"
39 #endif
40
41 #include <wx/clipbrd.h>
42 #include <wx/textctrl.h>
43 #include <wx/dataobj.h>
44
45 #ifdef WXLAYOUT_USE_CARET
46 # include <wx/caret.h>
47 #endif // WXLAYOUT_USE_CARET
48
49 #include <ctype.h>
50
51 #ifdef WXLAYOUT_DEBUG
52 # define WXLO_DEBUG(x) wxLogDebug x
53 #else
54 # define WXLO_DEBUG(x)
55 #endif
56
57 /// offsets to put a nice frame around text
58 #define WXLO_XOFFSET 4
59 #define WXLO_YOFFSET 4
60
61 /// offset to the right and bottom for when to redraw scrollbars
62 #define WXLO_ROFFSET 20
63 #define WXLO_BOFFSET 20
64
65 BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
66 EVT_PAINT (wxLayoutWindow::OnPaint)
67 EVT_CHAR (wxLayoutWindow::OnChar)
68 EVT_KEY_UP (wxLayoutWindow::OnKeyUp)
69 EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick)
70 EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick)
71 EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick)
72 EVT_MOTION (wxLayoutWindow::OnMouseMove)
73 EVT_MENU_RANGE(WXLOWIN_MENU_FIRST, WXLOWIN_MENU_LAST, wxLayoutWindow::OnMenu)
74 EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus)
75 EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
76 END_EVENT_TABLE()
77
78 wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
79 : wxScrolledWindow(parent, -1,
80 wxDefaultPosition, wxDefaultSize,
81 wxHSCROLL | wxVSCROLL | wxBORDER)
82
83 {
84 SetStatusBar(NULL); // don't use statusbar
85 m_Editable = false;
86 m_doSendEvents = false;
87 m_ViewStartX = 0; m_ViewStartY = 0;
88 m_DoPopupMenu = true;
89 m_PopupMenu = MakeFormatMenu();
90 m_memDC = new wxMemoryDC;
91 m_bitmap = new wxBitmap(4,4);
92 m_bitmapSize = wxPoint(4,4);
93 m_llist = new wxLayoutList();
94
95 m_BGbitmap = NULL;
96 m_ScrollToCursor = false;
97 SetWrapMargin(0);
98 wxPoint max = m_llist->GetSize();
99 SetScrollbars(10, 20 /*lineHeight*/, max.x/10+1, max.y/20+1);
100 EnableScrolling(true,true);
101 m_maxx = max.x; m_maxy = max.y;
102 m_Selecting = false;
103
104 #ifdef WXLAYOUT_USE_CARET
105 // FIXME cursor size shouldn't be hardcoded
106 wxCaret *caret = new wxCaret(this, 2, 20);
107 SetCaret(caret);
108 m_llist->SetCaret(caret);
109 caret->Show();
110 #endif // WXLAYOUT_USE_CARET
111
112 SetCursorVisibility(-1);
113 SetCursor(wxCURSOR_IBEAM);
114 SetDirty();
115 }
116
117 wxLayoutWindow::~wxLayoutWindow()
118 {
119 delete m_memDC; // deletes bitmap automatically (?)
120 delete m_bitmap;
121 delete m_llist;
122 delete m_PopupMenu;
123 SetBackgroundBitmap(NULL);
124 }
125
126 void
127 wxLayoutWindow::Clear(int family,
128 int size,
129 int style,
130 int weight,
131 int underline,
132 wxColour *fg,
133 wxColour *bg)
134 {
135 GetLayoutList()->Clear(family,size,style,weight,underline,fg,bg);
136 SetBackgroundColour(GetLayoutList()->GetDefaults()->GetBGColour());
137 ResizeScrollbars(true);
138 SetDirty();
139 SetModified(false);
140
141 DoPaint((wxRect *)NULL);
142 }
143
144 #ifdef __WXMSW__
145 long
146 wxLayoutWindow::MSWGetDlgCode()
147 {
148 // if we don't return this, we won't get OnChar() events for TABs and ENTER
149 return DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_WANTMESSAGE;
150 }
151 #endif //MSW
152
153 void
154 wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
155 {
156 wxPaintDC dc( this );
157 PrepareDC( dc );
158 SetFocus();
159
160 wxPoint findPos;
161 findPos.x = dc.DeviceToLogicalX(event.GetX());
162 findPos.y = dc.DeviceToLogicalY(event.GetY());
163
164 findPos.x -= WXLO_XOFFSET;
165 findPos.y -= WXLO_YOFFSET;
166
167 if(findPos.x < 0) findPos.x = 0;
168 if(findPos.y < 0) findPos.y = 0;
169
170 m_ClickPosition = wxPoint(event.GetX(), event.GetY());
171
172 wxPoint cursorPos;
173 bool found;
174 wxLayoutObject *obj = m_llist->FindObjectScreen(dc, findPos,
175 &cursorPos, &found);
176 wxLayoutObject::UserData *u = obj ? obj->GetUserData() : NULL;
177
178 //has the mouse only been moved?
179 if(eventId == WXLOWIN_MENU_MOUSEMOVE)
180 {
181 // found is only true if we are really over an object, not just
182 // behind it
183 if(found && u && ! m_Selecting)
184 {
185 if(!m_HandCursor)
186 SetCursor(wxCURSOR_HAND);
187 m_HandCursor = TRUE;
188 if(m_StatusBar && m_StatusFieldLabel != -1)
189 {
190 const wxString &label = u->GetLabel();
191 if(label.Length())
192 m_StatusBar->SetStatusText(label,
193 m_StatusFieldLabel);
194 }
195 }
196 else
197 {
198 if(m_HandCursor)
199 SetCursor(wxCURSOR_IBEAM);
200 m_HandCursor = FALSE;
201 if(m_StatusBar && m_StatusFieldLabel != -1)
202 m_StatusBar->SetStatusText("", m_StatusFieldLabel);
203 }
204 if(event.LeftIsDown())
205 {
206 if(! m_Selecting)
207 {
208 m_llist->StartSelection();
209 m_Selecting = true;
210 DoPaint(FALSE);
211 }
212 else
213 {
214 m_llist->ContinueSelection(cursorPos);
215 DoPaint(FALSE);
216 }
217 }
218 if(m_Selecting && ! event.LeftIsDown())
219 {
220 m_llist->EndSelection(cursorPos);
221 m_Selecting = false;
222 DoPaint(FALSE);
223 }
224 if(u) u->DecRef();
225 return;
226 }
227
228 // always move cursor to mouse click:
229 if(obj && eventId == WXLOWIN_MENU_LCLICK)
230 {
231 m_llist->MoveCursorTo(cursorPos);
232 if(m_CursorVisibility == -1)
233 m_CursorVisibility = 1;
234 ScrollToCursor();
235 DoPaint(FALSE); // DoPaint suppresses flicker under GTK
236 }
237
238 if(!m_doSendEvents) // nothing to do
239 {
240 if(u) u->DecRef();
241 return;
242 }
243
244 // only do the menu if activated, editable and not on a clickable object
245 if(eventId == WXLOWIN_MENU_RCLICK
246 && IsEditable()
247 && (! obj || u == NULL))
248 {
249 PopupMenu(m_PopupMenu, m_ClickPosition.x, m_ClickPosition.y);
250 if(u) u->DecRef();
251 return;
252 }
253
254 if(u) u->DecRef();
255 // find the object at this position
256 if(obj)
257 {
258 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, eventId);
259 commandEvent.SetEventObject( this );
260 commandEvent.SetClientData((char *)obj);
261 GetEventHandler()->ProcessEvent(commandEvent);
262 }
263 }
264
265 /*
266 * Some simple keyboard handling.
267 */
268 void
269 wxLayoutWindow::OnChar(wxKeyEvent& event)
270 {
271 int keyCode = event.KeyCode();
272
273 #ifdef WXLAYOUT_DEBUG
274 if(keyCode == WXK_F1)
275 {
276 m_llist->Debug();
277 return;
278 }
279 #endif
280
281 if(! m_Selecting && event.ShiftDown())
282 {
283 switch(keyCode)
284 {
285 case WXK_UP:
286 case WXK_DOWN:
287 case WXK_RIGHT:
288 case WXK_LEFT:
289 case WXK_PRIOR:
290 case WXK_NEXT:
291 case WXK_HOME:
292 case WXK_END:
293 m_Selecting = true;
294 m_llist->StartSelection();
295 break;
296 default:
297 ;
298 }
299 }
300
301 // If needed, make cursor visible:
302 if(m_CursorVisibility == -1)
303 m_CursorVisibility = 1;
304
305 /* These two nested switches work like this:
306 The first one processes all non-editing keycodes, to move the
307 cursor, etc. It's default will process all keycodes causing
308 modifications to the buffer, but only if editing is allowed.
309 */
310 switch(keyCode)
311 {
312 case WXK_RIGHT:
313 m_llist->MoveCursorHorizontally(1);
314 break;
315 case WXK_LEFT:
316 m_llist->MoveCursorHorizontally(-1);
317 break;
318 case WXK_UP:
319 m_llist->MoveCursorVertically(-1);
320 break;
321 case WXK_DOWN:
322 m_llist->MoveCursorVertically(1);
323 break;
324 case WXK_PRIOR:
325 m_llist->MoveCursorVertically(-20);
326 break;
327 case WXK_NEXT:
328 m_llist->MoveCursorVertically(20);
329 break;
330 case WXK_HOME:
331 m_llist->MoveCursorToBeginOfLine();
332 break;
333 case WXK_END:
334 m_llist->MoveCursorToEndOfLine();
335 break;
336 default:
337 if(keyCode == 'c' && event.ControlDown())
338 {
339 // this should work even in read-only mode
340 Copy();
341 }
342 if( IsEditable() )
343 {
344 /* First, handle control keys */
345 if(event.ControlDown() && ! event.AltDown())
346 {
347 switch(keyCode)
348 {
349 case WXK_INSERT:
350 Copy();
351 break;
352 case WXK_DELETE :
353 case 'd':
354 m_llist->Delete(1);
355 break;
356 case 'y':
357 m_llist->DeleteLines(1);
358 break;
359 case 'h': // like backspace
360 if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
361 break;
362 case 'u':
363 m_llist->DeleteToBeginOfLine();
364 break;
365 case 'k':
366 m_llist->DeleteToEndOfLine();
367 break;
368 case 'v':
369 Paste();
370 break;
371 case 'x':
372 Cut();
373 break;
374 #ifdef WXLAYOUT_DEBUG
375 case WXK_F1:
376 m_llist->SetFont(-1,-1,-1,-1,true); // underlined
377 break;
378 #endif
379 default:
380 ;
381 }
382 }
383 // ALT only:
384 else if( event.AltDown() && ! event.ControlDown() )
385 {
386 switch(keyCode)
387 {
388 case WXK_DELETE:
389 case 'd':
390 m_llist->DeleteWord();
391 break;
392 default:
393 ;
394 }
395 }
396 // no control keys:
397 else if ( ! event.AltDown() && ! event.ControlDown())
398 {
399 switch(keyCode)
400 {
401 case WXK_INSERT:
402 if(event.ShiftDown())
403 Paste();
404 break;
405 case WXK_DELETE :
406 if(event.ShiftDown())
407 Cut();
408 else
409 m_llist->Delete(1);
410 break;
411 case WXK_BACK: // backspace
412 if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
413 break;
414 case WXK_RETURN:
415 if(m_WrapMargin > 0)
416 m_llist->WrapLine(m_WrapMargin);
417 m_llist->LineBreak();
418 break;
419 default:
420 if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
421 && (keyCode < 256 && keyCode >= 32)
422 )
423 {
424 wxString tmp;
425 tmp += keyCode;
426 if(m_WrapMargin > 0 && isspace(keyCode))
427 m_llist->WrapLine(m_WrapMargin);
428 m_llist->Insert(tmp);
429 }
430 break;
431 }
432 }
433 SetDirty();
434 SetModified();
435 }// if(IsEditable())
436 }// first switch()
437 if(m_Selecting)
438 {
439 if(event.ShiftDown())
440 m_llist->ContinueSelection();
441 else
442 {
443 m_llist->EndSelection();
444 m_Selecting = false;
445 }
446 }
447
448 ScrollToCursor();
449 wxRect r = *m_llist->GetUpdateRect();
450 DoPaint(&r);
451 }
452
453 void
454 wxLayoutWindow::OnKeyUp(wxKeyEvent& event)
455 {
456 if(event.KeyCode() == WXK_SHIFT && m_llist->IsSelecting())
457 {
458 m_llist->EndSelection();
459 m_Selecting = false;
460 }
461 event.Skip();
462 }
463
464
465 void
466 wxLayoutWindow::ScrollToCursor(void)
467 {
468 wxClientDC dc( this );
469 PrepareDC( dc );
470
471 int x0,y0,x1,y1, dx, dy;
472
473 // Calculate where the top of the visible area is:
474 ViewStart(&x0,&y0);
475 GetScrollPixelsPerUnit(&dx, &dy);
476 x0 *= dx; y0 *= dy;
477
478 WXLO_DEBUG(("ScrollToCursor: ViewStart is %d/%d", x0, y0));
479
480 // Get the size of the visible window:
481 GetClientSize(&x1,&y1);
482 wxASSERT(x1 > 0);
483 wxASSERT(y1 > 0);
484 // As we have the values anyway, use them to avoid unnecessary
485 // scrollbar updates.
486 if(x1 > m_maxx) m_maxx = x1;
487 if(y1 > m_maxy) m_maxy = y1;
488 /* Make sure that the scrollbars are at a position so that the
489 cursor is visible if we are editing. */
490 /** Scroll so that cursor is visible! */
491 WXLO_DEBUG(("m_ScrollToCursor = %d", (int) m_ScrollToCursor));
492 wxPoint cc = m_llist->GetCursorScreenPos(*m_memDC);
493 if(cc.x < x0 || cc.y < y0
494 || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10)) // (9*x)/10 == 90%
495 {
496 int nx, ny;
497 nx = cc.x - x1/2; if(nx < 0) nx = 0;
498 ny = cc.y - y1/2; if(ny < 0) ny = 0;
499 Scroll(nx/dx,ny/dy); // new view start
500 x0 = nx; y0 = ny;
501 m_ScrollToCursor = false; // avoid recursion
502 }
503 }
504
505 void
506 wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc)
507 {
508 wxRect region = GetUpdateRegion().GetBox();
509 InternalPaint(& region);
510 }
511
512 void
513 wxLayoutWindow::DoPaint(const wxRect *updateRect)
514 {
515 #ifdef __WXGTK__
516 InternalPaint(updateRect);
517 #else
518 Refresh(FALSE, updateRect); // Causes bad flicker under wxGTK!!!
519 #endif
520 }
521
522 void
523 wxLayoutWindow::InternalPaint(const wxRect *updateRect)
524 {
525 wxPaintDC dc( this );
526 PrepareDC( dc );
527
528 #ifdef WXLAYOUT_USE_CARET
529 // hide the caret before drawing anything
530 GetCaret()->Hide();
531 #endif // WXLAYOUT_USE_CARET
532
533 int x0,y0,x1,y1, dx, dy;
534
535 // Calculate where the top of the visible area is:
536 ViewStart(&x0,&y0);
537 GetScrollPixelsPerUnit(&dx, &dy);
538 x0 *= dx; y0 *= dy;
539
540 // Get the size of the visible window:
541 GetClientSize(&x1,&y1);
542 wxASSERT(x1 > 0);
543 wxASSERT(y1 > 0);
544 // As we have the values anyway, use them to avoid unnecessary
545 // scrollbar updates.
546 if(x1 > m_maxx) m_maxx = x1;
547 if(y1 > m_maxy) m_maxy = y1;
548
549
550 if(updateRect)
551 {
552 WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld",
553 updateRect->x, updateRect->y,
554 updateRect->x+updateRect->width,
555 updateRect->y+updateRect->height));
556 }
557 if(IsDirty())
558 {
559 m_llist->Layout(dc);
560 ResizeScrollbars();
561 }
562 /* Check whether the window has grown, if so, we need to reallocate
563 the bitmap to be larger. */
564 if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
565 {
566 wxASSERT(m_bitmapSize.x > 0);
567 wxASSERT(m_bitmapSize.y > 0);
568
569 m_memDC->SelectObject(wxNullBitmap);
570 delete m_bitmap;
571 m_bitmapSize = wxPoint(x1,y1);
572 m_bitmap = new wxBitmap(x1,y1);
573 m_memDC->SelectObject(*m_bitmap);
574 }
575
576 m_memDC->SetDeviceOrigin(0,0);
577 m_memDC->SetBrush(wxBrush(m_llist->GetDefaults()->GetBGColour(),wxSOLID));
578 m_memDC->SetPen(wxPen(m_llist->GetDefaults()->GetBGColour(),
579 0,wxTRANSPARENT));
580 m_memDC->SetLogicalFunction(wxCOPY);
581
582 /* Either fill the background with the background bitmap, or clear
583 it. */
584 if(m_BGbitmap)
585 {
586 CoordType
587 y, x,
588 w = m_BGbitmap->GetWidth(),
589 h = m_BGbitmap->GetHeight();
590 for(y = 0; y < y1; y+=h)
591 for(x = 0; x < x1; x+=w)
592 m_memDC->DrawBitmap(*m_BGbitmap, x, y);
593 m_memDC->SetBackgroundMode(wxTRANSPARENT);
594 }
595 else
596 {
597 // clear the background: (must not be done if we use the update rectangle!)
598 m_memDC->SetBackgroundMode(wxSOLID);
599 m_memDC->DrawRectangle(0,0,x1, y1);
600 }
601
602
603 /* This is the important bit: we tell the list to draw itself: */
604 #if WXLO_DEBUG_URECT
605 if(updateRect)
606 {
607 WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld",
608 updateRect->x, updateRect->y,
609 updateRect->x+updateRect->width,
610 updateRect->y+updateRect->height));
611 }
612 #endif
613
614 // Device origins on the memDC are suspect, we translate manually
615 // with the translate parameter of Draw().
616 wxPoint offset(-x0+WXLO_XOFFSET,-y0+WXLO_YOFFSET);
617 m_llist->Draw(*m_memDC,offset, y0, y0+y1);
618
619 // We start calculating a new update rect before drawing the
620 // cursor, so that the cursor coordinates get included in the next
621 // update rectangle (although they are drawn on the memDC, this is
622 // needed to erase it):
623 m_llist->InvalidateUpdateRect();
624 if(m_CursorVisibility != 0)
625 m_llist->DrawCursor(*m_memDC,
626 m_HaveFocus && IsEditable(), // draw a thick
627 // cursor for editable windows with focus
628 offset);
629
630 // Now copy everything to the screen:
631 #if 0
632 // This somehow doesn't work, but even the following bit with the
633 // whole rect at once is still a bit broken I think.
634 wxRegionIterator ri ( GetUpdateRegion() );
635 if(ri)
636 while(ri)
637 {
638 WXLO_DEBUG(("UpdateRegion: %ld,%ld, %ld,%ld",
639 ri.GetX(),ri.GetY(),ri.GetW(),ri.GetH()));
640 dc.Blit(x0+ri.GetX(),y0+ri.GetY(),ri.GetW(),ri.GetH(),
641 m_memDC,ri.GetX(),ri.GetY(),wxCOPY,FALSE);
642 ri++;
643 }
644 else
645 #endif
646 {
647 // FIXME: Trying to copy only the changed parts, but it does not seem
648 // to work:
649 // x0 = updateRect->x; y0 = updateRect->y;
650 // if(updateRect->height < y1)
651 // y1 = updateRect->height;
652 // y1 += WXLO_YOFFSET; //FIXME might not be needed
653 dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
654 }
655
656 #ifdef WXLAYOUT_USE_CARET
657 // show the caret back after everything is redrawn
658 m_caret->Show();
659 #endif // WXLAYOUT_USE_CARET
660
661 ResetDirty();
662 m_ScrollToCursor = false;
663 if(m_StatusBar && m_StatusFieldCursor != -1)
664 {
665 wxString label;
666 label.Printf(_("Ln:%d Col:%d"),
667 m_llist->GetCursorPos().y+1,
668 m_llist->GetCursorPos().x+1);
669 m_StatusBar->SetStatusText(label, m_StatusFieldCursor);
670 }
671 }
672
673 // change the range and position of scrollbars
674 void
675 wxLayoutWindow::ResizeScrollbars(bool exact)
676 {
677 wxPoint max = m_llist->GetSize();
678
679 WXLO_DEBUG(("ResizeScrollbars: GetSize: %ld, %ld", (long int)max.x,
680 (long int) max.y));
681 if(max.x > m_maxx || max.y > m_maxy
682 || max.x > m_maxx-WXLO_ROFFSET || max.y > m_maxy-WXLO_BOFFSET
683 || exact)
684 {
685 if(! exact)
686 {
687 // add an extra bit to the sizes to avoid future updates
688 max.x = max.x+WXLO_ROFFSET;
689 max.y = max.y+WXLO_BOFFSET;
690 }
691 ViewStart(&m_ViewStartX, &m_ViewStartY);
692 SetScrollbars(10, 20, max.x/10+1,max.y/20+1,m_ViewStartX,m_ViewStartY,true);
693 m_maxx = max.x; m_maxy = max.y;
694 }
695 }
696
697 void
698 wxLayoutWindow::Paste(void)
699 {
700 // Read some text
701 if (wxTheClipboard->Open())
702 {
703 #if wxUSE_PRIVATE_CLIPBOARD_FORMAT
704 wxLayoutDataObject wxldo;
705 if (wxTheClipboard->IsSupported( wxldo.GetFormat() ))
706 {
707 wxTheClipboard->GetData(&wxldo);
708 {
709 }
710 //FIXME: missing functionality m_llist->Insert(wxldo.GetList());
711 }
712 else
713 #endif
714 {
715 wxTextDataObject data;
716 if (wxTheClipboard->IsSupported( data.GetFormat() ))
717 {
718 wxTheClipboard->GetData(&data);
719 wxString text = data.GetText();
720 wxLayoutImportText( m_llist, text);
721 }
722 }
723 wxTheClipboard->Close();
724 }
725
726 #if 0
727 /* My attempt to get the primary selection, but it does not
728 work. :-( */
729 if(text.Length() == 0)
730 {
731 wxTextCtrl tmp_tctrl(this,-1);
732 tmp_tctrl.Paste();
733 text += tmp_tctrl.GetValue();
734 }
735 #endif
736 }
737
738 bool
739 wxLayoutWindow::Copy(bool invalidate)
740 {
741 // Calling GetSelection() will automatically do an EndSelection()
742 // on the list, but we need to take a note of it, too:
743 if(m_Selecting)
744 {
745 m_Selecting = false;
746 m_llist->EndSelection();
747 }
748
749 wxLayoutDataObject wldo;
750 wxLayoutList *llist = m_llist->GetSelection(&wldo, invalidate);
751 if(! llist)
752 return FALSE;
753 // Export selection as text:
754 wxString text;
755 wxLayoutExportObject *export;
756 wxLayoutExportStatus status(llist);
757 while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_TEXT)) != NULL)
758 {
759 if(export->type == WXLO_EXPORT_TEXT)
760 text << *(export->content.text);
761 delete export;
762 }
763 delete llist;
764
765 // The exporter always appends a newline, so we chop it off if it
766 // is there:
767 {
768 size_t len = text.Length();
769 if(len > 2 && text[len-2] == '\r') // Windows
770 text = text.Mid(0,len-2);
771 else if(len > 1 && text[len-1] == '\n')
772 text = text.Mid(0,len-1);
773 }
774
775
776 if (wxTheClipboard->Open())
777 {
778 wxTextDataObject *data = new wxTextDataObject( text );
779 bool rc = wxTheClipboard->SetData( data );
780 #if wxUSE_PRIVATE_CLIPBOARD_FORMAT
781 rc |= wxTheClipboard->AddData( &wldo );
782 #endif
783 wxTheClipboard->Close();
784 return rc;
785 }
786
787 return FALSE;
788 }
789
790 bool
791 wxLayoutWindow::Cut(void)
792 {
793 if(Copy(false)) // do not invalidate selection after copy
794 {
795 m_llist->DeleteSelection();
796 return TRUE;
797 }
798 else
799 return FALSE;
800 }
801 bool
802 wxLayoutWindow::Find(const wxString &needle,
803 wxPoint * fromWhere)
804 {
805 wxPoint found;
806
807 if(fromWhere == NULL)
808 found = m_llist->FindText(needle, m_llist->GetCursorPos());
809 else
810 found = m_llist->FindText(needle, *fromWhere);
811 if(found.x != -1)
812 {
813 if(fromWhere)
814 {
815 *fromWhere = found;
816 fromWhere->x ++;
817 }
818 m_llist->MoveCursorTo(found);
819 ScrollToCursor();
820 return true;
821 }
822 return false;
823 }
824
825 wxMenu *
826 wxLayoutWindow::MakeFormatMenu()
827 {
828 wxMenu *m = new wxMenu(_("Layout Menu"));
829
830 m->Append(WXLOWIN_MENU_LARGER ,_("&Larger"),_("Switch to larger font."), false);
831 m->Append(WXLOWIN_MENU_SMALLER ,_("&Smaller"),_("Switch to smaller font."), false);
832 m->AppendSeparator();
833 m->Append(WXLOWIN_MENU_UNDERLINE_ON, _("&Underline on"),_("Activate underline mode."), false);
834 m->Append(WXLOWIN_MENU_UNDERLINE_OFF,_("&Underline off"),_("Deactivate underline mode."), false);
835 m->Append(WXLOWIN_MENU_BOLD_ON ,_("&Bold on"),_("Activate bold mode."), false);
836 m->Append(WXLOWIN_MENU_BOLD_OFF ,_("&Bold off"),_("Deactivate bold mode."), false);
837 m->Append(WXLOWIN_MENU_ITALICS_ON ,_("&Italics on"),_("Activate italics mode."), false);
838 m->Append(WXLOWIN_MENU_ITALICS_OFF ,_("&Italics off"),_("Deactivate italics mode."), false);
839 m->AppendSeparator();
840 m->Append(WXLOWIN_MENU_ROMAN ,_("&Roman"),_("Switch to roman font."), false);
841 m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Switch to typewriter font."), false);
842 m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Switch to sans serif font."), false);
843 return m;
844 }
845
846 void wxLayoutWindow::OnMenu(wxCommandEvent& event)
847 {
848 switch (event.GetId())
849 {
850 case WXLOWIN_MENU_LARGER:
851 m_llist->SetFontLarger(); break;
852 case WXLOWIN_MENU_SMALLER:
853 m_llist->SetFontSmaller(); break;
854 case WXLOWIN_MENU_UNDERLINE_ON:
855 m_llist->SetFontUnderline(true); break;
856 case WXLOWIN_MENU_UNDERLINE_OFF:
857 m_llist->SetFontUnderline(false); break;
858 case WXLOWIN_MENU_BOLD_ON:
859 m_llist->SetFontWeight(wxBOLD); break;
860 case WXLOWIN_MENU_BOLD_OFF:
861 m_llist->SetFontWeight(wxNORMAL); break;
862 case WXLOWIN_MENU_ITALICS_ON:
863 m_llist->SetFontStyle(wxITALIC); break;
864 case WXLOWIN_MENU_ITALICS_OFF:
865 m_llist->SetFontStyle(wxNORMAL); break;
866 case WXLOWIN_MENU_ROMAN:
867 m_llist->SetFontFamily(wxROMAN); break;
868 case WXLOWIN_MENU_TYPEWRITER:
869 m_llist->SetFontFamily(wxFIXED); break;
870 case WXLOWIN_MENU_SANSSERIF:
871 m_llist->SetFontFamily(wxSWISS); break;
872 }
873 }
874
875 void
876 wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
877 {
878 m_HaveFocus = true;
879 //FIXME: need argument DoPaint(); // to repaint the cursor
880 }
881
882 void
883 wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
884 {
885 m_HaveFocus = false;
886 //FIXME: need argument DoPaint(); // to repaint the cursor
887 }