X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/17808a759627b03c2acbe7333dd2386557e1b804..472137baebae6c011ad7d70285de454b9ce7796d:/src/richtext/richtextctrl.cpp diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index 6acea71f6c..3a6432a531 100644 --- a/src/richtext/richtextctrl.cpp +++ b/src/richtext/richtextctrl.cpp @@ -32,6 +32,7 @@ #include "wx/dcbuffer.h" #include "wx/arrimpl.cpp" #include "wx/fontenum.h" +#include "wx/accel.h" // DLL options compatibility check: #include "wx/app.h" @@ -54,6 +55,70 @@ DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED) DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED) DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED) DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_BUFFER_RESET) + +#if wxRICHTEXT_USE_OWN_CARET + +/*! + * wxRichTextCaret + * + * This implements a non-flashing cursor in case there + * are platform-specific problems with the generic caret. + * wxRICHTEXT_USE_OWN_CARET is set in richtextbuffer.h. + */ + +class wxRichTextCaret: public wxCaret +{ +public: + // ctors + // ----- + // default - use Create() + wxRichTextCaret() { Init(); } + // creates a block caret associated with the given window + wxRichTextCaret(wxRichTextCtrl *window, int width, int height) + : wxCaret(window, width, height) { Init(); m_richTextCtrl = window; } + wxRichTextCaret(wxRichTextCtrl *window, const wxSize& size) + : wxCaret(window, size) { Init(); m_richTextCtrl = window; } + + virtual ~wxRichTextCaret(); + + // implementation + // -------------- + + // called by wxWindow (not using the event tables) + virtual void OnSetFocus(); + virtual void OnKillFocus(); + + // draw the caret on the given DC + void DoDraw(wxDC *dc); + + // get the visible count + int GetVisibleCount() const { return m_countVisible; } + + // delay repositioning + bool GetNeedsUpdate() const { return m_needsUpdate; } + void SetNeedsUpdate(bool needsUpdate = true ) { m_needsUpdate = needsUpdate; } + +protected: + virtual void DoShow(); + virtual void DoHide(); + virtual void DoMove(); + virtual void DoSize(); + + // refresh the caret + void Refresh(); + +private: + void Init(); + + int m_xOld, + m_yOld; + bool m_hasFocus; // true => our window has focus + bool m_needsUpdate; // must be repositioned + + wxRichTextCtrl* m_richTextCtrl; +}; +#endif IMPLEMENT_CLASS( wxRichTextCtrl, wxControl ) @@ -71,6 +136,7 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxControl ) EVT_MIDDLE_DOWN(wxRichTextCtrl::OnMiddleClick) EVT_LEFT_DCLICK(wxRichTextCtrl::OnLeftDClick) EVT_CHAR(wxRichTextCtrl::OnChar) + EVT_KEY_DOWN(wxRichTextCtrl::OnChar) EVT_SIZE(wxRichTextCtrl::OnSize) EVT_SET_FOCUS(wxRichTextCtrl::OnSetFocus) EVT_KILL_FOCUS(wxRichTextCtrl::OnKillFocus) @@ -140,12 +206,6 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); } - GetBuffer().Reset(); - GetBuffer().SetRichTextCtrl(this); - - SetCaret(new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH, 16)); - GetCaret()->Show(); - if (style & wxTE_READONLY) SetEditable(false); @@ -157,8 +217,6 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va attributes.SetLineSpacing(10); attributes.SetParagraphSpacingAfter(10); attributes.SetParagraphSpacingBefore(0); - attributes.SetTextEffects(0); - attributes.SetTextEffectFlags(wxTEXT_ATTR_EFFECT_STRIKETHROUGH|wxTEXT_ATTR_EFFECT_CAPITALS); SetBasicStyle(attributes); @@ -170,6 +228,15 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); SetBackgroundStyle(wxBG_STYLE_CUSTOM); + GetBuffer().Reset(); + GetBuffer().SetRichTextCtrl(this); + +#if wxRICHTEXT_USE_OWN_CARET + SetCaret(new wxRichTextCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH, 16)); +#else + SetCaret(new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH, 16)); +#endif + // Tell the sizers to use the given or best size SetInitialSize(size); @@ -188,6 +255,17 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va GetBuffer().AddEventHandler(this); + // Accelerators + wxAcceleratorEntry entries[4]; + + entries[0].Set(wxACCEL_CMD, (int) 'C', wxID_COPY); + entries[1].Set(wxACCEL_CMD, (int) 'X', wxID_CUT); + entries[2].Set(wxACCEL_CMD, (int) 'V', wxID_PASTE); + entries[3].Set(wxACCEL_CMD, (int) 'A', wxID_SELECTALL); + + wxAcceleratorTable accel(4, entries); + SetAcceleratorTable(accel); + return true; } @@ -222,7 +300,8 @@ void wxRichTextCtrl::DoThaw() LayoutContent(); else SetupScrollbars(); - Refresh(false); + + wxWindow::DoThaw(); } /// Clear all text @@ -235,6 +314,8 @@ void wxRichTextCtrl::Clear() m_caretAtLineStart = false; m_selectionRange.SetRange(-2, -2); + Scroll(0,0); + if (!IsFrozen()) { LayoutContent(); @@ -247,8 +328,10 @@ void wxRichTextCtrl::Clear() /// Painting void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) { - if (GetCaret() && GetCaret()->IsVisible()) +#if !wxRICHTEXT_USE_OWN_CARET + if (GetCaret() && !IsFrozen()) GetCaret()->Hide(); +#endif { #if wxRICHTEXT_BUFFERED_PAINTING @@ -281,12 +364,19 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) } GetBuffer().Draw(dc, GetBuffer().GetRange(), GetInternalSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */); +#if wxRICHTEXT_USE_OWN_CARET + if (GetCaret()->IsVisible()) + { + ((wxRichTextCaret*) GetCaret())->DoDraw(& dc); + } +#endif } - if (GetCaret() && !GetCaret()->IsVisible()) +#if !wxRICHTEXT_USE_OWN_CARET + if (GetCaret()) GetCaret()->Show(); - PositionCaret(); +#endif } // Empty implementation, to prevent flicker @@ -298,22 +388,33 @@ void wxRichTextCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event)) { if (GetCaret()) { - if (!GetCaret()->IsVisible()) - GetCaret()->Show(); +#if !wxRICHTEXT_USE_OWN_CARET PositionCaret(); +#endif + GetCaret()->Show(); } - // if (!IsFrozen()) - // Refresh(false); +#if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET + // Work around dropouts when control is focused + if (!IsFrozen()) + { + Refresh(false); + } +#endif } void wxRichTextCtrl::OnKillFocus(wxFocusEvent& WXUNUSED(event)) { - if (GetCaret() && GetCaret()->IsVisible()) + if (GetCaret()) GetCaret()->Hide(); - // if (!IsFrozen()) - // Refresh(false); +#if defined(__WXGTK__) && !wxRICHTEXT_USE_OWN_CARET + // Work around dropouts when control is focused + if (!IsFrozen()) + { + Refresh(false); + } +#endif } void wxRichTextCtrl::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) @@ -339,8 +440,6 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event) m_dragging = true; CaptureMouse(); - SelectNone(); - bool caretAtLineStart = false; if (hit & wxRICHTEXT_HITTEST_BEFORE) @@ -356,8 +455,20 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event) position --; } + long oldCaretPos = m_caretPosition; + MoveCaret(position, caretAtLineStart); SetDefaultStyleToCursorStyle(); + + if (event.ShiftDown()) + { + if (m_selectionRange.GetStart() == -2) + ExtendSelection(oldCaretPos, m_caretPosition, wxRICHTEXT_SHIFT_DOWN); + else + ExtendSelection(m_caretPosition, m_caretPosition, wxRICHTEXT_SHIFT_DOWN); + } + else + SelectNone(); } event.Skip(); @@ -381,7 +492,7 @@ void wxRichTextCtrl::OnLeftUp(wxMouseEvent& event) wxPoint logicalPt = event.GetLogicalPosition(dc); int hit = GetBuffer().HitTest(dc, logicalPt, position); - if (hit != wxRICHTEXT_HITTEST_NONE) + if ((hit != wxRICHTEXT_HITTEST_NONE) && !(hit & wxRICHTEXT_HITTEST_OUTSIDE)) { wxRichTextEvent cmdEvent( wxEVT_COMMAND_RICHTEXT_LEFT_CLICK, @@ -483,13 +594,10 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event) if (m_caretPosition != position) { - bool extendSel = ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN); + ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN); MoveCaret(position, caretAtLineStart); SetDefaultStyleToCursorStyle(); - - if (extendSel) - Refresh(false); } } } @@ -548,6 +656,65 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) if (event.AltDown()) flags |= wxRICHTEXT_ALT_DOWN; + if (event.GetEventType() == wxEVT_KEY_DOWN) + { + // Must process this before translation, otherwise it's translated into a WXK_DELETE event. + if (event.CmdDown() && event.GetKeyCode() == WXK_BACK) + { + BeginBatchUndo(_("Delete Text")); + + long newPos = m_caretPosition; + + DeleteSelectedContent(& newPos); + + // Submit range in character positions, which are greater than caret positions, + // so subtract 1 for deleted character and add 1 for conversion to character position. + if (newPos > -1) + { + bool processed = false; + if (event.CmdDown()) + { + long pos = wxRichTextCtrl::FindNextWordPosition(-1); + if (pos != -1 && (pos < newPos)) + { + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this); + processed = true; + } + } + + if (!processed) + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this); + } + + EndBatchUndo(); + + if (GetLastPosition() == -1) + { + GetBuffer().Reset(); + + m_caretPosition = -1; + PositionCaret(); + SetDefaultStyleToCursorStyle(); + } + + ScrollIntoView(m_caretPosition, WXK_LEFT); + + wxRichTextEvent cmdEvent( + wxEVT_COMMAND_RICHTEXT_DELETE, + GetId()); + cmdEvent.SetEventObject(this); + cmdEvent.SetFlags(flags); + cmdEvent.SetPosition(m_caretPosition+1); + GetEventHandler()->ProcessEvent(cmdEvent); + + Update(); + } + else + event.Skip(); + + return; + } + if (event.GetKeyCode() == WXK_LEFT || event.GetKeyCode() == WXK_RIGHT || event.GetKeyCode() == WXK_UP || @@ -591,9 +758,11 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) wxString text; text = wxRichTextLineBreakChar; GetBuffer().InsertTextWithUndo(newPos+1, text, this); + m_caretAtLineStart = true; + PositionCaret(); } else - GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE); + GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE|wxRICHTEXT_INSERT_INTERACTIVE); EndBatchUndo(); SetDefaultStyleToCursorStyle(); @@ -621,14 +790,28 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) { BeginBatchUndo(_("Delete Text")); + long newPos = m_caretPosition; + + DeleteSelectedContent(& newPos); + // Submit range in character positions, which are greater than caret positions, // so subtract 1 for deleted character and add 1 for conversion to character position. - if (m_caretPosition > -1 && !HasSelection()) + if (newPos > -1) { - GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition, m_caretPosition), this); + bool processed = false; + if (event.CmdDown()) + { + long pos = wxRichTextCtrl::FindNextWordPosition(-1); + if (pos != -1 && (pos < newPos)) + { + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this); + processed = true; + } + } + + if (!processed) + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this); } - else - DeleteSelectedContent(); EndBatchUndo(); @@ -657,13 +840,27 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) { BeginBatchUndo(_("Delete Text")); + long newPos = m_caretPosition; + + DeleteSelectedContent(& newPos); + // Submit range in character positions, which are greater than caret positions, - if (m_caretPosition < GetBuffer().GetRange().GetEnd()+1 && !HasSelection()) + if (newPos < GetBuffer().GetRange().GetEnd()+1) { - GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition+1, m_caretPosition+1), this); + bool processed = false; + if (event.CmdDown()) + { + long pos = wxRichTextCtrl::FindNextWordPosition(1); + if (pos != -1 && (pos > newPos)) + { + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos+1, pos), this); + processed = true; + } + } + + if (!processed) + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos+1, newPos+1), this); } - else - DeleteSelectedContent(); EndBatchUndo(); @@ -977,6 +1174,11 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags) { if (flags & wxRICHTEXT_SHIFT_DOWN) { + if (oldPos == newPos) + return false; + + wxRichTextRange oldSelection = m_selectionRange; + // If not currently selecting, start selecting if (m_selectionRange.GetStart() == -2) { @@ -993,10 +1195,14 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags) // the end. if (newPos > m_selectionAnchor) m_selectionRange.SetRange(m_selectionAnchor+1, newPos); + else if (newPos == m_selectionAnchor) + m_selectionRange = wxRichTextRange(-2, -2); else m_selectionRange.SetRange(newPos+1, m_selectionAnchor); } + RefreshForSelectionChange(oldSelection, m_selectionRange); + if (m_selectionRange.GetStart() > m_selectionRange.GetEnd()) { wxLogDebug(wxT("Strange selection range")); @@ -1111,7 +1317,11 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode) } } } - PositionCaret(); + +#if !wxRICHTEXT_USE_OWN_CARET + if (scrolled) +#endif + PositionCaret(); return scrolled; } @@ -1266,8 +1476,6 @@ bool wxRichTextCtrl::MoveRight(int noPositions, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1295,8 +1503,6 @@ bool wxRichTextCtrl::MoveLeft(int noPositions, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1386,8 +1592,6 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1409,8 +1613,6 @@ bool wxRichTextCtrl::MoveToParagraphEnd(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1432,8 +1634,6 @@ bool wxRichTextCtrl::MoveToParagraphStart(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1457,8 +1657,6 @@ bool wxRichTextCtrl::MoveToLineEnd(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1484,8 +1682,6 @@ bool wxRichTextCtrl::MoveToLineStart(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1505,8 +1701,6 @@ bool wxRichTextCtrl::MoveHome(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1528,8 +1722,6 @@ bool wxRichTextCtrl::MoveEnd(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1569,8 +1761,6 @@ bool wxRichTextCtrl::PageDown(int noPages, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } } @@ -1688,8 +1878,6 @@ bool wxRichTextCtrl::WordLeft(int WXUNUSED(n), int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1712,8 +1900,6 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1745,6 +1931,15 @@ void wxRichTextCtrl::OnSize(wxSizeEvent& event) /// Idle-time processing void wxRichTextCtrl::OnIdle(wxIdleEvent& event) { +#if wxRICHTEXT_USE_OWN_CARET + if (((wxRichTextCaret*) GetCaret())->GetNeedsUpdate()) + { + ((wxRichTextCaret*) GetCaret())->SetNeedsUpdate(false); + PositionCaret(); + GetCaret()->Show(); + } +#endif + const int layoutInterval = wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL; if (m_fullLayoutRequired && (wxGetLocalTimeMillis() > (m_fullLayoutTime + layoutInterval))) @@ -1770,7 +1965,14 @@ void wxRichTextCtrl::OnIdle(wxIdleEvent& event) /// Scrolling void wxRichTextCtrl::OnScroll(wxScrollWinEvent& event) { - // Not used +#if wxRICHTEXT_USE_OWN_CARET + if (!((wxRichTextCaret*) GetCaret())->GetNeedsUpdate()) + { + GetCaret()->Hide(); + ((wxRichTextCaret*) GetCaret())->SetNeedsUpdate(); + } +#endif + event.Skip(); } @@ -1800,14 +2002,31 @@ void wxRichTextCtrl::SetupScrollbars(bool atTop) if (!atTop) GetViewStart(& startX, & startY); - int maxPositionX = 0; // wxMax(sz.x - clientSize.x, 0); + int maxPositionX = 0; int maxPositionY = (int) ((((float)(wxMax((unitsY*pixelsPerUnit) - clientSize.y, 0)))/((float)pixelsPerUnit)) + 0.5); + int newStartX = wxMin(maxPositionX, startX); + int newStartY = wxMin(maxPositionY, startY); + + int oldPPUX, oldPPUY; + int oldStartX, oldStartY; + int oldVirtualSizeX = 0, oldVirtualSizeY = 0; + GetScrollPixelsPerUnit(& oldPPUX, & oldPPUY); + GetViewStart(& oldStartX, & oldStartY); + GetVirtualSize(& oldVirtualSizeX, & oldVirtualSizeY); + if (oldPPUY > 0) + oldVirtualSizeY /= oldPPUY; + + if (oldPPUX == 0 && oldPPUY == pixelsPerUnit && oldVirtualSizeY == unitsY && oldStartX == newStartX && oldStartY == newStartY) + return; + + // Don't set scrollbars if there were none before, and there will be none now. + if (oldPPUY != 0 && (oldVirtualSizeY < clientSize.y) && (unitsY*pixelsPerUnit < clientSize.y)) + return; + // Move to previous scroll position if // possible - SetScrollbars(0, pixelsPerUnit, - 0, unitsY, - wxMin(maxPositionX, startX), wxMin(maxPositionY, startY)); + SetScrollbars(0, pixelsPerUnit, 0, unitsY, newStartX, newStartY); } /// Paint the background @@ -1853,7 +2072,7 @@ bool wxRichTextCtrl::RecreateBuffer(const wxSize& size) bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType) { - bool success = GetBuffer().LoadFile(filename, fileType); + bool success = GetBuffer().LoadFile(filename, (wxRichTextFileType)fileType); if (success) m_filename = filename; @@ -1877,7 +2096,7 @@ bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType) bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType) { - if (GetBuffer().SaveFile(filename, fileType)) + if (GetBuffer().SaveFile(filename, (wxRichTextFileType)fileType)) { m_filename = filename; @@ -1898,13 +2117,17 @@ bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType) /// Add a new paragraph of text to the end of the buffer wxRichTextRange wxRichTextCtrl::AddParagraph(const wxString& text) { - return GetBuffer().AddParagraph(text); + wxRichTextRange range = GetBuffer().AddParagraph(text); + LayoutContent(); + return range; } /// Add an image wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image) { - return GetBuffer().AddImage(image); + wxRichTextRange range = GetBuffer().AddImage(image); + LayoutContent(); + return range; } // ---------------------------------------------------------------------------- @@ -1921,7 +2144,13 @@ void wxRichTextCtrl::SelectAll() void wxRichTextCtrl::SelectNone() { if (!(GetSelectionRange() == wxRichTextRange(-2, -2))) - SetSelection(-2, -2); + { + wxRichTextRange oldSelection = m_selectionRange; + + m_selectionRange = wxRichTextRange(-2, -2); + + RefreshForSelectionChange(oldSelection, m_selectionRange); + } m_selectionAnchor = -2; } @@ -1940,6 +2169,9 @@ bool wxRichTextCtrl::SelectWord(long position) if (!para) return false; + if (position == para->GetRange().GetEnd()) + position --; + long positionStart = position; long positionEnd = position; @@ -1967,6 +2199,9 @@ bool wxRichTextCtrl::SelectWord(long position) if (positionEnd >= para->GetRange().GetEnd()) positionEnd = para->GetRange().GetEnd(); + if (positionEnd < positionStart) + return false; + SetSelection(positionStart, positionEnd+1); if (positionStart >= 0) @@ -2047,13 +2282,27 @@ wxString wxRichTextCtrl::GetRange(long from, long to) const void wxRichTextCtrl::DoSetValue(const wxString& value, int flags) { - Clear(); + // Don't call Clear here, since it always sends a text updated event + m_buffer.ResetAndClearCommands(); + m_buffer.SetDirty(true); + m_caretPosition = -1; + m_caretPositionForDefaultStyle = -2; + m_caretAtLineStart = false; + m_selectionRange.SetRange(-2, -2); + + Scroll(0,0); + + if (!IsFrozen()) + { + LayoutContent(); + Refresh(false); + } if (!value.IsEmpty()) { // Remove empty paragraph GetBuffer().Clear(); - DoWriteText(value); + DoWriteText(value, flags); // for compatibility, don't move the cursor when doing SetValue() SetInsertionPoint(0); @@ -2090,7 +2339,7 @@ void wxRichTextCtrl::AppendText(const wxString& text) } /// Write an image at the current insertion point -bool wxRichTextCtrl::WriteImage(const wxImage& image, int bitmapType) +bool wxRichTextCtrl::WriteImage(const wxImage& image, wxBitmapType bitmapType) { wxRichTextImageBlock imageBlock; @@ -2101,7 +2350,7 @@ bool wxRichTextCtrl::WriteImage(const wxImage& image, int bitmapType) return false; } -bool wxRichTextCtrl::WriteImage(const wxString& filename, int bitmapType) +bool wxRichTextCtrl::WriteImage(const wxString& filename, wxBitmapType bitmapType) { wxRichTextImageBlock imageBlock; @@ -2117,7 +2366,7 @@ bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock& imageBlock) return GetBuffer().InsertImageWithUndo(m_caretPosition+1, imageBlock, this); } -bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, int bitmapType) +bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, wxBitmapType bitmapType) { if (bitmap.Ok()) { @@ -2134,7 +2383,7 @@ bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, int bitmapType) /// Insert a newline (actually paragraph) at the current insertion point. bool wxRichTextCtrl::Newline() { - return GetBuffer().InsertNewlineWithUndo(m_caretPosition+1, this); + return GetBuffer().InsertNewlineWithUndo(m_caretPosition+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE); } /// Insert a line break at the current insertion point. @@ -2238,6 +2487,8 @@ void wxRichTextCtrl::SetInsertionPoint(long pos) SelectNone(); m_caretPosition = pos - 1; + + PositionCaret(); } void wxRichTextCtrl::SetInsertionPointEnd() @@ -2290,13 +2541,21 @@ void wxRichTextCtrl::SetSelection(long from, long to) void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCaret)) { - m_selectionAnchor = from; - m_selectionRange.SetRange(from, to-1); - if (from > -2) - m_caretPosition = from-1; + if (from == to) + { + SelectNone(); + } + else + { + wxRichTextRange oldSelection = m_selectionRange; + m_selectionAnchor = from; + m_selectionRange.SetRange(from, to-1); + if (from > -2) + m_caretPosition = from-1; - Refresh(false); - PositionCaret(); + RefreshForSelectionChange(oldSelection, m_selectionRange); + PositionCaret(); + } } // ---------------------------------------------------------------------------- @@ -2319,7 +2578,7 @@ void wxRichTextCtrl::Remove(long from, long to) { SelectNone(); - GetBuffer().DeleteRangeWithUndo(wxRichTextRange(from, to), this); + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(from, to-1), this); LayoutContent(); if (!IsFrozen()) @@ -2632,8 +2891,11 @@ void wxRichTextCtrl::PositionCaret() wxPoint pt = GetPhysicalPoint(newPt); if (GetCaret()->GetPosition() != pt || GetCaret()->GetSize() != newSz) { + GetCaret()->Hide(); + if (GetCaret()->GetSize() != newSz) + GetCaret()->SetSize(newSz); GetCaret()->Move(pt); - GetCaret()->SetSize(newSz); + GetCaret()->Show(); } } } @@ -2838,7 +3100,11 @@ bool wxRichTextCtrl::ApplyBoldToSelection() if (HasSelection()) return SetStyleEx(GetSelectionRange(), attr, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY); else - SetAndShowDefaultStyle(attr); + { + wxRichTextAttr current = GetDefaultStyleEx(); + current.Apply(attr); + SetAndShowDefaultStyle(current); + } return true; } @@ -2852,7 +3118,11 @@ bool wxRichTextCtrl::ApplyItalicToSelection() if (HasSelection()) return SetStyleEx(GetSelectionRange(), attr, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY); else - SetAndShowDefaultStyle(attr); + { + wxRichTextAttr current = GetDefaultStyleEx(); + current.Apply(attr); + SetAndShowDefaultStyle(current); + } return true; } @@ -2866,7 +3136,11 @@ bool wxRichTextCtrl::ApplyUnderlineToSelection() if (HasSelection()) return SetStyleEx(GetSelectionRange(), attr, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY); else - SetAndShowDefaultStyle(attr); + { + wxRichTextAttr current = GetDefaultStyleEx(); + current.Apply(attr); + SetAndShowDefaultStyle(current); + } return true; } @@ -2908,7 +3182,7 @@ bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def) // attributes are applied. wxTextAttr attr(GetStyleSheet() ? def->GetStyleMergedWithBase(GetStyleSheet()) : def->GetStyle()); - int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE; + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_RESET; if (def->IsKindOf(CLASSINFO(wxRichTextListStyleDefinition))) { @@ -2944,7 +3218,9 @@ bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def) return SetStyleEx(GetSelectionRange(), attr, flags); else { - SetAndShowDefaultStyle(attr); + wxRichTextAttr current = GetDefaultStyleEx(); + current.Apply(attr); + SetAndShowDefaultStyle(current); return true; } } @@ -3113,5 +3389,175 @@ void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event) Refresh(); } +// Refresh the area affected by a selection change +bool wxRichTextCtrl::RefreshForSelectionChange(const wxRichTextRange& oldSelection, const wxRichTextRange& newSelection) +{ + // Calculate the refresh rectangle - just the affected lines + long firstPos, lastPos; + if (oldSelection.GetStart() == -2 && newSelection.GetStart() != -2) + { + firstPos = newSelection.GetStart(); + lastPos = newSelection.GetEnd(); + } + else if (oldSelection.GetStart() != -2 && newSelection.GetStart() == -2) + { + firstPos = oldSelection.GetStart(); + lastPos = oldSelection.GetEnd(); + } + else if (oldSelection.GetStart() == -2 && newSelection.GetStart() == -2) + { + return false; + } + else + { + firstPos = wxMin(oldSelection.GetStart(), newSelection.GetStart()); + lastPos = wxMax(oldSelection.GetEnd(), newSelection.GetEnd()); + } + + wxRichTextLine* firstLine = GetBuffer().GetLineAtPosition(firstPos); + wxRichTextLine* lastLine = GetBuffer().GetLineAtPosition(lastPos); + + if (firstLine && lastLine) + { + wxSize clientSize = GetClientSize(); + wxPoint pt1 = GetPhysicalPoint(firstLine->GetAbsolutePosition()); + wxPoint pt2 = GetPhysicalPoint(lastLine->GetAbsolutePosition()) + wxPoint(0, lastLine->GetSize().y); + + pt1.x = 0; + pt1.y = wxMax(0, pt1.y); + pt2.x = 0; + pt2.y = wxMin(clientSize.y, pt2.y); + + wxRect rect(pt1, wxSize(clientSize.x, pt2.y - pt1.y)); + RefreshRect(rect, false); + } + else + Refresh(false); + + return true; +} + +#if wxRICHTEXT_USE_OWN_CARET + +// ---------------------------------------------------------------------------- +// initialization and destruction +// ---------------------------------------------------------------------------- + +void wxRichTextCaret::Init() +{ + m_hasFocus = true; + + m_xOld = + m_yOld = -1; + m_richTextCtrl = NULL; + m_needsUpdate = false; +} + +wxRichTextCaret::~wxRichTextCaret() +{ +} + +// ---------------------------------------------------------------------------- +// showing/hiding/moving the caret (base class interface) +// ---------------------------------------------------------------------------- + +void wxRichTextCaret::DoShow() +{ + Refresh(); +} + +void wxRichTextCaret::DoHide() +{ + Refresh(); +} + +void wxRichTextCaret::DoMove() +{ + if (IsVisible()) + { + Refresh(); + + if (m_xOld != -1 && m_yOld != -1) + { + if (m_richTextCtrl) + { + wxRect rect(GetPosition(), GetSize()); + m_richTextCtrl->RefreshRect(rect, false); + } + } + } + + m_xOld = m_x; + m_yOld = m_y; +} + +void wxRichTextCaret::DoSize() +{ + int countVisible = m_countVisible; + if (countVisible > 0) + { + m_countVisible = 0; + DoHide(); + } + + if (countVisible > 0) + { + m_countVisible = countVisible; + DoShow(); + } +} + +// ---------------------------------------------------------------------------- +// handling the focus +// ---------------------------------------------------------------------------- + +void wxRichTextCaret::OnSetFocus() +{ + m_hasFocus = true; + + if ( IsVisible() ) + Refresh(); +} + +void wxRichTextCaret::OnKillFocus() +{ + m_hasFocus = false; +} + +// ---------------------------------------------------------------------------- +// drawing the caret +// ---------------------------------------------------------------------------- + +void wxRichTextCaret::Refresh() +{ + if (m_richTextCtrl) + { + wxRect rect(GetPosition(), GetSize()); + m_richTextCtrl->RefreshRect(rect, false); + } +} + +void wxRichTextCaret::DoDraw(wxDC *dc) +{ + dc->SetPen( *wxBLACK_PEN ); + + dc->SetBrush(*(m_hasFocus ? wxBLACK_BRUSH : wxTRANSPARENT_BRUSH)); + dc->SetPen(*wxBLACK_PEN); + + // VZ: unfortunately, the rectangle comes out a pixel smaller when this is + // done under wxGTK - no idea why + //dc->SetLogicalFunction(wxINVERT); + + wxPoint pt(m_x, m_y); + + if (m_richTextCtrl) + { + pt = m_richTextCtrl->GetLogicalPoint(pt); + } + dc->DrawRectangle(pt.x, pt.y, m_width, m_height); +} +#endif + // wxRICHTEXT_USE_OWN_CARET + #endif // wxUSE_RICHTEXT