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