X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/29e1398fa035b277569c4514deb622e9f1ddcf40..3d777efedc1e05bd6c2a7c34a00a65895b62bb13:/src/generic/scrlwing.cpp diff --git a/src/generic/scrlwing.cpp b/src/generic/scrlwing.cpp index 278ae610c0..ed7d288d7e 100644 --- a/src/generic/scrlwing.cpp +++ b/src/generic/scrlwing.cpp @@ -5,7 +5,6 @@ // Modified by: Vadim Zeitlin on 31.08.00: wxScrollHelper allows to implement. // Ron Lee on 10.4.02: virtual size / auto scrollbars et al. // Created: 01/02/97 -// RCS-ID: $Id$ // Copyright: (c) wxWidgets team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -79,14 +78,10 @@ public: virtual bool ProcessEvent(wxEvent& event); - void ResetDrawnFlag() { m_hasDrawnWindow = false; } - private: wxScrollHelperBase *m_scrollHelper; - bool m_hasDrawnWindow; - - DECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler) + wxDECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler); }; #if wxUSE_TIMER @@ -112,7 +107,7 @@ private: int m_pos, m_orient; - DECLARE_NO_COPY_CLASS(wxAutoScrollTimer) + wxDECLARE_NO_COPY_CLASS(wxAutoScrollTimer); }; // ============================================================================ @@ -147,12 +142,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); + 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); - wxGetMousePosition(&event2.m_x, &event2.m_y); + event2.SetPosition(wxGetMousePosition()); // the mouse event coordinates should be client, not screen as // returned by wxGetMousePosition @@ -165,7 +161,16 @@ void wxAutoScrollTimer::Notify() 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); } @@ -185,26 +190,13 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event) { 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() @@ -216,22 +208,25 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event) if ( evType == wxEVT_SIZE ) { m_scrollHelper->HandleOnSize((wxSizeEvent &)event); - 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; @@ -298,8 +293,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; } @@ -314,7 +319,7 @@ bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event) 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 = @@ -328,6 +333,8 @@ wxScrollHelperBase::wxScrollHelperBase(wxWindow *win) m_xScrollingEnabled = m_yScrollingEnabled = true; + m_kbdScrollingEnabled = true; + m_scaleX = m_scaleY = 1.0; #if wxUSE_MOUSEWHEEL @@ -368,16 +375,17 @@ void wxScrollHelperBase::SetScrollbars(int pixelsPerUnitX, 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) ); @@ -443,12 +451,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; @@ -829,93 +831,77 @@ void wxScrollHelperBase::HandleOnPaint(wxPaintEvent& WXUNUSED(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: - 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); } } @@ -934,11 +920,7 @@ bool wxScrollHelperBase::SendAutoScrollEvents(wxScrollWinEvent& event) const void wxScrollHelperBase::StopAutoScrolling() { #if wxUSE_TIMER - if ( m_timerAutoScroll ) - { - delete m_timerAutoScroll; - m_timerAutoScroll = (wxTimer *)NULL; - } + wxDELETE(m_timerAutoScroll); #endif } @@ -990,7 +972,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 - //wxFAIL_MSG( _T("can't understand where has mouse gone") ); + //wxFAIL_MSG( wxT("can't understand where has mouse gone") ); return; } @@ -1035,6 +1017,9 @@ void wxScrollHelperBase::HandleOnMouseWheel(wxMouseEvent& event) newEvent.SetOrientation( event.GetWheelAxis() == 0 ? wxVERTICAL : wxHORIZONTAL); newEvent.SetEventObject(m_win); + if ( event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL ) + lines = -lines; + if (event.IsPageScroll()) { if (lines > 0) @@ -1073,7 +1058,7 @@ void wxScrollHelperBase::HandleOnChildFocus(wxChildFocusEvent& event) if ( win == m_targetWindow ) return; // nothing to do -#ifdef __WXMAC__ +#if defined( __WXOSX__ ) && wxUSE_SCROLLBAR if (wxDynamicCast(win, wxScrollBar)) return; #endif @@ -1115,7 +1100,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 - // 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) @@ -1232,28 +1217,20 @@ void 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 { @@ -1261,23 +1238,23 @@ wxScrollHelper::DoAdjustScrollbar(int orient, 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 ) @@ -1285,10 +1262,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() @@ -1348,6 +1346,7 @@ void wxScrollHelper::AdjustScrollbars() m_xScrollPixelsPerLine, m_xScrollLines, m_xScrollPosition, + m_xScrollLinesPerPage, m_xVisibility); DoAdjustScrollbar(wxVERTICAL, @@ -1356,6 +1355,7 @@ void wxScrollHelper::AdjustScrollbars() m_yScrollPixelsPerLine, m_yScrollLines, m_yScrollPosition, + m_yScrollLinesPerPage, m_yVisibility);