text is shown correctly in controls without wxHSCROLL (line wrap) style

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8718 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-11-11 04:31:42 +00:00
parent 8637e11695
commit 45911360b2
5 changed files with 278 additions and 278 deletions

2
TODO
View File

@@ -16,7 +16,6 @@ wxTextCtrl
*! 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
* scrollbars don't disappear after deleting long line
? text ctrl display pb when text is truncated ? text ctrl display pb when text is truncated
* too much is refreshed when double clicking (word select) * too much is refreshed when double clicking (word select)
@@ -52,6 +51,7 @@ All
+ 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
+ wxTextCtrl update rect overlaps with horz scrollbar + wxTextCtrl update rect overlaps with horz scrollbar
+ scrollbars don't disappear after deleting long line
MSW MSW

View File

@@ -300,6 +300,9 @@ 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
size_t GetPartOfWrappedLine(const wxChar* text, wxCoord width) 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
bool GetSelectedPartOfLine(long line, int *start, int *end) const; bool GetSelectedPartOfLine(long line, int *start, int *end) const;
@@ -331,6 +334,15 @@ protected:
// update the max width after the given line was modified // update the max width after the given line was modified
void UpdateMaxWidth(long line); void UpdateMaxWidth(long line);
// 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
wxTextCtrlHitTestResult HitTest2(wxCoord y,
wxCoord x1, wxCoord x2,
long *row,
long *colStart, long *colEnd,
wxCoord *ofsStart) const;
// event handlers // event handlers
void OnIdle(wxIdleEvent& event); void OnIdle(wxIdleEvent& event);
void OnChar(wxKeyEvent& event); void OnChar(wxKeyEvent& event);

View File

