diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j
index 26b1089d8..c68941af1 100644
--- a/AppKit/CPApplication.j
+++ b/AppKit/CPApplication.j
@@ -474,6 +474,16 @@ CPRunContinuesResponse = -1002;
_mainMenu = aMenu;
}
+- (void)orderFrontStandardAboutPanel:(id)aSender
+{
+ [self orderFrontStandardAboutPanelWithOptions:nil];
+}
+
+- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)aDictionary
+{
+ // FIXME: Implement.
+}
+
// Posting Actions
/*!
Tries to perform the action with an argument. Performs
diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j
index 9317a2992..626ac1e3c 100644
--- a/AppKit/CPButton.j
+++ b/AppKit/CPButton.j
@@ -46,9 +46,9 @@ CPImageOverlaps = 6;
/* @group CPButtonState */
-CPOnState = 1;
-CPOffState = 0;
-CPMixedState = -1;
+CPOnState = 1;
+CPOffState = 0;
+CPMixedState = -1;
/* @group CPBezelStyle */
@@ -70,24 +70,30 @@ CPHUDBezelStyle = -1;
/* @group CPButtonType */
-CPMomentaryLightButton = 0;
-CPPushOnPushOffButton = 1;
-CPToggleButton = 2;
-CPSwitchButton = 3;
-CPRadioButton = 4;
-CPMomentaryChangeButton = 5;
-CPOnOffButton = 6;
-CPMomentaryPushInButton = 7;
-CPMomentaryPushButton = 0;
-CPMomentaryLight = 7;
+CPMomentaryLightButton = 0;
+CPPushOnPushOffButton = 1;
+CPToggleButton = 2;
+CPSwitchButton = 3; // Deprecated, use CPCheckBox instead.
+CPRadioButton = 4; // Deprecated, use CPRadio instead.
+CPMomentaryChangeButton = 5;
+CPOnOffButton = 6;
+CPMomentaryPushInButton = 7;
+CPMomentaryPushButton = 0;
+CPMomentaryLight = 7;
+CPNoButtonMask = 0;
+CPContentsButtonMask = 1;
+CPPushInButtonMask = 2;
+CPGrayButtonMask = 4;
+CPBackgroundButtonMask = 8;
-var CPHUDBezelStyleTextColor = nil;
+CPNoCellMask = CPNoButtonMask;
+CPContentsCellMask = CPContentsButtonMask;
+CPPushInCellMask = CPPushInButtonMask;
+CPChangeGrayCellMask = CPGrayButtonMask;
+CPChangeBackgroundCellMask = CPBackgroundButtonMask;
-var _CPButtonClassName = nil,
- _CPButtonBezelStyleSizes = {},
- _CPButtonBezelStyleIdentifiers = {},
- _CPButtonBezelStyleHighlightedIdentifier = @"Highlighted";
+CPButtonStateMixed = CPThemeState("mixed");
/*! @class CPButton
@@ -97,8 +103,6 @@ var _CPButtonClassName = nil,
*/
@implementation CPButton : CPControl
{
- int _tag;
- int _state;
BOOL _allowsMixedState;
CPString _title;
@@ -107,26 +111,32 @@ var _CPButtonClassName = nil,
CPImage _image;
CPImage _alternateImage;
- // Layout Views
- CPView _bezelView;
- _CPImageAndTextView _contentView;
-
+ CPInteger _showsStateBy;
+ CPInteger _highlightsBy;
+ BOOL _imageDimsWhenDisabled;
+
// NS-style Display Properties
CPBezelStyle _bezelStyle;
- BOOL _isBordered;
CPControlSize _controlSize;
}
+ (id)standardButtonWithTitle:(CPString)aTitle
{
+ var button = [[CPButton alloc] init];
+
+ [button setTitle:aTitle];
+
+ return button;
}
-+ (id)standardCheckboxWithTitle:(CPString)aTitle
++ (id)standardCheckBoxWithTitle:(CPString)aTitle
{
+ return [CPCheckBox standardButtonWithTitle:aTitle];
}
-- (id)standardRadioButtonWithTitle:(CPString)aTitle
+- (id)standardRadioWithTitle:(CPString)aTitle
{
+ return [CPRadio standardButtonWithTitle:aTitle];
}
+ (CPString)themeClass
@@ -176,40 +186,84 @@ var _CPButtonClassName = nil,
*/
- (void)setAllowsMixedState:(BOOL)aFlag
{
+ aFlag = !!aFlag;
+
+ if (_allowsMixedState === aFlag)
+ return;
+
_allowsMixedState = aFlag;
+
+ if (!_allowsMixedState)
+ [self unsetThemeState:CPButtonStateMixed];
}
-/*!
- Sets the button to its next state.
-*/
-- (int)nextState
+- (void)setObjectValue:(id)anObjectValue
{
- if (_state == CPOffState)
- return CPOnState;
- else
- return (_state >= CPOnState && _allowsMixedState) ? CPMixedState : CPOffState;
+ if (!anObjectValue || anObjectValue === @"" || ([anObjectValue intValue] === 0))
+ anObjectValue = CPOffState;
+
+ else if (![anObjectValue isKindOfClass:[CPNumber class]])
+ anObjectValue = CPOnState;
+
+ else if (anObjectValue > CPOnState)
+ anObjectValue = CPOnState
+
+ else if (anObjectValue < CPOffState)
+ if ([self allowsMixedState])
+ anObjectValue = CPMixedState;
+
+ else
+ anObjectValue = CPOnState;
+
+ [super setObjectValue:anObjectValue];
+
+ switch ([self objectValue])
+ {
+ case CPMixedState: [self unsetThemeState:CPThemeStateSelected];
+ [self setThemeState:CPButtonStateMixed];
+ break;
+
+ case CPOnState: [self unsetThemeState:CPButtonStateMixed];
+ [self setThemeState:CPThemeStateSelected];
+ break;
+
+ case CPOffState: [self unsetThemeState:CPThemeStateSelected | CPButtonStateMixed];
+ }
+}
+
+- (CPInteger)nextState
+{
+ if ([self allowsMixedState])
+ {
+ var value = [self state];
+
+ return value - ((value === -1) ? -2 : 1);
+ }
+
+ return 1 - [self state];
}
- (void)setNextState
{
[self setState:[self nextState]];
}
+
/*!
Sets the button's state to aState.
@param aState Possible states are any of the CPButton globals:
CPOffState, CPOnState, CPMixedState
*/
-- (void)setState:(int)aState
+- (void)setState:(CPInteger)aState
{
- _state = aState;
+ [self setIntValue:aState];
}
/*!
Returns the button's current state
*/
-- (int)state
+- (CPInteger)state
{
- return _state;
+ return [self intValue];
}
- (void)setTitle:(CPString)aTitle
@@ -283,32 +337,96 @@ var _CPButtonClassName = nil,
return _alternateImage;
}
-/*!
- Highlights the receiver based on aFlag.
- @param If YES the button will highlight, NO the button will unhighlight.
-*/
-- (void)highlight:(BOOL)aFlag
+- (void)setShowsStateBy:(CPInteger)aMask
{
- [super highlight:aFlag];
-
- [self drawBezelWithHighlight:aFlag];
+ if (_showsStateBy === aMask)
+ return;
+
+ _showsStateBy = aMask;
+
+ [self setNeedsDisplay:YES];
+ [self setNeedsLayout];
}
-/*!
- Sets button's tag.
- @param aTag the button's new tag
-*/
-- (void)setTag:(int)aTag
+- (CPInteger)showsStateBy
{
- _tag = aTag;
+ return _showsStateBy;
}
-/*!
- Returns the button's tag.
-*/
-- (int)tag
+- (void)setHighlightsBy:(CPInteger)aMask
{
- return _tag;
+ if (_highlightsBy === aMask)
+ return;
+
+ _highlightsBy = aMask;
+
+ if ([self hasThemeState:CPThemeStateHighlighted])
+ {
+ [self setNeedsDisplay:YES];
+ [self setNeedsLayout];
+ }
+}
+
+- (void)setButtonType:(CPButtonType)aButtonType
+{
+ switch (buttonType)
+ {
+ case CPMomentaryLightButton: [self setHighlightsBy:CPChangeBackgroundCellMask];
+ [self setShowsStateBy:CPNoCellMask];
+ break;
+
+ case CPMomentaryPushInButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask];
+ [self setShowsStateBy:CPNoCellMask];
+ break;
+
+ case CPMomentaryChangeButton: [self setHighlightsBy:CPContentsCellMask];
+ [self setShowsStateBy:CPNoCellMask];
+ break;
+
+ case CPPushOnPushOffButton: [self setHighlightsBy:CPPushInCellMask | CPChangeGrayCellMask];
+ [self setShowsStateBy:CPChangeBackgroundCellMask];
+ break;
+
+ case CPOnOffButton: [self setHighlightsBy:CPChangeBackgroundCellMask];
+ [self setShowsStateBy:CPChangeBackgroundCellMask];
+ break;
+
+ case CPToggleButton: [self setHighlightsBy:CPPushInCellMask | NSContentsCellMask];
+ [self setShowsStateBy:CPContentsCellMask];
+ break;
+
+ case CPSwitchButton: [CPException raise:CPInvalidArgumentException
+ reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
+
+ case CPRadioButton: [CPException raise:CPInvalidArgumentException
+ reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
+
+ default: [CPException raise:CPInvalidArgumentException
+ reason:"Unknown button type."];
+ }
+
+ [self setImageDimsWhenDisabled:YES];
+}
+
+- (void)setImageDimsWhenDisabled:(BOOL)imageShouldDimWhenDisabled
+{
+ imageShouldDimWhenDisabled = !!imageShouldDimWhenDisabled;
+
+ if (_imageDimsWhenDisabled === imageShouldDimWhenDisabled)
+ return;
+
+ _imageDimsWhenDisabled = imageShouldDimWhenDisabled;
+
+ if (_imageDimsWhenDisabled)
+ {
+ [self setNeedsDisplay:YES];
+ [self setNeedsLayout];
+ }
+}
+
+- (BOOL)imageDimsWhenDisabled
+{
+ return _imageDimsWhenDisabled;
}
- (BOOL)startTrackingAt:(CGPoint)aPoint
@@ -321,35 +439,11 @@ var _CPButtonClassName = nil,
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self highlight:NO];
-
+
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
-}
-/* @ignore */
-- (void)drawBezelWithHighlight:(BOOL)shouldHighlight
-{ return;
- _bezelBorderNeedsUpdate = ![self window];
-
- if (_bezelBorderNeedsUpdate)
- return;
-
- [self setBackgroundColorWithName:shouldHighlight ? CPControlHighlightedBackgroundColor : CPControlNormalBackgroundColor];
-}
-
-- (CPView)createBezelView
-{
- var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
-
- [view setHitTests:NO];
-
- return view;
-}
-
-- (CPView)createContentView
-{
- var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
-
- return view;
+ if (mouseIsUp && CGRectContainsPoint([self bounds], aPoint))
+ [self setNextState];
}
- (CGRect)contentRectForBounds:(CGRect)bounds
@@ -494,15 +588,8 @@ var CPButtonImageKey = @"CPButtonImageKey",
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
- CPButtonContentInsetKey = @"CPButtonContentInsetKey",
- CPButtonBezelInsetKey = @"CPButtonBezelInsetKey",
- CPButtonBezelColorKey = @"CPButtonBezelColorKey",
- CPButtonImageAndTitleViewKey = @"CPButtonImageAndTitleViewKey",
- CPButtonImagePositionKey = @"CPButtonImagePositionKey",
- CPButtonImageScalingKey = @"CPButtonImageScalingKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
- CPButtonBezelStyleKey = @"CPButtonBezelStyleKey",
- CPButtonImageAndTitleViewKey = @"CPButtonImageAndTitleViewKey";
+ CPButtonBezelStyleKey = @"CPButtonBezelStyleKey";
@implementation CPButton (CPCoding)
@@ -549,3 +636,6 @@ var CPButtonImageKey = @"CPButtonImageKey",
}
@end
+
+@import "CPCheckBox.j"
+@import "CPRadio.j"
diff --git a/AppKit/CPCheckBox.j b/AppKit/CPCheckBox.j
new file mode 100644
index 000000000..487c51813
--- /dev/null
+++ b/AppKit/CPCheckBox.j
@@ -0,0 +1,63 @@
+/*
+ * CPCheckBox.j
+ * AppKit
+ *
+ * Created by Francisco Tolmasky.
+ * Copyright 2009, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+@import "CPButton.j"
+
+
+@implementation CPCheckBox : CPButton
+{
+}
+
++ (CPButton)standardButtonWithTitle:(CPString)aTitle
+{
+ var button = [[CPCheckBox alloc] init];
+
+ [button setTitle:aTitle];
+
+ return button;
+}
+
++ (CPString)themeClass
+{
+ return @"check-box";
+}
+
+- (id)initWithFrame:(CGRect)aFrame
+{
+ self = [super initWithFrame:aFrame];
+
+ if (self)
+ {
+ [self setHighlightsBy:CPContentsCellMask];
+ [self setShowsStateBy:CPContentsCellMask];
+
+ // Defaults?
+ [self setImagePosition:CPImageLeft];
+ [self setAlignment:CPLeftTextAlignment];
+
+ [self setBordered:YES];
+ }
+
+ return self;
+}
+
+@end
diff --git a/AppKit/CPMenuItem.j b/AppKit/CPMenuItem.j
index e0d163690..cf32d3241 100644
--- a/AppKit/CPMenuItem.j
+++ b/AppKit/CPMenuItem.j
@@ -113,11 +113,11 @@
{
if ([_menu autoenablesItems])
return;
-
+
_isEnabled = isEnabled;
-
+
[_menuItemView setDirty];
-
+
[_menu itemChanged:self];
}
@@ -686,7 +686,7 @@ CPControlKeyMask
*/
- (void)setView:(CPView)aView
{
- if (_view == aView)
+ if (_view === aView)
return;
_view = aView;
@@ -754,19 +754,23 @@ CPControlKeyMask
var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
CPMenuItemTargetKey = @"CPMenuItemTargetKey",
CPMenuItemActionKey = @"CPMenuItemActionKey",
-
+
CPMenuItemIsEnabledKey = @"CPMenuItemIsEnabledKey",
CPMenuItemIsHiddenKey = @"CPMenuItemIsHiddenKey",
-
+
CPMenuItemTagKey = @"CPMenuItemTagKey",
-
+
CPMenuItemImageKey = @"CPMenuItemImageKey",
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
-
+
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
-
- CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey";
+
+ CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
+ CPMenuItemViewKey = @"CPMenuItemViewKey";
+
+#define DEFAULT_VALUE(aKey, aDefaultValue) [aCoder containsValueForKey:(aKey)] ? [aCoder decodeObjectForKey:(aKey)] : (aDefaultValue)
+#define ENCODE_IFNOT(aKey, aValue, aDefaultValue) if ((aValue) !== (aDefaultValue)) [aCoder encodeObject:(aValue) forKey:(aKey)];
@implementation CPMenuItem (CPCoding)
/*!
@@ -787,22 +791,21 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
_target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
- _isEnabled = [aCoder decodeObjectForKey:CPMenuItemIsEnabledKey];
- _isHidden = [aCoder decodeObjectForKey:CPMenuItemIsHiddenKey];
-
- _tag = [aCoder containsValueForKey:CPMenuItemTagKey] ? [aCoder decodeObjectForKey:CPMenuItemTagKey] : 0;
+ _isEnabled = DEFAULT_VALUE(CPMenuItemIsEnabledKey, YES);
+ _isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
+ _tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
// int _state;
-
- _image = [aCoder decodeObjectForKey:CPMenuItemImageKey];
- _alternateImage = [aCoder decodeObjectForKey:CPMenuItemAlternateImageKey];
+
+ _image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
+ _alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
// CPImage _onStateImage;
// CPImage _offStateImage;
// CPImage _mixedStateImage;
- _submenu = [aCoder decodeObjectForKey:CPMenuItemSubmenuKey];
- _menu = [aCoder decodeObjectForKey:CPMenuItemMenuKey];
-
+ _submenu = DEFAULT_VALUE(CPMenuItemSubmenuKey, nil);
+ _menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
+
// CPString _keyEquivalent;
// unsigned _keyEquivalentModifierMask;
@@ -810,12 +813,11 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
// BOOL _isAlternate;
// int _indentationLevel;
-
+
// CPString _toolTip;
- _representedObject = [aCoder decodeObjectForKey:CPMenuItemRepresentedObjectKey];
-// id _representedObject;
-// CPView _view;
+ _representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
+ _view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
}
return self;
@@ -832,19 +834,19 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
[aCoder encodeObject:_action forKey:CPMenuItemActionKey];
- [aCoder encodeObject:_isEnabled forKey:CPMenuItemIsEnabledKey];
- [aCoder encodeObject:_isHidden forKey:CPMenuItemIsHiddenKey];
+ ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
+ ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO);
- if (_tag !== 0)
- [aCoder encodeObject:_tag forKey:CPMenuItemTagKey];
+ ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0);
- [aCoder encodeObject:_image forKey:CPMenuItemImageKey];
- [aCoder encodeObject:_alternateImage forKey:CPMenuItemAlternateImageKey];
+ ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
+ ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
- [aCoder encodeObject:_submenu forKey:CPMenuItemSubmenuKey];
- [aCoder encodeObject:_menu forKey:CPMenuItemMenuKey];
-
- [aCoder encodeObject:_representedObject forKey:CPMenuItemRepresentedObjectKey];
+ ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
+ ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
+
+ ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);
+ ENCODE_IFNOT(CPMenuItemViewKey, _view, nil)
}
@end
diff --git a/AppKit/CPRadio.j b/AppKit/CPRadio.j
new file mode 100644
index 000000000..a19df54f0
--- /dev/null
+++ b/AppKit/CPRadio.j
@@ -0,0 +1,159 @@
+/*
+ * CPRadio.j
+ * AppKit
+ *
+ * Created by Francisco Tolmasky.
+ * Copyright 2009, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+@import
+@import
+
+@import "CPButton.j"
+
+
+@implementation CPRadio : CPButton
+{
+ CPRadioGroup _radioGroup;
+}
+
++ (CPButton)standardButtonWithTitle:(CPString)aTitle
+{
+ var button = [[CPRadio alloc] init];
+
+ [button setTitle:aTitle];
+
+ return button;
+}
+
++ (CPString)themeClass
+{
+ return @"radio";
+}
+
+// Designated Initializer
+- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
+{
+ self = [super initWithFrame:aFrame];
+
+ if (self)
+ {
+ _radioGroup = aRadioGroup || [CPRadioGroup new];
+
+ [self setHighlightsBy:CPContentsCellMask];
+ [self setShowsStateBy:CPContentsCellMask];
+
+ // Defaults?
+ [self setImagePosition:CPImageLeft];
+ [self setAlignment:CPLeftTextAlignment];
+
+ [self setBordered:YES];
+ }
+
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)aFrame
+{
+ return [self initWithFrame:aFrame radioGroup:nil];
+}
+
+- (CPInteger)nextState
+{
+ return CPOnState;
+}
+
+- (void)setRadioGroup:(CPRadioGroup)aRadioGroup
+{
+ if (_radioGroup === aRadioGroup)
+ return;
+
+ [_radioGroup _removeRadio:self];
+ _radioGroup = aRadioGroup;
+ [_radioGroup _addRadio:self];
+}
+
+- (CPRadioGroup)radioGroup
+{
+ return _radioGroup;
+}
+
+- (void)setObjectValue:(id)aValue
+{
+ [super setObjectValue:aValue];
+
+ if ([self state] === CPOnState)
+ [_radioGroup _setSelectedRadio:self];
+}
+
+@end
+
+@implementation CPRadioGroup : CPObject
+{
+ CPSet _radios;
+ CPRadio _selectedRadio;
+}
+
+- (id)init
+{
+ self = [super init];
+
+ if (self)
+ {
+ _radios = [CPSet set];
+ _selectedRadio = nil;
+ }
+
+ return self;
+}
+
+- (void)_addRadio:(CPRadio)aRadio
+{
+ [_radios addObject:aRadio];
+
+ if ([aRadio state] === CPOnState)
+ [self _setSelectedRadio:aRadio];
+}
+
+- (void)_removeRadio:(CPRadio)aRadio
+{
+ if (_selectedRadio === aRadio)
+ _selectedRadio = nil;
+
+ [_radios removeObject:aRadio];
+}
+
+- (void)_setSelectedRadio:(CPRadio)aRadio
+{
+ if (_selectedRadio === aRadio)
+ return;
+
+ [_selectedRadio setState:CPOffState];
+ _selectedRadio = aRadio;
+}
+
+- (CPRadio)selectedRadio
+{
+ return _selectedRadio;
+}
+
+- (CPArray)radios
+{
+ return [_radios allObjects];
+}
+
+@end
diff --git a/AppKit/CPView.j b/AppKit/CPView.j
index 6db16de7c..b3230a4e6 100644
--- a/AppKit/CPView.j
+++ b/AppKit/CPView.j
@@ -552,11 +552,35 @@ var DOMElementPrototype = nil,
return enclosingMenuItem;*/
}
-- (int)tag
+- (void)setTag:(CPInteger)aTag
+{
+ _tag = aTag;
+}
+
+- (CPInteger)tag
{
return _tag;
}
+- (void)viewWithTag:(CPInteger)aTag
+{
+ if ([self tag] === aTag)
+ return self;
+
+ var index = 0,
+ count = _subviews.length;
+
+ for (; index < count; ++index)
+ {
+ var view = [_subviews[index] viewWithTag:aTag];
+
+ if (view)
+ return view;
+ }
+
+ return nil;
+}
+
/*!
Returns whether the view is flipped.
@return YES if the view is flipped. NO, otherwise.
@@ -1930,6 +1954,11 @@ setBoundsOrigin:
@implementation CPView (Theming)
#pragma mark Theme States
+- (unsigned)themeState
+{
+ return _themeState;
+}
+
- (BOOL)hasThemeState:(CPThemeState)aState
{
return !!(_themeState & ((typeof aState === "string") ? CPThemeState(aState) : aState));
@@ -2192,7 +2221,12 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
_tag = [aCoder decodeIntForKey:CPViewTagKey];
_window = [aCoder decodeObjectForKey:CPViewWindowKey];
- _subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey];
+
+ if ([aCoder containsValueForKey:CPViewSubviewsKey])
+ _subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey];
+ else
+ _subviews = [];
+
_superview = [aCoder decodeObjectForKey:CPViewSuperviewKey];
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || 0;
@@ -2223,7 +2257,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
[self setBackgroundColor:[aCoder decodeObjectForKey:CPViewBackgroundColorKey]];
_theme = [CPTheme defaultTheme];
- _themeState = [aCoder decodeIntForKey:CPViewThemeStateKey];
+ _themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
_themeAttributes = {};
var theClass = [self class],
@@ -2257,14 +2291,17 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
{
[super encodeWithCoder:aCoder];
- if (_tag != -1)
+ if (_tag !== -1)
[aCoder encodeInt:_tag forKey:CPViewTagKey];
[aCoder encodeRect:_frame forKey:CPViewFrameKey];
[aCoder encodeRect:_bounds forKey:CPViewBoundsKey];
[aCoder encodeConditionalObject:_window forKey:CPViewWindowKey];
- [aCoder encodeObject:_subviews forKey:CPViewSubviewsKey];
+
+ if (_subviews.length > 0)
+ [aCoder encodeObject:_subviews forKey:CPViewSubviewsKey];
+
[aCoder encodeConditionalObject:_superview forKey:CPViewSuperviewKey];
[aCoder encodeInt:_autoresizingMask forKey:CPViewAutoresizingMaskKey];
@@ -2281,7 +2318,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
[aCoder encodeConditionalObject:[self nextKeyView] forKey:CPViewNextKeyViewKey];
[aCoder encodeConditionalObject:[self previousKeyView] forKey:CPViewPreviousKeyViewKey];
- [aCoder encodeInt:_themeState forKey:CPViewThemeStateKey];
+ [aCoder encodeInt:CPThemeStateName(_themeState) forKey:CPViewThemeStateKey];
for (var attributeName in _themeAttributes)
if (_themeAttributes.hasOwnProperty(attributeName))
diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-selected.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected.png
new file mode 100644
index 000000000..7d4ee2983
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected.png differ
diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel.png b/AppKit/Themes/Aristo/Resources/check-box-bezel.png
new file mode 100644
index 000000000..d25d8c9d1
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/check-box-bezel.png differ
diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel-selected.png b/AppKit/Themes/Aristo/Resources/radio-bezel-selected.png
new file mode 100644
index 000000000..5987c9d53
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/radio-bezel-selected.png differ
diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel.png b/AppKit/Themes/Aristo/Resources/radio-bezel.png
new file mode 100644
index 000000000..d9b61ad38
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/radio-bezel.png differ
diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j
index 213a59704..4e00f026b 100644
--- a/AppKit/Themes/Aristo/ThemeDescriptors.j
+++ b/AppKit/Themes/Aristo/ThemeDescriptors.j
@@ -7,6 +7,7 @@
*/
@import
+@import
@implementation AristoThemeDescriptor : CPObject
@@ -252,6 +253,42 @@
return button;
}
++ (CPRadioButton)themedRadioButton
+{
+ var button = [[CPRadio alloc] initWithFrame:CGRectMake(0.0, 0.0, 120.0, 17.0)];
+
+ [button setTitle:@"Hello Friend!"];
+
+ var bezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:"radio-bezel.png" size:CGSizeMake(17.0, 17.0)]),
+ bezelColorSelected = PatternColor([_CPCibCustomResource imageResourceWithName:"radio-bezel-selected.png" size:CGSizeMake(17.0, 17.0)]);
+
+ [button setValue:CPLeftTextAlignment forThemeAttribute:@"alignment" inState:CPThemeStateBordered];
+ [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered];
+ [button setValue:CGInsetMake(0.0, 0.0, 0.0, 20.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered];
+ [button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
+ [button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected];
+
+ return button;
+}
+
++ (CPRadioButton)themedCheckBoxButton
+{
+ var button = [[CPCheckBox alloc] initWithFrame:CGRectMake(0.0, 0.0, 120.0, 17.0)];
+
+ [button setTitle:@"Another option"];
+
+ var bezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:"check-box-bezel.png" size:CGSizeMake(15.0, 15.0)]),
+ bezelColorSelected = PatternColor([_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected.png" size:CGSizeMake(15.0, 16.0)]);
+
+ [button setValue:CPLeftTextAlignment forThemeAttribute:@"alignment" inState:CPThemeStateBordered];
+ [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered];
+ [button setValue:CGInsetMake(0.0, 0.0, 0.0, 20.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered];
+ [button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
+ [button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected];
+
+ return button;
+}
+
+ (CPPopUpButton)themedPopUpButton
{
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0) pullsDown:NO],
diff --git a/External/Rakefile b/External/Rakefile
index 5b31563f4..d976681e0 100644
--- a/External/Rakefile
+++ b/External/Rakefile
@@ -29,6 +29,15 @@ file_d $ENVIRONMENT_JACK_PRODUCT => [$ENVIRONMENT_NARWHAL_PRODUCT] do
cp_r('jack', $ENVIRONMENT_JACK_PRODUCT)
end
-task :build => [$ENVIRONMENT_NARWHAL_PRODUCT, $ENVIRONMENT_BROWSERJS_PRODUCT, $ENVIRONMENT_JACK_PRODUCT, $ENVIRONMENT_NARWHAL_EXECUTABLE]
+task :update_submodules do
+ if executable_exists? "git"
+ system %{cd .. && git submodule update --init}
+ else
+ puts "Git not installed"
+ rake abort
+ end
+end
+
+task :build => [:update_submodules, $ENVIRONMENT_NARWHAL_PRODUCT, $ENVIRONMENT_BROWSERJS_PRODUCT, $ENVIRONMENT_JACK_PRODUCT, $ENVIRONMENT_NARWHAL_EXECUTABLE]
CLOBBER.include($ENVIRONMENT_NARWHAL_PRODUCT, $ENVIRONMENT_BROWSERJS_PRODUCT, $ENVIRONMENT_JACK_PRODUCT, $ENVIRONMENT_NARWHAL_EXECUTABLE)
diff --git a/Rakefile b/Rakefile
index 299f83a79..2ae19fb41 100644
--- a/Rakefile
+++ b/Rakefile
@@ -72,12 +72,12 @@ file_d $STARTER_DOWNLOAD_README => [$STARTER_README] do
end
task :install => [:downloads] do
- if ENV['prefix']
- prefix = "--prefix #{ENV['prefix']}"
- else
- prefix = ''
- end
- system %{cd #{$TOOLS_DOWNLOAD} && sudo sh ./install-tools #{prefix} }
+ if ENV['prefix']
+ prefix = "--prefix #{ENV['prefix']}"
+ else
+ prefix = ''
+ end
+ system %{cd #{$TOOLS_DOWNLOAD} && sudo sh ./install-tools #{prefix} }
end
task :test => [:build] do
@@ -101,12 +101,12 @@ task :docs do
end
task :submodules do
- if executable_exists? "git"
- system %{git submodule init}
- system %{git submodule update}
- else
- puts "Git not installed"
- end
+ if executable_exists? "git"
+ system %{cd .. && git submodule update --init}
+ else
+ puts "Git not installed"
+ rake abort
+ end
end
=begin