vert textctrl scrolling starts to work after tons of fixes to wxTextCtrl and

wxScrolledWindow (to better respect target window rect)


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8663 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-10-31 01:56:42 +00:00
parent f6c8b8f53d
commit 99eb9f350e
12 changed files with 145 additions and 42 deletions

1
TODO
View File

@@ -12,6 +12,7 @@ wxTextCtrl
? text ctrl display pb when text is truncated ? text ctrl display pb when text is truncated
* too much is refreshed when double clicking (word select) * too much is refreshed when double clicking (word select)
! update rect overlaps with horz scrollbar
!! own ScrollWindow() for horz scrolling as we must always scroll by char! !! own ScrollWindow() for horz scrolling as we must always scroll by char!
All All

View File

@@ -100,6 +100,22 @@ protected:
return m_rectToScroll.width != 0 ? &m_rectToScroll : NULL; return m_rectToScroll.width != 0 ? &m_rectToScroll : NULL;
} }
// get the size of the target window
wxSize GetTargetSize() const
{
return m_rectToScroll.width != 0 ? m_rectToScroll.GetSize()
: m_targetWindow->GetClientSize();
}
void GetTargetSize(int *w, int *h)
{
wxSize size = GetTargetSize();
if ( w )
*w = size.x;
if ( h )
*h = size.y;
}
wxWindow *m_win, wxWindow *m_win,
*m_targetWindow; *m_targetWindow;

View File

@@ -98,6 +98,7 @@ protected:
void OnKeyDown(wxKeyEvent& event); void OnKeyDown(wxKeyEvent& event);
void OnKeyUp(wxKeyEvent& event); void OnKeyUp(wxKeyEvent& event);
void OnFocus(wxFocusEvent& event); void OnFocus(wxFocusEvent& event);
void OnActivate(wxActivateEvent& event);
private: private:
// common part of all ctors // common part of all ctors

View File

@@ -71,6 +71,11 @@ public:
// return TRUE to refresh the control, FALSE otherwise // return TRUE to refresh the control, FALSE otherwise
virtual bool HandleFocus(wxControl *control, const wxFocusEvent& event); virtual bool HandleFocus(wxControl *control, const wxFocusEvent& event);
// react to the app getting/losing activation
//
// return TRUE to refresh the control, FALSE otherwise
virtual bool HandleActivation(wxControl *control, bool activated);
// virtual dtor for any base class // virtual dtor for any base class
virtual ~wxInputHandler(); virtual ~wxInputHandler();
}; };
@@ -124,6 +129,7 @@ public:
const wxMouseEvent& event); const wxMouseEvent& event);
virtual bool HandleMouseMove(wxControl *control, const wxMouseEvent& event); virtual bool HandleMouseMove(wxControl *control, const wxMouseEvent& event);
virtual bool HandleFocus(wxControl *control, const wxFocusEvent& event); virtual bool HandleFocus(wxControl *control, const wxFocusEvent& event);
virtual bool HandleActivation(wxControl *control, bool activated);
private: private:
// the window (button) which has capture or NULL and the flag telling if // the window (button) which has capture or NULL and the flag telling if

View File

@@ -260,6 +260,14 @@ protected:
// get the logical text width (accounting for scrolling) // get the logical text width (accounting for scrolling)
wxCoord GetTotalWidth() const; wxCoord GetTotalWidth() const;
// the text area is the part of the window in which the text can be
// displayed, i.e. part of it inside the margins and the real text area is
// the area in which the text *is* currently displayed: for example, in the
// multiline control case the text area can have extra space at the bottom
// which is not tall enough for another line and which is then not included
// into the real text area
wxRect GetRealTextArea() const;
// refresh the text in the given (in logical coords) rect // refresh the text in the given (in logical coords) rect
void RefreshTextRect(wxRect& rect); void RefreshTextRect(wxRect& rect);

View File

@@ -393,8 +393,10 @@ MyUnivFrame::MyUnivFrame(const wxString& title)
sizeText.x = 200; sizeText.x = 200;
text->SetSize(sizeText); 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), wxDefaultSize, "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n",
wxPoint(10, 30),
wxSize(-1, 150),
wxTE_MULTILINE); wxTE_MULTILINE);
#endif #endif
text->SetFocus(); text->SetFocus();

