Skip to content
Newer
Older
100644 267 lines (210 sloc) 8.5 KB
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
1 /*
2 Created on 28/02/2009
3 Copyright 2009 Max Howell <max@methylblue.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #define KNOB_WIDTH 38
20 #define HEIGHT 26
21 #define WIDTH 89
22 #define KNOB_MIN_X 0
23 #define KNOB_MAX_X (WIDTH-KNOB_WIDTH)
24
4b5e850 @mxcl Animate the button when clicked or dragged part way
authored Nov 20, 2009
25 @interface MBKnobAnimation : NSAnimation
26 {
27 int start, range;
77340d1 @mxcl NSAnimationDelegate is 10.6 only
authored Nov 21, 2009
28 id delegate;
4b5e850 @mxcl Animate the button when clicked or dragged part way
authored Nov 20, 2009
29 }
30 @end
31 @implementation MBKnobAnimation
32 -(id)initWithStart:(int)begin end:(int)end
33 {
34 [super init];
35 start = begin;
36 range = end - begin;
37 return self;
38 }
39 -(void)setCurrentProgress:(NSAnimationProgress)progress
40 {
41 int x = start+progress*range;
42 [super setCurrentProgress:progress];
77340d1 @mxcl NSAnimationDelegate is 10.6 only
authored Nov 21, 2009
43 [delegate performSelector:@selector(setPosition:) withObject:[NSNumber numberWithInteger:x]];
44 }
45 -(void)setDelegate:(id)d
46 {
47 delegate = d;
4b5e850 @mxcl Animate the button when clicked or dragged part way
authored Nov 20, 2009
48 }
49 @end
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
50
51
4b5e850 @mxcl Animate the button when clicked or dragged part way
authored Nov 20, 2009
52 #import "MBSliderButton.h"
53
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
54 @implementation MBSliderButton
55
56 -(void)awakeFromNib
57 {
58 surround = [[NSImage alloc] initByReferencingFile:[[prefpane bundle] pathForResource:@"button_surround" ofType:@"png"]];
59 knob = [[NSImage alloc] initByReferencingFile:[[prefpane bundle] pathForResource:@"button_knob" ofType:@"png"]];
60
61 state = false;
62 }
63
64 -(void)drawRect:(NSRect)rect
65 {
66 NSColor* darkGreen = [NSColor colorWithDeviceRed:0.431 green:0.639 blue:0.118 alpha:1.0];
67 NSColor* lightGreen = [NSColor colorWithDeviceRed:0.647 green:0.835 blue:0.247 alpha:1.0];
68 NSColor* darkGray = [NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:1.0];
69 NSColor* lightGray = [NSColor colorWithDeviceRed:0.7 green:0.7 blue:0.7 alpha:1.0];
70
71 NSGradient* green_gradient = [[NSGradient alloc] initWithStartingColor:darkGreen endingColor:lightGreen];
72 NSGradient* gray_gradient = [[NSGradient alloc] initWithStartingColor:darkGray endingColor:lightGray];
73
74 [green_gradient drawInRect:NSMakeRect(0, location.y, location.x+10, HEIGHT) angle:270];
75
76 NSString* s = @"ON";
77 NSMutableDictionary* attr = [NSMutableDictionary dictionaryWithObjectsAndKeys:
78 [NSFont boldSystemFontOfSize:15.0], NSFontAttributeName,
79 [NSColor colorWithDeviceRed:0.2 green:0.333 blue:0.027 alpha:1.0], NSForegroundColorAttributeName,
80 nil];
81
82 NSSize sz = [s sizeWithAttributes:attr];
83 NSPoint pt;
84 pt.x = (KNOB_MAX_X-sz.width)/2 - (KNOB_MAX_X-location.x);
85 pt.y = HEIGHT/2 - sz.height/2;
86 [s drawAtPoint:pt withAttributes:attr];
87
88 int x = location.x+KNOB_WIDTH-2;
89 [gray_gradient drawInRect:NSMakeRect(x, location.y, WIDTH-x, HEIGHT) angle:270];
90
91 s = @"OFF";
92 [attr setObject:[NSColor colorWithDeviceWhite:0.2 alpha:0.66] forKey:NSForegroundColorAttributeName];
93 sz = [s sizeWithAttributes:attr];
94 pt.x = location.x+KNOB_WIDTH+(KNOB_MAX_X-sz.width)/2;
95 [s drawAtPoint:pt withAttributes:attr];
96
97
98 [surround drawAtPoint:NSMakePoint(0,0) fromRect:NSZeroRect
99 operation:NSCompositeSourceOver
100 fraction:1.0];
101 pt = location;
102 pt.x -= 2;
103 [knob drawAtPoint:pt fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
104 }
105
106 -(BOOL)isOpaque
107 {
108 return YES;
109 }
110
111 -(NSInteger)state
112 {
113 return state ? NSOnState : NSOffState;
114 }
115
4b5e850 @mxcl Animate the button when clicked or dragged part way
authored Nov 20, 2009
116 -(void)animateTo:(int)x
117 {
118 MBKnobAnimation* a = [[MBKnobAnimation alloc] initWithStart:location.x end:x];
119 [a setDelegate:self];
120 if (location.x == 0 || location.x == KNOB_MAX_X){
121 [a setDuration:0.20];
122 [a setAnimationCurve:NSAnimationEaseInOut];
123 }else{
124 [a setDuration:0.35 * ((fabs(location.x-x))/KNOB_MAX_X)];
125 [a setAnimationCurve:NSAnimationLinear];
126 }
127
128 [a setAnimationBlockingMode:NSAnimationBlocking];
129 [a startAnimation];
130 [a release];
131 }
132
133 -(void)setPosition:(NSNumber*)x
134 {
135 location.x = [x intValue];
136 [self display];
137 }
138
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
139 -(void)setState:(NSInteger)newstate
140 {
99143f3 @mxcl Animate the button when setState is called
authored Nov 22, 2009
141 [self setState:newstate animate:true];
142 }
143
144 -(void)setState:(NSInteger)newstate animate:(bool)animate
145 {
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
146 if(newstate == [self state])
147 return;
148
99143f3 @mxcl Animate the button when setState is called
authored Nov 22, 2009
149 int x = newstate == NSOnState ? KNOB_MAX_X : 0;
150
151 //TODO animate if we are visible and otherwise don't
152 if(animate)
153 [self animateTo:x];
154 else
155 [self setNeedsDisplay:YES];
156
157 state = newstate == NSOnState ? true : false;
158 location.x = x;
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
159 }
160
161 -(void)offsetLocationByX:(float)x
162 {
163 location.x = location.x + x;
99143f3 @mxcl Animate the button when setState is called
authored Nov 22, 2009
164
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
165 if (location.x < KNOB_MIN_X) location.x = KNOB_MIN_X;
166 if (location.x > KNOB_MAX_X) location.x = KNOB_MAX_X;
99143f3 @mxcl Animate the button when setState is called
authored Nov 22, 2009
167
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
168 [self setNeedsDisplay:YES];
169 }
170
171 -(void)mouseDown:(NSEvent *)event
172 {
173 BOOL loop = YES;
174
175 // convert the initial click location into the view coords
176 NSPoint clickLocation = [self convertPoint:[event locationInWindow] fromView:nil];
177
178 // did the click occur in the draggable item?
179 if (NSPointInRect(clickLocation, [self bounds])) {
180
181 NSPoint newDragLocation;
182
183 // the tight event loop pattern doesn't require the use
184 // of any instance variables, so we'll use a local
185 // variable localLastDragLocation instead.
186 NSPoint localLastDragLocation;
187
188 // save the starting location as the first relative point
189 localLastDragLocation=clickLocation;
190
191 while (loop) {
192 // get the next event that is a mouse-up or mouse-dragged event
193 NSEvent *localEvent;
194 localEvent= [[self window] nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask];
195
196
197 switch ([localEvent type]) {
198 case NSLeftMouseDragged:
199
200 // convert the new drag location into the view coords
201 newDragLocation = [self convertPoint:[localEvent locationInWindow]
202 fromView:nil];
203
204
205 // offset the item and update the display
206 [self offsetLocationByX:(newDragLocation.x-localLastDragLocation.x)];
207
208 // update the relative drag location;
4b5e850 @mxcl Animate the button when clicked or dragged part way
authored Nov 20, 2009
209 localLastDragLocation = newDragLocation;
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
210
211 // support automatic scrolling during a drag
212 // by calling NSView's autoscroll: method
213 [self autoscroll:localEvent];
214
215 break;
216 case NSLeftMouseUp:
217 // mouse up has been detected,
218 // we can exit the loop
219 loop = NO;
220
4b5e850 @mxcl Animate the button when clicked or dragged part way
authored Nov 20, 2009
221 if (memcmp(&clickLocation, &localLastDragLocation, sizeof(NSPoint)) == 0)
222 [self animateTo:state ? 0 : KNOB_MAX_X];
223 else if (location.x > 0 && location.x < KNOB_MAX_X)
224 [self animateTo:state ? KNOB_MAX_X : 0];
225
e0d7c08 @mxcl Rocker button class and graphics
authored Nov 16, 2009
226 //TODO if let go of it halfway then slide to non destructive side
227
228 if(location.x == 0 && state || location.x == KNOB_MAX_X && !state){
229 state = !state;
230 // wanted to use self.action and self.target but both are null
231 // even though I set them up in IB! :(
232 [prefpane performSelector:@selector(onEnable:) withObject:self];
233 }
234
235 // the rectangle has moved, we need to reset our cursor
236 // rectangle
237 [[self window] invalidateCursorRectsForView:self];
238
239 break;
240 default:
241 // Ignore any other kind of event.
242 break;
243 }
244 }
245 };
246 return;
247 }
248
249 -(BOOL)acceptsFirstResponder
250 {
251 return YES;
252 }
253
254 -(IBAction)moveLeft:(id)sender
255 {
256 [self offsetLocationByX:-10.0];
257 [[self window] invalidateCursorRectsForView:self];
258 }
259
260 -(IBAction)moveRight:(id)sender
261 {
262 [self offsetLocationByX:10.0];
263 [[self window] invalidateCursorRectsForView:self];
264 }
265
266 @end
Something went wrong with that request. Please try again.