1. (hopefully) fixed horz scrolling

2. only refresh part of line in Replace()
3. changed wxWindow::Refresh() to take client coordinates
4. only refresh the text which must be refreshed when selection changes


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8449 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-10-01 22:47:30 +00:00
parent 62b93fefcf
commit b28342f733
9 changed files with 370 additions and 93 deletions

3
TODO
View File

@@ -4,7 +4,7 @@ TODO
wxTextCtrl wxTextCtrl
o DoDraw should iterat over update region instead of using bounding box * display corrupted when typing text in quickly
All All
@@ -31,6 +31,7 @@ DONE
All All
+ text ctrl horz scrolling + text ctrl horz scrolling
+ DoDraw should iterat over update region instead of using bounding box
MSW MSW

View File

@@ -302,6 +302,7 @@ public:
void SetTop(int top) { y = top; } void SetTop(int top) { y = top; }
void SetBottom(int bottom) { height = bottom - y + 1; } void SetBottom(int bottom) { height = bottom - y + 1; }
// operations with rect
void Inflate(wxCoord dx, wxCoord dy) void Inflate(wxCoord dx, wxCoord dy)
{ {
x -= dx; x -= dx;
@@ -312,12 +313,17 @@ public:
void Inflate(wxCoord d) { Inflate(d, d); } 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;
bool operator!=(const wxRect& rect) const { return !(*this == rect); } bool operator!=(const wxRect& rect) const { return !(*this == rect); }
bool Inside(int cx, int cy) const; bool Inside(int cx, int cy) const;
wxRect operator+(const wxRect& rect) const;
wxRect& operator+=(const wxRect& rect);
public: public:
int x, y, width, height; int x, y, width, height;

View File

@@ -169,6 +169,7 @@ public:
// caret stuff // caret stuff
virtual void ShowCaret(bool show = TRUE); virtual void ShowCaret(bool show = TRUE);
void HideCaret() { ShowCaret(FALSE); } void HideCaret() { ShowCaret(FALSE); }
void CreateCaret(); // for the current font size
wxCoord GetCaretPosition() const; // in pixels wxCoord GetCaretPosition() const; // in pixels
// helpers for cursor movement // helpers for cursor movement
@@ -176,7 +177,8 @@ public:
long GetWordEnd() const; long GetWordEnd() const;
// selection helpers // selection helpers
bool HasSelection() const { return m_selStart != -1; } bool HasSelection() const
{ return m_selStart != -1 && m_selEnd > m_selStart; }
void ClearSelection(); void ClearSelection();
void RemoveSelection(); void RemoveSelection();
wxString GetSelectionText() const; wxString GetSelectionText() const;
@@ -225,6 +227,9 @@ public:
long numArg = -1, long numArg = -1,
const wxString& strArg = wxEmptyString); const wxString& strArg = wxEmptyString);
// override this to recreate the caret here
virtual bool SetFont(const wxFont &font);
protected: protected:
// draw the text // draw the text
void DrawTextLine(wxDC& dc, const wxRect& rect, void DrawTextLine(wxDC& dc, const wxRect& rect,
@@ -251,8 +256,16 @@ protected:
// get the extent (width) of the text // get the extent (width) of the text
wxCoord GetTextWidth(const wxString& text) const; wxCoord GetTextWidth(const wxString& text) const;
// refresh the text in the given range (in text coords) of this line // refresh the text in the given range (in logical coords) of this line, if
void RefreshLine(long line, long from, long to); // 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 // get the text to show: either the text itself or the text replaced with
// starts for wxTE_PASSWORD control // starts for wxTE_PASSWORD control
@@ -277,6 +290,9 @@ private:
// the value (may be only part of it for the multiline controls) // the value (may be only part of it for the multiline controls)
wxString m_value; wxString m_value;
// the initially specified control size
wxSize m_sizeInitial;
// current position // current position
long m_curPos, long m_curPos,
m_curLine, m_curLine,

View File

@@ -98,7 +98,7 @@ public:
virtual int GetScrollThumb(int orient) const; virtual int GetScrollThumb(int orient) const;
virtual int GetScrollRange(int orient) const; virtual int GetScrollRange(int orient) const;
virtual void ScrollWindow(int dx, int dy, virtual void ScrollWindow(int dx, int dy,
const wxRect* rect = (wxRect *) NULL); const wxRect* rect = (wxRect *) NULL);
// take into account the borders here // take into account the borders here
virtual wxPoint GetClientAreaOrigin() const; virtual wxPoint GetClientAreaOrigin() const;
@@ -150,9 +150,19 @@ public:
// querying the current theme // querying the current theme
wxRenderer *GetRenderer() const { return m_renderer; } 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 // 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 // remember that the font/colour was changed
virtual bool SetBackgroundColour(const wxColour& colour); virtual bool SetBackgroundColour(const wxColour& colour);
virtual bool SetForegroundColour(const wxColour& colour); virtual bool SetForegroundColour(const wxColour& colour);

View File

@@ -233,7 +233,7 @@ MyUnivFrame::MyUnivFrame(const wxString& title)
#ifndef TEST_TEXT_ONLY #ifndef TEST_TEXT_ONLY
wxSize(700, 700) wxSize(700, 700)
#else #else
wxSize(240, 150) wxSize(240, 200)
#endif #endif
) )
{ {
@@ -383,8 +383,13 @@ MyUnivFrame::MyUnivFrame(const wxString& title)
new wxTextCtrl(this, -1, _T("Hello, Universe!"), new wxTextCtrl(this, -1, _T("Hello, Universe!"),
wxPoint(550, 150), wxDefaultSize); wxPoint(550, 150), wxDefaultSize);
#else // TEST_TEXT_ONLY #else // TEST_TEXT_ONLY
new wxTextCtrl(this, -1, _T("Hello, Universe!"), wxTextCtrl *text = new wxTextCtrl(this, -1, _T("Hello, Universe!"),
wxPoint(10, 40), wxSize(200, -1)); 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 #endif // !TEST_TEXT_ONLY/TEST_TEXT_ONLY
} }

View File

@@ -492,7 +492,10 @@ void wxListBox::OnIdle(wxIdleEvent& event)
} }
else else
{ {
wxRect rect = GetClientRect(); wxSize size = GetClientSize();
wxRect rect;
rect.width = size.x;
rect.height = size.y;
rect.y += m_updateFrom*GetLineHeight(); rect.y += m_updateFrom*GetLineHeight();
rect.height = m_updateCount*GetLineHeight(); rect.height = m_updateCount*GetLineHeight();
CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y); CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);

