more work on wxTextCtrl: mostly works but very slow

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8841 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-11-27 01:28:52 +00:00
parent 528a112b2c
commit 10644bd0bd
10 changed files with 166 additions and 61 deletions

5
TODO
View File

@@ -14,13 +14,14 @@ samples:
wxTextCtrl wxTextCtrl
*! call to RefreshLineRange() from Replace() is broken *!! display corrupted when typing text in quickly (even single line)
*! 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 * remember selection when losing/gaining activation
* too much is refreshed when double clicking (word select) * too much is refreshed when double clicking (word select)
* scrolling by dragging mouse outside the window
All All
! wxThemeSettings ! wxThemeSettings

View File

@@ -115,6 +115,8 @@
# endif # endif
#endif /* wxUSE_RADIOBTN */ #endif /* wxUSE_RADIOBTN */
/* I wonder if we shouldn't just remove all occurrences of
wxUSE_DYNAMIC_CLASSES from the sources? */
#if !defined(wxUSE_DYNAMIC_CLASSES) || !wxUSE_DYNAMIC_CLASSES #if !defined(wxUSE_DYNAMIC_CLASSES) || !wxUSE_DYNAMIC_CLASSES
# if wxABORT_ON_CONFIG_ERROR # if wxABORT_ON_CONFIG_ERROR
# error "wxUSE_DYNAMIC_CLASSES must be defined as 1" # error "wxUSE_DYNAMIC_CLASSES must be defined as 1"

View File

@@ -16,7 +16,7 @@
#pragma interface "ffile.h" #pragma interface "ffile.h"
#endif #endif
#if wxUSE_FILE #if wxUSE_FFILE
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/string.h" #include "wx/string.h"
@@ -109,7 +109,7 @@ private:
wxString m_name; // the name of the file (for diagnostic messages) wxString m_name; // the name of the file (for diagnostic messages)
}; };
#endif // wxUSE_FILE #endif // wxUSE_FFILE
#endif // _WX_FFILE_H_ #endif // _WX_FFILE_H_

View File

@@ -20,11 +20,6 @@
#include "wx/defs.h" #include "wx/defs.h"
#if !wxUSE_FILE
#undef wxUSE_TEXTFILE
#define wxUSE_TEXTFILE 0
#endif // wxUSE_FILE
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// constants // constants
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -55,6 +55,7 @@
#define wxUSE_ZLIB 0 #define wxUSE_ZLIB 0
#define wxUSE_APPLE_IEEE 0 #define wxUSE_APPLE_IEEE 0
#define wxUSE_FILE 0 #define wxUSE_FILE 0
#define wxUSE_FFILE 1
#define wxUSE_TEXTFILE 0 #define wxUSE_TEXTFILE 0
#define wxUSE_INTL 0 #define wxUSE_INTL 0
#define wxUSE_MENUS 0 #define wxUSE_MENUS 0

View File

