1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/richtext/richtextctrl.cpp 
   3 // Purpose:     A rich edit control 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  21 #include "wx/richtext/richtextctrl.h" 
  22 #include "wx/richtext/richtextstyles.h" 
  26     #include "wx/settings.h" 
  30 #include "wx/textfile.h" 
  32 #include "wx/filename.h" 
  33 #include "wx/dcbuffer.h" 
  34 #include "wx/arrimpl.cpp" 
  35 #include "wx/fontenum.h" 
  38 #if defined (__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__) 
  39 #define wxHAVE_PRIMARY_SELECTION 1 
  41 #define wxHAVE_PRIMARY_SELECTION 0 
  44 #if wxUSE_CLIPBOARD && wxHAVE_PRIMARY_SELECTION 
  45 #include "wx/clipbrd.h" 
  48 // DLL options compatibility check: 
  50 WX_CHECK_BUILD_OPTIONS("wxRichTextCtrl") 
  52 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
, wxRichTextEvent 
); 
  53 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
, wxRichTextEvent 
); 
  54 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
, wxRichTextEvent 
); 
  55 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
, wxRichTextEvent 
); 
  56 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_RETURN
, wxRichTextEvent 
); 
  57 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CHARACTER
, wxRichTextEvent 
); 
  58 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_DELETE
, wxRichTextEvent 
); 
  60 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING
, wxRichTextEvent 
); 
  61 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED
, wxRichTextEvent 
); 
  62 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING
, wxRichTextEvent 
); 
  63 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED
, wxRichTextEvent 
); 
  65 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED
, wxRichTextEvent 
); 
  66 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED
, wxRichTextEvent 
); 
  67 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED
, wxRichTextEvent 
); 
  68 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_PROPERTIES_CHANGED
, wxRichTextEvent 
); 
  69 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED
, wxRichTextEvent 
); 
  70 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_BUFFER_RESET
, wxRichTextEvent 
); 
  71 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_FOCUS_OBJECT_CHANGED
, wxRichTextEvent 
); 
  73 #if wxRICHTEXT_USE_OWN_CARET 
  78  * This implements a non-flashing cursor in case there 
  79  * are platform-specific problems with the generic caret. 
  80  * wxRICHTEXT_USE_OWN_CARET is set in richtextbuffer.h. 
  83 class wxRichTextCaret
; 
  84 class wxRichTextCaretTimer
: public wxTimer
 
  87     wxRichTextCaretTimer(wxRichTextCaret
* caret
) 
  91     virtual void Notify(); 
  92     wxRichTextCaret
* m_caret
; 
  95 class wxRichTextCaret
: public wxCaret
 
 100         // default - use Create() 
 101     wxRichTextCaret(): m_timer(this)  { Init(); } 
 102         // creates a block caret associated with the given window 
 103     wxRichTextCaret(wxRichTextCtrl 
*window
, int width
, int height
) 
 104         : wxCaret(window
, width
, height
), m_timer(this) { Init(); m_richTextCtrl 
= window
; } 
 105     wxRichTextCaret(wxRichTextCtrl 
*window
, const wxSize
& size
) 
 106         : wxCaret(window
, size
), m_timer(this) { Init(); m_richTextCtrl 
= window
; } 
 108     virtual ~wxRichTextCaret(); 
 113     // called by wxWindow (not using the event tables) 
 114     virtual void OnSetFocus(); 
 115     virtual void OnKillFocus(); 
 117     // draw the caret on the given DC 
 118     void DoDraw(wxDC 
*dc
); 
 120     // get the visible count 
 121     int GetVisibleCount() const { return m_countVisible
; } 
 123     // delay repositioning 
 124     bool GetNeedsUpdate() const { return m_needsUpdate
; } 
 125     void SetNeedsUpdate(bool needsUpdate 
= true ) { m_needsUpdate 
= needsUpdate
; } 
 129     bool GetRefreshEnabled() const { return m_refreshEnabled
; } 
 130     void EnableRefresh(bool b
) { m_refreshEnabled 
= b
; } 
 133     virtual void DoShow(); 
 134     virtual void DoHide(); 
 135     virtual void DoMove(); 
 136     virtual void DoSize(); 
 146     bool          m_hasFocus
;       // true => our window has focus 
 147     bool          m_needsUpdate
;    // must be repositioned 
 149     wxRichTextCaretTimer m_timer
; 
 150     wxRichTextCtrl
* m_richTextCtrl
; 
 151     bool          m_refreshEnabled
; 
 155 IMPLEMENT_DYNAMIC_CLASS( wxRichTextCtrl
, wxControl 
) 
 157 IMPLEMENT_DYNAMIC_CLASS( wxRichTextEvent
, wxNotifyEvent 
) 
 159 BEGIN_EVENT_TABLE( wxRichTextCtrl
, wxControl 
) 
 160     EVT_PAINT(wxRichTextCtrl::OnPaint
) 
 161     EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground
) 
 162     EVT_IDLE(wxRichTextCtrl::OnIdle
) 
 163     EVT_SCROLLWIN(wxRichTextCtrl::OnScroll
) 
 164     EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick
) 
 165     EVT_MOTION(wxRichTextCtrl::OnMoveMouse
) 
 166     EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp
) 
 167     EVT_RIGHT_DOWN(wxRichTextCtrl::OnRightClick
) 
 168     EVT_MIDDLE_DOWN(wxRichTextCtrl::OnMiddleClick
) 
 169     EVT_LEFT_DCLICK(wxRichTextCtrl::OnLeftDClick
) 
 170     EVT_CHAR(wxRichTextCtrl::OnChar
) 
 171     EVT_KEY_DOWN(wxRichTextCtrl::OnChar
) 
 172     EVT_SIZE(wxRichTextCtrl::OnSize
) 
 173     EVT_SET_FOCUS(wxRichTextCtrl::OnSetFocus
) 
 174     EVT_KILL_FOCUS(wxRichTextCtrl::OnKillFocus
) 
 175     EVT_MOUSE_CAPTURE_LOST(wxRichTextCtrl::OnCaptureLost
) 
 176     EVT_CONTEXT_MENU(wxRichTextCtrl::OnContextMenu
) 
 177     EVT_SYS_COLOUR_CHANGED(wxRichTextCtrl::OnSysColourChanged
) 
 179     EVT_MENU(wxID_UNDO
, wxRichTextCtrl::OnUndo
) 
 180     EVT_UPDATE_UI(wxID_UNDO
, wxRichTextCtrl::OnUpdateUndo
) 
 182     EVT_MENU(wxID_REDO
, wxRichTextCtrl::OnRedo
) 
 183     EVT_UPDATE_UI(wxID_REDO
, wxRichTextCtrl::OnUpdateRedo
) 
 185     EVT_MENU(wxID_COPY
, wxRichTextCtrl::OnCopy
) 
 186     EVT_UPDATE_UI(wxID_COPY
, wxRichTextCtrl::OnUpdateCopy
) 
 188     EVT_MENU(wxID_PASTE
, wxRichTextCtrl::OnPaste
) 
 189     EVT_UPDATE_UI(wxID_PASTE
, wxRichTextCtrl::OnUpdatePaste
) 
 191     EVT_MENU(wxID_CUT
, wxRichTextCtrl::OnCut
) 
 192     EVT_UPDATE_UI(wxID_CUT
, wxRichTextCtrl::OnUpdateCut
) 
 194     EVT_MENU(wxID_CLEAR
, wxRichTextCtrl::OnClear
) 
 195     EVT_UPDATE_UI(wxID_CLEAR
, wxRichTextCtrl::OnUpdateClear
) 
 197     EVT_MENU(wxID_SELECTALL
, wxRichTextCtrl::OnSelectAll
) 
 198     EVT_UPDATE_UI(wxID_SELECTALL
, wxRichTextCtrl::OnUpdateSelectAll
) 
 200     EVT_MENU(wxID_RICHTEXT_PROPERTIES1
, wxRichTextCtrl::OnProperties
) 
 201     EVT_UPDATE_UI(wxID_RICHTEXT_PROPERTIES1
, wxRichTextCtrl::OnUpdateProperties
) 
 203     EVT_MENU(wxID_RICHTEXT_PROPERTIES2
, wxRichTextCtrl::OnProperties
) 
 204     EVT_UPDATE_UI(wxID_RICHTEXT_PROPERTIES2
, wxRichTextCtrl::OnUpdateProperties
) 
 206     EVT_MENU(wxID_RICHTEXT_PROPERTIES3
, wxRichTextCtrl::OnProperties
) 
 207     EVT_UPDATE_UI(wxID_RICHTEXT_PROPERTIES3
, wxRichTextCtrl::OnUpdateProperties
) 
 215 wxArrayString 