View File

@@ -261,6 +261,7 @@ void wxScrollBar::OnIdle(wxIdleEvent& event)
#endif // 0/1 #endif // 0/1
} }
// FIXME: rect is client or win (must be client)?
Refresh(TRUE, &rect); Refresh(TRUE, &rect);
} }

View File

@@ -53,6 +53,20 @@
// turn extra wxTextCtrl-specific debugging on/off // turn extra wxTextCtrl-specific debugging on/off
#define WXDEBUG_TEXT #define WXDEBUG_TEXT
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
static inline void OrderPositions(long& from, long& to)
{
if ( from > to )
{
long tmp = from;
from = to;
to = tmp;
}
}
// ============================================================================ // ============================================================================
// implementation // implementation
// ============================================================================ // ============================================================================
@@ -103,19 +117,27 @@ bool wxTextCtrl::Create(wxWindow *parent,
return FALSE; return FALSE;
} }
// FIXME use renderer
wxCaret *caret = new wxCaret(this, 1, GetCharHeight());
#ifndef __WXMSW__
caret->SetBlinkTime(0);
#endif // __WXMSW__
SetCaret(caret);
SetCursor(wxCURSOR_IBEAM); SetCursor(wxCURSOR_IBEAM);
SetValue(value); 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; 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 // replace the part of the text with the new value
wxString valueNew(m_value, (size_t)from); 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; valueNew += text;
if ( (unsigned long)to < m_value.length() ) if ( (size_t)to < m_value.length() )
{ {
valueNew += m_value.c_str() + (size_t)to; 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; m_value = valueNew;
// force m_colLastVisible update // force m_colLastVisible update
@@ -166,22 +207,17 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
// for selection anchor) // for selection anchor)
ClearSelection(); ClearSelection();
// refresh to the end of the line // repaint
RefreshLine(0, from, -1); 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) void wxTextCtrl::Remove(long from, long to)
{ {
if ( from > to ) // Replace() only works with correctly ordered arguments, so exchange them
{ // if necessary
// Replace() only works with correctly ordered arguments, so exchange OrderPositions(from, to);
// them
long tmp = from;
from = to;
to = tmp;
}
Replace(from, to, _T("")); Replace(from, to, _T(""));
} }
@@ -291,7 +327,7 @@ wxString wxTextCtrl::GetSelectionText() const
void wxTextCtrl::SetSelection(long from, long to) void wxTextCtrl::SetSelection(long from, long to)
{ {
if ( from == -1 || to == -1 ) if ( from == -1 || to == from )
{ {
ClearSelection(); ClearSelection();
} }
@@ -309,14 +345,36 @@ void wxTextCtrl::SetSelection(long from, long to)
if ( from != m_selStart || to != m_selEnd ) 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_selStart = from;
m_selEnd = to; m_selEnd = to;
wxLogTrace(_T("text"), _T("Selection range is %ld-%ld"), wxLogTrace(_T("text"), _T("Selection range is %ld-%ld"),
m_selStart, m_selEnd); m_selStart, m_selEnd);
// FIXME: shouldn't refresh everything // refresh only the part of text which became (un)selected if
Refresh(); // 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 //else: nothing to do
} }
@@ -326,11 +384,17 @@ void wxTextCtrl::ClearSelection()
{ {
if ( HasSelection() ) 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_selStart =
m_selEnd = -1; m_selEnd = -1;
// FIXME: shouldn't refresh everything // refresh the old selection
Refresh(); RefreshTextRange(selStart, selEnd);
} }
// the anchor should be moved even if there was no selection previously // the anchor should be moved even if there was no selection previously
@@ -714,7 +778,7 @@ void wxTextCtrl::UpdateLastVisible()
w = w =
wOld = 0; wOld = 0;
m_colLastVisible = m_colStart; m_colLastVisible = m_colStart - 1;
const wxChar *pc = m_value.c_str() + (size_t)m_colStart; const wxChar *pc = m_value.c_str() + (size_t)m_colStart;
for ( ; *pc; pc++ ) for ( ; *pc; pc++ )
@@ -808,13 +872,13 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
wxString strBefore(line, (size_t)col); wxString strBefore(line, (size_t)col);
dc.GetTextExtent(strBefore, &width, NULL); dc.GetTextExtent(strBefore, &width, NULL);
if ( width >= x ) if ( width > x )
{ {
if ( matchDir == 1 ) if ( matchDir == 1 )
{ {
// we were going to the right and, finally, moved beyond // we were going to the right and, finally, moved beyond
// the original position - stop on the previous one // the original position - stop on the previous one
//col--; col--;
break; break;
} }
@@ -829,9 +893,10 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
} }
else // width < x else // width < x
{ {
// same logic as above // invert the logic above
if ( matchDir == -1 ) if ( matchDir == -1 )
{ {
// with the exception that we don't need to backtrack here
break; break;
} }
@@ -866,12 +931,12 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
text += line[col]; text += line[col];
dc.GetTextExtent(text, &width2, NULL); dc.GetTextExtent(text, &width2, NULL);
wxASSERT_MSG( (width1 <= x) && (x <= width2), wxASSERT_MSG( (width1 <= x) && (x < width2),
_T("incorrect HitTestLine() result") ); _T("incorrect HitTestLine() result") );
} }
else // we return last char else // we return last char
{ {
wxASSERT_MSG( x > width1, _T("incorrect HitTestLine() result") ); wxASSERT_MSG( x >= width1, _T("incorrect HitTestLine() result") );
} }
} }
#endif // WXDEBUG_TEXT #endif // WXDEBUG_TEXT
@@ -979,7 +1044,7 @@ void wxTextCtrl::ShowHorzPosition(wxCoord pos)
// scroll forward // scroll forward
long col; long col;
HitTestLine(GetValue(), pos - width, &col); HitTestLine(GetValue(), pos - width, &col);
ScrollText(col); ScrollText(col + 1);
} }
} }
} }
@@ -1011,7 +1076,7 @@ void wxTextCtrl::ScrollText(long col)
// order of operands // order of operands
int dx = m_ofsHorz - ofsHorz; 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 // DoDraw(), so we must update m_ofsHorz before calling it
m_ofsHorz = ofsHorz; m_ofsHorz = ofsHorz;
m_colStart = col; m_colStart = col;
@@ -1020,23 +1085,65 @@ void wxTextCtrl::ScrollText(long col)
if ( dx > 0 ) if ( dx > 0 )
{ {
// scrolling to the right: we need to recalc the last visible // 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(); UpdateLastVisible();
} }
else else
{ {
// when scrolling to the left, we don't need to worry about the // when scrolling to the left, we need to scroll the old rectangle
// last visible position, it will be updated later when we draw // occupied by the text - then the area where there was no text
// the text - but do force update // before will be refreshed and redrawn
m_colLastVisible = -1;
m_posLastVisible++; // but we still need to force updating after scrolling
m_colLastVisible = -1;
} }
wxRect rectText = m_rectText; wxRect rect = m_rectText;
rectText.width = m_posLastVisible; 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 // 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); 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(); wxCoord h = GetCharHeight();
wxRect rect; wxRect rect;
rect.x = GetTextWidth(text.Left((size_t)from)) - m_ofsHorz; rect.x = start - m_ofsHorz;
rect.y = line*h; rect.y = line*h;
if ( to == -1 ) if ( width == 0 )
{ {
// till the end of line // till the end of line
rect.width = m_rectText.width - rect.x; rect.width = m_rectText.width - rect.x;
@@ -1076,15 +1237,13 @@ void wxTextCtrl::RefreshLine(long line, long from, long to)
else else
{ {
// only part of line // only part of line
rect.width = GetTextWidth(text.Mid((size_t)from, (size_t)(to - from + 1))); rect.width = width;
} }
rect.height = h; rect.height = h;
// account for the origin offset // account for the text area offset
wxPoint pt = GetClientAreaOrigin() + m_rectText.GetPosition(); rect.Offset(m_rectText.GetPosition());
rect.x += pt.x;
rect.y += pt.y;
wxLogTrace(_T("text"), _T("Refreshing (%d, %d)-(%d, %d)"), wxLogTrace(_T("text"), _T("Refreshing (%d, %d)-(%d, %d)"),
rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); 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: Several remarks about wxTextCtrl redraw logic:
1. only the regions which must be updated are redrawn, this means that we 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 ScrollWindow() which only refresh small parts of it and iterate over the
update region in our DoDraw() 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) void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
{ {
// debugging trick to see the update rect visually // debugging trick to see the update rect visually
#if 1 #ifdef WXDEBUG_TEXT
if ( 0 ) if ( 0 )
{ {
wxWindowDC dc(this); wxWindowDC dc(this);
@@ -1181,7 +1340,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(rectUpdate); dc.DrawRectangle(rectUpdate);
} }
#endif #endif // WXDEBUG_TEXT
// calculate the range of lines to refresh // calculate the range of lines to refresh
wxPoint pt1 = rectUpdate.GetPosition(); wxPoint pt1 = rectUpdate.GetPosition();
@@ -1204,7 +1363,12 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
rectText.y = m_rectText.y + lineStart*rectText.height; rectText.y = m_rectText.y + lineStart*rectText.height;
// do draw the invalidated parts of each line // 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 // calculate the update rect in text positions for this line
if ( HitTest(pt1, &colStart, NULL) == wxTE_HT_AFTER ) if ( HitTest(pt1, &colStart, NULL) == wxTE_HT_AFTER )
@@ -1232,8 +1396,12 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
UpdateLastVisible(); UpdateLastVisible();
} }
wxASSERT_MSG( colStart <= m_colLastVisible, if ( colStart > m_colLastVisible )
_T("incorrect m_colLastVisible value") ); {
// don't bother redrawing something that is beyond the last
// visible position
continue;
}
if ( colEnd > m_colLastVisible ) if ( colEnd > m_colLastVisible )
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 // these values are relative to the start of the line while the
// string passed to DrawTextLine() is only part of it, so adjust // string passed to DrawTextLine() is only part of it, so adjust
// the selection range accordingly // the selection range accordingly
selStart += colStart; selStart -= colStart;
selEnd += colStart; selEnd -= colStart;
if ( selStart < 0 )
selStart = 0;
if ( (size_t)selEnd >= text.length() )
selEnd = text.length();
} }
// calculate the logical text coords // calculate the logical text coords
@@ -1263,11 +1437,6 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
DrawTextLine(dc, rectText, text, selStart, selEnd); DrawTextLine(dc, rectText, text, selStart, selEnd);
wxLogTrace(_T("text"), _T("Line %ld: positions %ld-%ld redrawn."), wxLogTrace(_T("text"), _T("Line %ld: positions %ld-%ld redrawn."),
line, colStart, colEnd); 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 wxCoord wxTextCtrl::GetCaretPosition() const
{ {
wxString textBeforeCaret(GetLineText(m_curLine), (size_t)m_curRow); wxString textBeforeCaret(GetLineText(m_curLine), (size_t)m_curRow);
@@ -1371,7 +1558,12 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig,
action = 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 ) if ( action == wxACTION_TEXT_HOME )
{ {
newPos = m_curPos - m_curRow; newPos = m_curPos - m_curRow;
@@ -1434,7 +1626,7 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig,
return wxControl::PerformAction(action, numArg, strArg); return wxControl::PerformAction(action, numArg, strArg);
} }
if ( newPos != -1 ) if ( newPos != INVALID_POS_VALUE )
{ {
// bring the new position into the range // bring the new position into the range
if ( newPos < 0 ) if ( newPos < 0 )

View File

@@ -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 // state flags
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -576,25 +602,47 @@ int wxWindow::GetScrollRange(int orient) const
void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect) 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 ) if ( !dx && !dy )
{ {
// nothing to do // nothing to do
return; return rect;
} }
// calculate the part of the window which we can just redraw in the new // calculate the part of the window which we can just redraw in the new
// location // 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"), wxLogTrace(_T("scroll"), _T("rect is %dx%d, scroll by %d, %d"),
sizeTotal.x, sizeTotal.y, dx, dy); sizeTotal.x, sizeTotal.y, dx, dy);
// the initial and end point of the region we move in client coords // the initial and end point of the region we move in client coords
wxPoint ptSource, ptDest; wxPoint ptSource, ptDest;
if ( rect ) if ( rectTotal )
{ {
ptSource = rect->GetPosition(); ptSource = rectTotal->GetPosition();
ptDest = rect->GetPosition(); ptDest = rectTotal->GetPosition();
} }
// the size of this region // 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 // just redraw everything as nothing of the displayed image will stay
wxLogTrace(_T("scroll"), _T("refreshing everything")); 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 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 // 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 // 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 dcMem.Blit(wxPoint(0, 0), size, &dc, ptSource
#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) #if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__)
+ ptOrigin + GetClientAreaOrigin()
#endif // broken wxGTK wxDC::Blit #endif // broken wxGTK wxDC::Blit
); );
dc.Blit(ptDest, size, &dcMem, wxPoint(0, 0)); 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 // diagonally anyhow and so adding extra logic to compute
// rectangle intersection is probably not worth the effort // rectangle intersection is probably not worth the effort
wxRect rect; rect.x = ptSource.x;
rect.x = ptOrigin.x + ptSource.x; rect.y = ptSource.y;
rect.y = ptOrigin.y + ptSource.y;
if ( dx ) 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)"), wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"),
rect.x, rect.y, rect.x, rect.y,
rect.GetRight() + 1, rect.GetBottom() + 1); rect.GetRight() + 1, rect.GetBottom() + 1);
Refresh(TRUE /* erase bkgnd */, &rect);
} }
if ( dy ) 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)"), wxLogTrace(_T("scroll"), _T("refreshing (%d, %d)-(%d, %d)"),
rect.x, rect.y, rect.x, rect.y,
rect.GetRight() + 1, rect.GetBottom() + 1); rect.GetRight() + 1, rect.GetBottom() + 1);
Refresh(TRUE /* erase bkgnd */, &rect);
} }
} }
return rect;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------