@@ -67,6 +67,7 @@ enum
TextTest_Add, TextTest_Add,
TextTest_Insert, TextTest_Insert,
TextTest_Clear, TextTest_Clear,
TextTest_Load,
TextTest_Password, TextTest_Password,
TextTest_WrapLines, TextTest_WrapLines,
@@ -133,6 +134,7 @@ protected:
void OnButtonInsert(wxCommandEvent& event); void OnButtonInsert(wxCommandEvent& event);
void OnButtonAdd(wxCommandEvent& event); void OnButtonAdd(wxCommandEvent& event);
void OnButtonClear(wxCommandEvent& event); void OnButtonClear(wxCommandEvent& event);
void OnButtonLoad(wxCommandEvent& event);
void OnButtonQuit(wxCommandEvent& event); void OnButtonQuit(wxCommandEvent& event);
@@ -231,6 +233,7 @@ BEGIN_EVENT_TABLE(TextTestFrame, wxFrame)
EVT_BUTTON(TextTest_Clear, TextTestFrame::OnButtonClear) EVT_BUTTON(TextTest_Clear, TextTestFrame::OnButtonClear)
EVT_BUTTON(TextTest_Add, TextTestFrame::OnButtonAdd) EVT_BUTTON(TextTest_Add, TextTestFrame::OnButtonAdd)
EVT_BUTTON(TextTest_Insert, TextTestFrame::OnButtonInsert) EVT_BUTTON(TextTest_Insert, TextTestFrame::OnButtonInsert)
EVT_BUTTON(TextTest_Load, TextTestFrame::OnButtonLoad)
EVT_UPDATE_UI(TextTest_Clear, TextTestFrame::OnUpdateUIClearButton) EVT_UPDATE_UI(TextTest_Clear, TextTestFrame::OnUpdateUIClearButton)
@@ -305,9 +308,6 @@ TextTestFrame::TextTestFrame(const wxString& title)
the pane containing the textctrl itself and the lower pane containing the pane containing the textctrl itself and the lower pane containing
the buttons which allow to add/change/delete strings to/from it. the buttons which allow to add/change/delete strings to/from it.
*/ */
wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL),
*sizerUp = new wxBoxSizer(wxHORIZONTAL),
*sizerLeft;
// upper left pane // upper left pane
static const wxString modes[] = static const wxString modes[] =
@@ -326,7 +326,7 @@ TextTestFrame::TextTestFrame(const wxString& title)
m_chkWrapLines = new wxCheckBox(m_panel, TextTest_WrapLines, _T("Line &wrap")); m_chkWrapLines = new wxCheckBox(m_panel, TextTest_WrapLines, _T("Line &wrap"));
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); wxSizer *sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL);
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
@@ -347,6 +347,9 @@ TextTestFrame::TextTestFrame(const wxString& title)
btn = new wxButton(m_panel, TextTest_Insert, _T("&Insert text")); btn = new wxButton(m_panel, TextTest_Insert, _T("&Insert text"));
sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5); sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
btn = new wxButton(m_panel, TextTest_Load, _T("&Load file"));
sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
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);
@@ -363,20 +366,20 @@ TextTestFrame::TextTestFrame(const wxString& title)
_T("Current pos:"), _T("Current pos:"),
m_textPosCur m_textPosCur
), ),
0, wxGROW | wxRIGHT, 5); 0, wxRIGHT, 5);
sizerRow->Add(CreateTextWithLabelSizer sizerRow->Add(CreateTextWithLabelSizer
( (
_T("Col:"), _T("Col:"),
m_textColCur m_textColCur
), ),
0, wxGROW | wxLEFT | wxRIGHT, 5); 0, wxLEFT | wxRIGHT, 5);
sizerRow->Add(CreateTextWithLabelSizer sizerRow->Add(CreateTextWithLabelSizer
( (
_T("Row:"), _T("Row:"),
m_textRowCur m_textRowCur
), ),
0, wxGROW | wxLEFT, 5); 0, wxLEFT, 5);
sizerMiddleDown->Add(sizerRow, 0, wxALL | wxGROW, 5); sizerMiddleDown->Add(sizerRow, 0, wxALL, 5);
m_textLineLast = CreateInfoText(); m_textLineLast = CreateInfoText();
m_textPosLast = CreateInfoText(); m_textPosLast = CreateInfoText();
@@ -389,7 +392,7 @@ TextTestFrame::TextTestFrame(const wxString& title)
_T("Last position:"), _T("Last position:"),
m_textPosLast m_textPosLast
), ),
0, wxALL | wxGROW, 5 0, wxALL, 5
); );
m_textSelFrom = CreateInfoText(); m_textSelFrom = CreateInfoText();
@@ -403,11 +406,11 @@ TextTestFrame::TextTestFrame(const wxString& title)
_T("to"), _T("to"),
m_textSelTo m_textSelTo
), ),
0, wxALL | wxGROW, 5 0, wxALL, 5
); );
wxSizer *sizerMiddle = new wxBoxSizer(wxVERTICAL); wxSizer *sizerMiddle = new wxBoxSizer(wxVERTICAL);
sizerMiddle->Add(sizerMiddleUp, 1, wxGROW, 5); sizerMiddle->Add(sizerMiddleUp, 0, wxGROW);
sizerMiddle->Add(sizerMiddleDown, 1, wxGROW | wxTOP, 5); sizerMiddle->Add(sizerMiddleDown, 0, wxGROW | wxTOP, 5);
// I don't understand what's going on :-( // I don't understand what's going on :-(
#ifdef __WXGTK__ #ifdef __WXGTK__
@@ -428,8 +431,9 @@ TextTestFrame::TextTestFrame(const wxString& title)
); );
// the 3 panes panes compose the upper part of the window // the 3 panes panes compose the upper part of the window
wxSizer *sizerUp = new wxBoxSizer(wxHORIZONTAL);
sizerUp->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10); sizerUp->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
sizerUp->Add(sizerMiddle, 1, wxGROW | wxALL, 10); sizerUp->Add(sizerMiddle, 0, wxGROW | wxALL, 10);
sizerUp->Add(m_sizerText, 1, wxGROW | (wxALL & ~wxRIGHT), 10); sizerUp->Add(m_sizerText, 1, wxGROW | (wxALL & ~wxRIGHT), 10);
// the lower one only has the log textctrl and a button to clear it // the lower one only has the log textctrl and a button to clear it
@@ -457,7 +461,8 @@ TextTestFrame::TextTestFrame(const wxString& title)
sizerDown->Add(sizerBtns, 0, wxALL | wxALIGN_RIGHT, 5); sizerDown->Add(sizerBtns, 0, wxALL | wxALIGN_RIGHT, 5);
// put everything together // put everything together
sizerTop->Add(sizerUp, 1, wxGROW | (wxALL & ~(wxTOP | wxBOTTOM)), 10); wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
sizerTop->Add(sizerUp, 1, wxGROW | wxRIGHT | wxLEFT, 10);
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);
@@ -487,7 +492,7 @@ wxTextCtrl *TextTestFrame::CreateInfoText()
if ( !s_maxWidth ) if ( !s_maxWidth )
{ {
// calc it once only // calc it once only
GetTextExtent(_T("99999"), &s_maxWidth, NULL); GetTextExtent(_T("9999999"), &s_maxWidth, NULL);
} }
wxTextCtrl *text = new wxTextCtrl(m_panel, -1, _T(""), wxTextCtrl *text = new wxTextCtrl(m_panel, -1, _T(""),
@@ -678,6 +683,21 @@ void TextTestFrame::OnButtonClear(wxCommandEvent& WXUNUSED(event))
m_text->SetFocus(); m_text->SetFocus();
} }
void TextTestFrame::OnButtonLoad(wxCommandEvent& WXUNUSED(event))
{
// search for the file in several dirs where it's likely to be
wxPathList pathlist;
pathlist.Add(_T("."));
pathlist.Add(_T(".."));
pathlist.Add(_T("../../../samples/texttest"));
wxString filename = pathlist.FindValidPath(_T("texttest.cpp"));
if ( !filename )
wxLogError(_T("File texttest.cpp not found."));
else if ( !m_text->LoadFile(filename) )
wxLogError(_T("Error loading file."));
}
void TextTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent& event) void TextTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent& event)
{ {
event.Enable(!m_text->GetValue().empty()); event.Enable(!m_text->GetValue().empty());

View File

@@ -386,12 +386,9 @@ MyUnivFrame::MyUnivFrame(const wxString& title)
new wxTextCtrl(this, -1, _T("Hello, Universe!"), new wxTextCtrl(this, -1, _T("Hello, Universe!"),
wxPoint(550, 150), wxDefaultSize); wxPoint(550, 150), wxDefaultSize);
#else // TEST_TEXT_ONLY #else // TEST_TEXT_ONLY
#if 0 #if 1
wxTextCtrl *text = new wxTextCtrl(this, -1, _T("Hello, Universe!"), wxTextCtrl *text = new wxTextCtrl(this, -1, _T("Hello, Universe!"),
wxPoint(10, 40)); wxPoint(10, 40));
wxSize sizeText = text->GetBestSize();
sizeText.x = 200;
text->SetSize(sizeText);
#else #else
wxTextCtrl *text = new wxTextCtrl(this, -1, _T("Hello,\nMultiverse!"), wxTextCtrl *text = new wxTextCtrl(this, -1, _T("Hello,\nMultiverse!"),
wxPoint(10, 30), wxPoint(10, 30),
@@ -410,6 +407,9 @@ MyUnivFrame::MyUnivFrame(const wxString& title)
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
text->SetFocus(); text->SetFocus();
//text->SetEditable(FALSE); //text->SetEditable(FALSE);
wxSize sizeText = text->GetBestSize();
sizeText.x = 200;
text->SetSize(sizeText);
#endif // !TEST_TEXT_ONLY/TEST_TEXT_ONLY #endif // !TEST_TEXT_ONLY/TEST_TEXT_ONLY
} }

View File

@@ -28,7 +28,7 @@
#pragma hdrstop #pragma hdrstop
#endif #endif
#if wxUSE_FILE #if wxUSE_FFILE
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/intl.h" #include "wx/intl.h"
@@ -258,4 +258,4 @@ size_t wxFFile::Length() const
return (size_t)-1; return (size_t)-1;
} }
#endif // wxUSE_FILE #endif // wxUSE_FFILE

