API  0.9.7
 All Classes Files Functions Variables Macros Groups Pages
CPProgressIndicator.j
Go to the documentation of this file.
1 /*
2  * CPProgressIndicator.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 /*
26  @global
27  @group CPProgressIndicatorStyle
28 */
30 /*
31  @global
32  @group CPProgressIndicatorStyle
33 */
35 /*
36  @global
37  @group CPProgressIndicatorStyle
38 */
40 
42 
51 @implementation CPProgressIndicator : CPView
52 {
53  double _minValue;
54  double _maxValue;
55 
56  double _doubleValue;
57 
58  CPControlSize _controlSize;
59 
60  BOOL _indeterminate;
61  CPProgressIndicatorStyle _style;
62 
63  BOOL _isAnimating;
64 
65  BOOL _isDisplayedWhenStoppedSet;
66  BOOL _isDisplayedWhenStopped;
67 }
68 
69 + (CPString)defaultThemeClass
70 {
71  return @"progress-indicator";
72 }
73 
74 + (CPDictionary)themeAttributes
75 {
76  return @{
77  @"indeterminate-bar-color": [CPNull null],
78  @"bar-color": [CPNull null],
79  @"default-height": 20,
80  @"bezel-color": [CPNull null],
81  @"spinning-mini-gif": [CPNull null],
82  @"spinning-small-gif": [CPNull null],
83  @"spinning-regular-gif": [CPNull null],
84  };
85 }
86 
87 + (Class)_binderClassForBinding:(CPString)aBinding
88 {
89  if (aBinding === CPValueBinding || aBinding === @"isIndeterminate")
90  return [_CPProgressIndicatorBinder class];
91 
92  return [super _binderClassForBinding:aBinding];
93 }
94 
95 - (id)initWithFrame:(CGRect)aFrame
96 {
97  self = [super initWithFrame:aFrame];
98 
99  if (self)
100  {
101  _minValue = 0.0;
102  _maxValue = 100.0;
103 
104  _doubleValue = 0.0;
105 
107  _isDisplayedWhenStoppedSet = NO;
108 
109  _controlSize = CPRegularControlSize;
110 
111  [self setNeedsLayout];
112  }
113 
114  return self;
115 }
116 
117 /*
118  @ignore
119 */
120 - (void)setUsesThreadedAnimation:(BOOL)aFlag
121 {
122 }
123 
128 - (void)startAnimation:(id)aSender
129 {
130  _isAnimating = YES;
131 
132  [self _hideOrDisplay];
133 }
134 
139 - (void)stopAnimation:(id)aSender
140 {
141  _isAnimating = NO;
142 
143  [self _hideOrDisplay];
144 }
145 
149 - (BOOL)usesThreadedAnimation
150 {
151  return NO;
152 }
153 
154 // Advancing the Progress Bar
159 - (void)incrementBy:(double)aValue
160 {
161  [self setDoubleValue:_doubleValue + aValue];
162 }
163 
167 - (void)setDoubleValue:(double)aValue
168 {
169  _doubleValue = MIN(MAX(aValue, _minValue), _maxValue);
170 
171  [self drawBar];
172 }
173 
177 - (double)doubleValue
178 {
179  return _doubleValue;
180 }
181 
186 - (void)setMinValue:(double)aValue
187 {
188  _minValue = aValue;
189 }
190 
194 - (double)minValue
195 {
196  return _minValue;
197 }
198 
203 - (void)setMaxValue:(double)aValue
204 {
205  _maxValue = aValue;
206 }
207 
211 - (double)maxValue
212 {
213  return _maxValue;
214 }
215 
216 // Setting the Appearance
221 - (void)setControlSize:(CPControlSize)aControlSize
222 {
223  if (_controlSize == aControlSize)
224  return;
225 
226  _controlSize = aControlSize;
227 
228  [self updateBackgroundColor];
229 }
230 
234 - (CPControlSize)controlSize
235 {
236  return _controlSize;
237 }
238 
239 /*
240  Not yet implemented
241 */
242 - (void)setControlTint:(CPControlTint)aControlTint
243 {
244 }
245 
246 /*
247  Not yet implemented.
248 */
249 - (CPControlTint)controlTint
250 {
251  return 0;
252 }
253 
254 /*
255  Not yet implemented.
256 */
257 - (void)setBezeled:(BOOL)isBezeled
258 {
259 }
260 
261 /*
262  Not yet implemented.
263 */
264 - (BOOL)isBezeled
265 {
266  return YES;
267 }
268 
273 - (void)setIndeterminate:(BOOL)indeterminate
274 {
275  if (_indeterminate == indeterminate)
276  return;
277 
278  _indeterminate = indeterminate;
279 
280  [self updateBackgroundColor];
281 }
282 
286 - (BOOL)isIndeterminate
287 {
288  return _indeterminate;
289 }
290 
295 - (void)setStyle:(CPProgressIndicatorStyle)aStyle
296 {
297  if (_style == aStyle)
298  return;
299 
300  _style = aStyle;
301 
302  [self setTheme:(_style === CPProgressIndicatorHUDBarStyle) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
303 
304  [self updateBackgroundColor];
305 }
306 
310 - (void)sizeToFit
311 {
312  if (_style == CPProgressIndicatorSpinningStyle)
313  [self setFrameSize:[[CPProgressIndicatorSpinningStyleColors[_controlSize] patternImage] size]];
314  else
315  [self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), [self valueForThemeAttribute:@"default-height"])];
316 }
317 
323 - (void)setDisplayedWhenStopped:(BOOL)isDisplayedWhenStopped
324 {
325  if (_isDisplayedWhenStoppedSet && _isDisplayedWhenStopped == isDisplayedWhenStopped)
326  return;
327 
328  _isDisplayedWhenStoppedSet = YES;
329 
330  _isDisplayedWhenStopped = isDisplayedWhenStopped;
331 
332  [self _hideOrDisplay];
333 }
334 
338 - (BOOL)isDisplayedWhenStopped
339 {
340  if (_isDisplayedWhenStoppedSet)
341  return _isDisplayedWhenStopped;
342 
344  return YES;
345 
346  return NO;
347 }
348 
349 /* @ignore */
350 - (void)_hideOrDisplay
351 {
352  [self setHidden:!_isAnimating && ![self isDisplayedWhenStopped]];
353 }
354 
355 - (void)setFrameSize:(CGSize)aSize
356 {
357  [super setFrameSize:aSize];
358 
359  [self drawBar];
360 }
361 
362 /* @ignore */
363 - (void)drawBar
364 {
365  [self setNeedsLayout];
366 }
367 
368 - (CPView)createEphemeralSubviewNamed:(CPString)aName
369 {
370  return [[CPView alloc] initWithFrame:CGRectMakeZero()];
371 }
372 
373 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
374 {
375  if (aViewName === @"bar-view" && _style !== CPProgressIndicatorSpinningStyle)
376  {
377  var width = CGRectGetWidth([self bounds]),
378  barWidth = width * ((_doubleValue - _minValue) / (_maxValue - _minValue));
379 
380  if (barWidth > 0.0 && barWidth < 4.0)
381  barWidth = 4.0;
382 
383  if (_indeterminate)
384  barWidth = width;
385 
386  return CGRectMake(0, 0, barWidth, [self valueForThemeAttribute:@"default-height"]);
387  }
388 
389  return nil;
390 }
391 
392 /* @ignore */
393 - (void)updateBackgroundColor
394 {
395  if ([CPProgressIndicatorSpinningStyleColors count] === 0)
396  {
397  CPProgressIndicatorSpinningStyleColors[CPMiniControlSize] = [self valueForThemeAttribute:@"spinning-mini-gif"];
398  CPProgressIndicatorSpinningStyleColors[CPSmallControlSize] = [self valueForThemeAttribute:@"spinning-small-gif"];
399  CPProgressIndicatorSpinningStyleColors[CPRegularControlSize] = [self valueForThemeAttribute:@"spinning-regular-gif"];
400  }
401 
402  [self setNeedsLayout];
403 }
404 
405 - (void)layoutSubviews
406 {
407  if (YES)//_isBezeled)
408  {
409  if (_style == CPProgressIndicatorSpinningStyle)
410  {
411  // This will cause the bar view to go away due to having a nil rect when _style == CPProgressIndicatorSpinningStyle.
412  [self layoutEphemeralSubviewNamed:"bar-view"
413  positioned:CPWindowBelow
414  relativeToEphemeralSubviewNamed:nil];
415 
416  [self setBackgroundColor:CPProgressIndicatorSpinningStyleColors[_controlSize]];
417  }
418  else
419  {
420  [self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
421 
422  var barView = [self layoutEphemeralSubviewNamed:"bar-view"
423  positioned:CPWindowBelow
424  relativeToEphemeralSubviewNamed:nil];
425 
426  if (_indeterminate)
427  [barView setBackgroundColor:[self currentValueForThemeAttribute:@"indeterminate-bar-color"]];
428  else
429  [barView setBackgroundColor:[self currentValueForThemeAttribute:@"bar-color"]];
430  }
431  }
432  else
433  [self setBackgroundColor:nil];
434 }
435 
436 @end
437 
438 
440 
441 - (id)initWithCoder:(CPCoder)aCoder
442 {
443  if (self = [super initWithCoder:aCoder])
444  {
445  _minValue = [aCoder decodeObjectForKey:@"_minValue"];
446  _maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
447  _doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
448  _controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
449  _indeterminate = [aCoder decodeObjectForKey:@"_indeterminate"];
450  _style = [aCoder decodeIntForKey:@"_style"];
451  _isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
452  _isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
453  _isDisplayedWhenStopped = [aCoder decodeObjectForKey:@"_isDisplayedWhenStopped"];
454 
455  [self updateBackgroundColor];
456  }
457 
458  return self;
459 }
460 
461 - (void)encodeWithCoder:(CPCoder)aCoder
462 {
463  // Don't encode the background colour. It can be recreated based on the flags
464  // and if encoded causes hardcoded image paths in the cib while just wasting space.
465  var backgroundColor = [self backgroundColor];
466  [self setBackgroundColor:nil];
467  [super encodeWithCoder:aCoder];
468  [self setBackgroundColor:backgroundColor];
469 
470  [aCoder encodeObject:_minValue forKey:@"_minValue"];
471  [aCoder encodeObject:_maxValue forKey:@"_maxValue"];
472  [aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
473  [aCoder encodeObject:_controlSize forKey:@"_controlSize"];
474  [aCoder encodeObject:_indeterminate forKey:@"_indeterminate"];
475  [aCoder encodeInt:_style forKey:@"_style"];
476  [aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
477  [aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
478  [aCoder encodeObject:_isDisplayedWhenStopped forKey:@"_isDisplayedWhenStopped"];
479 }
480 
481 @end
482 @implementation _CPProgressIndicatorBinder : CPBinder
483 {
484  id __doxygen__;
485 }
486 
487 - (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
488 {
489  var value = aBinding === CPValueBinding ? 0.0 : YES;
490 
491  [self _setPlaceholder:value forMarker:CPMultipleValuesMarker isDefault:YES];
492  [self _setPlaceholder:value forMarker:CPNoSelectionMarker isDefault:YES];
493  [self _setPlaceholder:value forMarker:CPNotApplicableMarker isDefault:YES];
494  [self _setPlaceholder:value forMarker:CPNullMarker isDefault:YES];
495 }
496 
497 - (id)valueForBinding:(CPString)aBinding
498 {
499  if (aBinding === CPValueBinding)
500  return [_source doubleValue];
501  else if (aBinding === @"isIndeterminate")
502  [_source isIndeterminate];
503  else
504  return [super valueForBinding:aBinding];
505 }
506 
507 - (BOOL)_setValue:(id)aValue forBinding:(CPString)aBinding
508 {
509  if (aBinding === CPValueBinding)
510  [_source setDoubleValue:aValue];
511  else if (aBinding === @"isIndeterminate")
512  [_source setIndeterminate:aValue];
513  else
514  return NO;
515 
516  return YES;
517 }
518 
519 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
520 {
521  if (![self _setValue:aValue forBinding:aBinding])
522  [super setValue:aValue forBinding:aBinding];
523 }
524 
525 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
526 {
527  if (![self _setValue:aValue forBinding:aBinding])
528  [super setPlaceholderValue:aValue withMarker:aMarker forBinding:aBinding];
529 }
530 
531 @end