+
+// ----------------------------------------------------------------------------
+// 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
+