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); 
 267     SetBasicStyle(attributes
); 
 270     SetMargins(margin
, margin
); 
 272     // The default attributes will be merged with base attributes, so 
 273     // can be empty to begin with 
 274     wxRichTextAttr defaultAttributes
; 
 275     SetDefaultStyle(defaultAttributes
); 
 277     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 278     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 281     GetBuffer().SetRichTextCtrl(this); 
 283 #if wxRICHTEXT_USE_OWN_CARET 
 284     SetCaret(new wxRichTextCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 286     SetCaret(new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 289     // Tell the sizers to use the given or best size 
 290     SetInitialSize(size
); 
 292 #if wxRICHTEXT_BUFFERED_PAINTING 
 294     RecreateBuffer(size
); 
 297     m_textCursor 
= wxCursor(wxCURSOR_IBEAM
); 
 298     m_urlCursor 
= wxCursor(wxCURSOR_HAND
); 
 300     SetCursor(m_textCursor
); 
 302     if (!value
.IsEmpty()) 
 305     GetBuffer().AddEventHandler(this); 
 308     wxAcceleratorEntry entries
[6]; 
 310     entries
[0].Set(wxACCEL_CTRL
,   (int) 'C',       wxID_COPY
); 
 311     entries
[1].Set(wxACCEL_CTRL
,   (int) 'X',       wxID_CUT
); 
 312     entries
[2].Set(wxACCEL_CTRL
,   (int) 'V',       wxID_PASTE
); 
 313     entries
[3].Set(wxACCEL_CTRL
,   (int) 'A',       wxID_SELECTALL
); 
 314     entries
[4].Set(wxACCEL_CTRL
,   (int) 'Z',       wxID_UNDO
); 
 315     entries
[5].Set(wxACCEL_CTRL
,   (int) 'Y',       wxID_REDO
); 
 317     wxAcceleratorTable 
accel(6, entries
); 
 318     SetAcceleratorTable(accel
); 
 320     m_contextMenu 
= new wxMenu
; 
 321     m_contextMenu
->Append(wxID_UNDO
, _("&Undo")); 
 322     m_contextMenu
->Append(wxID_REDO
, _("&Redo")); 
 323     m_contextMenu
->AppendSeparator(); 
 324     m_contextMenu
->Append(wxID_CUT
, _("Cu&t")); 
 325     m_contextMenu
->Append(wxID_COPY
, _("&Copy")); 
 326     m_contextMenu
->Append(wxID_PASTE
, _("&Paste")); 
 327     m_contextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
 328     m_contextMenu
->AppendSeparator(); 
 329     m_contextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
 330     m_contextMenu
->AppendSeparator(); 
 331     m_contextMenu
->Append(wxID_RICHTEXT_PROPERTIES1
, _("&Properties")); 
 333 #if wxUSE_DRAG_AND_DROP 
 334     SetDropTarget(new wxRichTextDropTarget(this)); 
 340 wxRichTextCtrl::~wxRichTextCtrl() 
 342     SetFocusObject(& GetBuffer(), false); 
 343     GetBuffer().RemoveEventHandler(this); 
 345     delete m_contextMenu
; 
 348 /// Member initialisation 
 349 void wxRichTextCtrl::Init() 
 351     m_contextMenu 
= NULL
; 
 353     m_caretPosition 
= -1; 
 354     m_selectionAnchor 
= -2; 
 355     m_selectionAnchorObject 
= NULL
; 
 356     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
 358     m_verticalScrollbarEnabled 
= true; 
 359     m_caretAtLineStart 
= false; 
 361 #if wxUSE_DRAG_AND_DROP 
 364     m_fullLayoutRequired 
= false; 
 365     m_fullLayoutTime 
= 0; 
 366     m_fullLayoutSavedPosition 
= 0; 
 367     m_delayedLayoutThreshold 
= wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD
; 
 368     m_caretPositionForDefaultStyle 
= -2; 
 369     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(GetUpdateRegion().GetBox()); 
 444         drawingArea
.SetPosition(GetUnscaledPoint(GetLogicalPoint(drawingArea
.GetPosition()))); 
 445         drawingArea
.SetSize(GetUnscaledSize(drawingArea
.GetSize())); 
 447         wxRect 
availableSpace(GetUnscaledSize(GetClientSize())); 
 448         wxRichTextDrawingContext 
context(& GetBuffer()); 
 449         if (GetBuffer().IsDirty()) 
 451             dc
.SetUserScale(GetScale(), GetScale()); 
 453             GetBuffer().Layout(dc
, context
, availableSpace
, availableSpace
, wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
); 
 454             GetBuffer().Invalidate(wxRICHTEXT_NONE
); 
 456             dc
.SetUserScale(1.0, 1.0); 
 461         wxRect 
clipRect(availableSpace
); 
 462         clipRect
.x 
+= GetBuffer().GetLeftMargin(); 
 463         clipRect
.y 
+= GetBuffer().GetTopMargin(); 
 464         clipRect
.width 
-= (GetBuffer().GetLeftMargin() + GetBuffer().GetRightMargin()); 
 465         clipRect
.height 
-= (GetBuffer().GetTopMargin() + GetBuffer().GetBottomMargin()); 
 467         clipRect 
= GetScaledRect(clipRect
); 
 468         clipRect
.SetPosition(GetLogicalPoint(clipRect
.GetPosition())); 
 470         dc
.SetClippingRegion(clipRect
); 
 473         if ((GetExtraStyle() & wxRICHTEXT_EX_NO_GUIDELINES
) == 0) 
 474             flags 
|= wxRICHTEXT_DRAW_GUIDELINES
; 
 476         dc
.SetUserScale(GetScale(), GetScale()); 
 478         GetBuffer().Draw(dc
, context
, GetBuffer().GetOwnRange(), GetSelection(), drawingArea
, 0 /* descent */, flags
); 
 480         dc
.DestroyClippingRegion(); 
 482         // Other user defined painting after everything else (i.e. all text) is painted 
 483         PaintAboveContent(dc
); 
 485 #if wxRICHTEXT_USE_OWN_CARET 
 486         if (GetCaret()->IsVisible()) 
 489             ((wxRichTextCaret
*) GetCaret())->DoDraw(& dc
); 
 493         dc
.SetUserScale(1.0, 1.0); 
 496 #if !wxRICHTEXT_USE_OWN_CARET 
 502         ((wxRichTextCaret
*) GetCaret())->EnableRefresh(true); 
 506 // Empty implementation, to prevent flicker 
 507 void wxRichTextCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 511 void wxRichTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
 515 #if !wxRICHTEXT_USE_OWN_CARET 
 521 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 522     // Work around dropouts when control is focused 
 530 void wxRichTextCtrl::OnKillFocus(wxFocusEvent
& WXUNUSED(event
)) 
 535 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 536     // Work around dropouts when control is focused 
 544 void wxRichTextCtrl::OnCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
 549 // Set up the caret for the given position and container, after a mouse click 
 550 bool wxRichTextCtrl::SetCaretPositionAfterClick(wxRichTextParagraphLayoutBox
* container
, long position
, int hitTestFlags
, bool extendSelection
) 
 552     bool caretAtLineStart 
= false; 
 554     if (hitTestFlags 
& wxRICHTEXT_HITTEST_BEFORE
) 
 556         // If we're at the start of a line (but not first in para) 
 557         // then we should keep the caret showing at the start of the line 
 558         // by showing the m_caretAtLineStart flag. 
 559         wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(position
); 
 560         wxRichTextLine
* line 
= container
->GetLineAtPosition(position
); 
 562         if (line 
&& para 
&& line
->GetAbsoluteRange().GetStart() == position 
&& para
->GetRange().GetStart() != position
) 
 563             caretAtLineStart 
= true; 
 567     if (extendSelection 
&& (m_caretPosition 
!= position
)) 
 568         ExtendSelection(m_caretPosition
, position
, wxRICHTEXT_SHIFT_DOWN
); 
 570     MoveCaret(position
, caretAtLineStart
); 
 571     SetDefaultStyleToCursorStyle(); 
 577 void wxRichTextCtrl::OnLeftClick(wxMouseEvent
& event
) 
 583     dc
.SetFont(GetFont()); 
 585     // TODO: detect change of focus object 
 587     wxRichTextObject
* hitObj 
= NULL
; 
 588     wxRichTextObject
* contextObj 
= NULL
; 
 589     wxRichTextDrawingContext 
context(& GetBuffer()); 
 590     int hit 
= GetBuffer().HitTest(dc
, context
, GetUnscaledPoint(event
.GetLogicalPosition(dc
)), position
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_HONOUR_ATOMIC
); 
 592 #if wxUSE_DRAG_AND_DROP 
 593     // If there's no selection, or we're not inside it, this isn't an attempt to initiate Drag'n'Drop 
 594     if (IsEditable() && HasSelection() && GetSelectionRange().ToInternal().Contains(position
)) 
 596         // This might be an attempt at initiating Drag'n'Drop. So set the time & flags 
 598         m_dragStartPoint 
= event
.GetPosition();   // No need to worry about logical positions etc, we only care about the distance from the original pt 
 601         m_dragStartTime 
= wxDateTime::UNow(); 
 602 #endif // wxUSE_DATETIME 
 604         // Preserve behaviour of clicking on an object within the selection 
 605         if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& hitObj
) 
 608         return; // Don't skip the event, else the selection will be lost 
 610 #endif // wxUSE_DRAG_AND_DROP 
 612     if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& hitObj
) 
 614         wxRichTextParagraphLayoutBox
* oldFocusObject 
= GetFocusObject(); 
 615         wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 616         if (container 
&& container 
!= GetFocusObject() && container
->AcceptsFocus()) 
 618             SetFocusObject(container
, false /* don't set caret position yet */); 
 624         long oldCaretPos 
