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" 
  29 #include "wx/textfile.h" 
  31 #include "wx/filename.h" 
  32 #include "wx/dcbuffer.h" 
  33 #include "wx/arrimpl.cpp" 
  34 #include "wx/fontenum.h" 
  36 // DLL options compatibility check: 
  38 WX_CHECK_BUILD_OPTIONS("wxRichTextCtrl") 
  40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
) 
  41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
) 
  42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
) 
  43 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
) 
  44 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_RETURN
) 
  45 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_CHARACTER
) 
  46 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_DELETE
) 
  48 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING
) 
  49 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED
) 
  50 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING
) 
  51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED
) 
  53 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED
) 
  54 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED
) 
  55 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED
) 
  56 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED
) 
  58 IMPLEMENT_CLASS( wxRichTextCtrl
, wxControl 
) 
  60 IMPLEMENT_CLASS( wxRichTextEvent
, wxNotifyEvent 
) 
  62 BEGIN_EVENT_TABLE( wxRichTextCtrl
, wxControl 
) 
  63     EVT_PAINT(wxRichTextCtrl::OnPaint
) 
  64     EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground
) 
  65     EVT_IDLE(wxRichTextCtrl::OnIdle
) 
  66     EVT_SCROLLWIN(wxRichTextCtrl::OnScroll
) 
  67     EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick
) 
  68     EVT_MOTION(wxRichTextCtrl::OnMoveMouse
) 
  69     EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp
) 
  70     EVT_RIGHT_DOWN(wxRichTextCtrl::OnRightClick
) 
  71     EVT_MIDDLE_DOWN(wxRichTextCtrl::OnMiddleClick
) 
  72     EVT_LEFT_DCLICK(wxRichTextCtrl::OnLeftDClick
) 
  73     EVT_CHAR(wxRichTextCtrl::OnChar
) 
  74     EVT_SIZE(wxRichTextCtrl::OnSize
) 
  75     EVT_SET_FOCUS(wxRichTextCtrl::OnSetFocus
) 
  76     EVT_KILL_FOCUS(wxRichTextCtrl::OnKillFocus
) 
  77     EVT_MOUSE_CAPTURE_LOST(wxRichTextCtrl::OnCaptureLost
) 
  78     EVT_CONTEXT_MENU(wxRichTextCtrl::OnContextMenu
) 
  79     EVT_SYS_COLOUR_CHANGED(wxRichTextCtrl::OnSysColourChanged
) 
  81     EVT_MENU(wxID_UNDO
, wxRichTextCtrl::OnUndo
) 
  82     EVT_UPDATE_UI(wxID_UNDO
, wxRichTextCtrl::OnUpdateUndo
) 
  84     EVT_MENU(wxID_REDO
, wxRichTextCtrl::OnRedo
) 
  85     EVT_UPDATE_UI(wxID_REDO
, wxRichTextCtrl::OnUpdateRedo
) 
  87     EVT_MENU(wxID_COPY
, wxRichTextCtrl::OnCopy
) 
  88     EVT_UPDATE_UI(wxID_COPY
, wxRichTextCtrl::OnUpdateCopy
) 
  90     EVT_MENU(wxID_PASTE
, wxRichTextCtrl::OnPaste
) 
  91     EVT_UPDATE_UI(wxID_PASTE
, wxRichTextCtrl::OnUpdatePaste
) 
  93     EVT_MENU(wxID_CUT
, wxRichTextCtrl::OnCut
) 
  94     EVT_UPDATE_UI(wxID_CUT
, wxRichTextCtrl::OnUpdateCut
) 
  96     EVT_MENU(wxID_CLEAR
, wxRichTextCtrl::OnClear
) 
  97     EVT_UPDATE_UI(wxID_CLEAR
, wxRichTextCtrl::OnUpdateClear
) 
  99     EVT_MENU(wxID_SELECTALL
, wxRichTextCtrl::OnSelectAll
) 
 100     EVT_UPDATE_UI(wxID_SELECTALL
, wxRichTextCtrl::OnUpdateSelectAll
) 
 107 wxArrayString 
