From a6fb54ec71b61642b47d107b660855a37f7c1b8a Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Tue, 29 Apr 2008 09:10:05 +0000 Subject: [PATCH] Added a wxRichTextCtrl-specific caret implementation in case of need git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@53408 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/richtext/richtextbuffer.h | 11 +- src/richtext/richtextbuffer.cpp | 6 + src/richtext/richtextctrl.cpp | 264 +++++++++++++++++++++++++-- 3 files changed, 261 insertions(+), 20 deletions(-) diff --git a/include/wx/richtext/richtextbuffer.h b/include/wx/richtext/richtextbuffer.h index f970e83728..754f5d49ca 100644 --- a/include/wx/richtext/richtextbuffer.h +++ b/include/wx/richtext/richtextbuffer.h @@ -70,6 +70,14 @@ #include "wx/dataobj.h" #endif +// Setting wxRICHTEXT_USE_OWN_CARET to 1 implements a non-flashing +// cursor reliably without using wxClientDC in case there +// are platform-specific problems with the generic caret. +#define wxRICHTEXT_USE_OWN_CARET 0 + +// Switch off for binary compatibility, on for faster drawing +#define wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING 0 + /*! * Special characters */ @@ -285,9 +293,6 @@ class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextBuffer; #define wxSCRIPT_MUL_FACTOR 1.5 -// Switch off for binary compatibility, on for faster drawing -#define wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING 0 - /*! * wxRichTextRange class declaration * This stores beginning and end positions for a range of data. diff --git a/src/richtext/richtextbuffer.cpp b/src/richtext/richtextbuffer.cpp index 12f91d4133..92599f467a 100644 --- a/src/richtext/richtextbuffer.cpp +++ b/src/richtext/richtextbuffer.cpp @@ -7073,6 +7073,9 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent m_ctrl->Refresh(false); } +#if wxRICHTEXT_USE_OWN_CARET + m_ctrl->PositionCaret(); +#endif if (sendUpdateEvent) m_ctrl->SendTextUpdatedEvent(); } @@ -7222,6 +7225,9 @@ bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, i if (!range.IsWithin(GetRange())) return false; + if (!m_image.Ok()) + ((wxRichTextImage*) this)->LoadFromBlock(); + #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS if (g_UseGlobalPartialTextExtents) { diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index 40be6f07cc..060d8b54cd 100644 --- a/src/richtext/richtextctrl.cpp +++ b/src/richtext/richtextctrl.cpp @@ -60,6 +60,69 @@ 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 ) IMPLEMENT_CLASS( wxRichTextEvent, wxNotifyEvent ) @@ -178,8 +241,11 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va 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)); - GetCaret()->Show(); +#endif // Tell the sizers to use the given or best size SetInitialSize(size); @@ -273,8 +339,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 @@ -284,8 +352,10 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) #endif PrepareDC(dc); - if (m_freezeCount > 0) + if (IsFrozen()) + { return; + } dc.SetFont(GetFont()); @@ -306,12 +376,21 @@ 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 @@ -323,22 +402,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)) @@ -1128,7 +1218,9 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode) } } +#if !wxRICHTEXT_USE_OWN_CARET if (scrolled) +#endif PositionCaret(); return scrolled; @@ -1735,10 +1827,18 @@ void wxRichTextCtrl::OnSize(wxSizeEvent& event) event.Skip(); } - /// 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))) @@ -1764,7 +1864,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(); } @@ -2741,8 +2848,6 @@ void wxRichTextCtrl::PositionCaret() if (!GetCaret()) return; - //wxLogDebug(wxT("PositionCaret")); - wxRect caretRect; if (GetCaretPositionForIndex(GetCaretPosition(), caretRect)) { @@ -2751,8 +2856,12 @@ void wxRichTextCtrl::PositionCaret() wxPoint pt = GetPhysicalPoint(newPt); if (GetCaret()->GetPosition() != pt || GetCaret()->GetSize() != newSz) { + //wxLogDebug(wxT("Positioning caret %d, %d"), pt.x, pt.y); + GetCaret()->Hide(); + if (GetCaret()->GetSize() != newSz) + GetCaret()->SetSize(newSz); GetCaret()->Move(pt); - GetCaret()->SetSize(newSz); + GetCaret()->Show(); } } } @@ -3282,5 +3391,126 @@ bool wxRichTextCtrlRefreshForSelectionChange(wxRichTextCtrl& ctrl, const wxRichT 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