@@ -68,30 +68,29 @@ enum
TextTest_Insert, TextTest_Insert,
TextTest_Clear, TextTest_Clear,
#if 0
TextTest_AddText,
TextTest_AddSeveral,
TextTest_AddMany,
TextTest_Change,
TextTest_ChangeText,
TextTest_Delete,
TextTest_DeleteText,
TextTest_DeleteSel,
#endif // 0
TextTest_Password, TextTest_Password,
TextTest_HScroll, TextTest_WrapLines,
TextTest_Textctrl, TextTest_Textctrl,
TextTest_Quit TextTest_Quit
}; };
// textctrl line number radiobox values // textctrl line number radiobox values
enum enum TextLines
{ {
TextLines_Single, TextLines_Single,
TextLines_Multi TextLines_Multi
}; };
// default values for the controls
static const struct ControlValues
{
TextLines textLines;
bool password;
bool wraplines;
bool readonly;
} DEFAULTS =
{ TextLines_Multi, FALSE, TRUE, FALSE };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// our classes // our classes
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -135,14 +134,6 @@ protected:
void OnButtonAdd(wxCommandEvent& event); void OnButtonAdd(wxCommandEvent& event);
void OnButtonClear(wxCommandEvent& event); void OnButtonClear(wxCommandEvent& event);
#if 0
void OnButtonChange(wxCommandEvent& event);
void OnButtonDelete(wxCommandEvent& event);
void OnButtonDeleteSel(wxCommandEvent& event);
void OnButtonAddSeveral(wxCommandEvent& event);
void OnButtonAddMany(wxCommandEvent& event);
#endif // 0
void OnButtonQuit(wxCommandEvent& event); void OnButtonQuit(wxCommandEvent& event);
void OnText(wxCommandEvent& event); void OnText(wxCommandEvent& event);
@@ -152,14 +143,8 @@ protected:
void OnUpdateUIClearButton(wxUpdateUIEvent& event); void OnUpdateUIClearButton(wxUpdateUIEvent& event);
#if 0
void OnUpdateUIAddSeveral(wxUpdateUIEvent& event);
void OnUpdateUIDeleteButton(wxUpdateUIEvent& event);
void OnUpdateUIDeleteSelButton(wxUpdateUIEvent& event);
#endif
void OnUpdateUIPasswordCheckbox(wxUpdateUIEvent& event); void OnUpdateUIPasswordCheckbox(wxUpdateUIEvent& event);
void OnUpdateUIHScrollCheckbox(wxUpdateUIEvent& event); void OnUpdateUIWrapLinesCheckbox(wxUpdateUIEvent& event);
void OnUpdateUIResetButton(wxUpdateUIEvent& event); void OnUpdateUIResetButton(wxUpdateUIEvent& event);
@@ -188,7 +173,7 @@ protected:
// the checkboxes controlling text ctrl styles // the checkboxes controlling text ctrl styles
wxCheckBox *m_chkPassword, wxCheckBox *m_chkPassword,
*m_chkHScroll, *m_chkWrapLines,
*m_chkReadonly; *m_chkReadonly;
// the textctrl itself and the sizer it is in // the textctrl itself and the sizer it is in
@@ -200,6 +185,8 @@ protected:
// the information text zones // the information text zones
wxTextCtrl *m_textPosCur, wxTextCtrl *m_textPosCur,
*m_textRowCur,
*m_textColCur,
*m_textPosLast, *m_textPosLast,
*m_textSelFrom, *m_textSelFrom,
*m_textSelTo; *m_textSelTo;
@@ -244,30 +231,10 @@ BEGIN_EVENT_TABLE(TextTestFrame, wxFrame)
EVT_BUTTON(TextTest_Add, TextTestFrame::OnButtonAdd) EVT_BUTTON(TextTest_Add, TextTestFrame::OnButtonAdd)
EVT_BUTTON(TextTest_Insert, TextTestFrame::OnButtonInsert) EVT_BUTTON(TextTest_Insert, TextTestFrame::OnButtonInsert)
#if 0
EVT_BUTTON(TextTest_Change, TextTestFrame::OnButtonChange)
EVT_BUTTON(TextTest_Delete, TextTestFrame::OnButtonDelete)
EVT_BUTTON(TextTest_DeleteSel, TextTestFrame::OnButtonDeleteSel)
EVT_BUTTON(TextTest_AddSeveral, TextTestFrame::OnButtonAddSeveral)
EVT_BUTTON(TextTest_AddMany, TextTestFrame::OnButtonAddMany)
EVT_TEXT_ENTER(TextTest_AddText, TextTestFrame::OnButtonAdd)
EVT_TEXT_ENTER(TextTest_DeleteText, TextTestFrame::OnButtonDelete)
#endif // 0
EVT_UPDATE_UI(TextTest_Clear, TextTestFrame::OnUpdateUIClearButton) EVT_UPDATE_UI(TextTest_Clear, TextTestFrame::OnUpdateUIClearButton)
#if 0
EVT_UPDATE_UI(TextTest_AddSeveral, TextTestFrame::OnUpdateUIAddSeveral)
EVT_UPDATE_UI(TextTest_DeleteText, TextTestFrame::OnUpdateUIClearButton)
EVT_UPDATE_UI(TextTest_Delete, TextTestFrame::OnUpdateUIDeleteButton)
EVT_UPDATE_UI(TextTest_Change, TextTestFrame::OnUpdateUIDeleteSelButton)
EVT_UPDATE_UI(TextTest_ChangeText, TextTestFrame::OnUpdateUIDeleteSelButton)
EVT_UPDATE_UI(TextTest_DeleteSel, TextTestFrame::OnUpdateUIDeleteSelButton)
#endif // 0
EVT_UPDATE_UI(TextTest_Password, TextTestFrame::OnUpdateUIPasswordCheckbox) EVT_UPDATE_UI(TextTest_Password, TextTestFrame::OnUpdateUIPasswordCheckbox)
EVT_UPDATE_UI(TextTest_HScroll, TextTestFrame::OnUpdateUIHScrollCheckbox) EVT_UPDATE_UI(TextTest_WrapLines, TextTestFrame::OnUpdateUIWrapLinesCheckbox)
EVT_UPDATE_UI(TextTest_Reset, TextTestFrame::OnUpdateUIResetButton) EVT_UPDATE_UI(TextTest_Reset, TextTestFrame::OnUpdateUIResetButton)
@@ -308,12 +275,14 @@ TextTestFrame::TextTestFrame(const wxString& title)
m_radioTextLines = (wxRadioBox *)NULL; m_radioTextLines = (wxRadioBox *)NULL;
m_chkPassword = m_chkPassword =
m_chkHScroll = m_chkWrapLines =
m_chkReadonly = (wxCheckBox *)NULL; m_chkReadonly = (wxCheckBox *)NULL;
m_text = m_text =
m_textLog = m_textLog =
m_textPosCur = m_textPosCur =
m_textRowCur =
m_textColCur =
m_textPosLast = m_textPosLast =
m_textSelFrom = m_textSelFrom =
m_textSelTo = (wxTextCtrl *)NULL; m_textSelTo = (wxTextCtrl *)NULL;
@@ -352,7 +321,7 @@ TextTestFrame::TextTestFrame(const wxString& title)
1, wxRA_SPECIFY_COLS); 1, wxRA_SPECIFY_COLS);
m_chkPassword = new wxCheckBox(m_panel, TextTest_Password, _T("&Password control")); m_chkPassword = new wxCheckBox(m_panel, TextTest_Password, _T("&Password control"));
m_chkHScroll = new wxCheckBox(m_panel, TextTest_HScroll, _T("&Horz scrollbar")); m_chkWrapLines = new wxCheckBox(m_panel, TextTest_WrapLines, _T("&Horz scrollbar"));
m_chkReadonly = new wxCheckBox(m_panel, -1, _T("&Read-only mode")); m_chkReadonly = new wxCheckBox(m_panel, -1, _T("&Read-only mode"));
sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL); sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL);
@@ -360,7 +329,7 @@ TextTestFrame::TextTestFrame(const wxString& title)
sizerLeft->Add(m_radioTextLines, 0, wxGROW | wxALL, 5); sizerLeft->Add(m_radioTextLines, 0, wxGROW | wxALL, 5);
sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer
sizerLeft->Add(m_chkPassword, 0, wxLEFT | wxRIGHT, 5); sizerLeft->Add(m_chkPassword, 0, wxLEFT | wxRIGHT, 5);
sizerLeft->Add(m_chkHScroll, 0, wxLEFT | wxRIGHT, 5); sizerLeft->Add(m_chkWrapLines, 0, wxLEFT | wxRIGHT, 5);
sizerLeft->Add(m_chkReadonly, 0, wxLEFT | wxRIGHT, 5); sizerLeft->Add(m_chkReadonly, 0, wxLEFT | wxRIGHT, 5);
wxButton *btn = new wxButton(m_panel, TextTest_Reset, _T("&Reset")); wxButton *btn = new wxButton(m_panel, TextTest_Reset, _T("&Reset"));
@@ -379,44 +348,32 @@ TextTestFrame::TextTestFrame(const wxString& title)
btn = new wxButton(m_panel, TextTest_Clear, _T("&Clear")); btn = new wxButton(m_panel, TextTest_Clear, _T("&Clear"));
sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5); sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
#if 0
btn = new wxButton(m_panel, TextTest_AddSeveral, _T("&Insert a few strings"));
sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
btn = new wxButton(m_panel, TextTest_AddMany, _T("Add &many strings"));
sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
sizerRow = new wxBoxSizer(wxHORIZONTAL);
btn = new wxButton(m_panel, TextTest_Change, _T("C&hange current"));
m_textChange = new wxTextCtrl(m_panel, TextTest_ChangeText, _T(""));
sizerRow->Add(btn, 0, wxRIGHT, 5);
sizerRow->Add(m_textChange, 1, wxLEFT, 5);
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
sizerRow = new wxBoxSizer(wxHORIZONTAL);
btn = new wxButton(m_panel, TextTest_Delete, _T("&Delete this item"));
m_textDelete = new wxTextCtrl(m_panel, TextTest_DeleteText, _T(""));
sizerRow->Add(btn, 0, wxRIGHT, 5);
sizerRow->Add(m_textDelete, 1, wxLEFT, 5);
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
btn = new wxButton(m_panel, TextTest_DeleteSel, _T("Delete &selection"));
sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
#endif // 0
wxStaticBox *box4 = new wxStaticBox(m_panel, -1, _T("&Info:")); wxStaticBox *box4 = new wxStaticBox(m_panel, -1, _T("&Info:"));
wxSizer *sizerMiddleDown = new wxStaticBoxSizer(box4, wxVERTICAL); wxSizer *sizerMiddleDown = new wxStaticBoxSizer(box4, wxVERTICAL);
m_textPosCur = CreateInfoText(); m_textPosCur = CreateInfoText();
sizerMiddleDown->Add m_textRowCur = CreateInfoText();
m_textColCur = CreateInfoText();
wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
sizerRow->Add(CreateTextWithLabelSizer
( (
CreateTextWithLabelSizer _T("Current pos:"),
(
_T("Current position:"),
m_textPosCur m_textPosCur
), ),
0, wxALL | wxGROW, 5 0, wxRIGHT | wxGROW, 5);
); sizerRow->Add(CreateTextWithLabelSizer
(
_T("Col:"),
m_textColCur
),
0, wxRIGHT | wxLEFT | wxGROW, 5);
sizerRow->Add(CreateTextWithLabelSizer
(
_T("Row:"),
m_textRowCur
),
0, wxLEFT | wxGROW, 5);
sizerMiddleDown->Add(sizerRow, 0, wxALL | wxGROW, 5);
m_textPosLast = CreateInfoText(); m_textPosLast = CreateInfoText();
sizerMiddleDown->Add sizerMiddleDown->Add
@@ -449,9 +406,15 @@ TextTestFrame::TextTestFrame(const wxString& title)
// right pane // right pane
wxStaticBox *box3 = new wxStaticBox(m_panel, -1, _T("&Text:")); wxStaticBox *box3 = new wxStaticBox(m_panel, -1, _T("&Text:"));
m_sizerText = new wxStaticBoxSizer(box3, wxHORIZONTAL); m_sizerText = new wxStaticBoxSizer(box3, wxHORIZONTAL);
m_text = new wxTextCtrl(m_panel, TextTest_Textctrl, _T("Hello, world!")); Reset();
m_sizerText->Add(m_text, 1, wxALL | wxALIGN_CENTRE_VERTICAL, 5); CreateText();
m_sizerText->SetMinSize(250, 300); m_sizerText->SetMinSize(250,
#ifdef __WXGTK__
300
#else
0
#endif
);
// the 3 panes panes compose the upper part of the window // the 3 panes panes compose the upper part of the window
sizerUp->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10); sizerUp->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
@@ -487,9 +450,6 @@ TextTestFrame::TextTestFrame(const wxString& title)
sizerTop->Add(0, 5, 0, wxGROW); // spacer in between sizerTop->Add(0, 5, 0, wxGROW); // spacer in between
sizerTop->Add(sizerDown, 0, wxGROW | (wxALL & ~wxTOP), 10); sizerTop->Add(sizerDown, 0, wxGROW | (wxALL & ~wxTOP), 10);
// final initialization
Reset();
m_panel->SetAutoLayout(TRUE); m_panel->SetAutoLayout(TRUE);
m_panel->SetSizer(sizerTop); m_panel->SetSizer(sizerTop);
@@ -551,10 +511,10 @@ wxSizer *TextTestFrame::CreateTextWithLabelSizer(const wxString& label,
void TextTestFrame::Reset() void TextTestFrame::Reset()
{ {
m_radioTextLines->SetSelection(TextLines_Single); m_radioTextLines->SetSelection(DEFAULTS.textLines);
m_chkPassword->SetValue(FALSE); m_chkPassword->SetValue(DEFAULTS.password);
m_chkHScroll->SetValue(TRUE); m_chkWrapLines->SetValue(DEFAULTS.wraplines);
m_chkReadonly->SetValue(FALSE); m_chkReadonly->SetValue(DEFAULTS.readonly);
} }
void TextTestFrame::CreateText() void TextTestFrame::CreateText()
@@ -578,7 +538,7 @@ void TextTestFrame::CreateText()
flags |= wxTE_PASSWORD; flags |= wxTE_PASSWORD;
if ( m_chkReadonly->GetValue() ) if ( m_chkReadonly->GetValue() )
flags |= wxTE_READONLY; flags |= wxTE_READONLY;
if ( m_chkHScroll->GetValue() ) if ( !m_chkWrapLines->GetValue() )
flags |= wxHSCROLL; flags |= wxHSCROLL;
wxString valueOld; wxString valueOld;
@@ -589,6 +549,10 @@ void TextTestFrame::CreateText()
m_sizerText->Remove(m_text); m_sizerText->Remove(m_text);
delete m_text; delete m_text;
} }
else
{
valueOld = _T("Hello, Universe!");
}
m_text = new wxTextCtrl(m_panel, TextTest_Textctrl, m_text = new wxTextCtrl(m_panel, TextTest_Textctrl,
valueOld, valueOld,
@@ -614,7 +578,15 @@ void TextTestFrame::OnIdle(wxIdleEvent& WXUNUSED(event))
if ( posCur != m_posCur ) if ( posCur != m_posCur )
{ {
m_textPosCur->Clear(); m_textPosCur->Clear();
m_textRowCur->Clear();
m_textColCur->Clear();
long col, row;
m_text->PositionToXY(posCur, &col, &row);
*m_textPosCur << posCur; *m_textPosCur << posCur;
*m_textRowCur << row;
*m_textColCur << col;
m_posCur = posCur; m_posCur = posCur;
} }
@@ -689,98 +661,12 @@ void TextTestFrame::OnButtonClear(wxCommandEvent& WXUNUSED(event))
m_text->SetFocus(); m_text->SetFocus();
} }
#if 0
void TextTestFrame::OnButtonChange(wxCommandEvent& WXUNUSED(event))
{
wxArrayInt selections;
int count = m_text->GetSelections(selections);
wxString s = m_textChange->GetValue();
for ( int n = 0; n < count; n++ )
{
m_text->SetString(selections[n], s);
}
}
void TextTestFrame::OnButtonDelete(wxCommandEvent& WXUNUSED(event))
{
unsigned long n;
if ( !m_textDelete->GetValue().ToULong(&n) ||
(n >= (unsigned)m_text->GetCount()) )
{
return;
}
m_text->Delete(n);
}
void TextTestFrame::OnButtonDeleteSel(wxCommandEvent& WXUNUSED(event))
{
wxArrayInt selections;
int n = m_text->GetSelections(selections);
while ( n > 0 )
{
m_text->Delete(selections[--n]);
}
}
void TextTestFrame::OnButtonAdd(wxCommandEvent& event)
{
static size_t s_item = 0;
wxString s = m_textAdd->GetValue();
if ( !m_textAdd->IsModified() )
{
// update the default string
m_textAdd->SetValue(wxString::Format(_T("test item %u"), ++s_item));
}
m_text->Append(s);
}
void TextTestFrame::OnButtonAddMany(wxCommandEvent& WXUNUSED(event))
{
// "many" means 1000 here
for ( size_t n = 0; n < 1000; n++ )
{
m_text->Append(wxString::Format(_T("item #%u"), n));
}
}
void TextTestFrame::OnButtonAddSeveral(wxCommandEvent& event)
{
wxArrayString items;
items.Add(_T("First"));
items.Add(_T("another one"));
items.Add(_T("and the last (very very very very very very very very very very long) one"));
m_text->InsertItems(items, 0);
}
void TextTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent& event)
{
unsigned long n;
event.Enable(m_textDelete->GetValue().ToULong(&n) &&
(n < (unsigned)m_text->GetCount()));
}
void TextTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent& event)
{
wxArrayInt selections;
event.Enable(m_text->GetSelections(selections) != 0);
}
void TextTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent& event)
{
event.Enable(!(m_text->GetWindowStyle() & wxLB_SORT));
}
#endif // 0
void TextTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent& event) void TextTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent& event)
{ {
event.Enable(!m_text->GetValue().empty()); event.Enable(!m_text->GetValue().empty());
} }
void TextTestFrame::OnUpdateUIHScrollCheckbox(wxUpdateUIEvent& event) void TextTestFrame::OnUpdateUIWrapLinesCheckbox(wxUpdateUIEvent& event)
{ {
event.Enable( !IsSingleLine() ); event.Enable( !IsSingleLine() );
} }
@@ -793,14 +679,24 @@ void TextTestFrame::OnUpdateUIPasswordCheckbox(wxUpdateUIEvent& event)
void TextTestFrame::OnUpdateUIResetButton(wxUpdateUIEvent& event) void TextTestFrame::OnUpdateUIResetButton(wxUpdateUIEvent& event)
{ {
event.Enable( (m_radioTextLines->GetSelection() != TextLines_Single) || event.Enable( (m_radioTextLines->GetSelection() != DEFAULTS.textLines) ||
m_chkReadonly->GetValue() || (m_chkReadonly->GetValue() != DEFAULTS.readonly) ||
m_chkPassword->GetValue() || (m_chkPassword->GetValue() != DEFAULTS.password) ||
!m_chkHScroll->GetValue() ); (m_chkWrapLines->GetValue() != DEFAULTS.wraplines) );
} }
void TextTestFrame::OnText(wxCommandEvent& event) void TextTestFrame::OnText(wxCommandEvent& event)
{ {
// small hack to suppress the very first message: by then the logging is
// not yet redirected and so initial setting of the text value results in
// an annoying message box
static bool s_firstTime = TRUE;
if ( s_firstTime )
{
s_firstTime = FALSE;
return;
}
wxLogMessage(_T("Text ctrl value changed")); wxLogMessage(_T("Text ctrl value changed"));
} }

