]> git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxlwindow.cpp
wxlayout bug
[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 #ifdef __BORLANDC__
15 # pragma hdrstop
16 #endif
17
18
19 #include "Mpch.h"
20 #ifdef M_BASEDIR
21 # ifndef USE_PCH
22 # include "Mcommon.h"
23 # include "gui/wxMenuDefs.h"
24 # include "gui/wxMApp.h"
25 # endif // USE_PCH
26 # include "gui/wxlwindow.h"
27 # include "gui/wxlparser.h"
28 #else
29 # ifdef __WXMSW__
30 # include <windows.h>
31 # undef FindWindow
32 # undef GetCharWidth
33 # undef StartDoc
34 # endif
35
36 # include "wxlwindow.h"
37 # include "wxlparser.h"
38 #endif
39
40 #include <wx/clipbrd.h>
41 #include <wx/textctrl.h>
42 #include <wx/dataobj.h>
43
44 #include <ctype.h>
45
46 #ifdef WXLAYOUT_DEBUG
47 # define WXLO_DEBUG(x) wxLogDebug x
48 #else
49 # define WXLO_DEBUG(x)
50 #endif
51
52 /// offsets to put a nice frame around text
53 #define WXLO_XOFFSET 4
54 #define WXLO_YOFFSET 4
55
56 /// offset to the right and bottom for when to redraw scrollbars
57 #define WXLO_ROFFSET 20
58 #define WXLO_BOFFSET 20
59
60 BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
61 EVT_PAINT (wxLayoutWindow::OnPaint)
62 EVT_CHAR (wxLayoutWindow::OnChar)
63 EVT_KEY_UP (wxLayoutWindow::OnKeyUp)
64 EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick)
65 EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick)
66 EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick)
67 EVT_MOTION (wxLayoutWindow::OnMouseMove)
68 EVT_MENU_RANGE(WXLOWIN_MENU_FIRST, WXLOWIN_MENU_LAST, wxLayoutWindow::OnMenu)
69 EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus)
70 EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
71 END_EVENT_TABLE()
72
73 wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
74 : wxScrolledWindow(parent, -1, wxDefaultPosition, wxDefaultSize,
75 wxHSCROLL | wxVSCROLL | wxBORDER)
76
77 {
78 m_Editable = false;
79 m_doSendEvents = false;
80 m_ViewStartX = 0; m_ViewStartY = 0;
81 m_DoPopupMenu = true;
82 m_PopupMenu = MakeFormatMenu();
83 m_memDC = new wxMemoryDC;
84 m_bitmap = new wxBitmap(4,4);
85 m_bitmapSize = wxPoint(4,4);
86 m_llist = new wxLayoutList();
87 m_BGbitmap = NULL;
88 m_ScrollToCursor = false;
89 SetWrapMargin(0);
90 wxPoint max = m_llist->GetSize();
91 SetScrollbars(10, 20 /*lineHeight*/, max.x/10+1, max.y/20+1);
92 EnableScrolling(true,true);
93 m_maxx = max.x; m_maxy = max.y;
94 m_Selecting = false;
95 SetCursor(wxCURSOR_IBEAM);
96 SetDirty();
97 }
98
99 wxLayoutWindow::~wxLayoutWindow()
100 {
101 delete m_memDC; // deletes bitmap automatically (?)
102 delete m_bitmap;
103 delete m_llist;
104 delete m_PopupMenu;
105 SetBackgroundBitmap(NULL);
106 }
107
108 #ifdef __WXMSW__
109 long
110 wxLayoutWindow::MSWGetDlgCode()
111 {
112 // if we don't return this, we won't get OnChar() events for TABs and ENTER
113 return DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_WANTMESSAGE;
114 }
115 #endif //MSW
116
117 void
118 wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
119 {
120 wxPaintDC dc( this );
121 PrepareDC( dc );
122 SetFocus();
123
124 wxPoint findPos;
125 findPos.x = dc.DeviceToLogicalX(event.GetX());
126 findPos.y = dc.DeviceToLogicalY(event.GetY());
127
128 findPos.x -= WXLO_XOFFSET;
129 findPos.y -= WXLO_YOFFSET;
130
131 if(findPos.x < 0) findPos.x = 0;
132 if(findPos.y < 0) findPos.y = 0;
133
134 m_ClickPosition = wxPoint(event.GetX(), event.GetY());
135
136 wxPoint cursorPos;
137 bool found;
138 wxLayoutObject *obj = m_llist->FindObjectScreen(dc, findPos,
139 &cursorPos, &found);
140
141 //has the mouse only been moved?
142 if(eventId == WXLOWIN_MENU_MOUSEMOVE)
143 {
144 // found is only true if we are really over an object, not just
145 // behind it
146 if(found && obj && obj->GetUserData() != NULL)
147 {
148 if(!m_HandCursor)
149 SetCursor(wxCURSOR_HAND);
150 m_HandCursor = TRUE;
151 }
152 else
153 {
154 if(m_HandCursor)
155 SetCursor(wxCURSOR_IBEAM);
156 m_HandCursor = FALSE;
157 }
158 return;
159 }
160
161 // always move cursor to mouse click:
162 if(obj && eventId == WXLOWIN_MENU_LCLICK)
163 {
164 m_llist->MoveCursorTo(cursorPos);
165 ScrollToCursor();
166 Refresh(FALSE); // DoPaint suppresses flicker under GTK
167 }
168 if(!m_doSendEvents) // nothing to do
169 return;
170
171 // only do the menu if activated, editable and not on a clickable object
172 if(eventId == WXLOWIN_MENU_RCLICK
173 && IsEditable()
174 && (! obj || (obj && obj->GetUserData() == NULL))
175 )
176 {
177 PopupMenu(m_PopupMenu, m_ClickPosition.x, m_ClickPosition.y);
178 return;
179 }
180 // find the object at this position
181 if(obj)
182 {
183 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, eventId);
184 commandEvent.SetEventObject( this );
185 commandEvent.SetClientData((char *)obj);
186 GetEventHandler()->ProcessEvent(commandEvent);
187 }
188 }
189
190 /*
191 * Some simple keyboard handling.
192 */
193 void
194 wxLayoutWindow::OnChar(wxKeyEvent& event)
195 {
196 #ifdef WXLAYOUT_DEBUG
197 if(event.KeyCode() == WXK_F1)
198 {
199 m_llist->Debug();
200 return;
201 }
202 #endif
203
204 long keyCode = event.KeyCode();
205 if(m_Selecting && ! event.ShiftDown())
206 {
207 m_llist->EndSelection();
208 m_Selecting = false;
209 }
210 else
211 if(! m_Selecting && event.ShiftDown())
212 {
213 switch(keyCode)
214 {
215 case WXK_UP:
216 case WXK_DOWN:
217 case WXK_RIGHT:
218 case WXK_LEFT:
219 case WXK_PRIOR:
220 case WXK_NEXT:
221 case WXK_HOME:
222 case WXK_END:
223 m_Selecting = true;
224 m_llist->StartSelection();
225 break;
226 default:
227 ;
228 }
229 }
230
231 /* These two nested switches work like this:
232 The first one processes all non-editing keycodes, to move the
233 cursor, etc. It's default will process all keycodes causing
234 modifications to the buffer, but only if editing is allowed.
235 */
236 switch(keyCode)
237 {
238 case WXK_RIGHT:
239 m_llist->MoveCursorHorizontally(1);
240 break;
241 case WXK_LEFT:
242 m_llist->MoveCursorHorizontally(-1);
243 break;
244 case WXK_UP:
245 m_llist->MoveCursorVertically(-1);
246 break;
247 case WXK_DOWN:
248 m_llist->MoveCursorVertically(1);
249 break;
250 case WXK_PRIOR:
251 m_llist->MoveCursorVertically(-20);
252 break;
253 case WXK_NEXT:
254 m_llist->MoveCursorVertically(20);
255 break;
256 case WXK_HOME:
257 m_llist->MoveCursorToBeginOfLine();
258 break;
259 case WXK_END:
260 m_llist->MoveCursorToEndOfLine();
261 break;
262 default:
263 if(keyCode == 'c' && event.ControlDown())
264 Copy();
265 if( IsEditable() )
266 {
267 /* First, handle control keys */
268 if(event.ControlDown() && ! event.AltDown())
269 {
270 switch(keyCode)
271 {
272 case WXK_DELETE :
273 case 'd':
274 m_llist->Delete(1);
275 break;
276 case 'y':
277 m_llist->DeleteLines(1);
278 break;
279 case 'h': // like backspace
280 if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
281 break;
282 case 'u':
283 m_llist->DeleteToBeginOfLine();
284 break;
285 case 'k':
286 m_llist->DeleteToEndOfLine();
287 break;
288 case 'v':
289 Paste();
290 break;
291 #ifdef WXLAYOUT_DEBUG
292 case WXK_F1:
293 m_llist->SetFont(-1,-1,-1,-1,true); // underlined
294 break;
295 #endif
296 default:
297 ;
298 }
299 }
300 // ALT only:
301 else if( event.AltDown() && ! event.ControlDown() )
302 {
303 switch(keyCode)
304 {
305 case WXK_DELETE:
306 case 'd':
307 m_llist->DeleteWord();
308 break;
309 default:
310 ;
311 }
312 }
313 // no control keys:
314 else if ( ! event.AltDown() && ! event.ControlDown())
315 {
316 switch(keyCode)
317 {
318 case WXK_INSERT:
319 if(event.ShiftDown())
320 Paste();
321 break;
322 case WXK_DELETE :
323 m_llist->Delete(1);
324 break;
325 case WXK_BACK: // backspace
326 if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
327 break;
328 case WXK_RETURN:
329 if(m_WrapMargin > 0)
330 m_llist->WrapLine(m_WrapMargin);
331 m_llist->LineBreak();
332 break;
333 default:
334 if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
335 && (keyCode < 256 && keyCode >= 32)
336 )
337 {
338 wxString tmp;
339 tmp += keyCode;
340 if(m_WrapMargin > 0 && isspace(keyCode))
341 m_llist->WrapLine(m_WrapMargin);
342 m_llist->Insert(tmp);
343 }
344 break;
345 }
346 }
347 SetDirty();
348 SetModified();
349 }// if(IsEditable())
350 }// first switch()
351 ScrollToCursor();
352 wxRect r = *m_llist->GetUpdateRect();
353 DoPaint(&r);
354 }
355
356 void
357 wxLayoutWindow::OnKeyUp(wxKeyEvent& event)
358 {
359 if(event.KeyCode() == WXK_SHIFT && m_llist->IsSelecting())
360 m_llist->EndSelection();
361 event.Skip();
362 }
363
364
365 void
366 wxLayoutWindow::ScrollToCursor(void)
367 {
368 wxClientDC dc( this );
369 PrepareDC( dc );
370
371 int x0,y0,x1,y1, dx, dy;
372
373 // Calculate where the top of the visible area is:
374 ViewStart(&x0,&y0);
375 GetScrollPixelsPerUnit(&dx, &dy);
376 x0 *= dx; y0 *= dy;
377
378 // Get the size of the visible window:
379 GetClientSize(&x1,&y1);
380 wxASSERT(x1 > 0);
381 wxASSERT(y1 > 0);
382 // As we have the values anyway, use them to avoid unnecessary
383 // scrollbar updates.
384 if(x1 > m_maxx) m_maxx = x1;
385 if(y1 > m_maxy) m_maxy = y1;
386 /* Make sure that the scrollbars are at a position so that the
387 cursor is visible if we are editing. */
388 /** Scroll so that cursor is visible! */
389 WXLO_DEBUG(("m_ScrollToCursor = %d", (int) m_ScrollToCursor));
390 wxPoint cc = m_llist->GetCursorScreenPos(*m_memDC);
391 if(cc.x < x0 || cc.y < y0
392 || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10)) // (9*x)/10 == 90%
393 {
394 int nx, ny;
395 nx = cc.x - x1/2; if(nx < 0) nx = 0;
396 ny = cc.y - y1/2; if(ny < 0) ny = 0;
397 Scroll(nx/dx,ny/dy); // new view start
398 x0 = nx; y0 = ny;
399 m_ScrollToCursor = false; // avoid recursion
400 }
401 }
402
403 void
404 wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc)
405 {
406 wxRect region = GetUpdateRegion().GetBox();
407 InternalPaint(& region);
408 }
409
410 void
411 wxLayoutWindow::DoPaint(const wxRect *updateRect)
412 {
413 #ifdef __WXGTK__
414 InternalPaint(updateRect);
415 #else
416 Refresh(FALSE, updateRect); // Causes bad flicker under wxGTK!!!
417 #endif
418 }
419
420 void
421 wxLayoutWindow::InternalPaint(const wxRect *updateRect)
422 {
423 wxPaintDC dc( this );
424 PrepareDC( dc );
425
426 int x0,y0,x1,y1, dx, dy;
427
428 // Calculate where the top of the visible area is:
429 ViewStart(&x0,&y0);
430 GetScrollPixelsPerUnit(&dx, &dy);
431 x0 *= dx; y0 *= dy;
432
433 // Get the size of the visible window:
434 GetClientSize(&x1,&y1);
435 wxASSERT(x1 > 0);
436 wxASSERT(y1 > 0);
437 // As we have the values anyway, use them to avoid unnecessary
438 // scrollbar updates.
439 if(x1 > m_maxx) m_maxx = x1;
440 if(y1 > m_maxy) m_maxy = y1;
441
442 WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld",
443 updateRect->x, updateRect->y,
444 updateRect->x+updateRect->width,
445 updateRect->y+updateRect->height));
446
447 if(IsDirty())
448 ResizeScrollbars();
449
450 /* Check whether the window has grown, if so, we need to reallocate
451 the bitmap to be larger. */
452 if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
453 {
454 wxASSERT(m_bitmapSize.x > 0);
455 wxASSERT(m_bitmapSize.y > 0);
456
457 m_memDC->SelectObject(wxNullBitmap);
458 delete m_bitmap;
459 m_bitmapSize = wxPoint(x1,y1);
460 m_bitmap = new wxBitmap(x1,y1);
461 m_memDC->SelectObject(*m_bitmap);
462 }
463
464 m_memDC->SetDeviceOrigin(0,0);
465 m_memDC->SetBrush(wxBrush(m_llist->GetDefaults()->GetBGColour(),wxSOLID));
466 m_memDC->SetPen(wxPen(m_llist->GetDefaults()->GetBGColour(),
467 0,wxTRANSPARENT));
468 m_memDC->SetLogicalFunction(wxCOPY);
469
470 /* Either fill the background with the background bitmap, or clear
471 it. */
472 if(m_BGbitmap)
473 {
474 CoordType
475 y, x,
476 w = m_BGbitmap->GetWidth(),
477 h = m_BGbitmap->GetHeight();
478 for(y = 0; y < y1; y+=h)
479 for(x = 0; x < x1; x+=w)
480 m_memDC->DrawBitmap(*m_BGbitmap, x, y);
481 m_memDC->SetBackgroundMode(wxTRANSPARENT);
482 }
483 else
484 {
485 // clear the background: (must not be done if we use the update rectangle!)
486 m_memDC->SetBackgroundMode(wxSOLID);
487 m_memDC->DrawRectangle(0,0,x1, y1);
488 }
489
490
491 /* This is the important bit: we tell the list to draw itself: */
492 WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld",
493 updateRect->x, updateRect->y,
494 updateRect->x+updateRect->width,
495 updateRect->y+updateRect->height));
496
497 // Device origins on the memDC are suspect, we translate manually
498 // with the translate parameter of Draw().
499 wxPoint offset(-x0+WXLO_XOFFSET,-y0+WXLO_YOFFSET);
500 m_llist->Draw(*m_memDC,offset, y0, y0+y1);
501
502 // We start calculating a new update rect before drawing the
503 // cursor, so that the cursor coordinates get included in the next
504 // update rectangle (although they are drawn on the memDC, this is
505 // needed to erase it):
506 m_llist->InvalidateUpdateRect();
507 m_llist->DrawCursor(*m_memDC,
508 m_HaveFocus && IsEditable(), // draw a thick
509 // cursor for editable windows with focus
510 offset);
511
512 // Now copy everything to the screen:
513 #if 0
514 // This somehow doesn't work, but even the following bit with the
515 // whole rect at once is still a bit broken I think.
516 wxRegionIterator ri ( GetUpdateRegion() );
517 if(ri)
518 while(ri)
519 {
520 WXLO_DEBUG(("UpdateRegion: %ld,%ld, %ld,%ld",
521 ri.GetX(),ri.GetY(),ri.GetW(),ri.GetH()));
522 dc.Blit(x0+ri.GetX(),y0+ri.GetY(),ri.GetW(),ri.GetH(),
523 m_memDC,ri.GetX(),ri.GetY(),wxCOPY,FALSE);
524 ri++;
525 }
526 else
527 #endif
528 {
529 // FIXME: Trying to copy only the changed parts, but it does not seem
530 // to work:
531 // x0 = updateRect->x; y0 = updateRect->y;
532 // if(updateRect->height < y1)
533 // y1 = updateRect->height;
534 // y1 += WXLO_YOFFSET; //FIXME might not be needed
535 dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
536 }
537
538 ResetDirty();
539 m_ScrollToCursor = false;
540 }
541
542 // change the range and position of scrollbars
543 void
544 wxLayoutWindow::ResizeScrollbars(bool exact)
545 {
546 wxPoint max = m_llist->GetSize();
547
548 if(max.x > m_maxx || max.y > m_maxy
549 || max.x > m_maxx-WXLO_ROFFSET || max.y > m_maxy-WXLO_BOFFSET
550 || exact)
551 {
552 if(! exact)
553 {
554 // add an extra bit to the sizes to avoid future updates
555 max.x = max.x+WXLO_ROFFSET;
556 max.y = max.y+WXLO_BOFFSET;
557 }
558 ViewStart(&m_ViewStartX, &m_ViewStartY);
559 SetScrollbars(10, 20, max.x/10+1,max.y/20+1,m_ViewStartX,m_ViewStartY,true);
560 m_maxx = max.x; m_maxy = max.y;
561 }
562 }
563
564 void
565 wxLayoutWindow::Paste(void)
566 {
567 wxString text;
568 // Read some text
569 if (wxTheClipboard->Open())
570 {
571 wxTextDataObject data;
572 if (wxTheClipboard->IsSupported( data.GetFormat() ))
573 {
574 wxTheClipboard->GetData(&data);
575 text += data.GetText();
576 }
577 wxTheClipboard->Close();
578 }
579 #if 0
580 /* My attempt to get the primary selection, but it does not
581 work. :-( */
582 if(text.Length() == 0)
583 {
584 wxTextCtrl tmp_tctrl(this,-1);
585 tmp_tctrl.Paste();
586 text += tmp_tctrl.GetValue();
587 }
588 #endif
589 wxLayoutImportText( m_llist, text);
590 }
591
592 bool
593 wxLayoutWindow::Copy(void)
594 {
595 wxLayoutList *llist = m_llist->GetSelection();
596 if(! llist)
597 return FALSE;
598
599 wxString text;
600 wxLayoutExportObject *export;
601 wxLayoutExportStatus status(llist);
602 while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_TEXT)) != NULL)
603 {
604 if(export->type == WXLO_EXPORT_TEXT)
605 text << *(export->content.text);
606 delete export;
607 }
608 delete llist;
609
610 // Read some text
611 if (wxTheClipboard->Open())
612 {
613 wxTextDataObject *data = new wxTextDataObject( text );
614 bool rc = wxTheClipboard->SetData( data );
615 wxTheClipboard->Close();
616 return rc;
617 }
618 return FALSE;
619 }
620
621 wxMenu *
622 wxLayoutWindow::MakeFormatMenu()
623 {
624 wxMenu *m = new wxMenu(_("Layout Menu"));
625
626 m->Append(WXLOWIN_MENU_LARGER ,_("&Larger"),_("Switch to larger font."), false);
627 m->Append(WXLOWIN_MENU_SMALLER ,_("&Smaller"),_("Switch to smaller font."), false);
628 m->AppendSeparator();
629 m->Append(WXLOWIN_MENU_UNDERLINE_ON, _("&Underline on"),_("Activate underline mode."), false);
630 m->Append(WXLOWIN_MENU_UNDERLINE_OFF,_("&Underline off"),_("Deactivate underline mode."), false);
631 m->Append(WXLOWIN_MENU_BOLD_ON ,_("&Bold on"),_("Activate bold mode."), false);
632 m->Append(WXLOWIN_MENU_BOLD_OFF ,_("&Bold off"),_("Deactivate bold mode."), false);
633 m->Append(WXLOWIN_MENU_ITALICS_ON ,_("&Italics on"),_("Activate italics mode."), false);
634 m->Append(WXLOWIN_MENU_ITALICS_OFF ,_("&Italics off"),_("Deactivate italics mode."), false);
635 m->AppendSeparator();
636 m->Append(WXLOWIN_MENU_ROMAN ,_("&Roman"),_("Switch to roman font."), false);
637 m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Switch to typewriter font."), false);
638 m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Switch to sans serif font."), false);
639 return m;
640 }
641
642 void wxLayoutWindow::OnMenu(wxCommandEvent& event)
643 {
644 switch (event.GetId())
645 {
646 case WXLOWIN_MENU_LARGER:
647 m_llist->SetFontLarger(); break;
648 case WXLOWIN_MENU_SMALLER:
649 m_llist->SetFontSmaller(); break;
650 case WXLOWIN_MENU_UNDERLINE_ON:
651 m_llist->SetFontUnderline(true); break;
652 case WXLOWIN_MENU_UNDERLINE_OFF:
653 m_llist->SetFontUnderline(false); break;
654 case WXLOWIN_MENU_BOLD_ON:
655 m_llist->SetFontWeight(wxBOLD); break;
656 case WXLOWIN_MENU_BOLD_OFF:
657 m_llist->SetFontWeight(wxNORMAL); break;
658 case WXLOWIN_MENU_ITALICS_ON:
659 m_llist->SetFontStyle(wxITALIC); break;
660 case WXLOWIN_MENU_ITALICS_OFF:
661 m_llist->SetFontStyle(wxNORMAL); break;
662 case WXLOWIN_MENU_ROMAN:
663 m_llist->SetFontFamily(wxROMAN); break;
664 case WXLOWIN_MENU_TYPEWRITER:
665 m_llist->SetFontFamily(wxFIXED); break;
666 case WXLOWIN_MENU_SANSSERIF:
667 m_llist->SetFontFamily(wxSWISS); break;
668 }
669 }
670
671 void
672 wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
673 {
674 m_HaveFocus = true;
675 //FIXME: need argument DoPaint(); // to repaint the cursor
676 }
677
678 void
679 wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
680 {
681 m_HaveFocus = false;
682 //FIXME: need argument DoPaint(); // to repaint the cursor
683 }