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
*! call to RefreshLineRange() from Replace() is broken
*! display corrupted when typing text in quickly (caret problem?)
*!! display corrupted when typing text in quickly (even single line)
* 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)
* scrolling by dragging mouse outside the window
All
! wxThemeSettings

View File

@@ -115,6 +115,8 @@
# endif
#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 wxABORT_ON_CONFIG_ERROR
# error "wxUSE_DYNAMIC_CLASSES must be defined as 1"

View File

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

View File

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

View File

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

View File

@@ -67,6 +67,7 @@ enum
TextTest_Add,
TextTest_Insert,
TextTest_Clear,
TextTest_Load,
TextTest_Password,
TextTest_WrapLines,
@@ -133,6 +134,7 @@ protected:
void OnButtonInsert(wxCommandEvent& event);
void OnButtonAdd(wxCommandEvent& event);
void OnButtonClear(wxCommandEvent& event);
void OnButtonLoad(wxCommandEvent& event);
void OnButtonQuit(wxCommandEvent& event);
@@ -231,6 +233,7 @@ BEGIN_EVENT_TABLE(TextTestFrame, wxFrame)
EVT_BUTTON(TextTest_Clear, TextTestFrame::OnButtonClear)
EVT_BUTTON(TextTest_Add, TextTestFrame::OnButtonAdd)
EVT_BUTTON(TextTest_Insert, TextTestFrame::OnButtonInsert)
EVT_BUTTON(TextTest_Load, TextTestFrame::OnButtonLoad)
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 buttons which allow to add/change/delete strings to/from it.
*/
wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL),
*sizerUp = new wxBoxSizer(wxHORIZONTAL),
*sizerLeft;
// upper left pane
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_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(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"));
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"));
sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
@@ -363,20 +366,20 @@ TextTestFrame::TextTestFrame(const wxString& title)
_T("Current pos:"),
m_textPosCur
),
0, wxGROW | wxRIGHT, 5);
0, wxRIGHT, 5);
sizerRow->Add(CreateTextWithLabelSizer
(
_T("Col:"),
m_textColCur
),
0, wxGROW | wxLEFT | wxRIGHT, 5);
0, wxLEFT | wxRIGHT, 5);
sizerRow->Add(CreateTextWithLabelSizer
(
_T("Row:"),
m_textRowCur
),
0, wxGROW | wxLEFT, 5);
sizerMiddleDown->Add(sizerRow, 0, wxALL | wxGROW, 5);
0, wxLEFT, 5);
sizerMiddleDown->Add(sizerRow, 0, wxALL, 5);
m_textLineLast = CreateInfoText();
m_textPosLast = CreateInfoText();
@@ -389,7 +392,7 @@ TextTestFrame::TextTestFrame(const wxString& title)
_T("Last position:"),
m_textPosLast
),
0, wxALL | wxGROW, 5
0, wxALL, 5
);
m_textSelFrom = CreateInfoText();
@@ -403,11 +406,11 @@ TextTestFrame::TextTestFrame(const wxString& title)
_T("to"),
m_textSelTo
),
0, wxALL | wxGROW, 5
0, wxALL, 5
);
wxSizer *sizerMiddle = new wxBoxSizer(wxVERTICAL);
sizerMiddle->Add(sizerMiddleUp, 1, wxGROW, 5);
sizerMiddle->Add(sizerMiddleDown, 1, wxGROW | wxTOP, 5);
sizerMiddle->Add(sizerMiddleUp, 0, wxGROW);
sizerMiddle->Add(sizerMiddleDown, 0, wxGROW | wxTOP, 5);
// I don't understand what's going on :-(
#ifdef __WXGTK__
@@ -428,8 +431,9 @@ TextTestFrame::TextTestFrame(const wxString& title)
);
// 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(sizerMiddle, 1, wxGROW | wxALL, 10);
sizerUp->Add(sizerMiddle, 0, wxGROW | wxALL, 10);
sizerUp->Add(m_sizerText, 1, wxGROW | (wxALL & ~wxRIGHT), 10);
// 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);
// 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(sizerDown, 0, wxGROW | (wxALL & ~wxTOP), 10);
@@ -487,7 +492,7 @@ wxTextCtrl *TextTestFrame::CreateInfoText()
if ( !s_maxWidth )
{
// calc it once only
GetTextExtent(_T("99999"), &s_maxWidth, NULL);
GetTextExtent(_T("9999999"), &s_maxWidth, NULL);
}
wxTextCtrl *text = new wxTextCtrl(m_panel, -1, _T(""),
@@ -678,6 +683,21 @@ void TextTestFrame::OnButtonClear(wxCommandEvent& WXUNUSED(event))
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)
{
event.Enable(!m_text->GetValue().empty());

View File

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

View File

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

View File

@@ -23,6 +23,18 @@
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:
@@ -1828,32 +1840,59 @@ void wxTextCtrl::UpdateLastVisible()
if ( !IsSingleLine() )
return;
// OPT: estimate the correct value first, just adjust it later
wxString text;
wxCoord w, wOld;
w =
wOld = 0;
m_colLastVisible = m_colStart;
const wxChar *pc = m_value.c_str() + (size_t)m_colStart;
for ( ; *pc; pc++ )
// use (efficient) HitTestLine to find the last visible character
wxString text = m_value.Mid((size_t)m_colStart /* to the end */);
wxTextCoord col;
switch ( HitTestLine(text, m_rectText.width, &col) )
{
text += *pc;
wOld = w;
w = GetTextWidth(text);
if ( w > m_rectText.width )
{
// this char is too much
break;
}
case wxTE_HT_BEYOND:
// everything is visible
m_colLastVisible = text.length();
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"),
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
// this one is only partly visible - unless the width of the
// string is exactly the max width
wReal = GetTextWidth(s.Truncate(col));
wReal = GetTextWidth(s.Truncate(col + 1));
if ( wReal > m_rectText.width )
{
// this character is not entirely visible, take the
// previous one
col--;
// recalc the width
wReal = -1;
}
//else: we can just see it
@@ -2639,7 +2681,7 @@ void wxTextCtrl::UpdateScrollbars()
// is our height enough to show all items?
wxTextCoord nRows = GetNumberOfRowsBefore(GetNumberOfLines());
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?
wxCoord charWidth, maxWidth;
@@ -3072,12 +3114,6 @@ 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)
if ( colEnd > colStart )
colEnd--;
}
}

View File

@@ -349,6 +349,17 @@ public:
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
// ----------------------------------------------------------------------------
@@ -770,7 +781,7 @@ wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control)
else if ( control == wxINP_HANDLER_CHECKLISTBOX )
handler = new wxStdCheckListboxInputHandler(GetDefaultInputHandler());
else if ( control == wxINP_HANDLER_TEXTCTRL )
handler = new wxStdTextCtrlInputHandler(GetDefaultInputHandler());
handler = new wxWin32TextCtrlInputHandler(GetDefaultInputHandler());
else
handler = GetDefaultInputHandler();
@@ -2121,3 +2132,42 @@ bool wxWin32CheckboxInputHandler::HandleKey(wxControl *control,
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);
}