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