move the grid-specific workaround for scrollbar hysteresis to wxScrollHelper itself, the scrollbars now should not only appear but also disappear correctly during resizing

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55627 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2008-09-14 22:44:08 +00:00
parent 801a964104
commit 69367c566e
4 changed files with 135 additions and 146 deletions

View File

@ -2036,6 +2036,10 @@ protected:
friend class WXDLLIMPEXP_FWD_ADV wxGridSelection;
private:
// implement wxScrolledWindow method to return m_gridWin size
virtual wxSize GetSizeAvailableForScrollTarget(const wxSize& size);
DECLARE_DYNAMIC_CLASS( wxGrid )
DECLARE_EVENT_TABLE()
DECLARE_NO_COPY_CLASS(wxGrid)

View File

@ -208,6 +208,17 @@ protected:
// in wxScrollHelperEvtHandler::ProcessEvent()
void ResetDrawnFlag();
// helper of AdjustScrollbars(): does the work for the single scrollbar
//
// notice that the parameters passed by non-const references are modified
// by this function
void AdjustScrollbar(int orient,
int clientSize,
int virtSize,
int& pixelsPerUnit,
int& scrollUnits,
int& scrollPosition);
double m_scaleX;
double m_scaleY;
@ -237,6 +248,19 @@ protected:
wxScrollHelperEvtHandler *m_handler;
private:
// this function should be overridden to return the size available for
// m_targetWindow inside m_win of the given size
//
// the default implementation is only good for m_targetWindow == m_win
// case, if we're scrolling a subwindow you must override this method
virtual wxSize GetSizeAvailableForScrollTarget(const wxSize& size)
{
wxASSERT_MSG( m_targetWindow == m_win, "must be overridden" );
return size;
}
DECLARE_NO_COPY_CLASS(wxScrollHelper)
};

View File