View File

@@ -141,7 +141,12 @@ void wxAppBase::SetActive(bool active, wxWindow *lastFocus)
} }
if ( s_lastFocus ) if ( s_lastFocus )
s_lastFocus->Refresh(); {
// give the focused window the chance to refresh itself if its
// appearance depends on the app activation state
wxActivateEvent event(wxEVT_ACTIVATE, active);
s_lastFocus->GetEventHandler()->ProcessEvent(event);
}
} }
#endif // wxUSE_GUI #endif // wxUSE_GUI

View File

@@ -220,7 +220,7 @@ void wxScrollHelper::SetScrollbars(int pixelsPerUnitX,
AdjustScrollbars(); AdjustScrollbars();
if (do_refresh && !noRefresh) if (do_refresh && !noRefresh)
m_targetWindow->Refresh(); m_targetWindow->Refresh(TRUE, GetRect());
#ifdef __WXMAC__ #ifdef __WXMAC__
m_targetWindow->MacUpdateImmediately() ; m_targetWindow->MacUpdateImmediately() ;
@@ -383,7 +383,7 @@ int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
if (m_xScrollPixelsPerLine > 0) if (m_xScrollPixelsPerLine > 0)
{ {
int w, h; int w, h;
m_targetWindow->GetClientSize(&w, &h); GetTargetSize(&w, &h);
int nMaxWidth = m_xScrollLines*m_xScrollPixelsPerLine; int nMaxWidth = m_xScrollLines*m_xScrollPixelsPerLine;
int noPositions = (int) ( ((nMaxWidth - w)/(double)m_xScrollPixelsPerLine) + 0.5 ); int noPositions = (int) ( ((nMaxWidth - w)/(double)m_xScrollPixelsPerLine) + 0.5 );
@@ -396,14 +396,14 @@ int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
nScrollInc = noPositions - m_xScrollPosition; // As +ve as we can go nScrollInc = noPositions - m_xScrollPosition; // As +ve as we can go
} }
else else
m_targetWindow->Refresh(); m_targetWindow->Refresh(TRUE, GetRect());
} }
else else
{ {
if (m_yScrollPixelsPerLine > 0) if (m_yScrollPixelsPerLine > 0)
{ {
int w, h; int w, h;
m_targetWindow->GetClientSize(&w, &h); GetTargetSize(&w, &h);
int nMaxHeight = m_yScrollLines*m_yScrollPixelsPerLine; int nMaxHeight = m_yScrollLines*m_yScrollPixelsPerLine;
int noPositions = (int) ( ((nMaxHeight - h)/(double)m_yScrollPixelsPerLine) + 0.5 ); int noPositions = (int) ( ((nMaxHeight - h)/(double)m_yScrollPixelsPerLine) + 0.5 );
@@ -416,7 +416,7 @@ int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
nScrollInc = noPositions - m_yScrollPosition; // As +ve as we can go nScrollInc = noPositions - m_yScrollPosition; // As +ve as we can go
} }
else else
m_targetWindow->Refresh(); m_targetWindow->Refresh(TRUE, GetRect());
} }
return nScrollInc; return nScrollInc;
@@ -426,7 +426,7 @@ int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
void wxScrollHelper::AdjustScrollbars() void wxScrollHelper::AdjustScrollbars()
{ {
int w, h; int w, h;
m_targetWindow->GetClientSize(&w, &h); GetTargetSize(&w, &h);
int oldXScroll = m_xScrollPosition; int oldXScroll = m_xScrollPosition;
int oldYScroll = m_yScrollPosition; int oldYScroll = m_yScrollPosition;
@@ -482,17 +482,19 @@ void wxScrollHelper::AdjustScrollbars()
if (oldXScroll != m_xScrollPosition) if (oldXScroll != m_xScrollPosition)
{ {
if (m_xScrollingEnabled) if (m_xScrollingEnabled)
m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll-m_xScrollPosition), 0, (const wxRect *) NULL ); m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll-m_xScrollPosition), 0,
GetRect() );
else else
m_targetWindow->Refresh(); m_targetWindow->Refresh(TRUE, GetRect());
} }
if (oldYScroll != m_yScrollPosition) if (oldYScroll != m_yScrollPosition)
{ {
if (m_yScrollingEnabled) if (m_yScrollingEnabled)
m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition), (const wxRect *) NULL ); m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition),
GetRect() );
else else
m_targetWindow->Refresh(); m_targetWindow->Refresh(TRUE, GetRect());
} }
} }
@@ -540,7 +542,7 @@ void wxScrollHelper::Scroll( int x_pos, int y_pos )
((y_pos == -1) || (y_pos == m_yScrollPosition))) return; ((y_pos == -1) || (y_pos == m_yScrollPosition))) return;
int w, h; int w, h;
m_targetWindow->GetClientSize(&w, &h); GetTargetSize(&w, &h);
if ((x_pos != -1) && (m_xScrollPixelsPerLine)) if ((x_pos != -1) && (m_xScrollPixelsPerLine))
{ {
@@ -558,8 +560,9 @@ void wxScrollHelper::Scroll( int x_pos, int y_pos )
m_xScrollPosition = wxMax( 0, m_xScrollPosition ); m_xScrollPosition = wxMax( 0, m_xScrollPosition );
if (old_x != m_xScrollPosition) { if (old_x != m_xScrollPosition) {
m_targetWindow->SetScrollPos( wxHORIZONTAL, m_xScrollPosition, TRUE ); m_targetWindow->SetScrollPos( wxHORIZONTAL, m_xScrollPosition, FALSE );
m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0 ); m_targetWindow->ScrollWindow( (old_x-m_xScrollPosition)*m_xScrollPixelsPerLine, 0,
GetRect() );
} }
} }
if ((y_pos != -1) && (m_yScrollPixelsPerLine)) if ((y_pos != -1) && (m_yScrollPixelsPerLine))
@@ -578,8 +581,9 @@ void wxScrollHelper::Scroll( int x_pos, int y_pos )
m_yScrollPosition = wxMax( 0, m_yScrollPosition ); m_yScrollPosition = wxMax( 0, m_yScrollPosition );
if (old_y != m_yScrollPosition) { if (old_y != m_yScrollPosition) {
m_targetWindow->SetScrollPos( wxVERTICAL, m_yScrollPosition, TRUE ); m_targetWindow->SetScrollPos( wxVERTICAL, m_yScrollPosition, FALSE );
m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine ); m_targetWindow->ScrollWindow( 0, (old_y-m_yScrollPosition)*m_yScrollPixelsPerLine,
GetRect() );
} }
} }
@@ -663,7 +667,7 @@ void wxScrollHelper::HandleOnChar(wxKeyEvent& event)
clix, cliy; // view size (on screen) clix, cliy; // view size (on screen)
GetViewStart(&stx, &sty); GetViewStart(&stx, &sty);
m_win->GetClientSize(&clix, &cliy); GetTargetSize(&clix, &cliy);
GetVirtualSize(&szx, &szy); GetVirtualSize(&szx, &szy);
if( m_xScrollPixelsPerLine ) if( m_xScrollPixelsPerLine )

