]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/scrlwing.cpp
Revert "Fix off by 1 error in wxGenericListCtrl::HitTest()."
[wxWidgets.git] / src / generic / scrlwing.cpp
index 278ae610c0335b082d11268f5e19b8e3150881e3..921c5961cae60beff416ab6d410b276c5a23c80c 100644 (file)
@@ -79,14 +79,10 @@ public:
 
     virtual bool ProcessEvent(wxEvent& event);
 
 
     virtual bool ProcessEvent(wxEvent& event);
 
-    void ResetDrawnFlag() { m_hasDrawnWindow = false; }
-
 private:
     wxScrollHelperBase *m_scrollHelper;
 
 private:
     wxScrollHelperBase *m_scrollHelper;
 
-    bool m_hasDrawnWindow;
-
-    DECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler)
+    wxDECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler);
 };
 
 #if wxUSE_TIMER
 };
 
 #if wxUSE_TIMER
@@ -112,7 +108,7 @@ private:
     int m_pos,
         m_orient;
 
     int m_pos,
         m_orient;
 
-    DECLARE_NO_COPY_CLASS(wxAutoScrollTimer)
+    wxDECLARE_NO_COPY_CLASS(wxAutoScrollTimer);
 };
 
 // ============================================================================
 };
 
 // ============================================================================
@@ -147,12 +143,13 @@ void wxAutoScrollTimer::Notify()
         // first scroll the window if we are allowed to do it
         wxScrollWinEvent event1(m_eventType, m_pos, m_orient);
         event1.SetEventObject(m_win);
         // first scroll the window if we are allowed to do it
         wxScrollWinEvent event1(m_eventType, m_pos, m_orient);
         event1.SetEventObject(m_win);
+        event1.SetId(m_win->GetId());
         if ( m_scrollHelper->SendAutoScrollEvents(event1) &&
                 m_win->GetEventHandler()->ProcessEvent(event1) )
         {
             // and then send a pseudo mouse-move event to refresh the selection
             wxMouseEvent event2(wxEVT_MOTION);
         if ( m_scrollHelper->SendAutoScrollEvents(event1) &&
                 m_win->GetEventHandler()->ProcessEvent(event1) )
         {
             // 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
 
             // the mouse event coordinates should be client, not screen as
             // returned by wxGetMousePosition
@@ -165,7 +162,16 @@ void wxAutoScrollTimer::Notify()
 
             event2.SetEventObject(m_win);
 
 
             event2.SetEventObject(m_win);
 
-            // FIXME: we don't fill in the other members - ok?
+            wxMouseState mouseState = wxGetMouseState();
+
+            event2.m_leftDown = mouseState.LeftIsDown();
+            event2.m_middleDown = mouseState.MiddleIsDown();
+            event2.m_rightDown = mouseState.RightIsDown();
+
+            event2.m_shiftDown = mouseState.ShiftDown();
+            event2.m_controlDown = mouseState.ControlDown();
+            event2.m_altDown = mouseState.AltDown();
+            event2.m_metaDown = mouseState.MetaDown();
 
             m_win->GetEventHandler()->ProcessEvent(event2);
         }
 
             m_win->GetEventHandler()->ProcessEvent(event2);
         }
@@ -185,26 +191,13 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
 {
     wxEventType evType = event.GetEventType();
 
 {
     wxEventType evType = event.GetEventType();
 
-    // the explanation of wxEVT_PAINT processing hack: for historic reasons
-    // there are 2 ways to process this event in classes deriving from
-    // wxScrolledWindow. The user code may
-    //
-    //  1. override wxScrolledWindow::OnDraw(dc)
-    //  2. define its own OnPaint() handler
-    //
-    // In addition, in wxUniversal wxWindow defines OnPaint() itself and
-    // always processes the draw event, so we can't just try the window
-    // OnPaint() first and call our HandleOnPaint() if it doesn't process it
-    // (the latter would never be called in wxUniversal).
-    //
-    // So the solution is to have a flag telling us whether the user code drew
-    // anything in the window. We set it to true here but reset it to false in
-    // wxScrolledWindow::OnPaint() handler (which wouldn't be called if the
-    // 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()
 
     // always process the size events ourselves, even if the user code handles
     // them as well, as we need to AdjustScrollbars()
@@ -216,22 +209,25 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
     if ( evType == wxEVT_SIZE )
     {
         m_scrollHelper->HandleOnSize((wxSizeEvent &)event);
     if ( evType == wxEVT_SIZE )
     {
         m_scrollHelper->HandleOnSize((wxSizeEvent &)event);
-
         return true;
     }
 
         return true;
     }
 
-    if ( processed )
-    {
-        // normally, nothing more to do here - except if it was a paint event
-        // which wasn't really processed, then we'll try to call our
-        // OnDraw() below (from HandleOnPaint)
-        if ( m_hasDrawnWindow || event.IsCommandEvent() )
-        {
-            return true;
-        }
-    }
+    if ( processed && event.IsCommandEvent())
+        return true;
 
 
-    if ( evType == wxEVT_PAINT )
+    // For wxEVT_PAINT the user code can either handle this event as usual or
+    // override virtual OnDraw(), so if the event hasn't been handled we need
+    // to call this virtual function ourselves.
+    if (
+#ifndef __WXUNIVERSAL__
+          // in wxUniversal "processed" will always be true, because
+          // all windows use the paint event to draw themselves.
+          // In this case we can't use this flag to determine if a custom
+          // paint event handler already drew our window and we just
+          // call OnDraw() anyway.
+          !processed &&
+#endif // !__WXUNIVERSAL__
+            evType == wxEVT_PAINT )
     {
         m_scrollHelper->HandleOnPaint((wxPaintEvent &)event);
         return true;
     {
         m_scrollHelper->HandleOnPaint((wxPaintEvent &)event);
         return true;
@@ -298,8 +294,18 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
         }
     }
 
         }
     }
 
