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 // DLL options compatibility check: 
  40 WX_CHECK_BUILD_OPTIONS("wxRichTextCtrl") 
  42 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
, wxRichTextEvent 
); 
  43 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
, wxRichTextEvent 
); 
  44 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
, wxRichTextEvent 
); 
  45 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
, wxRichTextEvent 
); 
  46 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_RETURN
, wxRichTextEvent 
); 
  47 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CHARACTER
, wxRichTextEvent 
); 
  48 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_DELETE
, wxRichTextEvent 
); 
  50 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING
, wxRichTextEvent 
); 
  51 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED
, wxRichTextEvent 
); 
  52 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING
, wxRichTextEvent 
); 
  53 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED
, wxRichTextEvent 
); 
  55 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED
, wxRichTextEvent 
); 
  56 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED
, wxRichTextEvent 
); 
  57 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED
, wxRichTextEvent 
); 
  58 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED
, wxRichTextEvent 
); 
  59 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_BUFFER_RESET
, wxRichTextEvent 
); 
  60 wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_FOCUS_OBJECT_CHANGED
, wxRichTextEvent 
); 
  62 #if wxRICHTEXT_USE_OWN_CARET 
  67  * This implements a non-flashing cursor in case there 
  68  * are platform-specific problems with the generic caret. 
  69  * wxRICHTEXT_USE_OWN_CARET is set in richtextbuffer.h. 
  72 class wxRichTextCaret
; 
  73 class wxRichTextCaretTimer
: public wxTimer
 
  76     wxRichTextCaretTimer(wxRichTextCaret
* caret
) 
  80     virtual void Notify(); 
  81     wxRichTextCaret
* m_caret
; 
  84 class wxRichTextCaret
: public wxCaret
 
  89         // default - use Create() 
  90     wxRichTextCaret(): m_timer(this)  { Init(); } 
  91         // creates a block caret associated with the given window 
  92     wxRichTextCaret(wxRichTextCtrl 
*window
, int width
, int height
) 
  93         : wxCaret(window
, width
, height
), m_timer(this) { Init(); m_richTextCtrl 
= window
; } 
  94     wxRichTextCaret(wxRichTextCtrl 
*window
, const wxSize
& size
) 
  95         : wxCaret(window
, size
), m_timer(this) { Init(); m_richTextCtrl 
= window
; } 
  97     virtual ~wxRichTextCaret(); 
 102     // called by wxWindow (not using the event tables) 
 103     virtual void OnSetFocus(); 
 104     virtual void OnKillFocus(); 
 106     // draw the caret on the given DC 
 107     void DoDraw(wxDC 
*dc
); 
 109     // get the visible count 
 110     int GetVisibleCount() const { return m_countVisible
; } 
 112     // delay repositioning 
 113     bool GetNeedsUpdate() const { return m_needsUpdate
; } 
 114     void SetNeedsUpdate(bool needsUpdate 
= true ) { m_needsUpdate 
= needsUpdate
; } 
 119     virtual void DoShow(); 
 120     virtual void DoHide(); 
 121     virtual void DoMove(); 
 122     virtual void DoSize(); 
 132     bool          m_hasFocus
;       // true => our window has focus 
 133     bool          m_needsUpdate
;    // must be repositioned 
 135     wxRichTextCaretTimer m_timer
; 
 136     wxRichTextCtrl
* m_richTextCtrl
; 
 140 IMPLEMENT_DYNAMIC_CLASS( wxRichTextCtrl
, wxControl 
) 
 142 IMPLEMENT_DYNAMIC_CLASS( wxRichTextEvent
, wxNotifyEvent 
) 
 144 BEGIN_EVENT_TABLE( wxRichTextCtrl
, wxControl 
) 
 145     EVT_PAINT(wxRichTextCtrl::OnPaint
) 
 146     EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground
) 
 147     EVT_IDLE(wxRichTextCtrl::OnIdle
) 
 148     EVT_SCROLLWIN(wxRichTextCtrl::OnScroll
) 
 149     EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick
) 
 150     EVT_MOTION(wxRichTextCtrl::OnMoveMouse
) 
 151     EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp
) 
 152     EVT_RIGHT_DOWN(wxRichTextCtrl::OnRightClick
) 
 153     EVT_MIDDLE_DOWN(wxRichTextCtrl::OnMiddleClick
) 
 154     EVT_LEFT_DCLICK(wxRichTextCtrl::OnLeftDClick
) 
 155     EVT_CHAR(wxRichTextCtrl::OnChar
) 
 156     EVT_KEY_DOWN(wxRichTextCtrl::OnChar
) 
 157     EVT_SIZE(wxRichTextCtrl::OnSize
) 
 158     EVT_SET_FOCUS(wxRichTextCtrl::OnSetFocus
) 
 159     EVT_KILL_FOCUS(wxRichTextCtrl::OnKillFocus
) 
 160     EVT_MOUSE_CAPTURE_LOST(wxRichTextCtrl::OnCaptureLost
) 
 161     EVT_CONTEXT_MENU(wxRichTextCtrl::OnContextMenu
) 
 162     EVT_SYS_COLOUR_CHANGED(wxRichTextCtrl::OnSysColourChanged
) 
 164     EVT_MENU(wxID_UNDO
, wxRichTextCtrl::OnUndo
) 
 165     EVT_UPDATE_UI(wxID_UNDO
, wxRichTextCtrl::OnUpdateUndo
) 
 167     EVT_MENU(wxID_REDO
, wxRichTextCtrl::OnRedo
) 
 168     EVT_UPDATE_UI(wxID_REDO
, wxRichTextCtrl::OnUpdateRedo
) 
 170     EVT_MENU(wxID_COPY
, wxRichTextCtrl::OnCopy
) 
 171     EVT_UPDATE_UI(wxID_COPY
, wxRichTextCtrl::OnUpdateCopy
) 
 173     EVT_MENU(wxID_PASTE
, wxRichTextCtrl::OnPaste
) 
 174     EVT_UPDATE_UI(wxID_PASTE
, wxRichTextCtrl::OnUpdatePaste
) 
 176     EVT_MENU(wxID_CUT
, wxRichTextCtrl::OnCut
) 
 177     EVT_UPDATE_UI(wxID_CUT
, wxRichTextCtrl::OnUpdateCut
) 
 179     EVT_MENU(wxID_CLEAR
, wxRichTextCtrl::OnClear
) 
 180     EVT_UPDATE_UI(wxID_CLEAR
, wxRichTextCtrl::OnUpdateClear
) 
 182     EVT_MENU(wxID_SELECTALL
, wxRichTextCtrl::OnSelectAll
) 
 183     EVT_UPDATE_UI(wxID_SELECTALL
, wxRichTextCtrl::OnUpdateSelectAll
) 
 185     EVT_MENU(wxID_RICHTEXT_PROPERTIES1
, wxRichTextCtrl::OnProperties
) 
 186     EVT_UPDATE_UI(wxID_RICHTEXT_PROPERTIES1
, wxRichTextCtrl::OnUpdateProperties
) 
 188     EVT_MENU(wxID_RICHTEXT_PROPERTIES2
, wxRichTextCtrl::OnProperties
) 
 189     EVT_UPDATE_UI(wxID_RICHTEXT_PROPERTIES2
, wxRichTextCtrl::OnUpdateProperties
) 
 191     EVT_MENU(wxID_RICHTEXT_PROPERTIES3
, wxRichTextCtrl::OnProperties
) 
 192     EVT_UPDATE_UI(wxID_RICHTEXT_PROPERTIES3
, wxRichTextCtrl::OnUpdateProperties
) 
 200 wxArrayString 