wxRichTextCtrl::sm_availableFontNames
; 
 217 wxRichTextCtrl::wxRichTextCtrl() 
 218               : wxScrollHelper(this) 
 223 wxRichTextCtrl::wxRichTextCtrl(wxWindow
* parent
, 
 225                                const wxString
& value
, 
 229                                const wxValidator
& validator
, 
 230                                const wxString
& name
) 
 231               : wxScrollHelper(this) 
 234     Create(parent
, id
, value
, pos
, size
, style
, validator
, name
); 
 238 bool wxRichTextCtrl::Create( wxWindow
* parent
, wxWindowID id
, const wxString
& value
, const wxPoint
& pos
, const wxSize
& size
, long style
, 
 239                              const wxValidator
& validator
, const wxString
& name
) 
 243     if (!wxControl::Create(parent
, id
, pos
, size
, 
 244                            style
|wxFULL_REPAINT_ON_RESIZE
, 
 248     if (!GetFont().IsOk()) 
 250         SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 253     // No physical scrolling, so we can preserve margins 
 254     EnableScrolling(false, false); 
 256     if (style 
& wxTE_READONLY
) 
 259     // The base attributes must all have default values 
 260     wxRichTextAttr attributes
; 
 261     attributes
.SetFont(GetFont()); 
 262     attributes
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
 263     attributes
.SetAlignment(wxTEXT_ALIGNMENT_LEFT
); 
 264     attributes
.SetLineSpacing(10); 
 265     attributes
.SetParagraphSpacingAfter(10); 
 266     attributes
.SetParagraphSpacingBefore(0); 
 268     SetBasicStyle(attributes
); 
 271     SetMargins(margin
, margin
); 
 273     // The default attributes will be merged with base attributes, so 
 274     // can be empty to begin with 
 275     wxRichTextAttr defaultAttributes
; 
 276     SetDefaultStyle(defaultAttributes
); 
 278     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 279     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 282     GetBuffer().SetRichTextCtrl(this); 
 284 #if wxRICHTEXT_USE_OWN_CARET 
 285     SetCaret(new wxRichTextCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 287     SetCaret(new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 290     // Tell the sizers to use the given or best size 
 291     SetInitialSize(size
); 
 293 #if wxRICHTEXT_BUFFERED_PAINTING 
 295     RecreateBuffer(size
); 
 298     m_textCursor 
= wxCursor(wxCURSOR_IBEAM
); 
 299     m_urlCursor 
= wxCursor(wxCURSOR_HAND
); 
 301     SetCursor(m_textCursor
); 
 303     if (!value
.IsEmpty()) 
 306     GetBuffer().AddEventHandler(this); 
 309     wxAcceleratorEntry entries
[6]; 
 311     entries
[0].Set(wxACCEL_CTRL
,   (int) 'C',       wxID_COPY
); 
 312     entries
[1].Set(wxACCEL_CTRL
,   (int) 'X',       wxID_CUT
); 
 313     entries
[2].Set(wxACCEL_CTRL
,   (int) 'V',       wxID_PASTE
); 
 314     entries
[3].Set(wxACCEL_CTRL
,   (int) 'A',       wxID_SELECTALL
); 
 315     entries
[4].Set(wxACCEL_CTRL
,   (int) 'Z',       wxID_UNDO
); 
 316     entries
[5].Set(wxACCEL_CTRL
,   (int) 'Y',       wxID_REDO
); 
 318     wxAcceleratorTable 
accel(6, entries
); 
 319     SetAcceleratorTable(accel
); 
 321     m_contextMenu 
= new wxMenu
; 
 322     m_contextMenu
->Append(wxID_UNDO
, _("&Undo")); 
 323     m_contextMenu
->Append(wxID_REDO
, _("&Redo")); 
 324     m_contextMenu
->AppendSeparator(); 
 325     m_contextMenu
->Append(wxID_CUT
, _("Cu&t")); 
 326     m_contextMenu
->Append(wxID_COPY
, _("&Copy")); 
 327     m_contextMenu
->Append(wxID_PASTE
, _("&Paste")); 
 328     m_contextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
 329     m_contextMenu
->AppendSeparator(); 
 330     m_contextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
 331     m_contextMenu
->AppendSeparator(); 
 332     m_contextMenu
->Append(wxID_RICHTEXT_PROPERTIES1
, _("&Properties")); 
 334 #if wxUSE_DRAG_AND_DROP 
 335     SetDropTarget(new wxRichTextDropTarget(this)); 
 341 wxRichTextCtrl::~wxRichTextCtrl() 
 343     SetFocusObject(& GetBuffer(), false); 
 344     GetBuffer().RemoveEventHandler(this); 
 346     delete m_contextMenu
; 
 349 /// Member initialisation 
 350 void wxRichTextCtrl::Init() 
 352     m_contextMenu 
= NULL
; 
 354     m_caretPosition 
= -1; 
 355     m_selectionAnchor 
= -2; 
 356     m_selectionAnchorObject 
= NULL
; 
 357     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
 359     m_verticalScrollbarEnabled 
= true; 
 360     m_caretAtLineStart 
= false; 
 362 #if wxUSE_DRAG_AND_DROP 
 365     m_fullLayoutRequired 
= false; 
 366     m_fullLayoutTime 
= 0; 
 367     m_fullLayoutSavedPosition 
= 0; 
 368     m_delayedLayoutThreshold 
= wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD
; 
 369     m_caretPositionForDefaultStyle 
= -2; 
 370     m_focusObject 
= & m_buffer
; 
 373 void wxRichTextCtrl::DoThaw() 
 375     if (GetBuffer().IsDirty()) 
 384 void wxRichTextCtrl::Clear() 
 386     if (GetFocusObject() == & GetBuffer()) 
 388         m_buffer
.ResetAndClearCommands(); 
 389         m_buffer
.Invalidate(wxRICHTEXT_ALL
); 
 393         GetFocusObject()->Reset(); 
 396     m_caretPosition 
= -1; 
 397     m_caretPositionForDefaultStyle 
= -2; 
 398     m_caretAtLineStart 
= false; 
 400     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
 410     wxTextCtrl::SendTextUpdatedEvent(this); 
 414 void wxRichTextCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 416 #if !wxRICHTEXT_USE_OWN_CARET 
 417     if (GetCaret() && !IsFrozen()) 
 420     // Stop the caret refreshing the control from within the 
 423         ((wxRichTextCaret
*) GetCaret())->EnableRefresh(false); 
 427 #if wxRICHTEXT_BUFFERED_PAINTING 
 428         wxBufferedPaintDC 
dc(this, m_bufferBitmap
); 
 438         dc
.SetFont(GetFont()); 
 440         // Paint the background 
 443         // wxRect drawingArea(GetLogicalPoint(wxPoint(0, 0)), GetClientSize()); 
 445         wxRect 
drawingArea(GetUpdateRegion().GetBox()); 
 446         drawingArea
.SetPosition(GetLogicalPoint(drawingArea
.GetPosition())); 
 448         wxRect 
availableSpace(GetClientSize()); 
 449         wxRichTextDrawingContext 
context(& GetBuffer()); 
 450         if (GetBuffer().IsDirty()) 
 452             GetBuffer().Layout(dc
, context
, availableSpace
, availableSpace
, wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
); 
 453             GetBuffer().Invalidate(wxRICHTEXT_NONE
); 
 457         wxRect 
clipRect(availableSpace
); 
 458         clipRect
.x 
+= GetBuffer().GetLeftMargin(); 
 459         clipRect
.y 
+= GetBuffer().GetTopMargin(); 
 460         clipRect
.width 
-= (GetBuffer().GetLeftMargin() + GetBuffer().GetRightMargin()); 
 461         clipRect
.height 
-= (GetBuffer().GetTopMargin() + GetBuffer().GetBottomMargin()); 
 462         clipRect
.SetPosition(GetLogicalPoint(clipRect
.GetPosition())); 
 463         dc
.SetClippingRegion(clipRect
); 
 466         if ((GetExtraStyle() & wxRICHTEXT_EX_NO_GUIDELINES
) == 0) 
 467             flags 
|= wxRICHTEXT_DRAW_GUIDELINES
; 
 469         GetBuffer().Draw(dc
, context
, GetBuffer().GetOwnRange(), GetSelection(), drawingArea
, 0 /* descent */, flags
); 
 471         dc
.DestroyClippingRegion(); 
 473         // Other user defined painting after everything else (i.e. all text) is painted 
 474         PaintAboveContent(dc
); 
 476 #if wxRICHTEXT_USE_OWN_CARET 
 477         if (GetCaret()->IsVisible()) 
 480             ((wxRichTextCaret
*) GetCaret())->DoDraw(& dc
); 
 485 #if !wxRICHTEXT_USE_OWN_CARET 
 491         ((wxRichTextCaret
*) GetCaret())->EnableRefresh(true); 
 495 // Empty implementation, to prevent flicker 
 496 void wxRichTextCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 500 void wxRichTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
 504 #if !wxRICHTEXT_USE_OWN_CARET 
 510 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 511     // Work around dropouts when control is focused 
 519 void wxRichTextCtrl::OnKillFocus(wxFocusEvent
& WXUNUSED(event
)) 
 524 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 525     // Work around dropouts when control is focused 
 533 void wxRichTextCtrl::OnCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
 538 // Set up the caret for the given position and container, after a mouse click 
 539 bool wxRichTextCtrl::SetCaretPositionAfterClick(wxRichTextParagraphLayoutBox
* container
, long position
, int hitTestFlags
, bool extendSelection
) 
 541     bool caretAtLineStart 
= false; 
 543     if (hitTestFlags 
& wxRICHTEXT_HITTEST_BEFORE
) 
 545         // If we're at the start of a line (but not first in para) 
 546         // then we should keep the caret showing at the start of the line 
 547         // by showing the m_caretAtLineStart flag. 
 548         wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(position
); 
 549         wxRichTextLine
* line 
= container
->GetLineAtPosition(position
); 
 551         if (line 
&& para 
&& line
->GetAbsoluteRange().GetStart() == position 
&& para
->GetRange().GetStart() != position
) 
 552             caretAtLineStart 
= true; 
 556     if (extendSelection 
&& (m_caretPosition 
!= position
)) 
 557         ExtendSelection(m_caretPosition
, position
, wxRICHTEXT_SHIFT_DOWN
); 
 559     MoveCaret(position
, caretAtLineStart
); 
 560     SetDefaultStyleToCursorStyle(); 
 566 void wxRichTextCtrl::OnLeftClick(wxMouseEvent
& event
) 
 572     dc
.SetFont(GetFont()); 
 574     // TODO: detect change of focus object 
 576     wxRichTextObject
* hitObj 
= NULL
; 
 577     wxRichTextObject
* contextObj 
= NULL
; 
 578     wxRichTextDrawingContext 
context(& GetBuffer()); 
 579     int hit 
= GetBuffer().HitTest(dc
, context
, event
.GetLogicalPosition(dc
), position
, & hitObj
, & contextObj
); 
 581 #if wxUSE_DRAG_AND_DROP 
 582     // If there's no selection, or we're not inside it, this isn't an attempt to initiate Drag'n'Drop 
 583     if (IsEditable() && HasSelection() && GetSelectionRange().ToInternal().Contains(position
)) 
 585         // This might be an attempt at initiating Drag'n'Drop. So set the time & flags 
 587         m_dragStartPoint 
= event
.GetPosition();   // No need to worry about logical positions etc, we only care about the distance from the original pt 
 590         m_dragStartTime 
= wxDateTime::UNow(); 
 591 #endif // wxUSE_DATETIME 
 593         // Preserve behaviour of clicking on an object within the selection 
 594         if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& hitObj
) 
 597         return; // Don't skip the event, else the selection will be lost 
 599 #endif // wxUSE_DRAG_AND_DROP 
 601     if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& hitObj
) 
 603         wxRichTextParagraphLayoutBox
* oldFocusObject 
= GetFocusObject(); 
 604         wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 605         if (container 
&& container 
!= GetFocusObject() && container
->AcceptsFocus()) 
 607             SetFocusObject(container
, false /* don't set caret position yet */); 
 613         long oldCaretPos 
= m_caretPosition
; 
 615         SetCaretPositionAfterClick(container
, position
, hit
); 
 617         // For now, don't handle shift-click when we're selecting multiple objects. 
 618         if (event
.ShiftDown() && GetFocusObject() == oldFocusObject 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 619             ExtendSelection(oldCaretPos
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 628 void wxRichTextCtrl::OnLeftUp(wxMouseEvent
& event
) 
 633         if (GetCapture() == this) 
 636         // See if we clicked on a URL 
 639         dc
.SetFont(GetFont()); 
 642         wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 643         wxRichTextObject
* hitObj 
= NULL
; 
 644         wxRichTextObject
* contextObj 
= NULL
; 
 645         wxRichTextDrawingContext 
context(& GetBuffer()); 
 646         // Only get objects at this level, not nested, because otherwise we couldn't swipe text at a single level. 
 647         int hit 
= GetFocusObject()->HitTest(dc
, context
, logicalPt
, position
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
); 
 649 #if wxUSE_DRAG_AND_DROP 
 652             // Preserve the behaviour that would have happened without drag-and-drop detection, in OnLeftClick 
 653             m_preDrag 
= false; // Tell DnD not to happen now: we are processing Left Up ourselves. 
 655             // Do the actions that would have been done in OnLeftClick if we hadn't tried to drag 
 657             wxRichTextObject
* hitObj 
= NULL
; 
 658             wxRichTextObject
* contextObj 
= NULL
; 
 659             int hit 
= GetBuffer().HitTest(dc
, context
, event
.GetLogicalPosition(dc
), position
, & hitObj
, & contextObj
); 
 660             wxRichTextParagraphLayoutBox
* oldFocusObject 
= GetFocusObject(); 
 661             wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 662             if (container 
&& container 
!= GetFocusObject() && container
->AcceptsFocus()) 
 664                 SetFocusObject(container
, false /* don't set caret position yet */); 
 667             long oldCaretPos 
= m_caretPosition
; 
 669             SetCaretPositionAfterClick(container
, position
, hit
); 
 671             // For now, don't handle shift-click when we're selecting multiple objects. 
 672             if (event
.ShiftDown() && GetFocusObject() == oldFocusObject 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 673                 ExtendSelection(oldCaretPos
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 679         if ((hit 
!= wxRICHTEXT_HITTEST_NONE
) && !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
 681             wxRichTextEvent 
cmdEvent( 
 682                 wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
, 
 684             cmdEvent
.SetEventObject(this); 
 685             cmdEvent
.SetPosition(position
); 
 687                 cmdEvent
.SetContainer(hitObj
->GetContainer()); 
 689             if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 692                 if (GetStyle(position
, attr
)) 
 694                     if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 696                         wxString urlTarget 
= attr
.GetURL(); 
 697                         if (!urlTarget
.IsEmpty()) 
 699                             wxMouseEvent 
mouseEvent(event
); 
 701                             long startPos 
= 0, endPos 
= 0; 
 702                             wxRichTextObject
* obj 
= GetFocusObject()->GetLeafObjectAtPosition(position
); 
 705                                 startPos 
= obj
->GetRange().GetStart(); 
 706                                 endPos 
= obj
->GetRange().GetEnd(); 
 709                             wxTextUrlEvent 
urlEvent(GetId(), mouseEvent
, startPos
, endPos
); 
 710                             InitCommandEvent(urlEvent
); 
 712                             urlEvent
.SetString(urlTarget
); 
 714                             GetEventHandler()->ProcessEvent(urlEvent
); 
 722 #if wxUSE_DRAG_AND_DROP 
 724 #endif // wxUSE_DRAG_AND_DROP 
 726 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ && wxHAVE_PRIMARY_SELECTION 
 727     if (HasSelection() && GetFocusObject() && GetFocusObject()->GetBuffer()) 
 729         // Put the selection in PRIMARY, if it exists 
 730         wxTheClipboard
->UsePrimarySelection(true); 
 732         wxRichTextRange range 
= GetInternalSelectionRange(); 
 733         GetFocusObject()->GetBuffer()->CopyToClipboard(range
); 
 735         wxTheClipboard
->UsePrimarySelection(false); 
 741 void wxRichTextCtrl::OnMoveMouse(wxMouseEvent
& event
) 
 743 #if wxUSE_DRAG_AND_DROP 
 744     // See if we're starting Drag'n'Drop 
 747         int x 
= m_dragStartPoint
.x 
- event
.GetPosition().x
; 
 748         int y 
= m_dragStartPoint
.y 
- event
.GetPosition().y
; 
 749         size_t distance 
= abs(x
) + abs(y
); 
 751         wxTimeSpan diff 
= wxDateTime::UNow() - m_dragStartTime
; 
 755              && (diff
.GetMilliseconds() > 100) 
 762             wxRichTextRange range 
= GetInternalSelectionRange(); 
 763             if (range 
== wxRICHTEXT_NONE
) 
 765               // Don't try to drag an empty range 
 770             // Cache the current situation, to be restored if Drag'n'Drop is cancelled 
 771             long oldPos 
= GetCaretPosition(); 
 772             wxRichTextParagraphLayoutBox
* oldFocus 
= GetFocusObject(); 
 774             wxDataObjectComposite
* compositeObject 
= new wxDataObjectComposite(); 
 775             wxString text 
= GetFocusObject()->GetTextForRange(range
); 
 777             text 
= wxTextFile::Translate(text
, wxTextFileType_Dos
); 
 779             compositeObject
->Add(new wxTextDataObject(text
), false /* not preferred */); 
 781             wxRichTextBuffer
* richTextBuf 
= new wxRichTextBuffer
; 
 782             GetFocusObject()->CopyFragment(range
, *richTextBuf
); 
 783             compositeObject
->Add(new wxRichTextBufferDataObject(richTextBuf
), true /* preferred */); 
 785             wxRichTextDropSource 
source(*compositeObject
, this); 
 786             // Use wxDrag_DefaultMove, not because it's the likelier choice but because pressing Ctrl for Copy obeys the principle of least surprise 
 787             // The alternative, wxDrag_DefaultCopy, requires the user to know that Move needs the Shift key pressed 
 788             BeginBatchUndo(_("Drag")); 
 789             switch (source
.DoDragDrop(wxDrag_AllowMove 
| wxDrag_DefaultMove
)) 
 792                 case wxDragCopy
:  break; 
 795                     wxLogError(wxT("An error occurred during drag and drop operation")); 
 798                     Refresh(); // This is needed in wxMSW, otherwise resetting the position doesn't 'take' 
 799                     SetCaretPosition(oldPos
); 
 800                     SetFocusObject(oldFocus
, false); 
 809 #endif // wxUSE_DRAG_AND_DROP 
 813     dc
.SetFont(GetFont()); 
 816     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 817     wxRichTextObject
* hitObj 
= NULL
; 
 818     wxRichTextObject
* contextObj 
= NULL
; 
 822     // If we're dragging, let's only consider positions at this level; otherwise 
 823     // selecting a range is not going to work. 
 824     wxRichTextParagraphLayoutBox
* container 
= & GetBuffer(); 
 827         flags 
= wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
; 
 828         container 
= GetFocusObject(); 
 830     wxRichTextDrawingContext 
context(& GetBuffer()); 
 831     int hit 
= container
->HitTest(dc
, context
, logicalPt
, position
, & hitObj
, & contextObj
, flags
); 
 833     // See if we need to change the cursor 
 836         if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
) && hitObj
) 
 838             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 840                 ProcessMouseMovement(actualContainer
, hitObj
, position
, logicalPt
); 
 843             SetCursor(m_textCursor
); 
 846     if (!event
.Dragging()) 
 853 #if wxUSE_DRAG_AND_DROP 
 858         wxRichTextParagraphLayoutBox
* commonAncestor 
= NULL
; 
 859         wxRichTextParagraphLayoutBox
* otherContainer 
= NULL
; 
 860         wxRichTextParagraphLayoutBox
* firstContainer 
= NULL
; 
 862         // Check for dragging across multiple containers 
 864         wxRichTextObject
* hitObj2 
= NULL
, *contextObj2 
= NULL
; 
 865         int hit2 
= GetBuffer().HitTest(dc
, context
, logicalPt
, position2
, & hitObj2
, & contextObj2
, 0); 
 866         if (hit2 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit2 
& wxRICHTEXT_HITTEST_OUTSIDE
) && hitObj2 
&& hitObj 
!= hitObj2
) 
 868             // See if we can find a common ancestor 
 869             if (m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 871                 firstContainer 
= GetFocusObject(); 
 872                 commonAncestor 
= wxDynamicCast(firstContainer
->GetParent(), wxRichTextParagraphLayoutBox
); 
 876                 firstContainer 
= wxDynamicCast(m_selectionAnchorObject
, wxRichTextParagraphLayoutBox
); 
 877                 //commonAncestor = GetFocusObject(); // when the selection state is not normal, the focus object (e.g. table) 
 878                                                    // is the common ancestor. 
 879                 commonAncestor 
= wxDynamicCast(firstContainer
->GetParent(), wxRichTextParagraphLayoutBox
); 
 882             if (commonAncestor 
&& commonAncestor
->HandlesChildSelections()) 
 884                 wxRichTextObject
* p 
= hitObj2
; 
 887                     if (p
->GetParent() == commonAncestor
) 
 889                         otherContainer 
= wxDynamicCast(p
, wxRichTextParagraphLayoutBox
); 
 896             if (commonAncestor 
&& firstContainer 
&& otherContainer
) 
 898                 // We have now got a second container that shares a parent with the current or anchor object. 
 899                 if (m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 901                     // Don't go into common-ancestor selection mode if we still have the same 
 903                     if (otherContainer 
!= firstContainer
) 
 905                         m_selectionState 
= wxRichTextCtrlSelectionState_CommonAncestor
; 
 906                         m_selectionAnchorObject 
= firstContainer
; 
 907                         m_selectionAnchor 
= firstContainer
->GetRange().GetStart(); 
 909                         // The common ancestor, such as a table, returns the cell selection 
 910                         // between the anchor and current position. 
 911                         m_selection 
= commonAncestor
->GetSelection(m_selectionAnchor
, otherContainer
->GetRange().GetStart()); 
 916                     m_selection 
= commonAncestor
->GetSelection(m_selectionAnchor
, otherContainer
->GetRange().GetStart()); 
 921                 if (otherContainer
->AcceptsFocus()) 
 922                     SetFocusObject(otherContainer
, false /* don't set caret and clear selection */); 
 923                 MoveCaret(-1, false); 
 924                 SetDefaultStyleToCursorStyle(); 
 929     if (hitObj 
&& m_dragging 
&& hit 
!= wxRICHTEXT_HITTEST_NONE 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
 
 930 #if wxUSE_DRAG_AND_DROP 
 935         // TODO: test closeness 
 936         SetCaretPositionAfterClick(container
, position
, hit
, true /* extend selection */); 
 941 void wxRichTextCtrl::OnRightClick(wxMouseEvent
& event
) 
 947     dc
.SetFont(GetFont()); 
 950     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 951     wxRichTextObject
* hitObj 
= NULL
; 
 952     wxRichTextObject
* contextObj 
= NULL
; 
 953     wxRichTextDrawingContext 
context(& GetBuffer()); 
 954     int hit 
= GetFocusObject()->HitTest(dc
, context
, logicalPt
, position
, & hitObj
, & contextObj
); 
 956     if (hitObj 
&& hitObj
->GetContainer() != GetFocusObject()) 
 958         wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 959         if (actualContainer 
&& actualContainer
->AcceptsFocus()) 
 961             SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
 962             SetCaretPositionAfterClick(actualContainer
, position
, hit
); 
 966     wxRichTextEvent 
cmdEvent( 
 967         wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
, 
 969     cmdEvent
.SetEventObject(this); 
 970     cmdEvent
.SetPosition(position
); 
 972         cmdEvent
.SetContainer(hitObj
->GetContainer()); 
 974     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 978 /// Left-double-click 
 979 void wxRichTextCtrl::OnLeftDClick(wxMouseEvent
& WXUNUSED(event
)) 
 981     wxRichTextEvent 
cmdEvent( 
 982         wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
, 
 984     cmdEvent
.SetEventObject(this); 
 985     cmdEvent
.SetPosition(m_caretPosition
+1); 
 986     cmdEvent
.SetContainer(GetFocusObject()); 
 988     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 990         SelectWord(GetCaretPosition()+1); 
 995 void wxRichTextCtrl::OnMiddleClick(wxMouseEvent
& event
) 
 997     wxRichTextEvent 
cmdEvent( 
 998         wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
, 
1000     cmdEvent
.SetEventObject(this); 
1001     cmdEvent
.SetPosition(m_caretPosition
+1); 
1002     cmdEvent
.SetContainer(GetFocusObject()); 
1004     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
1007 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ && wxHAVE_PRIMARY_SELECTION 
1008     // Paste any PRIMARY selection, if it exists 
1009     wxTheClipboard
->UsePrimarySelection(true); 
1011     wxTheClipboard
->UsePrimarySelection(false); 
1016 void wxRichTextCtrl::OnChar(wxKeyEvent
& event
) 
1019     if (event
.CmdDown()) 
1020         flags 
|= wxRICHTEXT_CTRL_DOWN
; 
1021     if (event
.ShiftDown()) 
1022         flags 
|= wxRICHTEXT_SHIFT_DOWN
; 
1023     if (event
.AltDown()) 
1024         flags 
|= wxRICHTEXT_ALT_DOWN
; 
1026     if (event
.GetEventType() == wxEVT_KEY_DOWN
) 
1028         if (event
.IsKeyInCategory(WXK_CATEGORY_NAVIGATION
)) 
1030             KeyboardNavigate(event
.GetKeyCode(), flags
); 
1034         long keycode 
= event
.GetKeyCode(); 
1094             case WXK_NUMPAD_HOME
: 
1095             case WXK_NUMPAD_LEFT
: 
1097             case WXK_NUMPAD_RIGHT
: 
1098             case WXK_NUMPAD_DOWN
: 
1099             case WXK_NUMPAD_PAGEUP
: 
1100             case WXK_NUMPAD_PAGEDOWN
: 
1101             case WXK_NUMPAD_END
: 
1102             case WXK_NUMPAD_BEGIN
: 
1103             case WXK_NUMPAD_INSERT
: 
1104             case WXK_WINDOWS_LEFT
: 
1113         // Must process this before translation, otherwise it's translated into a WXK_DELETE event. 
1114         if (event
.CmdDown() && event
.GetKeyCode() == WXK_BACK
) 
1121             if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1126             BeginBatchUndo(_("Delete Text")); 
1128             long newPos 
= m_caretPosition
; 
1130             bool processed 
= DeleteSelectedContent(& newPos
); 
1136             // Submit range in character positions, which are greater than caret positions, 
1137             // so subtract 1 for deleted character and add 1 for conversion to character position. 
1140                 if (event
.CmdDown()) 
1142                     long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
1145                         wxRichTextRange 
range(pos
+1, newPos
); 
1146                         if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1148                             GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1157                     wxRichTextRange 
range(newPos
, newPos
); 
1158                     if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1160                         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1168             if (GetLastPosition() == -1) 
1170                 GetFocusObject()->Reset(); 
1172                 m_caretPosition 
= -1; 
1174                 SetDefaultStyleToCursorStyle(); 
1177             ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
1181                 wxRichTextEvent 
cmdEvent( 
1182                     wxEVT_COMMAND_RICHTEXT_DELETE
, 
1184                 cmdEvent
.SetEventObject(this); 
1185                 cmdEvent
.SetFlags(flags
); 
1186                 cmdEvent
.SetPosition(m_caretPosition
+1); 
1187                 cmdEvent
.SetContainer(GetFocusObject()); 
1188                 GetEventHandler()->ProcessEvent(cmdEvent
); 
1199     // all the other keys modify the controls contents which shouldn't be 
1200     // possible if we're read-only 
1201     if ( !IsEditable() ) 
1207     if (event
.GetKeyCode() == WXK_RETURN
) 
1209         if (!CanInsertContent(* GetFocusObject(), m_caretPosition
+1)) 
1212         long newPos 
= m_caretPosition
; 
1214         if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1219         BeginBatchUndo(_("Insert Text")); 
1221         DeleteSelectedContent(& newPos
); 
1223         if (event
.ShiftDown()) 
1226             text 
= wxRichTextLineBreakChar
; 
1227             GetFocusObject()->InsertTextWithUndo(& GetBuffer(), newPos
+1, text
, this); 
1228             m_caretAtLineStart 
= true; 
1232             GetFocusObject()->InsertNewlineWithUndo(& GetBuffer(), newPos
+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
|wxRICHTEXT_INSERT_INTERACTIVE
); 
1235         SetDefaultStyleToCursorStyle(); 
1237         ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
1239         wxRichTextEvent 
cmdEvent( 
1240             wxEVT_COMMAND_RICHTEXT_RETURN
, 
1242         cmdEvent
.SetEventObject(this); 
1243         cmdEvent
.SetFlags(flags
); 
1244         cmdEvent
.SetPosition(newPos
+1); 
1245         cmdEvent
.SetContainer(GetFocusObject()); 
1247         if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
1249             // Generate conventional event 
1250             wxCommandEvent 
textEvent(wxEVT_COMMAND_TEXT_ENTER
, GetId()); 
1251             InitCommandEvent(textEvent
); 
1253             GetEventHandler()->ProcessEvent(textEvent
); 
1257     else if (event
.GetKeyCode() == WXK_BACK
) 
1259         long newPos 
= m_caretPosition
; 
1261         if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1266         BeginBatchUndo(_("Delete Text")); 
1268         bool processed 
= DeleteSelectedContent(& newPos
); 
1274         // Submit range in character positions, which are greater than caret positions, 
1275         // so subtract 1 for deleted character and add 1 for conversion to character position. 
1278             if (event
.CmdDown()) 
1280                 long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
1283                     wxRichTextRange 
range(pos
+1, newPos
); 
1284                     if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1286                         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1295                 wxRichTextRange 
range(newPos
, newPos
); 
1296                 if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1298                     GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1306         if (GetLastPosition() == -1) 
1308             GetFocusObject()->Reset(); 
1310             m_caretPosition 
= -1; 
1312             SetDefaultStyleToCursorStyle(); 
1315         ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
1319             wxRichTextEvent 
cmdEvent( 
1320                 wxEVT_COMMAND_RICHTEXT_DELETE
, 
1322             cmdEvent
.SetEventObject(this); 
1323             cmdEvent
.SetFlags(flags
); 
1324             cmdEvent
.SetPosition(m_caretPosition
+1); 
1325             cmdEvent
.SetContainer(GetFocusObject()); 
1326             GetEventHandler()->ProcessEvent(cmdEvent
); 
1331     else if (event
.GetKeyCode() == WXK_DELETE
) 
1333         long newPos 
= m_caretPosition
; 
1335         if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1340         BeginBatchUndo(_("Delete Text")); 
1342         bool processed 
= DeleteSelectedContent(& newPos
); 
1348         // Submit range in character positions, which are greater than caret positions, 
1349         if (newPos 
< GetFocusObject()->GetOwnRange().GetEnd()+1) 
1351             if (event
.CmdDown()) 
1353                 long pos 
= wxRichTextCtrl::FindNextWordPosition(1); 
1354                 if (pos 
!= -1 && (pos 
> newPos
)) 
1356                     wxRichTextRange 
range(newPos
+1, pos
); 
1357                     if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1359                         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1366             if (!processed 
&& newPos 
< (GetLastPosition()-1)) 
1368                 wxRichTextRange 
range(newPos
+1, newPos
+1); 
1369                 if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1371                     GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1379         if (GetLastPosition() == -1) 
1381             GetFocusObject()->Reset(); 
1383             m_caretPosition 
= -1; 
1385             SetDefaultStyleToCursorStyle(); 
1388         ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
1392             wxRichTextEvent 
cmdEvent( 
1393                 wxEVT_COMMAND_RICHTEXT_DELETE
, 
1395             cmdEvent
.SetEventObject(this); 
1396             cmdEvent
.SetFlags(flags
); 
1397             cmdEvent
.SetPosition(m_caretPosition
+1); 
1398             cmdEvent
.SetContainer(GetFocusObject()); 
1399             GetEventHandler()->ProcessEvent(cmdEvent
); 
1406         long keycode 
= event
.GetKeyCode(); 
1418                 if (event
.CmdDown()) 
1420                 // Fixes AltGr+key with European input languages on Windows 
1421                 if ((event
.CmdDown() && !event
.AltDown()) || (event
.AltDown() && !event
.CmdDown())) 
1428                 wxRichTextEvent 
cmdEvent( 
1429                     wxEVT_COMMAND_RICHTEXT_CHARACTER
, 
1431                 cmdEvent
.SetEventObject(this); 
1432                 cmdEvent
.SetFlags(flags
); 
1434                 cmdEvent
.SetCharacter(event
.GetUnicodeKey()); 
1436                 cmdEvent
.SetCharacter((wxChar
) keycode
); 
1438                 cmdEvent
.SetPosition(m_caretPosition
+1); 
1439                 cmdEvent
.SetContainer(GetFocusObject()); 
1441                 if (keycode 
== wxT('\t')) 
1443                     // See if we need to promote or demote the selection or paragraph at the cursor 
1444                     // position, instead of inserting a tab. 
1445                     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
1446                     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
); 
1447                     if (para 
&& para
->GetRange().GetStart() == pos 
&& para
->GetAttributes().HasListStyleName()) 
1449                         wxRichTextRange range
; 
1451                             range 
= GetSelectionRange(); 
1453                             range 
= para
->GetRange().FromInternal(); 
1455                         int promoteBy 
= event
.ShiftDown() ? 1 : -1; 
1457                         PromoteList(promoteBy
, range
, NULL
); 
1459                         GetEventHandler()->ProcessEvent(cmdEvent
); 
1465                 if (!CanInsertContent(* GetFocusObject(), m_caretPosition
+1)) 
1468                 if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1471                 BeginBatchUndo(_("Insert Text")); 
1473                 long newPos 
= m_caretPosition
; 
1474                 DeleteSelectedContent(& newPos
); 
1477                 wxString str 
= event
.GetUnicodeKey(); 
1479                 wxString str 
= (wxChar
) event
.GetKeyCode(); 
1481                 GetFocusObject()->InsertTextWithUndo(& GetBuffer(), newPos
+1, str
, this, 0); 
1485                 SetDefaultStyleToCursorStyle(); 
1486                 ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
1488                 cmdEvent
.SetPosition(m_caretPosition
); 
1489                 GetEventHandler()->ProcessEvent(cmdEvent
); 
1497 bool wxRichTextCtrl::ProcessMouseMovement(wxRichTextParagraphLayoutBox
* container
, wxRichTextObject
* WXUNUSED(obj
), long position
, const wxPoint
& WXUNUSED(pos
)) 
1499     wxRichTextAttr attr
; 
1500     if (container 
&& GetStyle(position
, attr
, container
)) 
1502         if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
1504             SetCursor(m_urlCursor
); 
1506         else if (!attr
.HasFlag(wxTEXT_ATTR_URL
)) 
1508             SetCursor(m_textCursor
); 
1516 /// Delete content if there is a selection, e.g. when pressing a key. 
1517 bool wxRichTextCtrl::DeleteSelectedContent(long* newPos
) 
1521         long pos 
= m_selection
.GetRange().GetStart(); 
1522         wxRichTextRange range 
= m_selection
.GetRange(); 
1524         // SelectAll causes more to be selected than doing it interactively, 
1525         // and causes a new paragraph to be inserted. So for multiline buffers, 
1526         // don't delete the final position. 
1527         if (range
.GetEnd() == GetLastPosition() && GetNumberOfLines() > 0) 
1528             range
.SetEnd(range
.GetEnd()-1); 
1530         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1531         m_selection
.Reset(); 
1532         m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
1542 /// Keyboard navigation 
1546 Left:       left one character 
1547 Right:      right one character 
1550 Ctrl-Left:  left one word 
1551 Ctrl-Right: right one word 
1552 Ctrl-Up:    previous paragraph start 
1553 Ctrl-Down:  next start of paragraph 
1556 Ctrl-Home:  start of document 
1557 Ctrl-End:   end of document 
1558 Page-Up:    Up a screen 
1559 Page-Down:  Down a screen 
1563 Ctrl-Alt-PgUp: Start of window 
1564 Ctrl-Alt-PgDn: End of window 
1565 F8:         Start selection mode 
1566 Esc:        End selection mode 
1568 Adding Shift does the above but starts/extends selection. 
1573 bool wxRichTextCtrl::KeyboardNavigate(int keyCode
, int flags
) 
1575     bool success 
= false; 
1577     if (keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT
) 
1579         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1580             success 
= WordRight(1, flags
); 
1582             success 
= MoveRight(1, flags
); 
1584     else if (keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT
) 
1586         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1587             success 
= WordLeft(1, flags
); 
1589             success 
= MoveLeft(1, flags
); 
1591     else if (keyCode 
== WXK_UP 
|| keyCode 
== WXK_NUMPAD_UP
) 
1593         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1594             success 
= MoveToParagraphStart(flags
); 
1596             success 
= MoveUp(1, flags
); 
1598     else if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN
) 
1600         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1601             success 
= MoveToParagraphEnd(flags
); 
1603             success 
= MoveDown(1, flags
); 
1605     else if (keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP
) 
1607         success 
= PageUp(1, flags
); 
1609     else if (keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1611         success 
= PageDown(1, flags
); 
1613     else if (keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME
) 
1615         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1616             success 
= MoveHome(flags
); 
1618             success 
= MoveToLineStart(flags
); 
1620     else if (keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END
) 
1622         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1623             success 
= MoveEnd(flags
); 
1625             success 
= MoveToLineEnd(flags
); 
1630         ScrollIntoView(m_caretPosition
, keyCode
); 
1631         SetDefaultStyleToCursorStyle(); 
1637 /// Extend the selection. Selections are in caret positions. 
1638 bool wxRichTextCtrl::ExtendSelection(long oldPos
, long newPos
, int flags
) 
1640     if (flags 
& wxRICHTEXT_SHIFT_DOWN
) 
1642         if (oldPos 
== newPos
) 
1645         wxRichTextSelection oldSelection 
= m_selection
; 
1647         m_selection
.SetContainer(GetFocusObject()); 
1649         wxRichTextRange oldRange
; 
1650         if (m_selection
.IsValid()) 
1651             oldRange 
= m_selection
.GetRange(); 
1653             oldRange 
= wxRICHTEXT_NO_SELECTION
; 
1654         wxRichTextRange newRange
; 
1656         // If not currently selecting, start selecting 
1657         if (oldRange
.GetStart() == -2) 
1659             m_selectionAnchor 
= oldPos
; 
1661             if (oldPos 
> newPos
) 
1662                 newRange
.SetRange(newPos
+1, oldPos
); 
1664                 newRange
.SetRange(oldPos
+1, newPos
); 
1668             // Always ensure that the selection range start is greater than 
1670             if (newPos 
> m_selectionAnchor
) 
1671                 newRange
.SetRange(m_selectionAnchor
+1, newPos
); 
1672             else if (newPos 
== m_selectionAnchor
) 
1673                 newRange 
= wxRichTextRange(-2, -2); 
1675                 newRange
.SetRange(newPos
+1, m_selectionAnchor
); 
1678         m_selection
.SetRange(newRange
); 
1680         RefreshForSelectionChange(oldSelection
, m_selection
); 
1682         if (newRange
.GetStart() > newRange
.GetEnd()) 
1684             wxLogDebug(wxT("Strange selection range")); 
1693 /// Scroll into view, returning true if we scrolled. 
1694 /// This takes a _caret_ position. 
1695 bool wxRichTextCtrl::ScrollIntoView(long position
, int keyCode
) 
1697     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(position
); 
1703     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1705     int startXUnits
, startYUnits
; 
1706     GetViewStart(& startXUnits
, & startYUnits
); 
1707     int startY 
= startYUnits 
* ppuY
; 
1710     GetVirtualSize(& sx
, & sy
); 
1716     wxRect rect 
= line
->GetRect(); 
1718     bool scrolled 
= false; 
1720     wxSize clientSize 
= GetClientSize(); 
1722     int leftMargin
, rightMargin
, topMargin
, bottomMargin
; 
1725         wxClientDC 
dc(this); 
1726         wxRichTextObject::GetTotalMargin(dc
, & GetBuffer(), GetBuffer().GetAttributes(), leftMargin
, rightMargin
, 
1727             topMargin
, bottomMargin
); 
1729 //    clientSize.y -= GetBuffer().GetBottomMargin(); 
1730     clientSize
.y 
-= bottomMargin
; 
1732     if (GetWindowStyle() & wxRE_CENTRE_CARET
) 
1734         int y 
= rect
.y 
- GetClientSize().y
/2; 
1735         int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1736         if (y 
>= 0 && (y 
+ clientSize
.y
) < GetBuffer().GetCachedSize().y
) 
1738             if (startYUnits 
!= yUnits
) 
1740                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1743 #if !wxRICHTEXT_USE_OWN_CARET 
1753     if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN 
|| 
1754         keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT 
|| 
1755         keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END 
|| 
1756         keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1758         if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1760             // Make it scroll so this item is at the bottom 
1762             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1763             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1765             // If we're still off the screen, scroll another line down 
1766             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1769             if (startYUnits 
!= yUnits
) 
1771                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1775         else if (rect
.y 
< (startY 
+ GetBuffer().GetTopMargin())) 
1777             // Make it scroll so this item is at the top 
1779             int y 
= rect
.y 
- GetBuffer().GetTopMargin(); 
1780             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1782             if (startYUnits 
!= yUnits
) 
1784                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1790     else if (keyCode 
== WXK_UP  
|| keyCode 
== WXK_NUMPAD_UP 
|| 
1791              keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT 
|| 
1792              keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME 
|| 
1793              keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP 
) 
1795         if (rect
.y 
< (startY 
+ GetBuffer().GetBottomMargin())) 
1797             // Make it scroll so this item is at the top 
1799             int y 
= rect
.y 
- GetBuffer().GetTopMargin(); 
1800             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1802             if (startYUnits 
!= yUnits
) 
1804                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1808         else if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1810             // Make it scroll so this item is at the bottom 
1812             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1813             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1815             // If we're still off the screen, scroll another line down 
1816             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1819             if (startYUnits 
!= yUnits
) 
1821                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1827 #if !wxRICHTEXT_USE_OWN_CARET 
1835 /// Is the given position visible on the screen? 
1836 bool wxRichTextCtrl::IsPositionVisible(long pos
) const 
1838     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(pos
-1); 
1844     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1847     GetViewStart(& startX
, & startY
); 
1849     startY 
= startY 
* ppuY
; 
1851     wxRect rect 
= line
->GetRect(); 
1852     wxSize clientSize 
= GetClientSize(); 
1853     clientSize
.y 
-= GetBuffer().GetBottomMargin(); 
1855     return (rect
.GetTop() >= (startY 
+ GetBuffer().GetTopMargin())) && (rect
.GetBottom() <= (startY 
+ clientSize
.y
)); 
1858 void wxRichTextCtrl::SetCaretPosition(long position
, bool showAtLineStart
) 
1860     m_caretPosition 
= position
; 
1861     m_caretAtLineStart 
= showAtLineStart
; 
1864 /// Move caret one visual step forward: this may mean setting a flag 
1865 /// and keeping the same position if we're going from the end of one line 
1866 /// to the start of the next, which may be the exact same caret position. 
1867 void wxRichTextCtrl::MoveCaretForward(long oldPosition
) 
1869     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(oldPosition
); 
1871     // Only do the check if we're not at the end of the paragraph (where things work OK 
1873     if (para 
&& (oldPosition 
!= para
->GetRange().GetEnd() - 1)) 
1875         wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(oldPosition
); 
1879             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1881             // We're at the end of a line. See whether we need to 
1882             // stay at the same actual caret position but change visual 
1883             // position, or not. 
1884             if (oldPosition 
== lineRange
.GetEnd()) 
1886                 if (m_caretAtLineStart
) 
1888                     // We're already at the start of the line, so actually move on now. 
1889                     m_caretPosition 
= oldPosition 
+ 1; 
1890                     m_caretAtLineStart 
= false; 
1894                     // We're showing at the end of the line, so keep to 
1895                     // the same position but indicate that we're to show 
1896                     // at the start of the next line. 
1897                     m_caretPosition 
= oldPosition
; 
1898                     m_caretAtLineStart 
= true; 
1900                 SetDefaultStyleToCursorStyle(); 
1906     SetDefaultStyleToCursorStyle(); 
1909 /// Move caret one visual step backward: this may mean setting a flag 
1910 /// and keeping the same position if we're going from the end of one line 
1911 /// to the start of the next, which may be the exact same caret position. 
1912 void wxRichTextCtrl::MoveCaretBack(long oldPosition
) 
1914     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(oldPosition
); 
1916     // Only do the check if we're not at the start of the paragraph (where things work OK 
1918     if (para 
&& (oldPosition 
!= para
->GetRange().GetStart())) 
1920         wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(oldPosition
); 
1924             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1926             // We're at the start of a line. See whether we need to 
1927             // stay at the same actual caret position but change visual 
1928             // position, or not. 
1929             if (oldPosition 
== lineRange
.GetStart()) 
1931                 m_caretPosition 
= oldPosition
-1; 
1932                 m_caretAtLineStart 
= true; 
1935             else if (oldPosition 
== lineRange
.GetEnd()) 
1937                 if (m_caretAtLineStart
) 
1939                     // We're at the start of the line, so keep the same caret position 
1940                     // but clear the start-of-line flag. 
1941                     m_caretPosition 
= oldPosition
; 
1942                     m_caretAtLineStart 
= false; 
1946                     // We're showing at the end of the line, so go back 
1947                     // to the previous character position. 
1948                     m_caretPosition 
= oldPosition 
- 1; 
1950                 SetDefaultStyleToCursorStyle(); 
1956     SetDefaultStyleToCursorStyle(); 
1960 bool wxRichTextCtrl::MoveRight(int noPositions
, int flags
) 
1962     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd(); 
1964     if (m_caretPosition 
+ noPositions 
< endPos
) 
1966         long oldPos 
= m_caretPosition
; 
1967         long newPos 
= m_caretPosition 
+ noPositions
; 
1969         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1973         // Determine by looking at oldPos and m_caretPosition whether 
1974         // we moved from the end of a line to the start of the next line, in which case 
1975         // we want to adjust the caret position such that it is positioned at the 
1976         // start of the next line, rather than jumping past the first character of the 
1978         if (noPositions 
== 1 && !extendSel
) 
1979             MoveCaretForward(oldPos
); 
1981             SetCaretPosition(newPos
); 
1984         SetDefaultStyleToCursorStyle(); 
1993 bool wxRichTextCtrl::MoveLeft(int noPositions
, int flags
) 
1997     if (m_caretPosition 
> startPos 
- noPositions 
+ 1) 
1999         long oldPos 
= m_caretPosition
; 
2000         long newPos 
= m_caretPosition 
- noPositions
; 
2001         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2005         if (noPositions 
== 1 && !extendSel
) 
2006             MoveCaretBack(oldPos
); 
2008             SetCaretPosition(newPos
); 
2011         SetDefaultStyleToCursorStyle(); 
2019 // Find the caret position for the combination of hit-test flags and character position. 
2020 // Returns the caret position and also an indication of where to place the caret (caretLineStart) 
2021 // since this is ambiguous (same position used for end of line and start of next). 
2022 long wxRichTextCtrl::FindCaretPositionForCharacterPosition(long position
, int hitTestFlags
, wxRichTextParagraphLayoutBox
* container
, 
2023                                                    bool& caretLineStart
) 
2025     // If end of previous line, and hitTest is wxRICHTEXT_HITTEST_BEFORE, 
2026     // we want to be at the end of the last line but with m_caretAtLineStart set to true, 
2027     // so we view the caret at the start of the line. 
2028     caretLineStart 
= false; 
2029     long caretPosition 
= position
; 
2031     if (hitTestFlags 
& wxRICHTEXT_HITTEST_BEFORE
) 
2033         wxRichTextLine
* thisLine 
= container
->GetLineAtPosition(position
-1); 
2034         wxRichTextRange lineRange
; 
2036             lineRange 
= thisLine
->GetAbsoluteRange(); 
2038         if (thisLine 
&& (position
-1) == lineRange
.GetEnd()) 
2041             caretLineStart 
= true; 
2045             wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(position
); 
2046             if (para 
&& para
->GetRange().GetStart() == position
) 
2050     return caretPosition
; 
2054 bool wxRichTextCtrl::MoveUp(int noLines
, int flags
) 
2056     return MoveDown(- noLines
, flags
); 
2060 bool wxRichTextCtrl::MoveDown(int noLines
, int flags
) 
2065     long lineNumber 
= GetFocusObject()->GetVisibleLineNumber(m_caretPosition
, true, m_caretAtLineStart
); 
2066     wxPoint pt 
= GetCaret()->GetPosition(); 
2067     long newLine 
= lineNumber 
+ noLines
; 
2068     bool notInThisObject 
= false; 
2070     if (lineNumber 
!= -1) 
2074             long lastLine 
= GetFocusObject()->GetVisibleLineNumber(GetFocusObject()->GetOwnRange().GetEnd()); 
2075             if (newLine 
> lastLine
) 
2076                 notInThisObject 
= true; 
2081                 notInThisObject 
= true; 
2085     wxRichTextParagraphLayoutBox
* container 
= GetFocusObject(); 
2086     int hitTestFlags 
= wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
|wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS
; 
2088     if (notInThisObject
) 
2090         // If we know we're navigating out of the current object, 
2091         // try to find an object anywhere in the buffer at the new position (up or down a bit) 
2092         container 
= & GetBuffer(); 
2093         hitTestFlags 
&= ~wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
; 
2095         if (noLines 
> 0) // going down 
2097             pt
.y 
= GetFocusObject()->GetPosition().y 
+ GetFocusObject()->GetCachedSize().y 
+ 2; 
2101             pt
.y 
= GetFocusObject()->GetPosition().y 
- 2; 
2106         wxRichTextLine
* lineObj 
= GetFocusObject()->GetLineForVisibleLineNumber(newLine
); 
2108             pt
.y 
= lineObj
->GetAbsolutePosition().y 
+ 2; 
2114     wxClientDC 
dc(this); 
2116     dc
.SetFont(GetFont()); 
2118     wxRichTextObject
* hitObj 
= NULL
; 
2119     wxRichTextObject
* contextObj 
= NULL
; 
2120     wxRichTextDrawingContext 
context(& GetBuffer()); 
2121     int hitTest 
= container
->HitTest(dc
, context
, pt
, newPos
, & hitObj
, & contextObj
, hitTestFlags
); 
2124         ((hitTest 
& wxRICHTEXT_HITTEST_NONE
) == 0) && 
2125         (! (hitObj 
== (& m_buffer
) && ((hitTest 
& wxRICHTEXT_HITTEST_OUTSIDE
) != 0))) // outside the buffer counts as 'do nothing' 
2128         if (notInThisObject
) 
2130             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
2131             if (actualContainer 
&& actualContainer 
!= GetFocusObject() && actualContainer
->AcceptsFocus()) 
2133                 SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
2135                 container 
= actualContainer
; 
2139         bool caretLineStart 
= true; 
2140         long caretPosition 
= FindCaretPositionForCharacterPosition(newPos
, hitTest
, container
, caretLineStart
); 
2141         long newSelEnd 
= caretPosition
; 
2144         if (notInThisObject
) 
2147             extendSel 
= ExtendSelection(m_caretPosition
, newSelEnd
, flags
); 
2152         SetCaretPosition(caretPosition
, caretLineStart
); 
2154         SetDefaultStyleToCursorStyle(); 
2162 /// Move to the end of the paragraph 
2163 bool wxRichTextCtrl::MoveToParagraphEnd(int flags
) 
2165     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(m_caretPosition
, true); 
2168         long newPos 
= para
->GetRange().GetEnd() - 1; 
2169         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2173         SetCaretPosition(newPos
); 
2175         SetDefaultStyleToCursorStyle(); 
2183 /// Move to the start of the paragraph 
2184 bool wxRichTextCtrl::MoveToParagraphStart(int flags
) 
2186     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(m_caretPosition
, true); 
2189         long newPos 
= para
->GetRange().GetStart() - 1; 
2190         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2194         SetCaretPosition(newPos
); 
2196         SetDefaultStyleToCursorStyle(); 
2204 /// Move to the end of the line 
2205 bool wxRichTextCtrl::MoveToLineEnd(int flags
) 
2207     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
2211         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2212         long newPos 
= lineRange
.GetEnd(); 
2213         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2217         SetCaretPosition(newPos
); 
2219         SetDefaultStyleToCursorStyle(); 
2227 /// Move to the start of the line 
2228 bool wxRichTextCtrl::MoveToLineStart(int flags
) 
2230     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
2233         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2234         long newPos 
= lineRange
.GetStart()-1; 
2236         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2240         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphForLine(line
); 
2242         SetCaretPosition(newPos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
2244         SetDefaultStyleToCursorStyle(); 
2252 /// Move to the start of the buffer 
2253 bool wxRichTextCtrl::MoveHome(int flags
) 
2255     if (m_caretPosition 
!= -1) 
2257         bool extendSel 
= ExtendSelection(m_caretPosition
, -1, flags
); 
2261         SetCaretPosition(-1); 
2263         SetDefaultStyleToCursorStyle(); 
2271 /// Move to the end of the buffer 
2272 bool wxRichTextCtrl::MoveEnd(int flags
) 
2274     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd()-1; 
2276     if (m_caretPosition 
!= endPos
) 
2278         bool extendSel 
= ExtendSelection(m_caretPosition
, endPos
, flags
); 
2282         SetCaretPosition(endPos
); 
2284         SetDefaultStyleToCursorStyle(); 
2292 /// Move noPages pages up 
2293 bool wxRichTextCtrl::PageUp(int noPages
, int flags
) 
2295     return PageDown(- noPages
, flags
); 
2298 /// Move noPages pages down 
2299 bool wxRichTextCtrl::PageDown(int noPages
, int flags
) 
2301     // Calculate which line occurs noPages * screen height further down. 
2302     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
2305         wxSize clientSize 
= GetClientSize(); 
2306         int newY 
= line
->GetAbsolutePosition().y 
+ noPages
*clientSize
.y
; 
2308         wxRichTextLine
* newLine 
= GetFocusObject()->GetLineAtYPosition(newY
); 
2311             wxRichTextRange lineRange 
= newLine
->GetAbsoluteRange(); 
2312             long pos 
= lineRange
.GetStart()-1; 
2313             if (pos 
!= m_caretPosition
) 
2315                 wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphForLine(newLine
); 
2317                 bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2321                 SetCaretPosition(pos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
2323                 SetDefaultStyleToCursorStyle(); 
2333 static bool wxRichTextCtrlIsWhitespace(const wxString
& str
) 
2335     return str 
== wxT(" ") || str 
== wxT("\t"); 
2338 // Finds the caret position for the next word 
2339 long wxRichTextCtrl::FindNextWordPosition(int direction
) const 
2341     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd(); 
2345         long i 
= m_caretPosition
+1+direction
; // +1 for conversion to character pos 
2347         // First skip current text to space 
2348         while (i 
< endPos 
&& i 
> -1) 
2350             // i is in character, not caret positions 
2351             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2352             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2353             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
2357             else if (!wxRichTextCtrlIsWhitespace(text
) && !text
.empty()) 
2364         while (i 
< endPos 
&& i 
> -1) 
2366             // i is in character, not caret positions 
2367             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2368             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2369             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
2370                 return wxMax(-1, i
); 
2372             if (text
.empty()) // End of paragraph, or maybe an image 
2373                 return wxMax(-1, i 
- 1); 
2374             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
2378                 // Convert to caret position 
2379                 return wxMax(-1, i 
- 1); 
2388         long i 
= m_caretPosition
; 
2390         // First skip white space 
2391         while (i 
< endPos 
&& i 
> -1) 
2393             // i is in character, not caret positions 
2394             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2395             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2397             if (text
.empty() || (line 
&& (i 
== line
->GetAbsoluteRange().GetStart()))) // End of paragraph, or maybe an image 
2399             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
2404         // Next skip current text to space 
2405         while (i 
< endPos 
&& i 
> -1) 
2407             // i is in character, not caret positions 
2408             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2409             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2410             if (line 
&& line
->GetAbsoluteRange().GetStart() == i
) 
2413             if (!wxRichTextCtrlIsWhitespace(text
) /* && !text.empty() */) 
2426 /// Move n words left 
2427 bool wxRichTextCtrl::WordLeft(int WXUNUSED(n
), int flags
) 
2429     long pos 
= FindNextWordPosition(-1); 
2430     if (pos 
!= m_caretPosition
) 
2432         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
, true); 
2434         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2438         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
2440         SetDefaultStyleToCursorStyle(); 
2448 /// Move n words right 
2449 bool wxRichTextCtrl::WordRight(int WXUNUSED(n
), int flags
) 
2451     long pos 
= FindNextWordPosition(1); 
2452     if (pos 
!= m_caretPosition
) 
2454         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
, true); 
2456         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2460         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
2462         SetDefaultStyleToCursorStyle(); 
2471 void wxRichTextCtrl::OnSize(wxSizeEvent
& event
) 
2473     // Only do sizing optimization for large buffers 
2474     if (GetBuffer().GetOwnRange().GetEnd() > m_delayedLayoutThreshold
) 
2476         m_fullLayoutRequired 
= true; 
2477         m_fullLayoutTime 
= wxGetLocalTimeMillis(); 
2478         m_fullLayoutSavedPosition 
= GetFirstVisiblePosition(); 
2479         LayoutContent(true /* onlyVisibleRect */); 
2482         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2484 #if wxRICHTEXT_BUFFERED_PAINTING 
2491 // Force any pending layout due to large buffer 
2492 void wxRichTextCtrl::ForceDelayedLayout() 
2494     if (m_fullLayoutRequired
) 
2496         m_fullLayoutRequired 
= false; 
2497         m_fullLayoutTime 
= 0; 
2498         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2499         ShowPosition(m_fullLayoutSavedPosition
); 
2505 /// Idle-time processing 
2506 void wxRichTextCtrl::OnIdle(wxIdleEvent
& event
) 
2508 #if wxRICHTEXT_USE_OWN_CARET 
2509     if (((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
2511         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(false); 
2517     const int layoutInterval 
= wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL
; 
2519     if (m_fullLayoutRequired 
&& (wxGetLocalTimeMillis() > (m_fullLayoutTime 
+ layoutInterval
))) 
2521         m_fullLayoutRequired 
= false; 
2522         m_fullLayoutTime 
= 0; 
2523         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2524         ShowPosition(m_fullLayoutSavedPosition
); 
2528     if (m_caretPositionForDefaultStyle 
!= -2) 
2530         // If the caret position has changed, no longer reflect the default style 
2532         if (GetCaretPosition() != m_caretPositionForDefaultStyle
) 
2533             m_caretPositionForDefaultStyle 
= -2; 
2540 void wxRichTextCtrl::OnScroll(wxScrollWinEvent
& event
) 
2542 #if wxRICHTEXT_USE_OWN_CARET 
2543     if (!((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
2546         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(); 
2553 /// Set up scrollbars, e.g. after a resize 
2554 void wxRichTextCtrl::SetupScrollbars(bool atTop
) 
2559     if (GetBuffer().IsEmpty() || !m_verticalScrollbarEnabled
) 
2561         SetScrollbars(0, 0, 0, 0, 0, 0); 
2565     // TODO: reimplement scrolling so we scroll by line, not by fixed number 
2566     // of pixels. See e.g. wxVScrolledWindow for ideas. 
2567     int pixelsPerUnit 
= 5; 
2568     wxSize clientSize 
= GetClientSize(); 
2570     int maxHeight 
= GetBuffer().GetCachedSize().y 
+ GetBuffer().GetTopMargin(); 
2572     // Round up so we have at least maxHeight pixels 
2573     int unitsY 
= (int) (((float)maxHeight
/(float)pixelsPerUnit
) + 0.5); 
2575     int startX 
= 0, startY 
= 0; 
2577         GetViewStart(& startX
, & startY
); 
2579     int maxPositionX 
= 0; 
2580     int maxPositionY 
= (int) ((((float)(wxMax((unitsY
*pixelsPerUnit
) - clientSize
.y
, 0)))/((float)pixelsPerUnit
)) + 0.5); 
2582     int newStartX 
= wxMin(maxPositionX
, startX
); 
2583     int newStartY 
= wxMin(maxPositionY
, startY
); 
2585     int oldPPUX
, oldPPUY
; 
2586     int oldStartX
, oldStartY
; 
2587     int oldVirtualSizeX 
= 0, oldVirtualSizeY 
= 0; 
2588     GetScrollPixelsPerUnit(& oldPPUX
, & oldPPUY
); 
2589     GetViewStart(& oldStartX
, & oldStartY
); 
2590     GetVirtualSize(& oldVirtualSizeX
, & oldVirtualSizeY
); 
2592         oldVirtualSizeY 
/= oldPPUY
; 
2594     if (oldPPUX 
== 0 && oldPPUY 
== pixelsPerUnit 
&& oldVirtualSizeY 
== unitsY 
&& oldStartX 
== newStartX 
&& oldStartY 
== newStartY
) 
2597     // Don't set scrollbars if there were none before, and there will be none now. 
2598     if (oldPPUY 
!= 0 && (oldVirtualSizeY
*oldPPUY 
< clientSize
.y
) && (unitsY
*pixelsPerUnit 
< clientSize
.y
)) 
2601     // Move to previous scroll position if 
2603     SetScrollbars(0, pixelsPerUnit
, 0, unitsY
, newStartX
, newStartY
); 
2606 /// Paint the background 
2607 void wxRichTextCtrl::PaintBackground(wxDC
& dc
) 
2609     wxColour backgroundColour 
= GetBackgroundColour(); 
2610     if (!backgroundColour
.IsOk()) 
2611         backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
2613     // Clear the background 
2614     dc
.SetBrush(wxBrush(backgroundColour
)); 
2615     dc
.SetPen(*wxTRANSPARENT_PEN
); 
2616     wxRect 
windowRect(GetClientSize()); 
2617     windowRect
.x 
-= 2; windowRect
.y 
-= 2; 
2618     windowRect
.width 
+= 4; windowRect
.height 
+= 4; 
2620     // We need to shift the rectangle to take into account 
2621     // scrolling. Converting device to logical coordinates. 
2622     CalcUnscrolledPosition(windowRect
.x
, windowRect
.y
, & windowRect
.x
, & windowRect
.y
); 
2623     dc
.DrawRectangle(windowRect
); 
2626 #if wxRICHTEXT_BUFFERED_PAINTING 
2627 /// Recreate buffer bitmap if necessary 
2628 bool wxRichTextCtrl::RecreateBuffer(const wxSize
& size
) 
2631     if (sz 
== wxDefaultSize
) 
2632         sz 
= GetClientSize(); 
2634     if (sz
.x 
< 1 || sz
.y 
< 1) 
2637     if (!m_bufferBitmap
.IsOk() || m_bufferBitmap
.GetWidth() < sz
.x 
|| m_bufferBitmap
.GetHeight() < sz
.y
) 
2638         m_bufferBitmap 
= wxBitmap(sz
.x
, sz
.y
); 
2639     return m_bufferBitmap
.IsOk(); 
2643 // ---------------------------------------------------------------------------- 
2644 // file IO functions 
2645 // ---------------------------------------------------------------------------- 
2647 bool wxRichTextCtrl::DoLoadFile(const wxString
& filename
, int fileType
) 
2649     bool success 
= GetBuffer().LoadFile(filename
, (wxRichTextFileType
)fileType
); 
2651         m_filename 
= filename
; 
2654     SetInsertionPoint(0); 
2657     SetupScrollbars(true); 
2659     wxTextCtrl::SendTextUpdatedEvent(this); 
2665         wxLogError(_("File couldn't be loaded.")); 
2671 bool wxRichTextCtrl::DoSaveFile(const wxString
& filename
, int fileType
) 
2673     if (GetBuffer().SaveFile(filename
, (wxRichTextFileType
)fileType
)) 
2675         m_filename 
= filename
; 
2682     wxLogError(_("The text couldn't be saved.")); 
2687 // ---------------------------------------------------------------------------- 
2688 // wxRichTextCtrl specific functionality 
2689 // ---------------------------------------------------------------------------- 
2691 /// Add a new paragraph of text to the end of the buffer 
2692 wxRichTextRange 
wxRichTextCtrl::AddParagraph(const wxString
& text
) 
2694     wxRichTextRange range 
= GetFocusObject()->AddParagraph(text
); 
2695     GetBuffer().Invalidate(); 
2701 wxRichTextRange 
wxRichTextCtrl::AddImage(const wxImage
& image
) 
2703     wxRichTextRange range 
= GetFocusObject()->AddImage(image
); 
2704     GetBuffer().Invalidate(); 
2709 // ---------------------------------------------------------------------------- 
2710 // selection and ranges 
2711 // ---------------------------------------------------------------------------- 
2713 void wxRichTextCtrl::SelectAll() 
2715     SetSelection(-1, -1); 
2719 void wxRichTextCtrl::SelectNone() 
2721     if (m_selection
.IsValid()) 
2723         wxRichTextSelection oldSelection 
= m_selection
; 
2725         m_selection
.Reset(); 
2727         RefreshForSelectionChange(oldSelection
, m_selection
); 
2729     m_selectionAnchor 
= -2; 
2730     m_selectionAnchorObject 
= NULL
; 
2731     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
2734 static bool wxIsWordDelimiter(const wxString
& text
) 
2736     return !text
.IsEmpty() && !wxIsalnum(text
[0]); 
2739 /// Select the word at the given character position 
2740 bool wxRichTextCtrl::SelectWord(long position
) 
2742     if (position 
< 0 || position 
> GetFocusObject()->GetOwnRange().GetEnd()) 
2745     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(position
); 
2749     if (position 
== para
->GetRange().GetEnd()) 
2752     long positionStart 
= position
; 
2753     long positionEnd 
= position
; 
2755     for (positionStart 
= position
; positionStart 
>= para
->GetRange().GetStart(); positionStart 
--) 
2757         wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(positionStart
, positionStart
)); 
2758         if (wxIsWordDelimiter(text
)) 
2764     if (positionStart 
< para
->GetRange().GetStart()) 
2765         positionStart 
= para
->GetRange().GetStart(); 
2767     for (positionEnd 
= position
; positionEnd 
< para
->GetRange().GetEnd(); positionEnd 
++) 
2769         wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(positionEnd
, positionEnd
)); 
2770         if (wxIsWordDelimiter(text
)) 
2776     if (positionEnd 
>= para
->GetRange().GetEnd()) 
2777         positionEnd 
= para
->GetRange().GetEnd(); 
2779     if (positionEnd 
< positionStart
) 
2782     SetSelection(positionStart
, positionEnd
+1); 
2784     if (positionStart 
>= 0) 
2786         MoveCaret(positionStart
-1, true); 
2787         SetDefaultStyleToCursorStyle(); 
2793 wxString 
wxRichTextCtrl::GetStringSelection() const 
2796     GetSelection(&from
, &to
); 
2798     return GetRange(from
, to
); 
2801 // ---------------------------------------------------------------------------- 
2803 // ---------------------------------------------------------------------------- 
2805 wxTextCtrlHitTestResult
 
2806 wxRichTextCtrl::HitTest(const wxPoint
& pt
, wxTextCoord 
*x
, wxTextCoord 
*y
) const 
2808     // implement in terms of the other overload as the native ports typically 
2809     // can get the position and not (x, y) pair directly (although wxUniv 
2810     // directly gets x and y -- and so overrides this method as well) 
2812     wxTextCtrlHitTestResult rc 
= HitTest(pt
, &pos
); 
2814     if ( rc 
!= wxTE_HT_UNKNOWN 
) 
2816         PositionToXY(pos
, x
, y
); 
2822 wxTextCtrlHitTestResult
 
2823 wxRichTextCtrl::HitTest(const wxPoint
& pt
, 
2826     wxClientDC 
dc((wxRichTextCtrl
*) this); 
2827     ((wxRichTextCtrl
*)this)->PrepareDC(dc
); 
2829     // Buffer uses logical position (relative to start of buffer) 
2831     wxPoint pt2 
= GetLogicalPoint(pt
); 
2833     wxRichTextObject
* hitObj 
= NULL
; 
2834     wxRichTextObject
* contextObj 
= NULL
; 
2835     wxRichTextDrawingContext 
context((wxRichTextBuffer
*) & GetBuffer()); 
2836     int hit 
= ((wxRichTextCtrl
*)this)->GetFocusObject()->HitTest(dc
, context
, pt2
, *pos
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
); 
2838     if ((hit 
& wxRICHTEXT_HITTEST_BEFORE
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2839         return wxTE_HT_BEFORE
; 
2840     else if ((hit 
& wxRICHTEXT_HITTEST_AFTER
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2841         return wxTE_HT_BEYOND
; 
2842     else if (hit 
& (wxRICHTEXT_HITTEST_BEFORE
|wxRICHTEXT_HITTEST_AFTER
)) 
2843         return wxTE_HT_ON_TEXT
; 
2845     return wxTE_HT_UNKNOWN
; 
2848 wxRichTextParagraphLayoutBox
* 
2849 wxRichTextCtrl::FindContainerAtPoint(const wxPoint pt
, long& position
, int& hit
, wxRichTextObject
* hitObj
, int flags
/* = 0*/) 
2851     wxClientDC 
dc(this); 
2853     dc
.SetFont(GetFont()); 
2855     wxPoint logicalPt 
= GetLogicalPoint(pt
); 
2857     wxRichTextObject
* contextObj 
= NULL
; 
2858     wxRichTextDrawingContext 
context(& GetBuffer()); 
2859     hit 
= GetBuffer().HitTest(dc
, context
, logicalPt
, position
, &hitObj
, &contextObj
, flags
); 
2860     wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
2866 // ---------------------------------------------------------------------------- 
2867 // set/get the controls text 
2868 // ---------------------------------------------------------------------------- 
2870 wxString 
wxRichTextCtrl::DoGetValue() const 
2872     return GetBuffer().GetText(); 
2875 wxString 
wxRichTextCtrl::GetRange(long from
, long to
) const 
2877     // Public API for range is different from internals 
2878     return GetFocusObject()->GetTextForRange(wxRichTextRange(from
, to
-1)); 
2881 void wxRichTextCtrl::DoSetValue(const wxString
& value
, int flags
) 
2883     // Don't call Clear here, since it always sends a text updated event 
2884     m_buffer
.ResetAndClearCommands(); 
2885     m_buffer
.Invalidate(wxRICHTEXT_ALL
); 
2886     m_caretPosition 
= -1; 
2887     m_caretPositionForDefaultStyle 
= -2; 
2888     m_caretAtLineStart 
= false; 
2889     m_selection
.Reset(); 
2890     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
2900     if (!value
.IsEmpty()) 
2902         // Remove empty paragraph 
2903         GetBuffer().Clear(); 
2904         DoWriteText(value
, flags
); 
2906         // for compatibility, don't move the cursor when doing SetValue() 
2907         SetInsertionPoint(0); 
2911         // still send an event for consistency 
2912         if (flags 
& SetValue_SendEvent
) 
2913             wxTextCtrl::SendTextUpdatedEvent(this); 
2918 void wxRichTextCtrl::WriteText(const wxString
& value
) 
2923 void wxRichTextCtrl::DoWriteText(const wxString
& value
, int flags
) 
2925     wxString valueUnix 
= wxTextFile::Translate(value
, wxTextFileType_Unix
); 
2927     GetFocusObject()->InsertTextWithUndo(& GetBuffer(), m_caretPosition
+1, valueUnix
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2929     if ( flags 
& SetValue_SendEvent 
) 
2930         wxTextCtrl::SendTextUpdatedEvent(this); 
2933 void wxRichTextCtrl::AppendText(const wxString
& text
) 
2935     SetInsertionPointEnd(); 
2940 /// Write an image at the current insertion point 
2941 bool wxRichTextCtrl::WriteImage(const wxImage
& image
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2943     wxRichTextImageBlock imageBlock
; 
2945     wxImage image2 
= image
; 
2946     if (imageBlock
.MakeImageBlock(image2
, bitmapType
)) 
2947         return WriteImage(imageBlock
, textAttr
); 
2952 bool wxRichTextCtrl::WriteImage(const wxString
& filename
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2954     wxRichTextImageBlock imageBlock
; 
2957     if (imageBlock
.MakeImageBlock(filename
, bitmapType
, image
, false)) 
2958         return WriteImage(imageBlock
, textAttr
); 
2963 bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock
& imageBlock
, const wxRichTextAttr
& textAttr
) 
2965     return GetFocusObject()->InsertImageWithUndo(& GetBuffer(), m_caretPosition
+1, imageBlock
, this, 0, textAttr
); 
2968 bool wxRichTextCtrl::WriteImage(const wxBitmap
& bitmap
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2972         wxRichTextImageBlock imageBlock
; 
2974         wxImage image 
= bitmap
.ConvertToImage(); 
2975         if (image
.IsOk() && imageBlock
.MakeImageBlock(image
, bitmapType
)) 
2976             return WriteImage(imageBlock
, textAttr
); 
2982 // Write a text box at the current insertion point. 
2983 wxRichTextBox
* wxRichTextCtrl::WriteTextBox(const wxRichTextAttr
& textAttr
) 
2985     wxRichTextBox
* textBox 
= new wxRichTextBox
; 
2986     textBox
->SetAttributes(textAttr
); 
2987     textBox
->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style 
2988     textBox
->AddParagraph(wxEmptyString
); 
2989     textBox
->SetParent(NULL
); 
2991     // The object returned is the one actually inserted into the buffer, 
2992     // while the original one is deleted. 
2993     wxRichTextObject
* obj 
= GetFocusObject()->InsertObjectWithUndo(& GetBuffer(), m_caretPosition
+1, textBox
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2994     wxRichTextBox
* box 
= wxDynamicCast(obj
, wxRichTextBox
); 
2998 // Write a table at the current insertion point, returning the table. 
2999 wxRichTextTable
* wxRichTextCtrl::WriteTable(int rows
, int cols
, const wxRichTextAttr
& tableAttr
, const wxRichTextAttr
& cellAttr
) 
3001     wxASSERT(rows 
> 0 && cols 
> 0); 
3003     if (rows 
<= 0 || cols 
<= 0) 
3006     wxRichTextTable
* table 
= new wxRichTextTable
; 
3007     table
->SetAttributes(tableAttr
); 
3008     table
->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style 
3010     table
->CreateTable(rows
, cols
); 
3012     table
->SetParent(NULL
); 
3015     for (j 
= 0; j 
< rows
; j
++) 
3017         for (i 
= 0; i 
< cols
; i
++) 
3019             table
->GetCell(j
, i
)->GetAttributes() = cellAttr
; 
3023     // The object returned is the one actually inserted into the buffer, 
3024     // while the original one is deleted. 
3025     wxRichTextObject
* obj 
= GetFocusObject()->InsertObjectWithUndo(& GetBuffer(), m_caretPosition
+1, table
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
3026     wxRichTextTable
* tableResult 
= wxDynamicCast(obj
, wxRichTextTable
); 
3031 /// Insert a newline (actually paragraph) at the current insertion point. 
3032 bool wxRichTextCtrl::Newline() 
3034     return GetFocusObject()->InsertNewlineWithUndo(& GetBuffer(), m_caretPosition
+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
3037 /// Insert a line break at the current insertion point. 
3038 bool wxRichTextCtrl::LineBreak() 
3041     text 
= wxRichTextLineBreakChar
; 
3042     return GetFocusObject()->InsertTextWithUndo(& GetBuffer(), m_caretPosition
+1, text
, this); 
3045 // ---------------------------------------------------------------------------- 
3046 // Clipboard operations 
3047 // ---------------------------------------------------------------------------- 
3049 void wxRichTextCtrl::Copy() 
3053         wxRichTextRange range 
= GetInternalSelectionRange(); 
3054         GetBuffer().CopyToClipboard(range
); 
3058 void wxRichTextCtrl::Cut() 
3062         wxRichTextRange range 
= GetInternalSelectionRange(); 
3063         GetBuffer().CopyToClipboard(range
); 
3065         DeleteSelectedContent(); 
3071 void wxRichTextCtrl::Paste() 
3075         BeginBatchUndo(_("Paste")); 
3077         long newPos 
= m_caretPosition
; 
3078         DeleteSelectedContent(& newPos
); 
3080         GetBuffer().PasteFromClipboard(newPos
); 
3086 void wxRichTextCtrl::DeleteSelection() 
3088     if (CanDeleteSelection()) 
3090         DeleteSelectedContent(); 
3094 bool wxRichTextCtrl::HasSelection() const 
3096     return (m_selection
.IsValid() && m_selection
.GetContainer() == GetFocusObject()); 
3099 bool wxRichTextCtrl::HasUnfocusedSelection() const 
3101     return m_selection
.IsValid(); 
3104 bool wxRichTextCtrl::CanCopy() const 
3106     // Can copy if there's a selection 
3107     return HasSelection(); 
3110 bool wxRichTextCtrl::CanCut() const 
3112     return CanDeleteSelection(); 
3115 bool wxRichTextCtrl::CanPaste() const 
3117     if ( !IsEditable() || !GetFocusObject() || !CanInsertContent(* GetFocusObject(), m_caretPosition
+1)) 
3120     return GetBuffer().CanPasteFromClipboard(); 
3123 bool wxRichTextCtrl::CanDeleteSelection() const 
3125     return HasSelection() && IsEditable() && CanDeleteRange(* GetFocusObject(), GetSelectionRange()); 
3129 // ---------------------------------------------------------------------------- 
3131 // ---------------------------------------------------------------------------- 
3133 void wxRichTextCtrl::SetContextMenu(wxMenu
* menu
) 
3135     if (m_contextMenu 
&& m_contextMenu 
!= menu
) 
3136         delete m_contextMenu
; 
3137     m_contextMenu 
= menu
; 
3140 void wxRichTextCtrl::SetEditable(bool editable
) 
3142     m_editable 
= editable
; 
3145 void wxRichTextCtrl::SetInsertionPoint(long pos
) 
3149     m_caretPosition 
= pos 
- 1; 
3153     SetDefaultStyleToCursorStyle(); 
3156 void wxRichTextCtrl::SetInsertionPointEnd() 
3158     long pos 
= GetLastPosition(); 
3159     SetInsertionPoint(pos
); 
3162 long wxRichTextCtrl::GetInsertionPoint() const 
3164     return m_caretPosition
+1; 
3167 wxTextPos 
wxRichTextCtrl::GetLastPosition() const 
3169     return GetFocusObject()->GetOwnRange().GetEnd(); 
3172 // If the return values from and to are the same, there is no 
3174 void wxRichTextCtrl::GetSelection(long* from
, long* to
) const 
3176     if (m_selection
.IsValid()) 
3178         *from 
= m_selection
.GetRange().GetStart(); 
3179         *to 
= m_selection
.GetRange().GetEnd(); 
3189 bool wxRichTextCtrl::IsEditable() const 
3194 // ---------------------------------------------------------------------------- 
3196 // ---------------------------------------------------------------------------- 
3198 void wxRichTextCtrl::SetSelection(long from
, long to
) 
3200     // if from and to are both -1, it means (in wxWidgets) that all text should 
3202     if ( (from 
== -1) && (to 
== -1) ) 
3205         to 
= GetLastPosition()+1; 
3214         wxRichTextSelection oldSelection 
= m_selection
; 
3216         m_selectionAnchor 
= from
-1; 
3217         m_selectionAnchorObject 
= NULL
; 
3218         m_selection
.Set(wxRichTextRange(from
, to
-1), GetFocusObject()); 
3220         m_caretPosition 
= wxMax(-1, to
-1); 
3222         RefreshForSelectionChange(oldSelection
, m_selection
); 
3227 // ---------------------------------------------------------------------------- 
3229 // ---------------------------------------------------------------------------- 
3231 void wxRichTextCtrl::Replace(long from
, long to
, 
3232                              const wxString
& value
) 
3234     BeginBatchUndo(_("Replace")); 
3236     SetSelection(from
, to
); 
3238     wxRichTextAttr attr 
= GetDefaultStyle(); 
3240     DeleteSelectedContent(); 
3242     SetDefaultStyle(attr
); 
3244     DoWriteText(value
, SetValue_SelectionOnly
); 
3249 void wxRichTextCtrl::Remove(long from
, long to
) 
3253     GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(from
, to
-1), this, & GetBuffer()); 
3260 bool wxRichTextCtrl::IsModified() const 
3262     return m_buffer
.IsModified(); 
3265 void wxRichTextCtrl::MarkDirty() 
3267     m_buffer
.Modify(true); 
3270 void wxRichTextCtrl::DiscardEdits() 
3272     m_caretPositionForDefaultStyle 
= -2; 
3273     m_buffer
.Modify(false); 
3274     m_buffer
.GetCommandProcessor()->ClearCommands(); 
3277 int wxRichTextCtrl::GetNumberOfLines() const 
3279     return GetFocusObject()->GetParagraphCount(); 
3282 // ---------------------------------------------------------------------------- 
3283 // Positions <-> coords 
3284 // ---------------------------------------------------------------------------- 
3286 long wxRichTextCtrl::XYToPosition(long x
, long y
) const 
3288     return GetFocusObject()->XYToPosition(x
, y
); 
3291 bool wxRichTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
3293     return GetFocusObject()->PositionToXY(pos
, x
, y
); 
3296 // ---------------------------------------------------------------------------- 
3298 // ---------------------------------------------------------------------------- 
3300 void wxRichTextCtrl::ShowPosition(long pos
) 
3302     if (!IsPositionVisible(pos
)) 
3303         ScrollIntoView(pos
-1, WXK_DOWN
); 
3306 int wxRichTextCtrl::GetLineLength(long lineNo
) const 
3308     return GetFocusObject()->GetParagraphLength(lineNo
); 
3311 wxString 
wxRichTextCtrl::GetLineText(long lineNo
) const 
3313     return GetFocusObject()->GetParagraphText(lineNo
); 
3316 // ---------------------------------------------------------------------------- 
3318 // ---------------------------------------------------------------------------- 
3320 void wxRichTextCtrl::Undo() 
3324         GetCommandProcessor()->Undo(); 
3328 void wxRichTextCtrl::Redo() 
3332         GetCommandProcessor()->Redo(); 
3336 bool wxRichTextCtrl::CanUndo() const 
3338     return GetCommandProcessor()->CanUndo() && IsEditable(); 
3341 bool wxRichTextCtrl::CanRedo() const 
3343     return GetCommandProcessor()->CanRedo() && IsEditable(); 
3346 // ---------------------------------------------------------------------------- 
3347 // implementation details 
3348 // ---------------------------------------------------------------------------- 
3350 void wxRichTextCtrl::Command(wxCommandEvent
& event
) 
3352     SetValue(event
.GetString()); 
3353     GetEventHandler()->ProcessEvent(event
); 
3356 void wxRichTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
3358     // By default, load the first file into the text window. 
3359     if (event
.GetNumberOfFiles() > 0) 
3361         LoadFile(event
.GetFiles()[0]); 
3365 wxSize 
wxRichTextCtrl::DoGetBestSize() const 
3367     return wxSize(10, 10); 
3370 // ---------------------------------------------------------------------------- 
3371 // standard handlers for standard edit menu events 
3372 // ---------------------------------------------------------------------------- 
3374 void wxRichTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
3379 void wxRichTextCtrl::OnClear(wxCommandEvent
& WXUNUSED(event
)) 
3384 void wxRichTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
3389 void wxRichTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
3394 void wxRichTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
3399 void wxRichTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
3404 void wxRichTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
3406     event
.Enable( CanCut() ); 
3409 void wxRichTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
3411     event
.Enable( CanCopy() ); 
3414 void wxRichTextCtrl::OnUpdateClear(wxUpdateUIEvent
& event
) 
3416     event
.Enable( CanDeleteSelection() ); 
3419 void wxRichTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
3421     event
.Enable( CanPaste() ); 
3424 void wxRichTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
3426     event
.Enable( CanUndo() ); 
3427     event
.SetText( GetCommandProcessor()->GetUndoMenuLabel() ); 
3430 void wxRichTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
3432     event
.Enable( CanRedo() ); 
3433     event
.SetText( GetCommandProcessor()->GetRedoMenuLabel() ); 
3436 void wxRichTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
3438     if (GetLastPosition() > 0) 
3442 void wxRichTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
3444     event
.Enable(GetLastPosition() > 0); 
3447 void wxRichTextCtrl::OnProperties(wxCommandEvent
& event
) 
3449     int idx 
= event
.GetId() - wxID_RICHTEXT_PROPERTIES1
; 
3450     if (idx 
>= 0 && idx 
< m_contextMenuPropertiesInfo
.GetCount()) 
3452         wxRichTextObject
* obj 
= m_contextMenuPropertiesInfo
.GetObject(idx
); 
3453         if (obj 
&& CanEditProperties(obj
)) 
3454             EditProperties(obj
, this); 
3456         m_contextMenuPropertiesInfo
.Clear(); 
3460 void wxRichTextCtrl::OnUpdateProperties(wxUpdateUIEvent
& event
) 
3462     int idx 
= event
.GetId() - wxID_RICHTEXT_PROPERTIES1
; 
3463     event
.Enable(idx 
>= 0 && idx 
< m_contextMenuPropertiesInfo
.GetCount()); 
3466 void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent
& event
) 
3468     if (event
.GetEventObject() != this) 
3474     ShowContextMenu(m_contextMenu
, event
.GetPosition()); 
3477 // Prepares the context menu, adding appropriate property-editing commands. 
3478 // Returns the number of property commands added. 
3479 int wxRichTextCtrl::PrepareContextMenu(wxMenu
* menu
, const wxPoint
& pt
, bool addPropertyCommands
) 
3481     wxClientDC 
dc(this); 
3483     dc
.SetFont(GetFont()); 
3485     m_contextMenuPropertiesInfo
.Clear(); 
3488     wxRichTextObject
* hitObj 
= NULL
; 
3489     wxRichTextObject
* contextObj 
= NULL
; 
3490     if (pt 
!= wxDefaultPosition
) 
3492         wxPoint logicalPt 
= GetLogicalPoint(ScreenToClient(pt
)); 
3493         wxRichTextDrawingContext 
context(& GetBuffer()); 
3494         int hit 
= GetBuffer().HitTest(dc
, context
, logicalPt
, position
, & hitObj
, & contextObj
); 
3496         if (hit 
== wxRICHTEXT_HITTEST_ON 
|| hit 
== wxRICHTEXT_HITTEST_BEFORE 
|| hit 
== wxRICHTEXT_HITTEST_AFTER
) 
3498             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
3499             if (hitObj 
&& actualContainer
) 
3501                 if (actualContainer
->AcceptsFocus()) 
3503                     SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
3504                     SetCaretPositionAfterClick(actualContainer
, position
, hit
); 
3507                 if (addPropertyCommands
) 
3508                     m_contextMenuPropertiesInfo
.AddItems(this, actualContainer
, hitObj
); 
3512                 if (addPropertyCommands
) 
3513                     m_contextMenuPropertiesInfo
.AddItems(this, GetFocusObject(), NULL
); 
3518             if (addPropertyCommands
) 
3519                 m_contextMenuPropertiesInfo
.AddItems(this, GetFocusObject(), NULL
); 
3524         // Invoked from the keyboard, so don't set the caret position and don't use the event 
3526         hitObj 
= GetFocusObject()->GetLeafObjectAtPosition(m_caretPosition
+1); 
3528             contextObj 
= hitObj
->GetParentContainer(); 
3530             contextObj 
= GetFocusObject(); 
3532         wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
3533         if (hitObj 
&& actualContainer
) 
3535             if (addPropertyCommands
) 
3536                 m_contextMenuPropertiesInfo
.AddItems(this, actualContainer
, hitObj
); 
3540             if (addPropertyCommands
) 
3541                 m_contextMenuPropertiesInfo
.AddItems(this, GetFocusObject(), NULL
); 
3547         if (addPropertyCommands
) 
3548             m_contextMenuPropertiesInfo
.AddMenuItems(menu
); 
3549         return m_contextMenuPropertiesInfo
.GetCount(); 
3555 // Shows the context menu, adding appropriate property-editing commands 
3556 bool wxRichTextCtrl::ShowContextMenu(wxMenu
* menu
, const wxPoint
& pt
, bool addPropertyCommands
) 
3560         PrepareContextMenu(menu
, pt
, addPropertyCommands
); 
3568 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
3570     return GetFocusObject()->SetStyle(wxRichTextRange(start
, end
-1), wxRichTextAttr(style
)); 
3573 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxRichTextAttr
& style
) 
3575     return GetFocusObject()->SetStyle(wxRichTextRange(start
, end
-1), style
); 
3578 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxTextAttr
& style
) 
3580     return GetFocusObject()->SetStyle(range
.ToInternal(), wxRichTextAttr(style
)); 
3583 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxRichTextAttr
& style
) 
3585     return GetFocusObject()->SetStyle(range
.ToInternal(), style
); 
3588 void wxRichTextCtrl::SetStyle(wxRichTextObject 
*obj
, const wxRichTextAttr
& textAttr
) 
3590     GetFocusObject()->SetStyle(obj
, textAttr
); 
3593 // extended style setting operation with flags including: 
3594 // wxRICHTEXT_SETSTYLE_WITH_UNDO, wxRICHTEXT_SETSTYLE_OPTIMIZE, wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY. 
3595 // see richtextbuffer.h for more details. 
3597 bool wxRichTextCtrl::SetStyleEx(const wxRichTextRange
& range
, const wxRichTextAttr
& style
, int flags
) 
3599     return GetFocusObject()->SetStyle(range
.ToInternal(), style
, flags
); 
3602 bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
3604     return GetBuffer().SetDefaultStyle(style
); 
3607 bool wxRichTextCtrl::SetDefaultStyle(const wxRichTextAttr
& style
) 
3609     wxRichTextAttr 
attr1(style
); 
3610     attr1
.GetTextBoxAttr().Reset(); 
3611     return GetBuffer().SetDefaultStyle(attr1
); 
3614 const wxRichTextAttr
& wxRichTextCtrl::GetDefaultStyleEx() const 
3616     return GetBuffer().GetDefaultStyle(); 
3619 bool wxRichTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
3621     wxRichTextAttr attr
; 
3622     if (GetFocusObject()->GetStyle(position
, attr
)) 
3631 bool wxRichTextCtrl::GetStyle(long position
, wxRichTextAttr
& style
) 
3633     return GetFocusObject()->GetStyle(position
, style
); 
3636 bool wxRichTextCtrl::GetStyle(long position
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3638     wxRichTextAttr attr
; 
3639     if (container
->GetStyle(position
, attr
)) 
3648 // get the common set of styles for the range 
3649 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxTextAttr
& style
) 
3651     wxRichTextAttr attr
; 
3652     if (GetFocusObject()->GetStyleForRange(range
.ToInternal(), attr
)) 
3661 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxRichTextAttr
& style
) 
3663     return GetFocusObject()->GetStyleForRange(range
.ToInternal(), style
); 
3666 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3668     return container
->GetStyleForRange(range
.ToInternal(), style
); 
3671 /// Get the content (uncombined) attributes for this position. 
3672 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxRichTextAttr
& style
) 
3674     return GetFocusObject()->GetUncombinedStyle(position
, style
); 
3677 /// Get the content (uncombined) attributes for this position. 
3678 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3680     return container
->GetUncombinedStyle(position
, style
); 
3683 bool wxRichTextCtrl::SetProperties(const wxRichTextRange
& range
, const wxRichTextProperties
& properties
, int flags
) 
3685     return GetFocusObject()->SetProperties(range
.ToInternal(), properties
, flags
); 
3688 /// Set font, and also the buffer attributes 
3689 bool wxRichTextCtrl::SetFont(const wxFont
& font
) 
3691     wxControl::SetFont(font
); 
3693     wxRichTextAttr attr 
= GetBuffer().GetAttributes(); 
3695     GetBuffer().SetBasicStyle(attr
); 
3697     GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
3703 /// Transform logical to physical 
3704 wxPoint 
wxRichTextCtrl::GetPhysicalPoint(const wxPoint
& ptLogical
) const 
3707     CalcScrolledPosition(ptLogical
.x
, ptLogical
.y
, & pt
.x
, & pt
.y
); 
3712 /// Transform physical to logical 
3713 wxPoint 
wxRichTextCtrl::GetLogicalPoint(const wxPoint
& ptPhysical
) const 
3716     CalcUnscrolledPosition(ptPhysical
.x
, ptPhysical
.y
, & pt
.x
, & pt
.y
); 
3721 /// Position the caret 
3722 void wxRichTextCtrl::PositionCaret(wxRichTextParagraphLayoutBox
* container
) 
3727     //wxLogDebug(wxT("PositionCaret")); 
3730     if (GetCaretPositionForIndex(GetCaretPosition(), caretRect
, container
)) 
3732         wxPoint newPt 
= caretRect
.GetPosition(); 
3733         wxSize newSz 
= caretRect
.GetSize(); 
3734         wxPoint pt 
= GetPhysicalPoint(newPt
); 
3735         if (GetCaret()->GetPosition() != pt 
|| GetCaret()->GetSize() != newSz
) 
3738             if (GetCaret()->GetSize() != newSz
) 
3739                 GetCaret()->SetSize(newSz
); 
3741             // Adjust size so the caret size and position doesn't appear in the margins 
3742             if (((pt
.y 
+ newSz
.y
) <= GetBuffer().GetTopMargin()) || (pt
.y 
>= (GetClientSize().y 
- GetBuffer().GetBottomMargin()))) 
3747             else if (pt
.y 
< GetBuffer().GetTopMargin() && (pt
.y 
+ newSz
.y
) > GetBuffer().GetTopMargin()) 
3749                 newSz
.y 
-= (GetBuffer().GetTopMargin() - pt
.y
); 
3752                     pt
.y 
= GetBuffer().GetTopMargin(); 
3753                     GetCaret()->SetSize(newSz
); 
3756             else if (pt
.y 
< (GetClientSize().y 
- GetBuffer().GetBottomMargin()) && (pt
.y 
+ newSz
.y
) > (GetClientSize().y 
- GetBuffer().GetBottomMargin())) 
3758                 newSz
.y 
= GetClientSize().y 
- GetBuffer().GetBottomMargin() - pt
.y
; 
3759                 GetCaret()->SetSize(newSz
); 
3762             GetCaret()->Move(pt
); 
3768 /// Get the caret height and position for the given character position 
3769 bool wxRichTextCtrl::GetCaretPositionForIndex(long position
, wxRect
& rect
, wxRichTextParagraphLayoutBox
* container
) 
3771     wxClientDC 
dc(this); 
3772     dc
.SetFont(GetFont()); 
3780         container 
= GetFocusObject(); 
3782     wxRichTextDrawingContext 
context(& GetBuffer()); 
3783     if (container
->FindPosition(dc
, context
, position
, pt
, & height
, m_caretAtLineStart
)) 
3785         // Caret height can't be zero 
3787             height 
= dc
.GetCharHeight(); 
3789         rect 
= wxRect(pt
, wxSize(wxRICHTEXT_DEFAULT_CARET_WIDTH
, height
)); 
3796 /// Gets the line for the visible caret position. If the caret is 
3797 /// shown at the very end of the line, it means the next character is actually 
3798 /// on the following line. So let's get the line we're expecting to find 
3799 /// if this is the case. 
3800 wxRichTextLine
* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPosition
) const 
3802     wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(caretPosition
, true); 
3803     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(caretPosition
, true); 
3806         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
3807         if (caretPosition 
== lineRange
.GetStart()-1 && 
3808             (para
->GetRange().GetStart() != lineRange
.GetStart())) 
3810             if (!m_caretAtLineStart
) 
3811                 line 
= GetFocusObject()->GetLineAtPosition(caretPosition
-1, true); 
3818 /// Move the caret to the given character position 
3819 bool wxRichTextCtrl::MoveCaret(long pos
, bool showAtLineStart
, wxRichTextParagraphLayoutBox
* container
) 
3821     if (GetBuffer().IsDirty()) 
3825         container 
= GetFocusObject(); 
3827     if (pos 
<= container
->GetOwnRange().GetEnd()) 
3829         SetCaretPosition(pos
, showAtLineStart
); 
3831         PositionCaret(container
); 
3839 /// Layout the buffer: which we must do before certain operations, such as 
3840 /// setting the caret position. 
3841 bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect
) 
3843     if (GetBuffer().IsDirty() || onlyVisibleRect
) 
3845         wxRect 
availableSpace(GetClientSize()); 
3846         if (availableSpace
.width 
== 0) 
3847             availableSpace
.width 
= 10; 
3848         if (availableSpace
.height 
== 0) 
3849             availableSpace
.height 
= 10; 
3851         int flags 
= wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
; 
3852         if (onlyVisibleRect
) 
3854             flags 
|= wxRICHTEXT_LAYOUT_SPECIFIED_RECT
; 
3855             availableSpace
.SetPosition(GetLogicalPoint(wxPoint(0, 0))); 
3858         wxClientDC 
dc(this); 
3859         dc
.SetFont(GetFont()); 
3863         wxRichTextDrawingContext 
context(& GetBuffer()); 
3864         GetBuffer().Defragment(); 
3865         GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation 
3866         GetBuffer().Layout(dc
, context
, availableSpace
, availableSpace
, flags
); 
3867         GetBuffer().Invalidate(wxRICHTEXT_NONE
); 
3876 /// Is all of the selection, or the current caret position, bold? 
3877 bool wxRichTextCtrl::IsSelectionBold() 
3881         wxRichTextAttr attr
; 
3882         wxRichTextRange range 
= GetSelectionRange(); 
3883         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3884         attr
.SetFontWeight(wxFONTWEIGHT_BOLD
); 
3886         return HasCharacterAttributes(range
, attr
); 
3890         // If no selection, then we need to combine current style with default style 
3891         // to see what the effect would be if we started typing. 
3892         wxRichTextAttr attr
; 
3893         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3895         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3896         if (GetStyle(pos
, attr
)) 
3898             if (IsDefaultStyleShowing()) 
3899                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3900             return attr
.GetFontWeight() == wxFONTWEIGHT_BOLD
; 
3906 /// Is all of the selection, or the current caret position, italics? 
3907 bool wxRichTextCtrl::IsSelectionItalics() 
3911         wxRichTextRange range 
= GetSelectionRange(); 
3912         wxRichTextAttr attr
; 
3913         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3914         attr
.SetFontStyle(wxFONTSTYLE_ITALIC
); 
3916         return HasCharacterAttributes(range
, attr
); 
3920         // If no selection, then we need to combine current style with default style 
3921         // to see what the effect would be if we started typing. 
3922         wxRichTextAttr attr
; 
3923         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3925         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3926         if (GetStyle(pos
, attr
)) 
3928             if (IsDefaultStyleShowing()) 
3929                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3930             return attr
.GetFontStyle() == wxFONTSTYLE_ITALIC
; 
3936 /// Is all of the selection, or the current caret position, underlined? 
3937 bool wxRichTextCtrl::IsSelectionUnderlined() 
3941         wxRichTextRange range 
= GetSelectionRange(); 
3942         wxRichTextAttr attr
; 
3943         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3944         attr
.SetFontUnderlined(true); 
3946         return HasCharacterAttributes(range
, attr
); 
3950         // If no selection, then we need to combine current style with default style 
3951         // to see what the effect would be if we started typing. 
3952         wxRichTextAttr attr
; 
3953         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3954         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3956         if (GetStyle(pos
, attr
)) 
3958             if (IsDefaultStyleShowing()) 
3959                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3960             return attr
.GetFontUnderlined(); 
3966 /// Does all of the selection, or the current caret position, have this wxTextAttrEffects flag(s)? 
3967 bool wxRichTextCtrl::DoesSelectionHaveTextEffectFlag(int flag
) 
3969     wxRichTextAttr attr
; 
3970     attr
.SetFlags(wxTEXT_ATTR_EFFECTS
); 
3971     attr
.SetTextEffectFlags(flag
); 
3972     attr
.SetTextEffects(flag
); 
3976         return HasCharacterAttributes(GetSelectionRange(), attr
); 
3980         // If no selection, then we need to combine current style with default style 
3981         // to see what the effect would be if we started typing. 
3982         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3983         if (GetStyle(pos
, attr
)) 
3985             if (IsDefaultStyleShowing()) 
3986                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3987             return (attr
.GetTextEffectFlags() & flag
) != 0; 
3993 /// Apply bold to the selection 
3994 bool wxRichTextCtrl::ApplyBoldToSelection() 
3996     wxRichTextAttr attr
; 
3997     attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3998     attr
.SetFontWeight(IsSelectionBold() ? wxFONTWEIGHT_NORMAL 
: wxFONTWEIGHT_BOLD
); 
4001         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4004         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4005         current
.Apply(attr
); 
4006         SetAndShowDefaultStyle(current
); 
4011 /// Apply italic to the selection 
4012 bool wxRichTextCtrl::ApplyItalicToSelection() 
4014     wxRichTextAttr attr
; 
4015     attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
4016     attr
.SetFontStyle(IsSelectionItalics() ? wxFONTSTYLE_NORMAL 
: wxFONTSTYLE_ITALIC
); 
4019         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4022         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4023         current
.Apply(attr
); 
4024         SetAndShowDefaultStyle(current
); 
4029 /// Apply underline to the selection 
4030 bool wxRichTextCtrl::ApplyUnderlineToSelection() 
4032     wxRichTextAttr attr
; 
4033     attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
4034     attr
.SetFontUnderlined(!IsSelectionUnderlined()); 
4037         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4040         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4041         current
.Apply(attr
); 
4042         SetAndShowDefaultStyle(current
); 
4047 /// Apply the wxTextAttrEffects flag(s) to the selection, or the current caret position if there's no selection 
4048 bool wxRichTextCtrl::ApplyTextEffectToSelection(int flags
) 
4050     wxRichTextAttr attr
; 
4051     attr
.SetFlags(wxTEXT_ATTR_EFFECTS
); 
4052     attr
.SetTextEffectFlags(flags
); 
4053     if (!DoesSelectionHaveTextEffectFlag(flags
)) 
4054         attr
.SetTextEffects(flags
); 
4056         attr
.SetTextEffects(attr
.GetTextEffectFlags() & ~flags
); 
4059         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4062         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4063         current
.Apply(attr
); 
4064         SetAndShowDefaultStyle(current
); 
4069 /// Is all of the selection aligned according to the specified flag? 
4070 bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment
) 
4072     wxRichTextRange range
; 
4074         range 
= GetSelectionRange(); 
4076         range 
= wxRichTextRange(GetCaretPosition()+1, GetCaretPosition()+2); 
4078     wxRichTextAttr attr
; 
4079     attr
.SetAlignment(alignment
); 
4081     return HasParagraphAttributes(range
, attr
); 
4084 /// Apply alignment to the selection 
4085 bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment
) 
4087     wxRichTextAttr attr
; 
4088     attr
.SetAlignment(alignment
); 
4090         return SetStyle(GetSelectionRange(), attr
); 
4093         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(GetCaretPosition()+1); 
4095             return SetStyleEx(para
->GetRange().FromInternal(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
); 
4100 /// Apply a named style to the selection 
4101 bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition
* def
) 
4103     // Flags are defined within each definition, so only certain 
4104     // attributes are applied. 
4105     wxRichTextAttr 
attr(GetStyleSheet() ? def
->GetStyleMergedWithBase(GetStyleSheet()) : def
->GetStyle()); 
4107     int flags 
= wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_RESET
; 
4109     if (def
->IsKindOf(CLASSINFO(wxRichTextListStyleDefinition
))) 
4111         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
4113         wxRichTextRange range
; 
4116             range 
= GetSelectionRange(); 
4119             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
4120             range 
= wxRichTextRange(pos
, pos
+1); 
4123         return SetListStyle(range
, (wxRichTextListStyleDefinition
*) def
, flags
); 
4126     bool isPara 
= false; 
4128     // Make sure the attr has the style name 
4129     if (def
->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition
))) 
4132         attr
.SetParagraphStyleName(def
->GetName()); 
4134         // If applying a paragraph style, we only want the paragraph nodes to adopt these 
4135         // attributes, and not the leaf nodes. This will allow the content (e.g. text) 
4136         // to change its style independently. 
4137         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
4139     else if (def
->IsKindOf(CLASSINFO(wxRichTextCharacterStyleDefinition
))) 
4140         attr
.SetCharacterStyleName(def
->GetName()); 
4141     else if (def
->IsKindOf(CLASSINFO(wxRichTextBoxStyleDefinition
))) 
4142         attr
.GetTextBoxAttr().SetBoxStyleName(def
->GetName()); 
4144     if (def
->IsKindOf(CLASSINFO(wxRichTextBoxStyleDefinition
))) 
4146         if (GetFocusObject() && (GetFocusObject() != & GetBuffer())) 
4148             SetStyle(GetFocusObject(), attr
); 
4154     else if (HasSelection()) 
4155         return SetStyleEx(GetSelectionRange(), attr
, flags
); 
4158         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4159         wxRichTextAttr 
defaultStyle(attr
); 
4162             // Don't apply extra character styles since they are already implied 
4163             // in the paragraph style 
4164             defaultStyle
.SetFlags(defaultStyle
.GetFlags() & ~wxTEXT_ATTR_CHARACTER
); 
4166         current
.Apply(defaultStyle
); 
4167         SetAndShowDefaultStyle(current
); 
4169         // If it's a paragraph style, we want to apply the style to the 
4170         // current paragraph even if we didn't select any text. 
4173             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
4174             wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
); 
4177                 return SetStyleEx(para
->GetRange().FromInternal(), attr
, flags
); 
4184 /// Apply the style sheet to the buffer, for example if the styles have changed. 
4185 bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet
* styleSheet
) 
4188         styleSheet 
= GetBuffer().GetStyleSheet(); 
4192     if (GetBuffer().ApplyStyleSheet(styleSheet
)) 
4194         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
4202 /// Sets the default style to the style under the cursor 
4203 bool wxRichTextCtrl::SetDefaultStyleToCursorStyle() 
4205     wxRichTextAttr attr
; 
4206     attr
.SetFlags(wxTEXT_ATTR_CHARACTER
); 
4208     // If at the start of a paragraph, use the next position. 
4209     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
4211     wxRichTextObject
* obj 
= GetFocusObject()->GetLeafObjectAtPosition(pos
); 
4212     if (obj 
&& obj
->IsTopLevel()) 
4214         // Don't use the attributes of a top-level object, since they might apply 
4215         // to content of the object, e.g. background colour. 
4216         SetDefaultStyle(wxRichTextAttr()); 
4219     else if (GetUncombinedStyle(pos
, attr
)) 
4221         SetDefaultStyle(attr
); 
4228 /// Returns the first visible position in the current view 
4229 long wxRichTextCtrl::GetFirstVisiblePosition() const 
4231     wxRichTextLine
* line 
= GetFocusObject()->GetLineAtYPosition(GetLogicalPoint(wxPoint(0, 0)).y
); 
4233         return line
->GetAbsoluteRange().GetStart(); 
4238 /// Get the first visible point in the window 
4239 wxPoint 
wxRichTextCtrl::GetFirstVisiblePoint() const 
4242     int startXUnits
, startYUnits
; 
4244     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
4245     GetViewStart(& startXUnits
, & startYUnits
); 
4247     return wxPoint(startXUnits 
* ppuX
, startYUnits 
* ppuY
); 
4250 /// The adjusted caret position is the character position adjusted to take 
4251 /// into account whether we're at the start of a paragraph, in which case 
4252 /// style information should be taken from the next position, not current one. 
4253 long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos
) const 
4255     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(caretPos
+1); 
4257     if (para 
&& (caretPos
+1 == para
->GetRange().GetStart())) 
4262 /// Get/set the selection range in character positions. -1, -1 means no selection. 
4263 /// The range is in API convention, i.e. a single character selection is denoted 
4265 wxRichTextRange 
wxRichTextCtrl::GetSelectionRange() const 
4267     wxRichTextRange range 
= GetInternalSelectionRange(); 
4268     if (range 
!= wxRichTextRange(-2,-2) && range 
!= wxRichTextRange(-1,-1)) 
4269         range
.SetEnd(range
.GetEnd() + 1); 
4273 void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange
& range
) 
4275     SetSelection(range
.GetStart(), range
.GetEnd()); 
4279 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
4281     return GetFocusObject()->SetListStyle(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
4284 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
4286     return GetFocusObject()->SetListStyle(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
4289 /// Clear list for given range 
4290 bool wxRichTextCtrl::ClearListStyle(const wxRichTextRange
& range
, int flags
) 
4292     return GetFocusObject()->ClearListStyle(range
.ToInternal(), flags
); 
4295 /// Number/renumber any list elements in the given range 
4296 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
4298     return GetFocusObject()->NumberList(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
4301 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
4303     return GetFocusObject()->NumberList(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
4306 /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 
4307 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int specifiedLevel
) 
4309     return GetFocusObject()->PromoteList(promoteBy
, range
.ToInternal(), def
, flags
, specifiedLevel
); 
4312 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int specifiedLevel
) 
4314     return GetFocusObject()->PromoteList(promoteBy
, range
.ToInternal(), defName
, flags
, specifiedLevel
); 
4317 /// Deletes the content in the given range 
4318 bool wxRichTextCtrl::Delete(const wxRichTextRange
& range
) 
4320     return GetFocusObject()->DeleteRangeWithUndo(range
.ToInternal(), this, & GetBuffer()); 
4323 const wxArrayString
& wxRichTextCtrl::GetAvailableFontNames() 
4325     if (sm_availableFontNames
.GetCount() == 0) 
4327         sm_availableFontNames 
= wxFontEnumerator::GetFacenames(); 
4328         sm_availableFontNames
.Sort(); 
4330     return sm_availableFontNames
; 
4333 void wxRichTextCtrl::ClearAvailableFontNames() 
4335     sm_availableFontNames
.Clear(); 
4338 void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
)) 
4340     //wxLogDebug(wxT("wxRichTextCtrl::OnSysColourChanged")); 
4342     wxTextAttrEx basicStyle 
= GetBasicStyle(); 
4343     basicStyle
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
4344     SetBasicStyle(basicStyle
); 
4345     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
4350 // Refresh the area affected by a selection change 
4351 bool wxRichTextCtrl::RefreshForSelectionChange(const wxRichTextSelection
& oldSelection
, const wxRichTextSelection
& newSelection
) 
4353     // If the selection is not part of the focus object, or we have multiple ranges, then the chances are that 
4354     // the selection contains whole containers rather than just text, so refresh everything 
4355     // for now as it would be hard to compute the rectangle bounding all selections. 
4356     // TODO: improve on this. 
4357     if ((oldSelection
.IsValid() && (oldSelection
.GetContainer() != GetFocusObject() || oldSelection
.GetCount() > 1)) || 
4358         (newSelection
.IsValid() && (newSelection
.GetContainer() != GetFocusObject() || newSelection
.GetCount() > 1))) 
4364     wxRichTextRange oldRange
, newRange
; 
4365     if (oldSelection
.IsValid()) 
4366         oldRange 
= oldSelection
.GetRange(); 
4368         oldRange 
= wxRICHTEXT_NO_SELECTION
; 
4369     if (newSelection
.IsValid()) 
4370         newRange 
= newSelection
.GetRange(); 
4372         newRange 
= wxRICHTEXT_NO_SELECTION
; 
4374     // Calculate the refresh rectangle - just the affected lines 
4375     long firstPos
, lastPos
; 
4376     if (oldRange
.GetStart() == -2 && newRange
.GetStart() != -2) 
4378         firstPos 
= newRange
.GetStart(); 
4379         lastPos 
= newRange
.GetEnd(); 
4381     else if (oldRange
.GetStart() != -2 && newRange
.GetStart() == -2) 
4383         firstPos 
= oldRange
.GetStart(); 
4384         lastPos 
= oldRange
.GetEnd(); 
4386     else if (oldRange
.GetStart() == -2 && newRange
.GetStart() == -2) 
4392         firstPos 
= wxMin(oldRange
.GetStart(), newRange
.GetStart()); 
4393         lastPos 
= wxMax(oldRange
.GetEnd(), newRange
.GetEnd()); 
4396     wxRichTextLine
* firstLine 
= GetFocusObject()->GetLineAtPosition(firstPos
); 
4397     wxRichTextLine
* lastLine 
= GetFocusObject()->GetLineAtPosition(lastPos
); 
4399     if (firstLine 
&& lastLine
) 
4401         wxSize clientSize 
= GetClientSize(); 
4402         wxPoint pt1 
= GetPhysicalPoint(firstLine
->GetAbsolutePosition()); 
4403         wxPoint pt2 
= GetPhysicalPoint(lastLine
->GetAbsolutePosition()) + wxPoint(0, lastLine
->GetSize().y
); 
4406         pt1
.y 
= wxMax(0, pt1
.y
); 
4408         pt2
.y 
= wxMin(clientSize
.y
, pt2
.y
); 
4410         wxRect 
rect(pt1
, wxSize(clientSize
.x
, pt2
.y 
- pt1
.y
)); 
4411         RefreshRect(rect
, false); 
4419 // margins functions 
4420 bool wxRichTextCtrl::DoSetMargins(const wxPoint
& pt
) 
4422     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().SetValue(pt
.x
, wxTEXT_ATTR_UNITS_PIXELS
); 
4423     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetRight().SetValue(pt
.x
, wxTEXT_ATTR_UNITS_PIXELS
); 
4424     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetTop().SetValue(pt
.y
, wxTEXT_ATTR_UNITS_PIXELS
); 
4425     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetBottom().SetValue(pt
.y
, wxTEXT_ATTR_UNITS_PIXELS
); 
4430 wxPoint 
wxRichTextCtrl::DoGetMargins() const 
4432     return wxPoint(GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().GetValue(), 
4433                    GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetTop().GetValue()); 
4436 bool wxRichTextCtrl::SetFocusObject(wxRichTextParagraphLayoutBox
* obj
, bool setCaretPosition
) 
4438     if (obj 
&& !obj
->AcceptsFocus()) 
4441     wxRichTextParagraphLayoutBox
* oldContainer 
= GetFocusObject(); 
4442     bool changingContainer 
= (m_focusObject 
!= obj
); 
4444     if (changingContainer 
&& HasSelection()) 
4447     m_focusObject 
= obj
; 
4450         m_focusObject 
= & m_buffer
; 
4452     if (setCaretPosition 
&& changingContainer
) 
4454         m_selection
.Reset(); 
4455         m_selectionAnchor 
= -2; 
4456         m_selectionAnchorObject 
= NULL
; 
4457         m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
4461         m_caretAtLineStart 
= false; 
4462         MoveCaret(pos
, m_caretAtLineStart
); 
4463         SetDefaultStyleToCursorStyle(); 
4465         wxRichTextEvent 
cmdEvent( 
4466             wxEVT_COMMAND_RICHTEXT_FOCUS_OBJECT_CHANGED
, 
4468         cmdEvent
.SetEventObject(this); 
4469         cmdEvent
.SetPosition(m_caretPosition
+1); 
4470         cmdEvent
.SetOldContainer(oldContainer
); 
4471         cmdEvent
.SetContainer(m_focusObject
); 
4473         GetEventHandler()->ProcessEvent(cmdEvent
); 
4478 #if wxUSE_DRAG_AND_DROP 
4479 void wxRichTextCtrl::OnDrop(wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), wxDragResult def
, wxDataObject
* DataObj
) 
4483     if ((def 
!= wxDragCopy
) && (def 
!= wxDragMove
)) 
4488     if (!GetSelection().IsValid()) 
4493     wxRichTextParagraphLayoutBox
* originContainer 
= GetSelection().GetContainer(); 
4494     wxRichTextParagraphLayoutBox
* destContainer 
= GetFocusObject(); // This will be the drop container, not necessarily the same as the origin one 
4496     wxRichTextBuffer
* richTextBuffer 
= ((wxRichTextBufferDataObject
*)DataObj
)->GetRichTextBuffer(); 
4499         long position 
= GetCaretPosition(); 
4500         wxRichTextRange selectionrange 
= GetInternalSelectionRange(); 
4501         if (selectionrange
.Contains(position
) && (def 
== wxDragMove
)) 
4503             // It doesn't make sense to move onto itself 
4507         // If we're moving, and the data is being moved forward, we need to drop first, then delete the selection 
4508         // If moving backwards, we need to delete then drop. If we're copying (or doing nothing) we don't delete anyway 
4509         bool DeleteAfter 
= (def 
== wxDragMove
) && (position 
> selectionrange
.GetEnd()); 
4510         if ((def 
== wxDragMove
) && !DeleteAfter
) 
4512             // We can't use e.g. DeleteSelectedContent() as it uses the focus container 
4513             originContainer
->DeleteRangeWithUndo(selectionrange
, this, &GetBuffer()); 
4516         destContainer
->InsertParagraphsWithUndo(&GetBuffer(), position
+1, *richTextBuffer
, this, 0); 
4517         ShowPosition(position 
+ richTextBuffer
->GetOwnRange().GetEnd()); 
4519         delete richTextBuffer
; 
4523             // We can't use e.g. DeleteSelectedContent() as it uses the focus container 
4524             originContainer
->DeleteRangeWithUndo(selectionrange
, this, &GetBuffer()); 
4531 #endif // wxUSE_DRAG_AND_DROP 
4534 #if wxUSE_DRAG_AND_DROP 
4535 bool wxRichTextDropSource::GiveFeedback(wxDragResult 
WXUNUSED(effect
)) 
4537     wxCHECK_MSG(m_rtc
, false, wxT("NULL m_rtc")); 
4541     wxRichTextObject
* hitObj 
= NULL
; 
4542     wxRichTextParagraphLayoutBox
* container 
= m_rtc
->FindContainerAtPoint(m_rtc
->ScreenToClient(wxGetMousePosition()), position
, hit
, hitObj
); 
4544     if (!(hit 
& wxRICHTEXT_HITTEST_NONE
) && container 
&& container
->AcceptsFocus()) 
4546         m_rtc
->StoreFocusObject(container
); 
4547         m_rtc
->SetCaretPositionAfterClick(container
, position
, hit
); 
4550     return false;  // so that the base-class sets a cursor 
4552 #endif // wxUSE_DRAG_AND_DROP 
4554 bool wxRichTextCtrl::CanDeleteRange(wxRichTextParagraphLayoutBox
& WXUNUSED(container
), const wxRichTextRange
& WXUNUSED(range
)) const 
4559 bool wxRichTextCtrl::CanInsertContent(wxRichTextParagraphLayoutBox
& WXUNUSED(container
), long WXUNUSED(pos
)) const 
4564 void wxRichTextCtrl::EnableVerticalScrollbar(bool enable
) 
4566     m_verticalScrollbarEnabled 
= enable
; 
4571 #if wxRICHTEXT_USE_OWN_CARET 
4573 // ---------------------------------------------------------------------------- 
4574 // initialization and destruction 
4575 // ---------------------------------------------------------------------------- 
4577 void wxRichTextCaret::Init() 
4580     m_refreshEnabled 
= true; 
4584     m_richTextCtrl 
= NULL
; 
4585     m_needsUpdate 
= false; 
4589 wxRichTextCaret::~wxRichTextCaret() 
4591     if (m_timer
.IsRunning()) 
4595 // ---------------------------------------------------------------------------- 
4596 // showing/hiding/moving the caret (base class interface) 
4597 // ---------------------------------------------------------------------------- 
4599 void wxRichTextCaret::DoShow() 
4603     if (!m_timer
.IsRunning()) 
4604         m_timer
.Start(GetBlinkTime()); 
4609 void wxRichTextCaret::DoHide() 
4611     if (m_timer
.IsRunning()) 
4617 void wxRichTextCaret::DoMove() 
4623         if (m_xOld 
!= -1 && m_yOld 
!= -1) 
4625             if (m_richTextCtrl 
&& m_refreshEnabled
) 
4627                 wxRect 
rect(GetPosition(), GetSize()); 
4628                 m_richTextCtrl
->RefreshRect(rect
, false); 
4637 void wxRichTextCaret::DoSize() 
4639     int countVisible 
= m_countVisible
; 
4640     if (countVisible 
> 0) 
4646     if (countVisible 
> 0) 
4648         m_countVisible 
= countVisible
; 
4653 // ---------------------------------------------------------------------------- 
4654 // handling the focus 
4655 // ---------------------------------------------------------------------------- 
4657 void wxRichTextCaret::OnSetFocus() 
4665 void wxRichTextCaret::OnKillFocus() 
4670 // ---------------------------------------------------------------------------- 
4671 // drawing the caret 
4672 // ---------------------------------------------------------------------------- 
4674 void wxRichTextCaret::Refresh() 
4676     if (m_richTextCtrl 
&& m_refreshEnabled
) 
4678         wxRect 
rect(GetPosition(), GetSize()); 
4679         m_richTextCtrl
->RefreshRect(rect
, false); 
4683 void wxRichTextCaret::DoDraw(wxDC 
*dc
) 
4685     dc
->SetPen( *wxBLACK_PEN 
); 
4687     dc
->SetBrush(*(m_hasFocus 
? wxBLACK_BRUSH 
: wxTRANSPARENT_BRUSH
)); 
4688     dc
->SetPen(*wxBLACK_PEN
); 
4690     wxPoint 
pt(m_x
, m_y
); 
4694         pt 
= m_richTextCtrl
->GetLogicalPoint(pt
); 
4696     if (IsVisible() && m_flashOn
) 
4697         dc
->DrawRectangle(pt
.x
, pt
.y
, m_width
, m_height
); 
4700 void wxRichTextCaret::Notify() 
4702     m_flashOn 
= !m_flashOn
; 
4706 void wxRichTextCaretTimer::Notify() 
4711     // wxRICHTEXT_USE_OWN_CARET 
4714 bool wxRichTextContextMenuPropertiesInfo::AddItem(const wxString
& label
, wxRichTextObject
* obj
) 
4718         m_labels
.Add(label
); 
4726 // Returns number of menu items were added. 
4727 int wxRichTextContextMenuPropertiesInfo::AddMenuItems(wxMenu
* menu
, int startCmd
) const 
4729     wxMenuItem
* item 
= menu
->FindItem(startCmd
); 
4730     // If none of the standard properties identifiers are in the menu, add them if necessary. 
4731     // If no items to add, just set the text to something generic 
4732     if (GetCount() == 0) 
4736             menu
->SetLabel(startCmd
, _("&Properties")); 
4738             // Delete the others if necessary 
4740             for (i 
= startCmd
+1; i 
< startCmd
+3; i
++) 
4742                 if (menu
->FindItem(i
)) 
4753         // Find the position of the first properties item 
4754         for (i 
= 0; i 
< (int) menu
->GetMenuItemCount(); i
++) 
4756             wxMenuItem
* item 
= menu
->FindItemByPosition(i
); 
4757             if (item 
&& item
->GetId() == startCmd
) 
4766             int insertBefore 
= pos
+1; 
4767             for (i 
= startCmd
; i 
< startCmd
+GetCount(); i
++) 
4769                 if (menu
->FindItem(i
)) 
4771                     menu
->SetLabel(i
, m_labels
[i 
- startCmd
]); 
4775                     if (insertBefore 
>= (int) menu
->GetMenuItemCount()) 
4776                         menu
->Append(i
, m_labels
[i 
- startCmd
]); 
4778                         menu
->Insert(insertBefore
, i
, m_labels
[i 
- startCmd
]); 
4783             // Delete any old items still left on the menu 
4784             for (i 
= startCmd 
+ GetCount(); i 
< startCmd
+3; i
++) 
4786                 if (menu
->FindItem(i
)) 
4794             // No existing property identifiers were found, so append to the end of the menu. 
4795             menu
->AppendSeparator(); 
4796             for (i 
= startCmd
; i 
< startCmd
+GetCount(); i
++) 
4798                 menu
->Append(i
, m_labels
[i 
- startCmd
]); 
4806 // Add appropriate menu items for the current container and clicked on object 
4807 // (and container's parent, if appropriate). 
4808 int wxRichTextContextMenuPropertiesInfo::AddItems(wxRichTextCtrl
* ctrl
, wxRichTextObject
* container
, wxRichTextObject
* obj
) 
4811     if (obj 
&& ctrl
->CanEditProperties(obj
)) 
4812         AddItem(ctrl
->GetPropertiesMenuLabel(obj
), obj
); 
4814     if (container 
&& container 
!= obj 
&& ctrl
->CanEditProperties(container
) && m_labels
.Index(ctrl
->GetPropertiesMenuLabel(container
)) == wxNOT_FOUND
) 
4815         AddItem(ctrl
->GetPropertiesMenuLabel(container
), container
); 
4817     if (container 
&& container
->GetParent() && ctrl
->CanEditProperties(container
->GetParent()) && m_labels
.Index(ctrl
->GetPropertiesMenuLabel(container
->GetParent())) == wxNOT_FOUND
) 
4818         AddItem(ctrl
->GetPropertiesMenuLabel(container
->GetParent()), container
->GetParent());