diff --git a/include/wx/cocoa/NSSlider.h b/include/wx/cocoa/NSSlider.h index 3543f3b8d8..9dc637dc5e 100644 --- a/include/wx/cocoa/NSSlider.h +++ b/include/wx/cocoa/NSSlider.h @@ -2,7 +2,7 @@ // Name: wx/cocoa/NSSlider.h // Purpose: wxCocoaNSSlider class // Author: Mark Oxenham -// Modified by: +// Modified by: David Elliott // Created: 2007/08/10 // RCS-ID: $Id$ // Copyright: (c) 2007 Software 2000 Ltd. All rights reserved. @@ -20,34 +20,28 @@ DECLARE_WXCOCOA_OBJC_CLASS(NSSlider); WX_DECLARE_OBJC_HASHMAP(NSSlider); +// For when we're not in Objective-C mode: +typedef struct objc_selector *SEL; + +class wxCocoaNSSliderLastSelectorChanger; + class wxCocoaNSSlider { + friend class wxCocoaNSSliderLastSelectorChanger; WX_DECLARE_OBJC_INTERFACE_HASHMAP(NSSlider); public: void AssociateNSSlider(WX_NSSlider cocoaNSSlider); void DisassociateNSSlider(WX_NSSlider cocoaNSSlider); - virtual void Cocoa_wxNSSliderUpArrowKeyDown(void) = 0; - virtual void Cocoa_wxNSSliderDownArrowKeyDown(void) = 0; - virtual void Cocoa_wxNSSliderLeftArrowKeyDown(void) = 0; - virtual void Cocoa_wxNSSliderRightArrowKeyDown(void) = 0; - virtual void Cocoa_wxNSSliderPageUpKeyDown(void) = 0; - virtual void Cocoa_wxNSSliderPageDownKeyDown(void) = 0; - virtual void Cocoa_wxNSSliderMoveUp(void) = 0; - virtual void Cocoa_wxNSSliderMoveDown(void) = 0; - virtual void Cocoa_wxNSSliderMoveLeft(void) = 0; - virtual void Cocoa_wxNSSliderMoveRight(void) = 0; - virtual void Cocoa_wxNSSliderPageUp(void) = 0; - virtual void Cocoa_wxNSSliderPageDown(void) = 0; virtual void CocoaNotification_startTracking(WX_NSNotification notification) = 0; virtual void CocoaNotification_continueTracking(WX_NSNotification notification) = 0; virtual void CocoaNotification_stopTracking(WX_NSNotification notification) = 0; - virtual ~wxCocoaNSSlider() { } + static SEL GetLastResponderSelector() + { return sm_lastResponderSelector; } protected: - static const wxObjcAutoRefFromAlloc sm_cocoaTarget; - static struct objc_object *sm_cocoaObserver; - + virtual ~wxCocoaNSSlider() { } + static SEL sm_lastResponderSelector; }; #endif diff --git a/include/wx/cocoa/slider.h b/include/wx/cocoa/slider.h index 2d2d4aaa1f..1d2a164666 100644 --- a/include/wx/cocoa/slider.h +++ b/include/wx/cocoa/slider.h @@ -54,25 +54,20 @@ public: // Cocoa callbacks // ------------------------------------------------------------------------ protected: - // from NSSLider + // Override this so we can use wxCocoaNSControl's target + void AssociateNSSlider(WX_NSSlider theSlider); + + // Helper method to do the real work virtual void ProcessEventType(wxEventType commandType); - virtual void Cocoa_wxNSSliderUpArrowKeyDown(void) { ProcessEventType(wxEVT_SCROLL_PAGEDOWN); } - virtual void Cocoa_wxNSSliderDownArrowKeyDown(void) { ProcessEventType(wxEVT_SCROLL_PAGEUP); } - virtual void Cocoa_wxNSSliderLeftArrowKeyDown(void) { ProcessEventType(wxEVT_SCROLL_PAGEUP); } - virtual void Cocoa_wxNSSliderRightArrowKeyDown(void) { ProcessEventType(wxEVT_SCROLL_PAGEDOWN); } - virtual void Cocoa_wxNSSliderPageUpKeyDown(void) { ProcessEventType(wxEVT_SCROLL_BOTTOM); } - virtual void Cocoa_wxNSSliderPageDownKeyDown(void) { ProcessEventType(wxEVT_SCROLL_TOP); } - virtual void Cocoa_wxNSSliderMoveUp(void) { ProcessEventType(wxEVT_SCROLL_PAGEDOWN); } - virtual void Cocoa_wxNSSliderMoveDown(void) { ProcessEventType(wxEVT_SCROLL_PAGEUP); } - virtual void Cocoa_wxNSSliderMoveLeft(void) { ProcessEventType(wxEVT_SCROLL_PAGEUP); } - virtual void Cocoa_wxNSSliderMoveRight(void) { ProcessEventType(wxEVT_SCROLL_PAGEDOWN); } - virtual void Cocoa_wxNSSliderPageUp(void) { ProcessEventType(wxEVT_SCROLL_BOTTOM); } - virtual void Cocoa_wxNSSliderPageDown(void) { ProcessEventType(wxEVT_SCROLL_TOP); } + + // from wxCocoaNSControl: + virtual void CocoaTarget_action(); + + // from wxCocoaNSSlider: virtual void CocoaNotification_startTracking(WX_NSNotification notification); virtual void CocoaNotification_continueTracking(WX_NSNotification notification); virtual void CocoaNotification_stopTracking(WX_NSNotification notification); - - + // ------------------------------------------------------------------------ // Implementation // ------------------------------------------------------------------------ diff --git a/src/cocoa/NSSlider.mm b/src/cocoa/NSSlider.mm index 5e352332d7..3233c5a55a 100644 --- a/src/cocoa/NSSlider.mm +++ b/src/cocoa/NSSlider.mm @@ -24,120 +24,30 @@ WX_IMPLEMENT_OBJC_INTERFACE_HASHMAP(NSSlider) -// ============================================================================ -// @class wxNSSliderTarget -// ============================================================================ -@interface wxNSSliderTarget : NSObject +class wxCocoaNSSliderLastSelectorChanger { -} - -- (void)wxNSSliderUpArrowKeyDown: (id)sender; -- (void)wxNSSliderDownArrowKeyDown: (id)sender; -- (void)wxNSSliderLeftArrowKeyDown: (id)sender; -- (void)wxNSSliderRightArrowKeyDown: (id)sender; -- (void)wxNSSliderPageUpKeyDown: (id)sender; -- (void)wxNSSliderPageDownKeyDown: (id)sender; -- (void)wxNSSliderMoveUp: (id)sender; -- (void)wxNSSliderMoveDown: (id)sender; -- (void)wxNSSliderMoveLeft: (id)sender; -- (void)wxNSSliderMoveRight: (id)sender; -- (void)wxNSSliderPageUp: (id)sender; -- (void)wxNSSliderPageDown: (id)sender; -@end // wxNSSliderTarget - -@implementation wxNSSliderTarget : NSObject - -- (void)wxNSSliderUpArrowKeyDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderUpArrowKeyDown received without associated wx object")); - slider->Cocoa_wxNSSliderUpArrowKeyDown(); -} - -- (void)wxNSSliderDownArrowKeyDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderDownArrowKeyDown received without associated wx object")); - slider->Cocoa_wxNSSliderDownArrowKeyDown(); -} - -- (void)wxNSSliderLeftArrowKeyDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderLeftArrowKeyDown received without associated wx object")); - slider->Cocoa_wxNSSliderLeftArrowKeyDown(); -} - -- (void)wxNSSliderRightArrowKeyDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderRightArrowKeyDown received without associated wx object")); - slider->Cocoa_wxNSSliderRightArrowKeyDown(); -} - -- (void)wxNSSliderPageUpKeyDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderPageUpKeyDown received without associated wx object")); - slider->Cocoa_wxNSSliderPageUpKeyDown(); -} - -- (void)wxNSSliderPageDownKeyDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderPageDownKeyDown received without associated wx object")); - slider->Cocoa_wxNSSliderPageDownKeyDown(); -} - -- (void)wxNSSliderMoveUp: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderMoveUp received without associated wx object")); - slider->Cocoa_wxNSSliderMoveUp(); -} - -- (void)wxNSSliderMoveDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderMoveDown received without associated wx object")); - slider->Cocoa_wxNSSliderMoveDown(); -} - -- (void)wxNSSliderMoveLeft: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderMoveLeft received without associated wx object")); - slider->Cocoa_wxNSSliderMoveLeft(); -} - -- (void)wxNSSliderMoveRight: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderMoveRight received without associated wx object")); - slider->Cocoa_wxNSSliderMoveRight(); -} - -- (void)wxNSSliderPageUp: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderPageUp received without associated wx object")); - slider->Cocoa_wxNSSliderPageUp(); -} - -- (void)wxNSSliderPageDown: (id)sender -{ - wxCocoaNSSlider *slider = wxCocoaNSSlider::GetFromCocoa(sender); - wxCHECK_RET(slider,wxT("wxNSSliderPageDown received without associated wx object")); - slider->Cocoa_wxNSSliderPageDown(); -} - -@end // implementation wxNSSliderTarget +public: + wxCocoaNSSliderLastSelectorChanger(SEL newSelector) + { + m_savedResponderSelector = wxCocoaNSSlider::sm_lastResponderSelector; + wxCocoaNSSlider::sm_lastResponderSelector = newSelector; + } + ~wxCocoaNSSliderLastSelectorChanger() + { + wxCocoaNSSlider::sm_lastResponderSelector = m_savedResponderSelector; + } +private: + SEL m_savedResponderSelector; +// Don't allow any default or copy construction + wxCocoaNSSliderLastSelectorChanger(); + wxCocoaNSSliderLastSelectorChanger(const wxCocoaNSSliderLastSelectorChanger&); + void operator=(const wxCocoaNSSliderLastSelectorChanger&); +}; // ============================================================================ // @class WXNSSlider // ============================================================================ - @implementation WXNSSlider : NSSlider // Override to ensure that WXNSSlider gets created with a WXNSSliderCell @@ -146,83 +56,53 @@ WX_IMPLEMENT_OBJC_INTERFACE_HASHMAP(NSSlider) return [WX_GET_OBJC_CLASS(WXNSSliderCell) class]; } +// The following methods are all NSResponder methods which NSSlider responds +// to in order to change its state and send the action message. We override +// them simply to record which one was called. This allows code listening +// only for the action message to determine what caused the action. +// Note that this is perfectly fine being a global because Cocoa processes +// events synchronously and only in the main thread. + - (void)keyDown:(NSEvent *)theEvent { - SEL originalAction = [self action]; - SEL newAction = originalAction; - NSString *theEventCharacters = [theEvent charactersIgnoringModifiers]; - - if ([theEventCharacters length] == 1) - { - switch ([theEventCharacters characterAtIndex:0]) - { - case NSUpArrowFunctionKey: newAction = @selector(wxNSSliderUpArrowKeyDown:); break; - case NSDownArrowFunctionKey: newAction = @selector(wxNSSliderDownArrowKeyDown:); break; - case NSLeftArrowFunctionKey: newAction = @selector(wxNSSliderLeftArrowKeyDown:); break; - case NSRightArrowFunctionKey: newAction = @selector(wxNSSliderRightArrowKeyDown:); break; - case NSPageUpFunctionKey: newAction = @selector(wxNSSliderPageUpKeyDown:); break; - case NSPageDownFunctionKey: newAction = @selector(wxNSSliderPageDownKeyDown:); break; - default: break; - } - } - - [self setAction:newAction]; + wxCocoaNSSliderLastSelectorChanger savedSelector(_cmd); [super keyDown:theEvent]; - [self setAction:originalAction]; } - (void)moveUp:(id)sender { - SEL originalAction = [self action]; - - [self setAction:@selector(wxNSSliderMoveUp:)]; + wxCocoaNSSliderLastSelectorChanger savedSelector(_cmd); [super moveUp:sender]; - [self setAction:originalAction]; } - (void)moveDown:(id)sender { - SEL originalAction = [self action]; - - [self setAction:@selector(wxNSSliderMoveDown:)]; + wxCocoaNSSliderLastSelectorChanger savedSelector(_cmd); [super moveDown:sender]; - [self setAction:originalAction]; } - (void)moveLeft:(id)sender { - SEL originalAction = [self action]; - - [self setAction:@selector(wxNSSliderMoveLeft:)]; + wxCocoaNSSliderLastSelectorChanger savedSelector(_cmd); [super moveLeft:sender]; - [self setAction:originalAction]; } - (void)moveRight:(id)sender { - SEL originalAction = [self action]; - - [self setAction:@selector(wxNSSliderMoveRight:)]; + wxCocoaNSSliderLastSelectorChanger savedSelector(_cmd); [super moveRight:sender]; - [self setAction:originalAction]; } - (void)pageUp:(id)sender { - SEL originalAction = [self action]; - - [self setAction:@selector(wxNSSliderPageUp:)]; + wxCocoaNSSliderLastSelectorChanger savedSelector(_cmd); [super pageUp:sender]; - [self setAction:originalAction]; } - (void)pageDown:(id)sender { - SEL originalAction = [self action]; - - [self setAction:@selector(wxNSSliderPageDown:)]; + wxCocoaNSSliderLastSelectorChanger savedSelector(_cmd); [super pageDown:sender]; - [self setAction:originalAction]; } @end @@ -232,10 +112,6 @@ WX_IMPLEMENT_GET_OBJC_CLASS(WXNSSlider,NSSlider) // @class WXNSSliderCell // ============================================================================ -#define kwxNSSliderStartTracking @"wxNSSliderStartTracking" -#define kwxNSSliderContinueTracking @"wxNSSliderContinueTracking" -#define kwxNSSliderStopTracking @"wxNSSliderStopTracking" - @implementation WXNSSliderCell : NSSliderCell - (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView { @@ -273,15 +149,14 @@ WX_IMPLEMENT_GET_OBJC_CLASS(WXNSSliderCell,NSSliderCell) // ============================================================================ // class wxCocoaNSSlider // ============================================================================ -const wxObjcAutoRefFromAlloc wxCocoaNSSlider::sm_cocoaTarget = [[wxNSSliderTarget alloc] init]; +SEL wxCocoaNSSlider::sm_lastResponderSelector; void wxCocoaNSSlider::AssociateNSSlider(WX_NSSlider cocoaNSSlider) { if(cocoaNSSlider) { sm_cocoaHash.insert(wxCocoaNSSliderHash::value_type(cocoaNSSlider,this)); - [cocoaNSSlider setTarget:sm_cocoaTarget]; } } diff --git a/src/cocoa/slider.mm b/src/cocoa/slider.mm index c94fc98575..b5041e9949 100644 --- a/src/cocoa/slider.mm +++ b/src/cocoa/slider.mm @@ -21,7 +21,10 @@ #include "wx/app.h" #endif //WX_PRECOMP +#import #include "wx/cocoa/objc/NSSlider.h" +#import +#import IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl) BEGIN_EVENT_TABLE(wxSlider, wxSliderBase) @@ -85,6 +88,14 @@ wxSlider::~wxSlider() DisassociateNSSlider(GetNSSlider()); } +void wxSlider::AssociateNSSlider(WX_NSSlider theSlider) +{ + wxCocoaNSSlider::AssociateNSSlider(theSlider); + // Set the target/action.. we don't really need to unset these + [theSlider setTarget:wxCocoaNSControl::sm_cocoaTarget]; + [theSlider setAction:@selector(wxNSControlAction:)]; +} + void wxSlider::ProcessEventType(wxEventType commandType) { wxScrollEvent event(commandType, GetId(), GetValue(), HasFlag(wxSL_VERTICAL)?wxVERTICAL:wxHORIZONTAL); @@ -92,6 +103,51 @@ void wxSlider::ProcessEventType(wxEventType commandType) GetEventHandler()->ProcessEvent(event); } +static inline wxEventType wxSliderEventTypeForKeyFromEvent(NSEvent *theEvent) +{ + NSString *theEventCharacters = [theEvent charactersIgnoringModifiers]; + + if ([theEventCharacters length] == 1) + { + switch ([theEventCharacters characterAtIndex:0]) + { + case NSUpArrowFunctionKey: + case NSRightArrowFunctionKey: return wxEVT_SCROLL_PAGEDOWN; + case NSDownArrowFunctionKey: + case NSLeftArrowFunctionKey: return wxEVT_SCROLL_PAGEUP; + case NSPageUpFunctionKey: return wxEVT_SCROLL_BOTTOM; + case NSPageDownFunctionKey: return wxEVT_SCROLL_TOP; + } + } + // Overload wxEVT_ANY to mean we can't determine the event type. + return wxEVT_ANY; +} + +void wxSlider::CocoaTarget_action() +{ + wxEventType sliderEventType; + SEL theSelector = wxCocoaNSSlider::GetLastResponderSelector(); + + if( theSelector == @selector(moveUp:) + || theSelector == @selector(moveRight:)) + sliderEventType = wxEVT_SCROLL_PAGEDOWN; + else if( theSelector == @selector(moveDown:) + || theSelector == @selector(moveLeft:)) + sliderEventType = wxEVT_SCROLL_PAGEUP; + else if( theSelector == @selector(pageUp:)) + sliderEventType = wxEVT_SCROLL_BOTTOM; + else if( theSelector == @selector(pageDown:)) + sliderEventType = wxEVT_SCROLL_TOP; + else if( theSelector == @selector(keyDown:)) + // This case should ideally never be reached. + sliderEventType = wxSliderEventTypeForKeyFromEvent([[GetNSSlider() window] currentEvent]); + else + // Don't generate an event. + return; + if(sliderEventType != wxEVT_ANY) + ProcessEventType(sliderEventType); +} + void wxSlider::CocoaNotification_startTracking(WX_NSNotification notification) { CocoaNotification_continueTracking(notification);