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:
5
TODO
5
TODO
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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_
|
||||
|
||||
|
@@ -20,11 +20,6 @@
|
||||
|
||||
#include "wx/defs.h"
|
||||
|
||||
#if !wxUSE_FILE
|
||||
#undef wxUSE_TEXTFILE
|
||||
#define wxUSE_TEXTFILE 0
|
||||
#endif // wxUSE_FILE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@@ -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
|
||||
|
@@ -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());
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user