View File

@@ -23,6 +23,18 @@
with lots of text with lots of text
*/ */
/*
Optimisation hints from PureQuantify:
1. wxStringTokenize is the slowest part of Replace
2. GetDC/ReleaseDC are very slow, avoid calling them several times
3. GetCharHeight() should be cached too
4. wxClientDC construction/destruction in HitTestLine is horribly expensive
For line wrapping controls HitTest2 takes 50% of program time. The results
of GetRowsPerLine and GetPartOfWrappedLine *MUST* be cached.
*/
/* /*
Some terminology: Some terminology:
@@ -1828,32 +1840,59 @@ void wxTextCtrl::UpdateLastVisible()
if ( !IsSingleLine() ) if ( !IsSingleLine() )
return; return;
// OPT: estimate the correct value first, just adjust it later // use (efficient) HitTestLine to find the last visible character
wxString text = m_value.Mid((size_t)m_colStart /* to the end */);
wxString text; wxTextCoord col;
wxCoord w, wOld; switch ( HitTestLine(text, m_rectText.width, &col) )
w =
wOld = 0;
m_colLastVisible = m_colStart;
const wxChar *pc = m_value.c_str() + (size_t)m_colStart;
for ( ; *pc; pc++ )
{ {
text += *pc; case wxTE_HT_BEYOND:
wOld = w; // everything is visible
w = GetTextWidth(text); m_colLastVisible = text.length();
if ( w > m_rectText.width )
{
// this char is too much
break;
}
m_colLastVisible++; // calc it below
m_posLastVisible = -1;
break;
/*
case wxTE_HT_BEFORE:
case wxTE_HT_BELOW:
*/
default:
wxFAIL_MSG(_T("unexpected HitTestLine() return value"));
// fall through
case wxTE_HT_ON_TEXT:
if ( col > 0 )
{
// the last entirely seen character is the previous one because
// this one is only partly visible - unless the width of the
// string is exactly the max width
m_posLastVisible = GetTextWidth(text.Truncate(col + 1));
if ( m_posLastVisible > m_rectText.width )
{
// this character is not entirely visible, take the
// previous one
col--;
// recalc it
m_posLastVisible = -1;
}
//else: we can just see it
m_colLastVisible = col;
}
break;
} }
m_posLastVisible = wOld; // calculate the width of the text really shown
if ( m_posLastVisible == -1 )
{
m_posLastVisible = GetTextWidth(text.Truncate(m_colLastVisible + 1));
}
// current value is relative the start of the string text which starts at
// m_colStart, we need an absolute offset into string
m_colLastVisible += m_colStart;
wxLogTrace(_T("text"), _T("Last visible column/position is %d/%ld"), wxLogTrace(_T("text"), _T("Last visible column/position is %d/%ld"),
m_colLastVisible, m_posLastVisible); m_colLastVisible, m_posLastVisible);
@@ -1918,12 +1957,15 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text,
// the last entirely seen character is the previous one because // the last entirely seen character is the previous one because
// this one is only partly visible - unless the width of the // this one is only partly visible - unless the width of the
// string is exactly the max width // string is exactly the max width
wReal = GetTextWidth(s.Truncate(col)); wReal = GetTextWidth(s.Truncate(col + 1));
if ( wReal > m_rectText.width ) if ( wReal > m_rectText.width )
{ {
// this character is not entirely visible, take the // this character is not entirely visible, take the
// previous one // previous one
col--; col--;
// recalc the width
wReal = -1;
} }
//else: we can just see it //else: we can just see it
@@ -2639,7 +2681,7 @@ void wxTextCtrl::UpdateScrollbars()
// is our height enough to show all items? // is our height enough to show all items?
wxTextCoord nRows = GetNumberOfRowsBefore(GetNumberOfLines()); wxTextCoord nRows = GetNumberOfRowsBefore(GetNumberOfLines());
wxCoord lineHeight = GetCharHeight(); wxCoord lineHeight = GetCharHeight();
bool showScrollbarY = nRows*lineHeight > size.y; bool showScrollbarY = !IsSingleLine() && nRows*lineHeight > size.y;
// is our width enough to show the longest line? // is our width enough to show the longest line?
wxCoord charWidth, maxWidth; wxCoord charWidth, maxWidth;
@@ -3072,12 +3114,6 @@ 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 partially in single line mode (in multi line we can't
// avoid showing parts of characters anyhow)
if ( colEnd > colStart )
colEnd--;
} }
} }

