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:
10
TODO
10
TODO
@@ -14,10 +14,11 @@ samples:
|
||||
|
||||
wxTextCtrl
|
||||
|
||||
* adjust refresh/scroll for WrapLines() case
|
||||
*! call to RefreshLineRange() from Replace() is broken
|
||||
*! display corrupted when typing text in quickly (caret problem?)
|
||||
* caret leaves traces under wxGTK
|
||||
? text ctrl display pb when text is truncated
|
||||
* remember selection when losing/gaining activation
|
||||
* too much is refreshed when double clicking (word select)
|
||||
|
||||
All
|
||||
@@ -27,15 +28,13 @@ All
|
||||
|
||||
* wxCheckListBox: redraw only the bitmap when toggled
|
||||
|
||||
* 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
|
||||
? problem with lbox horz scrolling: the focus rect isn't drawn entirely...
|
||||
|
||||
* popup menu for text ctrls
|
||||
|
||||
MSW
|
||||
|
||||
* checkboxes don't look correctly in checked+disabled state (radio too?)
|
||||
* text control scrollbar has text cursor
|
||||
scrollbar behaves strangely in log lbox with many strings
|
||||
|
||||
@@ -49,6 +48,7 @@ DONE
|
||||
|
||||
All
|
||||
|
||||
+ adjust refresh/scroll for WrapLines() case
|
||||
+ text ctrl horz scrolling
|
||||
+ DoDraw should iterate over update region instead of using bounding box
|
||||
+ listbox: horz scrollbar doesn't appear
|
||||
|
@@ -304,6 +304,7 @@ public:
|
||||
const wxMouseEvent& event);
|
||||
virtual bool HandleMouseMove(wxControl *control,
|
||||
const wxMouseEvent& event);
|
||||
virtual bool HandleFocus(wxControl *control, const wxFocusEvent& event);
|
||||
|
||||
protected:
|
||||
// get the position of the mouse click
|
||||
|
@@ -79,12 +79,15 @@ typedef long wxTextCoord;
|
||||
// wxTextCtrl::HitTest return values
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// the point asked is ...
|
||||
enum wxTextCtrlHitTestResult
|
||||
{
|
||||
wxTE_HT_BEFORE = -1,
|
||||
wxTE_HT_ON_TEXT,
|
||||
wxTE_HT_AFTER
|
||||
wxTE_HT_BEFORE = -1, // either to the left or upper
|
||||
wxTE_HT_ON_TEXT, // directly on
|
||||
wxTE_HT_BELOW, // below [the last line]
|
||||
wxTE_HT_BEYOND // after [the end of line]
|
||||
};
|
||||
// ... the character returned
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxTextCtrl
|
||||
@@ -163,8 +166,10 @@ public:
|
||||
wxTextCoord *x, wxTextCoord *y) const;
|
||||
|
||||
// wxUniv-specific: find a screen position (in client coordinates) of the
|
||||
// given text position
|
||||
bool PositionToPixelXY(wxTextPos pos, wxCoord *x, wxCoord *y) const;
|
||||
// given text position or of the caret
|
||||
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);
|
||||
|
||||
@@ -301,7 +306,7 @@ protected:
|
||||
wxRect GetRealTextArea() const;
|
||||
|
||||
// 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
|
||||
// width is 0, refresh to the end of line
|
||||
@@ -321,8 +326,10 @@ protected:
|
||||
// starts for wxTE_PASSWORD control
|
||||
wxString GetTextToShow(const wxString& text) const;
|
||||
|
||||
// find the number of characters of a line before it wraps at given width
|
||||
size_t GetPartOfWrappedLine(const wxChar* text, wxCoord width) const;
|
||||
// find the number of characters of a line before it wraps
|
||||
// (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
|
||||
// outside the selection, both will be -1 and FALSE will be returned
|
||||
@@ -359,17 +366,21 @@ protected:
|
||||
// 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
|
||||
// pixels
|
||||
//
|
||||
// as the last hack, this function accepts either logical or device (by
|
||||
// default) coords depending on devCoords flag
|
||||
wxTextCtrlHitTestResult HitTest2(wxCoord y,
|
||||
wxCoord x1,
|
||||
wxCoord x2,
|
||||
wxTextCoord *row,
|
||||
wxTextCoord *colStart,
|
||||
wxTextCoord *colEnd,
|
||||
wxTextCoord *colRowStart) const;
|
||||
wxTextCoord *colRowStart,
|
||||
bool devCoords = TRUE) const;
|
||||
|
||||
// HitTest() version for use in wxTextCtrl: it takes the text coordinates
|
||||
// (i.e. coords relative to the text rect)
|
||||
wxTextCtrlHitTestResult HitTestClient(wxCoord x, wxCoord y,
|
||||
// HitTest() version which takes the logical text coordinates and not the
|
||||
// device ones
|
||||
wxTextCtrlHitTestResult HitTestLogical(const wxPoint& pos,
|
||||
wxTextCoord *col,
|
||||
wxTextCoord *row) const;
|
||||
|
||||
|
@@ -363,19 +363,19 @@ TextTestFrame::TextTestFrame(const wxString& title)
|
||||
_T("Current pos:"),
|
||||
m_textPosCur
|
||||
),
|
||||
0, wxRIGHT | wxGROW, 5);
|
||||
0, wxGROW | wxRIGHT, 5);
|
||||
sizerRow->Add(CreateTextWithLabelSizer
|
||||
(
|
||||
_T("Col:"),
|
||||
m_textColCur
|
||||
),
|
||||
0, wxRIGHT | wxLEFT | wxGROW, 5);
|
||||
0, wxGROW | wxLEFT | wxRIGHT, 5);
|
||||
sizerRow->Add(CreateTextWithLabelSizer
|
||||
(
|
||||
_T("Row:"),
|
||||
m_textRowCur
|
||||
),
|
||||
0, wxLEFT | wxGROW, 5);
|
||||
0, wxGROW | wxLEFT, 5);
|
||||
sizerMiddleDown->Add(sizerRow, 0, wxALL | wxGROW, 5);
|
||||
|
||||
m_textLineLast = CreateInfoText();
|
||||
@@ -566,7 +566,7 @@ void TextTestFrame::CreateText()
|
||||
flags);
|
||||
m_sizerText->Add(m_text, 1, wxALL |
|
||||
(flags & wxTE_MULTILINE ? wxGROW
|
||||
: wxALIGN_CENTRE_VERTICAL), 5);
|
||||
: wxALIGN_TOP), 5);
|
||||
m_sizerText->Layout();
|
||||
}
|
||||
|
||||
|
@@ -74,7 +74,9 @@ void wxStaticText::SetLabel(const wxString& label)
|
||||
|
||||
wxSize wxStaticText::DoGetBestClientSize() const
|
||||
{
|
||||
wxClientDC dc(wxConstCast(this, wxStaticText));
|
||||
wxStaticText *self = wxConstCast(this, wxStaticText);
|
||||
wxClientDC dc(self);
|
||||
dc.SetFont(GetFont());
|
||||
wxCoord width, height;
|
||||
dc.GetMultiLineTextExtent(GetLabel(), &width, &height);
|
||||
|
||||
|
@@ -12,10 +12,13 @@
|
||||
/*
|
||||
TODO
|
||||
|
||||
! 1. update vert scrollbar when any line length changes for WrapLines()
|
||||
2. cursor movement ("Hello,^" -> "^verse!" on Arrow Down)?
|
||||
+ 1. update vert scrollbar when any line length changes for WrapLines()
|
||||
+ 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
|
||||
! 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 (?)
|
||||
}
|
||||
else
|
||||
{
|
||||
// this doesn't make sense for single line controls
|
||||
style &= ~wxHSCROLL;
|
||||
}
|
||||
|
||||
if ( !wxControl::Create(parent, id, pos, size, style,
|
||||
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.
|
||||
*/
|
||||
|
||||
// (0) remember the number of rows before we started
|
||||
wxTextCoord rowsOld = GetNumberOfRowsBefore(GetNumberOfLines());
|
||||
|
||||
// (1) join lines
|
||||
wxString textOrig;
|
||||
wxTextCoord line;
|
||||
@@ -631,20 +642,46 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text)
|
||||
}
|
||||
|
||||
// (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
|
||||
if ( lineStart < lineEnd )
|
||||
RefreshLineRange(lineStart + 1, lineEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// number of lines did change, we need to refresh everything below
|
||||
// the start line
|
||||
RefreshLineRange(lineStart + 1,
|
||||
wxMax(m_lines.GetCount(), countOld) - 1);
|
||||
if ( !WrapLines() )
|
||||
{
|
||||
// refresh only part of the first line
|
||||
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
|
||||
m_updateScrollbarY = TRUE;
|
||||
@@ -664,8 +701,24 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text)
|
||||
// end of the replacement text
|
||||
DoSetInsertionPoint(from + text.length());
|
||||
|
||||
// and the selection (do it after setting the cursor to have correct value
|
||||
// for selection anchor)
|
||||
// and the selection: this is complicated by the fact that selection coords
|
||||
// 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();
|
||||
}
|
||||
|
||||
@@ -1145,11 +1198,26 @@ bool wxTextCtrl::PositionToXY(wxTextPos pos,
|
||||
|
||||
wxTextCoord wxTextCtrl::GetRowsPerLine(wxTextCoord line) const
|
||||
{
|
||||
wxCoord wLine = m_rectText.width,
|
||||
wLineTotal = GetTextWidth(GetLineText(line));
|
||||
// we can't just divide the line length by the width of the window as there
|
||||
// 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
|
||||
return wLineTotal == 0 ? 1 : (wLineTotal + wLine - 1) / wLine;
|
||||
wxTextCoord rows = 0;
|
||||
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
|
||||
@@ -1166,8 +1234,9 @@ wxTextCoord wxTextCtrl::GetNumberOfRowsBefore(wxTextCoord lineMax) const
|
||||
return nRows;
|
||||
}
|
||||
|
||||
bool wxTextCtrl::PositionToPixelXY(wxTextPos pos,
|
||||
wxCoord *xOut, wxCoord *yOut) const
|
||||
bool wxTextCtrl::PositionToLogicalXY(wxTextPos pos,
|
||||
wxCoord *xOut,
|
||||
wxCoord *yOut) const
|
||||
{
|
||||
wxTextCoord col, line;
|
||||
|
||||
@@ -1205,8 +1274,7 @@ bool wxTextCtrl::PositionToPixelXY(wxTextPos pos,
|
||||
wxTextCoord colRowStart = 0;
|
||||
for ( ;; )
|
||||
{
|
||||
int rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart,
|
||||
m_rectText.width);
|
||||
int rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart);
|
||||
|
||||
// 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
|
||||
@@ -1237,6 +1305,22 @@ bool wxTextCtrl::PositionToPixelXY(wxTextPos pos,
|
||||
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
|
||||
// coords
|
||||
CalcScrolledPosition(m_rectText.x + x - m_ofsHorz,
|
||||
@@ -1247,6 +1331,17 @@ bool wxTextCtrl::PositionToPixelXY(wxTextPos pos,
|
||||
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
|
||||
void wxTextCtrl::ShowPosition(wxTextPos pos)
|
||||
{
|
||||
@@ -1261,19 +1356,11 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
|
||||
int xStart, yStart;
|
||||
GetViewStart(&xStart, &yStart);
|
||||
|
||||
wxTextCoord row, col;
|
||||
if ( (pos == -1) || (pos == m_curPos) )
|
||||
{
|
||||
row = m_curRow;
|
||||
col = m_curCol;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
wxFAIL_MSG(_T("not implemented for multiline"));
|
||||
if ( pos == -1 )
|
||||
pos = m_curPos;
|
||||
|
||||
return;
|
||||
}
|
||||
wxCoord x, y;
|
||||
PositionToLogicalXY(pos, &x, &y);
|
||||
|
||||
wxRect rectText = GetRealTextArea();
|
||||
|
||||
@@ -1281,9 +1368,11 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
|
||||
// it, make it the first one, otherwise the last one
|
||||
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
|
||||
{
|
||||
@@ -1293,8 +1382,27 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
|
||||
if ( WrapLines() )
|
||||
{
|
||||
// to find the last row we need to use the generic HitTest
|
||||
HitTestClient(0, rectText.height, NULL, &yEnd);
|
||||
yEnd--;
|
||||
wxTextCoord col;
|
||||
|
||||
// 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
|
||||
{
|
||||
@@ -1303,11 +1411,11 @@ void wxTextCtrl::ShowPosition(wxTextPos pos)
|
||||
yEnd = yStart + rectText.height / GetCharHeight() - 1;
|
||||
}
|
||||
|
||||
if ( yEnd < row )
|
||||
if ( yEnd < y )
|
||||
{
|
||||
// scroll down: the current item should appear at the
|
||||
// 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
|
||||
// translate everything to pixels
|
||||
|
||||
// we want the text between posLeft and posRight be entirely inside
|
||||
// the view (i.e. the current character)
|
||||
wxString line = GetLineText(row);
|
||||
wxCoord posLeft = GetTextWidth(line.Left(col));
|
||||
// we want the text between x and x2 be entirely inside the view
|
||||
// (i.e. the current character)
|
||||
|
||||
// make xStart the first visible pixel (and not position)
|
||||
int wChar = 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?
|
||||
{
|
||||
wxCoord posRight = posLeft + GetTextWidth(line[(size_t)col]);
|
||||
if ( posRight > xStart + rectText.width )
|
||||
wxTextCoord col, row;
|
||||
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,
|
||||
wxCoord width) const
|
||||
wxCoord *widthReal) const
|
||||
{
|
||||
wxTextCtrl *self = wxConstCast(this, wxTextCtrl);
|
||||
wxClientDC dc(self);
|
||||
dc.SetFont(GetFont());
|
||||
self->DoPrepareDC(dc);
|
||||
|
||||
wxCoord widthMax = m_rectText.width;
|
||||
|
||||
// the text which we can keep in this ROW
|
||||
wxString str;
|
||||
for ( wxCoord w = 0; *text && (w <= width); )
|
||||
wxCoord w, wOld;
|
||||
for ( wOld = w = 0; *text && (w <= widthMax); )
|
||||
{
|
||||
wOld = w;
|
||||
str += *text++;
|
||||
dc.GetTextExtent(str, &w, NULL);
|
||||
}
|
||||
|
||||
if ( *text )
|
||||
if ( w > widthMax )
|
||||
{
|
||||
// if we wrapped, the last letter was one too much
|
||||
if ( str.length() > 1 )
|
||||
@@ -1794,7 +1909,21 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text,
|
||||
// remove it
|
||||
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();
|
||||
@@ -1820,7 +1949,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
|
||||
// the end of it
|
||||
col = line.length() - 1;
|
||||
|
||||
res = wxTE_HT_AFTER;
|
||||
res = wxTE_HT_BEYOND;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
wxTextCtrlHitTestResult wxTextCtrl::HitTestClient(wxCoord x, wxCoord y,
|
||||
wxTextCoord *col,
|
||||
wxTextCoord *row) const
|
||||
wxTextCtrlHitTestResult wxTextCtrl::HitTestLogical(const wxPoint& pos,
|
||||
wxTextCoord *colOut,
|
||||
wxTextCoord *rowOut) const
|
||||
{
|
||||
// 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(x, y);
|
||||
pt += GetClientAreaOrigin();
|
||||
pt += m_rectText.GetPosition();
|
||||
return HitTest(pt, col, row);
|
||||
return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL, FALSE);
|
||||
}
|
||||
|
||||
wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
|
||||
@@ -1971,16 +2094,26 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
|
||||
wxTextCoord *rowOut,
|
||||
wxTextCoord *colStart,
|
||||
wxTextCoord *colEnd,
|
||||
wxTextCoord *colRowStartOut) const
|
||||
wxTextCoord *colRowStartOut,
|
||||
bool deviceCoords) const
|
||||
{
|
||||
// is the point in the text area or to the right or below it?
|
||||
wxTextCtrlHitTestResult res = wxTE_HT_ON_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
|
||||
wxPoint pt = GetClientAreaOrigin() + m_rectText.GetPosition();
|
||||
// area by adjusting for both the client and text area offsets (unless this
|
||||
// was already done)
|
||||
int 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)
|
||||
wxTextCoord row;
|
||||
@@ -2005,7 +2138,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
|
||||
// line
|
||||
row = rowLast;
|
||||
|
||||
res = wxTE_HT_AFTER;
|
||||
res = wxTE_HT_BELOW;
|
||||
}
|
||||
else if ( row < 0 )
|
||||
{
|
||||
@@ -2036,26 +2169,28 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
|
||||
textLine = GetLineText(row);
|
||||
size_t nRowInLine,
|
||||
nRowsPerLine = GetRowsPerLine(row);
|
||||
for ( nRowInLine = 0; nRowInLine < nRowsPerLine; nRowInLine++ )
|
||||
for ( nRowInLine = 0;
|
||||
!found && (nRowInLine < nRowsPerLine);
|
||||
nRowInLine++ )
|
||||
{
|
||||
int yCurNew = yCur + hLine;
|
||||
if ( yCurNew > y )
|
||||
rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart);
|
||||
|
||||
yCur += hLine;
|
||||
if ( yCur > y )
|
||||
{
|
||||
// point is in this row
|
||||
// point is in this row, so don't change colRowStart
|
||||
found = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
yCur = yCurNew;
|
||||
|
||||
rowLen = GetPartOfWrappedLine(textLine.c_str() + colRowStart,
|
||||
m_rectText.width);
|
||||
else
|
||||
{
|
||||
// the start of the next row
|
||||
colRowStart += rowLen;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 )
|
||||
{
|
||||
break;
|
||||
@@ -2070,12 +2205,14 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
|
||||
if ( row > rowLast )
|
||||
{
|
||||
// we are beyond the last line
|
||||
res = wxTE_HT_AFTER;
|
||||
res = wxTE_HT_BELOW;
|
||||
|
||||
row = rowLast;
|
||||
}
|
||||
else if ( !rowLen )
|
||||
{
|
||||
// find the length of the first row of the line we just found
|
||||
rowLen = GetPartOfWrappedLine(GetLineText(row), m_rectText.width);
|
||||
// we must get the length of the first row of the next line
|
||||
rowLen = GetPartOfWrappedLine(GetLineText(row));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2132,7 +2269,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
|
||||
// corresponding line
|
||||
if ( res == wxTE_HT_BEFORE )
|
||||
*colStart = 0;
|
||||
else // res == wxTE_HT_AFTER
|
||||
else // res == wxTE_HT_BELOW
|
||||
*colStart = GetLineText(GetNumberOfLines() - 1).length();
|
||||
}
|
||||
}
|
||||
@@ -2465,13 +2602,7 @@ void wxTextCtrl::RefreshLineRange(wxTextCoord lineFirst, wxTextCoord lineLast)
|
||||
wxCoord h = GetCharHeight();
|
||||
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;
|
||||
if ( bottom > m_rectText.height )
|
||||
bottom = m_rectText.height;
|
||||
|
||||
rect.SetBottom(bottom);
|
||||
|
||||
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
|
||||
OrderPositions(start, end);
|
||||
|
||||
// this is acceptable but we don't do anything in this case
|
||||
if ( start == end )
|
||||
return;
|
||||
|
||||
wxTextPos colStart, lineStart;
|
||||
if ( !PositionToXY(start, &colStart, &lineStart) )
|
||||
{
|
||||
@@ -2520,6 +2655,7 @@ void wxTextCtrl::RefreshTextRange(wxTextPos start, wxTextPos end)
|
||||
posCount = colEnd - posStart;
|
||||
}
|
||||
|
||||
if ( posCount )
|
||||
RefreshColRange(line, posStart, posCount);
|
||||
}
|
||||
}
|
||||
@@ -2530,6 +2666,9 @@ void wxTextCtrl::RefreshColRange(wxTextCoord line,
|
||||
{
|
||||
wxString text = GetLineText(line);
|
||||
|
||||
wxASSERT_MSG( (size_t)start <= text.length() && count,
|
||||
_T("invalid RefreshColRange() parameter") );
|
||||
|
||||
RefreshPixelRange(line,
|
||||
GetTextWidth(text.Left((size_t)start)),
|
||||
GetTextWidth(text.Mid((size_t)start, (size_t)count)));
|
||||
@@ -2542,23 +2681,31 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line,
|
||||
wxCoord start,
|
||||
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
|
||||
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 we need to refresh until the end of line, refresh all text
|
||||
// below because the next lines might have changed - we have no way
|
||||
// to know if they did or not
|
||||
RefreshLineRange(line, GetNumberOfLines());
|
||||
|
||||
return;
|
||||
width = wxMax(GetTextWidth(text), GetTotalWidth());
|
||||
}
|
||||
else
|
||||
{
|
||||
// refresh till the end of line
|
||||
width = GetTotalWidth() - start;
|
||||
// refresh till the end of visible line
|
||||
width = GetTotalWidth();
|
||||
}
|
||||
|
||||
width -= start;
|
||||
}
|
||||
|
||||
wxCoord h = GetCharHeight();
|
||||
@@ -2569,26 +2716,32 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line,
|
||||
|
||||
if ( WrapLines() )
|
||||
{
|
||||
wxCoord wLine = m_rectText.width;
|
||||
|
||||
// find the row where we start to refresh
|
||||
while ( rect.x > wLine )
|
||||
// (1) skip all rows which we don't touch at all
|
||||
wxCoord wLine;
|
||||
size_t ofs = GetPartOfWrappedLine(text.c_str(), &wLine);
|
||||
while ( wLine && (rect.x >= wLine) )
|
||||
{
|
||||
rect.x -= wLine;
|
||||
rect.y += h;
|
||||
|
||||
ofs += GetPartOfWrappedLine(text.c_str() + ofs, &wLine);
|
||||
}
|
||||
|
||||
// now refresh all lines except the last one
|
||||
while ( width > wLine )
|
||||
// (2) now refresh all lines except the last one: note that the first
|
||||
// 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;
|
||||
RefreshTextRect(rect);
|
||||
width -= wLine - rect.x;
|
||||
rect.x = 0;
|
||||
width -= wLine;
|
||||
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;
|
||||
@@ -2596,8 +2749,9 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line,
|
||||
RefreshTextRect(rect);
|
||||
}
|
||||
|
||||
void wxTextCtrl::RefreshTextRect(wxRect& rect)
|
||||
void wxTextCtrl::RefreshTextRect(const wxRect& rectClient)
|
||||
{
|
||||
wxRect rect = rectClient;
|
||||
if ( IsSingleLine() )
|
||||
{
|
||||
// account for horz scrolling
|
||||
@@ -2709,36 +2863,51 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
|
||||
#endif // WXDEBUG_TEXT
|
||||
|
||||
// calculate the range lineStart..lineEnd of lines to redraw
|
||||
wxTextCoord lineStart, lineEnd;
|
||||
if ( IsSingleLine() )
|
||||
{
|
||||
lineStart =
|
||||
lineEnd = 0;
|
||||
}
|
||||
else // multiline
|
||||
{
|
||||
wxPoint pt = rectUpdate.GetPosition();
|
||||
wxTextCoord lineStart;
|
||||
(void)HitTest(pt, NULL, &lineStart);
|
||||
|
||||
pt.y += rectUpdate.height;
|
||||
wxTextCoord lineEnd;
|
||||
(void)HitTest(pt, NULL, &lineEnd);
|
||||
}
|
||||
|
||||
// prepare for drawing
|
||||
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
|
||||
wxCoord y = rectUpdate.y;
|
||||
const wxCoord x1 = rectUpdate.x;
|
||||
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
|
||||
// over ROWs, not over LINEs
|
||||
for ( wxTextCoord line = lineStart;
|
||||
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
|
||||
wxTextCoord colStart, colEnd, colRowStart;
|
||||
if ( HitTest2(y, x1, x2,
|
||||
&line, &colStart, &colEnd, &colRowStart) == wxTE_HT_AFTER )
|
||||
wxTextCtrlHitTestResult ht = HitTest2(y, x1, x2,
|
||||
&line, &colStart, &colEnd,
|
||||
&colRowStart);
|
||||
|
||||
if ( (ht == wxTE_HT_BEYOND) || (ht == wxTE_HT_BELOW) )
|
||||
{
|
||||
wxASSERT_MSG( line <= lineEnd, _T("how did we get that far?") );
|
||||
|
||||
@@ -2781,14 +2950,16 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
|
||||
}
|
||||
|
||||
if ( colEnd > m_colLastVisible )
|
||||
{
|
||||
colEnd = m_colLastVisible;
|
||||
|
||||
// we don't draw the last character because it may be shown only
|
||||
// partially in single line mode (in multi line we can't avoid
|
||||
// showing parts of characters anyhow)
|
||||
// we don't draw the last character because it may be shown
|
||||
// only partially in single line mode (in multi line we can't
|
||||
// avoid showing parts of characters anyhow)
|
||||
if ( colEnd > colStart )
|
||||
colEnd--;
|
||||
}
|
||||
}
|
||||
|
||||
// extract the part of line we need to redraw
|
||||
wxString textLine = GetTextToShow(GetLineText(line));
|
||||
@@ -2814,7 +2985,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
|
||||
selEnd = text.length();
|
||||
}
|
||||
|
||||
// calculate the physical text coords
|
||||
// calculate the text coords on screen
|
||||
wxCoord ofsStart = GetTextWidth(
|
||||
textLine.Mid(colRowStart,
|
||||
colStart - colRowStart));
|
||||
@@ -2952,13 +3123,7 @@ void wxTextCtrl::ShowCaret(bool show)
|
||||
if ( caret )
|
||||
{
|
||||
// (re)position caret correctly
|
||||
wxCoord xCaret, yCaret;
|
||||
if ( !PositionToPixelXY(m_curPos, &xCaret, &yCaret) )
|
||||
{
|
||||
wxFAIL_MSG( _T("Caret can't be beyond the text!") );
|
||||
}
|
||||
|
||||
caret->Move(xCaret, yCaret);
|
||||
caret->Move(GetCaretPosition());
|
||||
|
||||
// and show it there
|
||||
caret->Show(show);
|
||||
@@ -3030,13 +3195,34 @@ bool wxTextCtrl::PerformAction(const wxControlAction& actionOrig,
|
||||
}
|
||||
else if ( action == wxACTION_TEXT_UP )
|
||||
{
|
||||
if ( m_curRow > 0 )
|
||||
newPos = XYToPosition(m_curCol, m_curRow - 1);
|
||||
// move the cursor up by one ROW not by one LINE: this means that we
|
||||
// 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 )
|
||||
{
|
||||
if ( (size_t)m_curRow < m_lines.GetCount() )
|
||||
newPos = XYToPosition(m_curCol, m_curRow + 1);
|
||||
// see comments for wxACTION_TEXT_UP
|
||||
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 )
|
||||
{
|
||||
@@ -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
|
||||
// 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++;
|
||||
}
|
||||
@@ -3426,4 +3612,18 @@ bool wxStdTextCtrlInputHandler::HandleMouseMove(wxControl *control,
|
||||
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
|
||||
|
@@ -1484,6 +1484,12 @@ void wxWin32Renderer::DrawCheckItem(wxDC& dc,
|
||||
|
||||
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;
|
||||
if ( flags & wxCONTROL_CHECKED )
|
||||
{
|
||||
@@ -1501,6 +1507,12 @@ wxBitmap wxWin32Renderer::GetCheckBitmap(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;
|
||||
if ( flags & wxCONTROL_CHECKED )
|
||||
{
|
||||
|
Reference in New Issue
Block a user