-    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;
 }
 
     return processed;
 }
@@ -314,7 +320,7 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event)
 
 wxScrollHelperBase::wxScrollHelperBase(wxWindow *win)
 {
 
 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_xScrollPixelsPerLine =
     m_yScrollPixelsPerLine =
@@ -328,6 +334,8 @@ wxScrollHelperBase::wxScrollHelperBase(wxWindow *win)
     m_xScrollingEnabled =
     m_yScrollingEnabled = true;
 
     m_xScrollingEnabled =
     m_yScrollingEnabled = true;
 
+    m_kbdScrollingEnabled = true;
+
     m_scaleX =
     m_scaleY = 1.0;
 #if wxUSE_MOUSEWHEEL
     m_scaleX =
     m_scaleY = 1.0;
 #if wxUSE_MOUSEWHEEL
@@ -368,16 +376,17 @@ void wxScrollHelperBase::SetScrollbars(int pixelsPerUnitX,
                                        int yPos,
                                        bool noRefresh)
 {
                                        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) ||
     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 != 0 && m_yScrollLines == 0) ||
-      (noUnitsY < m_yScrollLines && ypos > pixelsPerUnitY * noUnitsY) ||
+      (noUnitsY < m_yScrollLines && yPosInPixels > pixelsPerUnitY * noUnitsY) ||
       (xPos != m_xScrollPosition) ||
       (yPos != m_yScrollPosition)
     );
       (xPos != m_xScrollPosition) ||
       (yPos != m_yScrollPosition)
     );
@@ -443,12 +452,6 @@ void wxScrollHelperBase::DeleteEvtHandler()
     }
 }
 
     }
 }
 
-void wxScrollHelperBase::ResetDrawnFlag()
-{
-    wxCHECK_RET( m_handler, "invalid use of ResetDrawnFlag - no handler?" );
-    m_handler->ResetDrawnFlag();
-}
-
 void wxScrollHelperBase::DoSetTargetWindow(wxWindow *target)
 {
     m_targetWindow = target;
 void wxScrollHelperBase::DoSetTargetWindow(wxWindow *target)
 {
     m_targetWindow = target;
@@ -829,93 +832,77 @@ void wxScrollHelperBase::HandleOnPaint(wxPaintEvent& WXUNUSED(event))
 // this they always have the priority
 void wxScrollHelperBase::HandleOnChar(wxKeyEvent& event)
 {
 // 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
+    if ( !m_kbdScrollingEnabled )
     {
     {
-        clix = 0;
-        szx = -1;
-    }
-    if( m_yScrollPixelsPerLine )
-    {
-        cliy /= m_yScrollPixelsPerLine;
-        szy /= m_yScrollPixelsPerLine;
-    }
-    else
-    {
-        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);
+    newEvent.SetId(m_win->GetId());
+
+    // 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:
     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:
             break;
 
         case WXK_PAGEDOWN:
-            Scroll(-1, sty + (5 * cliy / 6));
+            newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
             break;
 
         case WXK_HOME:
             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;
 
             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:
             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:
             break;
 
         case WXK_RIGHT:
-            Scroll(stx + 1, -1);
+            newEvent.SetOrientation(wxHORIZONTAL);
+            // fall through
+
+        case WXK_DOWN:
+            newEvent.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
             break;
 
         default:
             break;
 
         default:
-            // not for us
+            // not a scrolling key
             event.Skip();
             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);
     }
 }
 
     }
 }
 
