1. more work on line wrap - mostly works now

2. small fixes to wxStaticText (best size calc) and to check box


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8755 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-11-20 01:16:27 +00:00
parent 55b9ea2484
commit 17516c205e
7 changed files with 389 additions and 163 deletions

10
TODO
View File

@@ -14,10 +14,11 @@ samples:
wxTextCtrl wxTextCtrl
* adjust refresh/scroll for WrapLines() case *! call to RefreshLineRange() from Replace() is broken
*! display corrupted when typing text in quickly (caret problem?) *! display corrupted when typing text in quickly (caret problem?)
* caret leaves traces under wxGTK * caret leaves traces under wxGTK
? text ctrl display pb when text is truncated ? text ctrl display pb when text is truncated
* remember selection when losing/gaining activation
* too much is refreshed when double clicking (word select) * too much is refreshed when double clicking (word select)
All All
@@ -27,15 +28,13 @@ All
* wxCheckListBox: redraw only the bitmap when toggled * wxCheckListBox: redraw only the bitmap when toggled
* problem with lbox horz scrolling: the focus rect isn't drawn entirely... ? problem with lbox horz scrolling: the focus rect isn't drawn entirely...
* write sample testing all listbox styles/events
* text ctrl wxTE_XXX styles support
* listbox inc kbd search
* popup menu for text ctrls * popup menu for text ctrls
MSW MSW
* checkboxes don't look correctly in checked+disabled state (radio too?)
* text control scrollbar has text cursor * text control scrollbar has text cursor
scrollbar behaves strangely in log lbox with many strings scrollbar behaves strangely in log lbox with many strings
@@ -49,6 +48,7 @@ DONE
All All
+ adjust refresh/scroll for WrapLines() case
+ text ctrl horz scrolling + text ctrl horz scrolling
+ DoDraw should iterate over update region instead of using bounding box + DoDraw should iterate over update region instead of using bounding box
+ listbox: horz scrollbar doesn't appear + listbox: horz scrollbar doesn't appear

View File

@@ -304,6 +304,7 @@ public:
const wxMouseEvent& event); const wxMouseEvent& event);
virtual bool HandleMouseMove(wxControl *control, virtual bool HandleMouseMove(wxControl *control,
const wxMouseEvent& event); const wxMouseEvent& event);
virtual bool HandleFocus(wxControl *control, const wxFocusEvent& event);
protected: protected:
// get the position of the mouse click // get the position of the mouse click

View File

@@ -79,12 +79,15 @@ typedef long wxTextCoord;
// wxTextCtrl::HitTest return values // wxTextCtrl::HitTest return values
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// the point asked is ...
enum wxTextCtrlHitTestResult enum wxTextCtrlHitTestResult
{ {
wxTE_HT_BEFORE = -1, wxTE_HT_BEFORE = -1, // either to the left or upper
wxTE_HT_ON_TEXT, wxTE_HT_ON_TEXT, // directly on
wxTE_HT_AFTER wxTE_HT_BELOW, // below [the last line]
wxTE_HT_BEYOND // after [the end of line]
}; };
// ... the character returned
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxTextCtrl // wxTextCtrl
@@ -163,8 +166,10 @@ public:
wxTextCoord *x, wxTextCoord *y) const; wxTextCoord *x, wxTextCoord *y) const;
// wxUniv-specific: find a screen position (in client coordinates) of the // wxUniv-specific: find a screen position (in client coordinates) of the
// given text position // given text position or of the caret
bool PositionToPixelXY(wxTextPos pos, wxCoord *x, wxCoord *y) const; bool PositionToLogicalXY(wxTextPos pos, wxCoord *x, wxCoord *y) const;
bool PositionToDeviceXY(wxTextPos pos, wxCoord *x, wxCoord *y) const;
wxPoint GetCaretPosition() const;
virtual void ShowPosition(wxTextPos pos); virtual void ShowPosition(wxTextPos pos);
@@ -301,7 +306,7 @@ protected:
wxRect GetRealTextArea() const; wxRect GetRealTextArea() const;
// refresh the text in the given (in logical coords) rect // refresh the text in the given (in logical coords) rect
void RefreshTextRect(wxRect& rect); void RefreshTextRect(const wxRect& rect);
// refresh the text in the given range (in logical coords) of this line, if // refresh the text in the given range (in logical coords) of this line, if
// width is 0, refresh to the end of line // width is 0, refresh to the end of line
@@ -321,8 +326,10 @@ protected:
// starts for wxTE_PASSWORD control // starts for wxTE_PASSWORD control
wxString GetTextToShow(const wxString& text) const; wxString GetTextToShow(const wxString& text) const;
// find the number of characters of a line before it wraps at given width // find the number of characters of a line before it wraps
size_t GetPartOfWrappedLine(const wxChar* text, wxCoord width) const; // (and optionally also the real width of the line)
size_t GetPartOfWrappedLine(const wxChar* text,
wxCoord *widthReal = NULL) const;
// get the start and end of the selection for this line: if the line is // get the start and end of the selection for this line: if the line is
// outside the selection, both will be -1 and FALSE will be returned // outside the selection, both will be -1 and FALSE will be returned
@@ -359,19 +366,23 @@ protected:
// HitTest2() is more efficient than 2 consecutive HitTest()s with the same // HitTest2() is more efficient than 2 consecutive HitTest()s with the same
// line (i.e. y) and it also returns the offset of the starting position in // line (i.e. y) and it also returns the offset of the starting position in
// pixels // pixels
//
// as the last hack, this function accepts either logical or device (by
// default) coords depending on devCoords flag
wxTextCtrlHitTestResult HitTest2(wxCoord y, wxTextCtrlHitTestResult HitTest2(wxCoord y,
wxCoord x1, wxCoord x1,
wxCoord x2, wxCoord x2,
wxTextCoord *row, wxTextCoord *row,
wxTextCoord *colStart, wxTextCoord *colStart,
wxTextCoord *colEnd, wxTextCoord *colEnd,
wxTextCoord *colRowStart) const; wxTextCoord *colRowStart,
bool devCoords = TRUE) const;
// HitTest() version for use in wxTextCtrl: it takes the text coordinates // HitTest() version which takes the logical text coordinates and not the
// (i.e. coords relative to the text rect) // device ones
wxTextCtrlHitTestResult HitTestClient(wxCoord x, wxCoord y, wxTextCtrlHitTestResult HitTestLogical(const wxPoint& pos,
wxTextCoord *col, wxTextCoord *col,
wxTextCoord *row) const; wxTextCoord *row) const;
// event handlers // event handlers
void OnIdle(wxIdleEvent& event); void OnIdle(wxIdleEvent& event);