wxRichTextCtrl::sm_availableFontNames
; 
 202 wxRichTextCtrl::wxRichTextCtrl() 
 203               : wxScrollHelper(this) 
 208 wxRichTextCtrl::wxRichTextCtrl(wxWindow
* parent
, 
 210                                const wxString
& value
, 
 214                                const wxValidator
& validator
, 
 215                                const wxString
& name
) 
 216               : wxScrollHelper(this) 
 219     Create(parent
, id
, value
, pos
, size
, style
, validator
, name
); 
 223 bool wxRichTextCtrl::Create( wxWindow
* parent
, wxWindowID id
, const wxString
& value
, const wxPoint
& pos
, const wxSize
& size
, long style
, 
 224                              const wxValidator
& validator
, const wxString
& name
) 
 228     if (!wxControl::Create(parent
, id
, pos
, size
, 
 229                            style
|wxFULL_REPAINT_ON_RESIZE
, 
 235         SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 238     // No physical scrolling, so we can preserve margins 
 239     EnableScrolling(false, false); 
 241     if (style 
& wxTE_READONLY
) 
 244     // The base attributes must all have default values 
 245     wxRichTextAttr attributes
; 
 246     attributes
.SetFont(GetFont()); 
 247     attributes
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
 248     attributes
.SetAlignment(wxTEXT_ALIGNMENT_LEFT
); 
 249     attributes
.SetLineSpacing(10); 
 250     attributes
.SetParagraphSpacingAfter(10); 
 251     attributes
.SetParagraphSpacingBefore(0); 
 253     SetBasicStyle(attributes
); 
 256     SetMargins(margin
, margin
); 
 258     // The default attributes will be merged with base attributes, so 
 259     // can be empty to begin with 
 260     wxRichTextAttr defaultAttributes
; 
 261     SetDefaultStyle(defaultAttributes
); 
 263     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 264     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 267     GetBuffer().SetRichTextCtrl(this); 
 269 #if wxRICHTEXT_USE_OWN_CARET 
 270     SetCaret(new wxRichTextCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 272     SetCaret(new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 275     // Tell the sizers to use the given or best size 
 276     SetInitialSize(size
); 
 278 #if wxRICHTEXT_BUFFERED_PAINTING 
 280     RecreateBuffer(size
); 
 283     m_textCursor 
= wxCursor(wxCURSOR_IBEAM
); 
 284     m_urlCursor 
= wxCursor(wxCURSOR_HAND
); 
 286     SetCursor(m_textCursor
); 
 288     if (!value
.IsEmpty()) 
 291     GetBuffer().AddEventHandler(this); 
 294     wxAcceleratorEntry entries
[6]; 
 296     entries
[0].Set(wxACCEL_CMD
,   (int) 'C',       wxID_COPY
); 
 297     entries
[1].Set(wxACCEL_CMD
,   (int) 'X',       wxID_CUT
); 
 298     entries
[2].Set(wxACCEL_CMD
,   (int) 'V',       wxID_PASTE
); 
 299     entries
[3].Set(wxACCEL_CMD
,   (int) 'A',       wxID_SELECTALL
); 
 300     entries
[4].Set(wxACCEL_CMD
,   (int) 'Z',       wxID_UNDO
); 
 301     entries
[5].Set(wxACCEL_CMD
,   (int) 'Y',       wxID_REDO
); 
 303     wxAcceleratorTable 
accel(6, entries
); 
 304     SetAcceleratorTable(accel
); 
 306     m_contextMenu 
= new wxMenu
; 
 307     m_contextMenu
->Append(wxID_UNDO
, _("&Undo")); 
 308     m_contextMenu
->Append(wxID_REDO
, _("&Redo")); 
 309     m_contextMenu
->AppendSeparator(); 
 310     m_contextMenu
->Append(wxID_CUT
, _("Cu&t")); 
 311     m_contextMenu
->Append(wxID_COPY
, _("&Copy")); 
 312     m_contextMenu
->Append(wxID_PASTE
, _("&Paste")); 
 313     m_contextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
 314     m_contextMenu
->AppendSeparator(); 
 315     m_contextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
 316     m_contextMenu
->AppendSeparator(); 
 317     m_contextMenu
->Append(wxID_RICHTEXT_PROPERTIES1
, _("&Properties")); 
 322 wxRichTextCtrl::~wxRichTextCtrl() 
 324     SetFocusObject(& GetBuffer(), false); 
 325     GetBuffer().RemoveEventHandler(this); 
 327     delete m_contextMenu
; 
 330 /// Member initialisation 
 331 void wxRichTextCtrl::Init() 
 333     m_contextMenu 
= NULL
; 
 335     m_caretPosition 
= -1; 
 336     m_selectionAnchor 
= -2; 
 337     m_selectionAnchorObject 
= NULL
; 
 338     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
 340     m_caretAtLineStart 
= false; 
 342     m_fullLayoutRequired 
= false; 
 343     m_fullLayoutTime 
= 0; 
 344     m_fullLayoutSavedPosition 
= 0; 
 345     m_delayedLayoutThreshold 
= wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD
; 
 346     m_caretPositionForDefaultStyle 
= -2; 
 347     m_focusObject 
= & m_buffer
; 
 350 void wxRichTextCtrl::DoThaw() 
 352     if (GetBuffer().IsDirty()) 
 361 void wxRichTextCtrl::Clear() 
 363     if (GetFocusObject() == & GetBuffer()) 
 365         m_buffer
.ResetAndClearCommands(); 
 366         m_buffer
.Invalidate(wxRICHTEXT_ALL
); 
 370         GetFocusObject()->Reset(); 
 373     m_caretPosition 
= -1; 
 374     m_caretPositionForDefaultStyle 
= -2; 
 375     m_caretAtLineStart 
= false; 
 377     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
 387     wxTextCtrl::SendTextUpdatedEvent(this); 
 391 void wxRichTextCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 393 #if !wxRICHTEXT_USE_OWN_CARET 
 394     if (GetCaret() && !IsFrozen()) 
 399 #if wxRICHTEXT_BUFFERED_PAINTING 
 400         wxBufferedPaintDC 
dc(this, m_bufferBitmap
); 
 410         dc
.SetFont(GetFont()); 
 412         // Paint the background 
 415         // wxRect drawingArea(GetLogicalPoint(wxPoint(0, 0)), GetClientSize()); 
 417         wxRect 
drawingArea(GetUpdateRegion().GetBox()); 
 418         drawingArea
.SetPosition(GetLogicalPoint(drawingArea
.GetPosition())); 
 420         wxRect 
availableSpace(GetClientSize()); 
 421         if (GetBuffer().IsDirty()) 
 423             GetBuffer().Layout(dc
, availableSpace
, wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
); 
 424             GetBuffer().Invalidate(wxRICHTEXT_NONE
); 
 428         wxRect 
clipRect(availableSpace
); 
 429         clipRect
.x 
+= GetBuffer().GetLeftMargin(); 
 430         clipRect
.y 
+= GetBuffer().GetTopMargin(); 
 431         clipRect
.width 
-= (GetBuffer().GetLeftMargin() + GetBuffer().GetRightMargin()); 
 432         clipRect
.height 
-= (GetBuffer().GetTopMargin() + GetBuffer().GetBottomMargin()); 
 433         clipRect
.SetPosition(GetLogicalPoint(clipRect
.GetPosition())); 
 434         dc
.SetClippingRegion(clipRect
); 
 437         if ((GetExtraStyle() & wxRICHTEXT_EX_NO_GUIDELINES
) == 0) 
 438             flags 
|= wxRICHTEXT_DRAW_GUIDELINES
; 
 440         GetBuffer().Draw(dc
, GetBuffer().GetOwnRange(), GetSelection(), drawingArea
, 0 /* descent */, flags
); 
 442         dc
.DestroyClippingRegion(); 
 444         // Other user defined painting after everything else (i.e. all text) is painted 
 445         PaintAboveContent(dc
); 
 447 #if wxRICHTEXT_USE_OWN_CARET 
 448         if (GetCaret()->IsVisible()) 
 450             ((wxRichTextCaret
*) GetCaret())->DoDraw(& dc
); 
 455 #if !wxRICHTEXT_USE_OWN_CARET 
 462 // Empty implementation, to prevent flicker 
 463 void wxRichTextCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 467 void wxRichTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
 471 #if !wxRICHTEXT_USE_OWN_CARET 
 477 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 478     // Work around dropouts when control is focused 
 486 void wxRichTextCtrl::OnKillFocus(wxFocusEvent
& WXUNUSED(event
)) 
 491 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 492     // Work around dropouts when control is focused 
 500 void wxRichTextCtrl::OnCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
 505 // Set up the caret for the given position and container, after a mouse click 
 506 bool wxRichTextCtrl::SetCaretPositionAfterClick(wxRichTextParagraphLayoutBox
* container
, long position
, int hitTestFlags
, bool extendSelection
) 
 508     bool caretAtLineStart 
= false; 
 510     if (hitTestFlags 
& wxRICHTEXT_HITTEST_BEFORE
) 
 512         // If we're at the start of a line (but not first in para) 
 513         // then we should keep the caret showing at the start of the line 
 514         // by showing the m_caretAtLineStart flag. 
 515         wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(position
); 
 516         wxRichTextLine
* line 
= container
->GetLineAtPosition(position
); 
 518         if (line 
&& para 
&& line
->GetAbsoluteRange().GetStart() == position 
&& para
->GetRange().GetStart() != position
) 
 519             caretAtLineStart 
= true; 
 523     if (extendSelection 
&& (m_caretPosition 
!= position
)) 
 524         ExtendSelection(m_caretPosition
, position
, wxRICHTEXT_SHIFT_DOWN
); 
 526     MoveCaret(position
, caretAtLineStart
); 
 527     SetDefaultStyleToCursorStyle(); 
 533 void wxRichTextCtrl::OnLeftClick(wxMouseEvent
& event
) 
 539     dc
.SetFont(GetFont()); 
 541     // TODO: detect change of focus object 
 543     wxRichTextObject
* hitObj 
= NULL
; 
 544     wxRichTextObject
* contextObj 
= NULL
; 
 545     int hit 
= GetBuffer().HitTest(dc
, event
.GetLogicalPosition(dc
), position
, & hitObj
, & contextObj
); 
 547     if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& hitObj
) 
 549         wxRichTextParagraphLayoutBox
* oldFocusObject 
= GetFocusObject(); 
 550         wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 551         if (container 
&& container 
!= GetFocusObject() && container
->AcceptsFocus()) 
 553             SetFocusObject(container
, false /* don't set caret position yet */); 
 556         m_dragStart 
= event
.GetLogicalPosition(dc
); 
 560         long oldCaretPos 
= m_caretPosition
; 
 562         SetCaretPositionAfterClick(container
, position
, hit
); 
 564         // For now, don't handle shift-click when we're selecting multiple objects. 
 565         if (event
.ShiftDown() && GetFocusObject() == oldFocusObject 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 567             if (!m_selection
.IsValid()) 
 568                 ExtendSelection(oldCaretPos
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 570                 ExtendSelection(m_caretPosition
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 580 void wxRichTextCtrl::OnLeftUp(wxMouseEvent
& event
) 
 585         if (GetCapture() == this) 
 588         // See if we clicked on a URL 
 591         dc
.SetFont(GetFont()); 
 594         wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 595         wxRichTextObject
* hitObj 
= NULL
; 
 596         wxRichTextObject
* contextObj 
= NULL
; 
 597         // Only get objects at this level, not nested, because otherwise we couldn't swipe text at a single level. 
 598         int hit 
= GetFocusObject()->HitTest(dc
, logicalPt
, position
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
); 
 600         if ((hit 
!= wxRICHTEXT_HITTEST_NONE
) && !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
 602             wxRichTextEvent 
cmdEvent( 
 603                 wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
, 
 605             cmdEvent
.SetEventObject(this); 
 606             cmdEvent
.SetPosition(position
); 
 608                 cmdEvent
.SetContainer(hitObj
->GetContainer()); 
 610             if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 613                 if (GetStyle(position
, attr
)) 
 615                     if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 617                         wxString urlTarget 
= attr
.GetURL(); 
 618                         if (!urlTarget
.IsEmpty()) 
 620                             wxMouseEvent 
mouseEvent(event
); 
 622                             long startPos 
= 0, endPos 
= 0; 
 623                             wxRichTextObject
* obj 
= GetFocusObject()->GetLeafObjectAtPosition(position
); 
 626                                 startPos 
= obj
->GetRange().GetStart(); 
 627                                 endPos 
= obj
->GetRange().GetEnd(); 
 630                             wxTextUrlEvent 
urlEvent(GetId(), mouseEvent
, startPos
, endPos
); 
 631                             InitCommandEvent(urlEvent
); 
 633                             urlEvent
.SetString(urlTarget
); 
 635                             GetEventHandler()->ProcessEvent(urlEvent
); 
 645 void wxRichTextCtrl::OnMoveMouse(wxMouseEvent
& event
) 
 649     dc
.SetFont(GetFont()); 
 652     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 653     wxRichTextObject
* hitObj 
= NULL
; 
 654     wxRichTextObject
* contextObj 
= NULL
; 
 658     // If we're dragging, let's only consider positions at this level; otherwise 
 659     // selecting a range is not going to work. 
 660     wxRichTextParagraphLayoutBox
* container 
= & GetBuffer(); 
 663         flags 
= wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
; 
 664         container 
= GetFocusObject(); 
 666     int hit 
= container
->HitTest(dc
, logicalPt
, position
, & hitObj
, & contextObj
, flags
); 
 668     // See if we need to change the cursor 
 671         if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
) && hitObj
) 
 673             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 675             if (actualContainer 
&& GetStyle(position
, attr
, actualContainer
)) 
 677                 if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 679                     SetCursor(m_urlCursor
); 
 681                 else if (!attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 683                     SetCursor(m_textCursor
); 
 688             SetCursor(m_textCursor
); 
 691     if (!event
.Dragging()) 
 699         wxRichTextParagraphLayoutBox
* commonAncestor 
= NULL
; 
 700         wxRichTextParagraphLayoutBox
* otherContainer 
= NULL
; 
 701         wxRichTextParagraphLayoutBox
* firstContainer 
= NULL
; 
 703         // Check for dragging across multiple containers 
 705         wxRichTextObject
* hitObj2 
= NULL
, *contextObj2 
= NULL
; 
 706         int hit2 
= GetBuffer().HitTest(dc
, logicalPt
, position2
, & hitObj2
, & contextObj2
, 0); 
 707         if (hit2 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit2 
& wxRICHTEXT_HITTEST_OUTSIDE
) && hitObj2 
&& hitObj 
!= hitObj2
) 
 709             // See if we can find a common ancestor 
 710             if (m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 712                 firstContainer 
= GetFocusObject(); 
 713                 commonAncestor 
= wxDynamicCast(firstContainer
->GetParent(), wxRichTextParagraphLayoutBox
); 
 717                 firstContainer 
= wxDynamicCast(m_selectionAnchorObject
, wxRichTextParagraphLayoutBox
); 
 718                 //commonAncestor = GetFocusObject(); // when the selection state is not normal, the focus object (e.g. table) 
 719                                                    // is the common ancestor. 
 720                 commonAncestor 
= wxDynamicCast(firstContainer
->GetParent(), wxRichTextParagraphLayoutBox
); 
 723             if (commonAncestor 
&& commonAncestor
->HandlesChildSelections()) 
 725                 wxRichTextObject
* p 
= hitObj2
; 
 728                     if (p
->GetParent() == commonAncestor
) 
 730                         otherContainer 
= wxDynamicCast(p
, wxRichTextParagraphLayoutBox
); 
 737             if (commonAncestor 
&& firstContainer 
&& otherContainer
) 
 739                 // We have now got a second container that shares a parent with the current or anchor object. 
 740                 if (m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 742                     // Don't go into common-ancestor selection mode if we still have the same 
 744                     if (otherContainer 
!= firstContainer
) 
 746                         m_selectionState 
= wxRichTextCtrlSelectionState_CommonAncestor
; 
 747                         m_selectionAnchorObject 
= firstContainer
; 
 748                         m_selectionAnchor 
= firstContainer
->GetRange().GetStart(); 
 750                         // The common ancestor, such as a table, returns the cell selection 
 751                         // between the anchor and current position. 
 752                         m_selection 
= commonAncestor
->GetSelection(m_selectionAnchor
, otherContainer
->GetRange().GetStart()); 
 757                     m_selection 
= commonAncestor
->GetSelection(m_selectionAnchor
, otherContainer
->GetRange().GetStart()); 
 762                 if (otherContainer
->AcceptsFocus()) 
 763                     SetFocusObject(otherContainer
, false /* don't set caret and clear selection */); 
 764                 MoveCaret(-1, false); 
 765                 SetDefaultStyleToCursorStyle(); 
 770     if (hitObj 
&& m_dragging 
&& hit 
!= wxRICHTEXT_HITTEST_NONE 
&& m_selectionState 
== wxRichTextCtrlSelectionState_Normal
) 
 772         // TODO: test closeness 
 773         SetCaretPositionAfterClick(container
, position
, hit
, true /* extend selection */); 
 778 void wxRichTextCtrl::OnRightClick(wxMouseEvent
& event
) 
 784     dc
.SetFont(GetFont()); 
 787     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 788     wxRichTextObject
* hitObj 
= NULL
; 
 789     wxRichTextObject
* contextObj 
= NULL
; 
 790     int hit 
= GetFocusObject()->HitTest(dc
, logicalPt
, position
, & hitObj
, & contextObj
); 
 792     if (hitObj 
&& hitObj
->GetContainer() != GetFocusObject()) 
 794         wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
 795         if (actualContainer 
&& actualContainer
->AcceptsFocus()) 
 797             SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
 798             SetCaretPositionAfterClick(actualContainer
, position
, hit
); 
 802     wxRichTextEvent 
cmdEvent( 
 803         wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
, 
 805     cmdEvent
.SetEventObject(this); 
 806     cmdEvent
.SetPosition(position
); 
 808         cmdEvent
.SetContainer(hitObj
->GetContainer()); 
 810     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 814 /// Left-double-click 
 815 void wxRichTextCtrl::OnLeftDClick(wxMouseEvent
& WXUNUSED(event
)) 
 817     wxRichTextEvent 
cmdEvent( 
 818         wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
, 
 820     cmdEvent
.SetEventObject(this); 
 821     cmdEvent
.SetPosition(m_caretPosition
+1); 
 822     cmdEvent
.SetContainer(GetFocusObject()); 
 824     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 826         SelectWord(GetCaretPosition()+1); 
 831 void wxRichTextCtrl::OnMiddleClick(wxMouseEvent
& event
) 
 833     wxRichTextEvent 
cmdEvent( 
 834         wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
, 
 836     cmdEvent
.SetEventObject(this); 
 837     cmdEvent
.SetPosition(m_caretPosition
+1); 
 838     cmdEvent
.SetContainer(GetFocusObject()); 
 840     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 845 void wxRichTextCtrl::OnChar(wxKeyEvent
& event
) 
 849         flags 
|= wxRICHTEXT_CTRL_DOWN
; 
 850     if (event
.ShiftDown()) 
 851         flags 
|= wxRICHTEXT_SHIFT_DOWN
; 
 853         flags 
|= wxRICHTEXT_ALT_DOWN
; 
 855     if (event
.GetEventType() == wxEVT_KEY_DOWN
) 
 857         if (event
.IsKeyInCategory(WXK_CATEGORY_NAVIGATION
)) 
 859             KeyboardNavigate(event
.GetKeyCode(), flags
); 
 863         long keycode 
= event
.GetKeyCode(); 
 923             case WXK_NUMPAD_HOME
: 
 924             case WXK_NUMPAD_LEFT
: 
 926             case WXK_NUMPAD_RIGHT
: 
 927             case WXK_NUMPAD_DOWN
: 
 928             case WXK_NUMPAD_PAGEUP
: 
 929             case WXK_NUMPAD_PAGEDOWN
: 
 931             case WXK_NUMPAD_BEGIN
: 
 932             case WXK_NUMPAD_INSERT
: 
 933             case WXK_WINDOWS_LEFT
: 
 942         // Must process this before translation, otherwise it's translated into a WXK_DELETE event. 
 943         if (event
.CmdDown() && event
.GetKeyCode() == WXK_BACK
) 
 945             BeginBatchUndo(_("Delete Text")); 
 947             long newPos 
= m_caretPosition
; 
 949             bool processed 
= DeleteSelectedContent(& newPos
); 
 951             // Submit range in character positions, which are greater than caret positions, 
 952             // so subtract 1 for deleted character and add 1 for conversion to character position. 
 957                     long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
 960                         GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(pos
+1, newPos
), this, & GetBuffer()); 
 966                     GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos
, newPos
), this, & GetBuffer()); 
 971             if (GetLastPosition() == -1) 
 973                 GetFocusObject()->Reset(); 
 975                 m_caretPosition 
= -1; 
 977                 SetDefaultStyleToCursorStyle(); 
 980             ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
 982             wxRichTextEvent 
cmdEvent( 
 983                 wxEVT_COMMAND_RICHTEXT_DELETE
, 
 985             cmdEvent
.SetEventObject(this); 
 986             cmdEvent
.SetFlags(flags
); 
 987             cmdEvent
.SetPosition(m_caretPosition
+1); 
 988             cmdEvent
.SetContainer(GetFocusObject()); 
 989             GetEventHandler()->ProcessEvent(cmdEvent
); 
 999     // all the other keys modify the controls contents which shouldn't be 
1000     // possible if we're read-only 
1001     if ( !IsEditable() ) 
1007     if (event
.GetKeyCode() == WXK_RETURN
) 
1009         BeginBatchUndo(_("Insert Text")); 
1011         long newPos 
= m_caretPosition
; 
1013         DeleteSelectedContent(& newPos
); 
1015         if (event
.ShiftDown()) 
1018             text 
= wxRichTextLineBreakChar
; 
1019             GetFocusObject()->InsertTextWithUndo(newPos
+1, text
, this, & GetBuffer()); 
1020             m_caretAtLineStart 
= true; 
1024             GetFocusObject()->InsertNewlineWithUndo(newPos
+1, this, & GetBuffer(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
|wxRICHTEXT_INSERT_INTERACTIVE
); 
1027         SetDefaultStyleToCursorStyle(); 
1029         ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
1031         wxRichTextEvent 
cmdEvent( 
1032             wxEVT_COMMAND_RICHTEXT_RETURN
, 
1034         cmdEvent
.SetEventObject(this); 
1035         cmdEvent
.SetFlags(flags
); 
1036         cmdEvent
.SetPosition(newPos
+1); 
1037         cmdEvent
.SetContainer(GetFocusObject()); 
1039         if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
1041             // Generate conventional event 
1042             wxCommandEvent 
textEvent(wxEVT_COMMAND_TEXT_ENTER
, GetId()); 
1043             InitCommandEvent(textEvent
); 
1045             GetEventHandler()->ProcessEvent(textEvent
); 
1049     else if (event
.GetKeyCode() == WXK_BACK
) 
1051         BeginBatchUndo(_("Delete Text")); 
1053         long newPos 
= m_caretPosition
; 
1055         bool processed 
= DeleteSelectedContent(& newPos
); 
1057         // Submit range in character positions, which are greater than caret positions, 
1058         // so subtract 1 for deleted character and add 1 for conversion to character position. 
1061             if (event
.CmdDown()) 
1063                 long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
1066                     GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(pos
+1, newPos
), this, & GetBuffer()); 
1072                 GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos
, newPos
), this, & GetBuffer()); 
1077         if (GetLastPosition() == -1) 
1079             GetFocusObject()->Reset(); 
1081             m_caretPosition 
= -1; 
1083             SetDefaultStyleToCursorStyle(); 
1086         ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
1088         wxRichTextEvent 
cmdEvent( 
1089             wxEVT_COMMAND_RICHTEXT_DELETE
, 
1091         cmdEvent
.SetEventObject(this); 
1092         cmdEvent
.SetFlags(flags
); 
1093         cmdEvent
.SetPosition(m_caretPosition
+1); 
1094         cmdEvent
.SetContainer(GetFocusObject()); 
1095         GetEventHandler()->ProcessEvent(cmdEvent
); 
1099     else if (event
.GetKeyCode() == WXK_DELETE
) 
1101         BeginBatchUndo(_("Delete Text")); 
1103         long newPos 
= m_caretPosition
; 
1105         bool processed 
= DeleteSelectedContent(& newPos
); 
1107         // Submit range in character positions, which are greater than caret positions, 
1108         if (newPos 
< GetFocusObject()->GetOwnRange().GetEnd()+1) 
1110             if (event
.CmdDown()) 
1112                 long pos 
= wxRichTextCtrl::FindNextWordPosition(1); 
1113                 if (pos 
!= -1 && (pos 
> newPos
)) 
1115                     GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos
+1, pos
), this, & GetBuffer()); 
1120             if (!processed 
&& newPos 
< (GetLastPosition()-1)) 
1121                 GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos
+1, newPos
+1), this, & GetBuffer()); 
1126         if (GetLastPosition() == -1) 
1128             GetFocusObject()->Reset(); 
1130             m_caretPosition 
= -1; 
1132             SetDefaultStyleToCursorStyle(); 
1135         wxRichTextEvent 
cmdEvent( 
1136             wxEVT_COMMAND_RICHTEXT_DELETE
, 
1138         cmdEvent
.SetEventObject(this); 
1139         cmdEvent
.SetFlags(flags
); 
1140         cmdEvent
.SetPosition(m_caretPosition
+1); 
1141         cmdEvent
.SetContainer(GetFocusObject()); 
1142         GetEventHandler()->ProcessEvent(cmdEvent
); 
1148         long keycode 
= event
.GetKeyCode(); 
1160                 if (event
.CmdDown()) 
1162                 // Fixes AltGr+key with European input languages on Windows 
1163                 if ((event
.CmdDown() && !event
.AltDown()) || (event
.AltDown() && !event
.CmdDown())) 
1170                 wxRichTextEvent 
cmdEvent( 
1171                     wxEVT_COMMAND_RICHTEXT_CHARACTER
, 
1173                 cmdEvent
.SetEventObject(this); 
1174                 cmdEvent
.SetFlags(flags
); 
1176                 cmdEvent
.SetCharacter(event
.GetUnicodeKey()); 
1178                 cmdEvent
.SetCharacter((wxChar
) keycode
); 
1180                 cmdEvent
.SetPosition(m_caretPosition
+1); 
1181                 cmdEvent
.SetContainer(GetFocusObject()); 
1183                 if (keycode 
== wxT('\t')) 
1185                     // See if we need to promote or demote the selection or paragraph at the cursor 
1186                     // position, instead of inserting a tab. 
1187                     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
1188                     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
); 
1189                     if (para 
&& para
->GetRange().GetStart() == pos 
&& para
->GetAttributes().HasListStyleName()) 
1191                         wxRichTextRange range
; 
1193                             range 
= GetSelectionRange(); 
1195                             range 
= para
->GetRange().FromInternal(); 
1197                         int promoteBy 
= event
.ShiftDown() ? 1 : -1; 
1199                         PromoteList(promoteBy
, range
, NULL
); 
1201                         GetEventHandler()->ProcessEvent(cmdEvent
); 
1207                 BeginBatchUndo(_("Insert Text")); 
1209                 long newPos 
= m_caretPosition
; 
1210                 DeleteSelectedContent(& newPos
); 
1213                 wxString str 
= event
.GetUnicodeKey(); 
1215                 wxString str 
= (wxChar
) event
.GetKeyCode(); 
1217                 GetFocusObject()->InsertTextWithUndo(newPos
+1, str
, this, & GetBuffer(), 0); 
1221                 SetDefaultStyleToCursorStyle(); 
1222                 ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
1224                 GetEventHandler()->ProcessEvent(cmdEvent
); 
1232 /// Delete content if there is a selection, e.g. when pressing a key. 
1233 bool wxRichTextCtrl::DeleteSelectedContent(long* newPos
) 
1237         long pos 
= m_selection
.GetRange().GetStart(); 
1238         wxRichTextRange range 
= m_selection
.GetRange(); 
1240         // SelectAll causes more to be selected than doing it interactively, 
1241         // and causes a new paragraph to be inserted. So for multiline buffers, 
1242         // don't delete the final position. 
1243         if (range
.GetEnd() == GetLastPosition() && GetNumberOfLines() > 0) 
1244             range
.SetEnd(range
.GetEnd()-1); 
1246         GetFocusObject()->DeleteRangeWithUndo(range
, this, & GetBuffer()); 
1247         m_selection
.Reset(); 
1248         m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
1258 /// Keyboard navigation 
1262 Left:       left one character 
1263 Right:      right one character 
1266 Ctrl-Left:  left one word 
1267 Ctrl-Right: right one word 
1268 Ctrl-Up:    previous paragraph start 
1269 Ctrl-Down:  next start of paragraph 
1272 Ctrl-Home:  start of document 
1273 Ctrl-End:   end of document 
1274 Page-Up:    Up a screen 
1275 Page-Down:  Down a screen 
1279 Ctrl-Alt-PgUp: Start of window 
1280 Ctrl-Alt-PgDn: End of window 
1281 F8:         Start selection mode 
1282 Esc:        End selection mode 
1284 Adding Shift does the above but starts/extends selection. 
1289 bool wxRichTextCtrl::KeyboardNavigate(int keyCode
, int flags
) 
1291     bool success 
= false; 
1293     if (keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT
) 
1295         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1296             success 
= WordRight(1, flags
); 
1298             success 
= MoveRight(1, flags
); 
1300     else if (keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT
) 
1302         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1303             success 
= WordLeft(1, flags
); 
1305             success 
= MoveLeft(1, flags
); 
1307     else if (keyCode 
== WXK_UP 
|| keyCode 
== WXK_NUMPAD_UP
) 
1309         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1310             success 
= MoveToParagraphStart(flags
); 
1312             success 
= MoveUp(1, flags
); 
1314     else if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN
) 
1316         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1317             success 
= MoveToParagraphEnd(flags
); 
1319             success 
= MoveDown(1, flags
); 
1321     else if (keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP
) 
1323         success 
= PageUp(1, flags
); 
1325     else if (keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1327         success 
= PageDown(1, flags
); 
1329     else if (keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME
) 
1331         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1332             success 
= MoveHome(flags
); 
1334             success 
= MoveToLineStart(flags
); 
1336     else if (keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END
) 
1338         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1339             success 
= MoveEnd(flags
); 
1341             success 
= MoveToLineEnd(flags
); 
1346         ScrollIntoView(m_caretPosition
, keyCode
); 
1347         SetDefaultStyleToCursorStyle(); 
1353 /// Extend the selection. Selections are in caret positions. 
1354 bool wxRichTextCtrl::ExtendSelection(long oldPos
, long newPos
, int flags
) 
1356     if (flags 
& wxRICHTEXT_SHIFT_DOWN
) 
1358         if (oldPos 
== newPos
) 
1361         wxRichTextSelection oldSelection 
= m_selection
; 
1363         m_selection
.SetContainer(GetFocusObject()); 
1365         wxRichTextRange oldRange
; 
1366         if (m_selection
.IsValid()) 
1367             oldRange 
= m_selection
.GetRange(); 
1369             oldRange 
= wxRICHTEXT_NO_SELECTION
; 
1370         wxRichTextRange newRange
; 
1372         // If not currently selecting, start selecting 
1373         if (oldRange
.GetStart() == -2) 
1375             m_selectionAnchor 
= oldPos
; 
1377             if (oldPos 
> newPos
) 
1378                 newRange
.SetRange(newPos
+1, oldPos
); 
1380                 newRange
.SetRange(oldPos
+1, newPos
); 
1384             // Always ensure that the selection range start is greater than 
1386             if (newPos 
> m_selectionAnchor
) 
1387                 newRange
.SetRange(m_selectionAnchor
+1, newPos
); 
1388             else if (newPos 
== m_selectionAnchor
) 
1389                 newRange 
= wxRichTextRange(-2, -2); 
1391                 newRange
.SetRange(newPos
+1, m_selectionAnchor
); 
1394         m_selection
.SetRange(newRange
); 
1396         RefreshForSelectionChange(oldSelection
, m_selection
); 
1398         if (newRange
.GetStart() > newRange
.GetEnd()) 
1400             wxLogDebug(wxT("Strange selection range")); 
1409 /// Scroll into view, returning true if we scrolled. 
1410 /// This takes a _caret_ position. 
1411 bool wxRichTextCtrl::ScrollIntoView(long position
, int keyCode
) 
1413     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(position
); 
1419     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1421     int startXUnits
, startYUnits
; 
1422     GetViewStart(& startXUnits
, & startYUnits
); 
1423     int startY 
= startYUnits 
* ppuY
; 
1426     GetVirtualSize(& sx
, & sy
); 
1432     wxRect rect 
= line
->GetRect(); 
1434     bool scrolled 
= false; 
1436     wxSize clientSize 
= GetClientSize(); 
1438     int leftMargin
, rightMargin
, topMargin
, bottomMargin
; 
1441         wxClientDC 
dc(this); 
1442         wxRichTextObject::GetTotalMargin(dc
, & GetBuffer(), GetBuffer().GetAttributes(), leftMargin
, rightMargin
, 
1443             topMargin
, bottomMargin
); 
1445 //    clientSize.y -= GetBuffer().GetBottomMargin(); 
1446     clientSize
.y 
-= bottomMargin
; 
1448     if (GetWindowStyle() & wxRE_CENTRE_CARET
) 
1450         int y 
= rect
.y 
- GetClientSize().y
/2; 
1451         int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1452         if (y 
>= 0 && (y 
+ clientSize
.y
) < GetBuffer().GetCachedSize().y
) 
1454             if (startYUnits 
!= yUnits
) 
1456                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1459 #if !wxRICHTEXT_USE_OWN_CARET 
1469     if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN 
|| 
1470         keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT 
|| 
1471         keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END 
|| 
1472         keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1474         if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1476             // Make it scroll so this item is at the bottom 
1478             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1479             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1481             // If we're still off the screen, scroll another line down 
1482             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1485             if (startYUnits 
!= yUnits
) 
1487                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1491         else if (rect
.y 
< (startY 
+ GetBuffer().GetTopMargin())) 
1493             // Make it scroll so this item is at the top 
1495             int y 
= rect
.y 
- GetBuffer().GetTopMargin(); 
1496             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1498             if (startYUnits 
!= yUnits
) 
1500                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1506     else if (keyCode 
== WXK_UP  
|| keyCode 
== WXK_NUMPAD_UP 
|| 
1507              keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT 
|| 
1508              keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME 
|| 
1509              keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP 
) 
1511         if (rect
.y 
< (startY 
+ GetBuffer().GetBottomMargin())) 
1513             // Make it scroll so this item is at the top 
1515             int y 
= rect
.y 
- GetBuffer().GetTopMargin(); 
1516             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1518             if (startYUnits 
!= yUnits
) 
1520                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1524         else if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1526             // Make it scroll so this item is at the bottom 
1528             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1529             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1531             // If we're still off the screen, scroll another line down 
1532             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1535             if (startYUnits 
!= yUnits
) 
1537                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1543 #if !wxRICHTEXT_USE_OWN_CARET 
1551 /// Is the given position visible on the screen? 
1552 bool wxRichTextCtrl::IsPositionVisible(long pos
) const 
1554     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(pos
-1); 
1560     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1563     GetViewStart(& startX
, & startY
); 
1565     startY 
= startY 
* ppuY
; 
1567     wxRect rect 
= line
->GetRect(); 
1568     wxSize clientSize 
= GetClientSize(); 
1569     clientSize
.y 
-= GetBuffer().GetBottomMargin(); 
1571     return (rect
.GetTop() >= (startY 
+ GetBuffer().GetTopMargin())) && (rect
.GetBottom() <= (startY 
+ clientSize
.y
)); 
1574 void wxRichTextCtrl::SetCaretPosition(long position
, bool showAtLineStart
) 
1576     m_caretPosition 
= position
; 
1577     m_caretAtLineStart 
= showAtLineStart
; 
1580 /// Move caret one visual step forward: this may mean setting a flag 
1581 /// and keeping the same position if we're going from the end of one line 
1582 /// to the start of the next, which may be the exact same caret position. 
1583 void wxRichTextCtrl::MoveCaretForward(long oldPosition
) 
1585     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(oldPosition
); 
1587     // Only do the check if we're not at the end of the paragraph (where things work OK 
1589     if (para 
&& (oldPosition 
!= para
->GetRange().GetEnd() - 1)) 
1591         wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(oldPosition
); 
1595             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1597             // We're at the end of a line. See whether we need to 
1598             // stay at the same actual caret position but change visual 
1599             // position, or not. 
1600             if (oldPosition 
== lineRange
.GetEnd()) 
1602                 if (m_caretAtLineStart
) 
1604                     // We're already at the start of the line, so actually move on now. 
1605                     m_caretPosition 
= oldPosition 
+ 1; 
1606                     m_caretAtLineStart 
= false; 
1610                     // We're showing at the end of the line, so keep to 
1611                     // the same position but indicate that we're to show 
1612                     // at the start of the next line. 
1613                     m_caretPosition 
= oldPosition
; 
1614                     m_caretAtLineStart 
= true; 
1616                 SetDefaultStyleToCursorStyle(); 
1622     SetDefaultStyleToCursorStyle(); 
1625 /// Move caret one visual step backward: this may mean setting a flag 
1626 /// and keeping the same position if we're going from the end of one line 
1627 /// to the start of the next, which may be the exact same caret position. 
1628 void wxRichTextCtrl::MoveCaretBack(long oldPosition
) 
1630     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(oldPosition
); 
1632     // Only do the check if we're not at the start of the paragraph (where things work OK 
1634     if (para 
&& (oldPosition 
!= para
->GetRange().GetStart())) 
1636         wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(oldPosition
); 
1640             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1642             // We're at the start of a line. See whether we need to 
1643             // stay at the same actual caret position but change visual 
1644             // position, or not. 
1645             if (oldPosition 
== lineRange
.GetStart()) 
1647                 m_caretPosition 
= oldPosition
-1; 
1648                 m_caretAtLineStart 
= true; 
1651             else if (oldPosition 
== lineRange
.GetEnd()) 
1653                 if (m_caretAtLineStart
) 
1655                     // We're at the start of the line, so keep the same caret position 
1656                     // but clear the start-of-line flag. 
1657                     m_caretPosition 
= oldPosition
; 
1658                     m_caretAtLineStart 
= false; 
1662                     // We're showing at the end of the line, so go back 
1663                     // to the previous character position. 
1664                     m_caretPosition 
= oldPosition 
- 1; 
1666                 SetDefaultStyleToCursorStyle(); 
1672     SetDefaultStyleToCursorStyle(); 
1676 bool wxRichTextCtrl::MoveRight(int noPositions
, int flags
) 
1678     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd(); 
1680     if (m_caretPosition 
+ noPositions 
< endPos
) 
1682         long oldPos 
= m_caretPosition
; 
1683         long newPos 
= m_caretPosition 
+ noPositions
; 
1685         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1689         // Determine by looking at oldPos and m_caretPosition whether 
1690         // we moved from the end of a line to the start of the next line, in which case 
1691         // we want to adjust the caret position such that it is positioned at the 
1692         // start of the next line, rather than jumping past the first character of the 
1694         if (noPositions 
== 1 && !extendSel
) 
1695             MoveCaretForward(oldPos
); 
1697             SetCaretPosition(newPos
); 
1700         SetDefaultStyleToCursorStyle(); 
1709 bool wxRichTextCtrl::MoveLeft(int noPositions
, int flags
) 
1713     if (m_caretPosition 
> startPos 
- noPositions 
+ 1) 
1715         long oldPos 
= m_caretPosition
; 
1716         long newPos 
= m_caretPosition 
- noPositions
; 
1717         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1721         if (noPositions 
== 1 && !extendSel
) 
1722             MoveCaretBack(oldPos
); 
1724             SetCaretPosition(newPos
); 
1727         SetDefaultStyleToCursorStyle(); 
1735 // Find the caret position for the combination of hit-test flags and character position. 
1736 // Returns the caret position and also an indication of where to place the caret (caretLineStart) 
1737 // since this is ambiguous (same position used for end of line and start of next). 
1738 long wxRichTextCtrl::FindCaretPositionForCharacterPosition(long position
, int hitTestFlags
, wxRichTextParagraphLayoutBox
* container
, 
1739                                                    bool& caretLineStart
) 
1741     // If end of previous line, and hitTest is wxRICHTEXT_HITTEST_BEFORE, 
1742     // we want to be at the end of the last line but with m_caretAtLineStart set to true, 
1743     // so we view the caret at the start of the line. 
1744     caretLineStart 
= false; 
1745     long caretPosition 
= position
; 
1747     if (hitTestFlags 
& wxRICHTEXT_HITTEST_BEFORE
) 
1749         wxRichTextLine
* thisLine 
= container
->GetLineAtPosition(position
-1); 
1750         wxRichTextRange lineRange
; 
1752             lineRange 
= thisLine
->GetAbsoluteRange(); 
1754         if (thisLine 
&& (position
-1) == lineRange
.GetEnd()) 
1757             caretLineStart 
= true; 
1761             wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(position
); 
1762             if (para 
&& para
->GetRange().GetStart() == position
) 
1766     return caretPosition
; 
1770 bool wxRichTextCtrl::MoveUp(int noLines
, int flags
) 
1772     return MoveDown(- noLines
, flags
); 
1776 bool wxRichTextCtrl::MoveDown(int noLines
, int flags
) 
1781     long lineNumber 
= GetFocusObject()->GetVisibleLineNumber(m_caretPosition
, true, m_caretAtLineStart
); 
1782     wxPoint pt 
= GetCaret()->GetPosition(); 
1783     long newLine 
= lineNumber 
+ noLines
; 
1784     bool notInThisObject 
= false; 
1786     if (lineNumber 
!= -1) 
1790             long lastLine 
= GetFocusObject()->GetVisibleLineNumber(GetFocusObject()->GetOwnRange().GetEnd()); 
1791             if (newLine 
> lastLine
) 
1792                 notInThisObject 
= true; 
1797                 notInThisObject 
= true; 
1801     wxRichTextParagraphLayoutBox
* container 
= GetFocusObject(); 
1802     int hitTestFlags 
= wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
|wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS
; 
1804     if (notInThisObject
) 
1806         // If we know we're navigating out of the current object, 
1807         // try to find an object anywhere in the buffer at the new position (up or down a bit) 
1808         container 
= & GetBuffer(); 
1809         hitTestFlags 
&= ~wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
; 
1811         if (noLines 
> 0) // going down 
1813             pt
.y 
= GetFocusObject()->GetPosition().y 
+ GetFocusObject()->GetCachedSize().y 
+ 2; 
1817             pt
.y 
= GetFocusObject()->GetPosition().y 
- 2; 
1822         wxRichTextLine
* lineObj 
= GetFocusObject()->GetLineForVisibleLineNumber(newLine
); 
1824             pt
.y 
= lineObj
->GetAbsolutePosition().y 
+ 2; 
1830     wxClientDC 
dc(this); 
1832     dc
.SetFont(GetFont()); 
1834     wxRichTextObject
* hitObj 
= NULL
; 
1835     wxRichTextObject
* contextObj 
= NULL
; 
1836     int hitTest 
= container
->HitTest(dc
, pt
, newPos
, & hitObj
, & contextObj
, hitTestFlags
); 
1839         ((hitTest 
& wxRICHTEXT_HITTEST_NONE
) == 0) && 
1840         (! (hitObj 
== (& m_buffer
) && ((hitTest 
& wxRICHTEXT_HITTEST_OUTSIDE
) != 0))) // outside the buffer counts as 'do nothing' 
1843         if (notInThisObject
) 
1845             wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
1846             if (actualContainer 
&& actualContainer 
!= GetFocusObject() && actualContainer
->AcceptsFocus()) 
1848                 SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
1850                 container 
= actualContainer
; 
1854         bool caretLineStart 
= true; 
1855         long caretPosition 
= FindCaretPositionForCharacterPosition(newPos
, hitTest
, container
, caretLineStart
); 
1856         long newSelEnd 
= caretPosition
; 
1859         if (notInThisObject
) 
1862             extendSel 
= ExtendSelection(m_caretPosition
, newSelEnd
, flags
); 
1867         SetCaretPosition(caretPosition
, caretLineStart
); 
1869         SetDefaultStyleToCursorStyle(); 
1877 /// Move to the end of the paragraph 
1878 bool wxRichTextCtrl::MoveToParagraphEnd(int flags
) 
1880     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(m_caretPosition
, true); 
1883         long newPos 
= para
->GetRange().GetEnd() - 1; 
1884         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1888         SetCaretPosition(newPos
); 
1890         SetDefaultStyleToCursorStyle(); 
1898 /// Move to the start of the paragraph 
1899 bool wxRichTextCtrl::MoveToParagraphStart(int flags
) 
1901     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(m_caretPosition
, true); 
1904         long newPos 
= para
->GetRange().GetStart() - 1; 
1905         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1909         SetCaretPosition(newPos
); 
1911         SetDefaultStyleToCursorStyle(); 
1919 /// Move to the end of the line 
1920 bool wxRichTextCtrl::MoveToLineEnd(int flags
) 
1922     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1926         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1927         long newPos 
= lineRange
.GetEnd(); 
1928         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1932         SetCaretPosition(newPos
); 
1934         SetDefaultStyleToCursorStyle(); 
1942 /// Move to the start of the line 
1943 bool wxRichTextCtrl::MoveToLineStart(int flags
) 
1945     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1948         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1949         long newPos 
= lineRange
.GetStart()-1; 
1951         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1955         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphForLine(line
); 
1957         SetCaretPosition(newPos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
1959         SetDefaultStyleToCursorStyle(); 
1967 /// Move to the start of the buffer 
1968 bool wxRichTextCtrl::MoveHome(int flags
) 
1970     if (m_caretPosition 
!= -1) 
1972         bool extendSel 
= ExtendSelection(m_caretPosition
, -1, flags
); 
1976         SetCaretPosition(-1); 
1978         SetDefaultStyleToCursorStyle(); 
1986 /// Move to the end of the buffer 
1987 bool wxRichTextCtrl::MoveEnd(int flags
) 
1989     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd()-1; 
1991     if (m_caretPosition 
!= endPos
) 
1993         bool extendSel 
= ExtendSelection(m_caretPosition
, endPos
, flags
); 
1997         SetCaretPosition(endPos
); 
1999         SetDefaultStyleToCursorStyle(); 
2007 /// Move noPages pages up 
2008 bool wxRichTextCtrl::PageUp(int noPages
, int flags
) 
2010     return PageDown(- noPages
, flags
); 
2013 /// Move noPages pages down 
2014 bool wxRichTextCtrl::PageDown(int noPages
, int flags
) 
2016     // Calculate which line occurs noPages * screen height further down. 
2017     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
2020         wxSize clientSize 
= GetClientSize(); 
2021         int newY 
= line
->GetAbsolutePosition().y 
+ noPages
*clientSize
.y
; 
2023         wxRichTextLine
* newLine 
= GetFocusObject()->GetLineAtYPosition(newY
); 
2026             wxRichTextRange lineRange 
= newLine
->GetAbsoluteRange(); 
2027             long pos 
= lineRange
.GetStart()-1; 
2028             if (pos 
!= m_caretPosition
) 
2030                 wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphForLine(newLine
); 
2032                 bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2036                 SetCaretPosition(pos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
2038                 SetDefaultStyleToCursorStyle(); 
2048 static bool wxRichTextCtrlIsWhitespace(const wxString
& str
) 
2050     return str 
== wxT(" ") || str 
== wxT("\t"); 
2053 // Finds the caret position for the next word 
2054 long wxRichTextCtrl::FindNextWordPosition(int direction
) const 
2056     long endPos 
= GetFocusObject()->GetOwnRange().GetEnd(); 
2060         long i 
= m_caretPosition
+1+direction
; // +1 for conversion to character pos 
2062         // First skip current text to space 
2063         while (i 
< endPos 
&& i 
> -1) 
2065             // i is in character, not caret positions 
2066             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2067             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2068             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
2072             else if (!wxRichTextCtrlIsWhitespace(text
) && !text
.empty()) 
2079         while (i 
< endPos 
&& i 
> -1) 
2081             // i is in character, not caret positions 
2082             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2083             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2084             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
2085                 return wxMax(-1, i
); 
2087             if (text
.empty()) // End of paragraph, or maybe an image 
2088                 return wxMax(-1, i 
- 1); 
2089             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
2093                 // Convert to caret position 
2094                 return wxMax(-1, i 
- 1); 
2103         long i 
= m_caretPosition
; 
2105         // First skip white space 
2106         while (i 
< endPos 
&& i 
> -1) 
2108             // i is in character, not caret positions 
2109             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2110             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2112             if (text
.empty() || (line 
&& (i 
== line
->GetAbsoluteRange().GetStart()))) // End of paragraph, or maybe an image 
2114             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
2119         // Next skip current text to space 
2120         while (i 
< endPos 
&& i 
> -1) 
2122             // i is in character, not caret positions 
2123             wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(i
, i
)); 
2124             wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(i
, false); 
2125             if (line 
&& line
->GetAbsoluteRange().GetStart() == i
) 
2128             if (!wxRichTextCtrlIsWhitespace(text
) /* && !text.empty() */) 
2141 /// Move n words left 
2142 bool wxRichTextCtrl::WordLeft(int WXUNUSED(n
), int flags
) 
2144     long pos 
= FindNextWordPosition(-1); 
2145     if (pos 
!= m_caretPosition
) 
2147         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
, true); 
2149         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2153         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
2155         SetDefaultStyleToCursorStyle(); 
2163 /// Move n words right 
2164 bool wxRichTextCtrl::WordRight(int WXUNUSED(n
), int flags
) 
2166     long pos 
= FindNextWordPosition(1); 
2167     if (pos 
!= m_caretPosition
) 
2169         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
, true); 
2171         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
2175         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
2177         SetDefaultStyleToCursorStyle(); 
2186 void wxRichTextCtrl::OnSize(wxSizeEvent
& event
) 
2188     // Only do sizing optimization for large buffers 
2189     if (GetBuffer().GetOwnRange().GetEnd() > m_delayedLayoutThreshold
) 
2191         m_fullLayoutRequired 
= true; 
2192         m_fullLayoutTime 
= wxGetLocalTimeMillis(); 
2193         m_fullLayoutSavedPosition 
= GetFirstVisiblePosition(); 
2194         LayoutContent(true /* onlyVisibleRect */); 
2197         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2199 #if wxRICHTEXT_BUFFERED_PAINTING 
2207 /// Idle-time processing 
2208 void wxRichTextCtrl::OnIdle(wxIdleEvent
& event
) 
2210 #if wxRICHTEXT_USE_OWN_CARET 
2211     if (((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
2213         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(false); 
2219     const int layoutInterval 
= wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL
; 
2221     if (m_fullLayoutRequired 
&& (wxGetLocalTimeMillis() > (m_fullLayoutTime 
+ layoutInterval
))) 
2223         m_fullLayoutRequired 
= false; 
2224         m_fullLayoutTime 
= 0; 
2225         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2226         ShowPosition(m_fullLayoutSavedPosition
); 
2230     if (m_caretPositionForDefaultStyle 
!= -2) 
2232         // If the caret position has changed, no longer reflect the default style 
2234         if (GetCaretPosition() != m_caretPositionForDefaultStyle
) 
2235             m_caretPositionForDefaultStyle 
= -2; 
2242 void wxRichTextCtrl::OnScroll(wxScrollWinEvent
& event
) 
2244 #if wxRICHTEXT_USE_OWN_CARET 
2245     if (!((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
2248         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(); 
2255 /// Set up scrollbars, e.g. after a resize 
2256 void wxRichTextCtrl::SetupScrollbars(bool atTop
) 
2261     if (GetBuffer().IsEmpty()) 
2263         SetScrollbars(0, 0, 0, 0, 0, 0); 
2267     // TODO: reimplement scrolling so we scroll by line, not by fixed number 
2268     // of pixels. See e.g. wxVScrolledWindow for ideas. 
2269     int pixelsPerUnit 
= 5; 
2270     wxSize clientSize 
= GetClientSize(); 
2272     int maxHeight 
= GetBuffer().GetCachedSize().y 
+ GetBuffer().GetTopMargin(); 
2274     // Round up so we have at least maxHeight pixels 
2275     int unitsY 
= (int) (((float)maxHeight
/(float)pixelsPerUnit
) + 0.5); 
2277     int startX 
= 0, startY 
= 0; 
2279         GetViewStart(& startX
, & startY
); 
2281     int maxPositionX 
= 0; 
2282     int maxPositionY 
= (int) ((((float)(wxMax((unitsY
*pixelsPerUnit
) - clientSize
.y
, 0)))/((float)pixelsPerUnit
)) + 0.5); 
2284     int newStartX 
= wxMin(maxPositionX
, startX
); 
2285     int newStartY 
= wxMin(maxPositionY
, startY
); 
2287     int oldPPUX
, oldPPUY
; 
2288     int oldStartX
, oldStartY
; 
2289     int oldVirtualSizeX 
= 0, oldVirtualSizeY 
= 0; 
2290     GetScrollPixelsPerUnit(& oldPPUX
, & oldPPUY
); 
2291     GetViewStart(& oldStartX
, & oldStartY
); 
2292     GetVirtualSize(& oldVirtualSizeX
, & oldVirtualSizeY
); 
2294         oldVirtualSizeY 
/= oldPPUY
; 
2296     if (oldPPUX 
== 0 && oldPPUY 
== pixelsPerUnit 
&& oldVirtualSizeY 
== unitsY 
&& oldStartX 
== newStartX 
&& oldStartY 
== newStartY
) 
2299     // Don't set scrollbars if there were none before, and there will be none now. 
2300     if (oldPPUY 
!= 0 && (oldVirtualSizeY
*oldPPUY 
< clientSize
.y
) && (unitsY
*pixelsPerUnit 
< clientSize
.y
)) 
2303     // Move to previous scroll position if 
2305     SetScrollbars(0, pixelsPerUnit
, 0, unitsY
, newStartX
, newStartY
); 
2308 /// Paint the background 
2309 void wxRichTextCtrl::PaintBackground(wxDC
& dc
) 
2311     wxColour backgroundColour 
= GetBackgroundColour(); 
2312     if (!backgroundColour
.Ok()) 
2313         backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
2315     // Clear the background 
2316     dc
.SetBrush(wxBrush(backgroundColour
)); 
2317     dc
.SetPen(*wxTRANSPARENT_PEN
); 
2318     wxRect 
windowRect(GetClientSize()); 
2319     windowRect
.x 
-= 2; windowRect
.y 
-= 2; 
2320     windowRect
.width 
+= 4; windowRect
.height 
+= 4; 
2322     // We need to shift the rectangle to take into account 
2323     // scrolling. Converting device to logical coordinates. 
2324     CalcUnscrolledPosition(windowRect
.x
, windowRect
.y
, & windowRect
.x
, & windowRect
.y
); 
2325     dc
.DrawRectangle(windowRect
); 
2328 #if wxRICHTEXT_BUFFERED_PAINTING 
2329 /// Recreate buffer bitmap if necessary 
2330 bool wxRichTextCtrl::RecreateBuffer(const wxSize
& size
) 
2333     if (sz 
== wxDefaultSize
) 
2334         sz 
= GetClientSize(); 
2336     if (sz
.x 
< 1 || sz
.y 
< 1) 
2339     if (!m_bufferBitmap
.Ok() || m_bufferBitmap
.GetWidth() < sz
.x 
|| m_bufferBitmap
.GetHeight() < sz
.y
) 
2340         m_bufferBitmap 
= wxBitmap(sz
.x
, sz
.y
); 
2341     return m_bufferBitmap
.Ok(); 
2345 // ---------------------------------------------------------------------------- 
2346 // file IO functions 
2347 // ---------------------------------------------------------------------------- 
2349 bool wxRichTextCtrl::DoLoadFile(const wxString
& filename
, int fileType
) 
2351     bool success 
= GetBuffer().LoadFile(filename
, (wxRichTextFileType
)fileType
); 
2353         m_filename 
= filename
; 
2356     SetInsertionPoint(0); 
2359     SetupScrollbars(true); 
2361     wxTextCtrl::SendTextUpdatedEvent(this); 
2367         wxLogError(_("File couldn't be loaded.")); 
2373 bool wxRichTextCtrl::DoSaveFile(const wxString
& filename
, int fileType
) 
2375     if (GetBuffer().SaveFile(filename
, (wxRichTextFileType
)fileType
)) 
2377         m_filename 
= filename
; 
2384     wxLogError(_("The text couldn't be saved.")); 
2389 // ---------------------------------------------------------------------------- 
2390 // wxRichTextCtrl specific functionality 
2391 // ---------------------------------------------------------------------------- 
2393 /// Add a new paragraph of text to the end of the buffer 
2394 wxRichTextRange 
wxRichTextCtrl::AddParagraph(const wxString
& text
) 
2396     wxRichTextRange range 
= GetFocusObject()->AddParagraph(text
); 
2397     GetBuffer().Invalidate(); 
2403 wxRichTextRange 
wxRichTextCtrl::AddImage(const wxImage
& image
) 
2405     wxRichTextRange range 
= GetFocusObject()->AddImage(image
); 
2406     GetBuffer().Invalidate(); 
2411 // ---------------------------------------------------------------------------- 
2412 // selection and ranges 
2413 // ---------------------------------------------------------------------------- 
2415 void wxRichTextCtrl::SelectAll() 
2417     SetSelection(-1, -1); 
2421 void wxRichTextCtrl::SelectNone() 
2423     if (m_selection
.IsValid()) 
2425         wxRichTextSelection oldSelection 
= m_selection
; 
2427         m_selection
.Reset(); 
2429         RefreshForSelectionChange(oldSelection
, m_selection
); 
2431     m_selectionAnchor 
= -2; 
2432     m_selectionAnchorObject 
= NULL
; 
2433     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
2436 static bool wxIsWordDelimiter(const wxString
& text
) 
2438     return !text
.IsEmpty() && !wxIsalnum(text
[0]); 
2441 /// Select the word at the given character position 
2442 bool wxRichTextCtrl::SelectWord(long position
) 
2444     if (position 
< 0 || position 
> GetFocusObject()->GetOwnRange().GetEnd()) 
2447     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(position
); 
2451     if (position 
== para
->GetRange().GetEnd()) 
2454     long positionStart 
= position
; 
2455     long positionEnd 
= position
; 
2457     for (positionStart 
= position
; positionStart 
>= para
->GetRange().GetStart(); positionStart 
--) 
2459         wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(positionStart
, positionStart
)); 
2460         if (wxIsWordDelimiter(text
)) 
2466     if (positionStart 
< para
->GetRange().GetStart()) 
2467         positionStart 
= para
->GetRange().GetStart(); 
2469     for (positionEnd 
= position
; positionEnd 
< para
->GetRange().GetEnd(); positionEnd 
++) 
2471         wxString text 
= GetFocusObject()->GetTextForRange(wxRichTextRange(positionEnd
, positionEnd
)); 
2472         if (wxIsWordDelimiter(text
)) 
2478     if (positionEnd 
>= para
->GetRange().GetEnd()) 
2479         positionEnd 
= para
->GetRange().GetEnd(); 
2481     if (positionEnd 
< positionStart
) 
2484     SetSelection(positionStart
, positionEnd
+1); 
2486     if (positionStart 
>= 0) 
2488         MoveCaret(positionStart
-1, true); 
2489         SetDefaultStyleToCursorStyle(); 
2495 wxString 
wxRichTextCtrl::GetStringSelection() const 
2498     GetSelection(&from
, &to
); 
2500     return GetRange(from
, to
); 
2503 // ---------------------------------------------------------------------------- 
2505 // ---------------------------------------------------------------------------- 
2507 wxTextCtrlHitTestResult
 
2508 wxRichTextCtrl::HitTest(const wxPoint
& pt
, wxTextCoord 
*x
, wxTextCoord 
*y
) const 
2510     // implement in terms of the other overload as the native ports typically 
2511     // can get the position and not (x, y) pair directly (although wxUniv 
2512     // directly gets x and y -- and so overrides this method as well) 
2514     wxTextCtrlHitTestResult rc 
= HitTest(pt
, &pos
); 
2516     if ( rc 
!= wxTE_HT_UNKNOWN 
) 
2518         PositionToXY(pos
, x
, y
); 
2524 wxTextCtrlHitTestResult
 
2525 wxRichTextCtrl::HitTest(const wxPoint
& pt
, 
2528     wxClientDC 
dc((wxRichTextCtrl
*) this); 
2529     ((wxRichTextCtrl
*)this)->PrepareDC(dc
); 
2531     // Buffer uses logical position (relative to start of buffer) 
2533     wxPoint pt2 
= GetLogicalPoint(pt
); 
2535     wxRichTextObject
* hitObj 
= NULL
; 
2536     wxRichTextObject
* contextObj 
= NULL
; 
2537     int hit 
= ((wxRichTextCtrl
*)this)->GetFocusObject()->HitTest(dc
, pt2
, *pos
, & hitObj
, & contextObj
, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
); 
2539     if ((hit 
& wxRICHTEXT_HITTEST_BEFORE
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2540         return wxTE_HT_BEFORE
; 
2541     else if ((hit 
& wxRICHTEXT_HITTEST_AFTER
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2542         return wxTE_HT_BEYOND
; 
2543     else if (hit 
& (wxRICHTEXT_HITTEST_BEFORE
|wxRICHTEXT_HITTEST_AFTER
)) 
2544         return wxTE_HT_ON_TEXT
; 
2546     return wxTE_HT_UNKNOWN
; 
2549 // ---------------------------------------------------------------------------- 
2550 // set/get the controls text 
2551 // ---------------------------------------------------------------------------- 
2553 wxString 
wxRichTextCtrl::DoGetValue() const 
2555     return GetBuffer().GetText(); 
2558 wxString 
wxRichTextCtrl::GetRange(long from
, long to
) const 
2560     // Public API for range is different from internals 
2561     return GetFocusObject()->GetTextForRange(wxRichTextRange(from
, to
-1)); 
2564 void wxRichTextCtrl::DoSetValue(const wxString
& value
, int flags
) 
2566     // Don't call Clear here, since it always sends a text updated event 
2567     m_buffer
.ResetAndClearCommands(); 
2568     m_buffer
.Invalidate(wxRICHTEXT_ALL
); 
2569     m_caretPosition 
= -1; 
2570     m_caretPositionForDefaultStyle 
= -2; 
2571     m_caretAtLineStart 
= false; 
2572     m_selection
.Reset(); 
2573     m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
2583     if (!value
.IsEmpty()) 
2585         // Remove empty paragraph 
2586         GetBuffer().Clear(); 
2587         DoWriteText(value
, flags
); 
2589         // for compatibility, don't move the cursor when doing SetValue() 
2590         SetInsertionPoint(0); 
2594         // still send an event for consistency 
2595         if (flags 
& SetValue_SendEvent
) 
2596             wxTextCtrl::SendTextUpdatedEvent(this); 
2601 void wxRichTextCtrl::WriteText(const wxString
& value
) 
2606 void wxRichTextCtrl::DoWriteText(const wxString
& value
, int flags
) 
2608     wxString valueUnix 
= wxTextFile::Translate(value
, wxTextFileType_Unix
); 
2610     GetFocusObject()->InsertTextWithUndo(m_caretPosition
+1, valueUnix
, this, & GetBuffer(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2612     if ( flags 
& SetValue_SendEvent 
) 
2613         wxTextCtrl::SendTextUpdatedEvent(this); 
2616 void wxRichTextCtrl::AppendText(const wxString
& text
) 
2618     SetInsertionPointEnd(); 
2623 /// Write an image at the current insertion point 
2624 bool wxRichTextCtrl::WriteImage(const wxImage
& image
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2626     wxRichTextImageBlock imageBlock
; 
2628     wxImage image2 
= image
; 
2629     if (imageBlock
.MakeImageBlock(image2
, bitmapType
)) 
2630         return WriteImage(imageBlock
, textAttr
); 
2635 bool wxRichTextCtrl::WriteImage(const wxString
& filename
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2637     wxRichTextImageBlock imageBlock
; 
2640     if (imageBlock
.MakeImageBlock(filename
, bitmapType
, image
, false)) 
2641         return WriteImage(imageBlock
, textAttr
); 
2646 bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock
& imageBlock
, const wxRichTextAttr
& textAttr
) 
2648     return GetFocusObject()->InsertImageWithUndo(m_caretPosition
+1, imageBlock
, this, & GetBuffer(), 0, textAttr
); 
2651 bool wxRichTextCtrl::WriteImage(const wxBitmap
& bitmap
, wxBitmapType bitmapType
, const wxRichTextAttr
& textAttr
) 
2655         wxRichTextImageBlock imageBlock
; 
2657         wxImage image 
= bitmap
.ConvertToImage(); 
2658         if (image
.Ok() && imageBlock
.MakeImageBlock(image
, bitmapType
)) 
2659             return WriteImage(imageBlock
, textAttr
); 
2665 // Write a text box at the current insertion point. 
2666 wxRichTextBox
* wxRichTextCtrl::WriteTextBox(const wxRichTextAttr
& textAttr
) 
2668     wxRichTextBox
* textBox 
= new wxRichTextBox
; 
2669     textBox
->SetAttributes(textAttr
); 
2670     textBox
->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style 
2671     textBox
->AddParagraph(wxEmptyString
); 
2672     textBox
->SetParent(NULL
); 
2674     // The object returned is the one actually inserted into the buffer, 
2675     // while the original one is deleted. 
2676     wxRichTextObject
* obj 
= GetFocusObject()->InsertObjectWithUndo(m_caretPosition
+1, textBox
, this, & GetBuffer(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2677     wxRichTextBox
* box 
= wxDynamicCast(obj
, wxRichTextBox
); 
2681 // Write a table at the current insertion point, returning the table. 
2682 wxRichTextTable
* wxRichTextCtrl::WriteTable(int rows
, int cols
, const wxRichTextAttr
& tableAttr
, const wxRichTextAttr
& cellAttr
) 
2684     wxASSERT(rows 
> 0 && cols 
> 0); 
2686     if (rows 
<= 0 || cols 
<= 0) 
2689     wxRichTextTable
* table 
= new wxRichTextTable
; 
2690     table
->SetAttributes(tableAttr
); 
2691     table
->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style 
2693     table
->CreateTable(rows
, cols
); 
2695     table
->SetParent(NULL
); 
2698     for (j 
= 0; j 
< rows
; j
++) 
2700         for (i 
= 0; i 
< cols
; i
++) 
2702             table
->GetCell(j
, i
)->GetAttributes() = cellAttr
; 
2706     // The object returned is the one actually inserted into the buffer, 
2707     // while the original one is deleted. 
2708     wxRichTextObject
* obj 
= GetFocusObject()->InsertObjectWithUndo(m_caretPosition
+1, table
, this, & GetBuffer(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2709     wxRichTextTable
* tableResult 
= wxDynamicCast(obj
, wxRichTextTable
); 
2714 /// Insert a newline (actually paragraph) at the current insertion point. 
2715 bool wxRichTextCtrl::Newline() 
2717     return GetFocusObject()->InsertNewlineWithUndo(m_caretPosition
+1, this, & GetBuffer(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2720 /// Insert a line break at the current insertion point. 
2721 bool wxRichTextCtrl::LineBreak() 
2724     text 
= wxRichTextLineBreakChar
; 
2725     return GetFocusObject()->InsertTextWithUndo(m_caretPosition
+1, text
, this, & GetBuffer()); 
2728 // ---------------------------------------------------------------------------- 
2729 // Clipboard operations 
2730 // ---------------------------------------------------------------------------- 
2732 void wxRichTextCtrl::Copy() 
2736         wxRichTextRange range 
= GetInternalSelectionRange(); 
2737         GetBuffer().CopyToClipboard(range
); 
2741 void wxRichTextCtrl::Cut() 
2745         wxRichTextRange range 
= GetInternalSelectionRange(); 
2746         GetBuffer().CopyToClipboard(range
); 
2748         DeleteSelectedContent(); 
2754 void wxRichTextCtrl::Paste() 
2758         BeginBatchUndo(_("Paste")); 
2760         long newPos 
= m_caretPosition
; 
2761         DeleteSelectedContent(& newPos
); 
2763         GetBuffer().PasteFromClipboard(newPos
); 
2769 void wxRichTextCtrl::DeleteSelection() 
2771     if (CanDeleteSelection()) 
2773         DeleteSelectedContent(); 
2777 bool wxRichTextCtrl::HasSelection() const 
2779     return (m_selection
.IsValid() && m_selection
.GetContainer() == GetFocusObject()); 
2782 bool wxRichTextCtrl::HasUnfocusedSelection() const 
2784     return m_selection
.IsValid(); 
2787 bool wxRichTextCtrl::CanCopy() const 
2789     // Can copy if there's a selection 
2790     return HasSelection(); 
2793 bool wxRichTextCtrl::CanCut() const 
2795     return HasSelection() && IsEditable(); 
2798 bool wxRichTextCtrl::CanPaste() const 
2800     if ( !IsEditable() ) 
2803     return GetBuffer().CanPasteFromClipboard(); 
2806 bool wxRichTextCtrl::CanDeleteSelection() const 
2808     return HasSelection() && IsEditable(); 
2812 // ---------------------------------------------------------------------------- 
2814 // ---------------------------------------------------------------------------- 
2816 void wxRichTextCtrl::SetContextMenu(wxMenu
* menu
) 
2818     if (m_contextMenu 
&& m_contextMenu 
!= menu
) 
2819         delete m_contextMenu
; 
2820     m_contextMenu 
= menu
; 
2823 void wxRichTextCtrl::SetEditable(bool editable
) 
2825     m_editable 
= editable
; 
2828 void wxRichTextCtrl::SetInsertionPoint(long pos
) 
2832     m_caretPosition 
= pos 
- 1; 
2836     SetDefaultStyleToCursorStyle(); 
2839 void wxRichTextCtrl::SetInsertionPointEnd() 
2841     long pos 
= GetLastPosition(); 
2842     SetInsertionPoint(pos
); 
2845 long wxRichTextCtrl::GetInsertionPoint() const 
2847     return m_caretPosition
+1; 
2850 wxTextPos 
wxRichTextCtrl::GetLastPosition() const 
2852     return GetFocusObject()->GetOwnRange().GetEnd(); 
2855 // If the return values from and to are the same, there is no 
2857 void wxRichTextCtrl::GetSelection(long* from
, long* to
) const 
2859     if (m_selection
.IsValid()) 
2861         *from 
= m_selection
.GetRange().GetStart(); 
2862         *to 
= m_selection
.GetRange().GetEnd(); 
2872 bool wxRichTextCtrl::IsEditable() const 
2877 // ---------------------------------------------------------------------------- 
2879 // ---------------------------------------------------------------------------- 
2881 void wxRichTextCtrl::SetSelection(long from
, long to
) 
2883     // if from and to are both -1, it means (in wxWidgets) that all text should 
2885     if ( (from 
== -1) && (to 
== -1) ) 
2888         to 
= GetLastPosition()+1; 
2897         wxRichTextSelection oldSelection 
= m_selection
; 
2899         m_selectionAnchor 
= from
-1; 
2900         m_selectionAnchorObject 
= NULL
; 
2901         m_selection
.Set(wxRichTextRange(from
, to
-1), GetFocusObject()); 
2903         m_caretPosition 
= wxMax(-1, to
-1); 
2905         RefreshForSelectionChange(oldSelection
, m_selection
); 
2910 // ---------------------------------------------------------------------------- 
2912 // ---------------------------------------------------------------------------- 
2914 void wxRichTextCtrl::Replace(long WXUNUSED(from
), long WXUNUSED(to
), 
2915                              const wxString
& value
) 
2917     BeginBatchUndo(_("Replace")); 
2919     DeleteSelectedContent(); 
2921     DoWriteText(value
, SetValue_SelectionOnly
); 
2926 void wxRichTextCtrl::Remove(long from
, long to
) 
2930     GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(from
, to
-1), this, & GetBuffer()); 
2937 bool wxRichTextCtrl::IsModified() const 
2939     return m_buffer
.IsModified(); 
2942 void wxRichTextCtrl::MarkDirty() 
2944     m_buffer
.Modify(true); 
2947 void wxRichTextCtrl::DiscardEdits() 
2949     m_caretPositionForDefaultStyle 
= -2; 
2950     m_buffer
.Modify(false); 
2951     m_buffer
.GetCommandProcessor()->ClearCommands(); 
2954 int wxRichTextCtrl::GetNumberOfLines() const 
2956     return GetFocusObject()->GetParagraphCount(); 
2959 // ---------------------------------------------------------------------------- 
2960 // Positions <-> coords 
2961 // ---------------------------------------------------------------------------- 
2963 long wxRichTextCtrl::XYToPosition(long x
, long y
) const 
2965     return GetFocusObject()->XYToPosition(x
, y
); 
2968 bool wxRichTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
2970     return GetFocusObject()->PositionToXY(pos
, x
, y
); 
2973 // ---------------------------------------------------------------------------- 
2975 // ---------------------------------------------------------------------------- 
2977 void wxRichTextCtrl::ShowPosition(long pos
) 
2979     if (!IsPositionVisible(pos
)) 
2980         ScrollIntoView(pos
-1, WXK_DOWN
); 
2983 int wxRichTextCtrl::GetLineLength(long lineNo
) const 
2985     return GetFocusObject()->GetParagraphLength(lineNo
); 
2988 wxString 
wxRichTextCtrl::GetLineText(long lineNo
) const 
2990     return GetFocusObject()->GetParagraphText(lineNo
); 
2993 // ---------------------------------------------------------------------------- 
2995 // ---------------------------------------------------------------------------- 
2997 void wxRichTextCtrl::Undo() 
3001         GetCommandProcessor()->Undo(); 
3005 void wxRichTextCtrl::Redo() 
3009         GetCommandProcessor()->Redo(); 
3013 bool wxRichTextCtrl::CanUndo() const 
3015     return GetCommandProcessor()->CanUndo() && IsEditable(); 
3018 bool wxRichTextCtrl::CanRedo() const 
3020     return GetCommandProcessor()->CanRedo() && IsEditable(); 
3023 // ---------------------------------------------------------------------------- 
3024 // implementation details 
3025 // ---------------------------------------------------------------------------- 
3027 void wxRichTextCtrl::Command(wxCommandEvent
& event
) 
3029     SetValue(event
.GetString()); 
3030     GetEventHandler()->ProcessEvent(event
); 
3033 void wxRichTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
3035     // By default, load the first file into the text window. 
3036     if (event
.GetNumberOfFiles() > 0) 
3038         LoadFile(event
.GetFiles()[0]); 
3042 wxSize 
wxRichTextCtrl::DoGetBestSize() const 
3044     return wxSize(10, 10); 
3047 // ---------------------------------------------------------------------------- 
3048 // standard handlers for standard edit menu events 
3049 // ---------------------------------------------------------------------------- 
3051 void wxRichTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
3056 void wxRichTextCtrl::OnClear(wxCommandEvent
& WXUNUSED(event
)) 
3061 void wxRichTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
3066 void wxRichTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
3071 void wxRichTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
3076 void wxRichTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
3081 void wxRichTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
3083     event
.Enable( CanCut() ); 
3086 void wxRichTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
3088     event
.Enable( CanCopy() ); 
3091 void wxRichTextCtrl::OnUpdateClear(wxUpdateUIEvent
& event
) 
3093     event
.Enable( CanDeleteSelection() ); 
3096 void wxRichTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
3098     event
.Enable( CanPaste() ); 
3101 void wxRichTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
3103     event
.Enable( CanUndo() ); 
3104     event
.SetText( GetCommandProcessor()->GetUndoMenuLabel() ); 
3107 void wxRichTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
3109     event
.Enable( CanRedo() ); 
3110     event
.SetText( GetCommandProcessor()->GetRedoMenuLabel() ); 
3113 void wxRichTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
3115     if (GetLastPosition() > 0) 
3119 void wxRichTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
3121     event
.Enable(GetLastPosition() > 0); 
3124 void wxRichTextCtrl::OnProperties(wxCommandEvent
& event
) 
3126     int idx 
= event
.GetId() - wxID_RICHTEXT_PROPERTIES1
; 
3127     if (idx 
>= 0 && idx 
< m_contextMenuPropertiesInfo
.GetCount()) 
3129         wxRichTextObject
* obj 
= m_contextMenuPropertiesInfo
.GetObject(idx
); 
3130         if (obj 
&& obj
->CanEditProperties()) 
3131             obj
->EditProperties(this, & GetBuffer()); 
3133         m_contextMenuPropertiesInfo
.Clear(); 
3137 void wxRichTextCtrl::OnUpdateProperties(wxUpdateUIEvent
& event
) 
3139     int idx 
= event
.GetId() - wxID_RICHTEXT_PROPERTIES1
; 
3140     event
.Enable(idx 
>= 0 && idx 
< m_contextMenuPropertiesInfo
.GetCount()); 
3143 void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent
& event
) 
3145     if (event
.GetEventObject() != this) 
3151     wxClientDC 
dc(this); 
3153     dc
.SetFont(GetFont()); 
3156     wxPoint pt 
= event
.GetPosition(); 
3157     wxPoint logicalPt 
= GetLogicalPoint(ScreenToClient(pt
)); 
3158     wxRichTextObject
* hitObj 
= NULL
; 
3159     wxRichTextObject
* contextObj 
= NULL
; 
3160     int hit 
= GetFocusObject()->HitTest(dc
, logicalPt
, position
, & hitObj
, & contextObj
); 
3162     m_contextMenuPropertiesInfo
.Clear(); 
3164     if (hit 
== wxRICHTEXT_HITTEST_ON 
|| hit 
== wxRICHTEXT_HITTEST_BEFORE 
|| hit 
== wxRICHTEXT_HITTEST_AFTER
) 
3166         wxRichTextParagraphLayoutBox
* actualContainer 
= wxDynamicCast(contextObj
, wxRichTextParagraphLayoutBox
); 
3167         if (hitObj 
&& actualContainer
) 
3169             if (actualContainer
->AcceptsFocus()) 
3171                 SetFocusObject(actualContainer
, false /* don't set caret position yet */); 
3172                 SetCaretPositionAfterClick(actualContainer
, position
, hit
); 
3175             m_contextMenuPropertiesInfo
.AddItems(actualContainer
, hitObj
); 
3178             m_contextMenuPropertiesInfo
.AddItems(GetFocusObject(), NULL
); 
3182         m_contextMenuPropertiesInfo
.AddItems(GetFocusObject(), NULL
); 
3187         m_contextMenuPropertiesInfo
.AddMenuItems(m_contextMenu
); 
3188         PopupMenu(m_contextMenu
); 
3192 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
3194     return GetFocusObject()->SetStyle(wxRichTextRange(start
, end
-1), wxRichTextAttr(style
)); 
3197 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxRichTextAttr
& style
) 
3199     return GetFocusObject()->SetStyle(wxRichTextRange(start
, end
-1), style
); 
3202 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxTextAttr
& style
) 
3204     return GetFocusObject()->SetStyle(range
.ToInternal(), wxRichTextAttr(style
)); 
3207 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxRichTextAttr
& style
) 
3209     return GetFocusObject()->SetStyle(range
.ToInternal(), style
); 
3212 void wxRichTextCtrl::SetStyle(wxRichTextObject 
*obj
, const wxRichTextAttr
& textAttr
) 
3214     GetFocusObject()->SetStyle(obj
, textAttr
); 
3217 // extended style setting operation with flags including: 
3218 // wxRICHTEXT_SETSTYLE_WITH_UNDO, wxRICHTEXT_SETSTYLE_OPTIMIZE, wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY. 
3219 // see richtextbuffer.h for more details. 
3221 bool wxRichTextCtrl::SetStyleEx(const wxRichTextRange
& range
, const wxRichTextAttr
& style
, int flags
) 
3223     return GetFocusObject()->SetStyle(range
.ToInternal(), style
, flags
); 
3226 bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
3228     return GetBuffer().SetDefaultStyle(style
); 
3231 bool wxRichTextCtrl::SetDefaultStyle(const wxRichTextAttr
& style
) 
3233     wxRichTextAttr 
attr1(style
); 
3234     attr1
.GetTextBoxAttr().Reset(); 
3235     return GetBuffer().SetDefaultStyle(attr1
); 
3238 const wxRichTextAttr
& wxRichTextCtrl::GetDefaultStyleEx() const 
3240     return GetBuffer().GetDefaultStyle(); 
3243 bool wxRichTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
3245     wxRichTextAttr attr
; 
3246     if (GetFocusObject()->GetStyle(position
, attr
)) 
3255 bool wxRichTextCtrl::GetStyle(long position
, wxRichTextAttr
& style
) 
3257     return GetFocusObject()->GetStyle(position
, style
); 
3260 bool wxRichTextCtrl::GetStyle(long position
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3262     wxRichTextAttr attr
; 
3263     if (container
->GetStyle(position
, attr
)) 
3272 // get the common set of styles for the range 
3273 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxTextAttr
& style
) 
3275     wxRichTextAttr attr
; 
3276     if (GetFocusObject()->GetStyleForRange(range
.ToInternal(), attr
)) 
3285 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxRichTextAttr
& style
) 
3287     return GetFocusObject()->GetStyleForRange(range
.ToInternal(), style
); 
3290 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3292     return container
->GetStyleForRange(range
.ToInternal(), style
); 
3295 /// Get the content (uncombined) attributes for this position. 
3296 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxRichTextAttr
& style
) 
3298     return GetFocusObject()->GetUncombinedStyle(position
, style
); 
3301 /// Get the content (uncombined) attributes for this position. 
3302 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxRichTextAttr
& style
, wxRichTextParagraphLayoutBox
* container
) 
3304     return container
->GetUncombinedStyle(position
, style
); 
3307 /// Set font, and also the buffer attributes 
3308 bool wxRichTextCtrl::SetFont(const wxFont
& font
) 
3310     wxControl::SetFont(font
); 
3312     wxRichTextAttr attr 
= GetBuffer().GetAttributes(); 
3314     GetBuffer().SetBasicStyle(attr
); 
3316     GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
3322 /// Transform logical to physical 
3323 wxPoint 
wxRichTextCtrl::GetPhysicalPoint(const wxPoint
& ptLogical
) const 
3326     CalcScrolledPosition(ptLogical
.x
, ptLogical
.y
, & pt
.x
, & pt
.y
); 
3331 /// Transform physical to logical 
3332 wxPoint 
wxRichTextCtrl::GetLogicalPoint(const wxPoint
& ptPhysical
) const 
3335     CalcUnscrolledPosition(ptPhysical
.x
, ptPhysical
.y
, & pt
.x
, & pt
.y
); 
3340 /// Position the caret 
3341 void wxRichTextCtrl::PositionCaret(wxRichTextParagraphLayoutBox
* container
) 
3346     //wxLogDebug(wxT("PositionCaret")); 
3349     if (GetCaretPositionForIndex(GetCaretPosition(), caretRect
, container
)) 
3351         wxPoint newPt 
= caretRect
.GetPosition(); 
3352         wxSize newSz 
= caretRect
.GetSize(); 
3353         wxPoint pt 
= GetPhysicalPoint(newPt
); 
3354         if (GetCaret()->GetPosition() != pt 
|| GetCaret()->GetSize() != newSz
) 
3357             if (GetCaret()->GetSize() != newSz
) 
3358                 GetCaret()->SetSize(newSz
); 
3360             int halfSize 
= newSz
.y
/2; 
3361             // If the caret is beyond the margin, hide it by moving it out of the way 
3362             if (((pt
.y 
+ halfSize
) < GetBuffer().GetTopMargin()) || ((pt
.y 
+ halfSize
) > (GetClientSize().y 
- GetBuffer().GetBottomMargin()))) 
3368             GetCaret()->Move(pt
); 
3374 /// Get the caret height and position for the given character position 
3375 bool wxRichTextCtrl::GetCaretPositionForIndex(long position
, wxRect
& rect
, wxRichTextParagraphLayoutBox
* container
) 
3377     wxClientDC 
dc(this); 
3378     dc
.SetFont(GetFont()); 
3386         container 
= GetFocusObject(); 
3388     if (container
->FindPosition(dc
, position
, pt
, & height
, m_caretAtLineStart
)) 
3390         // Caret height can't be zero 
3392             height 
= dc
.GetCharHeight(); 
3394         rect 
= wxRect(pt
, wxSize(wxRICHTEXT_DEFAULT_CARET_WIDTH
, height
)); 
3401 /// Gets the line for the visible caret position. If the caret is 
3402 /// shown at the very end of the line, it means the next character is actually 
3403 /// on the following line. So let's get the line we're expecting to find 
3404 /// if this is the case. 
3405 wxRichTextLine
* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPosition
) const 
3407     wxRichTextLine
* line 
= GetFocusObject()->GetLineAtPosition(caretPosition
, true); 
3408     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(caretPosition
, true); 
3411         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
3412         if (caretPosition 
== lineRange
.GetStart()-1 && 
3413             (para
->GetRange().GetStart() != lineRange
.GetStart())) 
3415             if (!m_caretAtLineStart
) 
3416                 line 
= GetFocusObject()->GetLineAtPosition(caretPosition
-1, true); 
3423 /// Move the caret to the given character position 
3424 bool wxRichTextCtrl::MoveCaret(long pos
, bool showAtLineStart
, wxRichTextParagraphLayoutBox
* container
) 
3426     if (GetBuffer().IsDirty()) 
3430         container 
= GetFocusObject(); 
3432     if (pos 
<= container
->GetOwnRange().GetEnd()) 
3434         SetCaretPosition(pos
, showAtLineStart
); 
3436         PositionCaret(container
); 
3444 /// Layout the buffer: which we must do before certain operations, such as 
3445 /// setting the caret position. 
3446 bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect
) 
3448     if (GetBuffer().IsDirty() || onlyVisibleRect
) 
3450         wxRect 
availableSpace(GetClientSize()); 
3451         if (availableSpace
.width 
== 0) 
3452             availableSpace
.width 
= 10; 
3453         if (availableSpace
.height 
== 0) 
3454             availableSpace
.height 
= 10; 
3456         int flags 
= wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
; 
3457         if (onlyVisibleRect
) 
3459             flags 
|= wxRICHTEXT_LAYOUT_SPECIFIED_RECT
; 
3460             availableSpace
.SetPosition(GetLogicalPoint(wxPoint(0, 0))); 
3463         wxClientDC 
dc(this); 
3464         dc
.SetFont(GetFont()); 
3468         GetBuffer().Defragment(); 
3469         GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation 
3470         GetBuffer().Layout(dc
, availableSpace
, flags
); 
3471         GetBuffer().Invalidate(wxRICHTEXT_NONE
); 
3480 /// Is all of the selection bold? 
3481 bool wxRichTextCtrl::IsSelectionBold() 
3485         wxRichTextAttr attr
; 
3486         wxRichTextRange range 
= GetSelectionRange(); 
3487         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3488         attr
.SetFontWeight(wxFONTWEIGHT_BOLD
); 
3490         return HasCharacterAttributes(range
, attr
); 
3494         // If no selection, then we need to combine current style with default style 
3495         // to see what the effect would be if we started typing. 
3496         wxRichTextAttr attr
; 
3497         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3499         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3500         if (GetStyle(pos
, attr
)) 
3502             if (IsDefaultStyleShowing()) 
3503                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3504             return attr
.GetFontWeight() == wxFONTWEIGHT_BOLD
; 
3510 /// Is all of the selection italics? 
3511 bool wxRichTextCtrl::IsSelectionItalics() 
3515         wxRichTextRange range 
= GetSelectionRange(); 
3516         wxRichTextAttr attr
; 
3517         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3518         attr
.SetFontStyle(wxFONTSTYLE_ITALIC
); 
3520         return HasCharacterAttributes(range
, attr
); 
3524         // If no selection, then we need to combine current style with default style 
3525         // to see what the effect would be if we started typing. 
3526         wxRichTextAttr attr
; 
3527         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3529         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3530         if (GetStyle(pos
, attr
)) 
3532             if (IsDefaultStyleShowing()) 
3533                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3534             return attr
.GetFontStyle() == wxFONTSTYLE_ITALIC
; 
3540 /// Is all of the selection underlined? 
3541 bool wxRichTextCtrl::IsSelectionUnderlined() 
3545         wxRichTextRange range 
= GetSelectionRange(); 
3546         wxRichTextAttr attr
; 
3547         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3548         attr
.SetFontUnderlined(true); 
3550         return HasCharacterAttributes(range
, attr
); 
3554         // If no selection, then we need to combine current style with default style 
3555         // to see what the effect would be if we started typing. 
3556         wxRichTextAttr attr
; 
3557         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3558         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3560         if (GetStyle(pos
, attr
)) 
3562             if (IsDefaultStyleShowing()) 
3563                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3564             return attr
.GetFontUnderlined(); 
3570 /// Apply bold to the selection 
3571 bool wxRichTextCtrl::ApplyBoldToSelection() 
3573     wxRichTextAttr attr
; 
3574     attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3575     attr
.SetFontWeight(IsSelectionBold() ? wxFONTWEIGHT_NORMAL 
: wxFONTWEIGHT_BOLD
); 
3578         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
3581         wxRichTextAttr current 
= GetDefaultStyleEx(); 
3582         current
.Apply(attr
); 
3583         SetAndShowDefaultStyle(current
); 
3588 /// Apply italic to the selection 
3589 bool wxRichTextCtrl::ApplyItalicToSelection() 
3591     wxRichTextAttr attr
; 
3592     attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3593     attr
.SetFontStyle(IsSelectionItalics() ? wxFONTSTYLE_NORMAL 
: wxFONTSTYLE_ITALIC
); 
3596         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
3599         wxRichTextAttr current 
= GetDefaultStyleEx(); 
3600         current
.Apply(attr
); 
3601         SetAndShowDefaultStyle(current
); 
3606 /// Apply underline to the selection 
3607 bool wxRichTextCtrl::ApplyUnderlineToSelection() 
3609     wxRichTextAttr attr
; 
3610     attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3611     attr
.SetFontUnderlined(!IsSelectionUnderlined()); 
3614         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
3617         wxRichTextAttr current 
= GetDefaultStyleEx(); 
3618         current
.Apply(attr
); 
3619         SetAndShowDefaultStyle(current
); 
3624 /// Is all of the selection aligned according to the specified flag? 
3625 bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment
) 
3627     wxRichTextRange range
; 
3629         range 
= GetSelectionRange(); 
3631         range 
= wxRichTextRange(GetCaretPosition()+1, GetCaretPosition()+2); 
3633     wxRichTextAttr attr
; 
3634     attr
.SetAlignment(alignment
); 
3636     return HasParagraphAttributes(range
, attr
); 
3639 /// Apply alignment to the selection 
3640 bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment
) 
3642     wxRichTextAttr attr
; 
3643     attr
.SetAlignment(alignment
); 
3645         return SetStyle(GetSelectionRange(), attr
); 
3648         wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(GetCaretPosition()+1); 
3650             return SetStyleEx(para
->GetRange().FromInternal(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
); 
3655 /// Apply a named style to the selection 
3656 bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition
* def
) 
3658     // Flags are defined within each definition, so only certain 
3659     // attributes are applied. 
3660     wxRichTextAttr 
attr(GetStyleSheet() ? def
->GetStyleMergedWithBase(GetStyleSheet()) : def
->GetStyle()); 
3662     int flags 
= wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_RESET
; 
3664     if (def
->IsKindOf(CLASSINFO(wxRichTextListStyleDefinition
))) 
3666         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
3668         wxRichTextRange range
; 
3671             range 
= GetSelectionRange(); 
3674             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3675             range 
= wxRichTextRange(pos
, pos
+1); 
3678         return SetListStyle(range
, (wxRichTextListStyleDefinition
*) def
, flags
); 
3681     bool isPara 
= false; 
3683     // Make sure the attr has the style name 
3684     if (def
->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition
))) 
3687         attr
.SetParagraphStyleName(def
->GetName()); 
3689         // If applying a paragraph style, we only want the paragraph nodes to adopt these 
3690         // attributes, and not the leaf nodes. This will allow the content (e.g. text) 
3691         // to change its style independently. 
3692         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
3695         attr
.SetCharacterStyleName(def
->GetName()); 
3698         return SetStyleEx(GetSelectionRange(), attr
, flags
); 
3701         wxRichTextAttr current 
= GetDefaultStyleEx(); 
3702         wxRichTextAttr 
defaultStyle(attr
); 
3705             // Don't apply extra character styles since they are already implied 
3706             // in the paragraph style 
3707             defaultStyle
.SetFlags(defaultStyle
.GetFlags() & ~wxTEXT_ATTR_CHARACTER
); 
3709         current
.Apply(defaultStyle
); 
3710         SetAndShowDefaultStyle(current
); 
3712         // If it's a paragraph style, we want to apply the style to the 
3713         // current paragraph even if we didn't select any text. 
3716             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3717             wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(pos
); 
3720                 return SetStyleEx(para
->GetRange().FromInternal(), attr
, flags
); 
3727 /// Apply the style sheet to the buffer, for example if the styles have changed. 
3728 bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet
* styleSheet
) 
3731         styleSheet 
= GetBuffer().GetStyleSheet(); 
3735     if (GetBuffer().ApplyStyleSheet(styleSheet
)) 
3737         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
3745 /// Sets the default style to the style under the cursor 
3746 bool wxRichTextCtrl::SetDefaultStyleToCursorStyle() 
3748     wxRichTextAttr attr
; 
3749     attr
.SetFlags(wxTEXT_ATTR_CHARACTER
); 
3751     // If at the start of a paragraph, use the next position. 
3752     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3754     if (GetUncombinedStyle(pos
, attr
)) 
3756         SetDefaultStyle(attr
); 
3763 /// Returns the first visible position in the current view 
3764 long wxRichTextCtrl::GetFirstVisiblePosition() const 
3766     wxRichTextLine
* line 
= GetFocusObject()->GetLineAtYPosition(GetLogicalPoint(wxPoint(0, 0)).y
); 
3768         return line
->GetAbsoluteRange().GetStart(); 
3773 /// Get the first visible point in the window 
3774 wxPoint 
wxRichTextCtrl::GetFirstVisiblePoint() const 
3777     int startXUnits
, startYUnits
; 
3779     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
3780     GetViewStart(& startXUnits
, & startYUnits
); 
3782     return wxPoint(startXUnits 
* ppuX
, startYUnits 
* ppuY
); 
3785 /// The adjusted caret position is the character position adjusted to take 
3786 /// into account whether we're at the start of a paragraph, in which case 
3787 /// style information should be taken from the next position, not current one. 
3788 long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos
) const 
3790     wxRichTextParagraph
* para 
= GetFocusObject()->GetParagraphAtPosition(caretPos
+1); 
3792     if (para 
&& (caretPos
+1 == para
->GetRange().GetStart())) 
3797 /// Get/set the selection range in character positions. -1, -1 means no selection. 
3798 /// The range is in API convention, i.e. a single character selection is denoted 
3800 wxRichTextRange 
wxRichTextCtrl::GetSelectionRange() const 
3802     wxRichTextRange range 
= GetInternalSelectionRange(); 
3803     if (range 
!= wxRichTextRange(-2,-2) && range 
!= wxRichTextRange(-1,-1)) 
3804         range
.SetEnd(range
.GetEnd() + 1); 
3808 void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange
& range
) 
3810     SetSelection(range
.GetStart(), range
.GetEnd()); 
3814 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3816     return GetFocusObject()->SetListStyle(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
3819 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
3821     return GetFocusObject()->SetListStyle(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
3824 /// Clear list for given range 
3825 bool wxRichTextCtrl::ClearListStyle(const wxRichTextRange
& range
, int flags
) 
3827     return GetFocusObject()->ClearListStyle(range
.ToInternal(), flags
); 
3830 /// Number/renumber any list elements in the given range 
3831 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3833     return GetFocusObject()->NumberList(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
3836 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
3838     return GetFocusObject()->NumberList(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
3841 /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 
3842 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int specifiedLevel
) 
3844     return GetFocusObject()->PromoteList(promoteBy
, range
.ToInternal(), def
, flags
, specifiedLevel
); 
3847 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int specifiedLevel
) 
3849     return GetFocusObject()->PromoteList(promoteBy
, range
.ToInternal(), defName
, flags
, specifiedLevel
); 
3852 /// Deletes the content in the given range 
3853 bool wxRichTextCtrl::Delete(const wxRichTextRange
& range
) 
3855     return GetFocusObject()->DeleteRangeWithUndo(range
.ToInternal(), this, & GetBuffer()); 
3858 const wxArrayString
& wxRichTextCtrl::GetAvailableFontNames() 
3860     if (sm_availableFontNames
.GetCount() == 0) 
3862         sm_availableFontNames 
= wxFontEnumerator::GetFacenames(); 
3863         sm_availableFontNames
.Sort(); 
3865     return sm_availableFontNames
; 
3868 void wxRichTextCtrl::ClearAvailableFontNames() 
3870     sm_availableFontNames
.Clear(); 
3873 void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
)) 
3875     //wxLogDebug(wxT("wxRichTextCtrl::OnSysColourChanged")); 
3877     wxTextAttrEx basicStyle 
= GetBasicStyle(); 
3878     basicStyle
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
3879     SetBasicStyle(basicStyle
); 
3880     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
3885 // Refresh the area affected by a selection change 
3886 bool wxRichTextCtrl::RefreshForSelectionChange(const wxRichTextSelection
& oldSelection
, const wxRichTextSelection
& newSelection
) 
3888     // If the selection is not part of the focus object, or we have multiple ranges, then the chances are that 
3889     // the selection contains whole containers rather than just text, so refresh everything 
3890     // for now as it would be hard to compute the rectangle bounding all selections. 
3891     // TODO: improve on this. 
3892     if ((oldSelection
.IsValid() && (oldSelection
.GetContainer() != GetFocusObject() || oldSelection
.GetCount() > 1)) || 
3893         (newSelection
.IsValid() && (newSelection
.GetContainer() != GetFocusObject() || newSelection
.GetCount() > 1))) 
3899     wxRichTextRange oldRange
, newRange
; 
3900     if (oldSelection
.IsValid()) 
3901         oldRange 
= oldSelection
.GetRange(); 
3903         oldRange 
= wxRICHTEXT_NO_SELECTION
; 
3904     if (newSelection
.IsValid()) 
3905         newRange 
= newSelection
.GetRange(); 
3907         newRange 
= wxRICHTEXT_NO_SELECTION
; 
3909     // Calculate the refresh rectangle - just the affected lines 
3910     long firstPos
, lastPos
; 
3911     if (oldRange
.GetStart() == -2 && newRange
.GetStart() != -2) 
3913         firstPos 
= newRange
.GetStart(); 
3914         lastPos 
= newRange
.GetEnd(); 
3916     else if (oldRange
.GetStart() != -2 && newRange
.GetStart() == -2) 
3918         firstPos 
= oldRange
.GetStart(); 
3919         lastPos 
= oldRange
.GetEnd(); 
3921     else if (oldRange
.GetStart() == -2 && newRange
.GetStart() == -2) 
3927         firstPos 
= wxMin(oldRange
.GetStart(), newRange
.GetStart()); 
3928         lastPos 
= wxMax(oldRange
.GetEnd(), newRange
.GetEnd()); 
3931     wxRichTextLine
* firstLine 
= GetFocusObject()->GetLineAtPosition(firstPos
); 
3932     wxRichTextLine
* lastLine 
= GetFocusObject()->GetLineAtPosition(lastPos
); 
3934     if (firstLine 
&& lastLine
) 
3936         wxSize clientSize 
= GetClientSize(); 
3937         wxPoint pt1 
= GetPhysicalPoint(firstLine
->GetAbsolutePosition()); 
3938         wxPoint pt2 
= GetPhysicalPoint(lastLine
->GetAbsolutePosition()) + wxPoint(0, lastLine
->GetSize().y
); 
3941         pt1
.y 
= wxMax(0, pt1
.y
); 
3943         pt2
.y 
= wxMin(clientSize
.y
, pt2
.y
); 
3945         wxRect 
rect(pt1
, wxSize(clientSize
.x
, pt2
.y 
- pt1
.y
)); 
3946         RefreshRect(rect
, false); 
3954 // margins functions 
3955 bool wxRichTextCtrl::DoSetMargins(const wxPoint
& pt
) 
3957     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().SetValue(pt
.x
, wxTEXT_ATTR_UNITS_PIXELS
); 
3958     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetRight().SetValue(pt
.x
, wxTEXT_ATTR_UNITS_PIXELS
); 
3959     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetTop().SetValue(pt
.y
, wxTEXT_ATTR_UNITS_PIXELS
); 
3960     GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetBottom().SetValue(pt
.y
, wxTEXT_ATTR_UNITS_PIXELS
); 
3965 wxPoint 
wxRichTextCtrl::DoGetMargins() const 
3967     return wxPoint(GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().GetValue(), 
3968                    GetBuffer().GetAttributes().GetTextBoxAttr().GetMargins().GetTop().GetValue()); 
3971 bool wxRichTextCtrl::SetFocusObject(wxRichTextParagraphLayoutBox
* obj
, bool setCaretPosition
) 
3973     if (obj 
&& !obj
->AcceptsFocus()) 
3976     wxRichTextParagraphLayoutBox
* oldContainer 
= GetFocusObject(); 
3977     bool changingContainer 
= (m_focusObject 
!= obj
); 
3979     m_focusObject 
= obj
; 
3982         m_focusObject 
= & m_buffer
; 
3984     if (setCaretPosition 
&& changingContainer
) 
3986         m_selection
.Reset(); 
3987         m_selectionAnchor 
= -2; 
3988         m_selectionAnchorObject 
= NULL
; 
3989         m_selectionState 
= wxRichTextCtrlSelectionState_Normal
; 
3993         m_caretAtLineStart 
= false; 
3994         MoveCaret(pos
, m_caretAtLineStart
); 
3995         SetDefaultStyleToCursorStyle(); 
3997         wxRichTextEvent 
cmdEvent( 
3998             wxEVT_COMMAND_RICHTEXT_FOCUS_OBJECT_CHANGED
, 
4000         cmdEvent
.SetEventObject(this); 
4001         cmdEvent
.SetPosition(m_caretPosition
+1); 
4002         cmdEvent
.SetOldContainer(oldContainer
); 
4003         cmdEvent
.SetContainer(m_focusObject
); 
4005         GetEventHandler()->ProcessEvent(cmdEvent
); 
4010 #if wxRICHTEXT_USE_OWN_CARET 
4012 // ---------------------------------------------------------------------------- 
4013 // initialization and destruction 
4014 // ---------------------------------------------------------------------------- 
4016 void wxRichTextCaret::Init() 
4022     m_richTextCtrl 
= NULL
; 
4023     m_needsUpdate 
= false; 
4027 wxRichTextCaret::~wxRichTextCaret() 
4029     if (m_timer
.IsRunning()) 
4033 // ---------------------------------------------------------------------------- 
4034 // showing/hiding/moving the caret (base class interface) 
4035 // ---------------------------------------------------------------------------- 
4037 void wxRichTextCaret::DoShow() 
4041     if (!m_timer
.IsRunning()) 
4042         m_timer
.Start(GetBlinkTime()); 
4047 void wxRichTextCaret::DoHide() 
4049     if (m_timer
.IsRunning()) 
4055 void wxRichTextCaret::DoMove() 
4061         if (m_xOld 
!= -1 && m_yOld 
!= -1) 
4065                 wxRect 
rect(GetPosition(), GetSize()); 
4066                 m_richTextCtrl
->RefreshRect(rect
, false); 
4075 void wxRichTextCaret::DoSize() 
4077     int countVisible 
= m_countVisible
; 
4078     if (countVisible 
> 0) 
4084     if (countVisible 
> 0) 
4086         m_countVisible 
= countVisible
; 
4091 // ---------------------------------------------------------------------------- 
4092 // handling the focus 
4093 // ---------------------------------------------------------------------------- 
4095 void wxRichTextCaret::OnSetFocus() 
4103 void wxRichTextCaret::OnKillFocus() 
4108 // ---------------------------------------------------------------------------- 
4109 // drawing the caret 
4110 // ---------------------------------------------------------------------------- 
4112 void wxRichTextCaret::Refresh() 
4116         wxRect 
rect(GetPosition(), GetSize()); 
4117         m_richTextCtrl
->RefreshRect(rect
, false); 
4121 void wxRichTextCaret::DoDraw(wxDC 
*dc
) 
4123     dc
->SetPen( *wxBLACK_PEN 
); 
4125     dc
->SetBrush(*(m_hasFocus 
? wxBLACK_BRUSH 
: wxTRANSPARENT_BRUSH
)); 
4126     dc
->SetPen(*wxBLACK_PEN
); 
4128     wxPoint 
pt(m_x
, m_y
); 
4132         pt 
= m_richTextCtrl
->GetLogicalPoint(pt
); 
4134     if (IsVisible() && m_flashOn
) 
4135         dc
->DrawRectangle(pt
.x
, pt
.y
, m_width
, m_height
); 
4138 void wxRichTextCaret::Notify() 
4140     m_flashOn 
= !m_flashOn
; 
4144 void wxRichTextCaretTimer::Notify() 
4149     // wxRICHTEXT_USE_OWN_CARET 
4152 bool wxRichTextContextMenuPropertiesInfo::AddItem(const wxString
& label
, wxRichTextObject
* obj
) 
4156         m_labels
.Add(label
); 
4164 // Returns number of menu items were added. 
4165 int wxRichTextContextMenuPropertiesInfo::AddMenuItems(wxMenu
* menu
, int startCmd
) const 
4167     wxMenuItem
* item 
= menu
->FindItem(startCmd
); 
4168     // If none of the standard properties identifiers are in the menu, assume it's 
4169     // a custom menu without properties commands, and don't add them. 
4172         // If no items, to add just set the text to something generic 
4173         if (GetCount() == 0) 
4175             menu
->SetLabel(startCmd
, _("&Properties")); 
4177             // Delete the others if necessary 
4179             for (i 
= startCmd
+1; i 
< startCmd
+3; i
++) 
4181                 if (menu
->FindItem(i
)) 
4191             // Find the position of the first properties item 
4192             for (i 
= 0; i 
< (int) menu
->GetMenuItemCount(); i
++) 
4194                 wxMenuItem
* item 
= menu
->FindItemByPosition(i
); 
4195                 if (item 
&& item
->GetId() == startCmd
) 
4204                 int insertBefore 
= pos
+1; 
4205                 for (i 
= startCmd
; i 
< startCmd
+GetCount(); i
++) 
4207                     if (menu
->FindItem(i
)) 
4209                         menu
->SetLabel(i
, m_labels
[i 
- startCmd
]); 
4213                         if (insertBefore 
>= (int) menu
->GetMenuItemCount()) 
4214                             menu
->Append(i
, m_labels
[i 
- startCmd
]); 
4216                             menu
->Insert(insertBefore
, i
, m_labels
[i 
- startCmd
]); 
4221                 // Delete any old items still left on the menu 
4222                 for (i 
= startCmd 
+ GetCount(); i 
< startCmd
+3; i
++) 
4224                     if (menu
->FindItem(i
)) 
4236 // Add appropriate menu items for the current container and clicked on object 
4237 // (and container's parent, if appropriate). 
4238 int wxRichTextContextMenuPropertiesInfo::AddItems(wxRichTextObject
* container
, wxRichTextObject
* obj
) 
4241     if (obj 
&& obj
->CanEditProperties()) 
4242         AddItem(obj
->GetPropertiesMenuLabel(), obj
); 
4244     if (container 
&& container 
!= obj 
&& container
->CanEditProperties() && m_labels
.Index(container
->GetPropertiesMenuLabel()) == wxNOT_FOUND
) 
4245         AddItem(container
->GetPropertiesMenuLabel(), container
); 
4247     if (container 
&& container
->GetParent() && container
->GetParent()->CanEditProperties() && m_labels
.Index(container
->GetParent()->GetPropertiesMenuLabel()) == wxNOT_FOUND
) 
4248         AddItem(container
->GetParent()->GetPropertiesMenuLabel(), container
->GetParent());