View File

@@ -60,20 +60,23 @@
The same example for a control with line wrap assuming "Universe" is too The same example for a control with line wrap assuming "Universe" is too
long to fit on the same line with "Hello,": long to fit on the same line with "Hello,":
pos: 0 1 2 3 4 5 6 pos: 0 1 2 3 4 5
H e l l o , line 0 (row 0) H e l l o , line 0 (row 0)
col: 0 1 2 3 4 5 col: 0 1 2 3 4 5
1 1 1 1 1 1 1 1 1 1 1 1 1 1
pos: 7 8 9 0 1 2 3 4 5 6 pos: 6 7 8 9 0 1 2 3 4 5 6
U n i v e r s e ! line 0 (row 1) U n i v e r s e ! line 0 (row 1)
col: 6 7 8 9 1 1 1 1 1 col: 6 7 8 9 1 1 1 1 1 1
0 1 2 3 4 0 1 2 3 4 5
(line 1 == row 2 same as above) (line 1 == row 2 same as above)
Note that now columns are offset relative to positions as the positions 6 Note that there is still the same number of columns and positions and that
and 7 correspond to the same character. there is no (logical) position at the end of the first ROW. This position
is identified with the preceding one (which is not how Windows does it: it
identifies it with the next one, i.e. the first position of the next line,
but much more logical IMHO).
*/ */
// ============================================================================ // ============================================================================
@@ -1862,6 +1865,25 @@ wxRect wxTextCtrl::GetRealTextArea() const
return rectText; return rectText;
} }
size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text,
wxCoord width) const
{
wxTextCtrl *self = wxConstCast(this, wxTextCtrl);
wxClientDC dc(self);
dc.SetFont(GetFont());
self->DoPrepareDC(dc);
// the text which we can keep in this ROW
wxString str;
for ( wxCoord w = 0; w < width; )
{
str += *text++;
dc.GetTextExtent(str, &w, NULL);
}
return str.length();
}
wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
wxCoord x, wxCoord x,
long *colOut) const long *colOut) const
@@ -2018,46 +2040,13 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pos,
// calculate the row // calculate the row
int row; int row;
if ( IsSingleLine() ) size_t ofsLineStart = 0; // used only for WrapLines() case
{
// there is only one row anyhow
row = 0;
}
else // multi line
{
int rowMax = GetNumberOfLines() - 1;
int hLine = GetCharHeight(); int hLine = GetCharHeight();
int rowMax = GetNumberOfLines() - 1;
if ( WrapLines() ) if ( IsSingleLine() || !WrapLines() )
{ {
// one line can take several rows in this case, so we need to // in this case row calculation is simple as all lines have the
// rescan the text
// OPT: as for horz hit testing we might approximate the result
// with y / hLine first and then scan from there, this is
// probably much more efficient when there is a lot of text
int yCur = 0;
wxCoord wLine = m_rectText.w;
for ( row = 0; (yCur < y) && (row <= rowMax); row++ )
{
wxCoord widthLineTotal = GetTextWidth(GetLineText(row));
int nRowsPerLine = widthLineTotal == 0
? 1
: (widthLineTotal + wLine - 1) / wLine;
yCur += nRowsPerLine*hLine;
}
if ( row > rowMax )
{
row = rowMax;
res = wxTE_HT_AFTER;
}
}
else // no line wrap
{
// in this case row calculation is simple as we all lines have the
// same height // same height
row = y / hLine; row = y / hLine;
if ( row > rowMax ) if ( row > rowMax )
@@ -2077,15 +2066,72 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pos,
res = wxTE_HT_BEFORE; res = wxTE_HT_BEFORE;
} }
} }
else // multline control with line wrap
{
// one line can take several rows in this case, so we need to
// rescan the text
// OPT: as for horz hit testing we might approximate the result
// with y / hLine first and then scan from there, this is
// probably much more efficient when there is a lot of text
wxString textLine;
row = 0;
int nRowInLine = 0,
nRowsPerLine = 0;
wxCoord wLine = m_rectText.width;
for ( int yCur = 0; yCur < y; yCur += hLine )
{
if ( nRowInLine == nRowsPerLine )
{
// pass to the next line
row++;
if ( row > rowMax )
{
// no next line
row = rowMax;
res = wxTE_HT_AFTER;
break;
}
textLine = GetLineText(row);
wxCoord widthLineTotal = GetTextWidth(textLine);
nRowsPerLine = widthLineTotal == 0
? 1
: (widthLineTotal + wLine - 1) / wLine;
// the offset of the start of the ROW in which y is from the
// start of this LINE
ofsLineStart = 0;
}
else
{
// pass to the next row in this line
ofsLineStart += GetPartOfWrappedLine
(
textLine.c_str() + ofsLineStart,
wLine
);
nRowInLine++;
}
}
} }
if ( res == wxTE_HT_ON_TEXT ) if ( res == wxTE_HT_ON_TEXT )
{ {
// now find the position in the line // now find the position in the line
wxString line = GetLineText(row); wxString line;
if ( ofsLineStart ) if ( ofsLineStart )
{ {
// // look in this row only, not in whole line (well, we leave the
// tail unchanged, but it shouldn't hurt)
line = GetLineText(row).c_str() + ofsLineStart;
}
else
{
// just take the whole string
line = GetLineText(row);
} }
res = HitTestLine(GetTextToShow(line), x, colOut); res = HitTestLine(GetTextToShow(line), x, colOut);
@@ -2116,6 +2162,44 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pos,
return res; return res;
} }
// TODO: implement HitTest() via HitTest2(), not the other way round!
wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y,
wxCoord x1,
wxCoord x2,
long *row,
long *colStart,
long *colEnd,
wxCoord *ofsStart) const
{
wxTextCtrlHitTestResult htr = HitTest(wxPoint(x1, y), colStart, row);
if ( htr == wxTE_HT_AFTER )
{
// if the start is after the text, the end is too
return wxTE_HT_AFTER;
}
if ( colEnd )
{
(void)HitTest(wxPoint(x2, y), colEnd, NULL);
}
if ( ofsStart )
{
long colStartRow;
(void)HitTest(wxPoint(GetRealTextArea().x + GetClientAreaOrigin().x, y),
&colStartRow, NULL);
wxASSERT_MSG( colStartRow <= *colStart, _T("are they on same line?") );
wxString s = GetLineText(*row);
*ofsStart = GetTextWidth(s.Mid((size_t)colStartRow,
(size_t)(*colStart - colStartRow)));
}
return htr;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// scrolling // scrolling
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -2371,7 +2455,7 @@ void wxTextCtrl::UpdateScrollbars()
// is our width enough to show the longest line? // is our width enough to show the longest line?
wxCoord charWidth, maxWidth; wxCoord charWidth, maxWidth;
bool showScrollbarX; bool showScrollbarX;
if ( GetWindowStyle() && wxHSCROLL ) if ( !WrapLines() )
{ {
charWidth = GetCharWidth(); charWidth = GetCharWidth();
maxWidth = GetMaxWidth(); maxWidth = GetMaxWidth();
@@ -2636,39 +2720,49 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
} }
#endif // WXDEBUG_TEXT #endif // WXDEBUG_TEXT
// calculate the range of lines to refresh // calculate the range lineStart..lineEnd of lines to redraw
wxPoint pt1 = rectUpdate.GetPosition(); wxPoint pt = rectUpdate.GetPosition();
long colStart, lineStart; long lineStart;
(void)HitTest(pt1, &colStart, &lineStart); (void)HitTest(pt, NULL, &lineStart);
wxPoint pt2 = pt1; pt.y += rectUpdate.height;
pt2.x += rectUpdate.width; long lineEnd;
pt2.y += rectUpdate.height; (void)HitTest(pt, NULL, &lineEnd);
long colEnd, lineEnd;
(void)HitTest(pt2, &colEnd, &lineEnd);
// pt1 and pt2 will run along the left and right update rect borders
// respectively from top to bottom (NB: they're in device coords)
pt2.y = pt1.y;
// prepare for drawing // prepare for drawing
wxCoord hLine = GetCharHeight();
wxRect rectText; wxRect rectText;
rectText.height = GetCharHeight(); rectText.height = hLine;
rectText.y = m_rectText.y + lineStart*rectText.height; rectText.y = m_rectText.y + lineStart*rectText.height;
// do draw the invalidated parts of each line // 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;
// do draw the invalidated parts of each line: note that we iterate here
// over ROWs, not over LINEs
for ( long line = lineStart; for ( long line = lineStart;
line <= lineEnd; line <= lineEnd;
line++, rectText.y += hLine,
rectText.y += rectText.height, y += hLine )
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 ) long colStart, colEnd;
wxCoord ofsStart;
if ( HitTest2(y, x1, x2,
&line, &colStart, &colEnd, &ofsStart) == wxTE_HT_AFTER )
{ {
wxASSERT_MSG( line <= lineEnd, _T("how did we get that far?") );
if ( line == lineEnd )
{
// we redrew everything
break;
}
// the update rect is beyond the end of line, no need to redraw // the update rect is beyond the end of line, no need to redraw
// anything // anything on this line - but continue with the remaining ones
continue; continue;
} }
@@ -2676,8 +2770,6 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
if ( colStart < m_colStart ) if ( colStart < m_colStart )
colStart = m_colStart; colStart = m_colStart;
(void)HitTest(pt2, &colEnd, NULL);
// colEnd may be less than colStart if colStart was changed by the // colEnd may be less than colStart if colStart was changed by the
// assignment above // assignment above
if ( colEnd < colStart ) if ( colEnd < colStart )
@@ -2735,7 +2827,7 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate)
} }
// calculate the logical text coords // calculate the logical text coords
rectText.x = m_rectText.x + GetTextWidth(textLine.Left(colStart)); rectText.x = m_rectText.x + ofsStart;
rectText.width = GetTextWidth(text); rectText.width = GetTextWidth(text);
// do draw the text // do draw the text