View File

@@ -363,19 +363,19 @@ TextTestFrame::TextTestFrame(const wxString& title)
_T("Current pos:"), _T("Current pos:"),
m_textPosCur m_textPosCur
), ),
0, wxRIGHT | wxGROW, 5); 0, wxGROW | wxRIGHT, 5);
sizerRow->Add(CreateTextWithLabelSizer sizerRow->Add(CreateTextWithLabelSizer
( (
_T("Col:"), _T("Col:"),
m_textColCur m_textColCur
), ),
0, wxRIGHT | wxLEFT | wxGROW, 5); 0, wxGROW | wxLEFT | wxRIGHT, 5);
sizerRow->Add(CreateTextWithLabelSizer sizerRow->Add(CreateTextWithLabelSizer
( (
_T("Row:"), _T("Row:"),
m_textRowCur m_textRowCur
), ),
0, wxLEFT | wxGROW, 5); 0, wxGROW | wxLEFT, 5);
sizerMiddleDown->Add(sizerRow, 0, wxALL | wxGROW, 5); sizerMiddleDown->Add(sizerRow, 0, wxALL | wxGROW, 5);
m_textLineLast = CreateInfoText(); m_textLineLast = CreateInfoText();
@@ -566,7 +566,7 @@ void TextTestFrame::CreateText()
flags); flags);
m_sizerText->Add(m_text, 1, wxALL | m_sizerText->Add(m_text, 1, wxALL |
(flags & wxTE_MULTILINE ? wxGROW (flags & wxTE_MULTILINE ? wxGROW
: wxALIGN_CENTRE_VERTICAL), 5); : wxALIGN_TOP), 5);
m_sizerText->Layout(); m_sizerText->Layout();
} }

View File