View File

@@ -347,9 +347,16 @@ bool wxStdButtonInputHandler::HandleMouseMove(wxControl *control,
bool wxStdButtonInputHandler::HandleFocus(wxControl *control, bool wxStdButtonInputHandler::HandleFocus(wxControl *control,
const wxFocusEvent& event) const wxFocusEvent& event)
{ {
// buttons change appearance when they get/lose focus // buttons change appearance when they get/lose focus, so return TRUE to
control->Refresh(); // refresh
return TRUE;
}
bool wxStdButtonInputHandler::HandleActivation(wxControl *control,
bool activated)
{
// the default button changes appearance when the app is [de]activated, so
// return TRUE to refresh
return TRUE; return TRUE;
} }

View File

@@ -53,6 +53,8 @@ BEGIN_EVENT_TABLE(wxControl, wxControlBase)
EVT_SET_FOCUS(wxControl::OnFocus) EVT_SET_FOCUS(wxControl::OnFocus)
EVT_KILL_FOCUS(wxControl::OnFocus) EVT_KILL_FOCUS(wxControl::OnFocus)
EVT_ACTIVATE(wxControl::OnActivate)
END_EVENT_TABLE() END_EVENT_TABLE()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -130,12 +132,22 @@ wxString wxControl::GetLabel() const
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// focus handling // focus/activation handling
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void wxControl::OnFocus(wxFocusEvent& event) void wxControl::OnFocus(wxFocusEvent& event)
{ {
if ( !m_handler || !m_handler->HandleFocus(this, event) ) if ( m_handler && m_handler->HandleFocus(this, event) )
Refresh();
else
event.Skip();
}
void wxControl::OnActivate(wxActivateEvent& event)
{
if ( m_handler && m_handler->HandleActivation(this, event.GetActive()) )
Refresh();
else
event.Skip(); event.Skip();
} }

View File

@@ -47,7 +47,14 @@ bool wxInputHandler::HandleMouseMove(wxControl * WXUNUSED(control),
return FALSE; return FALSE;
} }
bool wxInputHandler::HandleFocus(wxControl *control, const wxFocusEvent& event) bool wxInputHandler::HandleFocus(wxControl *WXUNUSED(control),
const wxFocusEvent& WXUNUSED(event))
{
return FALSE;
}
bool wxInputHandler::HandleActivation(wxControl *WXUNUSED(control),
bool WXUNUSED(activated))
{ {
return FALSE; return FALSE;
} }

