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