@@ -934,11 +921,7 @@ bool wxScrollHelperBase::SendAutoScrollEvents(wxScrollWinEvent& event) const
 void wxScrollHelperBase::StopAutoScrolling()
 {
 #if wxUSE_TIMER
 void wxScrollHelperBase::StopAutoScrolling()
 {
 #if wxUSE_TIMER
-    if ( m_timerAutoScroll )
-    {
-        delete m_timerAutoScroll;
-        m_timerAutoScroll = (wxTimer *)NULL;
-    }
+    wxDELETE(m_timerAutoScroll);
 #endif
 }
 
 #endif
 }
 
@@ -990,7 +973,7 @@ void wxScrollHelperBase::HandleOnMouseLeave(wxMouseEvent& event)
                 // but seems to happen sometimes under wxMSW - maybe it's a bug
                 // there but for now just ignore it
 
                 // 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;
             }
 
                 return;
             }
@@ -1073,7 +1056,7 @@ void wxScrollHelperBase::HandleOnChildFocus(wxChildFocusEvent& event)
     if ( win == m_targetWindow )
         return; // nothing to do
 
     if ( win == m_targetWindow )
         return; // nothing to do
 
-#ifdef __WXMAC__
+#if defined( __WXOSX__ ) && wxUSE_SCROLLBAR
     if (wxDynamicCast(win, wxScrollBar))
         return;
 #endif
     if (wxDynamicCast(win, wxScrollBar))
         return;
 #endif
@@ -1115,7 +1098,7 @@ void wxScrollHelperBase::HandleOnChildFocus(wxChildFocusEvent& event)
     // 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
     // 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)
     // scrolled window. If that is the case, then make only the focused window
     // visible
     if ( win->GetParent() != m_targetWindow)
@@ -1232,28 +1215,20 @@ void
 wxScrollHelper::DoAdjustScrollbar(int orient,
                                   int clientSize,
                                   int virtSize,
 wxScrollHelper::DoAdjustScrollbar(int orient,
                                   int clientSize,
                                   int virtSize,
-                                  int& pixelsPerUnit,
+                                  int pixelsPerUnit,
                                   int& scrollUnits,
                                   int& scrollPosition,
                                   int& scrollUnits,
                                   int& scrollPosition,
+                                  int& scrollLinesPerPage,
                                   wxScrollbarVisibility visibility)
 {
                                   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
     // scroll lines per page: if 0, no scrolling is needed
-    int unitsPerPage;
-
     // check if we need scrollbar in this direction at all
     // 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;
     {
         // scrolling is disabled or unnecessary
         scrollUnits =
         scrollPosition = 0;
-        unitsPerPage = 0;
+        scrollLinesPerPage = 0;
     }
     else // might need scrolling
     {
     }
     else // might need scrolling
     {
@@ -1261,23 +1236,23 @@ wxScrollHelper::DoAdjustScrollbar(int orient,
         scrollUnits = (virtSize + pixelsPerUnit - 1) / pixelsPerUnit;
 
         // Calculate the number of fully scroll units
         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;
         {
             // we're big enough to not need scrolling
             scrollUnits =
             scrollPosition = 0;
-            unitsPerPage = 0;
+            scrollLinesPerPage = 0;
         }
         else // we do need a scrollbar
         {
         }
         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
 
             // 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 )
             if ( scrollPosition > posMax )
                 scrollPosition = posMax;
             else if ( scrollPosition < 0 )
@@ -1285,10 +1260,31 @@ wxScrollHelper::DoAdjustScrollbar(int orient,
         }
     }
 
         }
     }
 
-    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()
 }
 
 void wxScrollHelper::AdjustScrollbars()
@@ -1348,6 +1344,7 @@ void wxScrollHelper::AdjustScrollbars()
                           m_xScrollPixelsPerLine,
                           m_xScrollLines,
                           m_xScrollPosition,
                           m_xScrollPixelsPerLine,
                           m_xScrollLines,
                           m_xScrollPosition,
+                          m_xScrollLinesPerPage,
                           m_xVisibility);
 
         DoAdjustScrollbar(wxVERTICAL,
                           m_xVisibility);
 
         DoAdjustScrollbar(wxVERTICAL,
@@ -1356,6 +1353,7 @@ void wxScrollHelper::AdjustScrollbars()
                           m_yScrollPixelsPerLine,
                           m_yScrollLines,
                           m_yScrollPosition,
                           m_yScrollPixelsPerLine,
                           m_yScrollLines,
                           m_yScrollPosition,
+                          m_yScrollLinesPerPage,
                           m_yVisibility);
 
 
                           m_yVisibility);