From: Vadim Zeitlin Date: Fri, 22 Sep 2000 22:44:34 +0000 (+0000) Subject: wxCaret now uses backing store instead of forcing window refresh each time the X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/f4b8bf2fd1fab57c46063f5955fe24ba3ed2c23e wxCaret now uses backing store instead of forcing window refresh each time the caret is hidden; the non blinking carets work too git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@8403 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/caret.h b/include/wx/caret.h index 9e0f3d3ea8..07e06afeea 100644 --- a/include/wx/caret.h +++ b/include/wx/caret.h @@ -196,5 +196,31 @@ private: #include "wx/generic/caret.h" #endif // platform +// ---------------------------------------------------------------------------- +// wxCaretSuspend: a simple class which hides the caret in its ctor and +// restores it in the dtor, this should be used when drawing on the screen to +// avoid overdrawing the caret +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxCaretSuspend +{ +public: + wxCaretSuspend(wxWindow *win) + { + m_caret = win->GetCaret(); + if ( m_caret ) + m_caret->Hide(); + } + + ~wxCaretSuspend() + { + if ( m_caret ) + m_caret->Show(); + } + +private: + wxCaret *m_caret; +}; + #endif // _WX_CARET_H_BASE_ diff --git a/include/wx/generic/caret.h b/include/wx/generic/caret.h index 9b2340de44..173e80a37b 100644 --- a/include/wx/generic/caret.h +++ b/include/wx/generic/caret.h @@ -73,6 +73,12 @@ private: // GTK specific initialization void InitGeneric(); + // the bitmap holding the part of window hidden by the caret when it was + // at (m_xOld, m_yOld) + wxBitmap m_bmpUnderCaret; + int m_xOld, + m_yOld; + wxCaretTimer m_timer; bool m_blinkedOut, // TRUE => caret hidden right now m_hasFocus; // TRUE => our window has focus diff --git a/samples/caret/caret.cpp b/samples/caret/caret.cpp index d62a84c1c9..760b54a830 100644 --- a/samples/caret/caret.cpp +++ b/samples/caret/caret.cpp @@ -358,6 +358,7 @@ void MyCanvas::OnSize( wxSizeEvent &event ) // would use GetUpdateRegion() and iterate over rectangles it contains void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) ) { + wxCaretSuspend cs(this); wxPaintDC dc( this ); PrepareDC( dc ); dc.Clear(); @@ -382,8 +383,6 @@ void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) ) void MyCanvas::OnChar( wxKeyEvent &event ) { - bool refresh = FALSE; - switch ( event.KeyCode() ) { case WXK_LEFT: @@ -418,10 +417,17 @@ void MyCanvas::OnChar( wxKeyEvent &event ) default: if ( !event.AltDown() && wxIsprint(event.KeyCode()) ) { - CharAt(m_xCaret, m_yCaret) = (wxChar)event.KeyCode(); - NextChar(); + wxChar ch = (wxChar)event.KeyCode(); + CharAt(m_xCaret, m_yCaret) = ch; + + wxCaretSuspend cs(this); + wxClientDC dc(this); + dc.SetFont(m_font); + dc.SetBackgroundMode(wxSOLID); // overwrite old value + dc.DrawText(ch, m_xMargin + m_xCaret * m_widthChar, + m_yMargin + m_yCaret * m_heightChar ); - refresh = TRUE; + NextChar(); } else { @@ -430,8 +436,5 @@ void MyCanvas::OnChar( wxKeyEvent &event ) } DoMoveCaret(); - - if ( refresh ) - Refresh(); } diff --git a/src/generic/caret.cpp b/src/generic/caret.cpp index 98966be56a..444a59fea1 100644 --- a/src/generic/caret.cpp +++ b/src/generic/caret.cpp @@ -33,6 +33,7 @@ #ifndef WX_PRECOMP #include "wx/window.h" #include "wx/dcclient.h" + #include "wx/dcmemory.h" #endif //WX_PRECOMP #include "wx/caret.h" @@ -91,6 +92,10 @@ void wxCaret::InitGeneric() { m_hasFocus = TRUE; m_blinkedOut = FALSE; + + m_xOld = + m_yOld = -1; + m_bmpUnderCaret.Create(m_width, m_height); } wxCaret::~wxCaret() @@ -134,12 +139,12 @@ void wxCaret::DoMove() if ( !m_blinkedOut ) { // hide it right now and it will be shown the next time it blinks - // unless it should be shown all the time in which case just show - // it at the new position - if ( m_timer.IsRunning() ) + Blink(); + + // but if the caret is not blinking, we should blink it back into + // visibility manually + if ( !m_timer.IsRunning() ) Blink(); - else - Refresh(); } } //else: will be shown at the correct location when it is shown @@ -165,10 +170,14 @@ void wxCaret::OnKillFocus() // the caret must be shown - otherwise, if it is hidden now, it will // stay so until the focus doesn't return because it won't blink any // more - m_blinkedOut = FALSE; - } - Refresh(); + // hide it first if it isn't hidden ... + if ( !m_blinkedOut ) + Blink(); + + // .. and show it in the new style + Blink(); + } } // ---------------------------------------------------------------------------- @@ -184,20 +193,32 @@ void wxCaret::Blink() void wxCaret::Refresh() { - if ( !m_blinkedOut ) + wxClientDC dcWin(GetWindow()); + wxMemoryDC dcMem; + dcMem.SelectObject(m_bmpUnderCaret); + if ( m_blinkedOut ) { - wxClientDC dc(GetWindow()); - DoDraw(&dc); + // restore the old image + dcWin.Blit(m_xOld, m_yOld, m_width, m_height, + &dcMem, 0, 0); + m_xOld = + m_yOld = -1; } else { - // FIXME can't be less efficient than this... we probably should use - // backing store for the caret instead of leaving all the burden - // of correct refresh logic handling to the user code + if ( m_xOld == -1 && m_yOld == -1 ) + { + // save the part we're going to overdraw + dcMem.Blit(0, 0, m_width, m_height, + &dcWin, m_x, m_y); + m_xOld = m_x; + m_yOld = m_y; + } + //else: we already saved the image below the caret, don't do it any + // more - // NB: +1 is needed! - wxRect rect(m_x, m_y, m_width + 1, m_height + 1); - GetWindow()->Refresh(FALSE, &rect); + // and draw the caret there + DoDraw(&dcWin); } } @@ -205,19 +226,14 @@ void wxCaret::DoDraw(wxDC *dc) { dc->SetPen( *wxBLACK_PEN ); - // VZ: Robert's code for I-shaped caret - this is nice but doesn't look - // at all the same as the MSW version and I don't know how to indicate - // that the window has focus or not with such caret -#if 0 - dc->DrawLine( m_x, m_y, m_x+m_width, m_y ); - dc->DrawLine( m_x, m_y+m_height, m_x+m_width, m_y+m_height ); - dc->DrawLine( m_x+(m_width/2), m_y, m_x+(m_width/2), m_y+m_height ); -// dc->DrawLine( m_x+(m_width/2)+1, m_y, m_x+(m_width/2)+1, m_y+m_height ); -#else // 1 - if ( m_hasFocus ) - dc->SetBrush( *wxBLACK_BRUSH ); - dc->DrawRectangle( m_x, m_y, m_width, m_height ); -#endif // 0/1 + 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); + + dc->DrawRectangle(m_x, m_y, m_width, m_height); } #endif // wxUSE_CARET