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; 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_DYNAMIC_CLASS( wxGrid )
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
DECLARE_NO_COPY_CLASS(wxGrid) DECLARE_NO_COPY_CLASS(wxGrid)

View File

@ -208,6 +208,17 @@ protected:
// in wxScrollHelperEvtHandler::ProcessEvent() // in wxScrollHelperEvtHandler::ProcessEvent()
void ResetDrawnFlag(); 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_scaleX;
double m_scaleY; double m_scaleY;
@ -237,6 +248,19 @@ protected:
wxScrollHelperEvtHandler *m_handler; 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) DECLARE_NO_COPY_CLASS(wxScrollHelper)
}; };

View File

@ -4698,6 +4698,15 @@ void wxGrid::CalcDimensions()
CalcWindowSizes(); CalcWindowSizes();
} }
wxSize wxGrid::GetSizeAvailableForScrollTarget(const wxSize& size)
{
wxSize sizeGridWin(size);
sizeGridWin.x -= m_rowLabelWidth;
sizeGridWin.y -= m_colLabelHeight;
return sizeGridWin;
}
void wxGrid::CalcWindowSizes() void wxGrid::CalcWindowSizes()
{ {
// escape if the window is has not been fully created yet // escape if the window is has not been fully created yet
@ -4708,33 +4717,6 @@ void wxGrid::CalcWindowSizes()
int cw, ch; int cw, ch;
GetClientSize( &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 // 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 // size the windows to negative sizes in this case
int gw = cw - m_rowLabelWidth; int gw = cw - m_rowLabelWidth;

View File

@ -644,7 +644,61 @@ int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event)
return nScrollInc; 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() void wxScrollHelper::AdjustScrollbars()
{ {
static wxRecursionGuardFlag s_flagReentrancy; static wxRecursionGuardFlag s_flagReentrancy;
@ -660,137 +714,62 @@ void wxScrollHelper::AdjustScrollbars()
return; return;
} }
int w = 0, h = 0;
int oldw, oldh;
int oldXScroll = m_xScrollPosition; int oldXScroll = m_xScrollPosition;
int oldYScroll = m_yScrollPosition; int oldYScroll = m_yScrollPosition;
// VZ: at least under Windows this loop is useless because when scrollbars // we may need to readjust the scrollbars several times as enabling one of
// [dis]appear we get a WM_SIZE resulting in another call to // them reduces the area available for the window contents and so can make
// AdjustScrollbars() anyhow. As it doesn't seem to do any harm I leave // the other scrollbar necessary now although it wasn't necessary before
// it here for now but it would be better to ensure that all ports //
// generate EVT_SIZE when scrollbars [dis]appear, emulating it if // VZ: normally this loop should be over in at most 2 iterations, I don't
// necessary, and remove it later // know why do we need 5 of them
// JACS: Stop potential infinite loop by limiting number of iterations for ( int iterationCount = 0; iterationCount < 5; iterationCount++ )
int iterationCount = 0;
const int iterationMax = 5;
do
{ {
iterationCount ++; wxSize clientSize = GetTargetSize();
const wxSize virtSize = m_targetWindow->GetVirtualSize();
GetTargetSize(&w, 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
// scroll lines per page: if 0, no scrolling is needed // full contents without the scrollbars, but its client size could be
int linesPerPage; // 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
if ( m_xScrollPixelsPerLine == 0 ) //
// 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 if ( availSize.x >= virtSize.x && availSize.y >= virtSize.y )
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)
{ {
// we're big enough to not need scrolling // this will be enough to make the scrollbars disappear below
linesPerPage = // and then the client size will indeed become equal to the
m_xScrollLines = // full available size
m_xScrollPosition = 0; clientSize = availSize;
}
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;
} }
} }
m_win->SetScrollbar(wxHORIZONTAL, m_xScrollPosition,
linesPerPage, m_xScrollLines);
// The amount by which we scroll when paging AdjustScrollbar(wxHORIZONTAL,
SetScrollPageSize(wxHORIZONTAL, linesPerPage); clientSize.x,
virtSize.x,
m_xScrollPixelsPerLine,
m_xScrollLines,
m_xScrollPosition);
GetTargetSize(0, &h); AdjustScrollbar(wxVERTICAL,
clientSize.y,
if ( m_yScrollPixelsPerLine == 0 ) virtSize.y,
{ m_yScrollPixelsPerLine,
// scrolling is disabled m_yScrollLines,
m_yScrollLines = 0; m_yScrollPosition);
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);
// If a scrollbar (dis)appeared as a result of this, adjust them again. // If a scrollbar (dis)appeared as a result of this, we need to adjust
oldw = w; // them again but if the client size didn't change, then we're done
oldh = h; if ( GetTargetSize() == clientSize )
break;
GetTargetSize( &w, &h ); }
} while ( (w != oldw || h != oldh) && (iterationCount < iterationMax) );
#ifdef __WXMOTIF__ #ifdef __WXMOTIF__
// Sorry, some Motif-specific code to implement a backing pixmap // Sorry, some Motif-specific code to implement a backing pixmap
@ -849,7 +828,7 @@ void wxScrollHelper::DoPrepareDC(wxDC& dc)
wxPoint pt = dc.GetDeviceOrigin(); wxPoint pt = dc.GetDeviceOrigin();
#ifdef __WXGTK__ #ifdef __WXGTK__
// It may actually be correct to always query // 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. // #ifdef GTK for now.
if (m_win->GetLayoutDirection() == wxLayout_RightToLeft) if (m_win->GetLayoutDirection() == wxLayout_RightToLeft)
dc.SetDeviceOrigin( pt.x + m_xScrollPosition * m_xScrollPixelsPerLine, dc.SetDeviceOrigin( pt.x + m_xScrollPosition * m_xScrollPixelsPerLine,