diff --git a/TODO b/TODO index 67fe295a0d..0a72e6bf81 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,7 @@ TODO wxTextCtrl -o DoDraw should iterat over update region instead of using bounding box +* display corrupted when typing text in quickly All @@ -31,6 +31,7 @@ DONE All + text ctrl horz scrolling ++ DoDraw should iterat over update region instead of using bounding box MSW diff --git a/include/wx/gdicmn.h b/include/wx/gdicmn.h index edd634d87f..3d8dc4efb9 100644 --- a/include/wx/gdicmn.h +++ b/include/wx/gdicmn.h @@ -302,6 +302,7 @@ public: void SetTop(int top) { y = top; } void SetBottom(int bottom) { height = bottom - y + 1; } + // operations with rect void Inflate(wxCoord dx, wxCoord dy) { x -= dx; @@ -312,12 +313,17 @@ public: void Inflate(wxCoord d) { Inflate(d, d); } + void Offset(wxCoord dx, wxCoord dy) { x += dx; y += dy; } + void Offset(const wxPoint& pt) { Offset(pt.x, pt.y); } + + wxRect operator+(const wxRect& rect) const; + wxRect& operator+=(const wxRect& rect); + + // tests bool operator==(const wxRect& rect) const; bool operator!=(const wxRect& rect) const { return !(*this == rect); } bool Inside(int cx, int cy) const; - wxRect operator+(const wxRect& rect) const; - wxRect& operator+=(const wxRect& rect); public: int x, y, width, height; diff --git a/include/wx/univ/textctrl.h b/include/wx/univ/textctrl.h index 1b5ae8d7b0..c6342beb9b 100644 --- a/include/wx/univ/textctrl.h +++ b/include/wx/univ/textctrl.h @@ -169,6 +169,7 @@ public: // caret stuff virtual void ShowCaret(bool show = TRUE); void HideCaret() { ShowCaret(FALSE); } + void CreateCaret(); // for the current font size wxCoord GetCaretPosition() const; // in pixels // helpers for cursor movement @@ -176,7 +177,8 @@ public: long GetWordEnd() const; // selection helpers - bool HasSelection() const { return m_selStart != -1; } + bool HasSelection() const + { return m_selStart != -1 && m_selEnd > m_selStart; } void ClearSelection(); void RemoveSelection(); wxString GetSelectionText() const; @@ -225,6 +227,9 @@ public: long numArg = -1, const wxString& strArg = wxEmptyString); + // override this to recreate the caret here + virtual bool SetFont(const wxFont &font); + protected: // draw the text void DrawTextLine(wxDC& dc, const wxRect& rect, @@ -251,8 +256,16 @@ protected: // get the extent (width) of the text wxCoord GetTextWidth(const wxString& text) const; - // refresh the text in the given range (in text coords) of this line - void RefreshLine(long line, long from, long to); + // refresh the text in the given range (in logical coords) of this line, if + // width is 0, refresh to the end of line + void RefreshPixelRange(long line, wxCoord start, wxCoord width); + + // refresh the text in the given range (in text coords) in this line + void RefreshLineRange(long line, long start, long count); + + // refresh the text in the given range which can span multiple lines + // (this method accepts arguments in any order) + void RefreshTextRange(long start, long end); // get the text to show: either the text itself or the text replaced with // starts for wxTE_PASSWORD control @@ -277,6 +290,9 @@ private: // the value (may be only part of it for the multiline controls) wxString m_value; + // the initially specified control size + wxSize m_sizeInitial; + // current position long m_curPos, m_curLine, diff --git a/include/wx/univ/window.h b/include/wx/univ/window.h index 2e6525896a..5fead5a626 100644 --- a/include/wx/univ/window.h +++ b/include/wx/univ/window.h @@ -98,7 +98,7 @@ public: virtual int GetScrollThumb(int orient) const; virtual int GetScrollRange(int orient) const; virtual void ScrollWindow(int dx, int dy, - const wxRect* rect = (wxRect *) NULL); + const wxRect* rect = (wxRect *) NULL); // take into account the borders here virtual wxPoint GetClientAreaOrigin() const; @@ -150,9 +150,19 @@ public: // querying the current theme wxRenderer *GetRenderer() const { return m_renderer; } + // scrolling helper: like ScrollWindow() except that it doesn't refresh the + // uncovered window areas but returns the rectangle to update (don't call + // this with both dx and dy non zero) + wxRect ScrollNoRefresh(int dx, int dy, const wxRect *rect = NULL); + // overridden base class methods // ----------------------------- + // the rect coordinates are, for us, in client coords, but if no rect is + // specified, the entire window is refreshed + virtual void Refresh(bool eraseBackground = TRUE, + const wxRect *rect = (const wxRect *) NULL); + // remember that the font/colour was changed virtual bool SetBackgroundColour(const wxColour& colour); virtual bool SetForegroundColour(const wxColour& colour); diff --git a/samples/univ/univ.cpp b/samples/univ/univ.cpp index 78afc03195..40fc9635af 100644 --- a/samples/univ/univ.cpp +++ b/samples/univ/univ.cpp @@ -233,7 +233,7 @@ MyUnivFrame::MyUnivFrame(const wxString& title) #ifndef TEST_TEXT_ONLY wxSize(700, 700) #else - wxSize(240, 150) + wxSize(240, 200) #endif ) { @@ -383,8 +383,13 @@ MyUnivFrame::MyUnivFrame(const wxString& title) new wxTextCtrl(this, -1, _T("Hello, Universe!"), wxPoint(550, 150), wxDefaultSize); #else // TEST_TEXT_ONLY - new wxTextCtrl(this, -1, _T("Hello, Universe!"), - wxPoint(10, 40), wxSize(200, -1)); + wxTextCtrl *text = new wxTextCtrl(this, -1, _T("Hello, Universe!"), + wxPoint(10, 40)); + text->SetFont(wxFont(24, wxFONTFAMILY_DEFAULT, + wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + wxSize sizeText = text->GetBestSize(); + sizeText.x = 200; + text->SetSize(sizeText); #endif // !TEST_TEXT_ONLY/TEST_TEXT_ONLY } diff --git a/src/univ/listbox.cpp b/src/univ/listbox.cpp index 2ae8af949f..488c3e2bee 100644 --- a/src/univ/listbox.cpp +++ b/src/univ/listbox.cpp @@ -492,7 +492,10 @@ void wxListBox::OnIdle(wxIdleEvent& event) } else { - wxRect rect = GetClientRect(); + wxSize size = GetClientSize(); + wxRect rect; + rect.width = size.x; + rect.height = size.y; rect.y += m_updateFrom*GetLineHeight(); rect.height = m_updateCount*GetLineHeight(); CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y); diff --git a/src/univ/scrolbar.cpp b/src/univ/scrolbar.cpp index 2210582119..bca063c5b2 100644 --- a/src/univ/scrolbar.cpp +++ b/src/univ/scrolbar.cpp @@ -261,6 +261,7 @@ void wxScrollBar::OnIdle(wxIdleEvent& event) #endif // 0/1 } + // FIXME: rect is client or win (must be client)? Refresh(TRUE, &rect); } diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp index c8af4206d2..992a0c9a01 100644 --- a/src/univ/textctrl.cpp +++ b/src/univ/textctrl.cpp @@ -53,6 +53,20 @@ // turn extra wxTextCtrl-specific debugging on/off #define WXDEBUG_TEXT +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static inline void OrderPositions(long& from, long& to) +{ + if ( from > to ) + { + long tmp = from; + from = to; + to = tmp; + } +} + // ============================================================================ // implementation // ============================================================================ @@ -103,19 +117,27 @@ bool wxTextCtrl::Create(wxWindow *parent, return FALSE; } - // FIXME use renderer - wxCaret *caret = new wxCaret(this, 1, GetCharHeight()); -#ifndef __WXMSW__ - caret->SetBlinkTime(0); -#endif // __WXMSW__ - SetCaret(caret); - SetCursor(wxCURSOR_IBEAM); SetValue(value); - SetBestSize(size); + SetBestSize(m_sizeInitial); + CreateCaret(); - caret->Show(); + return TRUE; +} + +bool wxTextCtrl::SetFont(const wxFont& font) +{ + if ( !wxControl::SetFont(font) ) + return FALSE; + + // recreate it, in fact + CreateCaret(); + + // and refresh everything, of course + SetInsertionPoint(0); + ClearSelection(); + Refresh(); return TRUE; } @@ -149,11 +171,30 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text) // replace the part of the text with the new value wxString valueNew(m_value, (size_t)from); + + // remember it for later use + wxCoord startNewText = GetTextWidth(valueNew); + + // if we really replace something, refresh till the end of line as all + // remaining text in it is affected, but if we just added some text to the + // end of line, we only need to refresh the area occupied by this text + // refresh to the end of the line + wxCoord widthNewText; + valueNew += text; - if ( (unsigned long)to < m_value.length() ) + if ( (size_t)to < m_value.length() ) { valueNew += m_value.c_str() + (size_t)to; + + // refresh till the end of line + widthNewText = 0; } + else // text appended, not replaced + { + // refresh only the new text + widthNewText = GetTextWidth(text); + } + m_value = valueNew; // force m_colLastVisible update @@ -166,22 +207,17 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text) // for selection anchor) ClearSelection(); - // refresh to the end of the line - RefreshLine(0, from, -1); + // repaint + RefreshPixelRange(0, startNewText, widthNewText); - // and the affected parts of the next line (TODO) + // TODO: and the affected parts of the next line(s) } void wxTextCtrl::Remove(long from, long to) { - if ( from > to ) - { - // Replace() only works with correctly ordered arguments, so exchange - // them - long tmp = from; - from = to; - to = tmp; - } + // Replace() only works with correctly ordered arguments, so exchange them + // if necessary + OrderPositions(from, to); Replace(from, to, _T("")); } @@ -291,7 +327,7 @@ wxString wxTextCtrl::GetSelectionText() const void wxTextCtrl::SetSelection(long from, long to) { - if ( from == -1 || to == -1 ) + if ( from == -1 || to == from ) { ClearSelection(); } @@ -309,14 +345,36 @@ void wxTextCtrl::SetSelection(long from, long to) if ( from != m_selStart || to != m_selEnd ) { + // we need to use temp vars as RefreshTextRange() may call DoDraw() + // directly and so m_selStart/End must be reset by then + long selStartOld = m_selStart, + selEndOld = m_selEnd; + m_selStart = from; m_selEnd = to; wxLogTrace(_T("text"), _T("Selection range is %ld-%ld"), m_selStart, m_selEnd); - // FIXME: shouldn't refresh everything - Refresh(); + // refresh only the part of text which became (un)selected if + // possible + if ( selStartOld == m_selStart ) + { + RefreshTextRange(selEndOld, m_selEnd); + } + else if ( selEndOld == m_selEnd ) + { + RefreshTextRange(m_selStart, selStartOld); + } + else + { + // OPT: could check for other cases too but it is probably not + // worth it as the two above are the most common ones + if ( selStartOld != -1 ) + RefreshTextRange(selStartOld, selEndOld); + if ( m_selStart != -1 ) + RefreshTextRange(m_selStart, m_selEnd); + } } //else: nothing to do } @@ -326,11 +384,17 @@ void wxTextCtrl::ClearSelection() { if ( HasSelection() ) { + // we need to use temp vars as RefreshTextRange() may call DoDraw() + // directly (see above as well) + long selStart = m_selStart, + selEnd = m_selEnd; + + // no selection any more m_selStart = m_selEnd = -1; - // FIXME: shouldn't refresh everything - Refresh(); + // refresh the old selection + RefreshTextRange(selStart, selEnd); } // the anchor should be moved even if there was no selection previously @@ -714,7 +778,7 @@ void wxTextCtrl::UpdateLastVisible() w = wOld = 0; - m_colLastVisible = m_colStart; + m_colLastVisible = m_colStart - 1; const wxChar *pc = m_value.c_str() + (size_t)m_colStart; for ( ; *pc; pc++ ) @@ -808,13 +872,13 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, wxString strBefore(line, (size_t)col); dc.GetTextExtent(strBefore, &width, NULL); - if ( width >= x ) + if ( width > x ) { if ( matchDir == 1 ) { // we were going to the right and, finally, moved beyond // the original position - stop on the previous one - //col--; + col--; break; } @@ -829,9 +893,10 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, } else // width < x { - // same logic as above + // invert the logic above if ( matchDir == -1 ) { + // with the exception that we don't need to backtrack here break; } @@ -866,12 +931,12 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, text += line[col]; dc.GetTextExtent(text, &width2, NULL); - wxASSERT_MSG( (width1 <= x) && (x <= width2), + wxASSERT_MSG( (width1 <= x) && (x < width2), _T("incorrect HitTestLine() result") ); } else // we return last char { - wxASSERT_MSG( x > width1, _T("incorrect HitTestLine() result") ); + wxASSERT_MSG( x >= width1, _T("incorrect HitTestLine() result") ); } } #endif // WXDEBUG_TEXT @@ -979,7 +1044,7 @@ void wxTextCtrl::ShowHorzPosition(wxCoord pos) // scroll forward long col; HitTestLine(GetValue(), pos - width, &col); - ScrollText(col); + ScrollText(col + 1); } } } @@ -1011,7 +1076,7 @@ void wxTextCtrl::ScrollText(long col) // order of operands int dx = m_ofsHorz - ofsHorz; - // NB2: ScrollWindow() calls Refresh() which results in a call to + // NB2: we call Refresh() below which results in a call to // DoDraw(), so we must update m_ofsHorz before calling it m_ofsHorz = ofsHorz; m_colStart = col; @@ -1020,23 +1085,65 @@ void wxTextCtrl::ScrollText(long col) if ( dx > 0 ) { // scrolling to the right: we need to recalc the last visible - // position beore scrolling + // position beore scrolling in order to make it appear exactly at + // the right edge of the text area after scrolling UpdateLastVisible(); } else { - // when scrolling to the left, we don't need to worry about the - // last visible position, it will be updated later when we draw - // the text - but do force update - m_colLastVisible = -1; + // when scrolling to the left, we need to scroll the old rectangle + // occupied by the text - then the area where there was no text + // before will be refreshed and redrawn - m_posLastVisible++; + // but we still need to force updating after scrolling + m_colLastVisible = -1; } - wxRect rectText = m_rectText; - rectText.width = m_posLastVisible; + wxRect rect = m_rectText; + rect.width = m_posLastVisible; - ScrollWindow(dx, 0, &rectText); + rect = ScrollNoRefresh(dx, 0, &rect); + + /* + we need to manually refresh the part which ScrollWindow() doesn't + refresh: indeed, if we had this: + + ********o + + where '*' is text and 'o' is blank area at the end (too small to + hold the next char) then after scrolling by 2 positions to the left + we're going to have + + ******RRo + + where 'R' is the area refreshed by ScrollWindow() - but we still + need to refresh the 'o' at the end as it may be now big enough to + hold the new character shifted into view. + + when we are scrolling to the right, we need to update this rect as + well because it might have contained something before but doesn't + contain anything any more + */ + + // we can combine both rectangles into one when scrolling to the left, + // but we need two separate Refreshes() otherwise + if ( dx > 0 ) + { + // refresh the uncovered part on the left + Refresh(TRUE, &rect); + + // and now the area on the right + rect.x = m_rectText.x + m_posLastVisible; + rect.width = m_rectText.width - m_posLastVisible; + } + else + { + // just extend the rect covering the uncovered area to the edge of + // the text rect + rect.width += m_rectText.width - m_posLastVisible; + } + + Refresh(TRUE, &rect); } } @@ -1059,16 +1166,70 @@ void wxTextCtrl::DoPrepareDC(wxDC& dc) // refresh // ---------------------------------------------------------------------------- -void wxTextCtrl::RefreshLine(long line, long from, long to) +void wxTextCtrl::RefreshTextRange(long start, long end) +{ + wxCHECK_RET( start != -1 && end != -1, + _T("invalid RefreshTextRange() arguments") ); + + // accept arguments in any order as it is more conenient for the caller + OrderPositions(start, end); + + long colStart, lineStart; + if ( !PositionToXY(start, &colStart, &lineStart) ) + { + // the range is entirely beyond the end of the text, nothing to do + return; + } + + long colEnd, lineEnd; + if ( !PositionToXY(end, &colEnd, &lineEnd) ) + { + // the range spans beyond the end of text, refresh to the end + colEnd = wxSTRING_MAXLEN; + lineEnd = GetNumberOfLines() - 1; + } + + // refresh all lines one by one + for ( long line = lineStart; line <= lineEnd; line++ ) + { + // refresh the first line from the start of the range to the end, the + // intermediate ones entirely and the last one from the beginning to + // the end of the range + long posStart = line == lineStart ? colStart : 0; + long posCount; + if ( (line != lineEnd) || (colEnd == wxSTRING_MAXLEN) ) + { + // intermediate line or the last one but we need to refresh it + // until the end anyhow - do it + posCount = wxSTRING_MAXLEN; + } + else // last line + { + // refresh just the positions in between the start and the end one + posCount = colEnd - posStart; + } + + RefreshLineRange(line, posStart, posCount); + } +} + +void wxTextCtrl::RefreshLineRange(long line, long start, long count) { wxString text = GetLineText(line); + RefreshPixelRange(line, + GetTextWidth(text.Left((size_t)start)), + GetTextWidth(text.Mid((size_t)start, (size_t)count))); +} + +void wxTextCtrl::RefreshPixelRange(long line, wxCoord start, wxCoord width) +{ wxCoord h = GetCharHeight(); wxRect rect; - rect.x = GetTextWidth(text.Left((size_t)from)) - m_ofsHorz; + rect.x = start - m_ofsHorz; rect.y = line*h; - if ( to == -1 ) + if ( width == 0 ) { // till the end of line rect.width = m_rectText.width - rect.x; @@ -1076,15 +1237,13 @@ void wxTextCtrl::RefreshLine(long line, long from, long to) else { // only part of line - rect.width = GetTextWidth(text.Mid((size_t)from, (size_t)(to - from + 1))); + rect.width = width; } rect.height = h; - // account for the origin offset - wxPoint pt = GetClientAreaOrigin() + m_rectText.GetPosition(); - rect.x += pt.x; - rect.y += pt.y; + // account for the text area offset + rect.Offset(m_rectText.GetPosition()); wxLogTrace(_T("text"), _T("Refreshing (%d, %d)-(%d, %d)"), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); @@ -1100,7 +1259,7 @@ void wxTextCtrl::RefreshLine(long line, long from, long to) Several remarks about wxTextCtrl redraw logic: 1. only the regions which must be updated are redrawn, this means that we - never Refresh() the entire window but use RefreshLine() and + never Refresh() the entire window but use RefreshPixelRange() and ScrollWindow() which only refresh small parts of it and iterate over the update region in our DoDraw() @@ -1172,7 +1331,7 @@ void wxTextCtrl::DrawTextLine(wxDC& dc, const wxRect& rect, void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) { // debugging trick to see the update rect visually -#if 1 +#ifdef WXDEBUG_TEXT if ( 0 ) { wxWindowDC dc(this); @@ -1181,7 +1340,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) dc.SetPen(*wxTRANSPARENT_PEN); dc.DrawRectangle(rectUpdate); } -#endif +#endif // WXDEBUG_TEXT // calculate the range of lines to refresh wxPoint pt1 = rectUpdate.GetPosition(); @@ -1204,7 +1363,12 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) rectText.y = m_rectText.y + lineStart*rectText.height; // do draw the invalidated parts of each line - for ( long line = lineStart; line <= lineEnd; line++ ) + for ( long line = lineStart; + line <= lineEnd; + line++, + rectText.y += rectText.height, + pt1.y += rectText.height, + pt2.y += rectText.height ) { // calculate the update rect in text positions for this line if ( HitTest(pt1, &colStart, NULL) == wxTE_HT_AFTER ) @@ -1232,8 +1396,12 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) UpdateLastVisible(); } - wxASSERT_MSG( colStart <= m_colLastVisible, - _T("incorrect m_colLastVisible value") ); + if ( colStart > m_colLastVisible ) + { + // don't bother redrawing something that is beyond the last + // visible position + continue; + } if ( colEnd > m_colLastVisible ) colEnd = m_colLastVisible; @@ -1251,8 +1419,14 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) // these values are relative to the start of the line while the // string passed to DrawTextLine() is only part of it, so adjust // the selection range accordingly - selStart += colStart; - selEnd += colStart; + selStart -= colStart; + selEnd -= colStart; + + if ( selStart < 0 ) + selStart = 0; + + if ( (size_t)selEnd >= text.length() ) + selEnd = text.length(); } // calculate the logical text coords @@ -1263,11 +1437,6 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) DrawTextLine(dc, rectText, text, selStart, selEnd); wxLogTrace(_T("text"), _T("Line %ld: positions %ld-%ld redrawn."), line, colStart, colEnd); - - // adjust for the next line - rectText.y += rectText.height; - pt1.y += rectText.height; - pt2.y += rectText.height; } } @@ -1319,6 +1488,24 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer) } } +// ---------------------------------------------------------------------------- +// caret +// ---------------------------------------------------------------------------- + +void wxTextCtrl::CreateCaret() +{ + // FIXME use renderer + wxCaret *caret = new wxCaret(this, 1, GetCharHeight()); +#ifndef __WXMSW__ + caret->SetBlinkTime(0); +#endif // __WXMSW__ + + // SetCaret() will delete the old caret if any + SetCaret(caret); + + caret->Show(); +} + wxCoord wxTextCtrl::GetCaretPosition() const { wxString textBeforeCaret(GetLineText(m_curLine), (size_t)m_curRow); @@ -1371,7 +1558,12 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, action = actionOrig; } - long newPos = -1; + // set newPos to -2 as it can't become equal to it in the assignments below + // (but it can become -1) + static const long INVALID_POS_VALUE = -2; + + long newPos = INVALID_POS_VALUE; + if ( action == wxACTION_TEXT_HOME ) { newPos = m_curPos - m_curRow; @@ -1434,7 +1626,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig, return wxControl::PerformAction(action, numArg, strArg); } - if ( newPos != -1 ) + if ( newPos != INVALID_POS_VALUE ) { // bring the new position into the range if ( newPos < 0 ) diff --git a/src/univ/winuniv.cpp b/src/univ/winuniv.cpp index ad6bbe73a7..b92ad57829 100644 --- a/src/univ/winuniv.cpp +++ b/src/univ/winuniv.cpp @@ -272,6 +272,32 @@ void wxWindow::DoDraw(wxControlRenderer *renderer) { } +void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient) +{ + if ( rectClient ) + { + wxRect rectWin = *rectClient; + rectWin.Offset(GetClientAreaOrigin()); + + wxWindowNative::Refresh(eraseBackground, &rectWin); + + // debugging helper +#if 0 + wxWindowDC dc(this); + dc.SetBrush(*wxBLUE_BRUSH); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(rectWin); + + ::GdiFlush(); + ::Sleep(1000); +#endif // 0 + } + else + { + wxWindowNative::Refresh(eraseBackground); + } +} + // ---------------------------------------------------------------------------- // state flags // ---------------------------------------------------------------------------- @@ -576,25 +602,47 @@ int wxWindow::GetScrollRange(int orient) const void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) { + wxRect r; + + if ( dx ) + { + r = ScrollNoRefresh(dx, 0, rect); + Refresh(TRUE /* erase bkgnd */, &r); + } + + if ( dy ) + { + r = ScrollNoRefresh(0, dy, rect); + Refresh(TRUE /* erase bkgnd */, &r); + } +} + +wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal) +{ + wxASSERT_MSG( !dx || !dy, _T("can't be used for diag scrolling") ); + + // the rect to refresh (which we will calculate) + wxRect rect; + if ( !dx && !dy ) { // nothing to do - return; + return rect; } // calculate the part of the window which we can just redraw in the new // location - wxSize sizeTotal = rect ? rect->GetSize() : GetClientSize(); + wxSize sizeTotal = rectTotal ? rectTotal->GetSize() : GetClientSize(); wxLogTrace(_T("scroll"), _T("rect is %dx%d, scroll by %d, %d"), sizeTotal.x, sizeTotal.y, dx, dy); // the initial and end point of the region we move in client coords wxPoint ptSource, ptDest; - if ( rect ) + if ( rectTotal ) { - ptSource = rect->GetPosition(); - ptDest = rect->GetPosition(); + ptSource = rectTotal->GetPosition(); + ptDest = rectTotal->GetPosition(); } // the size of this region @@ -606,12 +654,10 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) // just redraw everything as nothing of the displayed image will stay wxLogTrace(_T("scroll"), _T("refreshing everything")); - Refresh(TRUE, rect); + rect = rectTotal ? *rectTotal : GetClientRect(); } else // move the part which doesn't change to the new location { - wxPoint ptOrigin = GetClientAreaOrigin(); - // note that when we scroll the canvas in some direction we move the // block which doesn't need to be refreshed in the opposite direction @@ -645,7 +691,7 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) dcMem.Blit(wxPoint(0, 0), size, &dc, ptSource #if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) - + ptOrigin + + GetClientAreaOrigin() #endif // broken wxGTK wxDC::Blit ); dc.Blit(ptDest, size, &dcMem, wxPoint(0, 0)); @@ -663,9 +709,8 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) // diagonally anyhow and so adding extra logic to compute // rectangle intersection is probably not worth the effort - wxRect rect; - rect.x = ptOrigin.x + ptSource.x; - rect.y = ptOrigin.y + ptSource.y; + rect.x = ptSource.x; + rect.y = ptSource.y; if ( dx ) { @@ -686,8 +731,6 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"), rect.x, rect.y, rect.GetRight() + 1, rect.GetBottom() + 1); - - Refresh(TRUE /* erase bkgnd */, &rect); } if ( dy ) @@ -709,10 +752,10 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"), rect.x, rect.y, rect.GetRight() + 1, rect.GetBottom() + 1); - - Refresh(TRUE /* erase bkgnd */, &rect); } } + + return rect; } // ----------------------------------------------------------------------------