+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+// Default OnSize resets scrollbars, if any
+void wxScrollHelper::HandleOnSize(wxSizeEvent& WXUNUSED(event))
+{
+#if wxUSE_CONSTRAINTS
+ if ( m_targetWindow->GetAutoLayout() )
+ m_targetWindow->Layout();
+#endif
+
+ AdjustScrollbars();
+}
+
+// This calls OnDraw, having adjusted the origin according to the current
+// scroll position
+void wxScrollHelper::HandleOnPaint(wxPaintEvent& WXUNUSED(event))
+{
+ wxPaintDC dc(m_targetWindow);
+ DoPrepareDC(dc);
+
+ OnDraw(dc);
+}
+
+// kbd handling: notice that we use OnChar() and not OnKeyDown() for
+// compatibility here - if we used OnKeyDown(), the programs which process
+// arrows themselves in their OnChar() would never get the message and like
+// this they always have the priority
+void wxScrollHelper::HandleOnChar(wxKeyEvent& event)
+{
+ int stx, sty, // view origin
+ szx, szy, // view size (total)
+ clix, cliy; // view size (on screen)
+
+ GetViewStart(&stx, &sty);
+ GetTargetSize(&clix, &cliy);
+ 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
+ {
+ cliy = 0;
+ szy = -1;
+ }
+
+ int dsty;
+ switch ( event.KeyCode() )
+ {
+ case WXK_PAGEUP:
+ case WXK_PRIOR:
+ dsty = sty - (5 * cliy / 6);
+ Scroll(-1, (dsty == -1) ? 0 : dsty);
+ break;
+
+ case WXK_PAGEDOWN:
+ case WXK_NEXT:
+ Scroll(-1, sty + (5 * cliy / 6));
+ break;
+
+ case WXK_HOME:
+ Scroll(0, event.ControlDown() ? 0 : -1);
+ break;
+
+ case WXK_END:
+ Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
+ break;
+
+ case WXK_UP:
+ Scroll(-1, sty - 1);
+ break;
+
+ case WXK_DOWN:
+ Scroll(-1, sty + 1);
+ break;
+
+ case WXK_LEFT:
+ Scroll(stx - 1, -1);
+ break;
+
+ case WXK_RIGHT:
+ Scroll(stx + 1, -1);
+ break;
+
+ default:
+ // not for us
+ event.Skip();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// autoscroll stuff: these functions deal with sending fake scroll events when
+// a captured mouse is being held outside the window
+// ----------------------------------------------------------------------------
+
+bool wxScrollHelper::SendAutoScrollEvents(wxScrollWinEvent& event) const
+{
+ // only send the event if the window is scrollable in this direction
+ wxWindow *win = (wxWindow *)event.GetEventObject();
+ return win->HasScrollbar(event.GetOrientation());
+}
+
+void wxScrollHelper::StopAutoScrolling()
+{
+ if ( m_timerAutoScroll )
+ {
+ delete m_timerAutoScroll;
+ m_timerAutoScroll = (wxTimer *)NULL;
+ }
+}
+
+void wxScrollHelper::HandleOnMouseEnter(wxMouseEvent& event)
+{
+ StopAutoScrolling();
+
+ event.Skip();
+}
+
+void wxScrollHelper::HandleOnMouseLeave(wxMouseEvent& event)
+{
+ // don't prevent the usual processing of the event from taking place
+ event.Skip();
+
+ // when a captured mouse leave a scrolled window we start generate
+ // scrolling events to allow, for example, extending selection beyond the
+ // visible area in some controls
+ if ( wxWindow::GetCapture() == m_targetWindow )
+ {
+ // where is the mouse leaving?
+ int pos, orient;
+ wxPoint pt = event.GetPosition();
+ if ( pt.x < 0 )
+ {
+ orient = wxHORIZONTAL;
+ pos = 0;
+ }
+ else if ( pt.y < 0 )
+ {
+ orient = wxVERTICAL;
+ pos = 0;
+ }
+ else // we're lower or to the right of the window
+ {
+ wxSize size = m_targetWindow->GetClientSize();
+ if ( pt.x > size.x )
+ {
+ orient = wxHORIZONTAL;
+ pos = m_xScrollLines;
+ }
+ else if ( pt.y > size.y )
+ {
+ orient = wxVERTICAL;
+ pos = m_yScrollLines;
+ }
+ else // this should be impossible
+ {
+ // 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") );
+
+ return;
+ }
+ }
+
+ // only start the auto scroll timer if the window can be scrolled in
+ // this direction
+ if ( !m_targetWindow->HasScrollbar(orient) )
+ return;
+
+ delete m_timerAutoScroll;
+ m_timerAutoScroll = new wxAutoScrollTimer
+ (
+ m_targetWindow, this,
+ pos == 0 ? wxEVT_SCROLLWIN_LINEUP
+ : wxEVT_SCROLLWIN_LINEDOWN,
+ pos,
+ orient
+ );
+ m_timerAutoScroll->Start(50); // FIXME: make configurable
+ }
+}
+
+#if wxUSE_MOUSEWHEEL
+
+void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event)
+{
+ m_wheelRotation += event.GetWheelRotation();
+ int lines = m_wheelRotation / event.GetWheelDelta();
+ m_wheelRotation -= lines * event.GetWheelDelta();
+
+ if (lines != 0)
+ {
+ lines *= event.GetLinesPerAction();
+
+ int vsx, vsy;
+ GetViewStart(&vsx, &vsy);
+ Scroll(-1, vsy - lines);
+ }
+}
+
+#endif // wxUSE_MOUSEWHEEL
+
+// ----------------------------------------------------------------------------
+// wxGenericScrolledWindow implementation
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxGenericScrolledWindow, wxPanel)
+
+bool wxGenericScrolledWindow::Create(wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxString& name)
+{
+ m_targetWindow = this;
+
+ bool ok = wxPanel::Create(parent, id, pos, size, style, name);
+
+#ifdef __WXMSW__
+ // we need to process arrows ourselves for scrolling
+ m_lDlgCode |= DLGC_WANTARROWS;
+#endif // __WXMSW__
+
+ return ok;
+}
+
+wxGenericScrolledWindow::~wxGenericScrolledWindow()
+{
+}
+
+#if WXWIN_COMPATIBILITY
+void wxGenericScrolledWindow::GetScrollUnitsPerPage (int *x_page, int *y_page) const
+{
+ *x_page = GetScrollPageSize(wxHORIZONTAL);
+ *y_page = GetScrollPageSize(wxVERTICAL);
+}
+
+void wxGenericScrolledWindow::CalcUnscrolledPosition(int x, int y, float *xx, float *yy) const
+{
+ if ( xx )
+ *xx = (float)(x + m_xScrollPosition * m_xScrollPixelsPerLine);
+ if ( yy )
+ *yy = (float)(y + m_yScrollPosition * m_yScrollPixelsPerLine);
+}
+#endif // WXWIN_COMPATIBILITY
+