wxRichTextCtrl::sm_availableFontNames
; 
 109 wxRichTextCtrl::wxRichTextCtrl() 
 110               : wxScrollHelper(this) 
 115 wxRichTextCtrl::wxRichTextCtrl(wxWindow
* parent
, 
 117                                const wxString
& value
, 
 121                                const wxValidator
& validator
, 
 122                                const wxString
& name
) 
 123               : wxScrollHelper(this) 
 126     Create(parent
, id
, value
, pos
, size
, style
, validator
, name
); 
 130 bool wxRichTextCtrl::Create( wxWindow
* parent
, wxWindowID id
, const wxString
& value
, const wxPoint
& pos
, const wxSize
& size
, long style
, 
 131                              const wxValidator
& validator
, const wxString
& name
) 
 133     if (!wxControl::Create(parent
, id
, pos
, size
, 
 134                            style
|wxFULL_REPAINT_ON_RESIZE
, 
 140         SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 144     GetBuffer().SetRichTextCtrl(this); 
 146     SetCaret(new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH
, 16)); 
 149     if (style 
& wxTE_READONLY
) 
 152     // The base attributes must all have default values 
 153     wxTextAttr attributes
; 
 154     attributes
.SetFont(GetFont()); 
 155     attributes
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
 156     attributes
.SetAlignment(wxTEXT_ALIGNMENT_LEFT
); 
 157     attributes
.SetLineSpacing(10); 
 158     attributes
.SetParagraphSpacingAfter(10); 
 159     attributes
.SetParagraphSpacingBefore(0); 
 160     attributes
.SetTextEffects(0); 
 161     attributes
.SetTextEffectFlags(wxTEXT_ATTR_EFFECT_STRIKETHROUGH
|wxTEXT_ATTR_EFFECT_CAPITALS
); 
 163     SetBasicStyle(attributes
); 
 165     // The default attributes will be merged with base attributes, so 
 166     // can be empty to begin with 
 167     wxTextAttr defaultAttributes
; 
 168     SetDefaultStyle(defaultAttributes
); 
 170     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 171     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 173     // Tell the sizers to use the given or best size 
 174     SetInitialSize(size
); 
 176 #if wxRICHTEXT_BUFFERED_PAINTING 
 178     RecreateBuffer(size
); 
 181     m_textCursor 
= wxCursor(wxCURSOR_IBEAM
); 
 182     m_urlCursor 
= wxCursor(wxCURSOR_HAND
); 
 184     SetCursor(m_textCursor
); 
 186     if (!value
.IsEmpty()) 
 189     GetBuffer().AddEventHandler(this); 
 194 wxRichTextCtrl::~wxRichTextCtrl() 
 196     GetBuffer().RemoveEventHandler(this); 
 198     delete m_contextMenu
; 
 201 /// Member initialisation 
 202 void wxRichTextCtrl::Init() 
 205     m_contextMenu 
= NULL
; 
 207     m_caretPosition 
= -1; 
 208     m_selectionRange
.SetRange(-2, -2); 
 209     m_selectionAnchor 
= -2; 
 211     m_caretAtLineStart 
= false; 
 213     m_fullLayoutRequired 
= false; 
 214     m_fullLayoutTime 
= 0; 
 215     m_fullLayoutSavedPosition 
= 0; 
 216     m_delayedLayoutThreshold 
= wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD
; 
 217     m_caretPositionForDefaultStyle 
= -2; 
 220 /// Call Freeze to prevent refresh 
 221 void wxRichTextCtrl::Freeze() 
 226 /// Call Thaw to refresh 
 227 void wxRichTextCtrl::Thaw() 
 231     if (m_freezeCount 
== 0) 
 233         if (GetBuffer().GetDirty()) 
 242 void wxRichTextCtrl::Clear() 
 244     m_buffer
.ResetAndClearCommands(); 
 245     m_buffer
.SetDirty(true); 
 246     m_caretPosition 
= -1; 
 247     m_caretPositionForDefaultStyle 
= -2; 
 248     m_caretAtLineStart 
= false; 
 249     m_selectionRange
.SetRange(-2, -2); 
 251     if (m_freezeCount 
== 0) 
 257     wxTextCtrl::SendTextUpdatedEvent(this); 
 261 void wxRichTextCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 263     if (GetCaret() && GetCaret()->IsVisible()) 
 267 #if wxRICHTEXT_BUFFERED_PAINTING 
 268         wxBufferedPaintDC 
dc(this, m_bufferBitmap
); 
 274         if (m_freezeCount 
> 0) 
 277         dc
.SetFont(GetFont()); 
 279         // Paint the background 
 282         // wxRect drawingArea(GetLogicalPoint(wxPoint(0, 0)), GetClientSize()); 
 284         wxRect 
drawingArea(GetUpdateRegion().GetBox()); 
 285         drawingArea
.SetPosition(GetLogicalPoint(drawingArea
.GetPosition())); 
 287         wxRect 
availableSpace(GetClientSize()); 
 288         if (GetBuffer().GetDirty()) 
 290             GetBuffer().Layout(dc
, availableSpace
, wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
); 
 291             GetBuffer().SetDirty(false); 
 295         GetBuffer().Draw(dc
, GetBuffer().GetRange(), GetInternalSelectionRange(), drawingArea
, 0 /* descent */, 0 /* flags */); 
 298     if (GetCaret() && !GetCaret()->IsVisible()) 
 304 // Empty implementation, to prevent flicker 
 305 void wxRichTextCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 309 void wxRichTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
 313         if (!GetCaret()->IsVisible()) 
 322 void wxRichTextCtrl::OnKillFocus(wxFocusEvent
& WXUNUSED(event
)) 
 324     if (GetCaret() && GetCaret()->IsVisible()) 
 331 void wxRichTextCtrl::OnCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
 337 void wxRichTextCtrl::OnLeftClick(wxMouseEvent
& event
) 
 343     dc
.SetFont(GetFont()); 
 346     int hit 
= GetBuffer().HitTest(dc
, event
.GetLogicalPosition(dc
), position
); 
 348     if (hit 
!= wxRICHTEXT_HITTEST_NONE
) 
 350         m_dragStart 
= event
.GetLogicalPosition(dc
); 
 356         bool caretAtLineStart 
= false; 
 358         if (hit 
& wxRICHTEXT_HITTEST_BEFORE
) 
 360             // If we're at the start of a line (but not first in para) 
 361             // then we should keep the caret showing at the start of the line 
 362             // by showing the m_caretAtLineStart flag. 
 363             wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(position
); 
 364             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(position
); 
 366             if (line 
&& para 
&& line
->GetAbsoluteRange().GetStart() == position 
&& para
->GetRange().GetStart() != position
) 
 367                 caretAtLineStart 
= true; 
 371         MoveCaret(position
, caretAtLineStart
); 
 372         SetDefaultStyleToCursorStyle(); 
 379 void wxRichTextCtrl::OnLeftUp(wxMouseEvent
& event
) 
 384         if (GetCapture() == this) 
 387         // See if we clicked on a URL 
 390         dc
.SetFont(GetFont()); 
 393         wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 394         int hit 
= GetBuffer().HitTest(dc
, logicalPt
, position
); 
 396         if (hit 
!= wxRICHTEXT_HITTEST_NONE
) 
 398             wxRichTextEvent 
cmdEvent( 
 399                 wxEVT_COMMAND_RICHTEXT_LEFT_CLICK
, 
 401             cmdEvent
.SetEventObject(this); 
 402             cmdEvent
.SetPosition(m_caretPosition
+1); 
 404             if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 407                 if (GetStyle(position
, attr
)) 
 409                     if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 411                         wxString urlTarget 
= attr
.GetURL(); 
 412                         if (!urlTarget
.IsEmpty()) 
 414                             wxMouseEvent 
mouseEvent(event
); 
 416                             long startPos 
= 0, endPos 
= 0; 
 417                             wxRichTextObject
* obj 
= GetBuffer().GetLeafObjectAtPosition(position
); 
 420                                 startPos 
= obj
->GetRange().GetStart(); 
 421                                 endPos 
= obj
->GetRange().GetEnd(); 
 424                             wxTextUrlEvent 
urlEvent(GetId(), mouseEvent
, startPos
, endPos
); 
 425                             InitCommandEvent(urlEvent
); 
 427                             urlEvent
.SetString(urlTarget
); 
 429                             GetEventHandler()->ProcessEvent(urlEvent
); 
 439 void wxRichTextCtrl::OnMoveMouse(wxMouseEvent
& event
) 
 443     dc
.SetFont(GetFont()); 
 446     wxPoint logicalPt 
= event
.GetLogicalPosition(dc
); 
 447     int hit 
= GetBuffer().HitTest(dc
, logicalPt
, position
); 
 449     // See if we need to change the cursor 
 452         if (hit 
!= wxRICHTEXT_HITTEST_NONE 
&& !(hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
 455             if (GetStyle(position
, attr
)) 
 457                 if (attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 459                     SetCursor(m_urlCursor
); 
 461                 else if (!attr
.HasFlag(wxTEXT_ATTR_URL
)) 
 463                     SetCursor(m_textCursor
); 
 468             SetCursor(m_textCursor
); 
 471     if (!event
.Dragging()) 
 477     if (m_dragging 
&& hit 
!= wxRICHTEXT_HITTEST_NONE
) 
 479         // TODO: test closeness 
 481         bool caretAtLineStart 
= false; 
 483         if (hit 
& wxRICHTEXT_HITTEST_BEFORE
) 
 485             // If we're at the start of a line (but not first in para) 
 486             // then we should keep the caret showing at the start of the line 
 487             // by showing the m_caretAtLineStart flag. 
 488             wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(position
); 
 489             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(position
); 
 491             if (line 
&& para 
&& line
->GetAbsoluteRange().GetStart() == position 
&& para
->GetRange().GetStart() != position
) 
 492                 caretAtLineStart 
= true; 
 496         if (m_caretPosition 
!= position
) 
 498             bool extendSel 
= ExtendSelection(m_caretPosition
, position
, wxRICHTEXT_SHIFT_DOWN
); 
 500             MoveCaret(position
, caretAtLineStart
); 
 501             SetDefaultStyleToCursorStyle(); 
 510 void wxRichTextCtrl::OnRightClick(wxMouseEvent
& event
) 
 514     wxRichTextEvent 
cmdEvent( 
 515         wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK
, 
 517     cmdEvent
.SetEventObject(this); 
 518     cmdEvent
.SetPosition(m_caretPosition
+1); 
 520     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 524 /// Left-double-click 
 525 void wxRichTextCtrl::OnLeftDClick(wxMouseEvent
& WXUNUSED(event
)) 
 527     wxRichTextEvent 
cmdEvent( 
 528         wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK
, 
 530     cmdEvent
.SetEventObject(this); 
 531     cmdEvent
.SetPosition(m_caretPosition
+1); 
 533     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 535         SelectWord(GetCaretPosition()+1); 
 540 void wxRichTextCtrl::OnMiddleClick(wxMouseEvent
& event
) 
 542     wxRichTextEvent 
cmdEvent( 
 543         wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK
, 
 545     cmdEvent
.SetEventObject(this); 
 546     cmdEvent
.SetPosition(m_caretPosition
+1); 
 548     if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 553 void wxRichTextCtrl::OnChar(wxKeyEvent
& event
) 
 557         flags 
|= wxRICHTEXT_CTRL_DOWN
; 
 558     if (event
.ShiftDown()) 
 559         flags 
|= wxRICHTEXT_SHIFT_DOWN
; 
 561         flags 
|= wxRICHTEXT_ALT_DOWN
; 
 563     if (event
.GetKeyCode() == WXK_LEFT 
|| 
 564         event
.GetKeyCode() == WXK_RIGHT 
|| 
 565         event
.GetKeyCode() == WXK_UP 
|| 
 566         event
.GetKeyCode() == WXK_DOWN 
|| 
 567         event
.GetKeyCode() == WXK_HOME 
|| 
 568         event
.GetKeyCode() == WXK_PAGEUP 
|| 
 569         event
.GetKeyCode() == WXK_PAGEDOWN 
|| 
 570         event
.GetKeyCode() == WXK_END 
|| 
 572         event
.GetKeyCode() == WXK_NUMPAD_LEFT 
|| 
 573         event
.GetKeyCode() == WXK_NUMPAD_RIGHT 
|| 
 574         event
.GetKeyCode() == WXK_NUMPAD_UP 
|| 
 575         event
.GetKeyCode() == WXK_NUMPAD_DOWN 
|| 
 576         event
.GetKeyCode() == WXK_NUMPAD_HOME 
|| 
 577         event
.GetKeyCode() == WXK_NUMPAD_PAGEUP 
|| 
 578         event
.GetKeyCode() == WXK_NUMPAD_PAGEDOWN 
|| 
 579         event
.GetKeyCode() == WXK_NUMPAD_END
) 
 581         KeyboardNavigate(event
.GetKeyCode(), flags
); 
 585     // all the other keys modify the controls contents which shouldn't be 
 586     // possible if we're read-only 
 593     if (event
.GetKeyCode() == WXK_RETURN
) 
 595         BeginBatchUndo(_("Insert Text")); 
 597         long newPos 
= m_caretPosition
; 
 599         DeleteSelectedContent(& newPos
); 
 601         if (event
.ShiftDown()) 
 604             text 
= wxRichTextLineBreakChar
; 
 605             GetBuffer().InsertTextWithUndo(newPos
+1, text
, this); 
 608             GetBuffer().InsertNewlineWithUndo(newPos
+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
 611         SetDefaultStyleToCursorStyle(); 
 613         ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
 615         wxRichTextEvent 
cmdEvent( 
 616             wxEVT_COMMAND_RICHTEXT_RETURN
, 
 618         cmdEvent
.SetEventObject(this); 
 619         cmdEvent
.SetFlags(flags
); 
 620         cmdEvent
.SetPosition(newPos
+1); 
 622         if (!GetEventHandler()->ProcessEvent(cmdEvent
)) 
 624             // Generate conventional event 
 625             wxCommandEvent 
textEvent(wxEVT_COMMAND_TEXT_ENTER
, GetId()); 
 626             InitCommandEvent(textEvent
); 
 628             GetEventHandler()->ProcessEvent(textEvent
); 
 632     else if (event
.GetKeyCode() == WXK_BACK
) 
 634         BeginBatchUndo(_("Delete Text")); 
 636         // Submit range in character positions, which are greater than caret positions, 
 637         // so subtract 1 for deleted character and add 1 for conversion to character position. 
 638         if (m_caretPosition 
> -1 && !HasSelection()) 
 640             GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition
, m_caretPosition
), this); 
 643             DeleteSelectedContent(); 
 647         if (GetLastPosition() == -1) 
 651             m_caretPosition 
= -1; 
 653             SetDefaultStyleToCursorStyle(); 
 656         ScrollIntoView(m_caretPosition
, WXK_LEFT
); 
 658         wxRichTextEvent 
cmdEvent( 
 659             wxEVT_COMMAND_RICHTEXT_DELETE
, 
 661         cmdEvent
.SetEventObject(this); 
 662         cmdEvent
.SetFlags(flags
); 
 663         cmdEvent
.SetPosition(m_caretPosition
+1); 
 664         GetEventHandler()->ProcessEvent(cmdEvent
); 
 668     else if (event
.GetKeyCode() == WXK_DELETE
) 
 670         BeginBatchUndo(_("Delete Text")); 
 672         // Submit range in character positions, which are greater than caret positions, 
 673         if (m_caretPosition 
< GetBuffer().GetRange().GetEnd()+1 && !HasSelection()) 
 675             GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition
+1, m_caretPosition
+1), this); 
 678             DeleteSelectedContent(); 
 682         if (GetLastPosition() == -1) 
 686             m_caretPosition 
= -1; 
 688             SetDefaultStyleToCursorStyle(); 
 691         wxRichTextEvent 
cmdEvent( 
 692             wxEVT_COMMAND_RICHTEXT_DELETE
, 
 694         cmdEvent
.SetEventObject(this); 
 695         cmdEvent
.SetFlags(flags
); 
 696         cmdEvent
.SetPosition(m_caretPosition
+1); 
 697         GetEventHandler()->ProcessEvent(cmdEvent
); 
 703         long keycode 
= event
.GetKeyCode(); 
 776             case WXK_NUMPAD_SPACE
: 
 778             case WXK_NUMPAD_ENTER
: 
 783             case WXK_NUMPAD_HOME
: 
 784             case WXK_NUMPAD_LEFT
: 
 786             case WXK_NUMPAD_RIGHT
: 
 787             case WXK_NUMPAD_DOWN
: 
 788             case WXK_NUMPAD_PAGEUP
: 
 789             case WXK_NUMPAD_PAGEDOWN
: 
 791             case WXK_NUMPAD_BEGIN
: 
 792             case WXK_NUMPAD_INSERT
: 
 793             case WXK_NUMPAD_DELETE
: 
 794             case WXK_NUMPAD_EQUAL
: 
 795             case WXK_NUMPAD_MULTIPLY
: 
 797             case WXK_NUMPAD_SEPARATOR
: 
 798             case WXK_NUMPAD_SUBTRACT
: 
 799             case WXK_NUMPAD_DECIMAL
: 
 800             case WXK_WINDOWS_LEFT
: 
 808                 if (event
.CmdDown() || event
.AltDown()) 
 814                 wxRichTextEvent 
cmdEvent( 
 815                     wxEVT_COMMAND_RICHTEXT_CHARACTER
, 
 817                 cmdEvent
.SetEventObject(this); 
 818                 cmdEvent
.SetFlags(flags
); 
 820                 cmdEvent
.SetCharacter(event
.GetUnicodeKey()); 
 822                 cmdEvent
.SetCharacter((wxChar
) keycode
); 
 824                 cmdEvent
.SetPosition(m_caretPosition
+1); 
 826                 if (keycode 
== wxT('\t')) 
 828                     // See if we need to promote or demote the selection or paragraph at the cursor 
 829                     // position, instead of inserting a tab. 
 830                     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
 831                     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(pos
); 
 832                     if (para 
&& para
->GetRange().GetStart() == pos 
&& para
->GetAttributes().HasListStyleName()) 
 834                         wxRichTextRange range
; 
 836                             range 
= GetSelectionRange(); 
 838                             range 
= para
->GetRange().FromInternal(); 
 840                         int promoteBy 
= event
.ShiftDown() ? 1 : -1; 
 842                         PromoteList(promoteBy
, range
, NULL
); 
 844                         GetEventHandler()->ProcessEvent(cmdEvent
); 
 850                 BeginBatchUndo(_("Insert Text")); 
 852                 long newPos 
= m_caretPosition
; 
 853                 DeleteSelectedContent(& newPos
); 
 856                 wxString str 
= event
.GetUnicodeKey(); 
 858                 wxString str 
= (wxChar
) event
.GetKeyCode(); 
 860                 GetBuffer().InsertTextWithUndo(newPos
+1, str
, this, 0); 
 864                 SetDefaultStyleToCursorStyle(); 
 865                 ScrollIntoView(m_caretPosition
, WXK_RIGHT
); 
 867                 GetEventHandler()->ProcessEvent(cmdEvent
); 
 875 /// Delete content if there is a selection, e.g. when pressing a key. 
 876 bool wxRichTextCtrl::DeleteSelectedContent(long* newPos
) 
 880         long pos 
= m_selectionRange
.GetStart(); 
 881         GetBuffer().DeleteRangeWithUndo(m_selectionRange
, this); 
 882         m_selectionRange
.SetRange(-2, -2); 
 892 /// Keyboard navigation 
 896 Left:       left one character 
 897 Right:      right one character 
 900 Ctrl-Left:  left one word 
 901 Ctrl-Right: right one word 
 902 Ctrl-Up:    previous paragraph start 
 903 Ctrl-Down:  next start of paragraph 
 906 Ctrl-Home:  start of document 
 907 Ctrl-End:   end of document 
 909 Page-Down:  Down a screen 
 913 Ctrl-Alt-PgUp: Start of window 
 914 Ctrl-Alt-PgDn: End of window 
 915 F8:         Start selection mode 
 916 Esc:        End selection mode 
 918 Adding Shift does the above but starts/extends selection. 
 923 bool wxRichTextCtrl::KeyboardNavigate(int keyCode
, int flags
) 
 925     bool success 
= false; 
 927     if (keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT
) 
 929         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
 930             success 
= WordRight(1, flags
); 
 932             success 
= MoveRight(1, flags
); 
 934     else if (keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT
) 
 936         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
 937             success 
= WordLeft(1, flags
); 
 939             success 
= MoveLeft(1, flags
); 
 941     else if (keyCode 
== WXK_UP 
|| keyCode 
== WXK_NUMPAD_UP
) 
 943         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
 944             success 
= MoveToParagraphStart(flags
); 
 946             success 
= MoveUp(1, flags
); 
 948     else if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN
) 
 950         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
 951             success 
= MoveToParagraphEnd(flags
); 
 953             success 
= MoveDown(1, flags
); 
 955     else if (keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP
) 
 957         success 
= PageUp(1, flags
); 
 959     else if (keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
 961         success 
= PageDown(1, flags
); 
 963     else if (keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME
) 
 965         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
 966             success 
= MoveHome(flags
); 
 968             success 
= MoveToLineStart(flags
); 
 970     else if (keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END
) 
 972         if (flags 
& wxRICHTEXT_CTRL_DOWN
) 
 973             success 
= MoveEnd(flags
); 
 975             success 
= MoveToLineEnd(flags
); 
 980         ScrollIntoView(m_caretPosition
, keyCode
); 
 981         SetDefaultStyleToCursorStyle(); 
 987 /// Extend the selection. Selections are in caret positions. 
 988 bool wxRichTextCtrl::ExtendSelection(long oldPos
, long newPos
, int flags
) 
 990     if (flags 
& wxRICHTEXT_SHIFT_DOWN
) 
 992         // If not currently selecting, start selecting 
 993         if (m_selectionRange
.GetStart() == -2) 
 995             m_selectionAnchor 
= oldPos
; 
 998                 m_selectionRange
.SetRange(newPos
+1, oldPos
); 
1000                 m_selectionRange
.SetRange(oldPos
+1, newPos
); 
1004             // Always ensure that the selection range start is greater than 
1006             if (newPos 
> m_selectionAnchor
) 
1007                 m_selectionRange
.SetRange(m_selectionAnchor
+1, newPos
); 
1009                 m_selectionRange
.SetRange(newPos
+1, m_selectionAnchor
); 
1012         if (m_selectionRange
.GetStart() > m_selectionRange
.GetEnd()) 
1014             wxLogDebug(wxT("Strange selection range")); 
1023 /// Scroll into view, returning true if we scrolled. 
1024 /// This takes a _caret_ position. 
1025 bool wxRichTextCtrl::ScrollIntoView(long position
, int keyCode
) 
1027     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(position
); 
1033     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1035     int startXUnits
, startYUnits
; 
1036     GetViewStart(& startXUnits
, & startYUnits
); 
1037     int startY 
= startYUnits 
* ppuY
; 
1040     GetVirtualSize(& sx
, & sy
); 
1046     wxRect rect 
= line
->GetRect(); 
1048     bool scrolled 
= false; 
1050     wxSize clientSize 
= GetClientSize(); 
1053     if (keyCode 
== WXK_DOWN 
|| keyCode 
== WXK_NUMPAD_DOWN 
|| 
1054         keyCode 
== WXK_RIGHT 
|| keyCode 
== WXK_NUMPAD_RIGHT 
|| 
1055         keyCode 
== WXK_END 
|| keyCode 
== WXK_NUMPAD_END 
|| 
1056         keyCode 
== WXK_PAGEDOWN 
|| keyCode 
== WXK_NUMPAD_PAGEDOWN
) 
1058         if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1060             // Make it scroll so this item is at the bottom 
1062             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1063             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1065             // If we're still off the screen, scroll another line down 
1066             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1069             if (startYUnits 
!= yUnits
) 
1071                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1075         else if (rect
.y 
< startY
) 
1077             // Make it scroll so this item is at the top 
1080             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1082             if (startYUnits 
!= yUnits
) 
1084                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1090     else if (keyCode 
== WXK_UP  
|| keyCode 
== WXK_NUMPAD_UP 
|| 
1091              keyCode 
== WXK_LEFT 
|| keyCode 
== WXK_NUMPAD_LEFT 
|| 
1092              keyCode 
== WXK_HOME 
|| keyCode 
== WXK_NUMPAD_HOME 
|| 
1093              keyCode 
== WXK_PAGEUP 
|| keyCode 
== WXK_NUMPAD_PAGEUP 
) 
1095         if (rect
.y 
< startY
) 
1097             // Make it scroll so this item is at the top 
1100             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1102             if (startYUnits 
!= yUnits
) 
1104                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1108         else if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ startY
)) 
1110             // Make it scroll so this item is at the bottom 
1112             int y 
= rect
.y 
- (clientSize
.y 
- rect
.height
); 
1113             int yUnits 
= (int) (0.5 + ((float) y
)/(float) ppuY
); 
1115             // If we're still off the screen, scroll another line down 
1116             if ((rect
.y 
+ rect
.height
) > (clientSize
.y 
+ (yUnits
*ppuY
))) 
1119             if (startYUnits 
!= yUnits
) 
1121                 SetScrollbars(ppuX
, ppuY
, sxUnits
, syUnits
, 0, yUnits
); 
1131 /// Is the given position visible on the screen? 
1132 bool wxRichTextCtrl::IsPositionVisible(long pos
) const 
1134     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(pos
-1); 
1140     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
1143     GetViewStart(& startX
, & startY
); 
1145     startY 
= startY 
* ppuY
; 
1147     wxRect rect 
= line
->GetRect(); 
1148     wxSize clientSize 
= GetClientSize(); 
1150     return (rect
.GetBottom() > startY
) && (rect
.GetTop() < (startY 
+ clientSize
.y
)); 
1153 void wxRichTextCtrl::SetCaretPosition(long position
, bool showAtLineStart
) 
1155     m_caretPosition 
= position
; 
1156     m_caretAtLineStart 
= showAtLineStart
; 
1159 /// Move caret one visual step forward: this may mean setting a flag 
1160 /// and keeping the same position if we're going from the end of one line 
1161 /// to the start of the next, which may be the exact same caret position. 
1162 void wxRichTextCtrl::MoveCaretForward(long oldPosition
) 
1164     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(oldPosition
); 
1166     // Only do the check if we're not at the end of the paragraph (where things work OK 
1168     if (para 
&& (oldPosition 
!= para
->GetRange().GetEnd() - 1)) 
1170         wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(oldPosition
); 
1174             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1176             // We're at the end of a line. See whether we need to 
1177             // stay at the same actual caret position but change visual 
1178             // position, or not. 
1179             if (oldPosition 
== lineRange
.GetEnd()) 
1181                 if (m_caretAtLineStart
) 
1183                     // We're already at the start of the line, so actually move on now. 
1184                     m_caretPosition 
= oldPosition 
+ 1; 
1185                     m_caretAtLineStart 
= false; 
1189                     // We're showing at the end of the line, so keep to 
1190                     // the same position but indicate that we're to show 
1191                     // at the start of the next line. 
1192                     m_caretPosition 
= oldPosition
; 
1193                     m_caretAtLineStart 
= true; 
1195                 SetDefaultStyleToCursorStyle(); 
1201     SetDefaultStyleToCursorStyle(); 
1204 /// Move caret one visual step backward: this may mean setting a flag 
1205 /// and keeping the same position if we're going from the end of one line 
1206 /// to the start of the next, which may be the exact same caret position. 
1207 void wxRichTextCtrl::MoveCaretBack(long oldPosition
) 
1209     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(oldPosition
); 
1211     // Only do the check if we're not at the start of the paragraph (where things work OK 
1213     if (para 
&& (oldPosition 
!= para
->GetRange().GetStart())) 
1215         wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(oldPosition
); 
1219             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1221             // We're at the start of a line. See whether we need to 
1222             // stay at the same actual caret position but change visual 
1223             // position, or not. 
1224             if (oldPosition 
== lineRange
.GetStart()) 
1226                 m_caretPosition 
= oldPosition
-1; 
1227                 m_caretAtLineStart 
= true; 
1230             else if (oldPosition 
== lineRange
.GetEnd()) 
1232                 if (m_caretAtLineStart
) 
1234                     // We're at the start of the line, so keep the same caret position 
1235                     // but clear the start-of-line flag. 
1236                     m_caretPosition 
= oldPosition
; 
1237                     m_caretAtLineStart 
= false; 
1241                     // We're showing at the end of the line, so go back 
1242                     // to the previous character position. 
1243                     m_caretPosition 
= oldPosition 
- 1; 
1245                 SetDefaultStyleToCursorStyle(); 
1251     SetDefaultStyleToCursorStyle(); 
1255 bool wxRichTextCtrl::MoveRight(int noPositions
, int flags
) 
1257     long endPos 
= GetBuffer().GetRange().GetEnd(); 
1259     if (m_caretPosition 
+ noPositions 
< endPos
) 
1261         long oldPos 
= m_caretPosition
; 
1262         long newPos 
= m_caretPosition 
+ noPositions
; 
1264         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1268         // Determine by looking at oldPos and m_caretPosition whether 
1269         // we moved from the end of a line to the start of the next line, in which case 
1270         // we want to adjust the caret position such that it is positioned at the 
1271         // start of the next line, rather than jumping past the first character of the 
1273         if (noPositions 
== 1 && !extendSel
) 
1274             MoveCaretForward(oldPos
); 
1276             SetCaretPosition(newPos
); 
1279         SetDefaultStyleToCursorStyle(); 
1290 bool wxRichTextCtrl::MoveLeft(int noPositions
, int flags
) 
1294     if (m_caretPosition 
> startPos 
- noPositions 
+ 1) 
1296         long oldPos 
= m_caretPosition
; 
1297         long newPos 
= m_caretPosition 
- noPositions
; 
1298         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1302         if (noPositions 
== 1 && !extendSel
) 
1303             MoveCaretBack(oldPos
); 
1305             SetCaretPosition(newPos
); 
1308         SetDefaultStyleToCursorStyle(); 
1319 bool wxRichTextCtrl::MoveUp(int noLines
, int flags
) 
1321     return MoveDown(- noLines
, flags
); 
1325 bool wxRichTextCtrl::MoveDown(int noLines
, int flags
) 
1330     long lineNumber 
= GetBuffer().GetVisibleLineNumber(m_caretPosition
, true, m_caretAtLineStart
); 
1331     wxPoint pt 
= GetCaret()->GetPosition(); 
1332     long newLine 
= lineNumber 
+ noLines
; 
1334     if (lineNumber 
!= -1) 
1338             long lastLine 
= GetBuffer().GetVisibleLineNumber(GetBuffer().GetRange().GetEnd()); 
1340             if (newLine 
> lastLine
) 
1350     wxRichTextLine
* lineObj 
= GetBuffer().GetLineForVisibleLineNumber(newLine
); 
1353         pt
.y 
= lineObj
->GetAbsolutePosition().y 
+ 2; 
1359     wxClientDC 
dc(this); 
1361     dc
.SetFont(GetFont()); 
1363     int hitTest 
= GetBuffer().HitTest(dc
, pt
, newPos
); 
1365     if (hitTest 
!= wxRICHTEXT_HITTEST_NONE
) 
1367         // If end of previous line, and hitTest is wxRICHTEXT_HITTEST_BEFORE, 
1368         // we want to be at the end of the last line but with m_caretAtLineStart set to true, 
1369         // so we view the caret at the start of the line. 
1370         bool caretLineStart 
= false; 
1371         if (hitTest 
& wxRICHTEXT_HITTEST_BEFORE
) 
1373             wxRichTextLine
* thisLine 
= GetBuffer().GetLineAtPosition(newPos
-1); 
1374             wxRichTextRange lineRange
; 
1376                 lineRange 
= thisLine
->GetAbsoluteRange(); 
1378             if (thisLine 
&& (newPos
-1) == lineRange
.GetEnd()) 
1381                 caretLineStart 
= true; 
1385                 wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(newPos
); 
1386                 if (para 
&& para
->GetRange().GetStart() == newPos
) 
1391         long newSelEnd 
= newPos
; 
1393         bool extendSel 
= ExtendSelection(m_caretPosition
, newSelEnd
, flags
); 
1397         SetCaretPosition(newPos
, caretLineStart
); 
1399         SetDefaultStyleToCursorStyle(); 
1409 /// Move to the end of the paragraph 
1410 bool wxRichTextCtrl::MoveToParagraphEnd(int flags
) 
1412     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(m_caretPosition
, true); 
1415         long newPos 
= para
->GetRange().GetEnd() - 1; 
1416         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1420         SetCaretPosition(newPos
); 
1422         SetDefaultStyleToCursorStyle(); 
1432 /// Move to the start of the paragraph 
1433 bool wxRichTextCtrl::MoveToParagraphStart(int flags
) 
1435     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(m_caretPosition
, true); 
1438         long newPos 
= para
->GetRange().GetStart() - 1; 
1439         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1443         SetCaretPosition(newPos
); 
1445         SetDefaultStyleToCursorStyle(); 
1455 /// Move to the end of the line 
1456 bool wxRichTextCtrl::MoveToLineEnd(int flags
) 
1458     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1462         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1463         long newPos 
= lineRange
.GetEnd(); 
1464         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1468         SetCaretPosition(newPos
); 
1470         SetDefaultStyleToCursorStyle(); 
1480 /// Move to the start of the line 
1481 bool wxRichTextCtrl::MoveToLineStart(int flags
) 
1483     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1486         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1487         long newPos 
= lineRange
.GetStart()-1; 
1489         bool extendSel 
= ExtendSelection(m_caretPosition
, newPos
, flags
); 
1493         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphForLine(line
); 
1495         SetCaretPosition(newPos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
1497         SetDefaultStyleToCursorStyle(); 
1507 /// Move to the start of the buffer 
1508 bool wxRichTextCtrl::MoveHome(int flags
) 
1510     if (m_caretPosition 
!= -1) 
1512         bool extendSel 
= ExtendSelection(m_caretPosition
, -1, flags
); 
1516         SetCaretPosition(-1); 
1518         SetDefaultStyleToCursorStyle(); 
1528 /// Move to the end of the buffer 
1529 bool wxRichTextCtrl::MoveEnd(int flags
) 
1531     long endPos 
= GetBuffer().GetRange().GetEnd()-1; 
1533     if (m_caretPosition 
!= endPos
) 
1535         bool extendSel 
= ExtendSelection(m_caretPosition
, endPos
, flags
); 
1539         SetCaretPosition(endPos
); 
1541         SetDefaultStyleToCursorStyle(); 
1551 /// Move noPages pages up 
1552 bool wxRichTextCtrl::PageUp(int noPages
, int flags
) 
1554     return PageDown(- noPages
, flags
); 
1557 /// Move noPages pages down 
1558 bool wxRichTextCtrl::PageDown(int noPages
, int flags
) 
1560     // Calculate which line occurs noPages * screen height further down. 
1561     wxRichTextLine
* line 
= GetVisibleLineForCaretPosition(m_caretPosition
); 
1564         wxSize clientSize 
= GetClientSize(); 
1565         int newY 
= line
->GetAbsolutePosition().y 
+ noPages
*clientSize
.y
; 
1567         wxRichTextLine
* newLine 
= GetBuffer().GetLineAtYPosition(newY
); 
1570             wxRichTextRange lineRange 
= newLine
->GetAbsoluteRange(); 
1571             long pos 
= lineRange
.GetStart()-1; 
1572             if (pos 
!= m_caretPosition
) 
1574                 wxRichTextParagraph
* para 
= GetBuffer().GetParagraphForLine(newLine
); 
1576                 bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
1580                 SetCaretPosition(pos
, para
->GetRange().GetStart() != lineRange
.GetStart()); 
1582                 SetDefaultStyleToCursorStyle(); 
1594 static bool wxRichTextCtrlIsWhitespace(const wxString
& str
) 
1596     return str 
== wxT(" ") || str 
== wxT("\t"); 
1599 // Finds the caret position for the next word 
1600 long wxRichTextCtrl::FindNextWordPosition(int direction
) const 
1602     long endPos 
= GetBuffer().GetRange().GetEnd(); 
1606         long i 
= m_caretPosition
+1+direction
; // +1 for conversion to character pos 
1608         // First skip current text to space 
1609         while (i 
< endPos 
&& i 
> -1) 
1611             // i is in character, not caret positions 
1612             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1613             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1614             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
1618             else if (!wxRichTextCtrlIsWhitespace(text
) && !text
.empty()) 
1625         while (i 
< endPos 
&& i 
> -1) 
1627             // i is in character, not caret positions 
1628             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1629             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1630             if (line 
&& (i 
== line
->GetAbsoluteRange().GetEnd())) 
1631                 return wxMax(-1, i
); 
1633             if (text
.empty()) // End of paragraph, or maybe an image 
1634                 return wxMax(-1, i 
- 1); 
1635             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
1639                 // Convert to caret position 
1640                 return wxMax(-1, i 
- 1); 
1649         long i 
= m_caretPosition
; 
1651         // First skip white space 
1652         while (i 
< endPos 
&& i 
> -1) 
1654             // i is in character, not caret positions 
1655             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1656             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1658             if (text
.empty() || (line 
&& (i 
== line
->GetAbsoluteRange().GetStart()))) // End of paragraph, or maybe an image 
1660             else if (wxRichTextCtrlIsWhitespace(text
) || text
.empty()) 
1665         // Next skip current text to space 
1666         while (i 
< endPos 
&& i 
> -1) 
1668             // i is in character, not caret positions 
1669             wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(i
, i
)); 
1670             wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(i
, false); 
1671             if (line 
&& line
->GetAbsoluteRange().GetStart() == i
) 
1674             if (!wxRichTextCtrlIsWhitespace(text
) /* && !text.empty() */) 
1687 /// Move n words left 
1688 bool wxRichTextCtrl::WordLeft(int WXUNUSED(n
), int flags
) 
1690     long pos 
= FindNextWordPosition(-1); 
1691     if (pos 
!= m_caretPosition
) 
1693         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(pos
, true); 
1695         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
1699         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
1701         SetDefaultStyleToCursorStyle(); 
1711 /// Move n words right 
1712 bool wxRichTextCtrl::WordRight(int WXUNUSED(n
), int flags
) 
1714     long pos 
= FindNextWordPosition(1); 
1715     if (pos 
!= m_caretPosition
) 
1717         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(pos
, true); 
1719         bool extendSel 
= ExtendSelection(m_caretPosition
, pos
, flags
); 
1723         SetCaretPosition(pos
, para
->GetRange().GetStart() != pos
); 
1725         SetDefaultStyleToCursorStyle(); 
1736 void wxRichTextCtrl::OnSize(wxSizeEvent
& event
) 
1738     // Only do sizing optimization for large buffers 
1739     if (GetBuffer().GetRange().GetEnd() > m_delayedLayoutThreshold
) 
1741         m_fullLayoutRequired 
= true; 
1742         m_fullLayoutTime 
= wxGetLocalTimeMillis(); 
1743         m_fullLayoutSavedPosition 
= GetFirstVisiblePosition(); 
1744         LayoutContent(true /* onlyVisibleRect */); 
1747         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
1749 #if wxRICHTEXT_BUFFERED_PAINTING 
1757 /// Idle-time processing 
1758 void wxRichTextCtrl::OnIdle(wxIdleEvent
& event
) 
1760     const int layoutInterval 
= wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL
; 
1762     if (m_fullLayoutRequired 
&& (wxGetLocalTimeMillis() > (m_fullLayoutTime 
+ layoutInterval
))) 
1764         m_fullLayoutRequired 
= false; 
1765         m_fullLayoutTime 
= 0; 
1766         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
1767         ShowPosition(m_fullLayoutSavedPosition
); 
1771     if (m_caretPositionForDefaultStyle 
!= -2) 
1773         // If the caret position has changed, no longer reflect the default style 
1775         if (GetCaretPosition() != m_caretPositionForDefaultStyle
) 
1776             m_caretPositionForDefaultStyle 
= -2; 
1783 void wxRichTextCtrl::OnScroll(wxScrollWinEvent
& event
) 
1789 /// Set up scrollbars, e.g. after a resize 
1790 void wxRichTextCtrl::SetupScrollbars(bool atTop
) 
1795     if (GetBuffer().IsEmpty()) 
1797         SetScrollbars(0, 0, 0, 0, 0, 0); 
1801     // TODO: reimplement scrolling so we scroll by line, not by fixed number 
1802     // of pixels. See e.g. wxVScrolledWindow for ideas. 
1803     int pixelsPerUnit 
= 5; 
1804     wxSize clientSize 
= GetClientSize(); 
1806     int maxHeight 
= GetBuffer().GetCachedSize().y
; 
1808     // Round up so we have at least maxHeight pixels 
1809     int unitsY 
= (int) (((float)maxHeight
/(float)pixelsPerUnit
) + 0.5); 
1811     int startX 
= 0, startY 
= 0; 
1813         GetViewStart(& startX
, & startY
); 
1815     int maxPositionX 
= 0; // wxMax(sz.x - clientSize.x, 0); 
1816     int maxPositionY 
= (int) ((((float)(wxMax((unitsY
*pixelsPerUnit
) - clientSize
.y
, 0)))/((float)pixelsPerUnit
)) + 0.5); 
1818     // Move to previous scroll position if 
1820     SetScrollbars(0, pixelsPerUnit
, 
1822         wxMin(maxPositionX
, startX
), wxMin(maxPositionY
, startY
)); 
1825 /// Paint the background 
1826 void wxRichTextCtrl::PaintBackground(wxDC
& dc
) 
1828     wxColour backgroundColour 
= GetBackgroundColour(); 
1829     if (!backgroundColour
.Ok()) 
1830         backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
1832     // Clear the background 
1833     dc
.SetBrush(wxBrush(backgroundColour
)); 
1834     dc
.SetPen(*wxTRANSPARENT_PEN
); 
1835     wxRect 
windowRect(GetClientSize()); 
1836     windowRect
.x 
-= 2; windowRect
.y 
-= 2; 
1837     windowRect
.width 
+= 4; windowRect
.height 
+= 4; 
1839     // We need to shift the rectangle to take into account 
1840     // scrolling. Converting device to logical coordinates. 
1841     CalcUnscrolledPosition(windowRect
.x
, windowRect
.y
, & windowRect
.x
, & windowRect
.y
); 
1842     dc
.DrawRectangle(windowRect
); 
1845 #if wxRICHTEXT_BUFFERED_PAINTING 
1846 /// Recreate buffer bitmap if necessary 
1847 bool wxRichTextCtrl::RecreateBuffer(const wxSize
& size
) 
1850     if (sz 
== wxDefaultSize
) 
1851         sz 
= GetClientSize(); 
1853     if (sz
.x 
< 1 || sz
.y 
< 1) 
1856     if (!m_bufferBitmap
.Ok() || m_bufferBitmap
.GetWidth() < sz
.x 
|| m_bufferBitmap
.GetHeight() < sz
.y
) 
1857         m_bufferBitmap 
= wxBitmap(sz
.x
, sz
.y
); 
1858     return m_bufferBitmap
.Ok(); 
1862 // ---------------------------------------------------------------------------- 
1863 // file IO functions 
1864 // ---------------------------------------------------------------------------- 
1866 bool wxRichTextCtrl::DoLoadFile(const wxString
& filename
, int fileType
) 
1868     bool success 
= GetBuffer().LoadFile(filename
, fileType
); 
1870         m_filename 
= filename
; 
1873     SetInsertionPoint(0); 
1876     SetupScrollbars(true); 
1878     wxTextCtrl::SendTextUpdatedEvent(this); 
1884         wxLogError(_("File couldn't be loaded.")); 
1890 bool wxRichTextCtrl::DoSaveFile(const wxString
& filename
, int fileType
) 
1892     if (GetBuffer().SaveFile(filename
, fileType
)) 
1894         m_filename 
= filename
; 
1901     wxLogError(_("The text couldn't be saved.")); 
1906 // ---------------------------------------------------------------------------- 
1907 // wxRichTextCtrl specific functionality 
1908 // ---------------------------------------------------------------------------- 
1910 /// Add a new paragraph of text to the end of the buffer 
1911 wxRichTextRange 
wxRichTextCtrl::AddParagraph(const wxString
& text
) 
1913     return GetBuffer().AddParagraph(text
); 
1917 wxRichTextRange 
wxRichTextCtrl::AddImage(const wxImage
& image
) 
1919     return GetBuffer().AddImage(image
); 
1922 // ---------------------------------------------------------------------------- 
1923 // selection and ranges 
1924 // ---------------------------------------------------------------------------- 
1926 void wxRichTextCtrl::SelectAll() 
1928     SetSelection(0, GetLastPosition()+1); 
1929     m_selectionAnchor 
= -1; 
1933 void wxRichTextCtrl::SelectNone() 
1935     if (!(GetSelectionRange() == wxRichTextRange(-2, -2))) 
1936         SetSelection(-2, -2); 
1937     m_selectionAnchor 
= -2; 
1940 static bool wxIsWordDelimiter(const wxString
& text
) 
1942     return !text
.IsEmpty() && !wxIsalnum(text
[0]); 
1945 /// Select the word at the given character position 
1946 bool wxRichTextCtrl::SelectWord(long position
) 
1948     if (position 
< 0 || position 
> GetBuffer().GetRange().GetEnd()) 
1951     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(position
); 
1955     long positionStart 
= position
; 
1956     long positionEnd 
= position
; 
1958     for (positionStart 
= position
; positionStart 
>= para
->GetRange().GetStart(); positionStart 
--) 
1960         wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(positionStart
, positionStart
)); 
1961         if (wxIsWordDelimiter(text
)) 
1967     if (positionStart 
< para
->GetRange().GetStart()) 
1968         positionStart 
= para
->GetRange().GetStart(); 
1970     for (positionEnd 
= position
; positionEnd 
< para
->GetRange().GetEnd(); positionEnd 
++) 
1972         wxString text 
= GetBuffer().GetTextForRange(wxRichTextRange(positionEnd
, positionEnd
)); 
1973         if (wxIsWordDelimiter(text
)) 
1979     if (positionEnd 
>= para
->GetRange().GetEnd()) 
1980         positionEnd 
= para
->GetRange().GetEnd(); 
1982     SetSelection(positionStart
, positionEnd
+1); 
1984     if (positionStart 
>= 0) 
1986         MoveCaret(positionStart
-1, true); 
1987         SetDefaultStyleToCursorStyle(); 
1993 wxString 
wxRichTextCtrl::GetStringSelection() const 
1996     GetSelection(&from
, &to
); 
1998     return GetRange(from
, to
); 
2001 // ---------------------------------------------------------------------------- 
2003 // ---------------------------------------------------------------------------- 
2005 wxTextCtrlHitTestResult
 
2006 wxRichTextCtrl::HitTest(const wxPoint
& pt
, wxTextCoord 
*x
, wxTextCoord 
*y
) const 
2008     // implement in terms of the other overload as the native ports typically 
2009     // can get the position and not (x, y) pair directly (although wxUniv 
2010     // directly gets x and y -- and so overrides this method as well) 
2012     wxTextCtrlHitTestResult rc 
= HitTest(pt
, &pos
); 
2014     if ( rc 
!= wxTE_HT_UNKNOWN 
) 
2016         PositionToXY(pos
, x
, y
); 
2022 wxTextCtrlHitTestResult
 
2023 wxRichTextCtrl::HitTest(const wxPoint
& pt
, 
2026     wxClientDC 
dc((wxRichTextCtrl
*) this); 
2027     ((wxRichTextCtrl
*)this)->PrepareDC(dc
); 
2029     // Buffer uses logical position (relative to start of buffer) 
2031     wxPoint pt2 
= GetLogicalPoint(pt
); 
2033     int hit 
= ((wxRichTextCtrl
*)this)->GetBuffer().HitTest(dc
, pt2
, *pos
); 
2035     if ((hit 
& wxRICHTEXT_HITTEST_BEFORE
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2036         return wxTE_HT_BEFORE
; 
2037     else if ((hit 
& wxRICHTEXT_HITTEST_AFTER
) && (hit 
& wxRICHTEXT_HITTEST_OUTSIDE
)) 
2038         return wxTE_HT_BEYOND
; 
2039     else if (hit 
& (wxRICHTEXT_HITTEST_BEFORE
|wxRICHTEXT_HITTEST_AFTER
)) 
2040         return wxTE_HT_ON_TEXT
; 
2042     return wxTE_HT_UNKNOWN
; 
2045 // ---------------------------------------------------------------------------- 
2046 // set/get the controls text 
2047 // ---------------------------------------------------------------------------- 
2049 wxString 
wxRichTextCtrl::GetValue() const 
2051     return GetBuffer().GetText(); 
2054 wxString 
wxRichTextCtrl::GetRange(long from
, long to
) const 
2056     // Public API for range is different from internals 
2057     return GetBuffer().GetTextForRange(wxRichTextRange(from
, to
-1)); 
2060 void wxRichTextCtrl::DoSetValue(const wxString
& value
, int flags
) 
2064     if (!value
.IsEmpty()) 
2066         // Remove empty paragraph 
2067         GetBuffer().Clear(); 
2070         // for compatibility, don't move the cursor when doing SetValue() 
2071         SetInsertionPoint(0); 
2075         // still send an event for consistency 
2076         if (flags 
& SetValue_SendEvent
) 
2077             wxTextCtrl::SendTextUpdatedEvent(this); 
2082 void wxRichTextCtrl::WriteText(const wxString
& value
) 
2087 void wxRichTextCtrl::DoWriteText(const wxString
& value
, int flags
) 
2089     wxString valueUnix 
= wxTextFile::Translate(value
, wxTextFileType_Unix
); 
2091     GetBuffer().InsertTextWithUndo(m_caretPosition
+1, valueUnix
, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
2093     if ( flags 
& SetValue_SendEvent 
) 
2094         wxTextCtrl::SendTextUpdatedEvent(this); 
2097 void wxRichTextCtrl::AppendText(const wxString
& text
) 
2099     SetInsertionPointEnd(); 
2104 /// Write an image at the current insertion point 
2105 bool wxRichTextCtrl::WriteImage(const wxImage
& image
, int bitmapType
) 
2107     wxRichTextImageBlock imageBlock
; 
2109     wxImage image2 
= image
; 
2110     if (imageBlock
.MakeImageBlock(image2
, bitmapType
)) 
2111         return WriteImage(imageBlock
); 
2116 bool wxRichTextCtrl::WriteImage(const wxString
& filename
, int bitmapType
) 
2118     wxRichTextImageBlock imageBlock
; 
2121     if (imageBlock
.MakeImageBlock(filename
, bitmapType
, image
, false)) 
2122         return WriteImage(imageBlock
); 
2127 bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock
& imageBlock
) 
2129     return GetBuffer().InsertImageWithUndo(m_caretPosition
+1, imageBlock
, this); 
2132 bool wxRichTextCtrl::WriteImage(const wxBitmap
& bitmap
, int bitmapType
) 
2136         wxRichTextImageBlock imageBlock
; 
2138         wxImage image 
= bitmap
.ConvertToImage(); 
2139         if (image
.Ok() && imageBlock
.MakeImageBlock(image
, bitmapType
)) 
2140             return WriteImage(imageBlock
); 
2146 /// Insert a newline (actually paragraph) at the current insertion point. 
2147 bool wxRichTextCtrl::Newline() 
2149     return GetBuffer().InsertNewlineWithUndo(m_caretPosition
+1, this); 
2152 /// Insert a line break at the current insertion point. 
2153 bool wxRichTextCtrl::LineBreak() 
2156     text 
= wxRichTextLineBreakChar
; 
2157     return GetBuffer().InsertTextWithUndo(m_caretPosition
+1, text
, this); 
2160 // ---------------------------------------------------------------------------- 
2161 // Clipboard operations 
2162 // ---------------------------------------------------------------------------- 
2164 void wxRichTextCtrl::Copy() 
2168         wxRichTextRange range 
= GetInternalSelectionRange(); 
2169         GetBuffer().CopyToClipboard(range
); 
2173 void wxRichTextCtrl::Cut() 
2177         wxRichTextRange range 
= GetInternalSelectionRange(); 
2178         GetBuffer().CopyToClipboard(range
); 
2180         DeleteSelectedContent(); 
2186 void wxRichTextCtrl::Paste() 
2190         BeginBatchUndo(_("Paste")); 
2192         long newPos 
= m_caretPosition
; 
2193         DeleteSelectedContent(& newPos
); 
2195         GetBuffer().PasteFromClipboard(newPos
); 
2201 void wxRichTextCtrl::DeleteSelection() 
2203     if (CanDeleteSelection()) 
2205         DeleteSelectedContent(); 
2209 bool wxRichTextCtrl::HasSelection() const 
2211     return m_selectionRange
.GetStart() != -2 && m_selectionRange
.GetEnd() != -2; 
2214 bool wxRichTextCtrl::CanCopy() const 
2216     // Can copy if there's a selection 
2217     return HasSelection(); 
2220 bool wxRichTextCtrl::CanCut() const 
2222     return HasSelection() && IsEditable(); 
2225 bool wxRichTextCtrl::CanPaste() const 
2227     if ( !IsEditable() ) 
2230     return GetBuffer().CanPasteFromClipboard(); 
2233 bool wxRichTextCtrl::CanDeleteSelection() const 
2235     return HasSelection() && IsEditable(); 
2239 // ---------------------------------------------------------------------------- 
2241 // ---------------------------------------------------------------------------- 
2243 void wxRichTextCtrl::SetEditable(bool editable
) 
2245     m_editable 
= editable
; 
2248 void wxRichTextCtrl::SetInsertionPoint(long pos
) 
2252     m_caretPosition 
= pos 
- 1; 
2255 void wxRichTextCtrl::SetInsertionPointEnd() 
2257     long pos 
= GetLastPosition(); 
2258     SetInsertionPoint(pos
); 
2261 long wxRichTextCtrl::GetInsertionPoint() const 
2263     return m_caretPosition
+1; 
2266 wxTextPos 
wxRichTextCtrl::GetLastPosition() const 
2268     return GetBuffer().GetRange().GetEnd(); 
2271 // If the return values from and to are the same, there is no 
2273 void wxRichTextCtrl::GetSelection(long* from
, long* to
) const 
2275     *from 
= m_selectionRange
.GetStart(); 
2276     *to 
= m_selectionRange
.GetEnd(); 
2277     if ((*to
) != -1 && (*to
) != -2) 
2281 bool wxRichTextCtrl::IsEditable() const 
2286 // ---------------------------------------------------------------------------- 
2288 // ---------------------------------------------------------------------------- 
2290 void wxRichTextCtrl::SetSelection(long from
, long to
) 
2292     // if from and to are both -1, it means (in wxWidgets) that all text should 
2294     if ( (from 
== -1) && (to 
== -1) ) 
2297         to 
= GetLastPosition()+1; 
2300     DoSetSelection(from
, to
); 
2303 void wxRichTextCtrl::DoSetSelection(long from
, long to
, bool WXUNUSED(scrollCaret
)) 
2305     m_selectionAnchor 
= from
; 
2306     m_selectionRange
.SetRange(from
, to
-1); 
2308         m_caretPosition 
= from
-1; 
2314 // ---------------------------------------------------------------------------- 
2316 // ---------------------------------------------------------------------------- 
2318 void wxRichTextCtrl::Replace(long WXUNUSED(from
), long WXUNUSED(to
), 
2319                              const wxString
& value
) 
2321     BeginBatchUndo(_("Replace")); 
2323     DeleteSelectedContent(); 
2325     DoWriteText(value
, SetValue_SelectionOnly
); 
2330 void wxRichTextCtrl::Remove(long from
, long to
) 
2334     GetBuffer().DeleteRangeWithUndo(wxRichTextRange(from
, to
), this); 
2341 bool wxRichTextCtrl::IsModified() const 
2343     return m_buffer
.IsModified(); 
2346 void wxRichTextCtrl::MarkDirty() 
2348     m_buffer
.Modify(true); 
2351 void wxRichTextCtrl::DiscardEdits() 
2353     m_caretPositionForDefaultStyle 
= -2; 
2354     m_buffer
.Modify(false); 
2355     m_buffer
.GetCommandProcessor()->ClearCommands(); 
2358 int wxRichTextCtrl::GetNumberOfLines() const 
2360     return GetBuffer().GetParagraphCount(); 
2363 // ---------------------------------------------------------------------------- 
2364 // Positions <-> coords 
2365 // ---------------------------------------------------------------------------- 
2367 long wxRichTextCtrl::XYToPosition(long x
, long y
) const 
2369     return GetBuffer().XYToPosition(x
, y
); 
2372 bool wxRichTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
2374     return GetBuffer().PositionToXY(pos
, x
, y
); 
2377 // ---------------------------------------------------------------------------- 
2379 // ---------------------------------------------------------------------------- 
2381 void wxRichTextCtrl::ShowPosition(long pos
) 
2383     if (!IsPositionVisible(pos
)) 
2384         ScrollIntoView(pos
-1, WXK_DOWN
); 
2387 int wxRichTextCtrl::GetLineLength(long lineNo
) const 
2389     return GetBuffer().GetParagraphLength(lineNo
); 
2392 wxString 
wxRichTextCtrl::GetLineText(long lineNo
) const 
2394     return GetBuffer().GetParagraphText(lineNo
); 
2397 // ---------------------------------------------------------------------------- 
2399 // ---------------------------------------------------------------------------- 
2401 void wxRichTextCtrl::Undo() 
2405         GetCommandProcessor()->Undo(); 
2409 void wxRichTextCtrl::Redo() 
2413         GetCommandProcessor()->Redo(); 
2417 bool wxRichTextCtrl::CanUndo() const 
2419     return GetCommandProcessor()->CanUndo(); 
2422 bool wxRichTextCtrl::CanRedo() const 
2424     return GetCommandProcessor()->CanRedo(); 
2427 // ---------------------------------------------------------------------------- 
2428 // implementation details 
2429 // ---------------------------------------------------------------------------- 
2431 void wxRichTextCtrl::Command(wxCommandEvent
& event
) 
2433     SetValue(event
.GetString()); 
2434     GetEventHandler()->ProcessEvent(event
); 
2437 void wxRichTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
2439     // By default, load the first file into the text window. 
2440     if (event
.GetNumberOfFiles() > 0) 
2442         LoadFile(event
.GetFiles()[0]); 
2446 wxSize 
wxRichTextCtrl::DoGetBestSize() const 
2448     return wxSize(10, 10); 
2451 // ---------------------------------------------------------------------------- 
2452 // standard handlers for standard edit menu events 
2453 // ---------------------------------------------------------------------------- 
2455 void wxRichTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
2460 void wxRichTextCtrl::OnClear(wxCommandEvent
& WXUNUSED(event
)) 
2465 void wxRichTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
2470 void wxRichTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
2475 void wxRichTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
2480 void wxRichTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
2485 void wxRichTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
2487     event
.Enable( CanCut() ); 
2490 void wxRichTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
2492     event
.Enable( CanCopy() ); 
2495 void wxRichTextCtrl::OnUpdateClear(wxUpdateUIEvent
& event
) 
2497     event
.Enable( CanDeleteSelection() ); 
2500 void wxRichTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
2502     event
.Enable( CanPaste() ); 
2505 void wxRichTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
2507     event
.Enable( CanUndo() ); 
2508     event
.SetText( GetCommandProcessor()->GetUndoMenuLabel() ); 
2511 void wxRichTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
2513     event
.Enable( CanRedo() ); 
2514     event
.SetText( GetCommandProcessor()->GetRedoMenuLabel() ); 
2517 void wxRichTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
2522 void wxRichTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
2524     event
.Enable(GetLastPosition() > 0); 
2527 void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent
& event
) 
2529     if (event
.GetEventObject() != this) 
2537         m_contextMenu 
= new wxMenu
; 
2538         m_contextMenu
->Append(wxID_UNDO
, _("&Undo")); 
2539         m_contextMenu
->Append(wxID_REDO
, _("&Redo")); 
2540         m_contextMenu
->AppendSeparator(); 
2541         m_contextMenu
->Append(wxID_CUT
, _("Cu&t")); 
2542         m_contextMenu
->Append(wxID_COPY
, _("&Copy")); 
2543         m_contextMenu
->Append(wxID_PASTE
, _("&Paste")); 
2544         m_contextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
2545         m_contextMenu
->AppendSeparator(); 
2546         m_contextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
2548     PopupMenu(m_contextMenu
); 
2552 bool wxRichTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
2554     return GetBuffer().SetStyle(wxRichTextRange(start
, end
-1), wxTextAttr(style
)); 
2557 bool wxRichTextCtrl::SetStyle(const wxRichTextRange
& range
, const wxTextAttr
& style
) 
2559     return GetBuffer().SetStyle(range
.ToInternal(), style
); 
2562 // extended style setting operation with flags including: 
2563 // wxRICHTEXT_SETSTYLE_WITH_UNDO, wxRICHTEXT_SETSTYLE_OPTIMIZE, wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY. 
2564 // see richtextbuffer.h for more details. 
2566 bool wxRichTextCtrl::SetStyleEx(const wxRichTextRange
& range
, const wxTextAttr
& style
, int flags
) 
2568     return GetBuffer().SetStyle(range
.ToInternal(), style
, flags
); 
2571 bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
2573     return GetBuffer().SetDefaultStyle(wxTextAttr(style
)); 
2576 const wxTextAttr
& wxRichTextCtrl::GetDefaultStyle() const 
2578     return GetBuffer().GetDefaultStyle(); 
2581 bool wxRichTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
2583     return GetBuffer().GetStyle(position
, style
); 
2586 // get the common set of styles for the range 
2587 bool wxRichTextCtrl::GetStyleForRange(const wxRichTextRange
& range
, wxTextAttr
& style
) 
2589     return GetBuffer().GetStyleForRange(range
.ToInternal(), style
); 
2592 /// Get the content (uncombined) attributes for this position. 
2593 bool wxRichTextCtrl::GetUncombinedStyle(long position
, wxTextAttr
& style
) 
2595     return GetBuffer().GetUncombinedStyle(position
, style
); 
2598 /// Set font, and also the buffer attributes 
2599 bool wxRichTextCtrl::SetFont(const wxFont
& font
) 
2601     wxControl::SetFont(font
); 
2603     wxTextAttr attr 
= GetBuffer().GetAttributes(); 
2605     GetBuffer().SetBasicStyle(attr
); 
2607     GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2613 /// Transform logical to physical 
2614 wxPoint 
wxRichTextCtrl::GetPhysicalPoint(const wxPoint
& ptLogical
) const 
2617     CalcScrolledPosition(ptLogical
.x
, ptLogical
.y
, & pt
.x
, & pt
.y
); 
2622 /// Transform physical to logical 
2623 wxPoint 
wxRichTextCtrl::GetLogicalPoint(const wxPoint
& ptPhysical
) const 
2626     CalcUnscrolledPosition(ptPhysical
.x
, ptPhysical
.y
, & pt
.x
, & pt
.y
); 
2631 /// Position the caret 
2632 void wxRichTextCtrl::PositionCaret() 
2637     //wxLogDebug(wxT("PositionCaret")); 
2640     if (GetCaretPositionForIndex(GetCaretPosition(), caretRect
)) 
2642         wxPoint newPt 
= caretRect
.GetPosition(); 
2643         wxSize newSz 
= caretRect
.GetSize(); 
2644         wxPoint pt 
= GetPhysicalPoint(newPt
); 
2645         if (GetCaret()->GetPosition() != pt 
|| GetCaret()->GetSize() != newSz
) 
2647             GetCaret()->Move(pt
); 
2648             GetCaret()->SetSize(newSz
); 
2653 /// Get the caret height and position for the given character position 
2654 bool wxRichTextCtrl::GetCaretPositionForIndex(long position
, wxRect
& rect
) 
2656     wxClientDC 
dc(this); 
2657     dc
.SetFont(GetFont()); 
2664     if (GetBuffer().FindPosition(dc
, position
, pt
, & height
, m_caretAtLineStart
)) 
2666         // Caret height can't be zero 
2668             height 
= dc
.GetCharHeight(); 
2670         rect 
= wxRect(pt
, wxSize(wxRICHTEXT_DEFAULT_CARET_WIDTH
, height
)); 
2677 /// Gets the line for the visible caret position. If the caret is 
2678 /// shown at the very end of the line, it means the next character is actually 
2679 /// on the following line. So let's get the line we're expecting to find 
2680 /// if this is the case. 
2681 wxRichTextLine
* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPosition
) const 
2683     wxRichTextLine
* line 
= GetBuffer().GetLineAtPosition(caretPosition
, true); 
2684     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(caretPosition
, true); 
2687         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2688         if (caretPosition 
== lineRange
.GetStart()-1 && 
2689             (para
->GetRange().GetStart() != lineRange
.GetStart())) 
2691             if (!m_caretAtLineStart
) 
2692                 line 
= GetBuffer().GetLineAtPosition(caretPosition
-1, true); 
2699 /// Move the caret to the given character position 
2700 bool wxRichTextCtrl::MoveCaret(long pos
, bool showAtLineStart
) 
2702     if (GetBuffer().GetDirty()) 
2705     if (pos 
<= GetBuffer().GetRange().GetEnd()) 
2707         SetCaretPosition(pos
, showAtLineStart
); 
2717 /// Layout the buffer: which we must do before certain operations, such as 
2718 /// setting the caret position. 
2719 bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect
) 
2721     if (GetBuffer().GetDirty() || onlyVisibleRect
) 
2723         wxRect 
availableSpace(GetClientSize()); 
2724         if (availableSpace
.width 
== 0) 
2725             availableSpace
.width 
= 10; 
2726         if (availableSpace
.height 
== 0) 
2727             availableSpace
.height 
= 10; 
2729         int flags 
= wxRICHTEXT_FIXED_WIDTH
|wxRICHTEXT_VARIABLE_HEIGHT
; 
2730         if (onlyVisibleRect
) 
2732             flags 
|= wxRICHTEXT_LAYOUT_SPECIFIED_RECT
; 
2733             availableSpace
.SetPosition(GetLogicalPoint(wxPoint(0, 0))); 
2736         wxClientDC 
dc(this); 
2737         dc
.SetFont(GetFont()); 
2741         GetBuffer().Defragment(); 
2742         GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation 
2743         GetBuffer().Layout(dc
, availableSpace
, flags
); 
2744         GetBuffer().SetDirty(false); 
2753 /// Is all of the selection bold? 
2754 bool wxRichTextCtrl::IsSelectionBold() 
2759         wxRichTextRange range 
= GetSelectionRange(); 
2760         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
2761         attr
.SetFontWeight(wxBOLD
); 
2763         return HasCharacterAttributes(range
, attr
); 
2767         // If no selection, then we need to combine current style with default style 
2768         // to see what the effect would be if we started typing. 
2770         attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
2772         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
2773         if (GetStyle(pos
, attr
)) 
2775             if (IsDefaultStyleShowing()) 
2776                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
2777             return attr
.GetFontWeight() == wxBOLD
; 
2783 /// Is all of the selection italics? 
2784 bool wxRichTextCtrl::IsSelectionItalics() 
2788         wxRichTextRange range 
= GetSelectionRange(); 
2790         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
2791         attr
.SetFontStyle(wxITALIC
); 
2793         return HasCharacterAttributes(range
, attr
); 
2797         // If no selection, then we need to combine current style with default style 
2798         // to see what the effect would be if we started typing. 
2800         attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
2802         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
2803         if (GetStyle(pos
, attr
)) 
2805             if (IsDefaultStyleShowing()) 
2806                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
2807             return attr
.GetFontStyle() == wxITALIC
; 
2813 /// Is all of the selection underlined? 
2814 bool wxRichTextCtrl::IsSelectionUnderlined() 
2818         wxRichTextRange range 
= GetSelectionRange(); 
2820         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
2821         attr
.SetFontUnderlined(true); 
2823         return HasCharacterAttributes(range
, attr
); 
2827         // If no selection, then we need to combine current style with default style 
2828         // to see what the effect would be if we started typing. 
2830         attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
2831         long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
2833         if (GetStyle(pos
, attr
)) 
2835             if (IsDefaultStyleShowing()) 
2836                 wxRichTextApplyStyle(attr
, GetDefaultStyleEx()); 
2837             return attr
.GetFontUnderlined(); 
2843 /// Apply bold to the selection 
2844 bool wxRichTextCtrl::ApplyBoldToSelection() 
2847     attr
.SetFlags(wxTEXT_ATTR_FONT_WEIGHT
); 
2848     attr
.SetFontWeight(IsSelectionBold() ? wxNORMAL 
: wxBOLD
); 
2851         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
2853         SetAndShowDefaultStyle(attr
); 
2857 /// Apply italic to the selection 
2858 bool wxRichTextCtrl::ApplyItalicToSelection() 
2861     attr
.SetFlags(wxTEXT_ATTR_FONT_ITALIC
); 
2862     attr
.SetFontStyle(IsSelectionItalics() ? wxNORMAL 
: wxITALIC
); 
2865         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
2867         SetAndShowDefaultStyle(attr
); 
2871 /// Apply underline to the selection 
2872 bool wxRichTextCtrl::ApplyUnderlineToSelection() 
2875     attr
.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE
); 
2876     attr
.SetFontUnderlined(!IsSelectionUnderlined()); 
2879         return SetStyleEx(GetSelectionRange(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
); 
2881         SetAndShowDefaultStyle(attr
); 
2885 /// Is all of the selection aligned according to the specified flag? 
2886 bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment
) 
2888     wxRichTextRange range
; 
2890         range 
= GetSelectionRange(); 
2892         range 
= wxRichTextRange(GetCaretPosition()+1, GetCaretPosition()+2); 
2895     attr
.SetAlignment(alignment
); 
2897     return HasParagraphAttributes(range
, attr
); 
2900 /// Apply alignment to the selection 
2901 bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment
) 
2904     attr
.SetAlignment(alignment
); 
2906         return SetStyle(GetSelectionRange(), attr
); 
2909         wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(GetCaretPosition()+1); 
2911             return SetStyleEx(para
->GetRange().FromInternal(), attr
, wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
|wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
); 
2916 /// Apply a named style to the selection 
2917 bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition
* def
) 
2919     // Flags are defined within each definition, so only certain 
2920     // attributes are applied. 
2921     wxTextAttr 
attr(GetStyleSheet() ? def
->GetStyleMergedWithBase(GetStyleSheet()) : def
->GetStyle()); 
2923     int flags 
= wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_OPTIMIZE
; 
2925     if (def
->IsKindOf(CLASSINFO(wxRichTextListStyleDefinition
))) 
2927         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
2929         wxRichTextRange range
; 
2932             range 
= GetSelectionRange(); 
2935             long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
2936             range 
= wxRichTextRange(pos
, pos
+1); 
2939         return SetListStyle(range
, (wxRichTextListStyleDefinition
*) def
, flags
); 
2942     // Make sure the attr has the style name 
2943     if (def
->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition
))) 
2945         attr
.SetParagraphStyleName(def
->GetName()); 
2947         // If applying a paragraph style, we only want the paragraph nodes to adopt these 
2948         // attributes, and not the leaf nodes. This will allow the content (e.g. text) 
2949         // to change its style independently. 
2950         flags 
|= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
; 
2953         attr
.SetCharacterStyleName(def
->GetName()); 
2956         return SetStyleEx(GetSelectionRange(), attr
, flags
); 
2959         SetAndShowDefaultStyle(attr
); 
2964 /// Apply the style sheet to the buffer, for example if the styles have changed. 
2965 bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet
* styleSheet
) 
2968         styleSheet 
= GetBuffer().GetStyleSheet(); 
2972     if (GetBuffer().ApplyStyleSheet(styleSheet
)) 
2974         GetBuffer().Invalidate(wxRICHTEXT_ALL
); 
2982 /// Sets the default style to the style under the cursor 
2983 bool wxRichTextCtrl::SetDefaultStyleToCursorStyle() 
2986     attr
.SetFlags(wxTEXT_ATTR_CHARACTER
); 
2988     // If at the start of a paragraph, use the next position. 
2989     long pos 
= GetAdjustedCaretPosition(GetCaretPosition()); 
2991     if (GetUncombinedStyle(pos
, attr
)) 
2993         SetDefaultStyle(attr
); 
3000 /// Returns the first visible position in the current view 
3001 long wxRichTextCtrl::GetFirstVisiblePosition() const 
3003     wxRichTextLine
* line 
= GetBuffer().GetLineAtYPosition(GetLogicalPoint(wxPoint(0, 0)).y
); 
3005         return line
->GetAbsoluteRange().GetStart(); 
3010 /// Get the first visible point in the window 
3011 wxPoint 
wxRichTextCtrl::GetFirstVisiblePoint() const 
3014     int startXUnits
, startYUnits
; 
3016     GetScrollPixelsPerUnit(& ppuX
, & ppuY
); 
3017     GetViewStart(& startXUnits
, & startYUnits
); 
3019     return wxPoint(startXUnits 
* ppuX
, startYUnits 
* ppuY
); 
3022 /// The adjusted caret position is the character position adjusted to take 
3023 /// into account whether we're at the start of a paragraph, in which case 
3024 /// style information should be taken from the next position, not current one. 
3025 long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos
) const 
3027     wxRichTextParagraph
* para 
= GetBuffer().GetParagraphAtPosition(caretPos
+1); 
3029     if (para 
&& (caretPos
+1 == para
->GetRange().GetStart())) 
3034 /// Get/set the selection range in character positions. -1, -1 means no selection. 
3035 /// The range is in API convention, i.e. a single character selection is denoted 
3037 wxRichTextRange 
wxRichTextCtrl::GetSelectionRange() const 
3039     wxRichTextRange range 
= GetInternalSelectionRange(); 
3040     if (range 
!= wxRichTextRange(-2,-2) && range 
!= wxRichTextRange(-1,-1)) 
3041         range
.SetEnd(range
.GetEnd() + 1); 
3045 void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange
& range
) 
3047     wxRichTextRange 
range1(range
); 
3048     if (range1 
!= wxRichTextRange(-2,-2) && range1 
!= wxRichTextRange(-1,-1) ) 
3049         range1
.SetEnd(range1
.GetEnd() - 1); 
3051     wxASSERT( range1
.GetStart() > range1
.GetEnd() ); 
3053     SetInternalSelectionRange(range1
); 
3057 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3059     return GetBuffer().SetListStyle(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
3062 bool wxRichTextCtrl::SetListStyle(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
3064     return GetBuffer().SetListStyle(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
3067 /// Clear list for given range 
3068 bool wxRichTextCtrl::ClearListStyle(const wxRichTextRange
& range
, int flags
) 
3070     return GetBuffer().ClearListStyle(range
.ToInternal(), flags
); 
3073 /// Number/renumber any list elements in the given range 
3074 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3076     return GetBuffer().NumberList(range
.ToInternal(), def
, flags
, startFrom
, specifiedLevel
); 
3079 bool wxRichTextCtrl::NumberList(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
3081     return GetBuffer().NumberList(range
.ToInternal(), defName
, flags
, startFrom
, specifiedLevel
); 
3084 /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 
3085 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int specifiedLevel
) 
3087     return GetBuffer().PromoteList(promoteBy
, range
.ToInternal(), def
, flags
, specifiedLevel
); 
3090 bool wxRichTextCtrl::PromoteList(int promoteBy
, const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int specifiedLevel
) 
3092     return GetBuffer().PromoteList(promoteBy
, range
.ToInternal(), defName
, flags
, specifiedLevel
); 
3095 /// Deletes the content in the given range 
3096 bool wxRichTextCtrl::Delete(const wxRichTextRange
& range
) 
3098     return GetBuffer().DeleteRangeWithUndo(range
.ToInternal(), this); 
3101 const wxArrayString
& wxRichTextCtrl::GetAvailableFontNames() 
3103     if (sm_availableFontNames
.GetCount() == 0) 
3105         sm_availableFontNames 
= wxFontEnumerator::GetFacenames(); 
3106         sm_availableFontNames
.Sort(); 
3108     return sm_availableFontNames
; 
3111 void wxRichTextCtrl::ClearAvailableFontNames() 
3113     sm_availableFontNames
.Clear(); 
3116 void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
)) 
3118     //wxLogDebug(wxT("wxRichTextCtrl::OnSysColourChanged")); 
3120     wxTextAttrEx basicStyle 
= GetBasicStyle(); 
3121     basicStyle
.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
3122     SetBasicStyle(basicStyle
); 
3123     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));