1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/richtext/richeditctrl.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 
); 
  61 #if wxRICHTEXT_USE_OWN_CARET 
  66  * This implements a non-flashing cursor in case there 
  67  * are platform-specific problems with the generic caret. 
  68  * wxRICHTEXT_USE_OWN_CARET is set in richtextbuffer.h. 
  71 class wxRichTextCaret
; 
  72 class wxRichTextCaretTimer
: public wxTimer
 
  75     wxRichTextCaretTimer(wxRichTextCaret
* caret
) 
  79     virtual void Notify(); 
  80     wxRichTextCaret
* m_caret
; 
  83 class wxRichTextCaret
: public wxCaret
 
  88         // default - use Create() 
  89     wxRichTextCaret(): m_timer(this)  { Init(); } 
  90         // creates a block caret associated with the given window 
  91     wxRichTextCaret(wxRichTextCtrl 
*window
, int width
, int height
) 
  92         : wxCaret(window
, width
, height
), m_timer(this) { Init(); m_richTextCtrl 
= window
; } 
  93     wxRichTextCaret(wxRichTextCtrl 
*window
, const wxSize
& size
) 
  94         : wxCaret(window
, size
), m_timer(this) { Init(); m_richTextCtrl 
= window
; } 
  96     virtual ~wxRichTextCaret(); 
 101     // called by wxWindow (not using the event tables) 
 102     virtual void OnSetFocus(); 
 103     virtual void OnKillFocus(); 
 105     // draw the caret on the given DC 
 106     void DoDraw(wxDC 
*dc
); 
 108     // get the visible count 
 109     int GetVisibleCount() const { return m_countVisible
; } 
 111     // delay repositioning 
 112     bool GetNeedsUpdate() const { return m_needsUpdate
; } 
 113     void SetNeedsUpdate(bool needsUpdate 
= true ) { m_needsUpdate 
= needsUpdate
; } 
 118     virtual void DoShow(); 
 119     virtual void DoHide(); 
 120     virtual void DoMove(); 
 121     virtual void DoSize(); 
 131     bool          m_hasFocus
;       // true => our window has focus 
 132     bool          m_needsUpdate
;    // must be repositioned 
 134     wxRichTextCaretTimer m_timer
; 
 135     wxRichTextCtrl
* m_richTextCtrl
; 
 139 IMPLEMENT_DYNAMIC_CLASS( wxRichTextCtrl
, wxTextCtrlBase 
) 
 141 IMPLEMENT_DYNAMIC_CLASS( wxRichTextEvent
, wxNotifyEvent 
) 
 143 BEGIN_EVENT_TABLE( wxRichTextCtrl
, wxTextCtrlBase 
) 
 144     EVT_PAINT(wxRichTextCtrl::OnPaint
) 
 145     EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground
) 
 146     EVT_IDLE(wxRichTextCtrl::OnIdle
) 
 147     EVT_SCROLLWIN(wxRichTextCtrl::OnScroll
) 
 148     EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick
) 
 149     EVT_MOTION(wxRichTextCtrl::OnMoveMouse
) 
 150     EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp
) 
 151     EVT_RIGHT_DOWN(wxRichTextCtrl::OnRightClick
) 
 152     EVT_MIDDLE_DOWN(wxRichTextCtrl::OnMiddleClick
) 
 153     EVT_LEFT_DCLICK(wxRichTextCtrl::OnLeftDClick
) 
 154     EVT_CHAR(wxRichTextCtrl::OnChar
) 
 155     EVT_KEY_DOWN(wxRichTextCtrl::OnChar
) 
 156     EVT_SIZE(wxRichTextCtrl::OnSize
) 
 157     EVT_SET_FOCUS(wxRichTextCtrl::OnSetFocus
) 
 158     EVT_KILL_FOCUS(wxRichTextCtrl::OnKillFocus
) 
 159     EVT_MOUSE_CAPTURE_LOST(wxRichTextCtrl::OnCaptureLost
) 
 160     EVT_CONTEXT_MENU(wxRichTextCtrl::OnContextMenu
) 
 161     EVT_SYS_COLOUR_CHANGED(wxRichTextCtrl::OnSysColourChanged
) 
 163     EVT_MENU(wxID_UNDO
, wxRichTextCtrl::OnUndo
) 
 164     EVT_UPDATE_UI(wxID_UNDO
, wxRichTextCtrl::OnUpdateUndo
) 
 166     EVT_MENU(wxID_REDO
, wxRichTextCtrl::OnRedo
) 
 167     EVT_UPDATE_UI(wxID_REDO
, wxRichTextCtrl::OnUpdateRedo
) 
 169     EVT_MENU(wxID_COPY
, wxRichTextCtrl::OnCopy
) 
 170     EVT_UPDATE_UI(wxID_COPY
, wxRichTextCtrl::OnUpdateCopy
) 
 172     EVT_MENU(wxID_PASTE
, wxRichTextCtrl::OnPaste
) 
 173     EVT_UPDATE_UI(wxID_PASTE
, wxRichTextCtrl::OnUpdatePaste
) 
 175     EVT_MENU(wxID_CUT
, wxRichTextCtrl::OnCut
) 
 176     EVT_UPDATE_UI(wxID_CUT
, wxRichTextCtrl::OnUpdateCut
) 
 178     EVT_MENU(wxID_CLEAR
, wxRichTextCtrl::OnClear
) 
 179     EVT_UPDATE_UI(wxID_CLEAR
, wxRichTextCtrl::OnUpdateClear
) 
 181     EVT_MENU(wxID_SELECTALL
, wxRichTextCtrl::OnSelectAll
) 
 182     EVT_UPDATE_UI(wxID_SELECTALL
, wxRichTextCtrl::OnUpdateSelectAll
) 
 189 wxArrayString 