@ -4698,6 +4698,15 @@ void wxGrid::CalcDimensions()
CalcWindowSizes();
}
wxSize wxGrid::GetSizeAvailableForScrollTarget(const wxSize& size)
{
wxSize sizeGridWin(size);
sizeGridWin.x -= m_rowLabelWidth;
sizeGridWin.y -= m_colLabelHeight;
return sizeGridWin;
}
void wxGrid::CalcWindowSizes()
{
// escape if the window is has not been fully created yet
@ -4708,33 +4717,6 @@ void wxGrid::CalcWindowSizes()
int cw, ch;
GetClientSize( &cw, &ch );
// this block of code tries to work around the following problem: the grid
// could have been just resized to have enough space to show the full grid
// window contents without the scrollbars, but its client size could be
// not big enough because the grid has the scrollbars right now and so the
// scrollbars would remain even though we don't need them any more
//
// to prevent this from happening, check if we have enough space for
// everything without the scrollbars and explicitly disable them then
wxSize size = GetSize() - GetWindowBorderSize();
if ( size != wxSize(cw, ch) )
{
// check if we have enough space for grid window after accounting for
// the fixed size elements
size.x -= m_rowLabelWidth;
size.y -= m_colLabelHeight;
const wxSize vsize = m_gridWin->GetVirtualSize();
if ( size.x >= vsize.x && size.y >= vsize.y )
{
// yes, we do, so remove the scrollbars and use the new client size
// (which should be the same as full window size - borders now)
SetScrollbars(0, 0, 0, 0);
GetClientSize(&cw, &ch);
}
}
// the grid may be too small to have enough space for the labels yet, don't
// size the windows to negative sizes in this case
int gw = cw - m_rowLabelWidth;

View File

@ -644,7 +644,61 @@ int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
return nScrollInc;
}
// Adjust the scrollbars - new version.
void
wxScrollHelper::AdjustScrollbar(int orient,
int clientSize,
int virtSize,
int& pixelsPerUnit,
int& scrollUnits,
int& scrollPosition)
{
// scroll lines per page: if 0, no scrolling is needed
int unitsPerPage;
// check if we need scrollbar in this direction at all
if ( pixelsPerUnit == 0 || clientSize >= virtSize )
{
// scrolling is disabled or unnecessary
scrollUnits =
scrollPosition = 0;
unitsPerPage = 0;
}
else // might need scrolling
{
// Round up integer division to catch any "leftover" client space.
scrollUnits = (virtSize + pixelsPerUnit - 1) / pixelsPerUnit;
// Calculate the number of fully scroll units
unitsPerPage = clientSize / pixelsPerUnit;
if (unitsPerPage >= scrollUnits)
{
// we're big enough to not need scrolling
scrollUnits =
scrollPosition = 0;
unitsPerPage = 0;
}
else // we do need a scrollbar
{
if ( unitsPerPage < 1 )
unitsPerPage = 1;
// Correct position if greater than extent of canvas minus
// the visible portion of it or if below zero
const int posMax = scrollUnits - unitsPerPage;
if ( scrollPosition > posMax )
scrollPosition = posMax;
else if ( scrollPosition < 0 )
scrollPosition = 0;
}
}
m_win->SetScrollbar(orient, scrollPosition, unitsPerPage, scrollUnits);
// The amount by which we scroll when paging
SetScrollPageSize(orient, unitsPerPage);
}
void wxScrollHelper::AdjustScrollbars()
{
static wxRecursionGuardFlag s_flagReentrancy;
@ -660,137 +714,62 @@ void wxScrollHelper::AdjustScrollbars()
return;
}
int w = 0, h = 0;
int oldw, oldh;
int oldXScroll = m_xScrollPosition;
int oldYScroll = m_yScrollPosition;
// VZ: at least under Windows this loop is useless because when scrollbars
// [dis]appear we get a WM_SIZE resulting in another call to
// AdjustScrollbars() anyhow. As it doesn't seem to do any harm I leave
// it here for now but it would be better to ensure that all ports
// generate EVT_SIZE when scrollbars [dis]appear, emulating it if
// necessary, and remove it later
// JACS: Stop potential infinite loop by limiting number of iterations
int iterationCount = 0;
const int iterationMax = 5;
do
// we may need to readjust the scrollbars several times as enabling one of
// them reduces the area available for the window contents and so can make
// the other scrollbar necessary now although it wasn't necessary before
//
// VZ: normally this loop should be over in at most 2 iterations, I don't
// know why do we need 5 of them
for ( int iterationCount = 0; iterationCount < 5; iterationCount++ )
{
iterationCount ++;
wxSize clientSize = GetTargetSize();
const wxSize virtSize = m_targetWindow->GetVirtualSize();
GetTargetSize(&w, 0);
// scroll lines per page: if 0, no scrolling is needed
int linesPerPage;
if ( m_xScrollPixelsPerLine == 0 )
// this block of code tries to work around the following problem: the
// window could have been just resized to have enough space to show its
// full contents without the scrollbars, but its client size could be
// not big enough because it does have the scrollbars right now and so
// the scrollbars would remain even though we don't need them any more
//
// to prevent this from happening, check if we have enough space for
// everything without the scrollbars and explicitly disable them then
const wxSize availSize = GetSizeAvailableForScrollTarget(
m_win->GetSize() - m_win->GetWindowBorderSize());
if ( availSize != clientSize )
{
// scrolling is disabled
m_xScrollLines = 0;
m_xScrollPosition = 0;
linesPerPage = 0;
}
else // might need scrolling
{
// Round up integer division to catch any "leftover" client space.
const int wVirt = m_targetWindow->GetVirtualSize().GetWidth();
m_xScrollLines = (wVirt + m_xScrollPixelsPerLine - 1) / m_xScrollPixelsPerLine;
// Calculate page size i.e. number of scroll units you get on the
// current client window.
linesPerPage = w / m_xScrollPixelsPerLine;
// Special case. When client and virtual size are very close but
// the client is big enough, kill scrollbar.
if ((linesPerPage < m_xScrollLines) && (w >= wVirt)) ++linesPerPage;
if (linesPerPage >= m_xScrollLines)
if ( availSize.x >= virtSize.x && availSize.y >= virtSize.y )
{
// we're big enough to not need scrolling
linesPerPage =
m_xScrollLines =
m_xScrollPosition = 0;
}
else // we do need a scrollbar
{
if ( linesPerPage < 1 )
linesPerPage = 1;
// Correct position if greater than extent of canvas minus
// the visible portion of it or if below zero
const int posMax = m_xScrollLines - linesPerPage;
if ( m_xScrollPosition > posMax )
m_xScrollPosition = posMax;
else if ( m_xScrollPosition < 0 )
m_xScrollPosition = 0;
// this will be enough to make the scrollbars disappear below
// and then the client size will indeed become equal to the
// full available size
clientSize = availSize;
}
}
m_win->SetScrollbar(wxHORIZONTAL, m_xScrollPosition,
linesPerPage, m_xScrollLines);
// The amount by which we scroll when paging
SetScrollPageSize(wxHORIZONTAL, linesPerPage);
AdjustScrollbar(wxHORIZONTAL,
clientSize.x,
virtSize.x,
m_xScrollPixelsPerLine,
m_xScrollLines,
m_xScrollPosition);
GetTargetSize(0, &h);
if ( m_yScrollPixelsPerLine == 0 )
{
// scrolling is disabled
m_yScrollLines = 0;
m_yScrollPosition = 0;
linesPerPage = 0;
}
else // might need scrolling
{
// Round up integer division to catch any "leftover" client space.
const int hVirt = m_targetWindow->GetVirtualSize().GetHeight();
m_yScrollLines = ( hVirt + m_yScrollPixelsPerLine - 1 ) / m_yScrollPixelsPerLine;
// Calculate page size i.e. number of scroll units you get on the
// current client window.
linesPerPage = h / m_yScrollPixelsPerLine;
// Special case. When client and virtual size are very close but
// the client is big enough, kill scrollbar.
if ((linesPerPage < m_yScrollLines) && (h >= hVirt)) ++linesPerPage;
if (linesPerPage >= m_yScrollLines)
{
// we're big enough to not need scrolling
linesPerPage =
m_yScrollLines =
m_yScrollPosition = 0;
}
else // we do need a scrollbar
{
if ( linesPerPage < 1 )
linesPerPage = 1;
// Correct position if greater than extent of canvas minus
// the visible portion of it or if below zero
const int posMax = m_yScrollLines - linesPerPage;
if ( m_yScrollPosition > posMax )
m_yScrollPosition = posMax;
else if ( m_yScrollPosition < 0 )
m_yScrollPosition = 0;
}
}
m_win->SetScrollbar(wxVERTICAL, m_yScrollPosition,
linesPerPage, m_yScrollLines);
// The amount by which we scroll when paging
SetScrollPageSize(wxVERTICAL, linesPerPage);
AdjustScrollbar(wxVERTICAL,
clientSize.y,
virtSize.y,
m_yScrollPixelsPerLine,
m_yScrollLines,
m_yScrollPosition);
// If a scrollbar (dis)appeared as a result of this, adjust them again.
oldw = w;
oldh = h;
GetTargetSize( &w, &h );
} while ( (w != oldw || h != oldh) && (iterationCount < iterationMax) );
// If a scrollbar (dis)appeared as a result of this, we need to adjust
// them again but if the client size didn't change, then we're done
if ( GetTargetSize() == clientSize )
break;
}
#ifdef __WXMOTIF__
// Sorry, some Motif-specific code to implement a backing pixmap
@ -849,7 +828,7 @@ void wxScrollHelper::DoPrepareDC(wxDC& dc)
wxPoint pt = dc.GetDeviceOrigin();
#ifdef __WXGTK__
// It may actually be correct to always query
// the m_sign from the DC here, but I leve the
// the m_sign from the DC here, but I leave the
// #ifdef GTK for now.
if (m_win->GetLayoutDirection() == wxLayout_RightToLeft)
dc.SetDeviceOrigin( pt.x + m_xScrollPosition * m_xScrollPixelsPerLine,