View File

@@ -349,6 +349,17 @@ public:
bool pressed); bool pressed);
}; };
class wxWin32TextCtrlInputHandler : public wxStdTextCtrlInputHandler
{
public:
wxWin32TextCtrlInputHandler(wxInputHandler *handler)
: wxStdTextCtrlInputHandler(handler) { }
virtual bool HandleKey(wxControl *control,
const wxKeyEvent& event,
bool pressed);
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxWin32ColourScheme: uses (default) Win32 colours // wxWin32ColourScheme: uses (default) Win32 colours
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -770,7 +781,7 @@ wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control)
else if ( control == wxINP_HANDLER_CHECKLISTBOX ) else if ( control == wxINP_HANDLER_CHECKLISTBOX )
handler = new wxStdCheckListboxInputHandler(GetDefaultInputHandler()); handler = new wxStdCheckListboxInputHandler(GetDefaultInputHandler());
else if ( control == wxINP_HANDLER_TEXTCTRL ) else if ( control == wxINP_HANDLER_TEXTCTRL )
handler = new wxStdTextCtrlInputHandler(GetDefaultInputHandler()); handler = new wxWin32TextCtrlInputHandler(GetDefaultInputHandler());
else else
handler = GetDefaultInputHandler(); handler = GetDefaultInputHandler();
@@ -2121,3 +2132,42 @@ bool wxWin32CheckboxInputHandler::HandleKey(wxControl *control,
return FALSE; return FALSE;
} }
// ----------------------------------------------------------------------------
// wxWin32TextCtrlInputHandler
// ----------------------------------------------------------------------------
bool wxWin32TextCtrlInputHandler::HandleKey(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
// handle only MSW-specific text bindings here, the others are handled in
// the base class
if ( pressed )
{
int keycode = event.GetKeyCode();
wxControlAction action;
if ( keycode == WXK_DELETE && event.ShiftDown() )
{
action = wxACTION_TEXT_CUT;
}
else if ( keycode == WXK_INSERT )
{
if ( event.ControlDown() )
action = wxACTION_TEXT_COPY;
else if ( event.ShiftDown() )
action = wxACTION_TEXT_PASTE;
}
if ( action != wxACTION_NONE )
{
control->PerformAction(action);
return TRUE;
}
}
return wxStdTextCtrlInputHandler::HandleKey(control, event, pressed);
}