wxRichTextCtrl::sm_availableFontNames
; 
 191 wxRichTextCtrl::wxRichTextCtrl() 
 192               : wxScrollHelper(this) 
 197 wxRichTextCtrl::wxRichTextCtrl(wxWindow
* parent
, 
 199                                const wxString
& value
, 
 203                                const wxValidator
& validator
, 
 204                                const wxString
& name
) 
 205               : wxScrollHelper(this) 
 208     Create(parent
, id
, value
, pos
, size
, style
, validator
, name
); 
 212 bool wxRichTextCtrl::Create( wxWindow
* parent
, wxWindowID id
, const wxString
& value
, const wxPoint
& pos
, const wxSize
& size
, long style
, 
 213                              const wxValidator
& validator
, const wxString
& name
) 
 217     if (!wxTextCtrlBase::Create(parent
, id
, pos
, size
, 
 218                            style
|wxFULL_REPAINT_ON_RESIZE
, 
 224         SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 227     // No physical scrolling, so we can preserve margins 
 228     EnableScrolling(false, false); 
 230     if (style 
& wxTE_READONLY
) 
 233     // The base attributes must all have default values 
 234     wxTextAttr attributes
; 
 235     attributes
.SetFont(GetFont()); 
 236     attributes
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
 237     attributes
.SetAlignment(wxTEXT_ALIGNMENT_LEFT
); 
 238     attributes
.SetLineSpacing(10); 
 239     attributes
.SetParagraphSpacingAfter(10); 
 240     attributes
.SetParagraphSpacingBefore(0); 
 242     SetBasicStyle(attributes
); 
 244     // The default attributes will be merged with base attributes, so 
 245     // can be empty to begin with 
 246     wxTextAttr defaultAttributes
; 
 247     SetDefaultStyle(defaultAttributes
); 
 249     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 250     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 253     GetBuffer().SetRichTextCtrl(this); 
 255 #if wxRICHTEXT_USE_OWN_CARET 
 256     SetCaret(new wxRichTextCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 258     SetCaret(new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 261     // Tell the sizers to use the given or best size 
 262     SetInitialSize(size
); 
 264 #if wxRICHTEXT_BUFFERED_PAINTING 
 266     RecreateBuffer(size
); 
 269     m_textCursor 
= wxCursor(wxCURSOR_IBEAM
); 
 270     m_urlCursor 
= wxCursor(wxCURSOR_HAND
); 
 272     SetCursor(m_textCursor
); 
 274     if (!value
.IsEmpty()) 
 277     GetBuffer().AddEventHandler(this); 
 280     wxAcceleratorEntry entries
[6]; 
 282     entries
[0].Set(wxACCEL_CMD
,   (int) 'C',       wxID_COPY
); 
 283     entries
[1].Set(wxACCEL_CMD
,   (int) 'X',       wxID_CUT
); 
 284     entries
[2].Set(wxACCEL_CMD
,   (int) 'V',       wxID_PASTE
); 
 285     entries
[3].Set(wxACCEL_CMD
,   (int) 'A',       wxID_SELECTALL
); 
 286     entries
[4].Set(wxACCEL_CMD
,   (int) 'Z',       wxID_UNDO
); 
 287     entries
[5].Set(wxACCEL_CMD
,   (int) 'Y',       wxID_REDO
); 
 289     wxAcceleratorTable 
accel(6, entries
); 
 290     SetAcceleratorTable(accel
); 
 292     m_contextMenu 
= new wxMenu
; 
 293     m_contextMenu
->Append(wxID_UNDO
, _("&Undo")); 
 294     m_contextMenu
->Append(wxID_REDO
, _("&Redo")); 
 295     m_contextMenu
->AppendSeparator(); 
 296     m_contextMenu
->Append(wxID_CUT
, _("Cu&t")); 
 297     m_contextMenu
->Append(wxID_COPY
, _("&Copy")); 
 298     m_contextMenu
->Append(wxID_PASTE
, _("&Paste")); 
 299     m_contextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
 300     m_contextMenu
->AppendSeparator(); 
 301     m_contextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
 303     long ids 
= wxNewId(); 
 304     m_contextMenu
->AppendSeparator(); 
 305     m_contextMenu
->Append(ids
, _("&Properties")); 
 307     Connect(ids
, wxEVT_UPDATE_UI
, wxUpdateUIEventHandler(wxRichTextCtrl::OnUpdateImage
)); 
 308     Connect(ids
, wxEVT_COMMAND_MENU_SELECTED
, wxCommandEventHandler(wxRichTextCtrl::OnImage
)); 
 309     m_imagePropertyId 
= ids
; 
 313 wxRichTextCtrl::~wxRichTextCtrl() 
 315     GetBuffer().RemoveEventHandler(this); 
 316     Disconnect(m_imagePropertyId
, wxEVT_UPDATE_UI
, wxUpdateUIEventHandler(wxRichTextCtrl::OnUpdateImage
)); 
 317     Disconnect(m_imagePropertyId
, wxEVT_COMMAND_MENU_SELECTED
, wxCommandEventHandler(wxRichTextCtrl::OnImage
)); 
 319     delete m_contextMenu
; 
 322 /// Member initialisation 
 323 void wxRichTextCtrl::Init() 
 325     m_contextMenu 
= NULL
; 
 327     m_caretPosition 
= -1; 
 328     m_selectionRange
.SetRange(-2, -2); 
 329     m_selectionAnchor 
= -2; 
 331     m_caretAtLineStart 
= false; 
 333     m_fullLayoutRequired 
= false; 
 334     m_fullLayoutTime 
= 0; 
 335     m_fullLayoutSavedPosition 
= 0; 
 336     m_delayedLayoutThreshold 
= wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD
; 
 337     m_caretPositionForDefaultStyle 
= -2; 
 338     m_currentObject 
= NULL
; 
 341 void wxRichTextCtrl::DoThaw() 
 343     if (GetBuffer().GetDirty()) 
 352 void wxRichTextCtrl::Clear() 
 354     m_buffer
.ResetAndClearCommands(); 
 355     m_buffer
.SetDirty(true); 
 356     m_caretPosition 
= -1; 
 357     m_caretPositionForDefaultStyle 
= -2; 
 358     m_caretAtLineStart 
= false; 
 359     m_selectionRange
.SetRange(-2, -2); 
 369     wxTextCtrl::SendTextUpdatedEvent(this); 
 373 void wxRichTextCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 375 #if !wxRICHTEXT_USE_OWN_CARET 
 376     if (GetCaret() && !IsFrozen()) 
 381 #if wxRICHTEXT_BUFFERED_PAINTING 
 382         wxBufferedPaintDC 
dc(this, m_bufferBitmap
); 
 392         dc
.SetFont(GetFont()); 
 394         // Paint the background 
 397         // wxRect drawingArea(GetLogicalPoint(wxPoint(0, 0)), GetClientSize()); 
 399         wxRect 
drawingArea(GetUpdateRegion().GetBox()); 
 400         drawingArea
.SetPosition(GetLogicalPoint(drawingArea
.GetPosition())); 
 402         wxRect 
availableSpace(GetClientSize()); 
 403         if (GetBuffer().GetDirty()) 
 405             GetBuffer().Layout(dc
, availableSpace
, wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
); 
 406             GetBuffer().SetDirty(false); 
 410         wxRect 
clipRect(availableSpace
); 
 411         clipRect
.x 
+= GetBuffer().GetLeftMargin(); 
 412         clipRect
.y 
+= GetBuffer().GetTopMargin(); 
 413         clipRect
.width 
-= (GetBuffer().GetLeftMargin() + GetBuffer().GetRightMargin()); 
 414         clipRect
.height 
-= (GetBuffer().GetTopMargin() + GetBuffer().GetBottomMargin()); 
 415         clipRect
.SetPosition(GetLogicalPoint(clipRect
.GetPosition())); 
 416         dc
.SetClippingRegion(clipRect
); 
 418         GetBuffer().Draw(dc
, GetBuffer().GetRange(), GetInternalSelectionRange(), drawingArea
, 0 /* descent */, 0 /* flags */); 
 420         dc
.DestroyClippingRegion(); 
 422         // Other user defined painting after everything else (i.e. all text) is painted 
 423         PaintAboveContent(dc
); 
 425 #if wxRICHTEXT_USE_OWN_CARET 
 426         if (GetCaret()->IsVisible()) 
 428             ((wxRichTextCaret
*) GetCaret())->DoDraw(& dc
); 
 433 #if !wxRICHTEXT_USE_OWN_CARET 
 440 // Empty implementation, to prevent flicker 
 441 void wxRichTextCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 445 void wxRichTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
 449 #if !wxRICHTEXT_USE_OWN_CARET 
 455 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 456     // Work around dropouts when control is focused 
 464 void wxRichTextCtrl::OnKillFocus(wxFocusEvent
& WXUNUSED(event
)) 
 469 #if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET 
 470     // Work around dropouts when control is focused 
 478 void wxRichTextCtrl::OnCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
 484 void wxRichTextCtrl::OnLeftClick(wxMouseEvent
& event
) 
 490     dc
.SetFont(GetFont()); 
 493     int hit 
= GetBuffer().HitTest(dc
, event
.GetLogicalPosition(dc
), position
); 
 495     if (hit 
!= wxRICHTEXT_HITTEST_NONE
) 
 497         m_dragStart 
= event
.GetLogicalPosition(dc
); 
 501         bool caretAtLineStart 
= false; 
 503         if (hit 
& wxRICHTEXT_HITTEST_BEFORE
) 
 505             // If we're at the start of a line (but not first in para) 
 506             // then we should keep the caret showing at the start of the line 
 507             // by showing the m_caretAtLineStart flag. 
 508             wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(position
); 
 509             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(position
); 
 511             if (line 
&& para 
&& line
->GetAbsoluteRange().GetStart() == position 
&& para
->GetRange().GetStart() != position
) 
 512                 caretAtLineStart 
= true; 
 516         long oldCaretPos 
= m_caretPosition
; 
 518         MoveCaret(position
, caretAtLineStart
); 
 519         SetDefaultStyleToCursorStyle(); 
 521         if (event
.ShiftDown()) 
 523             if (m_selectionRange
.GetStart() == -2) 
 524                 ExtendSelection(oldCaretPos
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 526                 ExtendSelection(m_caretPosition
, m_caretPosition
, wxRICHTEXT_SHIFT_DOWN
); 
 536 void wxRichTextCtrl::OnLeftUp(wxMouseEvent
& event
) 
 541         if (GetCapture() == this) 
 544         // See if we clicked on a URL 
 547         dc
.SetFont(GetFont()); 
 550         wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 551         int hit 
= GetBuffer().HitTest(dc
, logicalPt
, position
); 
 553         if ((hit 
!= wxRICHTEXT_HITTEST_NONE
) && !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
 555             wxRichTextEvent 
cmdEvent( 
 556                 wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
, 
 558             cmdEvent
.SetEventObject(this); 
 559             cmdEvent
.SetPosition(m_caretPosition
+1); 
 561             if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 564                 if (GetStyle(position
, attr
)) 
 566                     if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 568                         wxString urlTarget 
= attr
.GetURL(); 
 569                         if (!urlTarget
.IsEmpty()) 
 571                             wxMouseEvent 
mouseEvent(event
); 
 573                             long startPos 
= 0, endPos 
= 0; 
 574                             wxRichTextObject
* obj 
= GetBuffer().GetLeafObjectAtPosition(position
); 
 577                                 startPos 
= obj
->GetRange().GetStart(); 
 578                                 endPos 
= obj
->GetRange().GetEnd(); 
 581                             wxTextUrlEvent 
urlEvent(GetId(), mouseEvent
, startPos
, endPos
); 
 582                             InitCommandEvent(urlEvent
); 
 584                             urlEvent
.SetString(urlTarget
); 
 586                             GetEventHandler()->ProcessEvent(urlEvent
); 
 596 void wxRichTextCtrl::OnMoveMouse(wxMouseEvent
& event
) 
 600     dc
.SetFont(GetFont()); 
 603     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 604     int hit 
= GetBuffer().HitTest(dc
, logicalPt
, position
); 
 606     // See if we need to change the cursor 
 609         if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
 612             if (GetStyle(position
, attr
)) 
 614                 if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 616                     SetCursor(m_urlCursor
); 
 618                 else if (!attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 620                     SetCursor(m_textCursor
); 
 625             SetCursor(m_textCursor
); 
 628     if (!event
.Dragging()) 
 634     if (m_dragging 
&& hit 
!= wxRICHTEXT_HITTEST_NONE
) 
 636         // TODO: test closeness 
 638         bool caretAtLineStart 
= false; 
 640         if (hit 
& wxRICHTEXT_HITTEST_BEFORE
) 
 642             // If we're at the start of a line (but not first in para) 
 643             // then we should keep the caret showing at the start of the line 
 644             // by showing the m_caretAtLineStart flag. 
 645             wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(position
); 
 646             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(position
); 
 648             if (line 
&& para 
&& line
->GetAbsoluteRange().GetStart() == position 
&& para
->GetRange().GetStart() != position
) 
 649                 caretAtLineStart 
= true; 
 653         if (m_caretPosition 
!= position
) 
 655             ExtendSelection(m_caretPosition
, position
, wxRICHTEXT_SHIFT_DOWN
); 
 657             MoveCaret(position
, caretAtLineStart
); 
 658             SetDefaultStyleToCursorStyle(); 
 664 void wxRichTextCtrl::OnRightClick(wxMouseEvent
& event
) 
 668     wxRichTextEvent 
cmdEvent( 
 669         wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
, 
 671     cmdEvent
.SetEventObject(this); 
 672     cmdEvent
.SetPosition(m_caretPosition
+1); 
 674     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 678 /// Left-double-click 
 679 void wxRichTextCtrl::OnLeftDClick(wxMouseEvent
& WXUNUSED(event
)) 
 681     wxRichTextEvent 
cmdEvent( 
 682         wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
, 
 684     cmdEvent
.SetEventObject(this); 
 685     cmdEvent
.SetPosition(m_caretPosition
+1); 
 687     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 689         SelectWord(GetCaretPosition()+1); 
 694 void wxRichTextCtrl::OnMiddleClick(wxMouseEvent
& event
) 
 696     wxRichTextEvent 
cmdEvent( 
 697         wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
, 
 699     cmdEvent
.SetEventObject(this); 
 700     cmdEvent
.SetPosition(m_caretPosition
+1); 
 702     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 707 void wxRichTextCtrl::OnChar(wxKeyEvent
& event
) 
 711         flags 
|= wxRICHTEXT_CTRL_DOWN
; 
 712     if (event
.ShiftDown()) 
 713         flags 
|= wxRICHTEXT_SHIFT_DOWN
; 
 715         flags 
|= wxRICHTEXT_ALT_DOWN
; 
 717     if (event
.GetEventType() == wxEVT_KEY_DOWN
) 
 719         if (event
.IsKeyInCategory(WXK_CATEGORY_NAVIGATION
)) 
 721             KeyboardNavigate(event
.GetKeyCode(), flags
); 
 725         long keycode 
= event
.GetKeyCode(); 
 785             case WXK_NUMPAD_HOME
: 
 786             case WXK_NUMPAD_LEFT
: 
 788             case WXK_NUMPAD_RIGHT
: 
 789             case WXK_NUMPAD_DOWN
: 
 790             case WXK_NUMPAD_PAGEUP
: 
 791             case WXK_NUMPAD_PAGEDOWN
: 
 793             case WXK_NUMPAD_BEGIN
: 
 794             case WXK_NUMPAD_INSERT
: 
 795             case WXK_WINDOWS_LEFT
: 
 804         // Must process this before translation, otherwise it's translated into a WXK_DELETE event. 
 805         if (event
.CmdDown() && event
.GetKeyCode() == WXK_BACK
) 
 807             BeginBatchUndo(_("Delete Text")); 
 809             long newPos 
= m_caretPosition
; 
 811             bool processed 
= DeleteSelectedContent(& newPos
); 
 813             // Submit range in character positions, which are greater than caret positions, 
 814             // so subtract 1 for deleted character and add 1 for conversion to character position. 
 819                     long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
 822                         GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos
+1, newPos
), this); 
 828                     GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos
, newPos
), this); 
 833             if (GetLastPosition() == -1) 
 837                 m_caretPosition 
= -1; 
 839                 SetDefaultStyleToCursorStyle(); 
 842             ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
 844             wxRichTextEvent 
cmdEvent( 
 845                 wxEVT_COMMAND_RICHTEXT_DELETE
, 
 847             cmdEvent
.SetEventObject(this); 
 848             cmdEvent
.SetFlags(flags
); 
 849             cmdEvent
.SetPosition(m_caretPosition
+1); 
 850             GetEventHandler()->ProcessEvent(cmdEvent
); 
 860     // all the other keys modify the controls contents which shouldn't be 
 861     // possible if we're read-only 
 868     if (event
.GetKeyCode() == WXK_RETURN
) 
 870         BeginBatchUndo(_("Insert Text")); 
 872         long newPos 
= m_caretPosition
; 
 874         DeleteSelectedContent(& newPos
); 
 876         if (event
.ShiftDown()) 
 879             text 
= wxRichTextLineBreakChar
; 
 880             GetBuffer().InsertTextWithUndo(newPos
+1, text
, this); 
 881             m_caretAtLineStart 
= true; 
 885             GetBuffer().InsertNewlineWithUndo(newPos
+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
|wxRICHTEXT_INSERT_INTERACTIVE
); 
 888         SetDefaultStyleToCursorStyle(); 
 890         ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
 892         wxRichTextEvent 
cmdEvent( 
 893             wxEVT_COMMAND_RICHTEXT_RETURN
, 
 895         cmdEvent
.SetEventObject(this); 
 896         cmdEvent
.SetFlags(flags
); 
 897         cmdEvent
.SetPosition(newPos
+1); 
 899         if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 901             // Generate conventional event 
 902             wxCommandEvent 
textEvent(wxEVT_COMMAND_TEXT_ENTER
, GetId()); 
 903             InitCommandEvent(textEvent
); 
 905             GetEventHandler()->ProcessEvent(textEvent
); 
 909     else if (event
.GetKeyCode() == WXK_BACK
) 
 911         BeginBatchUndo(_("Delete Text")); 
 913         long newPos 
= m_caretPosition
; 
 915         bool processed 
= DeleteSelectedContent(& newPos
); 
 917         // Submit range in character positions, which are greater than caret positions, 
 918         // so subtract 1 for deleted character and add 1 for conversion to character position. 
 923                 long pos 
= wxRichTextCtrl::FindNextWordPosition(-1); 
 926                     GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos
+1, newPos
), this); 
 932                 GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos
, newPos
), this); 
 937         if (GetLastPosition() == -1) 
 941             m_caretPosition 
= -1; 
 943             SetDefaultStyleToCursorStyle(); 
 946         ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
 948         wxRichTextEvent 
cmdEvent( 
 949             wxEVT_COMMAND_RICHTEXT_DELETE
, 
 951         cmdEvent
.SetEventObject(this); 
 952         cmdEvent
.SetFlags(flags
); 
 953         cmdEvent
.SetPosition(m_caretPosition
+1); 
 954         GetEventHandler()->ProcessEvent(cmdEvent
); 
 958     else if (event
.GetKeyCode() == WXK_DELETE
) 
 960         BeginBatchUndo(_("Delete Text")); 
 962         long newPos 
= m_caretPosition
; 
 964         bool processed 
= DeleteSelectedContent(& newPos
); 
 966         // Submit range in character positions, which are greater than caret positions, 
 967         if (newPos 
< GetBuffer().GetRange().GetEnd()+1) 
 971                 long pos 
= wxRichTextCtrl::FindNextWordPosition(1); 
 972                 if (pos 
!= -1 && (pos 
> newPos
)) 
 974                     GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos
+1, pos
), this); 
 979             if (!processed 
&& newPos 
< (GetLastPosition()-1)) 
 980                 GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos
+1, newPos
+1), this); 
 985         if (GetLastPosition() == -1) 
 989             m_caretPosition 
= -1; 
 991             SetDefaultStyleToCursorStyle(); 
 994         wxRichTextEvent 
cmdEvent( 
 995             wxEVT_COMMAND_RICHTEXT_DELETE
, 
 997         cmdEvent
.SetEventObject(this); 
 998         cmdEvent
.SetFlags(flags
); 
 999         cmdEvent
.SetPosition(m_caretPosition
+1); 
1000         GetEventHandler()->ProcessEvent(cmdEvent
); 
1006         long keycode 
= event
.GetKeyCode(); 
1018                 if (event
.CmdDown()) 
1020                 // Fixes AltGr+key with European input languages on Windows 
1021                 if ((event
.CmdDown() && !event
.AltDown()) || (event
.AltDown() && !event
.CmdDown())) 
1028                 wxRichTextEvent 
cmdEvent( 
1029                     wxEVT_COMMAND_RICHTEXT_CHARACTER
, 
1031                 cmdEvent
.SetEventObject(this); 
1032                 cmdEvent
.SetFlags(flags
); 
1034                 cmdEvent
.SetCharacter(event
.GetUnicodeKey()); 
1036                 cmdEvent
.SetCharacter((wxChar
) keycode
); 
1038                 cmdEvent
.SetPosition(m_caretPosition
+1); 
1040                 if (keycode 
== wxT('\t')) 
1042                     // See if we need to promote or demote the selection or paragraph at the cursor 
1043                     // position, instead of inserting a tab. 
1044                     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
1045                     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(pos
); 
1046                     if (para 
&& para
->GetRange().GetStart() == pos 
&& para
->GetAttributes().HasListStyleName()) 
1048                         wxRichTextRange range
; 
1050                             range 
= GetSelectionRange(); 
1052                             range 
= para
->GetRange().FromInternal(); 
1054                         int promoteBy 
= event
.ShiftDown() ? 1 : -1; 
1056                         PromoteList(promoteBy
, range
, NULL
); 
1058                         GetEventHandler()->ProcessEvent(cmdEvent
); 
1064                 BeginBatchUndo(_("Insert Text")); 
1066                 long newPos 
= m_caretPosition
; 
1067                 DeleteSelectedContent(& newPos
); 
1070                 wxString str 
= event
.GetUnicodeKey(); 
1072                 wxString str 
= (wxChar
) event
.GetKeyCode(); 
1074                 GetBuffer().InsertTextWithUndo(newPos
+1, str
, this, 0); 
1078                 SetDefaultStyleToCursorStyle(); 
1079                 ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
1081                 GetEventHandler()->ProcessEvent(cmdEvent
); 
1089 /// Delete content if there is a selection, e.g. when pressing a key. 
1090 bool wxRichTextCtrl::DeleteSelectedContent(long* newPos
) 
1094         long pos 
= m_selectionRange
.GetStart(); 
1095         wxRichTextRange range 
= m_selectionRange
; 
1097         // SelectAll causes more to be selected than doing it interactively, 
1098         // and causes a new paragraph to be inserted. So for multiline buffers, 
1099         // don't delete the final position. 
1100         if (range
.GetEnd() == GetLastPosition() && GetNumberOfLines() > 0) 
1101             range
.SetEnd(range
.GetEnd()-1); 
1103         GetBuffer().DeleteRangeWithUndo(range
, this); 
1104         m_selectionRange
.SetRange(-2, -2); 
1114 /// Keyboard navigation 
1118 Left:       left one character 
1119 Right:      right one character 
1122 Ctrl-Left:  left one word 
1123 Ctrl-Right: right one word 
1124 Ctrl-Up:    previous paragraph start 
1125 Ctrl-Down:  next start of paragraph 
1128 Ctrl-Home:  start of document 
1129 Ctrl-End:   end of document 
1130 Page-Up:    Up a screen 
1131 Page-Down:  Down a screen 
1135 Ctrl-Alt-PgUp: Start of window 
1136 Ctrl-Alt-PgDn: End of window 
1137 F8:         Start selection mode 
1138 Esc:        End selection mode 
1140 Adding Shift does the above but starts/extends selection. 
1145 bool wxRichTextCtrl::KeyboardNavigate(int keyCode
, int flags
) 
1147     bool success 
= false; 
1149     if (keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT
) 
1151         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1152             success 
= WordRight(1, flags
); 
1154             success 
= MoveRight(1, flags
); 
1156     else if (keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT
) 
1158         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1159             success 
= WordLeft(1, flags
); 
1161             success 
= MoveLeft(1, flags
); 
1163     else if (keyCode 
== WXK_UP 
|| keyCode 
== WXK_NUMPAD_UP
) 
1165         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1166             success 
= MoveToParagraphStart(flags
); 
1168             success 
= MoveUp(1, flags
); 
1170     else if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN
) 
1172         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1173             success 
= MoveToParagraphEnd(flags
); 
1175             success 
= MoveDown(1, flags
); 
1177     else if (keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP
) 
1179         success 
= PageUp(1, flags
); 
1181     else if (keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1183         success 
= PageDown(1, flags
); 
1185     else if (keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME
) 
1187         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1188             success 
= MoveHome(flags
); 
1190             success 
= MoveToLineStart(flags
); 
1192     else if (keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END
) 
1194         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
1195             success 
= MoveEnd(flags
); 
1197             success 
= MoveToLineEnd(flags
); 
1202         ScrollIntoView(m_caretPosition
, keyCode
); 
1203         SetDefaultStyleToCursorStyle(); 
1209 /// Extend the selection. Selections are in caret positions. 
1210 bool wxRichTextCtrl::ExtendSelection(long oldPos
, long newPos
, int flags
) 
1212     if (flags 
& wxRICHTEXT_SHIFT_DOWN
) 
1214         if (oldPos 
== newPos
) 
1217         wxRichTextRange oldSelection 
= m_selectionRange
; 
1219         // If not currently selecting, start selecting 
1220         if (m_selectionRange
.GetStart() == -2) 
1222             m_selectionAnchor 
= oldPos
; 
1224             if (oldPos 
> newPos
) 
1225                 m_selectionRange
.SetRange(newPos
+1, oldPos
); 
1227                 m_selectionRange
.SetRange(oldPos
+1, newPos
); 
1231             // Always ensure that the selection range start is greater than 
1233             if (newPos 
> m_selectionAnchor
) 
1234                 m_selectionRange
.SetRange(m_selectionAnchor
+1, newPos
); 
1235             else if (newPos 
== m_selectionAnchor
) 
1236                 m_selectionRange 
= wxRichTextRange(-2, -2); 
1238                 m_selectionRange
.SetRange(newPos
+1, m_selectionAnchor
); 
1241         RefreshForSelectionChange(oldSelection
, m_selectionRange
); 
1243         if (m_selectionRange
.GetStart() > m_selectionRange
.GetEnd()) 
1245             wxLogDebug(wxT("Strange selection range")); 
1254 /// Scroll into view, returning true if we scrolled. 
1255 /// This takes a _caret_ position. 
1256 bool wxRichTextCtrl::ScrollIntoView(long position
, int keyCode
) 
1258     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(position
); 
1264     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1266     int startXUnits
, startYUnits
; 
1267     GetViewStart(& startXUnits
, & startYUnits
); 
1268     int startY 
= startYUnits 
* ppuY
; 
1271     GetVirtualSize(& sx
, & sy
); 
1277     wxRect rect 
= line
->GetRect(); 
1279     bool scrolled 
= false; 
1281     wxSize clientSize 
= GetClientSize(); 
1282     clientSize
.y 
-= GetBuffer().GetBottomMargin(); 
1284     if (GetWindowStyle() & wxRE_CENTRE_CARET
) 
1286         int y 
= rect
.y 
- GetClientSize().y
/2; 
1287         int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1288         if (y 
>= 0 && (y 
+ clientSize
.y
) < GetBuffer().GetCachedSize().y
) 
1290             if (startYUnits 
!= yUnits
) 
1292                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1295 #if !wxRICHTEXT_USE_OWN_CARET 
1305     if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN 
|| 
1306         keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT 
|| 
1307         keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END 
|| 
1308         keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1310         if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1312             // Make it scroll so this item is at the bottom 
1314             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1315             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1317             // If we're still off the screen, scroll another line down 
1318             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1321             if (startYUnits 
!= yUnits
) 
1323                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1327         else if (rect
.y 
< (startY 
+ GetBuffer().GetTopMargin())) 
1329             // Make it scroll so this item is at the top 
1331             int y 
= rect
.y 
- GetBuffer().GetTopMargin(); 
1332             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1334             if (startYUnits 
!= yUnits
) 
1336                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1342     else if (keyCode 
== WXK_UP  
|| keyCode 
== WXK_NUMPAD_UP 
|| 
1343              keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT 
|| 
1344              keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME 
|| 
1345              keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP 
) 
1347         if (rect
.y 
< (startY 
+ GetBuffer().GetBottomMargin())) 
1349             // Make it scroll so this item is at the top 
1351             int y 
= rect
.y 
- GetBuffer().GetTopMargin(); 
1352             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1354             if (startYUnits 
!= yUnits
) 
1356                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1360         else if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1362             // Make it scroll so this item is at the bottom 
1364             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1365             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1367             // If we're still off the screen, scroll another line down 
1368             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1371             if (startYUnits 
!= yUnits
) 
1373                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1379 #if !wxRICHTEXT_USE_OWN_CARET 
1387 /// Is the given position visible on the screen? 
1388 bool wxRichTextCtrl::IsPositionVisible(long pos
) const 
1390     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(pos
-1); 
1396     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1399     GetViewStart(& startX
, & startY
); 
1401     startY 
= startY 
* ppuY
; 
1403     wxRect rect 
= line
->GetRect(); 
1404     wxSize clientSize 
= GetClientSize(); 
1405     clientSize
.y 
-= GetBuffer().GetBottomMargin(); 
1407     return (rect
.GetBottom() > (startY 
+ GetBuffer().GetTopMargin())) && (rect
.GetTop() < (startY 
+ clientSize
.y
)); 
1410 void wxRichTextCtrl::SetCaretPosition(long position
, bool showAtLineStart
) 
1412     m_caretPosition 
= position
; 
1413     m_caretAtLineStart 
= showAtLineStart
; 
1416 /// Move caret one visual step forward: this may mean setting a flag 
1417 /// and keeping the same position if we're going from the end of one line 
1418 /// to the start of the next, which may be the exact same caret position. 
1419 void wxRichTextCtrl::MoveCaretForward(long oldPosition
) 
1421     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(oldPosition
); 
1423     // Only do the check if we're not at the end of the paragraph (where things work OK 
1425     if (para 
&& (oldPosition 
!= para
->GetRange().GetEnd() - 1)) 
1427         wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(oldPosition
); 
1431             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1433             // We're at the end of a line. See whether we need to 
1434             // stay at the same actual caret position but change visual 
1435             // position, or not. 
1436             if (oldPosition 
== lineRange
.GetEnd()) 
1438                 if (m_caretAtLineStart
) 
1440                     // We're already at the start of the line, so actually move on now. 
1441                     m_caretPosition 
= oldPosition 
+ 1; 
1442                     m_caretAtLineStart 
= false; 
1446                     // We're showing at the end of the line, so keep to 
1447                     // the same position but indicate that we're to show 
1448                     // at the start of the next line. 
1449                     m_caretPosition 
= oldPosition
; 
1450                     m_caretAtLineStart 
= true; 
1452                 SetDefaultStyleToCursorStyle(); 
1458     SetDefaultStyleToCursorStyle(); 
1461 /// Move caret one visual step backward: this may mean setting a flag 
1462 /// and keeping the same position if we're going from the end of one line 
1463 /// to the start of the next, which may be the exact same caret position. 
1464 void wxRichTextCtrl::MoveCaretBack(long oldPosition
) 
1466     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(oldPosition
); 
1468     // Only do the check if we're not at the start of the paragraph (where things work OK 
1470     if (para 
&& (oldPosition 
!= para
->GetRange().GetStart())) 
1472         wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(oldPosition
); 
1476             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1478             // We're at the start of a line. See whether we need to 
1479             // stay at the same actual caret position but change visual 
1480             // position, or not. 
1481             if (oldPosition 
== lineRange
.GetStart()) 
1483                 m_caretPosition 
= oldPosition
-1; 
1484                 m_caretAtLineStart 
= true; 
1487             else if (oldPosition 
== lineRange
.GetEnd()) 
1489                 if (m_caretAtLineStart
) 
1491                     // We're at the start of the line, so keep the same caret position 
1492                     // but clear the start-of-line flag. 
1493                     m_caretPosition 
= oldPosition
; 
1494                     m_caretAtLineStart 
= false; 
1498                     // We're showing at the end of the line, so go back 
1499                     // to the previous character position. 
1500                     m_caretPosition 
= oldPosition 
- 1; 
1502                 SetDefaultStyleToCursorStyle(); 
1508     SetDefaultStyleToCursorStyle(); 
1512 bool wxRichTextCtrl::MoveRight(int noPositions
, int flags
) 
1514     long endPos 
= GetBuffer().GetRange().GetEnd(); 
1516     if (m_caretPosition 
+ noPositions 
< endPos
) 
1518         long oldPos 
= m_caretPosition
; 
1519         long newPos 
= m_caretPosition 
+ noPositions
; 
1521         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1525         // Determine by looking at oldPos and m_caretPosition whether 
1526         // we moved from the end of a line to the start of the next line, in which case 
1527         // we want to adjust the caret position such that it is positioned at the 
1528         // start of the next line, rather than jumping past the first character of the 
1530         if (noPositions 
== 1 && !extendSel
) 
1531             MoveCaretForward(oldPos
); 
1533             SetCaretPosition(newPos
); 
1536         SetDefaultStyleToCursorStyle(); 
1545 bool wxRichTextCtrl::MoveLeft(int noPositions
, int flags
) 
1549     if (m_caretPosition 
> startPos 
- noPositions 
+ 1) 
1551         long oldPos 
= m_caretPosition
; 
1552         long newPos 
= m_caretPosition 
- noPositions
; 
1553         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1557         if (noPositions 
== 1 && !extendSel
) 
1558             MoveCaretBack(oldPos
); 
1560             SetCaretPosition(newPos
); 
1563         SetDefaultStyleToCursorStyle(); 
1572 bool wxRichTextCtrl::MoveUp(int noLines
, int flags
) 
1574     return MoveDown(- noLines
, flags
); 
1578 bool wxRichTextCtrl::MoveDown(int noLines
, int flags
) 
1583     long lineNumber 
= GetBuffer().GetVisibleLineNumber(m_caretPosition
, true, m_caretAtLineStart
); 
1584     wxPoint pt 
= GetCaret()->GetPosition(); 
1585     long newLine 
= lineNumber 
+ noLines
; 
1587     if (lineNumber 
!= -1) 
1591             long lastLine 
= GetBuffer().GetVisibleLineNumber(GetBuffer().GetRange().GetEnd()); 
1593             if (newLine 
> lastLine
) 
1603     wxRichTextLine
* lineObj 
= GetBuffer().GetLineForVisibleLineNumber(newLine
); 
1606         pt
.y 
= lineObj
->GetAbsolutePosition().y 
+ 2; 
1612     wxClientDC 
dc(this); 
1614     dc
.SetFont(GetFont()); 
1616     int hitTest 
= GetBuffer().HitTest(dc
, pt
, newPos
); 
1618     if (hitTest 
!= wxRICHTEXT_HITTEST_NONE
) 
1620         // If end of previous line, and hitTest is wxRICHTEXT_HITTEST_BEFORE, 
1621         // we want to be at the end of the last line but with m_caretAtLineStart set to true, 
1622         // so we view the caret at the start of the line. 
1623         bool caretLineStart 
= false; 
1624         if (hitTest 
& wxRICHTEXT_HITTEST_BEFORE
) 
1626             wxRichTextLine
* thisLine 
= GetBuffer().GetLineAtPosition(newPos
-1); 
1627             wxRichTextRange lineRange
; 
1629                 lineRange 
= thisLine
->GetAbsoluteRange(); 
1631             if (thisLine 
&& (newPos
-1) == lineRange
.GetEnd()) 
1634                 caretLineStart 
= true; 
1638                 wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(newPos
); 
1639                 if (para 
&& para
->GetRange().GetStart() == newPos
) 
1644         long newSelEnd 
= newPos
; 
1646         bool extendSel 
= ExtendSelection(m_caretPosition
, newSelEnd
, flags
); 
1650         SetCaretPosition(newPos
, caretLineStart
); 
1652         SetDefaultStyleToCursorStyle(); 
1660 /// Move to the end of the paragraph 
1661 bool wxRichTextCtrl::MoveToParagraphEnd(int flags
) 
1663     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(m_caretPosition
, true); 
1666         long newPos 
= para
->GetRange().GetEnd() - 1; 
1667         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1671         SetCaretPosition(newPos
); 
1673         SetDefaultStyleToCursorStyle(); 
1681 /// Move to the start of the paragraph 
1682 bool wxRichTextCtrl::MoveToParagraphStart(int flags
) 
1684     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(m_caretPosition
, true); 
1687         long newPos 
= para
->GetRange().GetStart() - 1; 
1688         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1692         SetCaretPosition(newPos
); 
1694         SetDefaultStyleToCursorStyle(); 
1702 /// Move to the end of the line 
1703 bool wxRichTextCtrl::MoveToLineEnd(int flags
) 
1705     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1709         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1710         long newPos 
= lineRange
.GetEnd(); 
1711         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1715         SetCaretPosition(newPos
); 
1717         SetDefaultStyleToCursorStyle(); 
1725 /// Move to the start of the line 
1726 bool wxRichTextCtrl::MoveToLineStart(int flags
) 
1728     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1731         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1732         long newPos 
= lineRange
.GetStart()-1; 
1734         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1738         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphForLine(line
); 
1740         SetCaretPosition(newPos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
1742         SetDefaultStyleToCursorStyle(); 
1750 /// Move to the start of the buffer 
1751 bool wxRichTextCtrl::MoveHome(int flags
) 
1753     if (m_caretPosition 
!= -1) 
1755         bool extendSel 
= ExtendSelection(m_caretPosition
, -1, flags
); 
1759         SetCaretPosition(-1); 
1761         SetDefaultStyleToCursorStyle(); 
1769 /// Move to the end of the buffer 
1770 bool wxRichTextCtrl::MoveEnd(int flags
) 
1772     long endPos 
= GetBuffer().GetRange().GetEnd()-1; 
1774     if (m_caretPosition 
!= endPos
) 
1776         bool extendSel 
= ExtendSelection(m_caretPosition
, endPos
, flags
); 
1780         SetCaretPosition(endPos
); 
1782         SetDefaultStyleToCursorStyle(); 
1790 /// Move noPages pages up 
1791 bool wxRichTextCtrl::PageUp(int noPages
, int flags
) 
1793     return PageDown(- noPages
, flags
); 
1796 /// Move noPages pages down 
1797 bool wxRichTextCtrl::PageDown(int noPages
, int flags
) 
1799     // Calculate which line occurs noPages * screen height further down. 
1800     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1803         wxSize clientSize 
= GetClientSize(); 
1804         int newY 
= line
->GetAbsolutePosition().y 
+ noPages
*clientSize
.y
; 
1806         wxRichTextLine
* newLine 
= GetBuffer().GetLineAtYPosition(newY
); 
1809             wxRichTextRange lineRange 
= newLine
->GetAbsoluteRange(); 
1810             long pos 
= lineRange
.GetStart()-1; 
1811             if (pos 
!= m_caretPosition
) 
1813                 wxRichTextParagraph
* para 
= GetBuffer().GetParagraphForLine(newLine
); 
1815                 bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
1819                 SetCaretPosition(pos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
1821                 SetDefaultStyleToCursorStyle(); 
1831 static bool wxRichTextCtrlIsWhitespace(const wxString
& str
) 
1833     return str 
== wxT(" ") || str 
== wxT("\t"); 
1836 // Finds the caret position for the next word 
1837 long wxRichTextCtrl::FindNextWordPosition(int direction
) const 
1839     long endPos 
= GetBuffer().GetRange().GetEnd(); 
1843         long i 
= m_caretPosition
+1+direction
; // +1 for conversion to character pos 
1845         // First skip current text to space 
1846         while (i 
< endPos 
&& i 
> -1) 
1848             // i is in character, not caret positions 
1849             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1850             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1851             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
1855             else if (!wxRichTextCtrlIsWhitespace(text
) && !text
.empty()) 
1862         while (i 
< endPos 
&& i 
> -1) 
1864             // i is in character, not caret positions 
1865             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1866             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1867             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
1868                 return wxMax(-1, i
); 
1870             if (text
.empty()) // End of paragraph, or maybe an image 
1871                 return wxMax(-1, i 
- 1); 
1872             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
1876                 // Convert to caret position 
1877                 return wxMax(-1, i 
- 1); 
1886         long i 
= m_caretPosition
; 
1888         // First skip white space 
1889         while (i 
< endPos 
&& i 
> -1) 
1891             // i is in character, not caret positions 
1892             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1893             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1895             if (text
.empty() || (line 
&& (i 
== line
->GetAbsoluteRange().GetStart()))) // End of paragraph, or maybe an image 
1897             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
1902         // Next skip current text to space 
1903         while (i 
< endPos 
&& i 
> -1) 
1905             // i is in character, not caret positions 
1906             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1907             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1908             if (line 
&& line
->GetAbsoluteRange().GetStart() == i
) 
1911             if (!wxRichTextCtrlIsWhitespace(text
) /* && !text.empty() */) 
1924 /// Move n words left 
1925 bool wxRichTextCtrl::WordLeft(int WXUNUSED(n
), int flags
) 
1927     long pos 
= FindNextWordPosition(-1); 
1928     if (pos 
!= m_caretPosition
) 
1930         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(pos
, true); 
1932         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
1936         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
1938         SetDefaultStyleToCursorStyle(); 
1946 /// Move n words right 
1947 bool wxRichTextCtrl::WordRight(int WXUNUSED(n
), int flags
) 
1949     long pos 
= FindNextWordPosition(1); 
1950     if (pos 
!= m_caretPosition
) 
1952         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(pos
, true); 
1954         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
1958         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
1960         SetDefaultStyleToCursorStyle(); 
1969 void wxRichTextCtrl::OnSize(wxSizeEvent
& event
) 
1971     // Only do sizing optimization for large buffers 
1972     if (GetBuffer().GetRange().GetEnd() > m_delayedLayoutThreshold
) 
1974         m_fullLayoutRequired 
= true; 
1975         m_fullLayoutTime 
= wxGetLocalTimeMillis(); 
1976         m_fullLayoutSavedPosition 
= GetFirstVisiblePosition(); 
1977         LayoutContent(true /* onlyVisibleRect */); 
1980         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
1982 #if wxRICHTEXT_BUFFERED_PAINTING 
1990 /// Idle-time processing 
1991 void wxRichTextCtrl::OnIdle(wxIdleEvent
& event
) 
1993 #if wxRICHTEXT_USE_OWN_CARET 
1994     if (((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
1996         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(false); 
2002     const int layoutInterval 
= wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL
; 
2004     if (m_fullLayoutRequired 
&& (wxGetLocalTimeMillis() > (m_fullLayoutTime 
+ layoutInterval
))) 
2006         m_fullLayoutRequired 
= false; 
2007         m_fullLayoutTime 
= 0; 
2008         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2009         ShowPosition(m_fullLayoutSavedPosition
); 
2013     if (m_caretPositionForDefaultStyle 
!= -2) 
2015         // If the caret position has changed, no longer reflect the default style 
2017         if (GetCaretPosition() != m_caretPositionForDefaultStyle
) 
2018             m_caretPositionForDefaultStyle 
= -2; 
2025 void wxRichTextCtrl::OnScroll(wxScrollWinEvent
& event
) 
2027 #if wxRICHTEXT_USE_OWN_CARET 
2028     if (!((wxRichTextCaret
*) GetCaret())->GetNeedsUpdate()) 
2031         ((wxRichTextCaret
*) GetCaret())->SetNeedsUpdate(); 
2038 /// Set up scrollbars, e.g. after a resize 
2039 void wxRichTextCtrl::SetupScrollbars(bool atTop
) 
2044     if (GetBuffer().IsEmpty()) 
2046         SetScrollbars(0, 0, 0, 0, 0, 0); 
2050     // TODO: reimplement scrolling so we scroll by line, not by fixed number 
2051     // of pixels. See e.g. wxVScrolledWindow for ideas. 
2052     int pixelsPerUnit 
= 5; 
2053     wxSize clientSize 
= GetClientSize(); 
2055     int maxHeight 
= GetBuffer().GetCachedSize().y 
+ GetBuffer().GetTopMargin(); 
2057     // Round up so we have at least maxHeight pixels 
2058     int unitsY 
= (int) (((float)maxHeight
/(float)pixelsPerUnit
) + 0.5); 
2060     int startX 
= 0, startY 
= 0; 
2062         GetViewStart(& startX
, & startY
); 
2064     int maxPositionX 
= 0; 
2065     int maxPositionY 
= (int) ((((float)(wxMax((unitsY
*pixelsPerUnit
) - clientSize
.y
, 0)))/((float)pixelsPerUnit
)) + 0.5); 
2067     int newStartX 
= wxMin(maxPositionX
, startX
); 
2068     int newStartY 
= wxMin(maxPositionY
, startY
); 
2070     int oldPPUX
, oldPPUY
; 
2071     int oldStartX
, oldStartY
; 
2072     int oldVirtualSizeX 
= 0, oldVirtualSizeY 
= 0; 
2073     GetScrollPixelsPerUnit(& oldPPUX
, & oldPPUY
); 
2074     GetViewStart(& oldStartX
, & oldStartY
); 
2075     GetVirtualSize(& oldVirtualSizeX
, & oldVirtualSizeY
); 
2077         oldVirtualSizeY 
/= oldPPUY
; 
2079     if (oldPPUX 
== 0 && oldPPUY 
== pixelsPerUnit 
&& oldVirtualSizeY 
== unitsY 
&& oldStartX 
== newStartX 
&& oldStartY 
== newStartY
) 
2082     // Don't set scrollbars if there were none before, and there will be none now. 
2083     if (oldPPUY 
!= 0 && (oldVirtualSizeY
*oldPPUY 
< clientSize
.y
) && (unitsY
*pixelsPerUnit 
< clientSize
.y
)) 
2086     // Move to previous scroll position if 
2088     SetScrollbars(0, pixelsPerUnit
, 0, unitsY
, newStartX
, newStartY
); 
2091 /// Paint the background 
2092 void wxRichTextCtrl::PaintBackground(wxDC
& dc
) 
2094     wxColour backgroundColour 
= GetBackgroundColour(); 
2095     if (!backgroundColour
.Ok()) 
2096         backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
2098     // Clear the background 
2099     dc
.SetBrush(wxBrush(backgroundColour
)); 
2100     dc
.SetPen(*wxTRANSPARENT_PEN
); 
2101     wxRect 
windowRect(GetClientSize()); 
2102     windowRect
.x 
-= 2; windowRect
.y 
-= 2; 
2103     windowRect
.width 
+= 4; windowRect
.height 
+= 4; 
2105     // We need to shift the rectangle to take into account 
2106     // scrolling. Converting device to logical coordinates. 
2107     CalcUnscrolledPosition(windowRect
.x
, windowRect
.y
, & windowRect
.x
, & windowRect
.y
); 
2108     dc
.DrawRectangle(windowRect
); 
2111 #if wxRICHTEXT_BUFFERED_PAINTING 
2112 /// Recreate buffer bitmap if necessary 
2113 bool wxRichTextCtrl::RecreateBuffer(const wxSize
& size
) 
2116     if (sz 
== wxDefaultSize
) 
2117         sz 
= GetClientSize(); 
2119     if (sz
.x 
< 1 || sz
.y 
< 1) 
2122     if (!m_bufferBitmap
.Ok() || m_bufferBitmap
.GetWidth() < sz
.x 
|| m_bufferBitmap
.GetHeight() < sz
.y
) 
2123         m_bufferBitmap 
= wxBitmap(sz
.x
, sz
.y
); 
2124     return m_bufferBitmap
.Ok(); 
2128 // ---------------------------------------------------------------------------- 
2129 // file IO functions 
2130 // ---------------------------------------------------------------------------- 
2132 bool wxRichTextCtrl::DoLoadFile(const wxString
& filename
, int fileType
) 
2134     bool success 
= GetBuffer().LoadFile(filename
, (wxRichTextFileType
)fileType
); 
2136         m_filename 
= filename
; 
2139     SetInsertionPoint(0); 
2142     SetupScrollbars(true); 
2144     wxTextCtrl::SendTextUpdatedEvent(this); 
2150         wxLogError(_("File couldn't be loaded.")); 
2156 bool wxRichTextCtrl::DoSaveFile(const wxString
& filename
, int fileType
) 
2158     if (GetBuffer().SaveFile(filename
, (wxRichTextFileType
)fileType
)) 
2160         m_filename 
= filename
; 
2167     wxLogError(_("The text couldn't be saved.")); 
2172 // ---------------------------------------------------------------------------- 
2173 // wxRichTextCtrl specific functionality 
2174 // ---------------------------------------------------------------------------- 
2176 /// Add a new paragraph of text to the end of the buffer 
2177 wxRichTextRange 
wxRichTextCtrl::AddParagraph(const wxString
& text
) 
2179     wxRichTextRange range 
= GetBuffer().AddParagraph(text
); 
2185 wxRichTextRange 
wxRichTextCtrl::AddImage(const wxImage
& image
) 
2187     wxRichTextRange range 
= GetBuffer().AddImage(image
); 
2192 // ---------------------------------------------------------------------------- 
2193 // selection and ranges 
2194 // ---------------------------------------------------------------------------- 
2196 void wxRichTextCtrl::SelectAll() 
2198     SetSelection(-1, -1); 
2202 void wxRichTextCtrl::SelectNone() 
2204     if (!(GetSelectionRange() == wxRichTextRange(-2, -2))) 
2206         wxRichTextRange oldSelection 
= m_selectionRange
; 
2208         m_selectionRange 
= wxRichTextRange(-2, -2); 
2210         RefreshForSelectionChange(oldSelection
, m_selectionRange
); 
2212     m_selectionAnchor 
= -2; 
2215 static bool wxIsWordDelimiter(const wxString
& text
) 
2217     return !text
.IsEmpty() && !wxIsalnum(text
[0]); 
2220 /// Select the word at the given character position 
2221 bool wxRichTextCtrl::SelectWord(long position
) 
2223     if (position 
< 0 || position 
> GetBuffer().GetRange().GetEnd()) 
2226     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(position
); 
2230     if (position 
== para
->GetRange().GetEnd()) 
2233     long positionStart 
= position
; 
2234     long positionEnd 
= position
; 
2236     for (positionStart 
= position
; positionStart 
>= para
->GetRange().GetStart(); positionStart 
--) 
2238         wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(positionStart
, positionStart
)); 
2239         if (wxIsWordDelimiter(text
)) 
2245     if (positionStart 
< para
->GetRange().GetStart()) 
2246         positionStart 
= para
->GetRange().GetStart(); 
2248     for (positionEnd 
= position
; positionEnd 
< para
->GetRange().GetEnd(); positionEnd 
++) 
2250         wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(positionEnd
, positionEnd
)); 
2251         if (wxIsWordDelimiter(text
)) 
2257     if (positionEnd 
>= para
->GetRange().GetEnd()) 
2258         positionEnd 
= para
->GetRange().GetEnd(); 
2260     if (positionEnd 
< positionStart
) 
2263     SetSelection(positionStart
, positionEnd
+1); 
2265     if (positionStart 
>= 0) 
2267         MoveCaret(positionStart
-1, true); 
2268         SetDefaultStyleToCursorStyle(); 
2274 wxString 
wxRichTextCtrl::GetStringSelection() const 
2277     GetSelection(&from
, &to
); 
2279     return GetRange(from
, to
); 
2282 // ---------------------------------------------------------------------------- 
2284 // ---------------------------------------------------------------------------- 
2286 wxTextCtrlHitTestResult
 
2287 wxRichTextCtrl::HitTest(const wxPoint
& pt
, wxTextCoord 
*x
, wxTextCoord 
*y
) const 
2289     // implement in terms of the other overload as the native ports typically 
2290     // can get the position and not (x, y) pair directly (although wxUniv 
2291     // directly gets x and y -- and so overrides this method as well) 
2293     wxTextCtrlHitTestResult rc 
= HitTest(pt
, &pos
); 
2295     if ( rc 
!= wxTE_HT_UNKNOWN 
) 
2297         PositionToXY(pos
, x
, y
); 
2303 wxTextCtrlHitTestResult
 
2304 wxRichTextCtrl::HitTest(const wxPoint
& pt
, 
2307     wxClientDC 
dc((wxRichTextCtrl
*) this); 
2308     ((wxRichTextCtrl
*)this)->PrepareDC(dc
); 
2310     // Buffer uses logical position (relative to start of buffer) 
2312     wxPoint pt2 
= GetLogicalPoint(pt
); 
2314     int hit 
= ((wxRichTextCtrl
*)this)->GetBuffer().HitTest(dc
, pt2
, *pos
); 
2316     if ((hit 
& wxRICHTEXT_HITTEST_BEFORE
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2317         return wxTE_HT_BEFORE
; 
2318     else if ((hit 
& wxRICHTEXT_HITTEST_AFTER
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2319         return wxTE_HT_BEYOND
; 
2320     else if (hit 
& (wxRICHTEXT_HITTEST_BEFORE
|wxRICHTEXT_HITTEST_AFTER
)) 
2321         return wxTE_HT_ON_TEXT
; 
2323     return wxTE_HT_UNKNOWN
; 
2326 // ---------------------------------------------------------------------------- 
2327 // set/get the controls text 
2328 // ---------------------------------------------------------------------------- 
2330 wxString 
wxRichTextCtrl::DoGetValue() const 
2332     return GetBuffer().GetText(); 
2335 wxString 
wxRichTextCtrl::GetRange(long from
, long to
) const 
2337     // Public API for range is different from internals 
2338     return GetBuffer().GetTextForRange(wxRichTextRange(from
, to
-1)); 
2341 void wxRichTextCtrl::DoSetValue(const wxString
& value
, int flags
) 
2343     // Don't call Clear here, since it always sends a text updated event 
2344     m_buffer
.ResetAndClearCommands(); 
2345     m_buffer
.SetDirty(true); 
2346     m_caretPosition 
= -1; 
2347     m_caretPositionForDefaultStyle 
= -2; 
2348     m_caretAtLineStart 
= false; 
2349     m_selectionRange
.SetRange(-2, -2); 
2359     if (!value
.IsEmpty()) 
2361         // Remove empty paragraph 
2362         GetBuffer().Clear(); 
2363         DoWriteText(value
, flags
); 
2365         // for compatibility, don't move the cursor when doing SetValue() 
2366         SetInsertionPoint(0); 
2370         // still send an event for consistency 
2371         if (flags 
& SetValue_SendEvent
) 
2372             wxTextCtrl::SendTextUpdatedEvent(this); 
2377 void wxRichTextCtrl::WriteText(const wxString
& value
) 
2382 void wxRichTextCtrl::DoWriteText(const wxString
& value
, int flags
) 
2384     wxString valueUnix 
= wxTextFile::Translate(value
, wxTextFileType_Unix
); 
2386     GetBuffer().InsertTextWithUndo(m_caretPosition
+1, valueUnix
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2388     if ( flags 
& SetValue_SendEvent 
) 
2389         wxTextCtrl::SendTextUpdatedEvent(this); 
2392 void wxRichTextCtrl::AppendText(const wxString
& text
) 
2394     SetInsertionPointEnd(); 
2399 /// Write an image at the current insertion point 
2400 bool wxRichTextCtrl::WriteImage(const wxImage
& image
, wxBitmapType bitmapType
, const wxRichTextAnchoredObjectAttr
& attr
) 
2402     wxRichTextImageBlock imageBlock
; 
2404     wxImage image2 
= image
; 
2405     if (imageBlock
.MakeImageBlock(image2
, bitmapType
)) 
2406         return WriteImage(imageBlock
, attr
); 
2411 bool wxRichTextCtrl::WriteImage(const wxString
& filename
, wxBitmapType bitmapType
, const wxRichTextAnchoredObjectAttr
& attr
) 
2413     wxRichTextImageBlock imageBlock
; 
2416     if (imageBlock
.MakeImageBlock(filename
, bitmapType
, image
, false)) 
2417         return WriteImage(imageBlock
, attr
); 
2422 bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock
& imageBlock
, const wxRichTextAnchoredObjectAttr
& attr
) 
2424     return GetBuffer().InsertImageWithUndo(m_caretPosition
+1, imageBlock
, this, NULL
, attr
); 
2427 bool wxRichTextCtrl::WriteImage(const wxBitmap
& bitmap
, wxBitmapType bitmapType
, const wxRichTextAnchoredObjectAttr
& attr
) 
2431         wxRichTextImageBlock imageBlock
; 
2433         wxImage image 
= bitmap
.ConvertToImage(); 
2434         if (image
.Ok() && imageBlock
.MakeImageBlock(image
, bitmapType
)) 
2435             return WriteImage(imageBlock
, attr
); 
2441 /// Insert a newline (actually paragraph) at the current insertion point. 
2442 bool wxRichTextCtrl::Newline() 
2444     return GetBuffer().InsertNewlineWithUndo(m_caretPosition
+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2447 /// Insert a line break at the current insertion point. 
2448 bool wxRichTextCtrl::LineBreak() 
2451     text 
= wxRichTextLineBreakChar
; 
2452     return GetBuffer().InsertTextWithUndo(m_caretPosition
+1, text
, this); 
2455 // ---------------------------------------------------------------------------- 
2456 // Clipboard operations 
2457 // ---------------------------------------------------------------------------- 
2459 void wxRichTextCtrl::Copy() 
2463         wxRichTextRange range 
= GetInternalSelectionRange(); 
2464         GetBuffer().CopyToClipboard(range
); 
2468 void wxRichTextCtrl::Cut() 
2472         wxRichTextRange range 
= GetInternalSelectionRange(); 
2473         GetBuffer().CopyToClipboard(range
); 
2475         DeleteSelectedContent(); 
2481 void wxRichTextCtrl::Paste() 
2485         BeginBatchUndo(_("Paste")); 
2487         long newPos 
= m_caretPosition
; 
2488         DeleteSelectedContent(& newPos
); 
2490         GetBuffer().PasteFromClipboard(newPos
); 
2496 void wxRichTextCtrl::DeleteSelection() 
2498     if (CanDeleteSelection()) 
2500         DeleteSelectedContent(); 
2504 bool wxRichTextCtrl::HasSelection() const 
2506     return m_selectionRange
.GetStart() != -2 && m_selectionRange
.GetEnd() != -2; 
2509 bool wxRichTextCtrl::CanCopy() const 
2511     // Can copy if there's a selection 
2512     return HasSelection(); 
2515 bool wxRichTextCtrl::CanCut() const 
2517     return HasSelection() && IsEditable(); 
2520 bool wxRichTextCtrl::CanPaste() const 
2522     if ( !IsEditable() ) 
2525     return GetBuffer().CanPasteFromClipboard(); 
2528 bool wxRichTextCtrl::CanDeleteSelection() const 
2530     return HasSelection() && IsEditable(); 
2534 // ---------------------------------------------------------------------------- 
2536 // ---------------------------------------------------------------------------- 
2538 void wxRichTextCtrl::SetContextMenu(wxMenu
* menu
) 
2540     if (m_contextMenu 
&& m_contextMenu 
!= menu
) 
2541         delete m_contextMenu
; 
2542     m_contextMenu 
= menu
; 
2545 void wxRichTextCtrl::SetEditable(bool editable
) 
2547     m_editable 
= editable
; 
2550 void wxRichTextCtrl::SetInsertionPoint(long pos
) 
2554     m_caretPosition 
= pos 
- 1; 
2558     SetDefaultStyleToCursorStyle(); 
2561 void wxRichTextCtrl::SetInsertionPointEnd() 
2563     long pos 
= GetLastPosition(); 
2564     SetInsertionPoint(pos
); 
2567 long wxRichTextCtrl::GetInsertionPoint() const 
2569     return m_caretPosition
+1; 
2572 wxTextPos 
wxRichTextCtrl::GetLastPosition() const 
2574     return GetBuffer().GetRange().GetEnd(); 
2577 // If the return values from and to are the same, there is no 
2579 void wxRichTextCtrl::GetSelection(long* from
, long* to
) const 
2581     *from 
= m_selectionRange
.GetStart(); 
2582     *to 
= m_selectionRange
.GetEnd(); 
2583     if ((*to
) != -1 && (*to
) != -2) 
2587 bool wxRichTextCtrl::IsEditable() const 
2592 // ---------------------------------------------------------------------------- 
2594 // ---------------------------------------------------------------------------- 
2596 void wxRichTextCtrl::SetSelection(long from
, long to
) 
2598     // if from and to are both -1, it means (in wxWidgets) that all text should 
2600     if ( (from 
== -1) && (to 
== -1) ) 
2603         to 
= GetLastPosition()+1; 
2612         wxRichTextRange oldSelection 
= m_selectionRange
; 
2613         m_selectionAnchor 
= from
-1; 
2614         m_selectionRange
.SetRange(from
, to
-1); 
2616         m_caretPosition 
= wxMax(-1, to
-1); 
2618         RefreshForSelectionChange(oldSelection
, m_selectionRange
); 
2623 // ---------------------------------------------------------------------------- 
2625 // ---------------------------------------------------------------------------- 
2627 void wxRichTextCtrl::Replace(long WXUNUSED(from
), long WXUNUSED(to
), 
2628                              const wxString
& value
) 
2630     BeginBatchUndo(_("Replace")); 
2632     DeleteSelectedContent(); 
2634     DoWriteText(value
, SetValue_SelectionOnly
); 
2639 void wxRichTextCtrl::Remove(long from
, long to
) 
2643     GetBuffer().DeleteRangeWithUndo(wxRichTextRange(from
, to
-1), this); 
2650 bool wxRichTextCtrl::IsModified() const 
2652     return m_buffer
.IsModified(); 
2655 void wxRichTextCtrl::MarkDirty() 
2657     m_buffer
.Modify(true); 
2660 void wxRichTextCtrl::DiscardEdits() 
2662     m_caretPositionForDefaultStyle 
= -2; 
2663     m_buffer
.Modify(false); 
2664     m_buffer
.GetCommandProcessor()->ClearCommands(); 
2667 int wxRichTextCtrl::GetNumberOfLines() const 
2669     return GetBuffer().GetParagraphCount(); 
2672 // ---------------------------------------------------------------------------- 
2673 // Positions <-> coords 
2674 // ---------------------------------------------------------------------------- 
2676 long wxRichTextCtrl::XYToPosition(long x
, long y
) const 
2678     return GetBuffer().XYToPosition(x
, y
); 
2681 bool wxRichTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
2683     return GetBuffer().PositionToXY(pos
, x
, y
); 
2686 // ---------------------------------------------------------------------------- 
2688 // ---------------------------------------------------------------------------- 
2690 void wxRichTextCtrl::ShowPosition(long pos
) 
2692     if (!IsPositionVisible(pos
)) 
2693         ScrollIntoView(pos
-1, WXK_DOWN
); 
2696 int wxRichTextCtrl::GetLineLength(long lineNo
) const 
2698     return GetBuffer().GetParagraphLength(lineNo
); 
2701 wxString 
wxRichTextCtrl::GetLineText(long lineNo
) const 
2703     return GetBuffer().GetParagraphText(lineNo
); 
2706 // ---------------------------------------------------------------------------- 
2708 // ---------------------------------------------------------------------------- 
2710 void wxRichTextCtrl::Undo() 
2714         GetCommandProcessor()->Undo(); 
2718 void wxRichTextCtrl::Redo() 
2722         GetCommandProcessor()->Redo(); 
2726 bool wxRichTextCtrl::CanUndo() const 
2728     return GetCommandProcessor()->CanUndo(); 
2731 bool wxRichTextCtrl::CanRedo() const 
2733     return GetCommandProcessor()->CanRedo(); 
2736 // ---------------------------------------------------------------------------- 
2737 // implementation details 
2738 // ---------------------------------------------------------------------------- 
2740 void wxRichTextCtrl::Command(wxCommandEvent
& event
) 
2742     SetValue(event
.GetString()); 
2743     GetEventHandler()->ProcessEvent(event
); 
2746 void wxRichTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
2748     // By default, load the first file into the text window. 
2749     if (event
.GetNumberOfFiles() > 0) 
2751         LoadFile(event
.GetFiles()[0]); 
2755 wxSize 
wxRichTextCtrl::DoGetBestSize() const 
2757     return wxSize(10, 10); 
2760 // ---------------------------------------------------------------------------- 
2761 // standard handlers for standard edit menu events 
2762 // ---------------------------------------------------------------------------- 
2764 void wxRichTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
2769 void wxRichTextCtrl::OnClear(wxCommandEvent
& WXUNUSED(event
)) 
2774 void wxRichTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
2779 void wxRichTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
2784 void wxRichTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
2789 void wxRichTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
2794 void wxRichTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
2796     event
.Enable( CanCut() ); 
2799 void wxRichTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
2801     event
.Enable( CanCopy() ); 
2804 void wxRichTextCtrl::OnUpdateClear(wxUpdateUIEvent
& event
) 
2806     event
.Enable( CanDeleteSelection() ); 
2809 void wxRichTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
2811     event
.Enable( CanPaste() ); 
2814 void wxRichTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
2816     event
.Enable( CanUndo() ); 
2817     event
.SetText( GetCommandProcessor()->GetUndoMenuLabel() ); 
2820 void wxRichTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
2822     event
.Enable( CanRedo() ); 
2823     event
.SetText( GetCommandProcessor()->GetRedoMenuLabel() ); 
2826 void wxRichTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
2828     if (GetLastPosition() > 0) 
2832 void wxRichTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
2834     event
.Enable(GetLastPosition() > 0); 
2837 void wxRichTextCtrl::OnImage(wxCommandEvent
& WXUNUSED(event
)) 
2839     if (GetCurrentObject() && GetCurrentObject()->CanEditProperties()) 
2840         GetCurrentObject()->EditProperties(this, & GetBuffer());         
2841     SetCurrentObject(NULL
); 
2844 void wxRichTextCtrl::OnUpdateImage(wxUpdateUIEvent
& event
) 
2846     event
.Enable(GetCurrentObject() != NULL 
&& GetCurrentObject()->CanEditProperties()); 
2849 void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent
& event
) 
2851     if (event
.GetEventObject() != this) 
2857     wxClientDC 
dc(this); 
2859     dc
.SetFont(GetFont()); 
2862     wxPoint pt 
= event
.GetPosition(); 
2863     wxPoint logicalPt 
= GetLogicalPoint(ScreenToClient(pt
)); 
2864     int hit 
= GetBuffer().HitTest(dc
, logicalPt
, position
); 
2865     if (hit 
== wxRICHTEXT_HITTEST_ON 
|| hit 
== wxRICHTEXT_HITTEST_BEFORE 
|| hit 
== wxRICHTEXT_HITTEST_AFTER
) 
2867         m_currentObject 
= GetBuffer().GetLeafObjectAtPosition(position
); 
2871         m_currentObject 
= NULL
; 
2875         PopupMenu(m_contextMenu
); 
2879 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
2881     return GetBuffer().SetStyle(wxRichTextRange(start
, end
-1), wxTextAttr(style
)); 
2884 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxTextAttr
& style
) 
2886     return GetBuffer().SetStyle(range
.ToInternal(), style
); 
2889 void wxRichTextCtrl::SetImageStyle(wxRichTextImage 
*image
, const wxRichTextAnchoredObjectAttr
& attr
) 
2891     GetBuffer().SetImageStyle(image
, attr
); 
2894 // extended style setting operation with flags including: 
2895 // wxRICHTEXT_SETSTYLE_WITH_UNDO, wxRICHTEXT_SETSTYLE_OPTIMIZE, wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY. 
2896 // see richtextbuffer.h for more details. 
2898 bool wxRichTextCtrl::SetStyleEx(const wxRichTextRange
& range
, const wxTextAttr
& style
, int flags
) 
2900     return GetBuffer().SetStyle(range
.ToInternal(), style
, flags
); 
2903 bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
2905     return GetBuffer().SetDefaultStyle(wxTextAttr(style
)); 
2908 const wxTextAttr
& wxRichTextCtrl::GetDefaultStyle() const 
2910     return GetBuffer().GetDefaultStyle(); 
2913 bool wxRichTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
2915     return GetBuffer().GetStyle(position
, style
); 
2918 // get the common set of styles for the range 
2919 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxTextAttr
& style
) 
2921     return GetBuffer().GetStyleForRange(range
.ToInternal(), style
); 
2924 /// Get the content (uncombined) attributes for this position. 
2925 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxTextAttr
& style
) 
2927     return GetBuffer().GetUncombinedStyle(position
, style
); 
2930 /// Set font, and also the buffer attributes 
2931 bool wxRichTextCtrl::SetFont(const wxFont
& font
) 
2933     wxTextCtrlBase::SetFont(font
); 
2935     wxTextAttr attr 
= GetBuffer().GetAttributes(); 
2937     GetBuffer().SetBasicStyle(attr
); 
2939     GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2945 /// Transform logical to physical 
2946 wxPoint 
wxRichTextCtrl::GetPhysicalPoint(const wxPoint
& ptLogical
) const 
2949     CalcScrolledPosition(ptLogical
.x
, ptLogical
.y
, & pt
.x
, & pt
.y
); 
2954 /// Transform physical to logical 
2955 wxPoint 
wxRichTextCtrl::GetLogicalPoint(const wxPoint
& ptPhysical
) const 
2958     CalcUnscrolledPosition(ptPhysical
.x
, ptPhysical
.y
, & pt
.x
, & pt
.y
); 
2963 /// Position the caret 
2964 void wxRichTextCtrl::PositionCaret() 
2969     //wxLogDebug(wxT("PositionCaret")); 
2972     if (GetCaretPositionForIndex(GetCaretPosition(), caretRect
)) 
2974         wxPoint newPt 
= caretRect
.GetPosition(); 
2975         wxSize newSz 
= caretRect
.GetSize(); 
2976         wxPoint pt 
= GetPhysicalPoint(newPt
); 
2977         if (GetCaret()->GetPosition() != pt 
|| GetCaret()->GetSize() != newSz
) 
2980             if (GetCaret()->GetSize() != newSz
) 
2981                 GetCaret()->SetSize(newSz
); 
2983             int halfSize 
= newSz
.y
/2; 
2984             // If the caret is beyond the margin, hide it by moving it out of the way 
2985             if (((pt
.y 
+ halfSize
) < GetBuffer().GetTopMargin()) || ((pt
.y 
+ halfSize
) > (GetClientSize().y 
- GetBuffer().GetBottomMargin()))) 
2988             GetCaret()->Move(pt
); 
2994 /// Get the caret height and position for the given character position 
2995 bool wxRichTextCtrl::GetCaretPositionForIndex(long position
, wxRect
& rect
) 
2997     wxClientDC 
dc(this); 
2998     dc
.SetFont(GetFont()); 
3005     if (GetBuffer().FindPosition(dc
, position
, pt
, & height
, m_caretAtLineStart
)) 
3007         // Caret height can't be zero 
3009             height 
= dc
.GetCharHeight(); 
3011         rect 
= wxRect(pt
, wxSize(wxRICHTEXT_DEFAULT_CARET_WIDTH
, height
)); 
3018 /// Gets the line for the visible caret position. If the caret is 
3019 /// shown at the very end of the line, it means the next character is actually 
3020 /// on the following line. So let's get the line we're expecting to find 
3021 /// if this is the case. 
3022 wxRichTextLine
* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPosition
) const 
3024     wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(caretPosition
, true); 
3025     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(caretPosition
, true); 
3028         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
3029         if (caretPosition 
== lineRange
.GetStart()-1 && 
3030             (para
->GetRange().GetStart() != lineRange
.GetStart())) 
3032             if (!m_caretAtLineStart
) 
3033                 line 
= GetBuffer().GetLineAtPosition(caretPosition
-1, true); 
3040 /// Move the caret to the given character position 
3041 bool wxRichTextCtrl::MoveCaret(long pos
, bool showAtLineStart
) 
3043     if (GetBuffer().GetDirty()) 
3046     if (pos 
<= GetBuffer().GetRange().GetEnd()) 
3048         SetCaretPosition(pos
, showAtLineStart
); 
3058 /// Layout the buffer: which we must do before certain operations, such as 
3059 /// setting the caret position. 
3060 bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect
) 
3062     if (GetBuffer().GetDirty() || onlyVisibleRect
) 
3064         wxRect 
availableSpace(GetClientSize()); 
3065         if (availableSpace
.width 
== 0) 
3066             availableSpace
.width 
= 10; 
3067         if (availableSpace
.height 
== 0) 
3068             availableSpace
.height 
= 10; 
3070         int flags 
= wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
; 
3071         if (onlyVisibleRect
) 
3073             flags 
|= wxRICHTEXT_LAYOUT_SPECIFIED_RECT
; 
3074             availableSpace
.SetPosition(GetLogicalPoint(wxPoint(0, 0))); 
3077         wxClientDC 
dc(this); 
3078         dc
.SetFont(GetFont()); 
3082         GetBuffer().Defragment(); 
3083         GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation 
3084         GetBuffer().Layout(dc
, availableSpace
, flags
); 
3085         GetBuffer().SetDirty(false); 
3094 /// Is all of the selection bold? 
3095 bool wxRichTextCtrl::IsSelectionBold() 
3100         wxRichTextRange range 
= GetSelectionRange(); 
3101         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3102         attr
.SetFontWeight(wxFONTWEIGHT_BOLD
); 
3104         return HasCharacterAttributes(range
, attr
); 
3108         // If no selection, then we need to combine current style with default style 
3109         // to see what the effect would be if we started typing. 
3111         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3113         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3114         if (GetStyle(pos
, attr
)) 
3116             if (IsDefaultStyleShowing()) 
3117                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3118             return attr
.GetFontWeight() == wxFONTWEIGHT_BOLD
; 
3124 /// Is all of the selection italics? 
3125 bool wxRichTextCtrl::IsSelectionItalics() 
3129         wxRichTextRange range 
= GetSelectionRange(); 
3131         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3132         attr
.SetFontStyle(wxFONTSTYLE_ITALIC
); 
3134         return HasCharacterAttributes(range
, attr
); 
3138         // If no selection, then we need to combine current style with default style 
3139         // to see what the effect would be if we started typing. 
3141         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3143         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3144         if (GetStyle(pos
, attr
)) 
3146             if (IsDefaultStyleShowing()) 
3147                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3148             return attr
.GetFontStyle() == wxFONTSTYLE_ITALIC
; 
3154 /// Is all of the selection underlined? 
3155 bool wxRichTextCtrl::IsSelectionUnderlined() 
3159         wxRichTextRange range 
= GetSelectionRange(); 
3161         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3162         attr
.SetFontUnderlined(true); 
3164         return HasCharacterAttributes(range
, attr
); 
3168         // If no selection, then we need to combine current style with default style 
3169         // to see what the effect would be if we started typing. 
3171         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3172         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3174         if (GetStyle(pos
, attr
)) 
3176             if (IsDefaultStyleShowing()) 
3177                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
3178             return attr
.GetFontUnderlined(); 
3184 /// Apply bold to the selection 
3185 bool wxRichTextCtrl::ApplyBoldToSelection() 
3188     attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
3189     attr
.SetFontWeight(IsSelectionBold() ? wxFONTWEIGHT_NORMAL 
: wxFONTWEIGHT_BOLD
); 
3192         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
3195         wxRichTextAttr current 
= GetDefaultStyleEx(); 
3196         current
.Apply(attr
); 
3197         SetAndShowDefaultStyle(current
); 
3202 /// Apply italic to the selection 
3203 bool wxRichTextCtrl::ApplyItalicToSelection() 
3206     attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
3207     attr
.SetFontStyle(IsSelectionItalics() ? wxFONTSTYLE_NORMAL 
: wxFONTSTYLE_ITALIC
); 
3210         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
3213         wxRichTextAttr current 
= GetDefaultStyleEx(); 
3214         current
.Apply(attr
); 
3215         SetAndShowDefaultStyle(current
); 
3220 /// Apply underline to the selection 
3221 bool wxRichTextCtrl::ApplyUnderlineToSelection() 
3224     attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
3225     attr
.SetFontUnderlined(!IsSelectionUnderlined()); 
3228         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
3231         wxRichTextAttr current 
= GetDefaultStyleEx(); 
3232         current
.Apply(attr
); 
3233         SetAndShowDefaultStyle(current
); 
3238 /// Is all of the selection aligned according to the specified flag? 
3239 bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment
) 
3241     wxRichTextRange range
; 
3243         range 
= GetSelectionRange(); 
3245         range 
= wxRichTextRange(GetCaretPosition()+1, GetCaretPosition()+2); 
3248     attr
.SetAlignment(alignment
); 
3250     return HasParagraphAttributes(range
, attr
); 
3253 /// Apply alignment to the selection 
3254 bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment
) 
3257     attr
.SetAlignment(alignment
); 
3259         return SetStyle(GetSelectionRange(), attr
); 
3262         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(GetCaretPosition()+1); 
3264             return SetStyleEx(para
->GetRange().FromInternal(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
); 
3269 /// Apply a named style to the selection 
3270 bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition
* def
) 
3272     // Flags are defined within each definition, so only certain 
3273     // attributes are applied. 
3274     wxTextAttr 
attr(GetStyleSheet() ? def
->GetStyleMergedWithBase(GetStyleSheet()) : def
->GetStyle()); 
3276     int flags 
= wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_RESET
; 
3278     if (def
->IsKindOf(CLASSINFO(wxRichTextListStyleDefinition
))) 
3280         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
3282         wxRichTextRange range
; 
3285             range 
= GetSelectionRange(); 
3288             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3289             range 
= wxRichTextRange(pos
, pos
+1); 
3292         return SetListStyle(range
, (wxRichTextListStyleDefinition
*) def
, flags
); 
3295     bool isPara 
= false; 
3297     // Make sure the attr has the style name 
3298     if (def
->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition
))) 
3301         attr
.SetParagraphStyleName(def
->GetName()); 
3303         // If applying a paragraph style, we only want the paragraph nodes to adopt these 
3304         // attributes, and not the leaf nodes. This will allow the content (e.g. text) 
3305         // to change its style independently. 
3306         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
3309         attr
.SetCharacterStyleName(def
->GetName()); 
3312         return SetStyleEx(GetSelectionRange(), attr
, flags
); 
3315         wxTextAttr current 
= GetDefaultStyleEx(); 
3316         wxTextAttr 
defaultStyle(attr
); 
3319             // Don't apply extra character styles since they are already implied 
3320             // in the paragraph style 
3321             defaultStyle
.SetFlags(defaultStyle
.GetFlags() & ~wxTEXT_ATTR_CHARACTER
); 
3323         current
.Apply(defaultStyle
); 
3324         SetAndShowDefaultStyle(current
); 
3326         // If it's a paragraph style, we want to apply the style to the 
3327         // current paragraph even if we didn't select any text. 
3330             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3331             wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(pos
); 
3334                 return SetStyleEx(para
->GetRange().FromInternal(), attr
, flags
); 
3341 /// Apply the style sheet to the buffer, for example if the styles have changed. 
3342 bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet
* styleSheet
) 
3345         styleSheet 
= GetBuffer().GetStyleSheet(); 
3349     if (GetBuffer().ApplyStyleSheet(styleSheet
)) 
3351         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
3359 /// Sets the default style to the style under the cursor 
3360 bool wxRichTextCtrl::SetDefaultStyleToCursorStyle() 
3363     attr
.SetFlags(wxTEXT_ATTR_CHARACTER
); 
3365     // If at the start of a paragraph, use the next position. 
3366     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
3368     if (GetUncombinedStyle(pos
, attr
)) 
3370         SetDefaultStyle(attr
); 
3377 /// Returns the first visible position in the current view 
3378 long wxRichTextCtrl::GetFirstVisiblePosition() const 
3380     wxRichTextLine
* line 
= GetBuffer().GetLineAtYPosition(GetLogicalPoint(wxPoint(0, 0)).y
); 
3382         return line
->GetAbsoluteRange().GetStart(); 
3387 /// Get the first visible point in the window 
3388 wxPoint 
wxRichTextCtrl::GetFirstVisiblePoint() const 
3391     int startXUnits
, startYUnits
; 
3393     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
3394     GetViewStart(& startXUnits
, & startYUnits
); 
3396     return wxPoint(startXUnits 
* ppuX
, startYUnits 
* ppuY
); 
3399 /// The adjusted caret position is the character position adjusted to take 
3400 /// into account whether we're at the start of a paragraph, in which case 
3401 /// style information should be taken from the next position, not current one. 
3402 long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos
) const 
3404     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(caretPos
+1); 
3406     if (para 
&& (caretPos
+1 == para
->GetRange().GetStart())) 
3411 /// Get/set the selection range in character positions. -1, -1 means no selection. 
3412 /// The range is in API convention, i.e. a single character selection is denoted 
3414 wxRichTextRange 
wxRichTextCtrl::GetSelectionRange() const 
3416     wxRichTextRange range 
= GetInternalSelectionRange(); 
3417     if (range 
!= wxRichTextRange(-2,-2) && range 
!= wxRichTextRange(-1,-1)) 
3418         range
.SetEnd(range
.GetEnd() + 1); 
3422 void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange
& range
) 
3424     SetSelection(range
.GetStart(), range
.GetEnd()); 
3428 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3430     return GetBuffer().SetListStyle(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
3433 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
3435     return GetBuffer().SetListStyle(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
3438 /// Clear list for given range 
3439 bool wxRichTextCtrl::ClearListStyle(const wxRichTextRange
& range
, int flags
) 
3441     return GetBuffer().ClearListStyle(range
.ToInternal(), flags
); 
3444 /// Number/renumber any list elements in the given range 
3445 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3447     return GetBuffer().NumberList(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
3450 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
3452     return GetBuffer().NumberList(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
3455 /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 
3456 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int specifiedLevel
) 
3458     return GetBuffer().PromoteList(promoteBy
, range
.ToInternal(), def
, flags
, specifiedLevel
); 
3461 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int specifiedLevel
) 
3463     return GetBuffer().PromoteList(promoteBy
, range
.ToInternal(), defName
, flags
, specifiedLevel
); 
3466 /// Deletes the content in the given range 
3467 bool wxRichTextCtrl::Delete(const wxRichTextRange
& range
) 
3469     return GetBuffer().DeleteRangeWithUndo(range
.ToInternal(), this); 
3472 const wxArrayString
& wxRichTextCtrl::GetAvailableFontNames() 
3474     if (sm_availableFontNames
.GetCount() == 0) 
3476         sm_availableFontNames 
= wxFontEnumerator::GetFacenames(); 
3477         sm_availableFontNames
.Sort(); 
3479     return sm_availableFontNames
; 
3482 void wxRichTextCtrl::ClearAvailableFontNames() 
3484     sm_availableFontNames
.Clear(); 
3487 void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
)) 
3489     //wxLogDebug(wxT("wxRichTextCtrl::OnSysColourChanged")); 
3491     wxTextAttrEx basicStyle 
= GetBasicStyle(); 
3492     basicStyle
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
3493     SetBasicStyle(basicStyle
); 
3494     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
3499 // Refresh the area affected by a selection change 
3500 bool wxRichTextCtrl::RefreshForSelectionChange(const wxRichTextRange
& oldSelection
, const wxRichTextRange
& newSelection
) 
3502     // Calculate the refresh rectangle - just the affected lines 
3503     long firstPos
, lastPos
; 
3504     if (oldSelection
.GetStart() == -2 && newSelection
.GetStart() != -2) 
3506         firstPos 
= newSelection
.GetStart(); 
3507         lastPos 
= newSelection
.GetEnd(); 
3509     else if (oldSelection
.GetStart() != -2 && newSelection
.GetStart() == -2) 
3511         firstPos 
= oldSelection
.GetStart(); 
3512         lastPos 
= oldSelection
.GetEnd(); 
3514     else if (oldSelection
.GetStart() == -2 && newSelection
.GetStart() == -2) 
3520         firstPos 
= wxMin(oldSelection
.GetStart(), newSelection
.GetStart()); 
3521         lastPos 
= wxMax(oldSelection
.GetEnd(), newSelection
.GetEnd()); 
3524     wxRichTextLine
* firstLine 
= GetBuffer().GetLineAtPosition(firstPos
); 
3525     wxRichTextLine
* lastLine 
= GetBuffer().GetLineAtPosition(lastPos
); 
3527     if (firstLine 
&& lastLine
) 
3529         wxSize clientSize 
= GetClientSize(); 
3530         wxPoint pt1 
= GetPhysicalPoint(firstLine
->GetAbsolutePosition()); 
3531         wxPoint pt2 
= GetPhysicalPoint(lastLine
->GetAbsolutePosition()) + wxPoint(0, lastLine
->GetSize().y
); 
3534         pt1
.y 
= wxMax(0, pt1
.y
); 
3536         pt2
.y 
= wxMin(clientSize
.y
, pt2
.y
); 
3538         wxRect 
rect(pt1
, wxSize(clientSize
.x
, pt2
.y 
- pt1
.y
)); 
3539         RefreshRect(rect
, false); 
3547 #if wxRICHTEXT_USE_OWN_CARET 
3549 // ---------------------------------------------------------------------------- 
3550 // initialization and destruction 
3551 // ---------------------------------------------------------------------------- 
3553 void wxRichTextCaret::Init() 
3559     m_richTextCtrl 
= NULL
; 
3560     m_needsUpdate 
= false; 
3564 wxRichTextCaret::~wxRichTextCaret() 
3566     if (m_timer
.IsRunning()) 
3570 // ---------------------------------------------------------------------------- 
3571 // showing/hiding/moving the caret (base class interface) 
3572 // ---------------------------------------------------------------------------- 
3574 void wxRichTextCaret::DoShow() 
3578     if (!m_timer
.IsRunning()) 
3579         m_timer
.Start(GetBlinkTime()); 
3584 void wxRichTextCaret::DoHide() 
3586     if (m_timer
.IsRunning()) 
3592 void wxRichTextCaret::DoMove() 
3598         if (m_xOld 
!= -1 && m_yOld 
!= -1) 
3602                 wxRect 
rect(GetPosition(), GetSize()); 
3603                 m_richTextCtrl
->RefreshRect(rect
, false); 
3612 void wxRichTextCaret::DoSize() 
3614     int countVisible 
= m_countVisible
; 
3615     if (countVisible 
> 0) 
3621     if (countVisible 
> 0) 
3623         m_countVisible 
= countVisible
; 
3628 // ---------------------------------------------------------------------------- 
3629 // handling the focus 
3630 // ---------------------------------------------------------------------------- 
3632 void wxRichTextCaret::OnSetFocus() 
3640 void wxRichTextCaret::OnKillFocus() 
3645 // ---------------------------------------------------------------------------- 
3646 // drawing the caret 
3647 // ---------------------------------------------------------------------------- 
3649 void wxRichTextCaret::Refresh() 
3653         wxRect 
rect(GetPosition(), GetSize()); 
3654         m_richTextCtrl
->RefreshRect(rect
, false); 
3658 void wxRichTextCaret::DoDraw(wxDC 
*dc
) 
3660     dc
->SetPen( *wxBLACK_PEN 
); 
3662     dc
->SetBrush(*(m_hasFocus 
? wxBLACK_BRUSH 
: wxTRANSPARENT_BRUSH
)); 
3663     dc
->SetPen(*wxBLACK_PEN
); 
3665     wxPoint 
pt(m_x
, m_y
); 
3669         pt 
= m_richTextCtrl
->GetLogicalPoint(pt
); 
3671     if (IsVisible() && m_flashOn
) 
3672         dc
->DrawRectangle(pt
.x
, pt
.y
, m_width
, m_height
); 
3675 void wxRichTextCaret::Notify() 
3677     m_flashOn 
= !m_flashOn
; 
3681 void wxRichTextCaretTimer::Notify() 
3686     // wxRICHTEXT_USE_OWN_CARET