X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/44cc96a80c09c8572e1315be66d29f6d610cbf78..1a9a6eed360bc9a263f2ea7c0d470953397de531:/src/richtext/richtextctrl.cpp diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index f3247070de..c4a91f1528 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 ) @@ -76,6 +141,7 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxControl ) EVT_KILL_FOCUS(wxRichTextCtrl::OnKillFocus) EVT_MOUSE_CAPTURE_LOST(wxRichTextCtrl::OnCaptureLost) EVT_CONTEXT_MENU(wxRichTextCtrl::OnContextMenu) + EVT_SYS_COLOUR_CHANGED(wxRichTextCtrl::OnSysColourChanged) EVT_MENU(wxID_UNDO, wxRichTextCtrl::OnUndo) EVT_UPDATE_UI(wxID_UNDO, wxRichTextCtrl::OnUpdateUndo) @@ -139,12 +205,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); @@ -156,8 +216,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); @@ -169,6 +227,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); @@ -187,6 +254,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; } @@ -200,7 +278,6 @@ wxRichTextCtrl::~wxRichTextCtrl() /// Member initialisation void wxRichTextCtrl::Init() { - m_freezeCount = 0; m_contextMenu = NULL; m_caret = NULL; m_caretPosition = -1; @@ -216,25 +293,13 @@ void wxRichTextCtrl::Init() m_caretPositionForDefaultStyle = -2; } -/// Call Freeze to prevent refresh -void wxRichTextCtrl::Freeze() +void wxRichTextCtrl::DoThaw() { - m_freezeCount ++; -} - -/// Call Thaw to refresh -void wxRichTextCtrl::Thaw() -{ - m_freezeCount --; - - if (m_freezeCount == 0) - { - if (GetBuffer().GetDirty()) - LayoutContent(); - else - SetupScrollbars(); - Refresh(false); - } + if (GetBuffer().GetDirty()) + LayoutContent(); + else + SetupScrollbars(); + Refresh(false); } /// Clear all text @@ -247,7 +312,9 @@ void wxRichTextCtrl::Clear() m_caretAtLineStart = false; m_selectionRange.SetRange(-2, -2); - if (m_freezeCount == 0) + Scroll(0,0); + + if (!IsFrozen()) { LayoutContent(); Refresh(false); @@ -259,8 +326,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 @@ -268,11 +337,12 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) #else wxPaintDC dc(this); #endif - PrepareDC(dc); - if (m_freezeCount > 0) + if (IsFrozen()) return; + PrepareDC(dc); + dc.SetFont(GetFont()); // Paint the background @@ -292,12 +362,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 @@ -309,22 +386,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)) @@ -350,8 +438,6 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event) m_dragging = true; CaptureMouse(); - SelectNone(); - bool caretAtLineStart = false; if (hit & wxRICHTEXT_HITTEST_BEFORE) @@ -367,8 +453,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(); @@ -392,7 +490,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, @@ -494,19 +592,16 @@ 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); } } } /// Right-click -void wxRichTextCtrl::OnRightClick(wxMouseEvent& WXUNUSED(event)) +void wxRichTextCtrl::OnRightClick(wxMouseEvent& event) { SetFocus(); @@ -516,7 +611,8 @@ void wxRichTextCtrl::OnRightClick(wxMouseEvent& WXUNUSED(event)) cmdEvent.SetEventObject(this); cmdEvent.SetPosition(m_caretPosition+1); - GetEventHandler()->ProcessEvent(cmdEvent); + if (!GetEventHandler()->ProcessEvent(cmdEvent)) + event.Skip(); } /// Left-double-click @@ -603,7 +699,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) GetBuffer().InsertTextWithUndo(newPos+1, text, this); } 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(); @@ -635,7 +731,19 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) // so subtract 1 for deleted character and add 1 for conversion to character position. if (m_caretPosition > -1 && !HasSelection()) { - GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition, m_caretPosition), this); + bool processed = false; + if (event.CmdDown()) + { + long pos = wxRichTextCtrl::FindNextWordPosition(-1); + if (pos != -1 && (pos < m_caretPosition)) + { + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos+1, m_caretPosition), this); + processed = true; + } + } + + if (!processed) + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition, m_caretPosition), this); } else DeleteSelectedContent(); @@ -987,6 +1095,8 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags) { if (flags & wxRICHTEXT_SHIFT_DOWN) { + wxRichTextRange oldSelection = m_selectionRange; + // If not currently selecting, start selecting if (m_selectionRange.GetStart() == -2) { @@ -1007,6 +1117,8 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags) m_selectionRange.SetRange(newPos+1, m_selectionAnchor); } + RefreshForSelectionChange(oldSelection, m_selectionRange); + if (m_selectionRange.GetStart() > m_selectionRange.GetEnd()) { wxLogDebug(wxT("Strange selection range")); @@ -1121,7 +1233,11 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode) } } } - PositionCaret(); + +#if !wxRICHTEXT_USE_OWN_CARET + if (scrolled) +#endif + PositionCaret(); return scrolled; } @@ -1142,17 +1258,10 @@ bool wxRichTextCtrl::IsPositionVisible(long pos) const startX = 0; startY = startY * ppuY; - int sx = 0, sy = 0; - GetVirtualSize(& sx, & sy); - sx = 0; - if (ppuY != 0) - sy = sy/ppuY; - wxRect rect = line->GetRect(); - wxSize clientSize = GetClientSize(); - return !(((rect.y + rect.height) > (clientSize.y + startY)) || rect.y < startY); + return (rect.GetBottom() > startY) && (rect.GetTop() < (startY + clientSize.y)); } void wxRichTextCtrl::SetCaretPosition(long position, bool showAtLineStart) @@ -1283,8 +1392,6 @@ bool wxRichTextCtrl::MoveRight(int noPositions, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1312,8 +1419,6 @@ bool wxRichTextCtrl::MoveLeft(int noPositions, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1403,8 +1508,6 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1426,8 +1529,6 @@ bool wxRichTextCtrl::MoveToParagraphEnd(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1449,8 +1550,6 @@ bool wxRichTextCtrl::MoveToParagraphStart(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1474,8 +1573,6 @@ bool wxRichTextCtrl::MoveToLineEnd(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1501,8 +1598,6 @@ bool wxRichTextCtrl::MoveToLineStart(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1522,8 +1617,6 @@ bool wxRichTextCtrl::MoveHome(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1545,8 +1638,6 @@ bool wxRichTextCtrl::MoveEnd(int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } else @@ -1586,8 +1677,6 @@ bool wxRichTextCtrl::PageDown(int noPages, int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } } @@ -1705,8 +1794,6 @@ bool wxRichTextCtrl::WordLeft(int WXUNUSED(n), int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1729,8 +1816,6 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags) PositionCaret(); SetDefaultStyleToCursorStyle(); - if (extendSel) - Refresh(false); return true; } @@ -1762,6 +1847,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))) @@ -1787,14 +1881,21 @@ 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(); } /// Set up scrollbars, e.g. after a resize void wxRichTextCtrl::SetupScrollbars(bool atTop) { - if (m_freezeCount) + if (IsFrozen()) return; if (GetBuffer().IsEmpty()) @@ -1817,14 +1918,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 @@ -1870,7 +1988,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; @@ -1894,7 +2012,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; @@ -1915,13 +2033,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; } // ---------------------------------------------------------------------------- @@ -1938,7 +2060,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; } @@ -1957,6 +2085,9 @@ bool wxRichTextCtrl::SelectWord(long position) if (!para) return false; + if (position == para->GetRange().GetEnd()) + position --; + long positionStart = position; long positionEnd = position; @@ -1984,6 +2115,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) @@ -2064,13 +2198,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); @@ -2107,7 +2255,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; @@ -2118,7 +2266,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; @@ -2134,7 +2282,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()) { @@ -2255,6 +2403,8 @@ void wxRichTextCtrl::SetInsertionPoint(long pos) SelectNone(); m_caretPosition = pos - 1; + + PositionCaret(); } void wxRichTextCtrl::SetInsertionPointEnd() @@ -2307,13 +2457,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(); + } } // ---------------------------------------------------------------------------- @@ -2336,7 +2494,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()) @@ -2649,8 +2807,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(); } } } @@ -2855,7 +3016,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; } @@ -2869,7 +3034,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; } @@ -2883,7 +3052,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; } @@ -2925,7 +3098,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))) { @@ -2961,7 +3134,9 @@ bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def) return SetStyleEx(GetSelectionRange(), attr, flags); else { - SetAndShowDefaultStyle(attr); + wxRichTextAttr current = GetDefaultStyleEx(); + current.Apply(attr); + SetAndShowDefaultStyle(current); return true; } } @@ -3118,5 +3293,187 @@ void wxRichTextCtrl::ClearAvailableFontNames() sm_availableFontNames.Clear(); } +void wxRichTextCtrl::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) +{ + //wxLogDebug(wxT("wxRichTextCtrl::OnSysColourChanged")); + + wxTextAttrEx basicStyle = GetBasicStyle(); + basicStyle.SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + SetBasicStyle(basicStyle); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + 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