00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPFont.j"
00024 @import "CPShadow.j"
00025 @import "CPView.j"
00026
00027 #include "CoreGraphics/CGGeometry.h"
00028 #include "Platform/Platform.h"
00029
00030
00031
00032
00033
00034 CPLeftTextAlignment = 0;
00035
00036
00037
00038
00039 CPRightTextAlignment = 1;
00040
00041
00042
00043
00044 CPCenterTextAlignment = 2;
00045
00046
00047
00048
00049 CPJustifiedTextAlignment = 3;
00050
00051
00052
00053
00054 CPNaturalTextAlignment = 4;
00055
00056
00057
00058
00059
00060 CPRegularControlSize = 0;
00061
00062
00063
00064
00065 CPSmallControlSize = 1;
00066
00067
00068
00069
00070 CPMiniControlSize = 2;
00071
00072 CPControlNormalBackgroundColor = "CPControlNormalBackgroundColor";
00073 CPControlSelectedBackgroundColor = "CPControlSelectedBackgroundColor";
00074 CPControlHighlightedBackgroundColor = "CPControlHighlightedBackgroundColor";
00075 CPControlDisabledBackgroundColor = "CPControlDisabledBackgroundColor";
00076
00077 CPControlTextDidBeginEditingNotification = "CPControlTextDidBeginEditingNotification";
00078 CPControlTextDidChangeNotification = "CPControlTextDidChangeNotification";
00079 CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotification";
00080
00081 var CPControlBlackColor = [CPColor blackColor];
00082
00089 @implementation CPControl : CPView
00090 {
00091 id _value;
00092
00093
00094 id _target;
00095 SEL _action;
00096 int _sendActionOn;
00097
00098
00099 BOOL _continuousTracking;
00100 BOOL _trackingWasWithinFrame;
00101 unsigned _trackingMouseDownFlags;
00102 CGPoint _previousTrackingLocation;
00103
00104 JSObject _ephemeralSubviewsForNames;
00105 CPSet _ephereralSubviews;
00106
00107 CPString _toolTip;
00108 }
00109
00110 + (CPDictionary)themeAttributes
00111 {
00112 return [CPDictionary dictionaryWithObjects:[CPLeftTextAlignment,
00113 CPTopVerticalTextAlignment,
00114 CPLineBreakByClipping,
00115 [CPColor blackColor],
00116 [CPFont systemFontOfSize:12.0],
00117 nil,
00118 _CGSizeMakeZero(),
00119 CPImageLeft,
00120 CPScaleToFit,
00121 _CGSizeMakeZero(),
00122 _CGSizeMake(-1.0, -1.0)]
00123 forKeys:[@"alignment",
00124 @"vertical-alignment",
00125 @"line-break-mode",
00126 @"text-color",
00127 @"font",
00128 @"text-shadow-color",
00129 @"text-shadow-offset",
00130 @"image-position",
00131 @"image-scaling",
00132 @"min-size",
00133 @"max-size"]];
00134 }
00135
00136 - (id)initWithFrame:(CGRect)aFrame
00137 {
00138 self = [super initWithFrame:aFrame];
00139
00140 if (self)
00141 {
00142 _sendActionOn = CPLeftMouseUpMask;
00143 _trackingMouseDownFlags = 0;
00144 }
00145
00146 return self;
00147 }
00148
00153 - (void)setAction:(SEL)anAction
00154 {
00155 _action = anAction;
00156 }
00157
00161 - (SEL)action
00162 {
00163 return _action;
00164 }
00165
00170 - (void)setTarget:(id)aTarget
00171 {
00172 _target = aTarget;
00173 }
00174
00178 - (id)target
00179 {
00180 return _target;
00181 }
00182
00188 - (void)sendAction:(SEL)anAction to:(id)anObject
00189 {
00190 [CPApp sendAction:anAction to:anObject from:self];
00191 }
00192
00193 - (int)sendActionOn:(int)mask
00194 {
00195 var previousMask = _sendActionOn;
00196
00197 _sendActionOn = mask;
00198
00199 return previousMask;
00200 }
00201
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00222
00223
00224
00225
00226
00227
00228
00232 - (BOOL)isContinuous
00233 {
00234
00235 return (_sendActionOn & CPPeriodicMask) !== 0;
00236 }
00237
00241 - (void)setContinuous:(BOOL)flag
00242 {
00243
00244 if (flag)
00245 _sendActionOn |= CPPeriodicMask;
00246 else
00247 _sendActionOn &= ~CPPeriodicMask;
00248 }
00249
00250 - (BOOL)tracksMouseOutsideOfFrame
00251 {
00252 return NO;
00253 }
00254
00255 - (void)trackMouse:(CPEvent)anEvent
00256 {
00257 var type = [anEvent type],
00258 currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
00259 isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
00260
00261 if (type === CPLeftMouseUp)
00262 {
00263 [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
00264
00265 _trackingMouseDownFlags = 0;
00266 }
00267
00268 else
00269 {
00270 if (type === CPLeftMouseDown)
00271 {
00272 _trackingMouseDownFlags = [anEvent modifierFlags];
00273 _continuousTracking = [self startTrackingAt:currentLocation];
00274 }
00275 else if (type === CPLeftMouseDragged)
00276 {
00277 if (isWithinFrame)
00278 {
00279 if (!_trackingWasWithinFrame)
00280 _continuousTracking = [self startTrackingAt:currentLocation];
00281
00282 else if (_continuousTracking)
00283 _continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation];
00284 }
00285 else
00286 [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO];
00287 }
00288
00289 [CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
00290 }
00291
00292 if ((_sendActionOn & (1 << type)) && isWithinFrame)
00293 [self sendAction:_action to:_target];
00294
00295 _trackingWasWithinFrame = isWithinFrame;
00296 _previousTrackingLocation = currentLocation;
00297 }
00298
00299 - (void)performClick:(id)sender
00300 {
00301 [self highlight:YES];
00302 [self setState:[self nextState]];
00303 [self sendAction:[self action] to:[self target]];
00304 [self highlight:NO];
00305 }
00306
00307 - (unsigned)mouseDownFlags
00308 {
00309 return _trackingMouseDownFlags;
00310 }
00311
00312 - (BOOL)startTrackingAt:(CGPoint)aPoint
00313 {
00314 [self highlight:YES];
00315
00316 return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
00317 }
00318
00319 - (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
00320 {
00321 return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
00322 }
00323
00324 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
00325 {
00326 [self highlight:NO];
00327 }
00328
00329 - (void)mouseDown:(CPEvent)anEvent
00330 {
00331 if (![self isEnabled])
00332 return;
00333
00334 [self trackMouse:anEvent];
00335 }
00336
00340 - (id)objectValue
00341 {
00342 return _value;
00343 }
00344
00348 - (void)setObjectValue:(id)anObject
00349 {
00350 _value = anObject;
00351
00352 [self setNeedsLayout];
00353 [self setNeedsDisplay:YES];
00354 }
00355
00359 - (float)floatValue
00360 {
00361 var floatValue = parseFloat(_value, 10);
00362 return isNaN(floatValue) ? 0.0 : floatValue;
00363 }
00364
00368 - (void)setFloatValue:(float)aValue
00369 {
00370 [self setObjectValue:aValue];
00371 }
00372
00376 - (double)doubleValue
00377 {
00378 var doubleValue = parseFloat(_value, 10);
00379 return isNaN(doubleValue) ? 0.0 : doubleValue;
00380 }
00381
00385 - (void)setDoubleValue:(double)anObject
00386 {
00387 [self setObjectValue:anObject];
00388 }
00389
00393 - (int)intValue
00394 {
00395 var intValue = parseInt(_value, 10);
00396 return isNaN(intValue) ? 0.0 : intValue;
00397 }
00398
00402 - (void)setIntValue:(int)anObject
00403 {
00404 [self setObjectValue:anObject];
00405 }
00406
00410 - (int)integerValue
00411 {
00412 var intValue = parseInt(_value, 10);
00413 return isNaN(intValue) ? 0.0 : intValue;
00414 }
00415
00419 - (void)setIntegerValue:(int)anObject
00420 {
00421 [self setObjectValue:anObject];
00422 }
00423
00427 - (CPString)stringValue
00428 {
00429 return (_value === undefined || _value === nil) ? "" : String(_value);
00430 }
00431
00435 - (void)setStringValue:(CPString)anObject
00436 {
00437 [self setObjectValue:anObject];
00438 }
00439
00440 - (void)takeDoubleValueFrom:(id)sender
00441 {
00442 if ([sender respondsToSelector:@selector(doubleValue)])
00443 [self setDoubleValue:[sender doubleValue]];
00444 }
00445
00446
00447 - (void)takeFloatValueFrom:(id)sender
00448 {
00449 if ([sender respondsToSelector:@selector(floatValue)])
00450 [self setFloatValue:[sender floatValue]];
00451 }
00452
00453
00454 - (void)takeIntegerValueFrom:(id)sender
00455 {
00456 if ([sender respondsToSelector:@selector(integerValue)])
00457 [self setIntegerValue:[sender integerValue]];
00458 }
00459
00460
00461 - (void)takeIntValueFrom:(id)sender
00462 {
00463 if ([sender respondsToSelector:@selector(intValue)])
00464 [self setIntValue:[sender intValue]];
00465 }
00466
00467
00468 - (void)takeObjectValueFrom:(id)sender
00469 {
00470 if ([sender respondsToSelector:@selector(objectValue)])
00471 [self setObjectValue:[sender objectValue]];
00472 }
00473
00474 - (void)takeStringValueFrom:(id)sender
00475 {
00476 if ([sender respondsToSelector:@selector(stringValue)])
00477 [self setStringValue:[sender stringValue]];
00478 }
00479
00480 - (void)textDidBeginEditing:(CPNotification)note
00481 {
00482
00483 if([note object] != self)
00484 return;
00485
00486 [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
00487 }
00488
00489 - (void)textDidChange:(CPNotification)note
00490 {
00491
00492 if([note object] != self)
00493 return;
00494
00495 [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
00496 }
00497
00498 - (void)textDidEndEditing:(CPNotification)note
00499 {
00500
00501 if([note object] != self)
00502 return;
00503
00504 [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
00505 }
00506
00507 #define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
00508 - (void)set##UPPERCASE:(id)aValue\
00509 {\
00510 [self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
00511 }\
00512 - (id)LOWERCASE\
00513 {\
00514 return [self valueForThemeAttribute:ATTRIBUTENAME];\
00515 }
00516
00517 BRIDGE(Alignment, alignment, "alignment")
00518 BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
00519 BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
00520 BRIDGE(TextColor, textColor, "text-color")
00521 BRIDGE(Font, font, "font")
00522 BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
00523 BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
00524 BRIDGE(ImagePosition, imagePosition, "image-position")
00525 BRIDGE(ImageScaling, imageScaling, "image-scaling")
00526
00527 - (void)setEnabled:(BOOL)isEnabled
00528 {
00529 if (isEnabled)
00530 [self unsetThemeState:CPThemeStateDisabled];
00531 else
00532 [self setThemeState:CPThemeStateDisabled];
00533 }
00534
00535 - (BOOL)isEnabled
00536 {
00537 return ![self hasThemeState:CPThemeStateDisabled];
00538 }
00539
00540 - (void)highlight:(BOOL)shouldHighlight
00541 {
00542 [self setHighlighted:shouldHighlight];
00543 }
00544
00545 - (void)setHighlighted:(BOOL)isHighlighted
00546 {
00547 if (isHighlighted)
00548 [self setThemeState:CPThemeStateHighlighted];
00549 else
00550 [self unsetThemeState:CPThemeStateHighlighted];
00551 }
00552
00553 - (BOOL)isHighlighted
00554 {
00555 return [self hasThemeState:CPThemeStateHighlighted];
00556 }
00557
00558 - (CPView)createEphemeralSubviewNamed:(CPString)aViewName
00559 {
00560 return nil;
00561 }
00562
00563 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
00564 {
00565 return _CGRectMakeZero();
00566 }
00567
00568 - (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
00569 positioned:(CPWindowOrderingMode)anOrderingMode
00570 relativeToEphemeralSubviewNamed:(CPString)relativeToViewName
00571 {
00572 if (!_ephemeralSubviewsForNames)
00573 {
00574 _ephemeralSubviewsForNames = {};
00575 _ephemeralSubviews = [CPSet set];
00576 }
00577
00578 var frame = [self rectForEphemeralSubviewNamed:aViewName];
00579
00580 if (frame && !_CGRectIsEmpty(frame))
00581 {
00582 if (!_ephemeralSubviewsForNames[aViewName])
00583 {
00584 _ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName];
00585
00586 [_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]];
00587
00588 if (_ephemeralSubviewsForNames[aViewName])
00589 [self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]];
00590 }
00591
00592 if (_ephemeralSubviewsForNames[aViewName])
00593 [_ephemeralSubviewsForNames[aViewName] setFrame:frame];
00594 }
00595 else if (_ephemeralSubviewsForNames[aViewName])
00596 {
00597 [_ephemeralSubviewsForNames[aViewName] removeFromSuperview];
00598
00599 [_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]];
00600 delete _ephemeralSubviewsForNames[aViewName];
00601 }
00602
00603 return _ephemeralSubviewsForNames[aViewName];
00604 }
00605
00606 @end
00607
00608 var CPControlValueKey = "CPControlValueKey",
00609 CPControlControlStateKey = @"CPControlControlStateKey",
00610 CPControlIsEnabledKey = "CPControlIsEnabledKey",
00611
00612 CPControlTargetKey = "CPControlTargetKey",
00613 CPControlActionKey = "CPControlActionKey",
00614 CPControlSendActionOnKey = "CPControlSendActionOnKey";
00615
00616 var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
00617
00618 @implementation CPControl (CPCoding)
00619
00620
00621
00622
00623
00624
00625 - (id)initWithCoder:(CPCoder)aCoder
00626 {
00627 self = [super initWithCoder:aCoder];
00628
00629 if (self)
00630 {
00631 [self setObjectValue:[aCoder decodeObjectForKey:CPControlValueKey]];
00632
00633 [self setTarget:[aCoder decodeObjectForKey:CPControlTargetKey]];
00634 [self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
00635
00636 [self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
00637 }
00638
00639 return self;
00640 }
00641
00642
00643
00644
00645
00646 - (void)encodeWithCoder:(CPCoder)aCoder
00647 {
00648 var count = [_subviews count],
00649 ephemeral
00650 subviews = nil;
00651
00652 if (count > 0 && [_ephemeralSubviews count] > 0)
00653 {
00654 subviews = [_subviews.slice(0) copy];
00655
00656 while (count--)
00657 if ([_ephemeralSubviews containsObject:_subviews[count]])
00658 _subviews.splice(count, 1);
00659 }
00660
00661 [super encodeWithCoder:aCoder];
00662
00663 if (subviews)
00664 _subviews = subviews;
00665
00666 if (_value !== nil)
00667 [aCoder encodeObject:_value forKey:CPControlValueKey];
00668
00669 if (_target !== nil)
00670 [aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
00671
00672 if (_action !== NULL)
00673 [aCoder encodeObject:_action forKey:CPControlActionKey];
00674
00675 [aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
00676 }
00677
00678 @end
00679
00680 var _CPControlSizeIdentifiers = [],
00681 _CPControlCachedColorWithPatternImages = {},
00682 _CPControlCachedThreePartImagePattern = {};
00683
00684 _CPControlSizeIdentifiers[CPRegularControlSize] = "Regular";
00685 _CPControlSizeIdentifiers[CPSmallControlSize] = "Small";
00686 _CPControlSizeIdentifiers[CPMiniControlSize] = "Mini";
00687
00688 function _CPControlIdentifierForControlSize(aControlSize)
00689 {
00690 return _CPControlSizeIdentifiers[aControlSize];
00691 }
00692
00693 function _CPControlColorWithPatternImage(sizes, aClassName)
00694 {
00695 var index = 1,
00696 count = arguments.length,
00697 identifier = "";
00698
00699 for (; index < count; ++index)
00700 identifier += arguments[index];
00701
00702 var color = _CPControlCachedColorWithPatternImages[identifier];
00703
00704 if (!color)
00705 {
00706 var bundle = [CPBundle bundleForClass:[CPControl class]];
00707
00708 color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]];
00709
00710 _CPControlCachedColorWithPatternImages[identifier] = color;
00711 }
00712
00713 return color;
00714 }
00715
00716 function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
00717 {
00718 var index = 2,
00719 count = arguments.length,
00720 identifier = "";
00721
00722 for (; index < count; ++index)
00723 identifier += arguments[index];
00724
00725 var color = _CPControlCachedThreePartImagePattern[identifier];
00726
00727 if (!color)
00728 {
00729 var bundle = [CPBundle bundleForClass:[CPControl class]],
00730 path = aClassName + "/" + identifier;
00731
00732 sizes = sizes[identifier];
00733
00734 color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[
00735 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "0.png"] size:sizes[0]],
00736 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]],
00737 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
00738 ] isVertical:isVertical]];
00739
00740 _CPControlCachedThreePartImagePattern[identifier] = color;
00741 }
00742
00743 return color;
00744 }