From e2bfba21fe755746f8305a6db89ae43a02f2a697 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 21 Sep 2017 13:45:13 +0200 Subject: [PATCH] Fix sending EVT_SPIN_DOWN/UP events in Cocoa implementation of wxSpinButton To determine which wxSpinButton arrow was clicked, in the action handler there is compared current NSStepper value (after the actual change) with the value before the change. This former value is fetched in the internal mouse click event handler which is invoked before the action handler. This method of determining a delta works fine as long as the current value remains unchanged between the execution of the internal mouse click event handler and the action handler. But if the current value is explicitly changed (by calls to SetValue(), SetRange()) in some handler(s) invoked between these two (like e.g. bound EVT_LEFT_DOWN handler), calculated delta can be invalid and therefore wrong EVT_SPIN_DOWN/UP events can be sent. To get correct delta value we should to keep track of all explicit changes made to the current value starting from the mouse click and up to the entry to the action handler. Closes #17955. --- src/osx/cocoa/spinbutt.mm | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/osx/cocoa/spinbutt.mm b/src/osx/cocoa/spinbutt.mm index e3e197f12d..6649a31e4b 100644 --- a/src/osx/cocoa/spinbutt.mm +++ b/src/osx/cocoa/spinbutt.mm @@ -41,25 +41,55 @@ public : wxWidgetCocoaImpl(peer, w) { m_formerValue = 0; + m_trackValue = false; } ~wxSpinButtonCocoaImpl() { } + virtual void SetValue(wxInt32 v) wxOVERRIDE; + virtual void SetMinimum(wxInt32 v) wxOVERRIDE; + virtual void SetMaximum(wxInt32 v) wxOVERRIDE; virtual void controlAction(WXWidget slf, void* _cmd, void *sender) wxOVERRIDE; virtual void mouseEvent(WX_NSEvent event, WXWidget slf, void* _cmd) wxOVERRIDE; private: int m_formerValue; + bool m_trackValue; }; +void wxSpinButtonCocoaImpl::SetValue(wxInt32 v) +{ + [(NSStepper*)m_osxView setIntValue:v]; + if ( m_trackValue ) + m_formerValue = [(NSStepper*)m_osxView intValue]; +} + +void wxSpinButtonCocoaImpl::SetMinimum(wxInt32 v) +{ + [(NSStepper*)m_osxView setMinValue:(double)v]; + // Current value might be adjusted. + if ( m_trackValue ) + m_formerValue = [(NSStepper*)m_osxView intValue]; +} + +void wxSpinButtonCocoaImpl::SetMaximum(wxInt32 v) +{ + [(NSStepper*)m_osxView setMaxValue:(double)v]; + // Current value might be adjusted. + if ( m_trackValue ) + m_formerValue = [(NSStepper*)m_osxView intValue]; +} + void wxSpinButtonCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd) { - // send a release event in case we've been tracking the thumb + // Save and track the current value which may be changed + // in the mouse event handler if ( strcmp( sel_getName((SEL) _cmd) , "mouseDown:") == 0 ) { m_formerValue = [(NSStepper*)m_osxView intValue]; + m_trackValue = true; } wxWidgetCocoaImpl::mouseEvent(event, slf, _cmd); @@ -89,6 +119,7 @@ void wxSpinButtonCocoaImpl::controlAction( WXWidget WXUNUSED(slf), void *WXUNUSE wxpeer->TriggerScrollEvent(wxEVT_SCROLL_LINEDOWN); m_formerValue = [(NSStepper*)m_osxView intValue]; + m_trackValue = false; } }