= m_caretPosition
; 
 626         SetCaretPositionAfterClick(container
, position
, hit
); 
 628         // For now, don't handle shift-click when we're selecting multiple objects. 
 629         if (event
.ShiftDown() && GetFocusObject() == oldFocusObject 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 630             ExtendSelection(oldCaretPos
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 639 void wxRichTextCtrl::OnLeftUp(wxMouseEvent
& event
) 
 644         if (GetCapture() == this) 
 647         // See if we clicked on a URL 
 650         dc
.SetFont(GetFont()); 
 653         wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 654         wxRichTextObject
* hitObj 
= NULL
; 
 655         wxRichTextObject
* contextObj 
= NULL
; 
 656         wxRichTextDrawingContext 
context(& GetBuffer()); 
 657         // Only get objects at this level, not nested, because otherwise we couldn't swipe text at a single level. 
 658         int hit 
= GetFocusObject()->HitTest(dc
, context
, GetUnscaledPoint(logicalPt
), position
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
|wxRICHTEXT_HITTEST_HONOUR_ATOMIC
); 
 660 #if wxUSE_DRAG_AND_DROP 
 663             // Preserve the behaviour that would have happened without drag-and-drop detection, in OnLeftClick 
 664             m_preDrag 
= false; // Tell DnD not to happen now: we are processing Left Up ourselves. 
 666             // Do the actions that would have been done in OnLeftClick if we hadn't tried to drag 
 668             wxRichTextObject
* hitObj 
= NULL
; 
 669             wxRichTextObject
* contextObj 
= NULL
; 
 670             int hit 
= GetBuffer().HitTest(dc
, context
, GetUnscaledPoint(event
.GetLogicalPosition(dc
)), position
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_HONOUR_ATOMIC
); 
 671             wxRichTextParagraphLayoutBox
* oldFocusObject 
= GetFocusObject(); 
 672             wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 673             if (container 
&& container 
!= GetFocusObject() && container
->AcceptsFocus()) 
 675                 SetFocusObject(container
, false /* don't set caret position yet */); 
 678             long oldCaretPos 
= m_caretPosition
; 
 680             SetCaretPositionAfterClick(container
, position
, hit
); 
 682             // For now, don't handle shift-click when we're selecting multiple objects. 
 683             if (event
.ShiftDown() && GetFocusObject() == oldFocusObject 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 684                 ExtendSelection(oldCaretPos
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 690         if ((hit 
!= wxRICHTEXT_HITTEST_NONE
) && !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
 692             wxRichTextEvent 
cmdEvent( 
 693                 wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
, 
 695             cmdEvent
.SetEventObject(this); 
 696             cmdEvent
.SetPosition(position
); 
 698                 cmdEvent
.SetContainer(hitObj
->GetContainer()); 
 700             if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 703                 if (GetStyle(position
, attr
)) 
 705                     if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 707                         wxString urlTarget 
= attr
.GetURL(); 
 708                         if (!urlTarget
.IsEmpty()) 
 710                             wxMouseEvent 
mouseEvent(event
); 
 712                             long startPos 
= 0, endPos 
= 0; 
 713                             wxRichTextObject
* obj 
= GetFocusObject()->GetLeafObjectAtPosition(position
); 
 716                                 startPos 
= obj
->GetRange().GetStart(); 
 717                                 endPos 
= obj
->GetRange().GetEnd(); 
 720                             wxTextUrlEvent 
urlEvent(GetId(), mouseEvent
, startPos
, endPos
); 
 721                             InitCommandEvent(urlEvent
); 
 723                             urlEvent
.SetString(urlTarget
); 
 725                             GetEventHandler()->ProcessEvent(urlEvent
); 
 733 #if wxUSE_DRAG_AND_DROP 
 735 #endif // wxUSE_DRAG_AND_DROP 
 737 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ && wxHAVE_PRIMARY_SELECTION 
 738     if (HasSelection() && GetFocusObject() && GetFocusObject()->GetBuffer()) 
 740         // Put the selection in PRIMARY, if it exists 
 741         wxTheClipboard
->UsePrimarySelection(true); 
 743         wxRichTextRange range 
= GetInternalSelectionRange(); 
 744         GetFocusObject()->GetBuffer()->CopyToClipboard(range
); 
 746         wxTheClipboard
->UsePrimarySelection(false); 
 752 void wxRichTextCtrl::OnMoveMouse(wxMouseEvent
& event
) 
 754 #if wxUSE_DRAG_AND_DROP 
 756     if (m_preDrag 
|| m_dragging
) 
 758         int x 
= m_dragStartPoint
.x 
- event
.GetPosition().x
; 
 759         int y 
= m_dragStartPoint
.y 
- event
.GetPosition().y
; 
 760         distance 
= abs(x
) + abs(y
); 
 763     // See if we're starting Drag'n'Drop 
 767         wxTimeSpan diff 
= wxDateTime::UNow() - m_dragStartTime
; 
 771              && (diff
.GetMilliseconds() > 100) 
 778             wxRichTextRange range 
= GetInternalSelectionRange(); 
 779             if (range 
== wxRICHTEXT_NONE
) 
 781               // Don't try to drag an empty range 
 786             // Cache the current situation, to be restored if Drag'n'Drop is cancelled 
 787             long oldPos 
= GetCaretPosition(); 
 788             wxRichTextParagraphLayoutBox
* oldFocus 
= GetFocusObject(); 
 790             wxDataObjectComposite
* compositeObject 
= new wxDataObjectComposite(); 
 791             wxString text 
= GetFocusObject()->GetTextForRange(range
); 
 793             text 
= wxTextFile::Translate(text
, wxTextFileType_Dos
); 
 795             compositeObject
->Add(new wxTextDataObject(text
), false /* not preferred */); 
 797             wxRichTextBuffer
* richTextBuf 
= new wxRichTextBuffer
; 
 798             GetFocusObject()->CopyFragment(range
, *richTextBuf
); 
 799             compositeObject
->Add(new wxRichTextBufferDataObject(richTextBuf
), true /* preferred */); 
 801             wxRichTextDropSource 
source(*compositeObject
, this); 
 802             // Use wxDrag_DefaultMove, not because it's the likelier choice but because pressing Ctrl for Copy obeys the principle of least surprise 
 803             // The alternative, wxDrag_DefaultCopy, requires the user to know that Move needs the Shift key pressed 
 804             BeginBatchUndo(_("Drag")); 
 805             switch (source
.DoDragDrop(wxDrag_AllowMove 
| wxDrag_DefaultMove
)) 
 808                 case wxDragCopy
:  break; 
 811                     wxLogError(wxT("An error occurred during drag and drop operation")); 
 814                     Refresh(); // This is needed in wxMSW, otherwise resetting the position doesn't 'take' 
 815                     SetCaretPosition(oldPos
); 
 816                     SetFocusObject(oldFocus
, false); 
 825 #endif // wxUSE_DRAG_AND_DROP 
 829     dc
.SetFont(GetFont()); 
 832     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 833     wxRichTextObject
* hitObj 
= NULL
; 
 834     wxRichTextObject
* contextObj 
= NULL
; 
 838     // If we're dragging, let's only consider positions at this level; otherwise 
 839     // selecting a range is not going to work. 
 840     wxRichTextParagraphLayoutBox
* container 
= & GetBuffer(); 
 843         flags 
= wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
; 
 844         container 
= GetFocusObject(); 
 846     wxRichTextDrawingContext 
context(& GetBuffer()); 
 847     int hit 
= container
->HitTest(dc
, context
, GetUnscaledPoint(logicalPt
), position
, & hitObj
, & contextObj
, flags
); 
 849     // See if we need to change the cursor 
 852         if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
) && hitObj
) 
 854             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 856                 ProcessMouseMovement(actualContainer
, hitObj
, position
, logicalPt
); 
 859             SetCursor(m_textCursor
); 
 862     if (!event
.Dragging()) 
 869 #if wxUSE_DRAG_AND_DROP 
 875         wxRichTextParagraphLayoutBox
* commonAncestor 
= NULL
; 
 876         wxRichTextParagraphLayoutBox
* otherContainer 
= NULL
; 
 877         wxRichTextParagraphLayoutBox
* firstContainer 
= NULL
; 
 879         // Check for dragging across multiple containers 
 881         wxRichTextObject
* hitObj2 
= NULL
, *contextObj2 
= NULL
; 
 882         int hit2 
= GetBuffer().HitTest(dc
, context
, GetUnscaledPoint(logicalPt
), position2
, & hitObj2
, & contextObj2
, 0); 
 883         if (hit2 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit2 
& wxRICHTEXT_HITTEST_OUTSIDE
) && hitObj2 
&& hitObj 
!= hitObj2
) 
 885             // See if we can find a common ancestor 
 886             if (m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 888                 firstContainer 
= GetFocusObject(); 
 889                 commonAncestor 
= wxDynamicCast(firstContainer
->GetParent(), wxRichTextParagraphLayoutBox
); 
 893                 firstContainer 
= wxDynamicCast(m_selectionAnchorObject
, wxRichTextParagraphLayoutBox
); 
 894                 //commonAncestor = GetFocusObject(); // when the selection state is not normal, the focus object (e.g. table) 
 895                                                    // is the common ancestor. 
 896                 commonAncestor 
= wxDynamicCast(firstContainer
->GetParent(), wxRichTextParagraphLayoutBox
); 
 899             if (commonAncestor 
&& commonAncestor
->HandlesChildSelections()) 
 901                 wxRichTextObject
* p 
= hitObj2
; 
 904                     if (p
->GetParent() == commonAncestor
) 
 906                         otherContainer 
= wxDynamicCast(p
, wxRichTextParagraphLayoutBox
); 
 913             if (commonAncestor 
&& firstContainer 
&& otherContainer
) 
 915                 // We have now got a second container that shares a parent with the current or anchor object. 
 916                 if (m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 918                     // Don't go into common-ancestor selection mode if we still have the same 
 920                     if (otherContainer 
!= firstContainer
) 
 922                         m_selectionState 
= wxRichTextCtrlSelectionState_CommonAncestor
; 
 923                         m_selectionAnchorObject 
= firstContainer
; 
 924                         m_selectionAnchor 
= firstContainer
->GetRange().GetStart(); 
 926                         // The common ancestor, such as a table, returns the cell selection 
 927                         // between the anchor and current position. 
 928                         m_selection 
= commonAncestor
->GetSelection(m_selectionAnchor
, otherContainer
->GetRange().GetStart()); 
 933                     m_selection 
= commonAncestor
->GetSelection(m_selectionAnchor
, otherContainer
->GetRange().GetStart()); 
 938                 if (otherContainer
->AcceptsFocus()) 
 939                     SetFocusObject(otherContainer
, false /* don't set caret and clear selection */); 
 940                 MoveCaret(-1, false); 
 941                 SetDefaultStyleToCursorStyle(); 
 946     if (hitObj 
&& m_dragging 
&& hit 
!= wxRICHTEXT_HITTEST_NONE 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
 
 947 #if wxUSE_DRAG_AND_DROP 
 953         SetCaretPositionAfterClick(container
, position
, hit
, true /* extend selection */); 
 958 void wxRichTextCtrl::OnRightClick(wxMouseEvent
& event
) 
 964     dc
.SetFont(GetFont()); 
 967     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 968     wxRichTextObject
* hitObj 
= NULL
; 
 969     wxRichTextObject
* contextObj 
= NULL
; 
 970     wxRichTextDrawingContext 
context(& GetBuffer()); 
 971     int hit 
= GetFocusObject()->HitTest(dc
, context
, GetUnscaledPoint(logicalPt
), position
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_HONOUR_ATOMIC
); 
 973     if (hitObj 
&& hitObj
->GetContainer() != GetFocusObject()) 
 975         wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 976         if (actualContainer 
&& actualContainer
->AcceptsFocus()) 
 978             SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
 979             SetCaretPositionAfterClick(actualContainer
, position
, hit
); 
 983     wxRichTextEvent 
cmdEvent( 
 984         wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
, 
 986     cmdEvent
.SetEventObject(this); 
 987     cmdEvent
.SetPosition(position
); 
 989         cmdEvent
.SetContainer(hitObj
->GetContainer()); 
 991     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 995 /// Left-double-click 
 996 void wxRichTextCtrl::OnLeftDClick(wxMouseEvent
& WXUNUSED(event
)) 
 998     wxRichTextEvent 
cmdEvent( 
 999         wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
, 
1001     cmdEvent
.SetEventObject(this); 
1002     cmdEvent
.SetPosition(m_caretPosition
+1); 
1003     cmdEvent
.SetContainer(GetFocusObject()); 
1005     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
1007         SelectWord(GetCaretPosition()+1); 
1012 void wxRichTextCtrl::OnMiddleClick(wxMouseEvent
& event
) 
1014     wxRichTextEvent 
cmdEvent( 
1015         wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
, 
1017     cmdEvent
.SetEventObject(this); 
1018     cmdEvent
.SetPosition(m_caretPosition
+1); 
1019     cmdEvent
.SetContainer(GetFocusObject()); 
1021     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
1024 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ && wxHAVE_PRIMARY_SELECTION 
1025     // Paste any PRIMARY selection, if it exists 
1026     wxTheClipboard
->UsePrimarySelection(true); 
1028     wxTheClipboard
->UsePrimarySelection(false); 
1033 void wxRichTextCtrl::OnChar(wxKeyEvent
& event
) 
1036     if (event
.CmdDown()) 
1037         flags 
|= wxRICHTEXT_CTRL_DOWN
; 
1038     if (event
.ShiftDown()) 
1039         flags 
|= wxRICHTEXT_SHIFT_DOWN
; 
1040     if (event
.AltDown()) 
1041         flags 
|= wxRICHTEXT_ALT_DOWN
; 
1043     if (event
.GetEventType() == wxEVT_KEY_DOWN
) 
1045         if (event
.IsKeyInCategory(WXK_CATEGORY_NAVIGATION
)) 
1047             KeyboardNavigate(event
.GetKeyCode(), flags
); 
1051         long keycode 
= event
.GetKeyCode(); 
1111             case WXK_NUMPAD_HOME
: 
1112             case WXK_NUMPAD_LEFT
: 
1114             case WXK_NUMPAD_RIGHT
: 
1115             case WXK_NUMPAD_DOWN
: 
1116             case WXK_NUMPAD_PAGEUP
: 
1117             case WXK_NUMPAD_PAGEDOWN
: 
1118             case WXK_NUMPAD_END
: 
1119             case WXK_NUMPAD_BEGIN
: 
1120             case WXK_NUMPAD_INSERT
: 
1121             case WXK_WINDOWS_LEFT
: 
1130         // Must process this before translation, otherwise it's translated into a WXK_DELETE event. 
1131         if (event
.CmdDown() && event
.GetKeyCode() == WXK_BACK
) 
1138             if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1143             BeginBatchUndo(_("Delete Text")); 
1145             long newPos 
= m_caretPosition
; 
1147             bool processed 
= DeleteSelectedContent(& newPos
); 
1153             // Submit range in character positions, which are greater than caret positions, 
1154             // so subtract 1 for deleted character and add 1 for conversion to character position. 
1157                 if (event
.CmdDown()) 
1159                     long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
1162                         wxRichTextRange 
range(pos
+1, newPos
); 
1163                         if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1165                             GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1174                     wxRichTextRange 
range(newPos
, newPos
); 
1175                     if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1177                         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1185             if (GetLastPosition() == -1) 
1187                 GetFocusObject()->Reset(); 
1189                 m_caretPosition 
= -1; 
1191                 SetDefaultStyleToCursorStyle(); 
1194             ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
1196             // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. 
1198                 wxRichTextEvent 
cmdEvent( 
1199                     wxEVT_COMMAND_RICHTEXT_DELETE
, 
1201                 cmdEvent
.SetEventObject(this); 
1202                 cmdEvent
.SetFlags(flags
); 
1203                 cmdEvent
.SetPosition(m_caretPosition
+1); 
1204                 cmdEvent
.SetContainer(GetFocusObject()); 
1205                 GetEventHandler()->ProcessEvent(cmdEvent
); 
1216     // all the other keys modify the controls contents which shouldn't be 
1217     // possible if we're read-only 
1218     if ( !IsEditable() ) 
1224     if (event
.GetKeyCode() == WXK_RETURN
) 
1226         if (!CanInsertContent(* GetFocusObject(), m_caretPosition
+1)) 
1229         long newPos 
= m_caretPosition
; 
1231         if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1236         BeginBatchUndo(_("Insert Text")); 
1238         DeleteSelectedContent(& newPos
); 
1240         if (event
.ShiftDown()) 
1243             text 
= wxRichTextLineBreakChar
; 
1244             GetFocusObject()->InsertTextWithUndo(& GetBuffer(), newPos
+1, text
, this); 
1245             m_caretAtLineStart 
= true; 
1249             GetFocusObject()->InsertNewlineWithUndo(& GetBuffer(), newPos
+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
|wxRICHTEXT_INSERT_INTERACTIVE
); 
1252         SetDefaultStyleToCursorStyle(); 
1254         ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
1256         wxRichTextEvent 
cmdEvent( 
1257             wxEVT_COMMAND_RICHTEXT_RETURN
, 
1259         cmdEvent
.SetEventObject(this); 
1260         cmdEvent
.SetFlags(flags
); 
1261         cmdEvent
.SetPosition(newPos
+1); 
1262         cmdEvent
.SetContainer(GetFocusObject()); 
1264         if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
1266             // Generate conventional event 
1267             wxCommandEvent 
textEvent(wxEVT_COMMAND_TEXT_ENTER
, GetId()); 
1268             InitCommandEvent(textEvent
); 
1270             GetEventHandler()->ProcessEvent(textEvent
); 
1274     else if (event
.GetKeyCode() == WXK_BACK
) 
1276         long newPos 
= m_caretPosition
; 
1278         if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1283         BeginBatchUndo(_("Delete Text")); 
1285         bool processed 
= DeleteSelectedContent(& newPos
); 
1291         // Submit range in character positions, which are greater than caret positions, 
1292         // so subtract 1 for deleted character and add 1 for conversion to character position. 
1295             if (event
.CmdDown()) 
1297                 long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
1300                     wxRichTextRange 
range(pos
+1, newPos
); 
1301                     if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1303                         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1312                 wxRichTextRange 
range(newPos
, newPos
); 
1313                 if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1315                     GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1323         if (GetLastPosition() == -1) 
1325             GetFocusObject()->Reset(); 
1327             m_caretPosition 
= -1; 
1329             SetDefaultStyleToCursorStyle(); 
1332         ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
1334         // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. 
1336             wxRichTextEvent 
cmdEvent( 
1337                 wxEVT_COMMAND_RICHTEXT_DELETE
, 
1339             cmdEvent
.SetEventObject(this); 
1340             cmdEvent
.SetFlags(flags
); 
1341             cmdEvent
.SetPosition(m_caretPosition
+1); 
1342             cmdEvent
.SetContainer(GetFocusObject()); 
1343             GetEventHandler()->ProcessEvent(cmdEvent
); 
1348     else if (event
.GetKeyCode() == WXK_DELETE
) 
1350         long newPos 
= m_caretPosition
; 
1352         if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1357         BeginBatchUndo(_("Delete Text")); 
1359         bool processed 
= DeleteSelectedContent(& newPos
); 
1365         // Submit range in character positions, which are greater than caret positions, 
1366         if (newPos 
< GetFocusObject()->GetOwnRange().GetEnd()+1) 
1368             if (event
.CmdDown()) 
1370                 long pos 
= wxRichTextCtrl::FindNextWordPosition(1); 
1371                 if (pos 
!= -1 && (pos 
> newPos
)) 
1373                     wxRichTextRange 
range(newPos
+1, pos
); 
1374                     if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1376                         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1383             if (!processed 
&& newPos 
< (GetLastPosition()-1)) 
1385                 wxRichTextRange 
range(newPos
+1, newPos
+1); 
1386                 if (CanDeleteRange(* GetFocusObject(), range
.FromInternal())) 
1388                     GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1396         if (GetLastPosition() == -1) 
1398             GetFocusObject()->Reset(); 
1400             m_caretPosition 
= -1; 
1402             SetDefaultStyleToCursorStyle(); 
1405         ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
1407         // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. 
1409             wxRichTextEvent 
cmdEvent( 
1410                 wxEVT_COMMAND_RICHTEXT_DELETE
, 
1412             cmdEvent
.SetEventObject(this); 
1413             cmdEvent
.SetFlags(flags
); 
1414             cmdEvent
.SetPosition(m_caretPosition
+1); 
1415             cmdEvent
.SetContainer(GetFocusObject()); 
1416             GetEventHandler()->ProcessEvent(cmdEvent
); 
1423         long keycode 
= event
.GetKeyCode(); 
1435                 if (event
.CmdDown()) 
1437                 // Fixes AltGr+key with European input languages on Windows 
1438                 if ((event
.CmdDown() && !event
.AltDown()) || (event
.AltDown() && !event
.CmdDown())) 
1445                 wxRichTextEvent 
cmdEvent( 
1446                     wxEVT_COMMAND_RICHTEXT_CHARACTER
, 
1448                 cmdEvent
.SetEventObject(this); 
1449                 cmdEvent
.SetFlags(flags
); 
1451                 cmdEvent
.SetCharacter(event
.GetUnicodeKey()); 
1453                 cmdEvent
.SetCharacter((wxChar
) keycode
); 
1455                 cmdEvent
.SetPosition(m_caretPosition
+1); 
1456                 cmdEvent
.SetContainer(GetFocusObject()); 
1458                 if (keycode 
== wxT('\t')) 
1460                     // See if we need to promote or demote the selection or paragraph at the cursor 
1461                     // position, instead of inserting a tab. 
1462                     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
1463                     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
); 
1464                     if (para 
&& para
->GetRange().GetStart() == pos 
&& para
->GetAttributes().HasListStyleName()) 
1466                         wxRichTextRange range
; 
1468                             range 
= GetSelectionRange(); 
1470                             range 
= para
->GetRange().FromInternal(); 
1472                         int promoteBy 
= event
.ShiftDown() ? 1 : -1; 
1474                         PromoteList(promoteBy
, range
, NULL
); 
1476                         GetEventHandler()->ProcessEvent(cmdEvent
); 
1482                 if (!CanInsertContent(* GetFocusObject(), m_caretPosition
+1)) 
1485                 if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) 
1488                 BeginBatchUndo(_("Insert Text")); 
1490                 long newPos 
= m_caretPosition
; 
1491                 DeleteSelectedContent(& newPos
); 
1494                 wxString str 
= event
.GetUnicodeKey(); 
1496                 wxString str 
= (wxChar
) event
.GetKeyCode(); 
1498                 GetFocusObject()->InsertTextWithUndo(& GetBuffer(), newPos
+1, str
, this, 0); 
1502                 SetDefaultStyleToCursorStyle(); 
1503                 ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
1505                 cmdEvent
.SetPosition(m_caretPosition
); 
1506                 GetEventHandler()->ProcessEvent(cmdEvent
); 
1514 bool wxRichTextCtrl::ProcessMouseMovement(wxRichTextParagraphLayoutBox
* container
, wxRichTextObject
* WXUNUSED(obj
), long position
, const wxPoint
& WXUNUSED(pos
)) 
1516     wxRichTextAttr attr
; 
1517     if (container 
&& GetStyle(position
, attr
, container
)) 
1519         if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
1521             SetCursor(m_urlCursor
); 
1523         else if (!attr
.HasFlag(wxTEXT_ATTR_URL
)) 
1525             SetCursor(m_textCursor
); 
1533 /// Delete content if there is a selection, e.g. when pressing a key. 
1534 bool wxRichTextCtrl::DeleteSelectedContent(long* newPos
) 
1538         long pos 
= m_selection
.GetRange().GetStart(); 
1539         wxRichTextRange range 
= m_selection
.GetRange(); 
1541         // SelectAll causes more to be selected than doing it interactively, 
1542         // and causes a new paragraph to be inserted. So for multiline buffers, 
1543         // don't delete the final position. 
1544         if (range
.GetEnd() == GetLastPosition() && GetNumberOfLines() > 0) 
1545             range
.SetEnd(range
.GetEnd()-1); 
1547         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1548         m_selection
.Reset(); 
1549         m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
1559 /// Keyboard navigation 
1563 Left:       left one character 
1564 Right:      right one character 
1567 Ctrl-Left:  left one word 
1568 Ctrl-Right: right one word 
1569 Ctrl-Up:    previous paragraph start 
1570 Ctrl-Down:  next start of paragraph 
1573 Ctrl-Home:  start of document 
1574 Ctrl-End:   end of document 
1575 Page-Up:    Up a screen 
1576 Page-Down:  Down a screen 
1580 Ctrl-Alt-PgUp: Start of window 
1581 Ctrl-Alt-PgDn: End of window 
1582 F8:         Start selection mode 
1583 Esc:        End selection mode 
1585 Adding Shift does the above but starts/extends selection. 
1590 bool wxRichTextCtrl::KeyboardNavigate(int keyCode
, int flags
) 
1592     bool success 
= false; 
1594     if (keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT
) 
1596         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1597             success 
= WordRight(1, flags
); 
1599             success 
= MoveRight(1, flags
); 
1601     else if (keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT
) 
1603         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1604             success 
= WordLeft(1, flags
); 
1606             success 
= MoveLeft(1, flags
); 
1608     else if (keyCode 
== WXK_UP 
|| keyCode 
== WXK_NUMPAD_UP
) 
1610         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1611             success 
= MoveToParagraphStart(flags
); 
1613             success 
= MoveUp(1, flags
); 
1615     else if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN
) 
1617         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1618             success 
= MoveToParagraphEnd(flags
); 
1620             success 
= MoveDown(1, flags
); 
1622     else if (keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP
) 
1624         success 
= PageUp(1, flags
); 
1626     else if (keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1628         success 
= PageDown(1, flags
); 
1630     else if (keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME
) 
1632         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1633             success 
= MoveHome(flags
); 
1635             success 
= MoveToLineStart(flags
); 
1637     else if (keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END
) 
1639         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1640             success 
= MoveEnd(flags
); 
1642             success 
= MoveToLineEnd(flags
); 
1647         ScrollIntoView(m_caretPosition
, keyCode
); 
1648         SetDefaultStyleToCursorStyle(); 
1654 /// Extend the selection. Selections are in caret positions. 
1655 bool wxRichTextCtrl::ExtendSelection(long oldPos
, long newPos
, int flags
) 
1657     if (flags 
& wxRICHTEXT_SHIFT_DOWN
) 
1659         if (oldPos 
== newPos
) 
1662         wxRichTextSelection oldSelection 
= m_selection
; 
1664         m_selection
.SetContainer(GetFocusObject()); 
1666         wxRichTextRange oldRange
; 
1667         if (m_selection
.IsValid()) 
1668             oldRange 
= m_selection
.GetRange(); 
1670             oldRange 
= wxRICHTEXT_NO_SELECTION
; 
1671         wxRichTextRange newRange
; 
1673         // If not currently selecting, start selecting 
1674         if (oldRange
.GetStart() == -2) 
1676             m_selectionAnchor 
= oldPos
; 
1678             if (oldPos 
> newPos
) 
1679                 newRange
.SetRange(newPos
+1, oldPos
); 
1681                 newRange
.SetRange(oldPos
+1, newPos
); 
1685             // Always ensure that the selection range start is greater than 
1687             if (newPos 
> m_selectionAnchor
) 
1688                 newRange
.SetRange(m_selectionAnchor
+1, newPos
); 
1689             else if (newPos 
== m_selectionAnchor
) 
1690                 newRange 
= wxRichTextRange(-2, -2); 
1692                 newRange
.SetRange(newPos
+1, m_selectionAnchor
); 
1695         m_selection
.SetRange(newRange
); 
1697         RefreshForSelectionChange(oldSelection
, m_selection
); 
1699         if (newRange
.GetStart() > newRange
.GetEnd()) 
1701             wxLogDebug(wxT("Strange selection range")); 
1710 /// Scroll into view, returning true if we scrolled. 
1711 /// This takes a _caret_ position. 
1712 bool wxRichTextCtrl::ScrollIntoView(long position
, int keyCode
) 
1714     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(position
); 
1720     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1722     int startXUnits
, startYUnits
; 
1723     GetViewStart(& startXUnits
, & startYUnits
); 
1724     int startY 
= startYUnits 
* ppuY
; 
1727     GetVirtualSize(& sx
, & sy
); 
1733     wxRect rect 
= GetScaledRect(line
->GetRect()); 
1735     bool scrolled 
= false; 
1737     wxSize clientSize 
= GetClientSize(); 
1739     int leftMargin
, rightMargin
, topMargin
, bottomMargin
; 
1742         wxClientDC 
dc(this); 
1743         wxRichTextObject::GetTotalMargin(dc
, & GetBuffer(), GetBuffer().GetAttributes(), leftMargin
, rightMargin
, 
1744             topMargin
, bottomMargin
); 
1746     clientSize
.y 
-= (int) (0.5 + bottomMargin 
* GetScale()); 
1748     if (GetWindowStyle() & wxRE_CENTRE_CARET
) 
1750         int y 
= rect
.y 
- GetClientSize().y
/2; 
1751         int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1752         if (y 
>= 0 && (y 
+ clientSize
.y
) < (int) (0.5 + GetBuffer().GetCachedSize().y 
* GetScale())) 
1754             if (startYUnits 
!= yUnits
) 
1756                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1759 #if !wxRICHTEXT_USE_OWN_CARET 
1769     if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN 
|| 
1770         keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT 
|| 
1771         keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END 
|| 
1772         keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1774         if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1776             // Make it scroll so this item is at the bottom 
1778             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1779             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1781             // If we're still off the screen, scroll another line down 
1782             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1785             if (startYUnits 
!= yUnits
) 
1787                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1791         else if (rect
.y 
< (startY 
+ (int) (0.5 + GetBuffer().GetTopMargin() * GetScale()))) 
1793             // Make it scroll so this item is at the top 
1795             int y 
= rect
.y 
- (int) (0.5 + GetBuffer().GetTopMargin() * GetScale()); 
1796             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1798             if (startYUnits 
!= yUnits
) 
1800                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1806     else if (keyCode 
== WXK_UP  
|| keyCode 
== WXK_NUMPAD_UP 
|| 
1807              keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT 
|| 
1808              keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME 
|| 
1809              keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP 
) 
1811         if (rect
.y 
< (startY 
+ (int) (0.5 + GetBuffer().GetBottomMargin() * GetScale()))) 
1813             // Make it scroll so this item is at the top 
1815             int y 
= rect
.y 
- (int) (0.5 + GetBuffer().GetTopMargin() * GetScale()); 
1816             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1818             if (startYUnits 
!= yUnits
) 
1820                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1824         else if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1826             // Make it scroll so this item is at the bottom 
1828             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1829             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1831             // If we're still off the screen, scroll another line down 
1832             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1835             if (startYUnits 
!= yUnits
) 
1837                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1843 #if !wxRICHTEXT_USE_OWN_CARET 
1851 /// Is the given position visible on the screen? 
1852 bool wxRichTextCtrl::IsPositionVisible(long pos
) const 
1854     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(pos
-1); 
1860     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1863     GetViewStart(& startX
, & startY
); 
1865     startY 
= startY 
* ppuY
; 
1867     wxRect rect 
= GetScaledRect(line
->GetRect()); 
1868     wxSize clientSize 
= GetClientSize(); 
1869     clientSize
.y 
-= (int) (0.5 + GetBuffer().GetBottomMargin() * GetScale()); 
1871     return (rect
.GetTop() >= (startY 
+ (int) (0.5 + GetBuffer().GetTopMargin() * GetScale()))) && 
1872            (rect
.GetBottom() <= (startY 
+ clientSize
.y
)); 
1875 void wxRichTextCtrl::SetCaretPosition(long position
, bool showAtLineStart
) 
1877     m_caretPosition 
= position
; 
1878     m_caretAtLineStart 
= showAtLineStart
; 
1881 /// Move caret one visual step forward: this may mean setting a flag 
1882 /// and keeping the same position if we're going from the end of one line 
1883 /// to the start of the next, which may be the exact same caret position. 
1884 void wxRichTextCtrl::MoveCaretForward(long oldPosition
) 
1886     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(oldPosition
); 
1888     // Only do the check if we're not at the end of the paragraph (where things work OK 
1890     if (para 
&& (oldPosition 
!= para
->GetRange().GetEnd() - 1)) 
1892         wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(oldPosition
); 
1896             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1898             // We're at the end of a line. See whether we need to 
1899             // stay at the same actual caret position but change visual 
1900             // position, or not. 
1901             if (oldPosition 
== lineRange
.GetEnd()) 
1903                 if (m_caretAtLineStart
) 
1905                     // We're already at the start of the line, so actually move on now. 
1906                     m_caretPosition 
= oldPosition 
+ 1; 
1907                     m_caretAtLineStart 
= false; 
1911                     // We're showing at the end of the line, so keep to 
1912                     // the same position but indicate that we're to show 
1913                     // at the start of the next line. 
1914                     m_caretPosition 
= oldPosition
; 
1915                     m_caretAtLineStart 
= true; 
1917                 SetDefaultStyleToCursorStyle(); 
1923     SetDefaultStyleToCursorStyle(); 
1926 /// Move caret one visual step backward: this may mean setting a flag 
1927 /// and keeping the same position if we're going from the end of one line 
1928 /// to the start of the next, which may be the exact same caret position. 
1929 void wxRichTextCtrl::MoveCaretBack(long oldPosition
) 
1931     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(oldPosition
); 
1933     // Only do the check if we're not at the start of the paragraph (where things work OK 
1935     if (para 
&& (oldPosition 
!= para
->GetRange().GetStart())) 
1937         wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(oldPosition
); 
1941             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1943             // We're at the start of a line. See whether we need to 
1944             // stay at the same actual caret position but change visual 
1945             // position, or not. 
1946             if (oldPosition 
== lineRange
.GetStart()) 
1948                 m_caretPosition 
= oldPosition
-1; 
1949                 m_caretAtLineStart 
= true; 
1952             else if (oldPosition 
== lineRange
.GetEnd()) 
1954                 if (m_caretAtLineStart
) 
1956                     // We're at the start of the line, so keep the same caret position 
1957                     // but clear the start-of-line flag. 
1958                     m_caretPosition 
= oldPosition
; 
1959                     m_caretAtLineStart 
= false; 
1963                     // We're showing at the end of the line, so go back 
1964                     // to the previous character position. 
1965                     m_caretPosition 
= oldPosition 
- 1; 
1967                 SetDefaultStyleToCursorStyle(); 
1973     SetDefaultStyleToCursorStyle(); 
1977 bool wxRichTextCtrl::MoveRight(int noPositions
, int flags
) 
1979     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd(); 
1981     if (m_caretPosition 
+ noPositions 
< endPos
) 
1983         long oldPos 
= m_caretPosition
; 
1984         long newPos 
= m_caretPosition 
+ noPositions
; 
1986         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1990         // Determine by looking at oldPos and m_caretPosition whether 
1991         // we moved from the end of a line to the start of the next line, in which case 
1992         // we want to adjust the caret position such that it is positioned at the 
1993         // start of the next line, rather than jumping past the first character of the 
1995         if (noPositions 
== 1 && !extendSel
) 
1996             MoveCaretForward(oldPos
); 
1998             SetCaretPosition(newPos
); 
2001         SetDefaultStyleToCursorStyle(); 
2010 bool wxRichTextCtrl::MoveLeft(int noPositions
, int flags
) 
2014     if (m_caretPosition 
> startPos 
- noPositions 
+ 1) 
2016         long oldPos 
= m_caretPosition
; 
2017         long newPos 
= m_caretPosition 
- noPositions
; 
2018         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2022         if (noPositions 
== 1 && !extendSel
) 
2023             MoveCaretBack(oldPos
); 
2025             SetCaretPosition(newPos
); 
2028         SetDefaultStyleToCursorStyle(); 
2036 // Find the caret position for the combination of hit-test flags and character position. 
2037 // Returns the caret position and also an indication of where to place the caret (caretLineStart) 
2038 // since this is ambiguous (same position used for end of line and start of next). 
2039 long wxRichTextCtrl::FindCaretPositionForCharacterPosition(long position
, int hitTestFlags
, wxRichTextParagraphLayoutBox
* container
, 
2040                                                    bool& caretLineStart
) 
2042     // If end of previous line, and hitTest is wxRICHTEXT_HITTEST_BEFORE, 
2043     // we want to be at the end of the last line but with m_caretAtLineStart set to true, 
2044     // so we view the caret at the start of the line. 
2045     caretLineStart 
= false; 
2046     long caretPosition 
= position
; 
2048     if (hitTestFlags 
& wxRICHTEXT_HITTEST_BEFORE
) 
2050         wxRichTextLine
* thisLine 
= container
->GetLineAtPosition(position
-1); 
2051         wxRichTextRange lineRange
; 
2053             lineRange 
= thisLine
->GetAbsoluteRange(); 
2055         if (thisLine 
&& (position
-1) == lineRange
.GetEnd()) 
2058             caretLineStart 
= true; 
2062             wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(position
); 
2063             if (para 
&& para
->GetRange().GetStart() == position
) 
2067     return caretPosition
; 
2071 bool wxRichTextCtrl::MoveUp(int noLines
, int flags
) 
2073     return MoveDown(- noLines
, flags
); 
2077 bool wxRichTextCtrl::MoveDown(int noLines
, int flags
) 
2082     long lineNumber 
= GetFocusObject()->GetVisibleLineNumber(m_caretPosition
, true, m_caretAtLineStart
); 
2083     wxPoint pt 
= GetCaret()->GetPosition(); 
2084     long newLine 
= lineNumber 
+ noLines
; 
2085     bool notInThisObject 
= false; 
2087     if (lineNumber 
!= -1) 
2091             long lastLine 
= GetFocusObject()->GetVisibleLineNumber(GetFocusObject()->GetOwnRange().GetEnd()); 
2092             if (newLine 
> lastLine
) 
2093                 notInThisObject 
= true; 
2098                 notInThisObject 
= true; 
2102     wxRichTextParagraphLayoutBox
* container 
= GetFocusObject(); 
2103     int hitTestFlags 
= wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
|wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS
|wxRICHTEXT_HITTEST_HONOUR_ATOMIC
; 
2105     if (notInThisObject
) 
2107         // If we know we're navigating out of the current object, 
2108         // try to find an object anywhere in the buffer at the new position (up or down a bit) 
2109         container 
= & GetBuffer(); 
2110         hitTestFlags 
&= ~wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
; 
2112         if (noLines 
> 0) // going down 
2114             pt
.y 
= GetFocusObject()->GetPosition().y 
+ GetFocusObject()->GetCachedSize().y 
+ 2; 
2118             pt
.y 
= GetFocusObject()->GetPosition().y 
- 2; 
2123         wxRichTextLine
* lineObj 
= GetFocusObject()->GetLineForVisibleLineNumber(newLine
); 
2125             pt
.y 
= lineObj
->GetAbsolutePosition().y 
+ 2; 
2131     wxClientDC 
dc(this); 
2133     dc
.SetFont(GetFont()); 
2135     wxRichTextObject
* hitObj 
= NULL
; 
2136     wxRichTextObject
* contextObj 
= NULL
; 
2137     wxRichTextDrawingContext 
context(& GetBuffer()); 
2138     int hitTest 
= container
->HitTest(dc
, context
, pt
, newPos
, & hitObj
, & contextObj
, hitTestFlags
); 
2141         ((hitTest 
& wxRICHTEXT_HITTEST_NONE
) == 0) && 
2142         (! (hitObj 
== (& m_buffer
) && ((hitTest 
& wxRICHTEXT_HITTEST_OUTSIDE
) != 0))) // outside the buffer counts as 'do nothing' 
2145         if (notInThisObject
) 
2147             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
2148             if (actualContainer 
&& actualContainer 
!= GetFocusObject() && actualContainer
->AcceptsFocus()) 
2150                 SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
2152                 container 
= actualContainer
; 
2156         bool caretLineStart 
= true; 
2157         long caretPosition 
= FindCaretPositionForCharacterPosition(newPos
, hitTest
, container
, caretLineStart
); 
2158         long newSelEnd 
= caretPosition
; 
2161         if (notInThisObject
) 
2164             extendSel 
= ExtendSelection(m_caretPosition
, newSelEnd
, flags
); 
2169         SetCaretPosition(caretPosition
, caretLineStart
); 
2171         SetDefaultStyleToCursorStyle(); 
2179 /// Move to the end of the paragraph 
2180 bool wxRichTextCtrl::MoveToParagraphEnd(int flags
) 
2182     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(m_caretPosition
, true); 
2185         long newPos 
= para
->GetRange().GetEnd() - 1; 
2186         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2190         SetCaretPosition(newPos
); 
2192         SetDefaultStyleToCursorStyle(); 
2200 /// Move to the start of the paragraph 
2201 bool wxRichTextCtrl::MoveToParagraphStart(int flags
) 
2203     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(m_caretPosition
, true); 
2206         long newPos 
= para
->GetRange().GetStart() - 1; 
2207         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2211         SetCaretPosition(newPos
, true); 
2213         SetDefaultStyleToCursorStyle(); 
2221 /// Move to the end of the line 
2222 bool wxRichTextCtrl::MoveToLineEnd(int flags
) 
2224     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
2228         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2229         long newPos 
= lineRange
.GetEnd(); 
2230         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2234         SetCaretPosition(newPos
); 
2236         SetDefaultStyleToCursorStyle(); 
2244 /// Move to the start of the line 
2245 bool wxRichTextCtrl::MoveToLineStart(int flags
) 
2247     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
2250         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2251         long newPos 
= lineRange
.GetStart()-1; 
2253         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
2257         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphForLine(line
); 
2259         SetCaretPosition(newPos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
2261         SetDefaultStyleToCursorStyle(); 
2269 /// Move to the start of the buffer 
2270 bool wxRichTextCtrl::MoveHome(int flags
) 
2272     if (m_caretPosition 
!= -1) 
2274         bool extendSel 
= ExtendSelection(m_caretPosition
, -1, flags
); 
2278         SetCaretPosition(-1); 
2280         SetDefaultStyleToCursorStyle(); 
2288 /// Move to the end of the buffer 
2289 bool wxRichTextCtrl::MoveEnd(int flags
) 
2291     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd()-1; 
2293     if (m_caretPosition 
!= endPos
) 
2295         bool extendSel 
= ExtendSelection(m_caretPosition
, endPos
, flags
); 
2299         SetCaretPosition(endPos
); 
2301         SetDefaultStyleToCursorStyle(); 
2309 /// Move noPages pages up 
2310 bool wxRichTextCtrl::PageUp(int noPages
, int flags
) 
2312     return PageDown(- noPages
, flags
); 
2315 /// Move noPages pages down 
2316 bool wxRichTextCtrl::PageDown(int noPages
, int flags
) 
2318     // Calculate which line occurs noPages * screen height further down. 
2319     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
2322         wxSize clientSize 
= GetClientSize(); 
2323         int newY 
= line
->GetAbsolutePosition().y 
+ noPages
*clientSize
.y
; 
2325         wxRichTextLine
* newLine 
= GetFocusObject()->GetLineAtYPosition(newY
); 
2328             wxRichTextRange lineRange 
= newLine
->GetAbsoluteRange(); 
2329             long pos 
= lineRange
.GetStart()-1; 
2330             if (pos 
!= m_caretPosition
) 
2332                 wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphForLine(newLine
); 
2334                 bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2338                 SetCaretPosition(pos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
2340                 SetDefaultStyleToCursorStyle(); 
2350 static bool wxRichTextCtrlIsWhitespace(const wxString
& str
) 
2352     return str 
== wxT(" ") || str 
== wxT("\t") || (!str
.empty() && (str
[0] == (wxChar
) 160)); 
2355 // Finds the caret position for the next word 
2356 long wxRichTextCtrl::FindNextWordPosition(int direction
) const 
2358     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd(); 
2362         long i 
= m_caretPosition
+1+direction
; // +1 for conversion to character pos 
2364         // First skip current text to space 
2365         while (i 
< endPos 
&& i 
> -1) 
2367             // i is in character, not caret positions 
2368             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2369             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2370             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
2374             else if (!wxRichTextCtrlIsWhitespace(text
) && !text
.empty()) 
2381         while (i 
< endPos 
&& i 
> -1) 
2383             // i is in character, not caret positions 
2384             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2385             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2386             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
2387                 return wxMax(-1, i
); 
2389             if (text
.empty()) // End of paragraph, or maybe an image 
2390                 return wxMax(-1, i 
- 1); 
2391             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
2395                 // Convert to caret position 
2396                 return wxMax(-1, i 
- 1); 
2405         long i 
= m_caretPosition
; 
2407         // First skip white space 
2408         while (i 
< endPos 
&& i 
> -1) 
2410             // i is in character, not caret positions 
2411             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2412             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2414             if (text
.empty() || (line 
&& (i 
== line
->GetAbsoluteRange().GetStart()))) // End of paragraph, or maybe an image 
2416             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
2421         // Next skip current text to space 
2422         while (i 
< endPos 
&& i 
> -1) 
2424             // i is in character, not caret positions 
2425             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2426             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2427             if (line 
&& line
->GetAbsoluteRange().GetStart() == i
) 
2430             if (!wxRichTextCtrlIsWhitespace(text
) /* && !text.empty() */) 
2443 /// Move n words left 
2444 bool wxRichTextCtrl::WordLeft(int WXUNUSED(n
), int flags
) 
2446     long pos 
= FindNextWordPosition(-1); 
2447     if (pos 
!= m_caretPosition
) 
2449         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
, true); 
2451         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2455         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
2457         SetDefaultStyleToCursorStyle(); 
2465 /// Move n words right 
2466 bool wxRichTextCtrl::WordRight(int WXUNUSED(n
), int flags
) 
2468     long pos 
= FindNextWordPosition(1); 
2469     if (pos 
!= m_caretPosition
) 
2471         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
, true); 
2473         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2477         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
2479         SetDefaultStyleToCursorStyle(); 
2488 void wxRichTextCtrl::OnSize(wxSizeEvent
& event
) 
2490     // Only do sizing optimization for large buffers 
2491     if (GetBuffer().GetOwnRange().GetEnd() > m_delayedLayoutThreshold
) 
2493         m_fullLayoutRequired 
= true; 
2494         m_fullLayoutTime 
= wxGetLocalTimeMillis(); 
2495         m_fullLayoutSavedPosition 
= GetFirstVisiblePosition(); 
2496         LayoutContent(true /* onlyVisibleRect */); 
2499         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2501 #if wxRICHTEXT_BUFFERED_PAINTING 
2508 // Force any pending layout due to large buffer 
2509 void wxRichTextCtrl::ForceDelayedLayout() 
2511     if (m_fullLayoutRequired
) 
2513         m_fullLayoutRequired 
= false; 
2514         m_fullLayoutTime 
= 0; 
2515         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2516         ShowPosition(m_fullLayoutSavedPosition
); 
2522 /// Idle-time processing 
2523 void wxRichTextCtrl::OnIdle(wxIdleEvent
& event
) 
2525 #if wxRICHTEXT_USE_OWN_CARET 
2526     if (((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
2528         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(false); 
2534     const int layoutInterval 
= wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL
; 
2536     if (m_fullLayoutRequired 
&& (wxGetLocalTimeMillis() > (m_fullLayoutTime 
+ layoutInterval
))) 
2538         m_fullLayoutRequired 
= false; 
2539         m_fullLayoutTime 
= 0; 
2540         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2541         ShowPosition(m_fullLayoutSavedPosition
); 
2545     if (m_caretPositionForDefaultStyle 
!= -2) 
2547         // If the caret position has changed, no longer reflect the default style 
2549         if (GetCaretPosition() != m_caretPositionForDefaultStyle
) 
2550             m_caretPositionForDefaultStyle 
= -2; 
2557 void wxRichTextCtrl::OnScroll(wxScrollWinEvent
& event
) 
2559 #if wxRICHTEXT_USE_OWN_CARET 
2560     if (!((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
2563         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(); 
2570 /// Set up scrollbars, e.g. after a resize 
2571 void wxRichTextCtrl::SetupScrollbars(bool atTop
) 
2576     if (GetBuffer().IsEmpty() || !m_verticalScrollbarEnabled
) 
2578         SetScrollbars(0, 0, 0, 0, 0, 0); 
2582     // TODO: reimplement scrolling so we scroll by line, not by fixed number 
2583     // of pixels. See e.g. wxVScrolledWindow for ideas. 
2584     int pixelsPerUnit 
= 5; 
2585     wxSize clientSize 
= GetClientSize(); 
2587     int maxHeight 
= (int) (0.5 + GetScale() * (GetBuffer().GetCachedSize().y 
+ GetBuffer().GetTopMargin())); 
2589     // Round up so we have at least maxHeight pixels 
2590     int unitsY 
= (int) (((float)maxHeight
/(float)pixelsPerUnit
) + 0.5); 
2592     int startX 
= 0, startY 
= 0; 
2594         GetViewStart(& startX
, & startY
); 
2596     int maxPositionX 
= 0; 
2597     int maxPositionY 
= (int) ((((float)(wxMax((unitsY
*pixelsPerUnit
) - clientSize
.y
, 0)))/((float)pixelsPerUnit
)) + 0.5); 
2599     int newStartX 
= wxMin(maxPositionX
, startX
); 
2600     int newStartY 
= wxMin(maxPositionY
, startY
); 
2602     int oldPPUX
, oldPPUY
; 
2603     int oldStartX
, oldStartY
; 
2604     int oldVirtualSizeX 
= 0, oldVirtualSizeY 
= 0; 
2605     GetScrollPixelsPerUnit(& oldPPUX
, & oldPPUY
); 
2606     GetViewStart(& oldStartX
, & oldStartY
); 
2607     GetVirtualSize(& oldVirtualSizeX
, & oldVirtualSizeY
); 
2609         oldVirtualSizeY 
/= oldPPUY
; 
2611     if (oldPPUX 
== 0 && oldPPUY 
== pixelsPerUnit 
&& oldVirtualSizeY 
== unitsY 
&& oldStartX 
== newStartX 
&& oldStartY 
== newStartY
) 
2614     // Don't set scrollbars if there were none before, and there will be none now. 
2615     if (oldPPUY 
!= 0 && (oldVirtualSizeY
*oldPPUY 
< clientSize
.y
) && (unitsY
*pixelsPerUnit 
< clientSize
.y
)) 
2618     // Move to previous scroll position if 
2620     SetScrollbars(0, pixelsPerUnit
, 0, unitsY
, newStartX
, newStartY
); 
2623 /// Paint the background 
2624 void wxRichTextCtrl::PaintBackground(wxDC
& dc
) 
2626     wxColour backgroundColour 
= GetBackgroundColour(); 
2627     if (!backgroundColour
.IsOk()) 
2628         backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
2630     // Clear the background 
2631     dc
.SetBrush(wxBrush(backgroundColour
)); 
2632     dc
.SetPen(*wxTRANSPARENT_PEN
); 
2633     wxRect 
windowRect(GetClientSize()); 
2634     windowRect
.x 
-= 2; windowRect
.y 
-= 2; 
2635     windowRect
.width 
+= 4; windowRect
.height 
+= 4; 
2637     // We need to shift the rectangle to take into account 
2638     // scrolling. Converting device to logical coordinates. 
2639     CalcUnscrolledPosition(windowRect
.x
, windowRect
.y
, & windowRect
.x
, & windowRect
.y
); 
2640     dc
.DrawRectangle(windowRect
); 
2643 #if wxRICHTEXT_BUFFERED_PAINTING 
2644 /// Recreate buffer bitmap if necessary 
2645 bool wxRichTextCtrl::RecreateBuffer(const wxSize
& size
) 
2648     if (sz 
== wxDefaultSize
) 
2649         sz 
= GetClientSize(); 
2651     if (sz
.x 
< 1 || sz
.y 
< 1) 
2654     if (!m_bufferBitmap
.IsOk() || m_bufferBitmap
.GetWidth() < sz
.x 
|| m_bufferBitmap
.GetHeight() < sz
.y
) 
2655         m_bufferBitmap 
= wxBitmap(sz
.x
, sz
.y
); 
2656     return m_bufferBitmap
.IsOk(); 
2660 // ---------------------------------------------------------------------------- 
2661 // file IO functions 
2662 // ---------------------------------------------------------------------------- 
2664 bool wxRichTextCtrl::DoLoadFile(const wxString
& filename
, int fileType
) 
2666     SetFocusObject(& GetBuffer(), true); 
2668     bool success 
= GetBuffer().LoadFile(filename
, (wxRichTextFileType
)fileType
); 
2670         m_filename 
= filename
; 
2673     SetInsertionPoint(0); 
2676     SetupScrollbars(true); 
2678     wxTextCtrl::SendTextUpdatedEvent(this); 
2684         wxLogError(_("File couldn't be loaded.")); 
2690 bool wxRichTextCtrl::DoSaveFile(const wxString
& filename
, int fileType
) 
2692     if (GetBuffer().SaveFile(filename
, (wxRichTextFileType
)fileType
)) 
2694         m_filename 
= filename
; 
2701     wxLogError(_("The text couldn't be saved.")); 
2706 // ---------------------------------------------------------------------------- 
2707 // wxRichTextCtrl specific functionality 
2708 // ---------------------------------------------------------------------------- 
2710 /// Add a new paragraph of text to the end of the buffer 
2711 wxRichTextRange 
wxRichTextCtrl::AddParagraph(const wxString
& text
) 
2713     wxRichTextRange range 
= GetFocusObject()->AddParagraph(text
); 
2714     GetBuffer().Invalidate(); 
2720 wxRichTextRange 
wxRichTextCtrl::AddImage(const wxImage
& image
) 
2722     wxRichTextRange range 
= GetFocusObject()->AddImage(image
); 
2723     GetBuffer().Invalidate(); 
2728 // ---------------------------------------------------------------------------- 
2729 // selection and ranges 
2730 // ---------------------------------------------------------------------------- 
2732 void wxRichTextCtrl::SelectAll() 
2734     SetSelection(-1, -1); 
2738 void wxRichTextCtrl::SelectNone() 
2740     if (m_selection
.IsValid()) 
2742         wxRichTextSelection oldSelection 
= m_selection
; 
2744         m_selection
.Reset(); 
2746         RefreshForSelectionChange(oldSelection
, m_selection
); 
2748     m_selectionAnchor 
= -2; 
2749     m_selectionAnchorObject 
= NULL
; 
2750     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
2753 static bool wxIsWordDelimiter(const wxString
& text
) 
2755     return !text
.IsEmpty() && !wxIsalnum(text
[0]); 
2758 /// Select the word at the given character position 
2759 bool wxRichTextCtrl::SelectWord(long position
) 
2761     if (position 
< 0 || position 
> GetFocusObject()->GetOwnRange().GetEnd()) 
2764     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(position
); 
2768     if (position 
== para
->GetRange().GetEnd()) 
2771     long positionStart 
= position
; 
2772     long positionEnd 
= position
; 
2774     for (positionStart 
= position
; positionStart 
>= para
->GetRange().GetStart(); positionStart 
--) 
2776         wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(positionStart
, positionStart
)); 
2777         if (wxIsWordDelimiter(text
)) 
2783     if (positionStart 
< para
->GetRange().GetStart()) 
2784         positionStart 
= para
->GetRange().GetStart(); 
2786     for (positionEnd 
= position
; positionEnd 
< para
->GetRange().GetEnd(); positionEnd 
++) 
2788         wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(positionEnd
, positionEnd
)); 
2789         if (wxIsWordDelimiter(text
)) 
2795     if (positionEnd 
>= para
->GetRange().GetEnd()) 
2796         positionEnd 
= para
->GetRange().GetEnd(); 
2798     if (positionEnd 
< positionStart
) 
2801     SetSelection(positionStart
, positionEnd
+1); 
2803     if (positionStart 
>= 0) 
2805         MoveCaret(positionStart
-1, true); 
2806         SetDefaultStyleToCursorStyle(); 
2812 wxString 
wxRichTextCtrl::GetStringSelection() const 
2815     GetSelection(&from
, &to
); 
2817     return GetRange(from
, to
); 
2820 // ---------------------------------------------------------------------------- 
2822 // ---------------------------------------------------------------------------- 
2824 wxTextCtrlHitTestResult
 
2825 wxRichTextCtrl::HitTest(const wxPoint
& pt
, wxTextCoord 
*x
, wxTextCoord 
*y
) const 
2827     // implement in terms of the other overload as the native ports typically 
2828     // can get the position and not (x, y) pair directly (although wxUniv 
2829     // directly gets x and y -- and so overrides this method as well) 
2831     wxTextCtrlHitTestResult rc 
= HitTest(pt
, &pos
); 
2833     if ( rc 
!= wxTE_HT_UNKNOWN 
) 
2835         PositionToXY(pos
, x
, y
); 
2841 wxTextCtrlHitTestResult
 
2842 wxRichTextCtrl::HitTest(const wxPoint
& pt
, 
2845     wxClientDC 
dc((wxRichTextCtrl
*) this); 
2846     ((wxRichTextCtrl
*)this)->PrepareDC(dc
); 
2848     // Buffer uses logical position (relative to start of buffer) 
2850     wxPoint pt2 
= GetLogicalPoint(pt
); 
2852     wxRichTextObject
* hitObj 
= NULL
; 
2853     wxRichTextObject
* contextObj 
= NULL
; 
2854     wxRichTextDrawingContext 
context((wxRichTextBuffer
*) & GetBuffer()); 
2855     int hit 
= ((wxRichTextCtrl
*)this)->GetFocusObject()->HitTest(dc
, context
, pt2
, *pos
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
); 
2857     if ((hit 
& wxRICHTEXT_HITTEST_BEFORE
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2858         return wxTE_HT_BEFORE
; 
2859     else if ((hit 
& wxRICHTEXT_HITTEST_AFTER
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2860         return wxTE_HT_BEYOND
; 
2861     else if (hit 
& (wxRICHTEXT_HITTEST_BEFORE
|wxRICHTEXT_HITTEST_AFTER
)) 
2862         return wxTE_HT_ON_TEXT
; 
2864     return wxTE_HT_UNKNOWN
; 
2867 wxRichTextParagraphLayoutBox
* 
2868 wxRichTextCtrl::FindContainerAtPoint(const wxPoint pt
, long& position
, int& hit
, wxRichTextObject
* hitObj
, int flags
/* = 0*/) 
2870     wxClientDC 
dc(this); 
2872     dc
.SetFont(GetFont()); 
2874     wxPoint logicalPt 
= GetLogicalPoint(pt
); 
2876     wxRichTextObject
* contextObj 
= NULL
; 
2877     wxRichTextDrawingContext 
context(& GetBuffer()); 
2878     hit 
= GetBuffer().HitTest(dc
, context
, GetUnscaledPoint(logicalPt
), position
, &hitObj
, &contextObj
, flags
); 
2879     wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
2885 // ---------------------------------------------------------------------------- 
2886 // set/get the controls text 
2887 // ---------------------------------------------------------------------------- 
2889 wxString 
wxRichTextCtrl::DoGetValue() const 
2891     return GetBuffer().GetText(); 
2894 wxString 
wxRichTextCtrl::GetRange(long from
, long to
) const 
2896     // Public API for range is different from internals 
2897     return GetFocusObject()->GetTextForRange(wxRichTextRange(from
, to
-1)); 
2900 void wxRichTextCtrl::DoSetValue(const wxString
& value
, int flags
) 
2902     // Don't call Clear here, since it always sends a text updated event 
2903     m_buffer
.ResetAndClearCommands(); 
2904     m_buffer
.Invalidate(wxRICHTEXT_ALL
); 
2905     m_caretPosition 
= -1; 
2906     m_caretPositionForDefaultStyle 
= -2; 
2907     m_caretAtLineStart 
= false; 
2908     m_selection
.Reset(); 
2909     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
2919     if (!value
.IsEmpty()) 
2921         // Remove empty paragraph 
2922         GetBuffer().Clear(); 
2923         DoWriteText(value
, flags
); 
2925         // for compatibility, don't move the cursor when doing SetValue() 
2926         SetInsertionPoint(0); 
2930         // still send an event for consistency 
2931         if (flags 
& SetValue_SendEvent
) 
2932             wxTextCtrl::SendTextUpdatedEvent(this); 
2937 void wxRichTextCtrl::WriteText(const wxString
& value
) 
2942 void wxRichTextCtrl::DoWriteText(const wxString
& value
, int flags
) 
2944     wxString valueUnix 
= wxTextFile::Translate(value
, wxTextFileType_Unix
); 
2946     GetFocusObject()->InsertTextWithUndo(& GetBuffer(), m_caretPosition
+1, valueUnix
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2947     GetBuffer().Defragment(); 
2949     if ( flags 
& SetValue_SendEvent 
) 
2950         wxTextCtrl::SendTextUpdatedEvent(this); 
2953 void wxRichTextCtrl::AppendText(const wxString
& text
) 
2955     SetInsertionPointEnd(); 
2960 /// Write an image at the current insertion point 
2961 bool wxRichTextCtrl::WriteImage(const wxImage
& image
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2963     wxRichTextImageBlock imageBlock
; 
2965     wxImage image2 
= image
; 
2966     if (imageBlock
.MakeImageBlock(image2
, bitmapType
)) 
2967         return WriteImage(imageBlock
, textAttr
); 
2972 bool wxRichTextCtrl::WriteImage(const wxString
& filename
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2974     wxRichTextImageBlock imageBlock
; 
2977     if (imageBlock
.MakeImageBlock(filename
, bitmapType
, image
, false)) 
2978         return WriteImage(imageBlock
, textAttr
); 
2983 bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock
& imageBlock
, const wxRichTextAttr
& textAttr
) 
2985     return GetFocusObject()->InsertImageWithUndo(& GetBuffer(), m_caretPosition
+1, imageBlock
, this, 0, textAttr
); 
2988 bool wxRichTextCtrl::WriteImage(const wxBitmap
& bitmap
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2992         wxRichTextImageBlock imageBlock
; 
2994         wxImage image 
= bitmap
.ConvertToImage(); 
2995         if (image
.IsOk() && imageBlock
.MakeImageBlock(image
, bitmapType
)) 
2996             return WriteImage(imageBlock
, textAttr
); 
3002 // Write a text box at the current insertion point. 
3003 wxRichTextBox
* wxRichTextCtrl::WriteTextBox(const wxRichTextAttr
& textAttr
) 
3005     wxRichTextBox
* textBox 
= new wxRichTextBox
; 
3006     textBox
->SetAttributes(textAttr
); 
3007     textBox
->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style 
3008     textBox
->AddParagraph(wxEmptyString
); 
3009     textBox
->SetParent(NULL
); 
3011     // The object returned is the one actually inserted into the buffer, 
3012     // while the original one is deleted. 
3013     wxRichTextObject
* obj 
= GetFocusObject()->InsertObjectWithUndo(& GetBuffer(), m_caretPosition
+1, textBox
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
3014     wxRichTextBox
* box 
= wxDynamicCast(obj
, wxRichTextBox
); 
3018 wxRichTextField
* wxRichTextCtrl::WriteField(const wxString
& fieldType
, const wxRichTextProperties
& properties
, 
3019                             const wxRichTextAttr
& textAttr
) 
3021     return GetFocusObject()->InsertFieldWithUndo(& GetBuffer(), m_caretPosition
+1, fieldType
, properties
, 
3022                 this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
, textAttr
); 
3025 // Write a table at the current insertion point, returning the table. 
3026 wxRichTextTable
* wxRichTextCtrl::WriteTable(int rows
, int cols
, const wxRichTextAttr
& tableAttr
, const wxRichTextAttr
& cellAttr
) 
3028     wxASSERT(rows 
> 0 && cols 
> 0); 
3030     if (rows 
<= 0 || cols 
<= 0) 
3033     wxRichTextTable
* table 
= new wxRichTextTable
; 
3034     table
->SetAttributes(tableAttr
); 
3035     table
->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style 
3037     table
->CreateTable(rows
, cols
); 
3039     table
->SetParent(NULL
); 
3042     for (j 
= 0; j 
< rows
; j
++) 
3044         for (i 
= 0; i 
< cols
; i
++) 
3046             table
->GetCell(j
, i
)->GetAttributes() = cellAttr
; 
3050     // The object returned is the one actually inserted into the buffer, 
3051     // while the original one is deleted. 
3052     wxRichTextObject
* obj 
= GetFocusObject()->InsertObjectWithUndo(& GetBuffer(), m_caretPosition
+1, table
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
3053     wxRichTextTable
* tableResult 
= wxDynamicCast(obj
, wxRichTextTable
); 
3058 /// Insert a newline (actually paragraph) at the current insertion point. 
3059 bool wxRichTextCtrl::Newline() 
3061     return GetFocusObject()->InsertNewlineWithUndo(& GetBuffer(), m_caretPosition
+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
3064 /// Insert a line break at the current insertion point. 
3065 bool wxRichTextCtrl::LineBreak() 
3068     text 
= wxRichTextLineBreakChar
; 
3069     return GetFocusObject()->InsertTextWithUndo(& GetBuffer(), m_caretPosition
+1, text
, this); 
3072 // ---------------------------------------------------------------------------- 
3073 // Clipboard operations 
3074 // ---------------------------------------------------------------------------- 
3076 void wxRichTextCtrl::Copy() 
3080         wxRichTextRange range 
= GetInternalSelectionRange(); 
3081         GetBuffer().CopyToClipboard(range
); 
3085 void wxRichTextCtrl::Cut() 
3089         wxRichTextRange range 
= GetInternalSelectionRange(); 
3090         GetBuffer().CopyToClipboard(range
); 
3092         DeleteSelectedContent(); 
3098 void wxRichTextCtrl::Paste() 
3102         BeginBatchUndo(_("Paste")); 
3104         long newPos 
= m_caretPosition
; 
3105         DeleteSelectedContent(& newPos
); 
3107         GetBuffer().PasteFromClipboard(newPos
); 
3113 void wxRichTextCtrl::DeleteSelection() 
3115     if (CanDeleteSelection()) 
3117         DeleteSelectedContent(); 
3121 bool wxRichTextCtrl::HasSelection() const 
3123     return (m_selection
.IsValid() && m_selection
.GetContainer() == GetFocusObject()); 
3126 bool wxRichTextCtrl::HasUnfocusedSelection() const 
3128     return m_selection
.IsValid(); 
3131 bool wxRichTextCtrl::CanCopy() const 
3133     // Can copy if there's a selection 
3134     return HasSelection(); 
3137 bool wxRichTextCtrl::CanCut() const 
3139     return CanDeleteSelection(); 
3142 bool wxRichTextCtrl::CanPaste() const 
3144     if ( !IsEditable() || !GetFocusObject() || !CanInsertContent(* GetFocusObject(), m_caretPosition
+1)) 
3147     return GetBuffer().CanPasteFromClipboard(); 
3150 bool wxRichTextCtrl::CanDeleteSelection() const 
3152     return HasSelection() && IsEditable() && CanDeleteRange(* GetFocusObject(), GetSelectionRange()); 
3156 // ---------------------------------------------------------------------------- 
3158 // ---------------------------------------------------------------------------- 
3160 void wxRichTextCtrl::SetContextMenu(wxMenu
* menu
) 
3162     if (m_contextMenu 
&& m_contextMenu 
!= menu
) 
3163         delete m_contextMenu
; 
3164     m_contextMenu 
= menu
; 
3167 void wxRichTextCtrl::SetEditable(bool editable
) 
3169     m_editable 
= editable
; 
3172 void wxRichTextCtrl::SetInsertionPoint(long pos
) 
3176     m_caretPosition 
= pos 
- 1; 
3177     m_caretAtLineStart 
= true; 
3181     SetDefaultStyleToCursorStyle(); 
3184 void wxRichTextCtrl::SetInsertionPointEnd() 
3186     long pos 
= GetLastPosition(); 
3187     SetInsertionPoint(pos
); 
3190 long wxRichTextCtrl::GetInsertionPoint() const 
3192     return m_caretPosition
+1; 
3195 wxTextPos 
wxRichTextCtrl::GetLastPosition() const 
3197     return GetFocusObject()->GetOwnRange().GetEnd(); 
3200 // If the return values from and to are the same, there is no 
3202 void wxRichTextCtrl::GetSelection(long* from
, long* to
) const 
3204     if (m_selection
.IsValid()) 
3206         *from 
= m_selection
.GetRange().GetStart(); 
3207         *to 
= m_selection
.GetRange().GetEnd(); 
3217 bool wxRichTextCtrl::IsEditable() const 
3222 // ---------------------------------------------------------------------------- 
3224 // ---------------------------------------------------------------------------- 
3226 void wxRichTextCtrl::SetSelection(long from
, long to
) 
3228     // if from and to are both -1, it means (in wxWidgets) that all text should 
3230     if ( (from 
== -1) && (to 
== -1) ) 
3233         to 
= GetLastPosition()+1; 
3242         wxRichTextSelection oldSelection 
= m_selection
; 
3244         m_selectionAnchor 
= from
-1; 
3245         m_selectionAnchorObject 
= NULL
; 
3246         m_selection
.Set(wxRichTextRange(from
, to
-1), GetFocusObject()); 
3248         m_caretPosition 
= wxMax(-1, to
-1); 
3250         RefreshForSelectionChange(oldSelection
, m_selection
); 
3255 // ---------------------------------------------------------------------------- 
3257 // ---------------------------------------------------------------------------- 
3259 void wxRichTextCtrl::Replace(long from
, long to
, 
3260                              const wxString
& value
) 
3262     BeginBatchUndo(_("Replace")); 
3264     SetSelection(from
, to
); 
3266     wxRichTextAttr attr 
= GetDefaultStyle(); 
3268     DeleteSelectedContent(); 
3270     SetDefaultStyle(attr
); 
3272     DoWriteText(value
, SetValue_SelectionOnly
); 
3277 void wxRichTextCtrl::Remove(long from
, long to
) 
3281     GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(from
, to
-1), this, & GetBuffer()); 
3288 bool wxRichTextCtrl::IsModified() const 
3290     return m_buffer
.IsModified(); 
3293 void wxRichTextCtrl::MarkDirty() 
3295     m_buffer
.Modify(true); 
3298 void wxRichTextCtrl::DiscardEdits() 
3300     m_caretPositionForDefaultStyle 
= -2; 
3301     m_buffer
.Modify(false); 
3302     m_buffer
.GetCommandProcessor()->ClearCommands(); 
3305 int wxRichTextCtrl::GetNumberOfLines() const 
3307     return GetFocusObject()->GetParagraphCount(); 
3310 // ---------------------------------------------------------------------------- 
3311 // Positions <-> coords 
3312 // ---------------------------------------------------------------------------- 
3314 long wxRichTextCtrl::XYToPosition(long x
, long y
) const 
3316     return GetFocusObject()->XYToPosition(x
, y
); 
3319 bool wxRichTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
3321     return GetFocusObject()->PositionToXY(pos
, x
, y
); 
3324 // ---------------------------------------------------------------------------- 
3326 // ---------------------------------------------------------------------------- 
3328 void wxRichTextCtrl::ShowPosition(long pos
) 
3330     if (!IsPositionVisible(pos
)) 
3331         ScrollIntoView(pos
-1, WXK_DOWN
); 
3334 int wxRichTextCtrl::GetLineLength(long lineNo
) const 
3336     return GetFocusObject()->GetParagraphLength(lineNo
); 
3339 wxString 
wxRichTextCtrl::GetLineText(long lineNo
) const 
3341     return GetFocusObject()->GetParagraphText(lineNo
); 
3344 // ---------------------------------------------------------------------------- 
3346 // ---------------------------------------------------------------------------- 
3348 void wxRichTextCtrl::Undo() 
3352         GetCommandProcessor()->Undo(); 
3356 void wxRichTextCtrl::Redo() 
3360         GetCommandProcessor()->Redo(); 
3364 bool wxRichTextCtrl::CanUndo() const 
3366     return GetCommandProcessor()->CanUndo() && IsEditable(); 
3369 bool wxRichTextCtrl::CanRedo() const 
3371     return GetCommandProcessor()->CanRedo() && IsEditable(); 
3374 // ---------------------------------------------------------------------------- 
3375 // implementation details 
3376 // ---------------------------------------------------------------------------- 
3378 void wxRichTextCtrl::Command(wxCommandEvent
& event
) 
3380     SetValue(event
.GetString()); 
3381     GetEventHandler()->ProcessEvent(event
); 
3384 void wxRichTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
3386     // By default, load the first file into the text window. 
3387     if (event
.GetNumberOfFiles() > 0) 
3389         LoadFile(event
.GetFiles()[0]); 
3393 wxSize 
wxRichTextCtrl::DoGetBestSize() const 
3395     return wxSize(10, 10); 
3398 // ---------------------------------------------------------------------------- 
3399 // standard handlers for standard edit menu events 
3400 // ---------------------------------------------------------------------------- 
3402 void wxRichTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
3407 void wxRichTextCtrl::OnClear(wxCommandEvent
& WXUNUSED(event
)) 
3412 void wxRichTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
3417 void wxRichTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
3422 void wxRichTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
3427 void wxRichTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
3432 void wxRichTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
3434     event
.Enable( CanCut() ); 
3437 void wxRichTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
3439     event
.Enable( CanCopy() ); 
3442 void wxRichTextCtrl::OnUpdateClear(wxUpdateUIEvent
& event
) 
3444     event
.Enable( CanDeleteSelection() ); 
3447 void wxRichTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
3449     event
.Enable( CanPaste() ); 
3452 void wxRichTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
3454     event
.Enable( CanUndo() ); 
3455     event
.SetText( GetCommandProcessor()->GetUndoMenuLabel() ); 
3458 void wxRichTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
3460     event
.Enable( CanRedo() ); 
3461     event
.SetText( GetCommandProcessor()->GetRedoMenuLabel() ); 
3464 void wxRichTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
3466     if (GetLastPosition() > 0) 
3470 void wxRichTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
3472     event
.Enable(GetLastPosition() > 0); 
3475 void wxRichTextCtrl::OnProperties(wxCommandEvent
& event
) 
3477     int idx 
= event
.GetId() - wxID_RICHTEXT_PROPERTIES1
; 
3478     if (idx 
>= 0 && idx 
< m_contextMenuPropertiesInfo
.GetCount()) 
3480         wxRichTextObject
* obj 
= m_contextMenuPropertiesInfo
.GetObject(idx
); 
3481         if (obj 
&& CanEditProperties(obj
)) 
3482             EditProperties(obj
, this); 
3484         m_contextMenuPropertiesInfo
.Clear(); 
3488 void wxRichTextCtrl::OnUpdateProperties(wxUpdateUIEvent
& event
) 
3490     int idx 
= event
.GetId() - wxID_RICHTEXT_PROPERTIES1
; 
3491     event
.Enable(idx 
>= 0 && idx 
< m_contextMenuPropertiesInfo
.GetCount()); 
3494 void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent
& event
) 
3496     if (event
.GetEventObject() != this) 
3502     ShowContextMenu(m_contextMenu
, event
.GetPosition()); 
3505 // Prepares the context menu, adding appropriate property-editing commands. 
3506 // Returns the number of property commands added. 
3507 int wxRichTextCtrl::PrepareContextMenu(wxMenu
* menu
, const wxPoint
& pt
, bool addPropertyCommands
) 
3509     wxClientDC 
dc(this); 
3511     dc
.SetFont(GetFont()); 
3513     m_contextMenuPropertiesInfo
.Clear(); 
3516     wxRichTextObject
* hitObj 
= NULL
; 
3517     wxRichTextObject
* contextObj 
= NULL
; 
3518     if (pt 
!= wxDefaultPosition
) 
3520         wxPoint logicalPt 
= GetLogicalPoint(ScreenToClient(pt
)); 
3521         wxRichTextDrawingContext 
context(& GetBuffer()); 
3522         int hit 
= GetBuffer().HitTest(dc
, context
, GetUnscaledPoint(logicalPt
), position
, & hitObj
, & contextObj
); 
3524         if (hit 
== wxRICHTEXT_HITTEST_ON 
|| hit 
== wxRICHTEXT_HITTEST_BEFORE 
|| hit 
== wxRICHTEXT_HITTEST_AFTER
) 
3526             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
3527             if (hitObj 
&& actualContainer
) 
3529                 if (actualContainer
->AcceptsFocus()) 
3531                     SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
3532                     SetCaretPositionAfterClick(actualContainer
, position
, hit
); 
3535                 if (addPropertyCommands
) 
3536                     m_contextMenuPropertiesInfo
.AddItems(this, actualContainer
, hitObj
); 
3540                 if (addPropertyCommands
) 
3541                     m_contextMenuPropertiesInfo
.AddItems(this, GetFocusObject(), NULL
); 
3546             if (addPropertyCommands
) 
3547                 m_contextMenuPropertiesInfo
.AddItems(this, GetFocusObject(), NULL
); 
3552         // Invoked from the keyboard, so don't set the caret position and don't use the event 
3554         hitObj 
= GetFocusObject()->GetLeafObjectAtPosition(m_caretPosition
+1); 
3556             contextObj 
= hitObj
->GetParentContainer(); 
3558             contextObj 
= GetFocusObject(); 
3560         wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
3561         if (hitObj 
&& actualContainer
) 
3563             if (addPropertyCommands
) 
3564                 m_contextMenuPropertiesInfo
.AddItems(this, actualContainer
, hitObj
); 
3568             if (addPropertyCommands
) 
3569                 m_contextMenuPropertiesInfo
.AddItems(this, GetFocusObject(), NULL
); 
3575         if (addPropertyCommands
) 
3576             m_contextMenuPropertiesInfo
.AddMenuItems(menu
); 
3577         return m_contextMenuPropertiesInfo
.GetCount(); 
3583 // Shows the context menu, adding appropriate property-editing commands 
3584 bool wxRichTextCtrl::ShowContextMenu(wxMenu
* menu
, const wxPoint
& pt
, bool addPropertyCommands
) 
3588         PrepareContextMenu(menu
, pt
, addPropertyCommands
); 
3596 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
3598     return GetFocusObject()->SetStyle(wxRichTextRange(start
, end
-1), wxRichTextAttr(style
)); 
3601 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxRichTextAttr
& style
) 
3603     return GetFocusObject()->SetStyle(wxRichTextRange(start
, end
-1), style
); 
3606 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxTextAttr
& style
) 
3608     return GetFocusObject()->SetStyle(range
.ToInternal(), wxRichTextAttr(style
)); 
3611 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxRichTextAttr
& style
) 
3613     return GetFocusObject()->SetStyle(range
.ToInternal(), style
); 
3616 void wxRichTextCtrl::SetStyle(wxRichTextObject 
*obj
, const wxRichTextAttr
& textAttr
, int flags
) 
3618     GetFocusObject()->SetStyle(obj
, textAttr
, flags
); 
3621 // extended style setting operation with flags including: 
3622 // wxRICHTEXT_SETSTYLE_WITH_UNDO, wxRICHTEXT_SETSTYLE_OPTIMIZE, wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY. 
3623 // see richtextbuffer.h for more details. 
3625 bool wxRichTextCtrl::SetStyleEx(const wxRichTextRange
& range
, const wxRichTextAttr
& style
, int flags
) 
3627     return GetFocusObject()->SetStyle(range
.ToInternal(), style
, flags
); 
3630 bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
3632     return GetBuffer().SetDefaultStyle(style
); 
3635 bool wxRichTextCtrl::SetDefaultStyle(const wxRichTextAttr
& style
) 
3637     wxRichTextAttr 
attr1(style
); 
3638     attr1
.GetTextBoxAttr().Reset(); 
3639     return GetBuffer().SetDefaultStyle(attr1
); 
3642 const wxRichTextAttr
& wxRichTextCtrl::GetDefaultStyleEx() const 
3644     return GetBuffer().GetDefaultStyle(); 
3647 bool wxRichTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
3649     wxRichTextAttr attr
; 
3650     if (GetFocusObject()->GetStyle(position
, attr
)) 
3659 bool wxRichTextCtrl::GetStyle(long position
, wxRichTextAttr
& style
) 
3661     return GetFocusObject()->GetStyle(position
, style
); 
3664 bool wxRichTextCtrl::GetStyle(long position
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3666     wxRichTextAttr attr
; 
3667     if (container
->GetStyle(position
, attr
)) 
3676 // get the common set of styles for the range 
3677 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxTextAttr
& style
) 
3679     wxRichTextAttr attr
; 
3680     if (GetFocusObject()->GetStyleForRange(range
.ToInternal(), attr
)) 
3689 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxRichTextAttr
& style
) 
3691     return GetFocusObject()->GetStyleForRange(range
.ToInternal(), style
); 
3694 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3696     return container
->GetStyleForRange(range
.ToInternal(), style
); 
3699 /// Get the content (uncombined) attributes for this position. 
3700 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxRichTextAttr
& style
) 
3702     return GetFocusObject()->GetUncombinedStyle(position
, style
); 
3705 /// Get the content (uncombined) attributes for this position. 
3706 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3708     return container
->GetUncombinedStyle(position
, style
); 
3711 bool wxRichTextCtrl::SetProperties(const wxRichTextRange
& range
, const wxRichTextProperties
& properties
, int flags
) 
3713     return GetFocusObject()->SetProperties(range
.ToInternal(), properties
, flags
); 
3716 /// Set font, and also the buffer attributes 
3717 bool wxRichTextCtrl::SetFont(const wxFont
& font
) 
3719     wxControl::SetFont(font
); 
3721     wxRichTextAttr attr 
= GetBuffer().GetAttributes(); 
3723     GetBuffer().SetBasicStyle(attr
); 
3725     GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
3731 /// Transform logical to physical 
3732 wxPoint 
wxRichTextCtrl::GetPhysicalPoint(const wxPoint
& ptLogical
) const 
3735     CalcScrolledPosition(ptLogical
.x
, ptLogical
.y
, & pt
.x
, & pt
.y
); 
3740 /// Transform physical to logical 
3741 wxPoint 
wxRichTextCtrl::GetLogicalPoint(const wxPoint
& ptPhysical
) const 
3744     CalcUnscrolledPosition(ptPhysical
.x
, ptPhysical
.y
, & pt
.x
, & pt
.y
); 
3749 /// Position the caret 
3750 void wxRichTextCtrl::PositionCaret(wxRichTextParagraphLayoutBox
* container
) 
3755     //wxLogDebug(wxT("PositionCaret")); 
3758     if (GetCaretPositionForIndex(GetCaretPosition(), caretRect
, container
)) 
3760         caretRect 
= GetScaledRect(caretRect
); 
3761         int topMargin 
= (int) (0.5 + GetScale()*GetBuffer().GetTopMargin()); 
3762         int bottomMargin 
= (int) (0.5 + GetScale()*GetBuffer().GetBottomMargin()); 
3763         wxPoint newPt 
= caretRect
.GetPosition(); 
3764         wxSize newSz 
= caretRect
.GetSize(); 
3765         wxPoint pt 
= GetPhysicalPoint(newPt
); 
3766         if (GetCaret()->GetPosition() != pt 
|| GetCaret()->GetSize() != newSz
) 
3769             if (GetCaret()->GetSize() != newSz
) 
3770                 GetCaret()->SetSize(newSz
); 
3772             // Adjust size so the caret size and position doesn't appear in the margins 
3773             if (((pt
.y 
+ newSz
.y
) <= topMargin
) || (pt
.y 
>= (GetClientSize().y 
- bottomMargin
))) 
3778             else if (pt
.y 
< topMargin 
&& (pt
.y 
+ newSz
.y
) > topMargin
) 
3780                 newSz
.y 
-= (topMargin 
- pt
.y
); 
3784                     GetCaret()->SetSize(newSz
); 
3787             else if (pt
.y 
< (GetClientSize().y 
- bottomMargin
) && (pt
.y 
+ newSz
.y
) > (GetClientSize().y 
- bottomMargin
)) 
3789                 newSz
.y 
= GetClientSize().y 
- bottomMargin 
- pt
.y
; 
3790                 GetCaret()->SetSize(newSz
); 
3793             GetCaret()->Move(pt
); 
3799 /// Get the caret height and position for the given character position 
3800 bool wxRichTextCtrl::GetCaretPositionForIndex(long position
, wxRect
& rect
, wxRichTextParagraphLayoutBox
* container
) 
3802     wxClientDC 
dc(this); 
3804     dc
.SetUserScale(GetScale(), GetScale()); 
3805     dc
.SetFont(GetFont()); 
3811         container 
= GetFocusObject(); 
3813     wxRichTextDrawingContext 
context(& GetBuffer()); 
3814     if (container
->FindPosition(dc
, context
, position
, pt
, & height
, m_caretAtLineStart
)) 
3816         // Caret height can't be zero 
3818             height 
= dc
.GetCharHeight(); 
3820         rect 
= wxRect(pt
, wxSize(wxRICHTEXT_DEFAULT_CARET_WIDTH
, height
)); 
3827 /// Gets the line for the visible caret position. If the caret is 
3828 /// shown at the very end of the line, it means the next character is actually 
3829 /// on the following line. So let's get the line we're expecting to find 
3830 /// if this is the case. 
3831 wxRichTextLine
* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPosition
) const 
3833     wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(caretPosition
, true); 
3834     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(caretPosition
, true); 
3837         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
3838         if (caretPosition 
== lineRange
.GetStart()-1 && 
3839             (para
->GetRange().GetStart() != lineRange
.GetStart())) 
3841             if (!m_caretAtLineStart
) 
3842                 line 
= GetFocusObject()->GetLineAtPosition(caretPosition
-1, true); 
3849 /// Move the caret to the given character position 
3850 bool wxRichTextCtrl::MoveCaret(long pos
, bool showAtLineStart
, wxRichTextParagraphLayoutBox
* container
) 
3852     if (GetBuffer().IsDirty()) 
3856         container 
= GetFocusObject(); 
3858     if (pos 
<= container
->GetOwnRange().GetEnd()) 
3860         SetCaretPosition(pos
, showAtLineStart
); 
3862         PositionCaret(container
); 
3870 /// Layout the buffer: which we must do before certain operations, such as 
3871 /// setting the caret position. 
3872 bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect
) 
3874     if (GetBuffer().IsDirty() || onlyVisibleRect
) 
3876         wxRect 
availableSpace(GetUnscaledSize(GetClientSize())); 
3877         if (availableSpace
.width 
== 0) 
3878             availableSpace
.width 
= 10; 
3879         if (availableSpace
.height 
== 0) 
3880             availableSpace
.height 
= 10; 
3882         int flags 
= wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
; 
3883         if (onlyVisibleRect
) 
3885             flags 
|= wxRICHTEXT_LAYOUT_SPECIFIED_RECT
; 
3886             availableSpace
.SetPosition(GetUnscaledPoint(GetLogicalPoint(wxPoint(0, 0)))); 
3889         wxClientDC 
dc(this); 
3892         dc
.SetFont(GetFont()); 
3894         wxRichTextDrawingContext 
context(& GetBuffer()); 
3895         GetBuffer().Defragment(); 
3896         GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation 
3897         GetBuffer().Layout(dc
, context
, availableSpace
, availableSpace
, flags
); 
3898         GetBuffer().Invalidate(wxRICHTEXT_NONE
); 
3900         if (!IsFrozen() && !onlyVisibleRect
) 
3907 /// Is all of the selection, or the current caret position, bold? 
3908 bool wxRichTextCtrl::IsSelectionBold() 
3912         wxRichTextAttr attr
; 
3913         wxRichTextRange range 
= GetSelectionRange(); 
3914         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3915         attr
.SetFontWeight(wxFONTWEIGHT_BOLD
); 
3917         return HasCharacterAttributes(range
, attr
); 
3921         // If no selection, then we need to combine current style with default style 
3922         // to see what the effect would be if we started typing. 
3923         wxRichTextAttr attr
; 
3924         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3926         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3927         if (GetStyle(pos
, attr
)) 
3929             if (IsDefaultStyleShowing()) 
3930                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3931             return attr
.GetFontWeight() == wxFONTWEIGHT_BOLD
; 
3937 /// Is all of the selection, or the current caret position, italics? 
3938 bool wxRichTextCtrl::IsSelectionItalics() 
3942         wxRichTextRange range 
= GetSelectionRange(); 
3943         wxRichTextAttr attr
; 
3944         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3945         attr
.SetFontStyle(wxFONTSTYLE_ITALIC
); 
3947         return HasCharacterAttributes(range
, attr
); 
3951         // If no selection, then we need to combine current style with default style 
3952         // to see what the effect would be if we started typing. 
3953         wxRichTextAttr attr
; 
3954         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3956         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3957         if (GetStyle(pos
, attr
)) 
3959             if (IsDefaultStyleShowing()) 
3960                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3961             return attr
.GetFontStyle() == wxFONTSTYLE_ITALIC
; 
3967 /// Is all of the selection, or the current caret position, underlined? 
3968 bool wxRichTextCtrl::IsSelectionUnderlined() 
3972         wxRichTextRange range 
= GetSelectionRange(); 
3973         wxRichTextAttr attr
; 
3974         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3975         attr
.SetFontUnderlined(true); 
3977         return HasCharacterAttributes(range
, attr
); 
3981         // If no selection, then we need to combine current style with default style 
3982         // to see what the effect would be if we started typing. 
3983         wxRichTextAttr attr
; 
3984         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3985         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3987         if (GetStyle(pos
, attr
)) 
3989             if (IsDefaultStyleShowing()) 
3990                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3991             return attr
.GetFontUnderlined(); 
3997 /// Does all of the selection, or the current caret position, have this wxTextAttrEffects flag(s)? 
3998 bool wxRichTextCtrl::DoesSelectionHaveTextEffectFlag(int flag
) 
4000     wxRichTextAttr attr
; 
4001     attr
.SetFlags(wxTEXT_ATTR_EFFECTS
); 
4002     attr
.SetTextEffectFlags(flag
); 
4003     attr
.SetTextEffects(flag
); 
4007         return HasCharacterAttributes(GetSelectionRange(), attr
); 
4011         // If no selection, then we need to combine current style with default style 
4012         // to see what the effect would be if we started typing. 
4013         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
4014         if (GetStyle(pos
, attr
)) 
4016             if (IsDefaultStyleShowing()) 
4017                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
4018             return (attr
.GetTextEffectFlags() & flag
) != 0; 
4024 /// Apply bold to the selection 
4025 bool wxRichTextCtrl::ApplyBoldToSelection() 
4027     wxRichTextAttr attr
; 
4028     attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
4029     attr
.SetFontWeight(IsSelectionBold() ? wxFONTWEIGHT_NORMAL 
: wxFONTWEIGHT_BOLD
); 
4032         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4035         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4036         current
.Apply(attr
); 
4037         SetAndShowDefaultStyle(current
); 
4042 /// Apply italic to the selection 
4043 bool wxRichTextCtrl::ApplyItalicToSelection() 
4045     wxRichTextAttr attr
; 
4046     attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
4047     attr
.SetFontStyle(IsSelectionItalics() ? wxFONTSTYLE_NORMAL 
: wxFONTSTYLE_ITALIC
); 
4050         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4053         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4054         current
.Apply(attr
); 
4055         SetAndShowDefaultStyle(current
); 
4060 /// Apply underline to the selection 
4061 bool wxRichTextCtrl::ApplyUnderlineToSelection() 
4063     wxRichTextAttr attr
; 
4064     attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
4065     attr
.SetFontUnderlined(!IsSelectionUnderlined()); 
4068         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4071         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4072         current
.Apply(attr
); 
4073         SetAndShowDefaultStyle(current
); 
4078 /// Apply the wxTextAttrEffects flag(s) to the selection, or the current caret position if there's no selection 
4079 bool wxRichTextCtrl::ApplyTextEffectToSelection(int flags
) 
4081     wxRichTextAttr attr
; 
4082     attr
.SetFlags(wxTEXT_ATTR_EFFECTS
); 
4083     attr
.SetTextEffectFlags(flags
); 
4084     if (!DoesSelectionHaveTextEffectFlag(flags
)) 
4085         attr
.SetTextEffects(flags
); 
4087         attr
.SetTextEffects(attr
.GetTextEffectFlags() & ~flags
); 
4090         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
4093         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4094         current
.Apply(attr
); 
4095         SetAndShowDefaultStyle(current
); 
4100 /// Is all of the selection aligned according to the specified flag? 
4101 bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment
) 
4103     wxRichTextRange range
; 
4105         range 
= GetSelectionRange(); 
4107         range 
= wxRichTextRange(GetCaretPosition()+1, GetCaretPosition()+2); 
4109     wxRichTextAttr attr
; 
4110     attr
.SetAlignment(alignment
); 
4112     return HasParagraphAttributes(range
, attr
); 
4115 /// Apply alignment to the selection 
4116 bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment
) 
4118     wxRichTextAttr attr
; 
4119     attr
.SetAlignment(alignment
); 
4121         return SetStyle(GetSelectionRange(), attr
); 
4124         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(GetCaretPosition()+1); 
4126             return SetStyleEx(para
->GetRange().FromInternal(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
); 
4131 /// Apply a named style to the selection 
4132 bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition
* def
) 
4134     // Flags are defined within each definition, so only certain 
4135     // attributes are applied. 
4136     wxRichTextAttr 
attr(GetStyleSheet() ? def
->GetStyleMergedWithBase(GetStyleSheet()) : def
->GetStyle()); 
4138     int flags 
= wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_RESET
; 
4140     if (wxDynamicCast(def
, wxRichTextListStyleDefinition
)) 
4142         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
4144         wxRichTextRange range
; 
4147             range 
= GetSelectionRange(); 
4150             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
4151             range 
= wxRichTextRange(pos
, pos
+1); 
4154         return SetListStyle(range
, (wxRichTextListStyleDefinition
*) def
, flags
); 
4157     bool isPara 
= false; 
4159     // Make sure the attr has the style name 
4160     if (wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
)) 
4163         attr
.SetParagraphStyleName(def
->GetName()); 
4165         // If applying a paragraph style, we only want the paragraph nodes to adopt these 
4166         // attributes, and not the leaf nodes. This will allow the content (e.g. text) 
4167         // to change its style independently. 
4168         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
4170     else if (wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
)) 
4171         attr
.SetCharacterStyleName(def
->GetName()); 
4172     else if (wxDynamicCast(def
, wxRichTextBoxStyleDefinition
)) 
4173         attr
.GetTextBoxAttr().SetBoxStyleName(def
->GetName()); 
4175     if (wxDynamicCast(def
, wxRichTextBoxStyleDefinition
)) 
4177         if (GetFocusObject() && (GetFocusObject() != & GetBuffer())) 
4179             SetStyle(GetFocusObject(), attr
); 
4185     else if (HasSelection()) 
4186         return SetStyleEx(GetSelectionRange(), attr
, flags
); 
4189         wxRichTextAttr current 
= GetDefaultStyleEx(); 
4190         wxRichTextAttr 
defaultStyle(attr
); 
4193             // Don't apply extra character styles since they are already implied 
4194             // in the paragraph style 
4195             defaultStyle
.SetFlags(defaultStyle
.GetFlags() & ~wxTEXT_ATTR_CHARACTER
); 
4197         current
.Apply(defaultStyle
); 
4198         SetAndShowDefaultStyle(current
); 
4200         // If it's a paragraph style, we want to apply the style to the 
4201         // current paragraph even if we didn't select any text. 
4204             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
4205             wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
); 
4208                 return SetStyleEx(para
->GetRange().FromInternal(), attr
, flags
); 
4215 /// Apply the style sheet to the buffer, for example if the styles have changed. 
4216 bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet
* styleSheet
) 
4219         styleSheet 
= GetBuffer().GetStyleSheet(); 
4223     if (GetBuffer().ApplyStyleSheet(styleSheet
)) 
4225         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
4233 /// Sets the default style to the style under the cursor 
4234 bool wxRichTextCtrl::SetDefaultStyleToCursorStyle() 
4236     wxRichTextAttr attr
; 
4237     attr
.SetFlags(wxTEXT_ATTR_CHARACTER
); 
4239     // If at the start of a paragraph, use the next position. 
4240     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
4242     wxRichTextObject
* obj 
= GetFocusObject()->GetLeafObjectAtPosition(pos
); 
4243     if (obj 
&& obj
->IsTopLevel()) 
4245         // Don't use the attributes of a top-level object, since they might apply 
4246         // to content of the object, e.g. background colour. 
4247         SetDefaultStyle(wxRichTextAttr()); 
4250     else if (GetUncombinedStyle(pos
, attr
)) 
4252         SetDefaultStyle(attr
); 
4259 /// Returns the first visible position in the current view 
4260 long wxRichTextCtrl::GetFirstVisiblePosition() const 
4262     wxRichTextLine
* line 
= GetFocusObject()->GetLineAtYPosition(GetUnscaledPoint(GetLogicalPoint(wxPoint(0, 0))).y
); 
4264         return line
->GetAbsoluteRange().GetStart(); 
4269 /// Get the first visible point in the window 
4270 wxPoint 
wxRichTextCtrl::GetFirstVisiblePoint() const 
4273     int startXUnits
, startYUnits
; 
4275     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
4276     GetViewStart(& startXUnits
, & startYUnits
); 
4278     return wxPoint(startXUnits 
* ppuX
, startYUnits 
* ppuY
); 
4281 /// The adjusted caret position is the character position adjusted to take 
4282 /// into account whether we're at the start of a paragraph, in which case 
4283 /// style information should be taken from the next position, not current one. 
4284 long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos
) const 
4286     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(caretPos
+1); 
4288     if (para 
&& (caretPos
+1 == para
->GetRange().GetStart())) 
4293 /// Get/set the selection range in character positions. -1, -1 means no selection. 
4294 /// The range is in API convention, i.e. a single character selection is denoted 
4296 wxRichTextRange 
wxRichTextCtrl::GetSelectionRange() const 
4298     wxRichTextRange range 
= GetInternalSelectionRange(); 
4299     if (range 
!= wxRichTextRange(-2,-2) && range 
!= wxRichTextRange(-1,-1)) 
4300         range
.SetEnd(range
.GetEnd() + 1); 
4304 void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange
& range
) 
4306     SetSelection(range
.GetStart(), range
.GetEnd()); 
4310 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
4312     return GetFocusObject()->SetListStyle(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
4315 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
4317     return GetFocusObject()->SetListStyle(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
4320 /// Clear list for given range 
4321 bool wxRichTextCtrl::ClearListStyle(const wxRichTextRange
& range
, int flags
) 
4323     return GetFocusObject()->ClearListStyle(range
.ToInternal(), flags
); 
4326 /// Number/renumber any list elements in the given range 
4327 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
4329     return GetFocusObject()->NumberList(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
4332 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
4334     return GetFocusObject()->NumberList(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
4337 /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 
4338 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int specifiedLevel
) 
4340     return GetFocusObject()->PromoteList(promoteBy
, range
.ToInternal(), def
, flags
, specifiedLevel
); 
4343 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int specifiedLevel
) 
4345     return GetFocusObject()->PromoteList(promoteBy
, range
.ToInternal(), defName
, flags
, specifiedLevel
); 
4348 /// Deletes the content in the given range 
4349 bool wxRichTextCtrl::Delete(const wxRichTextRange
& range
) 
4351     return GetFocusObject()->DeleteRangeWithUndo(range
.ToInternal(), this, & GetBuffer()); 
4354 const wxArrayString
& wxRichTextCtrl::GetAvailableFontNames() 
4356     if (sm_availableFontNames
.GetCount() == 0) 
4358         sm_availableFontNames 
= wxFontEnumerator::GetFacenames(); 
4359         sm_availableFontNames
.Sort(); 
4361     return sm_availableFontNames
; 
4364 void wxRichTextCtrl::ClearAvailableFontNames() 
4366     sm_availableFontNames
.Clear(); 
4369 void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
)) 
4371     //wxLogDebug(wxT("wxRichTextCtrl::OnSysColourChanged")); 
4373     wxTextAttrEx basicStyle 
= GetBasicStyle(); 
4374     basicStyle
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
4375     SetBasicStyle(basicStyle
); 
4376     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
4381 // Refresh the area affected by a selection change 
4382 bool wxRichTextCtrl::RefreshForSelectionChange(const wxRichTextSelection
& oldSelection
, const wxRichTextSelection
& newSelection
) 
4384     // If the selection is not part of the focus object, or we have multiple ranges, then the chances are that 
4385     // the selection contains whole containers rather than just text, so refresh everything 
4386     // for now as it would be hard to compute the rectangle bounding all selections. 
4387     // TODO: improve on this. 
4388     if ((oldSelection
.IsValid() && (oldSelection
.GetContainer() != GetFocusObject() || oldSelection
.GetCount() > 1)) || 
4389         (newSelection
.IsValid() && (newSelection
.GetContainer() != GetFocusObject() || newSelection
.GetCount() > 1))) 
4395     wxRichTextRange oldRange
, newRange
; 
4396     if (oldSelection
.IsValid()) 
4397         oldRange 
= oldSelection
.GetRange(); 
4399         oldRange 
= wxRICHTEXT_NO_SELECTION
; 
4400     if (newSelection
.IsValid()) 
4401         newRange 
= newSelection
.GetRange(); 
4403         newRange 
= wxRICHTEXT_NO_SELECTION
; 
4405     // Calculate the refresh rectangle - just the affected lines 
4406     long firstPos
, lastPos
; 
4407     if (oldRange
.GetStart() == -2 && newRange
.GetStart() != -2) 
4409         firstPos 
= newRange
.GetStart(); 
4410         lastPos 
= newRange
.GetEnd(); 
4412     else if (oldRange
.GetStart() != -2 && newRange
.GetStart() == -2) 
4414         firstPos 
= oldRange
.GetStart(); 
4415         lastPos 
= oldRange
.GetEnd(); 
4417     else if (oldRange
.GetStart() == -2 && newRange
.GetStart() == -2) 
4423         firstPos 
= wxMin(oldRange
.GetStart(), newRange
.GetStart()); 
4424         lastPos 
= wxMax(oldRange
.GetEnd(), newRange
.GetEnd()); 
4427     wxRichTextLine
* firstLine 
= GetFocusObject()->GetLineAtPosition(firstPos
); 
4428     wxRichTextLine
* lastLine 
= GetFocusObject()->GetLineAtPosition(lastPos
); 
4430     if (firstLine 
&& lastLine
) 
4432         wxSize clientSize 
= GetClientSize(); 
4433         wxPoint pt1 
= GetPhysicalPoint(GetScaledPoint(firstLine
->GetAbsolutePosition())); 
4434         wxPoint pt2 
= GetPhysicalPoint(GetScaledPoint(lastLine
->GetAbsolutePosition())) + wxPoint(0, (int) (0.5 + lastLine
->GetSize().y 
* GetScale())); 
4437         pt1
.y 
= wxMax(0, pt1
.y
); 
4439         pt2
.y 
= wxMin(clientSize
.y
, pt2
.y
); 
4441         wxRect 
rect(pt1
, wxSize(clientSize
.x
, pt2
.y 
- pt1
.y
)); 
4442         RefreshRect(rect
, false); 
4450 // margins functions 
4451 bool wxRichTextCtrl::DoSetMargins(const wxPoint
& pt
) 
4453     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().SetValue(pt
.x
, wxTEXT_ATTR_UNITS_PIXELS
); 
4454     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetRight().SetValue(pt
.x
, wxTEXT_ATTR_UNITS_PIXELS
); 
4455     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetTop().SetValue(pt
.y
, wxTEXT_ATTR_UNITS_PIXELS
); 
4456     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetBottom().SetValue(pt
.y
, wxTEXT_ATTR_UNITS_PIXELS
); 
4461 wxPoint 
wxRichTextCtrl::DoGetMargins() const 
4463     return wxPoint(GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().GetValue(), 
4464                    GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetTop().GetValue()); 
4467 bool wxRichTextCtrl::SetFocusObject(wxRichTextParagraphLayoutBox
* obj
, bool setCaretPosition
) 
4469     if (obj 
&& !obj
->AcceptsFocus()) 
4472     wxRichTextParagraphLayoutBox
* oldContainer 
= GetFocusObject(); 
4473     bool changingContainer 
= (m_focusObject 
!= obj
); 
4475     if (changingContainer 
&& HasSelection()) 
4478     m_focusObject 
= obj
; 
4481         m_focusObject 
= & m_buffer
; 
4483     if (setCaretPosition 
&& changingContainer
) 
4485         m_selection
.Reset(); 
4486         m_selectionAnchor 
= -2; 
4487         m_selectionAnchorObject 
= NULL
; 
4488         m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
4492         m_caretAtLineStart 
= false; 
4493         MoveCaret(pos
, m_caretAtLineStart
); 
4494         SetDefaultStyleToCursorStyle(); 
4496         wxRichTextEvent 
cmdEvent( 
4497             wxEVT_COMMAND_RICHTEXT_FOCUS_OBJECT_CHANGED
, 
4499         cmdEvent
.SetEventObject(this); 
4500         cmdEvent
.SetPosition(m_caretPosition
+1); 
4501         cmdEvent
.SetOldContainer(oldContainer
); 
4502         cmdEvent
.SetContainer(m_focusObject
); 
4504         GetEventHandler()->ProcessEvent(cmdEvent
); 
4509 #if wxUSE_DRAG_AND_DROP 
4510 void wxRichTextCtrl::OnDrop(wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
), wxDragResult def
, wxDataObject
* DataObj
) 
4514     if ((def 
!= wxDragCopy
) && (def 
!= wxDragMove
)) 
4519     if (!GetSelection().IsValid()) 
4524     wxRichTextParagraphLayoutBox
* originContainer 
= GetSelection().GetContainer(); 
4525     wxRichTextParagraphLayoutBox
* destContainer 
= GetFocusObject(); // This will be the drop container, not necessarily the same as the origin one 
4527     wxRichTextBuffer
* richTextBuffer 
= ((wxRichTextBufferDataObject
*)DataObj
)->GetRichTextBuffer(); 
4530         long position 
= GetCaretPosition(); 
4531         wxRichTextRange selectionrange 
= GetInternalSelectionRange(); 
4532         if (selectionrange
.Contains(position
) && (def 
== wxDragMove
)) 
4534             // It doesn't make sense to move onto itself 
4538         // If we're moving, and the data is being moved forward, we need to drop first, then delete the selection 
4539         // If moving backwards, we need to delete then drop. If we're copying (or doing nothing) we don't delete anyway 
4540         bool DeleteAfter 
= (def 
== wxDragMove
) && (position 
> selectionrange
.GetEnd()); 
4541         if ((def 
== wxDragMove
) && !DeleteAfter
) 
4543             // We can't use e.g. DeleteSelectedContent() as it uses the focus container 
4544             originContainer
->DeleteRangeWithUndo(selectionrange
, this, &GetBuffer()); 
4547         destContainer
->InsertParagraphsWithUndo(&GetBuffer(), position
+1, *richTextBuffer
, this, 0); 
4548         ShowPosition(position 
+ richTextBuffer
->GetOwnRange().GetEnd()); 
4550         delete richTextBuffer
; 
4554             // We can't use e.g. DeleteSelectedContent() as it uses the focus container 
4555             originContainer
->DeleteRangeWithUndo(selectionrange
, this, &GetBuffer()); 
4562 #endif // wxUSE_DRAG_AND_DROP 
4565 #if wxUSE_DRAG_AND_DROP 
4566 bool wxRichTextDropSource::GiveFeedback(wxDragResult 
WXUNUSED(effect
)) 
4568     wxCHECK_MSG(m_rtc
, false, wxT("NULL m_rtc")); 
4572     wxRichTextObject
* hitObj 
= NULL
; 
4573     wxRichTextParagraphLayoutBox
* container 
= m_rtc
->FindContainerAtPoint(m_rtc
->GetUnscaledPoint(m_rtc
->ScreenToClient(wxGetMousePosition())), position
, hit
, hitObj
); 
4575     if (!(hit 
& wxRICHTEXT_HITTEST_NONE
) && container 
&& container
->AcceptsFocus()) 
4577         m_rtc
->StoreFocusObject(container
); 
4578         m_rtc
->SetCaretPositionAfterClick(container
, position
, hit
); 
4581     return false;  // so that the base-class sets a cursor 
4583 #endif // wxUSE_DRAG_AND_DROP 
4585 bool wxRichTextCtrl::CanDeleteRange(wxRichTextParagraphLayoutBox
& WXUNUSED(container
), const wxRichTextRange
& WXUNUSED(range
)) const 
4590 bool wxRichTextCtrl::CanInsertContent(wxRichTextParagraphLayoutBox
& WXUNUSED(container
), long WXUNUSED(pos
)) const 
4595 void wxRichTextCtrl::EnableVerticalScrollbar(bool enable
) 
4597     m_verticalScrollbarEnabled 
= enable
; 
4601 void wxRichTextCtrl::SetFontScale(double fontScale
, bool refresh
) 
4603     GetBuffer().SetFontScale(fontScale
); 
4606         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
4611 void wxRichTextCtrl::SetDimensionScale(double dimScale
, bool refresh
) 
4613     GetBuffer().SetDimensionScale(dimScale
); 
4616         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
4621 // Sets an overall scale factor for displaying and editing the content. 
4622 void wxRichTextCtrl::SetScale(double scale
, bool refresh
) 
4627         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
4632 // Get an unscaled point 
4633 wxPoint 
wxRichTextCtrl::GetUnscaledPoint(const wxPoint
& pt
) const 
4635     if (GetScale() == 1.0) 
4638         return wxPoint((int) (0.5 + double(pt
.x
) / GetScale()), (int) (0.5 + double(pt
.y
) / GetScale())); 
4641 // Get a scaled point 
4642 wxPoint 
wxRichTextCtrl::GetScaledPoint(const wxPoint
& pt
) const 
4644     if (GetScale() == 1.0) 
4647         return wxPoint((int) (0.5 + double(pt
.x
) * GetScale()), (int) (0.5 + double(pt
.y
) * GetScale())); 
4650 // Get an unscaled size 
4651 wxSize 
wxRichTextCtrl::GetUnscaledSize(const wxSize
& sz
) const 
4653     if (GetScale() == 1.0) 
4656         return wxSize((int) (0.5 + double(sz
.x
) / GetScale()), (int) (0.5 + double(sz
.y
) / GetScale())); 
4659 // Get a scaled size 
4660 wxSize 
wxRichTextCtrl::GetScaledSize(const wxSize
& sz
) const 
4662     if (GetScale() == 1.0) 
4665         return wxSize((int) (0.5 + double(sz
.x
) * GetScale()), (int) (0.5 + double(sz
.y
) * GetScale())); 
4668 // Get an unscaled rect 
4669 wxRect 
wxRichTextCtrl::GetUnscaledRect(const wxRect
& rect
) const 
4671     if (GetScale() == 1.0) 
4674         return wxRect((int) (0.5 + double(rect
.x
) / GetScale()), (int) (0.5 + double(rect
.y
) / GetScale()), 
4675                       (int) (0.5 + double(rect
.width
) / GetScale()), (int) (0.5 + double(rect
.height
) / GetScale())); 
4678 // Get a scaled rect 
4679 wxRect 
wxRichTextCtrl::GetScaledRect(const wxRect
& rect
) const 
4681     if (GetScale() == 1.0) 
4684         return wxRect((int) (0.5 + double(rect
.x
) * GetScale()), (int) (0.5 + double(rect
.y
) * GetScale()), 
4685                       (int) (0.5 + double(rect
.width
) * GetScale()), (int) (0.5 + double(rect
.height
) * GetScale())); 
4688 #if wxRICHTEXT_USE_OWN_CARET 
4690 // ---------------------------------------------------------------------------- 
4691 // initialization and destruction 
4692 // ---------------------------------------------------------------------------- 
4694 void wxRichTextCaret::Init() 
4697     m_refreshEnabled 
= true; 
4701     m_richTextCtrl 
= NULL
; 
4702     m_needsUpdate 
= false; 
4706 wxRichTextCaret::~wxRichTextCaret() 
4708     if (m_timer
.IsRunning()) 
4712 // ---------------------------------------------------------------------------- 
4713 // showing/hiding/moving the caret (base class interface) 
4714 // ---------------------------------------------------------------------------- 
4716 void wxRichTextCaret::DoShow() 
4720     if (!m_timer
.IsRunning()) 
4721         m_timer
.Start(GetBlinkTime()); 
4726 void wxRichTextCaret::DoHide() 
4728     if (m_timer
.IsRunning()) 
4734 void wxRichTextCaret::DoMove() 
4740         if (m_xOld 
!= -1 && m_yOld 
!= -1) 
4742             if (m_richTextCtrl 
&& m_refreshEnabled
) 
4744                 wxRect 
rect(GetPosition(), GetSize()); 
4745                 m_richTextCtrl
->RefreshRect(rect
, false); 
4754 void wxRichTextCaret::DoSize() 
4756     int countVisible 
= m_countVisible
; 
4757     if (countVisible 
> 0) 
4763     if (countVisible 
> 0) 
4765         m_countVisible 
= countVisible
; 
4770 // ---------------------------------------------------------------------------- 
4771 // handling the focus 
4772 // ---------------------------------------------------------------------------- 
4774 void wxRichTextCaret::OnSetFocus() 
4782 void wxRichTextCaret::OnKillFocus() 
4787 // ---------------------------------------------------------------------------- 
4788 // drawing the caret 
4789 // ---------------------------------------------------------------------------- 
4791 void wxRichTextCaret::Refresh() 
4793     if (m_richTextCtrl 
&& m_refreshEnabled
) 
4795         wxRect 
rect(GetPosition(), GetSize()); 
4796         m_richTextCtrl
->RefreshRect(rect
, false); 
4800 void wxRichTextCaret::DoDraw(wxDC 
*dc
) 
4802     dc
->SetPen( *wxBLACK_PEN 
); 
4804     dc
->SetBrush(*(m_hasFocus 
? wxBLACK_BRUSH 
: wxTRANSPARENT_BRUSH
)); 
4805     dc
->SetPen(*wxBLACK_PEN
); 
4807     wxPoint 
pt(m_x
, m_y
); 
4811         pt 
= m_richTextCtrl
->GetLogicalPoint(pt
); 
4813     if (IsVisible() && m_flashOn
) 
4814         dc
->DrawRectangle(pt
.x
, pt
.y
, m_width
, m_height
); 
4817 void wxRichTextCaret::Notify() 
4819     m_flashOn 
= !m_flashOn
; 
4823 void wxRichTextCaretTimer::Notify() 
4828     // wxRICHTEXT_USE_OWN_CARET 
4831 bool wxRichTextContextMenuPropertiesInfo::AddItem(const wxString
& label
, wxRichTextObject
* obj
) 
4835         m_labels
.Add(label
); 
4843 // Returns number of menu items were added. 
4844 int wxRichTextContextMenuPropertiesInfo::AddMenuItems(wxMenu
* menu
, int startCmd
) const 
4846     wxMenuItem
* item 
= menu
->FindItem(startCmd
); 
4847     // If none of the standard properties identifiers are in the menu, add them if necessary. 
4848     // If no items to add, just set the text to something generic 
4849     if (GetCount() == 0) 
4853             menu
->SetLabel(startCmd
, _("&Properties")); 
4855             // Delete the others if necessary 
4857             for (i 
= startCmd
+1; i 
< startCmd
+3; i
++) 
4859                 if (menu
->FindItem(i
)) 
4870         // Find the position of the first properties item 
4871         for (i 
= 0; i 
< (int) menu
->GetMenuItemCount(); i
++) 
4873             wxMenuItem
* item 
= menu
->FindItemByPosition(i
); 
4874             if (item 
&& item
->GetId() == startCmd
) 
4883             int insertBefore 
= pos
+1; 
4884             for (i 
= startCmd
; i 
< startCmd
+GetCount(); i
++) 
4886                 if (menu
->FindItem(i
)) 
4888                     menu
->SetLabel(i
, m_labels
[i 
- startCmd
]); 
4892                     if (insertBefore 
>= (int) menu
->GetMenuItemCount()) 
4893                         menu
->Append(i
, m_labels
[i 
- startCmd
]); 
4895                         menu
->Insert(insertBefore
, i
, m_labels
[i 
- startCmd
]); 
4900             // Delete any old items still left on the menu 
4901             for (i 
= startCmd 
+ GetCount(); i 
< startCmd
+3; i
++) 
4903                 if (menu
->FindItem(i
)) 
4911             // No existing property identifiers were found, so append to the end of the menu. 
4912             menu
->AppendSeparator(); 
4913             for (i 
= startCmd
; i 
< startCmd
+GetCount(); i
++) 
4915                 menu
->Append(i
, m_labels
[i 
- startCmd
]); 
4923 // Add appropriate menu items for the current container and clicked on object 
4924 // (and container's parent, if appropriate). 
4925 int wxRichTextContextMenuPropertiesInfo::AddItems(wxRichTextCtrl
* ctrl
, wxRichTextObject
* container
, wxRichTextObject
* obj
) 
4928     if (obj 
&& ctrl
->CanEditProperties(obj
)) 
4929         AddItem(ctrl
->GetPropertiesMenuLabel(obj
), obj
); 
4931     if (container 
&& container 
!= obj 
&& ctrl
->CanEditProperties(container
) && m_labels
.Index(ctrl
->GetPropertiesMenuLabel(container
)) == wxNOT_FOUND
) 
4932         AddItem(ctrl
->GetPropertiesMenuLabel(container
), container
); 
4934     if (container 
&& container
->GetParent() && ctrl
->CanEditProperties(container
->GetParent()) && m_labels
.Index(ctrl
->GetPropertiesMenuLabel(container
->GetParent())) == wxNOT_FOUND
) 
4935         AddItem(ctrl
->GetPropertiesMenuLabel(container
->GetParent()), container
->GetParent());