diff --git a/include/wx/univ/textctrl.h b/include/wx/univ/textctrl.h index eebd2f7f9a..757cac771a 100644 --- a/include/wx/univ/textctrl.h +++ b/include/wx/univ/textctrl.h @@ -296,7 +296,14 @@ protected: // set the caret to its initial (default) position void InitInsertionPoint(); + // get the width of the longest line in pixels + wxCoord GetMaxWidth() const; + + // update the max width if the width of this line is greater than it + void UpdateMaxWidth(long line); + // event handlers + void OnIdle(wxIdleEvent& event); void OnChar(wxKeyEvent& event); void OnSize(wxSizeEvent& event); @@ -315,6 +322,9 @@ protected: } private: + // update the scrollbars (only called from OnIdle) + void UpdateScrollbars(); + // the initially specified control size wxSize m_sizeInitial; @@ -329,6 +339,9 @@ private: m_curCol, m_curRow; + // last position (only used by GetLastPosition()) + long m_posLast; + // selection long m_selAnchor, m_selStart, @@ -353,6 +366,19 @@ private: wxCoord m_posLastVisible; long m_colLastVisible; + // this section is for the controls with scrollbar(s) + + // the current ranges of the scrollbars + int m_scrollRangeX, + m_scrollRangeY; + + // should we adjust the horz/vert scrollbar? + bool m_updateScrollbarX, + m_updateScrollbarY; + + // the max line length in pixels + wxCoord m_widthMax; + DECLARE_EVENT_TABLE() DECLARE_DYNAMIC_CLASS(wxTextCtrl) }; diff --git a/samples/univ/univ.cpp b/samples/univ/univ.cpp index a6b5c54604..2c44732390 100644 --- a/samples/univ/univ.cpp +++ b/samples/univ/univ.cpp @@ -397,6 +397,7 @@ MyUnivFrame::MyUnivFrame(const wxString& title) text = new wxTextCtrl(this, -1, _T("Hello,\nMultiverse!"), wxPoint(10, 10), wxDefaultSize, wxTE_MULTILINE); + text->SetFocus(); #endif // !TEST_TEXT_ONLY/TEST_TEXT_ONLY } diff --git a/src/univ/listbox.cpp b/src/univ/listbox.cpp index f201134eb0..cf74ae7748 100644 --- a/src/univ/listbox.cpp +++ b/src/univ/listbox.cpp @@ -540,7 +540,7 @@ void wxListBox::OnIdle(wxIdleEvent& event) { UpdateScrollbars(); - m_updateScrollbarX = FALSE; + m_updateScrollbarX = m_updateScrollbarY = FALSE; } @@ -678,6 +678,10 @@ void wxListBox::OnSize(wxSizeEvent& event) // recalculate the number of items per page CalcItemsPerPage(); + // the scrollbars might [dis]appear + m_updateScrollbarX = + m_updateScrollbarY = TRUE; + event.Skip(); } diff --git a/src/univ/scrolbar.cpp b/src/univ/scrolbar.cpp index b53def2ffa..24f70bb15a 100644 --- a/src/univ/scrolbar.cpp +++ b/src/univ/scrolbar.cpp @@ -116,6 +116,9 @@ bool wxScrollBar::Create(wxWindow *parent, SetBestSize(size); + // override the cursor of the target window (if any) + SetCursor(wxCURSOR_ARROW); + return TRUE; } diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp index 32711f565d..232c292a9a 100644 --- a/src/univ/textctrl.cpp +++ b/src/univ/textctrl.cpp @@ -84,7 +84,10 @@ static inline void OrderPositions(long& from, long& to) BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) EVT_CHAR(OnChar) + EVT_SIZE(OnSize) + + EVT_IDLE(OnIdle) END_EVENT_TABLE() IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl) @@ -112,6 +115,17 @@ void wxTextCtrl::Init() m_curPos = m_curCol = m_curRow = 0; + + m_scrollRangeX = + m_scrollRangeY = 0; + + m_updateScrollbarX = + m_updateScrollbarY = FALSE; + + m_widthMax = -1; + + // init wxScrollHelper + SetWindow(this); } bool wxTextCtrl::Create(wxWindow *parent, @@ -131,10 +145,25 @@ bool wxTextCtrl::Create(wxWindow *parent, SetCursor(wxCURSOR_IBEAM); - // we should always have at least one line in a multiline control if ( style & wxTE_MULTILINE ) { + // we should always have at least one line in a multiline control m_lines.Add(wxEmptyString); + + // we might support it but it's quite useless and other ports don't + // support it anyhow + wxASSERT_MSG( !(style & wxTE_PASSWORD), + _T("wxTE_PASSWORD can't be used with multiline ctrls") ); + + // create vertical scrollbar if necessary (on by default) + if ( !(style & wxTE_NO_VSCROLL) ) + { + } + + // and the horizontal one + if ( style & wxHSCROLL ) + { + } } SetValue(value); @@ -161,6 +190,9 @@ bool wxTextCtrl::SetFont(const wxFont& font) // and refresh everything, of course InitInsertionPoint(); ClearSelection(); + + m_widthMax = -1; + Refresh(); return TRUE; @@ -523,6 +555,8 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text) { // we have the replacement line for this one m_lines[line] = lines[nReplaceLine]; + + UpdateMaxWidth(line); } else // no more replacement lines { @@ -538,6 +572,8 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text) while ( nReplaceLine < nReplaceCount ) { m_lines.Insert(lines[nReplaceLine++], ++lineEnd); + + UpdateMaxWidth(lineEnd); } // (5) now refresh the changed area @@ -554,6 +590,9 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text) // number of lines did change, we need to refresh everything below the // start line RefreshLineRange(lineStart + 1); + + // the vert scrollbar might [dis]appear + m_updateScrollbarY = TRUE; } #endif // 0/1 @@ -1043,10 +1082,37 @@ void wxTextCtrl::ShowPosition(long pos) { ShowHorzPosition(GetCaretPosition(pos)); } - else // multiline + else if ( m_scrollRangeX || m_scrollRangeY ) // multiline with scrollbars { - // TODO + int xStart, yStart; + GetViewStart(&xStart, &yStart); + + if ( m_scrollRangeY ) + { + // scroll the position vertically into view: if it is currently + // above it, make it the first one, otherwise the last one + if ( m_curRow < yStart ) + { + Scroll(0, m_curRow); + } + else + { + int yEnd = yStart + GetClientSize().y / GetCharHeight() - 1; + if ( yEnd < m_curRow ) + { + // scroll down: the current item should appear at the + // bottom of the view + Scroll(0, m_curRow - (yEnd - yStart)); + } + } + } + + if ( m_scrollRangeX ) + { + // TODO + } } + //else: multiline but no scrollbars, hence nothing to do ShowCaret(); } @@ -1306,6 +1372,9 @@ void wxTextCtrl::OnSize(wxSizeEvent& event) { UpdateTextRect(); + m_updateScrollbarX = + m_updateScrollbarY = TRUE; + event.Skip(); } @@ -1671,6 +1740,103 @@ void wxTextCtrl::DoPrepareDC(wxDC& dc) } } +void wxTextCtrl::UpdateMaxWidth(long line) +{ + wxCoord width; + GetTextExtent(GetLineText(line), &width, NULL); + + // GetMaxWidth() and not m_widthMax as it might be not calculated yet + if ( width > GetMaxWidth() ) + { + m_widthMax = width; + + m_updateScrollbarX = TRUE; + } +} + +wxCoord wxTextCtrl::GetMaxWidth() const +{ + if ( m_widthMax == -1 ) + { + // recalculate it + + // OPT: should we remember the widths of all the lines? + + wxTextCtrl *self = wxConstCast(this, wxTextCtrl); + wxClientDC dc(self); + dc.SetFont(GetFont()); + + size_t count = m_lines.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxCoord width; + dc.GetTextExtent(m_lines[n], &width, NULL); + if ( width > m_widthMax ) + { + self->m_widthMax = width; + } + } + } + + return m_widthMax; +} + +void wxTextCtrl::UpdateScrollbars() +{ + wxSize size = GetClientSize(); + + // is our height enough to show all items? + int nLines = GetNumberOfLines(); + wxCoord lineHeight = GetCharHeight(); + bool showScrollbarY = nLines*lineHeight > size.y; + + // is our width enough to show the longest line? + wxCoord charWidth, maxWidth; + bool showScrollbarX; + if ( GetWindowStyle() && wxHSCROLL ) + { + charWidth = GetCharWidth(); + maxWidth = GetMaxWidth(); + showScrollbarX = maxWidth > size.x; + } + else // never show the horz scrollbar + { + // just to suppress compiler warnings about using uninit vars below + charWidth = maxWidth = 0; + + showScrollbarX = FALSE; + } + + // calc the scrollbars ranges + int scrollRangeX = showScrollbarX + ? (maxWidth + 2*charWidth - 1) / charWidth + : 0; + int scrollRangeY = showScrollbarY ? nLines : 0; + + if ( (scrollRangeY != m_scrollRangeY) || (scrollRangeX != m_scrollRangeX) ) + { + int x, y; + GetViewStart(&x, &y); + SetScrollbars(charWidth, lineHeight, + scrollRangeX, scrollRangeY, + x, y); + + m_scrollRangeX = scrollRangeX; + m_scrollRangeY = scrollRangeY; + } +} + +void wxTextCtrl::OnIdle(wxIdleEvent& event) +{ + if ( m_updateScrollbarX || m_updateScrollbarY ) + { + UpdateScrollbars(); + + m_updateScrollbarX = + m_updateScrollbarY = FALSE; + } +} + // ---------------------------------------------------------------------------- // refresh // ---------------------------------------------------------------------------- diff --git a/src/univ/winuniv.cpp b/src/univ/winuniv.cpp index 187818198e..b0274c780a 100644 --- a/src/univ/winuniv.cpp +++ b/src/univ/winuniv.cpp @@ -85,6 +85,8 @@ bool wxWindow::Create(wxWindow *parent, long style, const wxString& name) { + // we add wxCLIP_CHILDREN and wxNO_FULL_REPAINT_ON_RESIZE because without + // these styles we can't get rid of flicker on wxMSW if ( !wxWindowNative::Create(parent, id, pos, size, style | wxCLIP_CHILDREN, name) ) {