View File

@@ -1113,6 +1113,7 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
} }
} }
// pos may be -1 to show the current position
void wxTextCtrl::ShowPosition(long pos) void wxTextCtrl::ShowPosition(long pos)
{ {
HideCaret(); HideCaret();
@@ -1126,22 +1127,37 @@ void wxTextCtrl::ShowPosition(long pos)
int xStart, yStart; int xStart, yStart;
GetViewStart(&xStart, &yStart); GetViewStart(&xStart, &yStart);
long row, col;
if ( (pos == -1) || (pos == m_curPos) )
{
row = m_curRow;
col = m_curCol;
}
else
{
// TODO
wxFAIL_MSG(_T("not implemented for multiline"));
return;
}
if ( m_scrollRangeY ) if ( m_scrollRangeY )
{ {
// scroll the position vertically into view: if it is currently // scroll the position vertically into view: if it is currently
// above it, make it the first one, otherwise the last one // above it, make it the first one, otherwise the last one
if ( m_curRow < yStart ) if ( row < yStart )
{ {
Scroll(0, m_curRow); Scroll(0, row);
} }
else else
{ {
int yEnd = yStart + GetClientSize().y / GetCharHeight() - 1; int yEnd = yStart +
if ( yEnd < m_curRow ) GetRealTextArea().height / GetCharHeight() - 1;
if ( yEnd < row )
{ {
// scroll down: the current item should appear at the // scroll down: the current item should appear at the
// bottom of the view // bottom of the view
Scroll(0, m_curRow - (yEnd - yStart) + 1); Scroll(0, row - (yEnd - yStart));
} }
} }
} }
@@ -1368,7 +1384,7 @@ void wxTextCtrl::UpdateTextRect()
wxRect(wxPoint(0, 0), GetClientSize())); wxRect(wxPoint(0, 0), GetClientSize()));
// only scroll this rect when the window is scrolled // only scroll this rect when the window is scrolled
SetTargetRect(m_rectText); SetTargetRect(GetRealTextArea());
UpdateLastVisible(); UpdateLastVisible();
} }
@@ -1435,6 +1451,16 @@ wxCoord wxTextCtrl::GetTextWidth(const wxString& text) const
return w; return w;
} }
wxRect wxTextCtrl::GetRealTextArea() const
{
// the real text area always holds an entire number of lines, so the only
// difference with the text area is a narrow strip along the bottom border
wxRect rectText = m_rectText;
int hLine = GetCharHeight();
rectText.height = (m_rectText.height / hLine) * hLine;
return rectText;
}
wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line, wxTextCtrlHitTestResult wxTextCtrl::HitTestLine(const wxString& line,
wxCoord x, wxCoord x,
long *colOut) const long *colOut) const
@@ -1590,7 +1616,7 @@ wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pos,
// row calculation is simple as we assume that all lines have the same // row calculation is simple as we assume that all lines have the same
// height // height
int row = y / GetCharHeight(); int row = (y - 1) / GetCharHeight();
int rowMax = GetNumberOfLines() - 1; int rowMax = GetNumberOfLines() - 1;
if ( row > rowMax ) if ( row > rowMax )
{ {
@@ -1839,7 +1865,7 @@ wxCoord wxTextCtrl::GetMaxWidth() const
void wxTextCtrl::UpdateScrollbars() void wxTextCtrl::UpdateScrollbars()
{ {
wxSize size = GetClientSize(); wxSize size = GetRealTextArea().GetSize();
// is our height enough to show all items? // is our height enough to show all items?
int nLines = GetNumberOfLines(); int nLines = GetNumberOfLines();
@@ -1879,6 +1905,9 @@ void wxTextCtrl::UpdateScrollbars()
m_scrollRangeX = scrollRangeX; m_scrollRangeX = scrollRangeX;
m_scrollRangeY = scrollRangeY; m_scrollRangeY = scrollRangeY;
// bring the current position in view
ShowPosition(-1);
} }
} }
@@ -2005,6 +2034,10 @@ void wxTextCtrl::RefreshTextRect(wxRect& rect)
// account for horz scrolling // account for horz scrolling
rect.x -= m_ofsHorz; rect.x -= m_ofsHorz;
} }
else // multiline
{
CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
}
// account for the text area offset // account for the text area offset
rect.Offset(m_rectText.GetPosition()); rect.Offset(m_rectText.GetPosition());
@@ -2224,23 +2257,24 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer)
// the update region is in window coord and text area is in the client // the update region is in window coord and text area is in the client
// ones, so it must be shifted before computing intesection // ones, so it must be shifted before computing intesection
wxRegion rgnUpdate = GetUpdateRegion(); wxRegion rgnUpdate = GetUpdateRegion();
wxRect rectTextArea = m_rectText; wxRect rectTextArea = GetRealTextArea();
wxPoint pt = GetClientAreaOrigin(); wxPoint pt = GetClientAreaOrigin();
rectTextArea.x += pt.x; wxRect rectTextAreaAdjusted = rectTextArea;
rectTextArea.y += pt.y; rectTextAreaAdjusted.x += pt.x;
rgnUpdate.Intersect(rectTextArea); rectTextAreaAdjusted.y += pt.y;
rgnUpdate.Intersect(rectTextAreaAdjusted);
// even though the drawing is already clipped to the update region, we must // even though the drawing is already clipped to the update region, we must
// explicitly clip it to the rect we will use as otherwise parts of letters // explicitly clip it to the rect we will use as otherwise parts of letters
// might be drawn outside of it (if even a small part of a charater is // might be drawn outside of it (if even a small part of a charater is
// inside, HitTest() will return its column and DrawText() can't draw only // inside, HitTest() will return its column and DrawText() can't draw only
// the part of the character, of course) // the part of the character, of course)
dc.SetClippingRegion(m_rectText); dc.SetClippingRegion(rectTextArea);
// adjust for scrolling // adjust for scrolling
DoPrepareDC(dc); DoPrepareDC(dc);
// and now refresh thei nvalidated parts of the window // and now refresh the invalidated parts of the window
wxRegionIterator iter(rgnUpdate); wxRegionIterator iter(rgnUpdate);
for ( ; iter.HaveRects(); iter++ ) for ( ; iter.HaveRects(); iter++ )
{ {
@@ -2323,10 +2357,10 @@ void wxTextCtrl::ShowCaret(bool show)
{ {
// position it correctly (taking scrolling into account) // position it correctly (taking scrolling into account)
wxCoord xCaret, yCaret; wxCoord xCaret, yCaret;
CalcUnscrolledPosition(m_rectText.x + GetCaretPosition() - m_ofsHorz, CalcScrolledPosition(m_rectText.x + GetCaretPosition() - m_ofsHorz,
m_rectText.y + m_curRow*GetCharHeight(), m_rectText.y + m_curRow*GetCharHeight(),
&xCaret, &xCaret,
&yCaret); &yCaret);
caret->Move(xCaret, yCaret); caret->Move(xCaret, yCaret);
// and show it there // and show it there