@@ -74,7 +74,9 @@ void wxStaticText::SetLabel(const wxString& label)
wxSize wxStaticText::DoGetBestClientSize() const wxSize wxStaticText::DoGetBestClientSize() const
{ {
wxClientDC dc(wxConstCast(this, wxStaticText)); wxStaticText *self = wxConstCast(this, wxStaticText);
wxClientDC dc(self);
dc.SetFont(GetFont());
wxCoord width, height; wxCoord width, height;
dc.GetMultiLineTextExtent(GetLabel(), &width, &height); dc.GetMultiLineTextExtent(GetLabel(), &width, &height);

View File

@@ -12,10 +12,13 @@
/* /*
TODO TODO
! 1. update vert scrollbar when any line length changes for WrapLines() + 1. update vert scrollbar when any line length changes for WrapLines()
2. cursor movement ("Hello,^" -> "^verse!" on Arrow Down)? + 2. cursor movement ("Hello,^" -> "^verse!" on Arrow Down)?
-> maybe save the x position and use it instead of current in handling
DOWN/UP actions (this would make up/down always return the cursor to
the same location)?
3. split file into chunks 3. split file into chunks
! 4. rewrite Replace() refresh logic to deal with wrapping lines +? 4. rewrite Replace() refresh logic to deal with wrapping lines
*/ */
/* /*
@@ -359,6 +362,11 @@ bool wxTextCtrl::Create(wxWindow *parent,
// TODO: support wxTE_NO_VSCROLL (?) // TODO: support wxTE_NO_VSCROLL (?)
} }
else
{
// this doesn't make sense for single line controls
style &= ~wxHSCROLL;
}
if ( !wxControl::Create(parent, id, pos, size, style, if ( !wxControl::Create(parent, id, pos, size, style,
validator, name) ) validator, name) )
@@ -513,6 +521,9 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text)
replace a part of it with the new text and break it into lines again. replace a part of it with the new text and break it into lines again.
*/ */
// (0) remember the number of rows before we started
wxTextCoord rowsOld = GetNumberOfRowsBefore(GetNumberOfLines());
// (1) join lines // (1) join lines
wxString textOrig; wxString textOrig;
wxTextCoord line; wxTextCoord line;
@@ -631,20 +642,46 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text)
} }
// (5) now refresh the changed area // (5) now refresh the changed area
RefreshPixelRange(lineStart, startNewText, widthNewText);
if ( m_lines.GetCount() == countOld ) // we may optimize refresh if the number of rows didn't change - but if
// it did we have to refresh everything below the part we chanegd as
// well as it might have moved
wxTextCoord rowsNew = GetNumberOfRowsBefore(GetNumberOfLines());
if ( rowsNew == rowsOld )
{ {
// number of lines didn't change, refresh the updated lines and the // refresh the line we changed
RefreshPixelRange(lineStart, startNewText, widthNewText);
// number of rows didn't change, refresh the updated rows and the
// last one // last one
if ( lineStart < lineEnd ) if ( lineStart < lineEnd )
RefreshLineRange(lineStart + 1, lineEnd); RefreshLineRange(lineStart + 1, lineEnd);
} }
else else
{ {
// number of lines did change, we need to refresh everything below if ( !WrapLines() )
// the start line {
RefreshLineRange(lineStart + 1, // refresh only part of the first line
wxMax(m_lines.GetCount(), countOld) - 1); RefreshPixelRange(lineStart, startNewText, widthNewText);
// and refresh the rest below
lineStart++;
}
//else: refresh all lines we changed (OPT?)
RefreshLineRange(lineStart, m_lines.GetCount() - 1);
// refresh text rect left below
if ( rowsNew < rowsOld )
{
wxCoord h = GetCharHeight();
wxRect rect;
rect.x = 0;
rect.width = m_rectText.width;
rect.y = rowsNew*h;
rect.height = (rowsOld - rowsNew)*h;
RefreshTextRect(rect);
}
// the vert scrollbar might [dis]appear // the vert scrollbar might [dis]appear
m_updateScrollbarY = TRUE; m_updateScrollbarY = TRUE;
@@ -664,8 +701,24 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text)
// end of the replacement text // end of the replacement text
DoSetInsertionPoint(from + text.length()); DoSetInsertionPoint(from + text.length());
// and the selection (do it after setting the cursor to have correct value // and the selection: this is complicated by the fact that selection coords
// for selection anchor) // must be first updated to reflect change in text coords, i.e. if we had
// selection from 17 to 19 and we just removed this range, we don't have to
// refresh anything, so we can't just use ClearSelection() here
if ( HasSelection() )
{
// refresh the parst of the selection outside the changed text (which
// we already refreshed)
if ( m_selStart < from )
RefreshTextRange(m_selStart, from);
if ( to < m_selEnd )
RefreshTextRange(to, m_selEnd);
m_selStart =
m_selEnd = -1;
}
// now call it to do the rest (not related to refreshing)
ClearSelection(); ClearSelection();
} }
@@ -1145,11 +1198,26 @@ bool wxTextCtrl::PositionToXY(wxTextPos pos,
wxTextCoord wxTextCtrl::GetRowsPerLine(wxTextCoord line) const wxTextCoord wxTextCtrl::GetRowsPerLine(wxTextCoord line) const
{ {
wxCoord wLine = m_rectText.width, // we can't just divide the line length by the width of the window as there
wLineTotal = GetTextWidth(GetLineText(line)); // are "unuse" parts of rows at the end, so we really need to use
// GetPartOfWrappedLine() here
wxString lineText = GetLineText(line);
// an empty line still has 1 row in it wxTextCoord rows = 0;
return wLineTotal == 0 ? 1 : (wLineTotal + wLine - 1) / wLine; size_t rowLen,
colRowStart = 0;
for ( ;; )
{
rowLen = GetPartOfWrappedLine(lineText.c_str() + colRowStart);
if ( !rowLen )
break;
colRowStart += rowLen;
rows++;
}
// empty line still takes one row
return rows == 0 ? 1 : rows;
} }
wxTextCoord wxTextCtrl::GetNumberOfRowsBefore(wxTextCoord lineMax) const wxTextCoord wxTextCtrl::GetNumberOfRowsBefore(wxTextCoord lineMax) const
@@ -1166,8 +1234,9 @@ wxTextCoord wxTextCtrl::GetNumberOfRowsBefore(wxTextCoord lineMax) const
return nRows; return nRows;
} }
bool wxTextCtrl::PositionToPixelXY(wxTextPos pos, bool wxTextCtrl::PositionToLogicalXY(wxTextPos pos,
wxCoord *xOut, wxCoord *yOut) const wxCoord *xOut,
wxCoord *yOut) const
{ {
wxTextCoord col, line; wxTextCoord col, line;
@@ -1205,8 +1274,7 @@ bool wxTextCtrl::PositionToPixelXY(wxTextPos pos,
wxTextCoord colRowStart = 0; wxTextCoord colRowStart = 0;
for ( ;; ) for ( ;; )
{ {
int rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart, int rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart);
m_rectText.width);
// the test is quite interesting because the last position in any // the test is quite interesting because the last position in any
// but the last row of the line is invalid: you can't put the // but the last row of the line is invalid: you can't put the
@@ -1237,6 +1305,22 @@ bool wxTextCtrl::PositionToPixelXY(wxTextPos pos,
x = GetTextWidth(textLine.Mid(colRowStart, col - colRowStart)); x = GetTextWidth(textLine.Mid(colRowStart, col - colRowStart));
} }
if ( xOut )
*xOut = x;
if ( yOut )
*yOut = y;
return TRUE;
}
bool wxTextCtrl::PositionToDeviceXY(wxTextPos pos,
wxCoord *xOut,
wxCoord *yOut) const
{
wxCoord x, y;
if ( !PositionToLogicalXY(pos, &x, &y) )
return FALSE;
// finally translate the logical text rect coords into physical client // finally translate the logical text rect coords into physical client
// coords // coords
CalcScrolledPosition(m_rectText.x + x - m_ofsHorz, CalcScrolledPosition(m_rectText.x + x - m_ofsHorz,
@@ -1247,6 +1331,17 @@ bool wxTextCtrl::PositionToPixelXY(wxTextPos pos,
return TRUE; return TRUE;
} }
wxPoint wxTextCtrl::GetCaretPosition() const
{
wxCoord xCaret, yCaret;
if ( !PositionToDeviceXY(m_curPos, &xCaret, &yCaret) )
{
wxFAIL_MSG( _T("Caret can't be beyond the text!") );
}
return wxPoint(xCaret, yCaret);
}
// pos may be -1 to show the current position // pos may be -1 to show the current position
void wxTextCtrl::ShowPosition(wxTextPos pos) void wxTextCtrl::ShowPosition(wxTextPos pos)
{ {
@@ -1261,19 +1356,11 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
int xStart, yStart; int xStart, yStart;
GetViewStart(&xStart, &yStart); GetViewStart(&xStart, &yStart);
wxTextCoord row, col; if ( pos == -1 )
if ( (pos == -1) || (pos == m_curPos) ) pos = m_curPos;
{
row = m_curRow;
col = m_curCol;
}
else
{
// TODO
wxFAIL_MSG(_T("not implemented for multiline"));
return; wxCoord x, y;
} PositionToLogicalXY(pos, &x, &y);
wxRect rectText = GetRealTextArea(); wxRect rectText = GetRealTextArea();
@@ -1281,9 +1368,11 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
// it, make it the first one, otherwise the last one // it, make it the first one, otherwise the last one
if ( m_scrollRangeY ) if ( m_scrollRangeY )
{ {
if ( row < yStart ) y /= GetCharHeight();
if ( y < yStart )
{ {
Scroll(0, row); Scroll(0, y);
} }
else // we are currently in or below the view area else // we are currently in or below the view area
{ {
@@ -1293,8 +1382,27 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
if ( WrapLines() ) if ( WrapLines() )
{ {
// to find the last row we need to use the generic HitTest // to find the last row we need to use the generic HitTest
HitTestClient(0, rectText.height, NULL, &yEnd); wxTextCoord col;
yEnd--;
// OPT this is a bit silly: we undo this in HitTest(), so
// it would be better to factor out the common
// functionality into a separate function (OTOH it
// won't probably save us that much)
wxPoint pt(0, rectText.height - 1);
pt += GetClientAreaOrigin();
pt += m_rectText.GetPosition();
HitTest(pt, &col, &yEnd);
// find the row inside the line
wxString text = GetLineText(yEnd);
yEnd = GetNumberOfRowsBefore(yEnd);
wxTextCoord colRowStart = GetPartOfWrappedLine(text);
while ( colRowStart < col )
{
yEnd++;
colRowStart += GetPartOfWrappedLine(text.c_str() +
colRowStart);
}
} }
else else
{ {
@@ -1303,11 +1411,11 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
yEnd = yStart + rectText.height / GetCharHeight() - 1; yEnd = yStart + rectText.height / GetCharHeight() - 1;
} }
if ( yEnd < row ) if ( yEnd < y )
{ {
// scroll down: the current item should appear at the // scroll down: the current item should appear at the
// bottom of the view // bottom of the view
Scroll(0, row - (yEnd - yStart)); Scroll(0, y - (yEnd - yStart));
} }
} }
} }
@@ -1319,25 +1427,28 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
// column as they all have different widths, so we need to // column as they all have different widths, so we need to
// translate everything to pixels // translate everything to pixels
// we want the text between posLeft and posRight be entirely inside // we want the text between x and x2 be entirely inside the view
// the view (i.e. the current character) // (i.e. the current character)
wxString line = GetLineText(row);
wxCoord posLeft = GetTextWidth(line.Left(col));
// make xStart the first visible pixel (and not position) // make xStart the first visible pixel (and not position)
int wChar = GetCharWidth(); int wChar = GetCharWidth();
xStart *= GetCharWidth(); xStart *= GetCharWidth();
if ( posLeft < xStart ) if ( x < xStart )
{ {
Scroll(posLeft / wChar, row); Scroll(x / wChar, y);
} }
else // maybe we're beyond the right border of the view? else // maybe we're beyond the right border of the view?
{ {
wxCoord posRight = posLeft + GetTextWidth(line[(size_t)col]); wxTextCoord col, row;
if ( posRight > xStart + rectText.width ) if ( PositionToXY(pos, &col, &row) )
{ {
Scroll(posRight / wChar, row); wxString lineText = GetLineText(row);
wxCoord x2 = x + GetTextWidth(lineText[(size_t)col]);
if ( x2 > xStart + rectText.width )
{
Scroll(x2 / wChar, row);
}
} }
} }
} }
@@ -1771,22 +1882,26 @@ wxRect wxTextCtrl::GetRealTextArea() const
} }
size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text,
wxCoord width) const wxCoord *widthReal) const
{ {
wxTextCtrl *self = wxConstCast(this, wxTextCtrl); wxTextCtrl *self = wxConstCast(this, wxTextCtrl);
wxClientDC dc(self); wxClientDC dc(self);
dc.SetFont(GetFont()); dc.SetFont(GetFont());
self->DoPrepareDC(dc); self->DoPrepareDC(dc);
wxCoord widthMax = m_rectText.width;
// the text which we can keep in this ROW // the text which we can keep in this ROW
wxString str; wxString str;
for ( wxCoord w = 0; *text && (w <= width); ) wxCoord w, wOld;
for ( wOld = w = 0; *text && (w <= widthMax); )
{ {
wOld = w;
str += *text++; str += *text++;
dc.GetTextExtent(str, &w, NULL); dc.GetTextExtent(str, &w, NULL);
} }
if ( *text ) if ( w > widthMax )
{ {
// if we wrapped, the last letter was one too much // if we wrapped, the last letter was one too much
if ( str.length() > 1 ) if ( str.length() > 1 )
@@ -1794,7 +1909,21 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text,
// remove it // remove it
str.erase(str.length() - 1, 1); str.erase(str.length() - 1, 1);
} }
//else: but always keep at least one letter in each row else // but always keep at least one letter in each row
{
// the real width then is the last value of w and not teh one
// before last
wOld = w;
}
}
else // we didn't wrap
{
wOld = w;
}
if ( widthReal )
{
*widthReal = wOld;
} }
return str.length(); return str.length();
@@ -1820,7 +1949,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
// the end of it // the end of it
col = line.length() - 1; col = line.length() - 1;
res = wxTE_HT_AFTER; res = wxTE_HT_BEYOND;
} }
else if ( x < 0 ) else if ( x < 0 )
{ {
@@ -1952,17 +2081,11 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pos,
return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL); return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL);
} }
wxTextCtrlHitTestResult wxTextCtrl::HitTestClient(wxCoord x, wxCoord y, wxTextCtrlHitTestResult wxTextCtrl::HitTestLogical(const wxPoint& pos,
wxTextCoord *col, wxTextCoord *colOut,
wxTextCoord *row) const wxTextCoord *rowOut) const
{ {
// OPT this is a bit silly: we undo this in HitTest(), so it would be return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL, FALSE);
// better to factor out the common functionality into a separate
// function (OTOH it won't probably save us that much)
wxPoint pt(x, y);
pt += GetClientAreaOrigin();
pt += m_rectText.GetPosition();
return HitTest(pt, col, row);
} }
wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0, wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
@@ -1971,16 +2094,26 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
wxTextCoord *rowOut, wxTextCoord *rowOut,
wxTextCoord *colStart, wxTextCoord *colStart,
wxTextCoord *colEnd, wxTextCoord *colEnd,
wxTextCoord *colRowStartOut) const wxTextCoord *colRowStartOut,
bool deviceCoords) const
{ {
// is the point in the text area or to the right or below it? // is the point in the text area or to the right or below it?
wxTextCtrlHitTestResult res = wxTE_HT_ON_TEXT; wxTextCtrlHitTestResult res = wxTE_HT_ON_TEXT;
// translate the window coords x0 and y0 into the client coords in the text // translate the window coords x0 and y0 into the client coords in the text
// area by adjusting for both the client and text area offsets // area by adjusting for both the client and text area offsets (unless this
wxPoint pt = GetClientAreaOrigin() + m_rectText.GetPosition(); // was already done)
int x1, y; int x1, y;
CalcUnscrolledPosition(x10 - pt.x, y0 - pt.y, &x1, &y); if ( deviceCoords )
{
wxPoint pt = GetClientAreaOrigin() + m_rectText.GetPosition();
CalcUnscrolledPosition(x10 - pt.x, y0 - pt.y, &x1, &y);
}
else
{
y = y0;
x1 = x10;
}
// calculate the row (it is really a LINE, not a ROW) // calculate the row (it is really a LINE, not a ROW)
wxTextCoord row; wxTextCoord row;
@@ -2005,7 +2138,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
// line // line
row = rowLast; row = rowLast;
res = wxTE_HT_AFTER; res = wxTE_HT_BELOW;
} }
else if ( row < 0 ) else if ( row < 0 )
{ {
@@ -2036,26 +2169,28 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
textLine = GetLineText(row); textLine = GetLineText(row);
size_t nRowInLine, size_t nRowInLine,
nRowsPerLine = GetRowsPerLine(row); nRowsPerLine = GetRowsPerLine(row);
for ( nRowInLine = 0; nRowInLine < nRowsPerLine; nRowInLine++ ) for ( nRowInLine = 0;
!found && (nRowInLine < nRowsPerLine);
nRowInLine++ )
{ {
int yCurNew = yCur + hLine; rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart);
if ( yCurNew > y )
yCur += hLine;
if ( yCur > y )
{ {
// point is in this row // point is in this row, so don't change colRowStart
found = TRUE; found = TRUE;
break;
} }
else
yCur = yCurNew; {
// the start of the next row
rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart, colRowStart += rowLen;
m_rectText.width); }
colRowStart += rowLen;
} }
// we shouldn't increase LINE in the outer for loop if we found // we shouldn't increase LINE in the outer for loop if we found
// match inside this one // match inside this one, this is why we break here instead of just
// putting "& !found" in for condition
if ( found ) if ( found )
{ {
break; break;
@@ -2070,12 +2205,14 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
if ( row > rowLast ) if ( row > rowLast )
{ {
// we are beyond the last line // we are beyond the last line
res = wxTE_HT_AFTER; res = wxTE_HT_BELOW;
row = rowLast;
} }
else if ( !rowLen ) else if ( !rowLen )
{ {
// find the length of the first row of the line we just found // we must get the length of the first row of the next line
rowLen = GetPartOfWrappedLine(GetLineText(row), m_rectText.width); rowLen = GetPartOfWrappedLine(GetLineText(row));
} }
} }
@@ -2132,7 +2269,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
// corresponding line // corresponding line
if ( res == wxTE_HT_BEFORE ) if ( res == wxTE_HT_BEFORE )
*colStart = 0; *colStart = 0;
else // res == wxTE_HT_AFTER else // res == wxTE_HT_BELOW
*colStart = GetLineText(GetNumberOfLines() - 1).length(); *colStart = GetLineText(GetNumberOfLines() - 1).length();
} }
} }
@@ -2465,13 +2602,7 @@ void wxTextCtrl::RefreshLineRange(wxTextCoord lineFirst, wxTextCoord lineLast)
wxCoord h = GetCharHeight(); wxCoord h = GetCharHeight();
rect.y = GetNumberOfRowsBefore(lineFirst)*h; rect.y = GetNumberOfRowsBefore(lineFirst)*h;
// don't refresh beyond the window boundary
if ( lineLast > GetNumberOfLines() - 1 )
lineLast = GetNumberOfLines() - 1;
wxCoord bottom = GetNumberOfRowsBefore(lineLast + 1)*h; wxCoord bottom = GetNumberOfRowsBefore(lineLast + 1)*h;
if ( bottom > m_rectText.height )
bottom = m_rectText.height;
rect.SetBottom(bottom); rect.SetBottom(bottom);
RefreshTextRect(rect); RefreshTextRect(rect);
@@ -2485,6 +2616,10 @@ void wxTextCtrl::RefreshTextRange(wxTextPos start, wxTextPos end)
// accept arguments in any order as it is more conenient for the caller // accept arguments in any order as it is more conenient for the caller
OrderPositions(start, end); OrderPositions(start, end);
// this is acceptable but we don't do anything in this case
if ( start == end )
return;
wxTextPos colStart, lineStart; wxTextPos colStart, lineStart;
if ( !PositionToXY(start, &colStart, &lineStart) ) if ( !PositionToXY(start, &colStart, &lineStart) )
{ {
@@ -2520,7 +2655,8 @@ void wxTextCtrl::RefreshTextRange(wxTextPos start, wxTextPos end)
posCount = colEnd - posStart; posCount = colEnd - posStart;
} }
RefreshColRange(line, posStart, posCount); if ( posCount )
RefreshColRange(line, posStart, posCount);
} }
} }
@@ -2530,6 +2666,9 @@ void wxTextCtrl::RefreshColRange(wxTextCoord line,
{ {
wxString text = GetLineText(line); wxString text = GetLineText(line);
wxASSERT_MSG( (size_t)start <= text.length() && count,
_T("invalid RefreshColRange() parameter") );
RefreshPixelRange(line, RefreshPixelRange(line,
GetTextWidth(text.Left((size_t)start)), GetTextWidth(text.Left((size_t)start)),
GetTextWidth(text.Mid((size_t)start, (size_t)count))); GetTextWidth(text.Mid((size_t)start, (size_t)count)));
@@ -2542,23 +2681,31 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line,
wxCoord start, wxCoord start,
wxCoord width) wxCoord width)
{ {
// we will use line text only in line wrap case
wxString text;
if ( WrapLines() )
{
text = GetLineText(line);
}
// special case: width == 0 means to refresh till the end of line // special case: width == 0 means to refresh till the end of line
if ( width == 0 ) if ( width == 0 )
{ {
// FIXME we refresh till the end of the current line here, but we can't
// tell if the line didn't have fewer or more rows before - it is
// the callers responsability to not call us in this way if it is
// the case
if ( WrapLines() ) if ( WrapLines() )
{ {
// if we need to refresh until the end of line, refresh all text width = wxMax(GetTextWidth(text), GetTotalWidth());
// below because the next lines might have changed - we have no way
// to know if they did or not
RefreshLineRange(line, GetNumberOfLines());
return;
} }
else else
{ {
// refresh till the end of line // refresh till the end of visible line
width = GetTotalWidth() - start; width = GetTotalWidth();
} }
width -= start;
} }
wxCoord h = GetCharHeight(); wxCoord h = GetCharHeight();
@@ -2569,26 +2716,32 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line,
if ( WrapLines() ) if ( WrapLines() )
{ {
wxCoord wLine = m_rectText.width; // (1) skip all rows which we don't touch at all
wxCoord wLine;
// find the row where we start to refresh size_t ofs = GetPartOfWrappedLine(text.c_str(), &wLine);
while ( rect.x > wLine ) while ( wLine && (rect.x >= wLine) )
{ {
rect.x -= wLine; rect.x -= wLine;
rect.y += h; rect.y += h;
ofs += GetPartOfWrappedLine(text.c_str() + ofs, &wLine);
} }
// now refresh all lines except the last one // (2) now refresh all lines except the last one: note that the first
while ( width > wLine ) // line is refreshed from the given start to the end, all the next
// ones - entirely
while ( wLine && (rect.x + width > wLine) )
{ {
rect.width = GetTotalWidth() - rect.x; rect.width = GetTotalWidth() - rect.x;
RefreshTextRect(rect); RefreshTextRect(rect);
width -= wLine - rect.x;
rect.x = 0; rect.x = 0;
width -= wLine;
rect.y += h; rect.y += h;
ofs += GetPartOfWrappedLine(text.c_str() + ofs, &wLine);
} }
// the code below will refresh the line too // (3) the code below will refresh the last line
} }
rect.width = width; rect.width = width;
@@ -2596,8 +2749,9 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line,
RefreshTextRect(rect); RefreshTextRect(rect);
} }
void wxTextCtrl::RefreshTextRect(wxRect& rect) void wxTextCtrl::RefreshTextRect(const wxRect& rectClient)
{ {
wxRect rect = rectClient;
if ( IsSingleLine() ) if ( IsSingleLine() )
{ {
// account for horz scrolling // account for horz scrolling
@@ -2709,36 +2863,51 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
#endif // WXDEBUG_TEXT #endif // WXDEBUG_TEXT
// calculate the range lineStart..lineEnd of lines to redraw // calculate the range lineStart..lineEnd of lines to redraw
wxPoint pt = rectUpdate.GetPosition(); wxTextCoord lineStart, lineEnd;
wxTextCoord lineStart; if ( IsSingleLine() )
(void)HitTest(pt, NULL, &lineStart); {
lineStart =
lineEnd = 0;
}
else // multiline
{
wxPoint pt = rectUpdate.GetPosition();
(void)HitTest(pt, NULL, &lineStart);
pt.y += rectUpdate.height; pt.y += rectUpdate.height;
wxTextCoord lineEnd; (void)HitTest(pt, NULL, &lineEnd);
(void)HitTest(pt, NULL, &lineEnd); }
// prepare for drawing // prepare for drawing
wxCoord hLine = GetCharHeight(); wxCoord hLine = GetCharHeight();
wxRect rectText;
rectText.height = hLine;
rectText.y = m_rectText.y + lineStart*rectText.height;
// these vars will be used for hit testing of the current row // these vars will be used for hit testing of the current row
wxCoord y = rectUpdate.y; wxCoord y = rectUpdate.y;
const wxCoord x1 = rectUpdate.x; const wxCoord x1 = rectUpdate.x;
const wxCoord x2 = rectUpdate.x + rectUpdate.width; const wxCoord x2 = rectUpdate.x + rectUpdate.width;
wxRect rectText;
rectText.height = hLine;
if ( !IsSingleLine() )
{
CalcUnscrolledPosition(0, y - GetClientAreaOrigin().y,
NULL, &rectText.y);
}
// do draw the invalidated parts of each line: note that we iterate here // do draw the invalidated parts of each line: note that we iterate here
// over ROWs, not over LINEs // over ROWs, not over LINEs
for ( wxTextCoord line = lineStart; for ( wxTextCoord line = lineStart;
y < rectUpdate.y + rectUpdate.height; y < rectUpdate.y + rectUpdate.height;
rectText.y += hLine, y += hLine,
y += hLine ) rectText.y += hLine )
{ {
// calculate the update rect in text positions for this line // calculate the update rect in text positions for this line
wxTextCoord colStart, colEnd, colRowStart; wxTextCoord colStart, colEnd, colRowStart;
if ( HitTest2(y, x1, x2, wxTextCtrlHitTestResult ht = HitTest2(y, x1, x2,
&line, &colStart, &colEnd, &colRowStart) == wxTE_HT_AFTER ) &line, &colStart, &colEnd,
&colRowStart);
if ( (ht == wxTE_HT_BEYOND) || (ht == wxTE_HT_BELOW) )
{ {
wxASSERT_MSG( line <= lineEnd, _T("how did we get that far?") ); wxASSERT_MSG( line <= lineEnd, _T("how did we get that far?") );
@@ -2781,13 +2950,15 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
} }
if ( colEnd > m_colLastVisible ) if ( colEnd > m_colLastVisible )
{
colEnd = m_colLastVisible; colEnd = m_colLastVisible;
// we don't draw the last character because it may be shown only // we don't draw the last character because it may be shown
// partially in single line mode (in multi line we can't avoid // only partially in single line mode (in multi line we can't
// showing parts of characters anyhow) // avoid showing parts of characters anyhow)
if ( colEnd > colStart ) if ( colEnd > colStart )
colEnd--; colEnd--;
}
} }
// extract the part of line we need to redraw // extract the part of line we need to redraw
@@ -2814,7 +2985,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
selEnd = text.length(); selEnd = text.length();
} }
// calculate the physical text coords // calculate the text coords on screen
wxCoord ofsStart = GetTextWidth( wxCoord ofsStart = GetTextWidth(
textLine.Mid(colRowStart, textLine.Mid(colRowStart,
colStart - colRowStart)); colStart - colRowStart));
@@ -2952,13 +3123,7 @@ void wxTextCtrl::ShowCaret(bool show)
if ( caret ) if ( caret )
{ {
// (re)position caret correctly // (re)position caret correctly
wxCoord xCaret, yCaret; caret->Move(GetCaretPosition());
if ( !PositionToPixelXY(m_curPos, &xCaret, &yCaret) )
{
wxFAIL_MSG( _T("Caret can't be beyond the text!") );
}
caret->Move(xCaret, yCaret);
// and show it there // and show it there
caret->Show(show); caret->Show(show);
@@ -3030,13 +3195,34 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig,
} }
else if ( action == wxACTION_TEXT_UP ) else if ( action == wxACTION_TEXT_UP )
{ {
if ( m_curRow > 0 ) // move the cursor up by one ROW not by one LINE: this means that we
newPos = XYToPosition(m_curCol, m_curRow - 1); // should really use HitTest() and not just go to the same position in
// the previous line
wxPoint pt = GetCaretPosition() - m_rectText.GetPosition();
CalcUnscrolledPosition(pt.x, pt.y, &pt.x, &pt.y);
pt.y -= GetCharHeight();
wxTextCoord col, row;
if ( HitTestLogical(pt, &col, &row) != wxTE_HT_BEFORE )
{
newPos = XYToPosition(col, row);
}
} }
else if ( action == wxACTION_TEXT_DOWN ) else if ( action == wxACTION_TEXT_DOWN )
{ {
if ( (size_t)m_curRow < m_lines.GetCount() ) // see comments for wxACTION_TEXT_UP
newPos = XYToPosition(m_curCol, m_curRow + 1); wxPoint pt = GetCaretPosition() - m_rectText.GetPosition();
CalcUnscrolledPosition(pt.x, pt.y, &pt.x, &pt.y);
pt.y += GetCharHeight();
wxTextCoord col, row;
if ( HitTestLogical(pt, &col, &row) != wxTE_HT_BELOW )
{
// note that wxTE_HT_BEYOND is ok: it happens when we go down from
// a longer line to a shorter one, for example (OTOH wxTE_HT_BEFORE
// can never happen)
newPos = XYToPosition(col, row);
}
} }
else if ( action == wxACTION_TEXT_LEFT ) else if ( action == wxACTION_TEXT_LEFT )
{ {
@@ -3249,7 +3435,7 @@ wxTextPos wxStdTextCtrlInputHandler::HitTest(const wxTextCtrl *text,
// if the point is after the last column we must adjust the position to be // if the point is after the last column we must adjust the position to be
// the last position in the line (unless it is already the last) // the last position in the line (unless it is already the last)
if ( (ht == wxTE_HT_AFTER) && (pos < text->GetLastPosition()) ) if ( (ht == wxTE_HT_BEYOND) && (pos < text->GetLastPosition()) )
{ {
pos++; pos++;
} }
@@ -3426,4 +3612,18 @@ bool wxStdTextCtrlInputHandler::HandleMouseMove(wxControl *control,
return wxStdInputHandler::HandleMouseMove(control, event); return wxStdInputHandler::HandleMouseMove(control, event);
} }
bool wxStdTextCtrlInputHandler::HandleFocus(wxControl *control,
const wxFocusEvent& event)
{
if ( event.GetEventType() == wxEVT_KILL_FOCUS )
{
wxStaticCast(control, wxTextCtrl)->ClearSelection();
// don't refresh
return FALSE;
}
return wxStdInputHandler::HandleFocus(control, event);
}
#endif // wxUSE_TEXTCTRL #endif // wxUSE_TEXTCTRL

View File

@@ -1484,6 +1484,12 @@ void wxWin32Renderer::DrawCheckItem(wxDC& dc,
wxBitmap wxWin32Renderer::GetCheckBitmap(int flags) wxBitmap wxWin32Renderer::GetCheckBitmap(int flags)
{ {
if ( flags & wxCONTROL_DISABLED )
{
// the disabled indicators look the same as pressed ones in Windows
flags |= wxCONTROL_PRESSED;
}
char **xpm; char **xpm;
if ( flags & wxCONTROL_CHECKED ) if ( flags & wxCONTROL_CHECKED )
{ {
@@ -1501,6 +1507,12 @@ wxBitmap wxWin32Renderer::GetCheckBitmap(int flags)
wxBitmap wxWin32Renderer::GetRadioBitmap(int flags) wxBitmap wxWin32Renderer::GetRadioBitmap(int flags)
{ {
if ( flags & wxCONTROL_DISABLED )
{
// the disabled indicators look the same as pressed ones in Windows
flags |= wxCONTROL_PRESSED;
}
char **xpm; char **xpm;
if ( flags & wxCONTROL_CHECKED ) if ( flags & wxCONTROL_CHECKED )
{ {