1. added wxEvtHandler::SafelyProcessEvent() and wxWindow::HandleWindowEvent() to...
[wxWidgets.git] / src / cocoa / slider.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/slider.mm
3 // Purpose:     wxSlider
4 // Author:      David Elliott
5 //              Mark Oxenham
6 // Modified by:
7 // Created:     2003/06/19
8 // RCS-ID:      $Id$
9 // Copyright:   (c) 2003 David Elliott
10 //              (c) 2007 Software 2000 Ltd.
11 // Licence:     wxWidgets licence
12 /////////////////////////////////////////////////////////////////////////////
13
14 #include "wx/wxprec.h"
15
16 #if wxUSE_SLIDER
17
18 #include "wx/slider.h"
19
20 #ifndef WX_PRECOMP
21     #include "wx/app.h"
22 #endif //WX_PRECOMP
23
24 #import <Foundation/NSString.h>
25 #include "wx/cocoa/objc/NSSlider.h"
26 #import <AppKit/NSEvent.h>
27 #import <AppKit/NSWindow.h>
28
29 IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
30     BEGIN_EVENT_TABLE(wxSlider, wxSliderBase)
31 END_EVENT_TABLE()
32 WX_IMPLEMENT_COCOA_OWNER(wxSlider,NSSlider,NSControl,NSView)
33
34
35 inline void AdjustDimension(
36                 bool            isTicksStyle,
37                 int             &pos,
38                 wxSize          &size,
39                 int             (wxSize::*GetDimension)() const,
40                 void            (wxSize::*SetDimension)(int))
41 {
42     const int dimension = (size.*GetDimension)();
43     const int minSize = (isTicksStyle) ? 23 : 20;
44
45     // prevent clipping of overly "thin" sliders
46     if (dimension < minSize)
47     {
48         (size.*SetDimension)(minSize);
49     }
50
51     // move the slider control to the middle of the dimension that is not
52     // being used to define its length
53     pos += (dimension - (size.*GetDimension)() + 1) / 2;
54 }
55
56 bool wxSlider::Create(wxWindow *parent, wxWindowID winid,
57             int value, int minValue, int maxValue,
58             const wxPoint& pos, const wxSize& size, long style,
59             const wxValidator& validator, const wxString& name)
60 {
61     wxSize adjustedSize(size);
62     wxPoint adjustedPos(pos);
63     const bool isTicksStyle = (style & wxSL_TICKS) != 0;
64
65     if ((style & wxSL_HORIZONTAL) && (size.GetHeight() != wxDefaultCoord))
66     {
67         AdjustDimension(isTicksStyle, adjustedPos.y, adjustedSize, &wxSize::GetHeight, &wxSize::SetHeight);
68     }
69     else if ((style & wxSL_VERTICAL) && (size.GetWidth() != wxDefaultCoord))
70     {
71         AdjustDimension(isTicksStyle, adjustedPos.x, adjustedSize, &wxSize::GetWidth, &wxSize::SetWidth);
72     }
73     
74     if(!CreateControl(parent,winid,adjustedPos,adjustedSize,style,validator,name))
75         return false;
76     SetNSSlider([[WX_GET_OBJC_CLASS(WXNSSlider) alloc] initWithFrame: MakeDefaultNSRect(adjustedSize)]);
77     [m_cocoaNSView release];
78     
79     if(m_parent)
80         m_parent->CocoaAddChild(this);
81     SetInitialFrameRect(adjustedPos,adjustedSize);
82     
83     SetRange(minValue, maxValue);
84     SetValue(value);
85     
86     // -1 default for wxSL_AUTOTICKS == false
87     int tickMarks = -1;
88     // minValue > maxValue not handled, tickMarks set to 0
89     if ( style & wxSL_AUTOTICKS )
90         tickMarks = ((maxValue - minValue >= 0) ? (maxValue - minValue) : 0);
91     // arg2 needed a value, doesnt do anything
92     SetTickFreq(tickMarks,1);
93
94     return true;
95 }
96
97 wxSlider::~wxSlider()
98 {
99     DisassociateNSSlider(GetNSSlider());
100 }
101
102 void wxSlider::AssociateNSSlider(WX_NSSlider theSlider)
103 {
104     wxCocoaNSSlider::AssociateNSSlider(theSlider);
105     // Set the target/action.. we don't really need to unset these
106     [theSlider setTarget:wxCocoaNSControl::sm_cocoaTarget];
107     [theSlider setAction:@selector(wxNSControlAction:)];
108 }
109
110 void wxSlider::ProcessEventType(wxEventType commandType)
111 {
112     wxScrollEvent event(commandType, GetId(), GetValue(), HasFlag(wxSL_VERTICAL)?wxVERTICAL:wxHORIZONTAL);
113     event.SetEventObject(this);
114     HandleWindowEvent(event);
115 }
116
117 static inline wxEventType wxSliderEventTypeForKeyFromEvent(NSEvent *theEvent)
118 {
119     NSString *theEventCharacters = [theEvent charactersIgnoringModifiers];
120
121     if ([theEventCharacters length] == 1)
122     {
123         switch ([theEventCharacters characterAtIndex:0])
124         {
125             case NSUpArrowFunctionKey:
126             case NSRightArrowFunctionKey:   return wxEVT_SCROLL_PAGEDOWN;
127             case NSDownArrowFunctionKey:
128             case NSLeftArrowFunctionKey:    return wxEVT_SCROLL_PAGEUP;
129             case NSPageUpFunctionKey:       return wxEVT_SCROLL_BOTTOM;
130             case NSPageDownFunctionKey:     return wxEVT_SCROLL_TOP;
131         }
132     }
133     // Overload wxEVT_ANY to mean we can't determine the event type.
134     return wxEVT_ANY;
135 }
136
137 void wxSlider::CocoaTarget_action()
138 {
139     wxEventType sliderEventType;
140     SEL theSelector = wxCocoaNSSlider::GetLastResponderSelector();
141     
142     if(         theSelector == @selector(moveUp:)
143             ||  theSelector == @selector(moveRight:))
144         sliderEventType = wxEVT_SCROLL_PAGEDOWN;
145     else if(    theSelector == @selector(moveDown:)
146             ||  theSelector == @selector(moveLeft:))
147         sliderEventType = wxEVT_SCROLL_PAGEUP;
148     else if(    theSelector == @selector(pageUp:))
149         sliderEventType = wxEVT_SCROLL_BOTTOM;
150     else if(    theSelector == @selector(pageDown:))
151         sliderEventType = wxEVT_SCROLL_TOP;
152     else if(    theSelector == @selector(keyDown:))
153         // This case should ideally never be reached.
154         sliderEventType = wxSliderEventTypeForKeyFromEvent([[GetNSSlider() window] currentEvent]);
155     else
156         // Don't generate an event.
157         return;
158     if(sliderEventType != wxEVT_ANY)
159         ProcessEventType(sliderEventType);
160 }
161
162 void wxSlider::CocoaNotification_startTracking(WX_NSNotification notification)
163 {
164     CocoaNotification_continueTracking(notification);
165 }
166
167 void wxSlider::CocoaNotification_continueTracking(WX_NSNotification notification)
168 {
169     const double realValue = [GetNSSlider() doubleValue];
170
171     if (realValue != [GetNSSlider() intValue])
172     {
173         SetValue(rint(realValue));
174     }
175
176     ProcessEventType(wxEVT_SCROLL_THUMBTRACK);
177 }
178
179 void wxSlider::CocoaNotification_stopTracking(WX_NSNotification notification)
180 {
181     ProcessEventType(wxEVT_SCROLL_THUMBRELEASE);
182 }
183
184 int wxSlider::GetValue() const
185 {
186     return [GetNSSlider() intValue];
187 }
188
189 void wxSlider::SetValue(int value)
190 {
191     [GetNSSlider() setIntValue:value];
192 }
193
194 void wxSlider::SetRange(int minValue, int maxValue)
195 {
196     [GetNSSlider() setMinValue:minValue];
197     [GetNSSlider() setMaxValue:maxValue];
198 }
199
200 int wxSlider::GetMin() const
201 {
202     return [GetNSSlider() minValue];
203 }
204
205 int wxSlider::GetMax() const
206 {
207     return [GetNSSlider() maxValue];
208 }
209
210 void wxSlider::SetTickFreq(int n, int pos)
211 {
212     const int numTicks = (n > 0) ? ((GetMax() - GetMin()) / n) + 1 : 0;
213     [GetNSSlider() setNumberOfTickMarks:numTicks];
214 }
215
216 int wxSlider::GetTickFreq() const
217 {
218     const int numTicks = [GetNSSlider() numberOfTickMarks];
219     return ((numTicks != 0) ? (GetMax() - GetMin()) / (numTicks - 1) : 0);
220 }
221
222 void wxSlider::SetTickPos(int pos)
223 {
224     NSTickMarkPosition thePos = NSTickMarkBelow;
225     wxSize size = GetSize();
226
227     if (size.GetWidth() < size.GetHeight()) // NSSlider isVertical method can return -1 if it has not been displayed.
228     {
229         thePos = (pos != 1) ? NSTickMarkLeft : NSTickMarkRight;
230     }
231     else
232     {
233         thePos = (pos != 1) ? NSTickMarkBelow : NSTickMarkAbove;
234     }
235
236     [GetNSSlider() setTickMarkPosition:thePos];
237 }
238
239 void wxSlider::SetLineSize(int lineSize)
240 {
241     // to do
242 }
243
244 void wxSlider::SetPageSize(int pageSize)
245 {
246     // to do
247 }
248
249 int wxSlider::GetLineSize() const
250 {
251     return 1;
252 }
253
254 int wxSlider::GetPageSize() const
255 {
256     return 1;
257 }
258
259 int wxSlider::GetThumbLength() const
260 {
261     return 1;
262 }
263
264 void wxSlider::SetThumbLength(int lenPixels)
265 {
266     // to do
267 }
268
269 #endif // wxUSE_SLIDER