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