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