bool m_hasDrawnWindow;
- DECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler)
+ wxDECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler);
};
#if wxUSE_TIMER
int m_pos,
m_orient;
- DECLARE_NO_COPY_CLASS(wxAutoScrollTimer)
+ wxDECLARE_NO_COPY_CLASS(wxAutoScrollTimer);
};
// ============================================================================
{
// and then send a pseudo mouse-move event to refresh the selection
wxMouseEvent event2(wxEVT_MOTION);
- wxGetMousePosition(&event2.m_x, &event2.m_y);
+ event2.SetPosition(wxGetMousePosition());
// the mouse event coordinates should be client, not screen as
// returned by wxGetMousePosition
// user code defined OnPaint() in the derived class)
m_hasDrawnWindow = true;
- // pass it on to the real handler
- bool processed = wxEvtHandler::ProcessEvent(event);
+ // Pass it on to the real handler: notice that we must not call
+ // ProcessEvent() on this object itself as it wouldn't pass it to the next
+ // handler (i.e. the real window) if we're called from a previous handler
+ // (as indicated by "process here only" flag being set) and we do want to
+ // execute the handler defined in the window we're associated with right
+ // now, without waiting until TryAfter() is called from wxEvtHandler.
+ bool processed = m_nextHandler->ProcessEvent(event);
// always process the size events ourselves, even if the user code handles
// them as well, as we need to AdjustScrollbars()
}
}
- if ( processed )
- event.Skip(wasSkipped);
+ event.Skip(wasSkipped);
+
+ // We called ProcessEvent() on the next handler, meaning that we explicitly
+ // worked around the request to process the event in this handler only. As
+ // explained above, this is unfortunately really necessary but the trouble
+ // is that the event will continue to be post-processed by the previous
+ // handler resulting in duplicate calls to event handlers. Call the special
+ // function below to prevent this from happening, base class DoTryChain()
+ // will check for it and behave accordingly.
+ //
+ // And if we're not called from DoTryChain(), this won't do anything anyhow.
+ event.DidntHonourProcessOnlyIn();
return processed;
}
wxScrollHelperBase::wxScrollHelperBase(wxWindow *win)
{
- wxASSERT_MSG( win, _T("associated window can't be NULL in wxScrollHelper") );
+ wxASSERT_MSG( win, wxT("associated window can't be NULL in wxScrollHelper") );
m_xScrollPixelsPerLine =
m_yScrollPixelsPerLine =
m_xScrollingEnabled =
m_yScrollingEnabled = true;
+ m_kbdScrollingEnabled = true;
+
m_scaleX =
m_scaleY = 1.0;
#if wxUSE_MOUSEWHEEL
int yPos,
bool noRefresh)
{
- int xpos, ypos;
+ // Convert positions expressed in scroll units to positions in pixels.
+ int xPosInPixels = (xPos + m_xScrollPosition)*m_xScrollPixelsPerLine,
+ yPosInPixels = (yPos + m_yScrollPosition)*m_yScrollPixelsPerLine;
- CalcUnscrolledPosition(xPos, yPos, &xpos, &ypos);
bool do_refresh =
(
(noUnitsX != 0 && m_xScrollLines == 0) ||
- (noUnitsX < m_xScrollLines && xpos > pixelsPerUnitX * noUnitsX) ||
+ (noUnitsX < m_xScrollLines && xPosInPixels > pixelsPerUnitX * noUnitsX) ||
(noUnitsY != 0 && m_yScrollLines == 0) ||
- (noUnitsY < m_yScrollLines && ypos > pixelsPerUnitY * noUnitsY) ||
+ (noUnitsY < m_yScrollLines && yPosInPixels > pixelsPerUnitY * noUnitsY) ||
(xPos != m_xScrollPosition) ||
(yPos != m_yScrollPosition)
);
// this they always have the priority
void wxScrollHelperBase::HandleOnChar(wxKeyEvent& event)
{
- int stx = 0, sty = 0, // view origin
- szx = 0, szy = 0, // view size (total)
- clix = 0, cliy = 0; // view size (on screen)
-
- GetViewStart(&stx, &sty);
- GetTargetSize(&clix, &cliy);
- m_targetWindow->GetVirtualSize(&szx, &szy);
-
- if( m_xScrollPixelsPerLine )
- {
- clix /= m_xScrollPixelsPerLine;
- szx /= m_xScrollPixelsPerLine;
- }
- else
- {
- clix = 0;
- szx = -1;
- }
- if( m_yScrollPixelsPerLine )
- {
- cliy /= m_yScrollPixelsPerLine;
- szy /= m_yScrollPixelsPerLine;
- }
- else
+ if ( !m_kbdScrollingEnabled )
{
- cliy = 0;
- szy = -1;
+ event.Skip();
+ return;
}
- int xScrollOld = m_xScrollPosition,
- yScrollOld = m_yScrollPosition;
+ // prepare the event this key press maps to
+ wxScrollWinEvent newEvent;
+
+ newEvent.SetPosition(0);
+ newEvent.SetEventObject(m_win);
+
+ // this is the default, it's changed to wxHORIZONTAL below if needed
+ newEvent.SetOrientation(wxVERTICAL);
+
+ // some key events result in scrolling in both horizontal and vertical
+ // direction, e.g. Ctrl-{Home,End}, if this flag is true we should generate
+ // a second event in horizontal direction in addition to the primary one
+ bool sendHorizontalToo = false;
- int dsty;
switch ( event.GetKeyCode() )
{
case WXK_PAGEUP:
- dsty = sty - (5 * cliy / 6);
- Scroll(-1, (dsty == -1) ? 0 : dsty);
+ newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
break;
case WXK_PAGEDOWN:
- Scroll(-1, sty + (5 * cliy / 6));
+ newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
break;
case WXK_HOME:
- Scroll(0, event.ControlDown() ? 0 : -1);
- break;
+ newEvent.SetEventType(wxEVT_SCROLLWIN_TOP);
- case WXK_END:
- Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
+ sendHorizontalToo = event.ControlDown();
break;
- case WXK_UP:
- Scroll(-1, sty - 1);
- break;
+ case WXK_END:
+ newEvent.SetEventType(wxEVT_SCROLLWIN_BOTTOM);
- case WXK_DOWN:
- Scroll(-1, sty + 1);
+ sendHorizontalToo = event.ControlDown();
break;
case WXK_LEFT:
- Scroll(stx - 1, -1);
+ newEvent.SetOrientation(wxHORIZONTAL);
+ // fall through
+
+ case WXK_UP:
+ newEvent.SetEventType(wxEVT_SCROLLWIN_LINEUP);
break;
case WXK_RIGHT:
- Scroll(stx + 1, -1);
+ newEvent.SetOrientation(wxHORIZONTAL);
+ // fall through
+
+ case WXK_DOWN:
+ newEvent.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
break;
default:
- // not for us
+ // not a scrolling key
event.Skip();
+ return;
}
- if ( m_xScrollPosition != xScrollOld )
- {
- wxScrollWinEvent evt(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition,
- wxHORIZONTAL);
- evt.SetEventObject(m_win);
- m_win->GetEventHandler()->ProcessEvent(evt);
- }
+ m_win->ProcessWindowEvent(newEvent);
- if ( m_yScrollPosition != yScrollOld )
+ if ( sendHorizontalToo )
{
- wxScrollWinEvent evt(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition,
- wxVERTICAL);
- evt.SetEventObject(m_win);
- m_win->GetEventHandler()->ProcessEvent(evt);
+ newEvent.SetOrientation(wxHORIZONTAL);
+ m_win->ProcessWindowEvent(newEvent);
}
}
void wxScrollHelperBase::StopAutoScrolling()
{
#if wxUSE_TIMER
- if ( m_timerAutoScroll )
- {
- delete m_timerAutoScroll;
- m_timerAutoScroll = (wxTimer *)NULL;
- }
+ wxDELETE(m_timerAutoScroll);
#endif
}
// but seems to happen sometimes under wxMSW - maybe it's a bug
// there but for now just ignore it
- //wxFAIL_MSG( _T("can't understand where has mouse gone") );
+ //wxFAIL_MSG( wxT("can't understand where has mouse gone") );
return;
}
if ( win == m_targetWindow )
return; // nothing to do
-#ifdef __WXMAC__
+#if defined( __WXOSX__ ) && wxUSE_SCROLLBAR
if (wxDynamicCast(win, wxScrollBar))
return;
#endif
// part of a wxComboCtrl visible and the button would still be outside the
// scrolled area. But do so only if the parent fits *entirely* inside the
// scrolled window. In other situations, such as nested wxPanel or
- // wxScrolledWindows, the parent might be way to big to fit inside the
+ // wxScrolledWindows, the parent might be way too big to fit inside the
// scrolled window. If that is the case, then make only the focused window
// visible
if ( win->GetParent() != m_targetWindow)
wxScrollHelper::DoAdjustScrollbar(int orient,
int clientSize,
int virtSize,
- int& pixelsPerUnit,
+ int pixelsPerUnit,
int& scrollUnits,
int& scrollPosition,
+ int& scrollLinesPerPage,
wxScrollbarVisibility visibility)
{
- if ( visibility == wxSHOW_SB_NEVER )
- {
- m_win->SetScrollbar(orient, 0, 0, 0);
- return;
- }
-
// 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 && visibility != wxSHOW_SB_ALWAYS) )
+ if ( pixelsPerUnit == 0 || clientSize >= virtSize )
{
// scrolling is disabled or unnecessary
scrollUnits =
scrollPosition = 0;
- unitsPerPage = 0;
+ scrollLinesPerPage = 0;
}
else // might need scrolling
{
scrollUnits = (virtSize + pixelsPerUnit - 1) / pixelsPerUnit;
// Calculate the number of fully scroll units
- unitsPerPage = clientSize / pixelsPerUnit;
+ scrollLinesPerPage = clientSize / pixelsPerUnit;
- if (unitsPerPage >= scrollUnits)
+ if ( scrollLinesPerPage >= scrollUnits )
{
// we're big enough to not need scrolling
scrollUnits =
scrollPosition = 0;
- unitsPerPage = 0;
+ scrollLinesPerPage = 0;
}
else // we do need a scrollbar
{
- if ( unitsPerPage < 1 )
- unitsPerPage = 1;
+ if ( scrollLinesPerPage < 1 )
+ scrollLinesPerPage = 1;
// Correct position if greater than extent of canvas minus
// the visible portion of it or if below zero
- const int posMax = scrollUnits - unitsPerPage;
+ const int posMax = scrollUnits - scrollLinesPerPage;
if ( scrollPosition > posMax )
scrollPosition = posMax;
else if ( scrollPosition < 0 )
}
}
- m_win->SetScrollbar(orient, scrollPosition, unitsPerPage, scrollUnits);
+ // in wxSHOW_SB_NEVER case don't show the scrollbar even if it's needed, in
+ // wxSHOW_SB_ALWAYS case show the scrollbar even if it's not needed by
+ // passing a special range value to SetScrollbar()
+ int range;
+ switch ( visibility )
+ {
+ case wxSHOW_SB_NEVER:
+ range = 0;
+ break;
+
+ case wxSHOW_SB_ALWAYS:
+ range = scrollUnits ? scrollUnits : -1;
+ break;
+
+ default:
+ wxFAIL_MSG( wxS("unknown scrollbar visibility") );
+ // fall through
+
+ case wxSHOW_SB_DEFAULT:
+ range = scrollUnits;
+ break;
+
+ }
- // The amount by which we scroll when paging
- SetScrollPageSize(orient, unitsPerPage);
+ m_win->SetScrollbar(orient, scrollPosition, scrollLinesPerPage, range);
}
void wxScrollHelper::AdjustScrollbars()
m_xScrollPixelsPerLine,
m_xScrollLines,
m_xScrollPosition,
+ m_xScrollLinesPerPage,
m_xVisibility);
DoAdjustScrollbar(wxVERTICAL,
m_yScrollPixelsPerLine,
m_yScrollLines,
m_yScrollPosition,
+ m_yScrollLinesPerPage,
m_yVisibility);