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 \
00509 - (void)set##UPPERCASE:(id)aValue\
00510 {\
00511 [self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
00512 }\
00513 \
00514 - (id)LOWERCASE\
00515 {\
00516 return [self valueForThemeAttribute:ATTRIBUTENAME];\
00517 }
00518
00519 BRIDGE(Alignment, alignment, "alignment")
00520 BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
00521 BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
00522 BRIDGE(TextColor, textColor, "text-color")
00523 BRIDGE(Font, font, "font")
00524 BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
00525 BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
00526 BRIDGE(ImagePosition, imagePosition, "image-position")
00527 BRIDGE(ImageScaling, imageScaling, "image-scaling")
00528
00529 - (void)setEnabled:(BOOL)isEnabled
00530 {
00531 if (isEnabled)
00532 [self unsetThemeState:CPThemeStateDisabled];
00533 else
00534 [self setThemeState:CPThemeStateDisabled];
00535 }
00536
00537 - (BOOL)isEnabled
00538 {
00539 return ![self hasThemeState:CPThemeStateDisabled];
00540 }
00541
00542 - (void)highlight:(BOOL)shouldHighlight
00543 {
00544 [self setHighlighted:shouldHighlight];
00545 }
00546
00547 - (void)setHighlighted:(BOOL)isHighlighted
00548 {
00549 if (isHighlighted)
00550 [self setThemeState:CPThemeStateHighlighted];
00551 else
00552 [self unsetThemeState:CPThemeStateHighlighted];
00553 }
00554
00555 - (BOOL)isHighlighted
00556 {
00557 return [self hasThemeState:CPThemeStateHighlighted];
00558 }
00559
00560 - (CPView)createEphemeralSubviewNamed:(CPString)aViewName
00561 {
00562 return nil;
00563 }
00564
00565 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
00566 {
00567 return _CGRectMakeZero();
00568 }
00569
00570 - (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
00571 positioned:(CPWindowOrderingMode)anOrderingMode
00572 relativeToEphemeralSubviewNamed:(CPString)relativeToViewName
00573 {
00574 if (!_ephemeralSubviewsForNames)
00575 {
00576 _ephemeralSubviewsForNames = {};
00577 _ephemeralSubviews = [CPSet set];
00578 }
00579
00580 var frame = [self rectForEphemeralSubviewNamed:aViewName];
00581
00582 if (frame && !_CGRectIsEmpty(frame))
00583 {
00584 if (!_ephemeralSubviewsForNames[aViewName])
00585 {
00586 _ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName];
00587
00588 [_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]];
00589
00590 if (_ephemeralSubviewsForNames[aViewName])
00591 [self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]];
00592 }
00593
00594 if (_ephemeralSubviewsForNames[aViewName])
00595 [_ephemeralSubviewsForNames[aViewName] setFrame:frame];
00596 }
00597 else if (_ephemeralSubviewsForNames[aViewName])
00598 {
00599 [_ephemeralSubviewsForNames[aViewName] removeFromSuperview];
00600
00601 [_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]];
00602 delete _ephemeralSubviewsForNames[aViewName];
00603 }
00604
00605 return _ephemeralSubviewsForNames[aViewName];
00606 }
00607
00608 @end
00609
00610 var CPControlValueKey = "CPControlValueKey",
00611 CPControlControlStateKey = @"CPControlControlStateKey",
00612 CPControlIsEnabledKey = "CPControlIsEnabledKey",
00613
00614 CPControlTargetKey = "CPControlTargetKey",
00615 CPControlActionKey = "CPControlActionKey",
00616 CPControlSendActionOnKey = "CPControlSendActionOnKey";
00617
00618 var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
00619
00620 @implementation CPControl (CPCoding)
00621
00622
00623
00624
00625
00626
00627 - (id)initWithCoder:(CPCoder)aCoder
00628 {
00629 self = [super initWithCoder:aCoder];
00630
00631 if (self)
00632 {
00633 [self setObjectValue:[aCoder decodeObjectForKey:CPControlValueKey]];
00634
00635 [self setTarget:[aCoder decodeObjectForKey:CPControlTargetKey]];
00636 [self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
00637
00638 [self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
00639 }
00640
00641 return self;
00642 }
00643
00644
00645
00646
00647
00648 - (void)encodeWithCoder:(CPCoder)aCoder
00649 {
00650 var count = [_subviews count],
00651 ephemeral
00652 subviews = nil;
00653
00654 if (count > 0 && [_ephemeralSubviews count] > 0)
00655 {
00656 subviews = [_subviews.slice(0) copy];
00657
00658 while (count--)
00659 if ([_ephemeralSubviews containsObject:_subviews[count]])
00660 _subviews.splice(count, 1);
00661 }
00662
00663 [super encodeWithCoder:aCoder];
00664
00665 if (subviews)
00666 _subviews = subviews;
00667
00668 if (_value !== nil)
00669 [aCoder encodeObject:_value forKey:CPControlValueKey];
00670
00671 if (_target !== nil)
00672 [aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
00673
00674 if (_action !== NULL)
00675 [aCoder encodeObject:_action forKey:CPControlActionKey];
00676
00677 [aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
00678 }
00679
00680 @end
00681
00682 var _CPControlSizeIdentifiers = [],
00683 _CPControlCachedColorWithPatternImages = {},
00684 _CPControlCachedThreePartImagePattern = {};
00685
00686 _CPControlSizeIdentifiers[CPRegularControlSize] = "Regular";
00687 _CPControlSizeIdentifiers[CPSmallControlSize] = "Small";
00688 _CPControlSizeIdentifiers[CPMiniControlSize] = "Mini";
00689
00690 function _CPControlIdentifierForControlSize(aControlSize)
00691 {
00692 return _CPControlSizeIdentifiers[aControlSize];
00693 }
00694
00695 function _CPControlColorWithPatternImage(sizes, aClassName)
00696 {
00697 var index = 1,
00698 count = arguments.length,
00699 identifier = "";
00700
00701 for (; index < count; ++index)
00702 identifier += arguments[index];
00703
00704 var color = _CPControlCachedColorWithPatternImages[identifier];
00705
00706 if (!color)
00707 {
00708 var bundle = [CPBundle bundleForClass:[CPControl class]];
00709
00710 color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]];
00711
00712 _CPControlCachedColorWithPatternImages[identifier] = color;
00713 }
00714
00715 return color;
00716 }
00717
00718 function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
00719 {
00720 var index = 2,
00721 count = arguments.length,
00722 identifier = "";
00723
00724 for (; index < count; ++index)
00725 identifier += arguments[index];
00726
00727 var color = _CPControlCachedThreePartImagePattern[identifier];
00728
00729 if (!color)
00730 {
00731 var bundle = [CPBundle bundleForClass:[CPControl class]],
00732 path = aClassName + "/" + identifier;
00733
00734 sizes = sizes[identifier];
00735
00736 color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[
00737 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "0.png"] size:sizes[0]],
00738 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]],
00739 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
00740 ] isVertical:isVertical]];
00741
00742 _CPControlCachedThreePartImagePattern[identifier] = color;
00743 }
00744
00745 return color;
00746 }