View File

@@ -701,7 +701,7 @@ wxColour wxWin32ColourScheme::GetBackground(wxWindow *win) const
wxTextCtrl *text = wxDynamicCast(win, wxTextCtrl); wxTextCtrl *text = wxDynamicCast(win, wxTextCtrl);
if ( text ) if ( text )
{ {
if ( !text->IsEditable() ) if ( !text->IsEnabled() ) // not IsEditable()
col = Get(CONTROL); col = Get(CONTROL);
//else: execute code below //else: execute code below
} }
@@ -1736,7 +1736,7 @@ wxRect wxWin32Renderer::GetTextTotalArea(const wxTextCtrl *text,
{ {
// this is what Windows does // this is what Windows does
wxRect rectTotal = rect; wxRect rectTotal = rect;
rectTotal.Inflate(10); rectTotal.Inflate(1);
rectTotal.height++; rectTotal.height++;
return rectTotal; return rectTotal;
@@ -1748,7 +1748,7 @@ wxRect wxWin32Renderer::GetTextClientArea(const wxTextCtrl *text,
// undo GetTextTotalArea() // undo GetTextTotalArea()
wxRect rectText = rect; wxRect rectText = rect;
rectText.height--; rectText.height--;
rectText.Inflate(-10); rectText.Inflate(-1);
return rectText; return rectText;
} }