diff --git a/TODO b/TODO index cfe400382d..fdae84eaf7 100644 --- a/TODO +++ b/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 diff --git a/include/wx/chkconf.h b/include/wx/chkconf.h index 80aca90026..f6390a5231 100644 --- a/include/wx/chkconf.h +++ b/include/wx/chkconf.h @@ -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" diff --git a/include/wx/ffile.h b/include/wx/ffile.h index 969aa40039..4c48810ea5 100644 --- a/include/wx/ffile.h +++ b/include/wx/ffile.h @@ -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_ diff --git a/include/wx/textfile.h b/include/wx/textfile.h index d8777bf8ef..8b5c149522 100644 --- a/include/wx/textfile.h +++ b/include/wx/textfile.h @@ -20,11 +20,6 @@ #include "wx/defs.h" -#if !wxUSE_FILE - #undef wxUSE_TEXTFILE - #define wxUSE_TEXTFILE 0 -#endif // wxUSE_FILE - // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- diff --git a/include/wx/univ/setup.h b/include/wx/univ/setup.h index a4bc7f6a57..a99c0a07e7 100644 --- a/include/wx/univ/setup.h +++ b/include/wx/univ/setup.h @@ -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 diff --git a/samples/textctrl/texttest.cpp b/samples/textctrl/texttest.cpp index c94a01e125..07006ba2c5 100644 --- a/samples/textctrl/texttest.cpp +++ b/samples/textctrl/texttest.cpp @@ -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()); diff --git a/samples/univ/univ.cpp b/samples/univ/univ.cpp index 3f6704cf29..307fe9c597 100644 --- a/samples/univ/univ.cpp +++ b/samples/univ/univ.cpp @@ -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 } diff --git a/src/common/ffile.cpp b/src/common/ffile.cpp index 4bca0e0e2e..b05b929e7c 100644 --- a/src/common/ffile.cpp +++ b/src/common/ffile.cpp @@ -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 diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp index 93dde134d8..229161f36e 100644 --- a/src/univ/textctrl.cpp +++ b/src/univ/textctrl.cpp @@ -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--; } } diff --git a/src/univ/themes/win32.cpp b/src/univ/themes/win32.cpp index 0ce93a6d33..115f97a7b5 100644 --- a/src/univ/themes/win32.cpp +++ b/src/univ/themes/win32.cpp @@ -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); +} +