From aebbdbe0a335a7ae8b7bbeb5cc7f39062482d4b0 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sat, 23 May 2009 12:33:24 -0700 Subject: [PATCH] Fixed a few graphics bugs and made the automatically generated theme gallery nicer. Reviewed by me. --- AppKit/CPApplication.j | 5 + AppKit/CPPopUpButton.j | 2 +- AppKit/Themes/Aristo/ThemeDescriptors.j | 250 ++++++----- AppKit/Tools/BlendKit/BKShowcaseController.j | 392 ++++++++++++++---- AppKit/Tools/BlendKit/BKThemeDescriptor.j | 200 +++++++++ AppKit/Tools/BlendKit/BKUtilities.j | 91 ---- AppKit/Tools/BlendKit/BlendKit.j | 1 + .../BlendKit/Resources/dark-checkers.png | Bin 0 -> 131 bytes .../BlendKit/Resources/light-checkers.png | Bin 0 -> 3471 bytes AppKit/Tools/BlendKit/Resources/selection.png | Bin 0 -> 4090 bytes 10 files changed, 648 insertions(+), 293 deletions(-) create mode 100644 AppKit/Tools/BlendKit/BKThemeDescriptor.j create mode 100644 AppKit/Tools/BlendKit/Resources/dark-checkers.png create mode 100644 AppKit/Tools/BlendKit/Resources/light-checkers.png create mode 100644 AppKit/Tools/BlendKit/Resources/selection.png diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index de8572111..012cc2ffb 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -476,6 +476,11 @@ CPRunContinuesResponse = -1002; _mainMenu = aMenu; } +- (void)orderFrontColorPanel:(id)aSender +{ + [[CPColorPanel sharedColorPanel] orderFront:self]; +} + - (void)orderFrontStandardAboutPanel:(id)aSender { [self orderFrontStandardAboutPanelWithOptions:nil]; diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index eeaa785b7..acaecb870 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -502,7 +502,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { if ([self title] === aTitle) return; - + if ([self pullsDown]) { var items = [_menu itemArray]; diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index 06588e24f..f5ecf0d27 100644 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -10,7 +10,7 @@ @import -@implementation AristoThemeDescriptor : CPObject +@implementation AristoThemeDescriptor : BKThemeDescriptor { } @@ -19,6 +19,137 @@ return @"Aristo"; } ++ (CPButton)button +{ + var button = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 24.0)], + + bezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]], + + highlightedBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]], + + defaultBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"default-button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"default-button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"default-button-bezel-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]], + + defaultHighlightedBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]]; + + [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered]; + [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateBordered]; + [button setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateBordered]; + [button setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"]; + + [button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; + [button setValue:highlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted]; + [button setValue:CGInsetMake(0.0, 5.0, 0.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; + + [button setValue:defaultBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateDefault]; + [button setValue:defaultHighlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted|CPThemeStateDefault]; + [button setValue:[CPColor colorWithCalibratedRed:13.0/255.0 green:51.0/255.0 blue:70.0/255.0 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDefault]; + + [button setValue:CGSizeMake(0.0, 24.0) forThemeAttribute:@"min-size"]; + [button setValue:CGSizeMake(-1.0, 24.0) forThemeAttribute:@"max-size"]; + + return button; +} + ++ (CPButton)themedStandardButton +{ + var button = [self button]; + + [button setTitle:@"Cancel"]; + + return button; +} + ++ (CPButton)themedDefaultButton +{ + var button = [self button]; + + [button setTitle:@"OK"]; + [button setDefaultButton:YES]; + + return button; +} + ++ (CPPopUpButton)themedPopUpButton +{ + var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0) pullsDown:NO], + color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"popup-bezel-right.png" size:CGSizeMake(27.0, 24.0)] + ] + isVertical:NO]]; + + [button setTitle:@"Pop Up"]; + + [button setValue:color forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; + [button setValue:CGInsetMake(0, 27.0 + 5.0, 0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; + [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font"]; + [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color"]; + [button setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset"]; + + [button setValue:CGSizeMake(32.0, 24.0) forThemeAttribute:@"min-size"]; + [button setValue:CGSizeMake(-1.0, 24.0) forThemeAttribute:@"max-size"]; + + [button addItemWithTitle:@"item"]; + + return button; +} + ++ (CPPopUpButton)themedPullDownMenu +{ + var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0) pullsDown:YES], + color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"popup-bezel-right-pullsdown.png" size:CGSizeMake(27.0, 24.0)] + ] + isVertical:NO]]; + + [button setTitle:@"Pull Down"]; + + [button setValue:color forThemeAttribute:@"bezel-color" inState:CPPopUpButtonStatePullsDown|CPThemeStateBordered]; + [button setValue:CGInsetMake(0, 27.0 + 5.0, 0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; + [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font"]; + [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color"]; + [button setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset"]; + + [button setValue:CGSizeMake(32.0, 24.0) forThemeAttribute:@"min-size"]; + [button setValue:CGSizeMake(-1.0, 24.0) forThemeAttribute:@"max-size"]; + + [button addItemWithTitle:@"item"]; + + return button; +} + + (CPScroller)themedVerticalScroller { var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 17.0, 170.0)], @@ -69,11 +200,11 @@ { var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 170.0, 17.0)], trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-horizontal-track.png" size:CGSizeMake(1.0, 17.0)]), - disabledTrackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track-disabled.png" size:CGSizeMake(17.0, 1.0)]); + disabledTrackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-horizontal-track-disabled.png" size:CGSizeMake(17.0, 1.0)]); [scroller setValue:19.0 forThemeAttribute:@"minimum-knob-length"]; [scroller setValue:CGInsetMake(2.0, 0.0, 0.0, 0.0) forThemeAttribute:@"knob-inset"]; - [scroller setValue:CGInsetMake(0.0, -9.0, 0.0, -11.0) forThemeAttribute:@"track-inset"]; + [scroller setValue:CGInsetMake(0.0, -10.0, 0.0, -11.0) forThemeAttribute:@"track-inset"]; [scroller setValue:trackColor forThemeAttribute:@"knob-slot-color"]; [scroller setValue:disabledTrackColor forThemeAttribute:@"knob-slot-color" inState:CPThemeStateDisabled]; @@ -200,65 +331,6 @@ return textfield; } -+ (CPButton)themedButton -{ - var button = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 24.0)], - - bezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: - [ - [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"button-bezel-right.png" size:CGSizeMake(4.0, 24.0)] - ] - isVertical:NO]], - - highlightedBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: - [ - [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] - ] - isVertical:NO]], - - defaultBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: - [ - [_CPCibCustomResource imageResourceWithName:"default-button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"default-button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"default-button-bezel-right.png" size:CGSizeMake(4.0, 24.0)] - ] - isVertical:NO]], - - defaultHighlightedBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: - [ - [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] - ] - isVertical:NO]]; - - - [button setTitle:@"Cancel"]; - - [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered]; - [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; - [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateBordered]; - [button setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateBordered]; - [button setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"]; - - [button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; - [button setValue:highlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted]; - [button setValue:CGInsetMake(0.0, 5.0, 0.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; - - [button setValue:defaultBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateDefault]; - [button setValue:defaultHighlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted|CPThemeStateDefault]; - [button setValue:[CPColor colorWithCalibratedRed:13.0/255.0 green:51.0/255.0 blue:70.0/255.0 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDefault]; - - [button setValue:CGSizeMake(0.0, 24.0) forThemeAttribute:@"min-size"]; - [button setValue:CGSizeMake(-1.0, 24.0) forThemeAttribute:@"max-size"]; - - return button; -} - + (CPRadioButton)themedRadioButton { var button = [[CPRadio alloc] initWithFrame:CGRectMake(0.0, 0.0, 120.0, 17.0)]; @@ -315,56 +387,6 @@ return button; } -+ (CPPopUpButton)themedPopUpButton -{ - var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0) pullsDown:NO], - color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: - [ - [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"popup-bezel-right.png" size:CGSizeMake(27.0, 24.0)] - ] - isVertical:NO]]; - - [button setTitle:@"Pop Up"]; - - [button setValue:color forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; - [button setValue:CGInsetMake(0, 27.0 + 5.0, 0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; - [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font"]; - [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; - [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color"]; - [button setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset"]; - - [button addItemWithTitle:@"item"]; - - return button; -} - -+ (CPPopUpButton)themedPullDownMenu -{ - var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0) pullsDown:YES], - color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: - [ - [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], - [_CPCibCustomResource imageResourceWithName:"popup-bezel-right-pullsdown.png" size:CGSizeMake(27.0, 24.0)] - ] - isVertical:NO]]; - - [button setTitle:@"Pop Up"]; - - [button setValue:color forThemeAttribute:@"bezel-color" inState:CPPopUpButtonStatePullsDown|CPThemeStateBordered]; - [button setValue:CGInsetMake(0, 27.0 + 5.0, 0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; - [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font"]; - [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; - [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color"]; - [button setValue:CGSizeMake(0.0, 1.0) forThemeAttribute:@"text-shadow-offset"]; - - [button addItemWithTitle:@"item"]; - - return button; -} - + (CPPopUpButton)themedSegmentedControl { var segmentedControl = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 24.0)]; @@ -527,7 +549,7 @@ @end -@implementation AristoHUDThemeDescriptor : CPObject +@implementation AristoHUDThemeDescriptor : BKThemeDescriptor { } @@ -536,7 +558,7 @@ return @"Aristo-HUD"; } -+ (CPColor)themeShowcaseBackgroundColor ++ (CPColor)defaultShowcaseBackgroundColor { return [CPColor blackColor]; } diff --git a/AppKit/Tools/BlendKit/BKShowcaseController.j b/AppKit/Tools/BlendKit/BKShowcaseController.j index 4b5a15fa3..623aba85f 100644 --- a/AppKit/Tools/BlendKit/BKShowcaseController.j +++ b/AppKit/Tools/BlendKit/BKShowcaseController.j @@ -5,108 +5,344 @@ @import "BKUtilities.j" +var LEFT_PANEL_WIDTH = 176.0; + +var BKStateToolbarItemIdentifier = @"BKStateToolbarItemIdentifier", + BKBackgroundColorToolbarItemIdentifier = @"BKBackgroundColorToolbarItemIdentifier"; + @implementation BKShowcaseController : CPObject { + CPArray _themeDescriptorClasses; + + CPCollectionView _themesCollectionView; + CPCollectionView _themedObjectsCollectionView; } - (void)applicationDidFinishLaunching:(CPNotification)aNotification { + _themeDescriptorClasses = [BKThemeDescriptor allThemeDescriptorClasses]; + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], - contentView = [theWindow contentView], + toolbar = [[CPToolbar alloc] initWithIdentifier:@"Toolbar"]; + + [toolbar setDelegate:self]; + [theWindow setToolbar:toolbar]; + + var contentView = [theWindow contentView], bounds = [contentView bounds], - themeDescriptorClasses = BKThemeDescriptorClasses(); - - var tabView = [[CPTabView alloc] initWithFrame:bounds]; - - [tabView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; - - [contentView addSubview:tabView]; - - var index = 0, - count = [themeDescriptorClasses count]; - - for (; index < count; ++index) + splitView = [[CPSplitView alloc] initWithFrame:bounds]; + + [splitView setIsPaneSplitter:YES]; + [splitView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + + [contentView addSubview:splitView]; + + // Left Pane + var label = [CPTextField labelWithTitle:@"THEMES"]; + + [label setFont:[CPFont boldSystemFontOfSize:11.0]]; + [label setTextColor:[CPColor colorWithCalibratedRed:92.0 / 255.0 green:110.0 / 255.0 blue:129.0 / 255.0 alpha:1.0]]; + [label setTextShadowColor:[CPColor colorWithCalibratedRed:225.0 / 255.0 green:255.0 / 255.0 blue:255.0 / 255.0 alpha:0.7]]; + [label setTextShadowOffset:CGSizeMake(0.0, 1.0)]; + [label sizeToFit]; + [label setFrameOrigin:CGPointMake(5.0, 2.0)]; + + var themeDescriptorItem = [[CPCollectionViewItem alloc] init]; + + [themeDescriptorItem setView:[[BKThemeDescriptorCell alloc] init]]; + + _themesCollectionView = [[CPCollectionView alloc] initWithFrame:CGRectMake(0.0, 0.0, LEFT_PANEL_WIDTH, CGRectGetHeight(bounds))]; + + [_themesCollectionView setDelegate:self]; + [_themesCollectionView setItemPrototype:themeDescriptorItem]; + [_themesCollectionView setMinItemSize:CGSizeMake(20.0, 36.0)]; + [_themesCollectionView setMaxItemSize:CGSizeMake(10000000.0, 36.0)]; + [_themesCollectionView setMaxNumberOfColumns:1]; + [_themesCollectionView setContent:_themeDescriptorClasses]; + [_themesCollectionView setAutoresizingMask:CPViewWidthSizable]; + [_themesCollectionView setVerticalMargin:0.0]; + [_themesCollectionView setSelectable:YES]; + [_themesCollectionView setFrameOrigin:CGPointMake(0.0, 20.0)]; + [_themesCollectionView setAutoresizingMask:CPViewWidthSizable]; + + var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, LEFT_PANEL_WIDTH, CGRectGetHeight(bounds))], + contentView = [scrollView contentView]; + + [scrollView setAutohidesScrollers:YES]; + [scrollView setDocumentView:_themesCollectionView]; + + [contentView setBackgroundColor:[CPColor colorWithRed:212.0 / 255.0 green:221.0 / 255.0 blue:230.0 / 255.0 alpha:1.0]]; + [contentView addSubview:label]; + + [splitView addSubview:scrollView]; + + // Right Pane + _themedObjectsCollectionView = [[CPCollectionView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds) - LEFT_PANEL_WIDTH - 1.0, 10.0)]; + + var collectionViewItem = [[CPCollectionViewItem alloc] init]; + + [collectionViewItem setView:[[BKShowcaseCell alloc] init]]; + + [_themedObjectsCollectionView setItemPrototype:collectionViewItem]; + [_themedObjectsCollectionView setVerticalMargin:20.0]; + [_themedObjectsCollectionView setAutoresizingMask:CPViewWidthSizable]; + + var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(LEFT_PANEL_WIDTH + 1.0, 0.0, CGRectGetWidth(bounds) - LEFT_PANEL_WIDTH - 1.0, CGRectGetHeight(bounds))]; + + [scrollView setHasHorizontalScroller:NO]; + [scrollView setAutohidesScrollers:YES]; + [scrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + [scrollView setDocumentView:_themedObjectsCollectionView]; + + [splitView addSubview:scrollView]; + + [_themesCollectionView setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]]; + + [theWindow setFullBridge:YES]; + [theWindow makeKeyAndOrderFront:self]; +} + +- (void)collectionViewDidChangeSelection:(CPCollectionView)aCollectionView +{ + var themeDescriptorClass = _themeDescriptorClasses[[[aCollectionView selectionIndexes] firstIndex]], + itemSize = [themeDescriptorClass itemSize]; + + // Make room for label and apply a minimum size. + itemSize.width = MAX(100.0, itemSize.width + 20.0); + itemSize.height = MAX(100.0, itemSize.height + 30.0); + + [_themedObjectsCollectionView setMinItemSize:itemSize]; + [_themedObjectsCollectionView setMaxItemSize:itemSize]; + + [_themedObjectsCollectionView setContent:[themeDescriptorClass themedObjectTemplates]]; + [BKShowcaseCell setBackgroundColor:[themeDescriptorClass showcaseBackgroundColor]]; +} + +- (CPArray)toolbarAllowedItemIdentifiers:(CPToolbar)aToolbar +{ + return [CPToolbarSpaceItemIdentifier, CPToolbarFlexibleSpaceItemIdentifier, BKBackgroundColorToolbarItemIdentifier, BKStateToolbarItemIdentifier]; +} + +- (CPArray)toolbarDefaultItemIdentifiers:(CPToolbar)aToolbar +{ + return [CPToolbarFlexibleSpaceItemIdentifier, BKBackgroundColorToolbarItemIdentifier, BKStateToolbarItemIdentifier]; +} + +- (CPToolbarItem)toolbar:(CPToolbar)aToolbar itemForItemIdentifier:(CPString)anItemIdentifier willBeInsertedIntoToolbar:(BOOL)aFlag +{ + var toolbarItem = [[CPToolbarItem alloc] initWithItemIdentifier:anItemIdentifier]; + + [toolbarItem setTarget:self]; + + if (anItemIdentifier === BKStateToolbarItemIdentifier) { - var theClass = themeDescriptorClasses[index], - item = [[CPTabViewItem alloc] initWithIdentifier:[theClass themeName]], - templates = BKThemeObjectTemplatesForClass(theClass), - templatesCount = [templates count], - viewTemplates = [], - itemSize = CGSizeMake(0.0, 0.0); - - while (templatesCount--) - { - var template = templates[templatesCount], - object = [template valueForKey:@"themedObject"]; + var popUpButton = [CPPopUpButton buttonWithTitle:@"Enabled"]; - if ([object isKindOfClass:[CPView class]]) - { - var size = [object frame].size, - labelWidth = [[template valueForKey:@"label"] sizeWithFont:[CPFont boldSystemFontOfSize:12.0]].width + 20.0; + [popUpButton addItemWithTitle:@"Disabled"]; - if (size.width > itemSize.width) - itemSize.width = size.width; - - if (labelWidth > itemSize.width) - itemSize.width = labelWidth; - - if (size.height > itemSize.height) - itemSize.height = size.height; - - [viewTemplates addObject:template]; - } - } - - itemSize.width += 20.0; - itemSize.height += 30.0; + [toolbarItem setView:popUpButton]; + [toolbarItem setTarget:nil]; + [toolbarItem setAction:@selector(changeState:)]; + [toolbarItem setLabel:@"State"]; - var collectionView = [[CPCollectionView alloc] initWithFrame:CGRectMakeZero()], - collectionViewItem = [[CPCollectionViewItem alloc] init]; + var width = CGRectGetWidth([popUpButton frame]); - var backgroundColor = nil; + [toolbarItem setMinSize:CGSizeMake(width + 20.0, 32.0)]; + [toolbarItem setMaxSize:CGSizeMake(width + 20.0, 32.0)]; + } + + else if (BKBackgroundColorToolbarItemIdentifier) + { + var popUpButton = [CPPopUpButton buttonWithTitle:@"Light Checkers"]; - if ([theClass respondsToSelector:@selector(themeShowcaseBackgroundColor)]) - backgroundColor = [theClass themeShowcaseBackgroundColor]; + [popUpButton addItemWithTitle:@"Dark Checkers"]; + [popUpButton addItemWithTitle:@"Window Background Color"]; + [popUpButton addItemWithTitle:@"White"]; + [popUpButton addItemWithTitle:@"Black"]; + [popUpButton addItemWithTitle:@"More Choices..."]; - [collectionViewItem setView:[[BKShowcaseCell alloc] initWithShowcaseBackgroundColor:backgroundColor]]; + var itemArray = [popUpButton itemArray]; - [collectionView setItemPrototype:collectionViewItem]; - [collectionView setMinItemSize:itemSize]; - [collectionView setMaxItemSize:itemSize]; - [collectionView setVerticalMargin:5.0]; - [collectionView setContent:viewTemplates]; - - [item setLabel:[theClass themeName]]; - [item setView:collectionView]; + [itemArray[0] setRepresentedObject:[BKThemeDescriptor lightCheckersColor]]; + [itemArray[1] setRepresentedObject:[BKThemeDescriptor darkCheckersColor]]; + [itemArray[2] setRepresentedObject:[BKThemeDescriptor windowBackgroundColor]]; + [itemArray[3] setRepresentedObject:[CPColor whiteColor]]; + [itemArray[4] setRepresentedObject:[CPColor blackColor]]; - [tabView addTabViewItem:item]; + [toolbarItem setView:popUpButton]; + [toolbarItem setTarget:nil]; + [toolbarItem setAction:@selector(changeColor:)]; + [toolbarItem setLabel:@"Background Color"]; + + var width = CGRectGetWidth([popUpButton frame]); + + [toolbarItem setMinSize:CGSizeMake(width, 32.0)]; + [toolbarItem setMaxSize:CGSizeMake(width, 32.0)]; } - [theWindow orderFront:self]; + return toolbarItem; +} + +- (BKThemeDescriptor)selectedThemeDescriptor +{ + return _themeDescriptorClasses[[[_themesCollectionView selectionIndexes] firstIndex]]; +} + +- (void)changeState:(id)aSender +{ + var themedObjectTemplates = [[self selectedThemeDescriptor] themedObjectTemplates], + count = [themedObjectTemplates count]; + + while (count--) + { + var themedObject = [themedObjectTemplates[count] valueForKey:@"themedObject"]; + + if ([themedObject respondsToSelector:@selector(setEnabled:)]) + [themedObject setEnabled:[aSender title] === @"Enabled" ? YES : NO]; + } +} + +- (void)changeColor:(id)aSender +{ + var color = nil; + + if ([aSender isKindOfClass:[CPColorPanel class]]) + color = [aSender color]; + + else + { + if ([aSender titleOfSelectedItem] === @"More Choices...") + { + [aSender addItemWithTitle:@"Other"]; + [aSender selectItemWithTitle:@"Other"]; + + [CPApp orderFrontColorPanel:self]; + } + else + { + color = [[aSender selectedItem] representedObject]; + + [aSender removeItemWithTitle:@"Other"]; + } + } + + if (color) + { + [[self selectedThemeDescriptor] setShowcaseBackgroundColor:color]; + [BKShowcaseCell setBackgroundColor:color]; + } +} + +@end + +var SelectionColor = nil; + +@implementation BKThemeDescriptorCell : CPView +{ + CPTextField _label; +} + ++ (CPImage)selectionColor +{ + if (!SelectionColor) + SelectionColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[BKThemeDescriptorCell class]] pathForResource:@"selection.png"] size:CGSizeMake(1.0, 36.0)]]; + + return SelectionColor; +} + +- (void)setRepresentedObject:(id)aThemeDescriptor +{ + if (!_label) + { + _label = [CPTextField labelWithTitle:@"hello"]; + + [_label setFont:[CPFont systemFontOfSize:11.0]]; + [_label setFrame:CGRectMake(10.0, 0.0, CGRectGetWidth([self bounds]) - 20.0, CGRectGetHeight([self bounds]))]; + + [_label setVerticalAlignment:CPCenterVerticalTextAlignment]; + [_label setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + + [self addSubview:_label]; + } + + [_label setStringValue:[aThemeDescriptor themeName] + " (" + [[aThemeDescriptor themedObjectTemplates] count] + ")"]; +} + +- (void)setSelected:(BOOL)isSelected +{ + [self setBackgroundColor:isSelected ? [[self class] selectionColor] : nil]; + + [_label setTextShadowOffset:isSelected ? CGSizeMake(0.0, 1.0) : CGSizeMakeZero()]; + [_label setTextShadowColor:isSelected ? [CPColor blackColor] : nil]; + [_label setFont:isSelected ? [CPFont boldSystemFontOfSize:11.0] : [CPFont systemFontOfSize:11.0]]; + [_label setTextColor:isSelected ? [CPColor whiteColor] : [CPColor blackColor]]; } @end +var ShowcaseCellBackgroundColor = nil; + +var BKShowcaseCellBackgroundColorDidChangeNotification = @"BKShowcaseCellBackgroundColorDidChangeNotification"; + @implementation BKShowcaseCell : CPView { - CPColor _showcaseBackgroundColor; CPView _backgroundView; CPView _view; CPTextField _label; } -- (id)initWithShowcaseBackgroundColor:(CPColor)aColor ++ (void)setBackgroundColor:(CPColor)aColor +{ + if (ShowcaseCellBackgroundColor === aColor) + return; + + ShowcaseCellBackgroundColor = aColor; + + [[CPNotificationCenter defaultCenter] + postNotificationName:BKShowcaseCellBackgroundColorDidChangeNotification + object:nil]; +} + ++ (CPColor)backgroundColor +{ + return ShowcaseCellBackgroundColor; +} + +- (id)init { self = [super init]; if (self) - _showcaseBackgroundColor = aColor; + [[CPNotificationCenter defaultCenter] + addObserver:self + selector:@selector(showcaseBackgroundDidChange:) + name:BKShowcaseCellBackgroundColorDidChangeNotification + object:nil]; return self; } +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super initWithCoder:aCoder]; + + if (self) + [[CPNotificationCenter defaultCenter] + addObserver:self + selector:@selector(showcaseBackgroundDidChange:) + name:BKShowcaseCellBackgroundColorDidChangeNotification + object:nil]; + + return self; +} + +- (void)showcaseBackgroundDidChange:(CPNotification)aNotification +{ + [_backgroundView setBackgroundColor:[BKShowcaseCell backgroundColor]]; +} + - (void)setSelected:(BOOL)isSelected { } @@ -116,26 +352,24 @@ if (!_label) { _label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; - + [_label setAlignment:CPCenterTextAlignment]; [_label setAutoresizingMask:CPViewMinYMargin | CPViewWidthSizable]; - [_label setFont:[CPFont boldSystemFontOfSize:12.0]]; - + [_label setFont:[CPFont boldSystemFontOfSize:11.0]]; + [self addSubview:_label]; } - + [_label setStringValue:[anObject valueForKey:@"label"]]; [_label sizeToFit]; - + [_label setFrame:CGRectMake(0.0, CGRectGetHeight([self bounds]) - CGRectGetHeight([_label frame]), CGRectGetWidth([self bounds]), CGRectGetHeight([_label frame]))]; - + if (!_backgroundView) { _backgroundView = [[CPView alloc] init]; - [_backgroundView setBackgroundColor:_showcaseBackgroundColor]; - [self addSubview:_backgroundView]; } @@ -153,23 +387,7 @@ (CGRectGetHeight([_backgroundView bounds]) - CGRectGetHeight([_view frame])) / 2.0)]; [_backgroundView addSubview:_view]; -} - -- (id)initWithCoder:(CPCoder)aCoder -{ - self = [super initWithCoder:aCoder]; - - if (self) - _showcaseBackgroundColor = [aCoder decodeObjectForKey:@"showcase-background-color"]; - - return self -} - -- (void)encodeWithCoder:(CPCoder)aCoder -{ - [super encodeWithCoder:aCoder]; - - [aCoder encodeObject:_showcaseBackgroundColor forKey:@"showcase-background-color"]; + [_backgroundView setBackgroundColor:[BKShowcaseCell backgroundColor]]; } @end diff --git a/AppKit/Tools/BlendKit/BKThemeDescriptor.j b/AppKit/Tools/BlendKit/BKThemeDescriptor.j new file mode 100644 index 000000000..fde4743fd --- /dev/null +++ b/AppKit/Tools/BlendKit/BKThemeDescriptor.j @@ -0,0 +1,200 @@ + +@import + + +var ItemSizes = { }, + ThemedObjects = { }, + BackgroundColors = { }, + + LightCheckersColor = nil, + DarkCheckersColor = nil, + WindowBackgroundColor = nil; + +@implementation BKThemeDescriptor : CPObject +{ +} + ++ (CPArray)allThemeDescriptorClasses +{ + // Grab Theme Descriptor Classes. + var themeDescriptorClasses = []; + + for (candidate in window) + { + var theClass = objj_getClass(candidate), + theClassName = class_getName(theClass); + + if (theClassName === "BKThemeDescriptor") + continue; + + var index = theClassName.indexOf("ThemeDescriptor"); + + if ((index >= 0) && (index === theClassName.length - "ThemeDescriptor".length)) + themeDescriptorClasses.push(theClass); + } + + [themeDescriptorClasses sortUsingSelector:@selector(compare:)]; + + return themeDescriptorClasses; +} + ++ (CPColor)lightCheckersColor +{ + if (!LightCheckersColor) + LightCheckersColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[BKThemeDescriptor class]] pathForResource:@"light-checkers.png"] size:CGSizeMake(12.0, 12.0)]]; + + return LightCheckersColor; +} + ++ (CPColor)darkCheckersColor +{ + if (!DarkCheckersColor) + DarkCheckersColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[BKThemeDescriptor class]] pathForResource:@"dark-checkers.png"] size:CGSizeMake(12.0, 12.0)]]; + + return DarkCheckersColor; +} + ++ (CPColor)windowBackgroundColor +{ + return [_CPStandardWindowView bodyBackgroundColor]; +} + ++ (CPColor)defaultShowcaseBackgroundColor +{ + return [self lightCheckersColor]; +} + ++ (CPColor)showcaseBackgroundColor +{ + var className = [self className]; + + if (!BackgroundColors[className]) + BackgroundColors[className] = [self defaultShowcaseBackgroundColor]; + + return BackgroundColors[className]; +} + ++ (void)setShowcaseBackgroundColor:(CPColor)aColor +{ + BackgroundColors[[self className]] = aColor; +} + ++ (CGSize)itemSize +{ + var className = [self className]; + + if (!ItemSizes[className]) + [self calculateThemedObjectTemplates]; + + return CGSizeMakeCopy(ItemSizes[className]); +} + ++ (CPArray)themedObjectTemplates +{ + var className = [self className]; + + if (!ThemedObjects[className]) + [self calculateThemedObjectTemplates]; + + return ThemedObjects[className]; +} + ++ (void)calculateThemedObjectTemplates +{ + var templates = [], + itemSize = CGSizeMake(0.0, 0.0), + methods = class_copyMethodList([self class].isa), + index = 0, + count = [methods count]; + + for (; index < count; ++index) + { + var method = methods[index], + selector = method_getName(method); + + if (selector.indexOf("themed") !== 0) + continue; + + var impl = method_getImplementation(method), + object = impl(self, selector); + + if (!object) + continue; + + var template = [[BKThemeObjectTemplate alloc] init]; + + [template setValue:object forKey:@"themedObject"]; + [template setValue:BKLabelFromIdentifier(selector) forKey:@"label"]; + + [templates addObject:template]; + + if ([object isKindOfClass:[CPView class]]) + { + var size = [object frame].size, + labelWidth = [[template valueForKey:@"label"] sizeWithFont:[CPFont boldSystemFontOfSize:12.0]].width + 20.0; + + if (size.width > itemSize.width) + itemSize.width = size.width; + + if (labelWidth > itemSize.width) + itemSize.width = labelWidth; + + if (size.height > itemSize.height) + itemSize.height = size.height; + } + } + + var className = [self className]; + + ItemSizes[className] = itemSize; + ThemedObjects[className] = templates; +} + ++ (int)compare:(BKThemeDescriptor)aThemeDescriptor +{ + return [[self themeName] compare:[aThemeDescriptor themeName]]; +} + +@end + +function BKLabelFromIdentifier(anIdentifier) +{ + var string = anIdentifier.substr("themed".length); + index = 0, + count = string.length, + label = "", + lastCapital = null, + isLeadingCapital = YES; + + for (; index < count; ++index) + { + var character = string.charAt(index), + isCapital = /^[A-Z]/.test(character); + + if (isCapital) + { + if (!isLeadingCapital) + { + if (lastCapital === null) + label += ' ' + character.toLowerCase(); + else + label += character; + } + + lastCapital = character; + } + else + { + if (isLeadingCapital && lastCapital !== null) + label += lastCapital; + + label += character; + + lastCapital = null; + isLeadingCapital = NO; + } + } + + return label; +} + diff --git a/AppKit/Tools/BlendKit/BKUtilities.j b/AppKit/Tools/BlendKit/BKUtilities.j index 42e3de0c2..ca8986cdd 100644 --- a/AppKit/Tools/BlendKit/BKUtilities.j +++ b/AppKit/Tools/BlendKit/BKUtilities.j @@ -52,94 +52,3 @@ } @end - -function BKThemeDescriptorClasses() -{ - // Grab Theme Descriptor Classes. - var themeDescriptorClasses = []; - - for (candidate in window) - { - var theClass = objj_getClass(candidate), - theClassName = class_getName(theClass), - index = theClassName.indexOf("ThemeDescriptor"); - - if ((index >= 0) && (index === theClassName.length - "ThemeDescriptor".length)) - themeDescriptorClasses.push(theClass); - } - - return themeDescriptorClasses; -} - -function BKThemeObjectTemplatesForClass(aClass) -{ - var templates = [], - methods = class_copyMethodList(aClass.isa), - count = [methods count]; - - while (count--) - { - var method = methods[count], - selector = method_getName(method); - - if (selector.indexOf("themed") === 0) - { - var impl = method_getImplementation(method), - object = impl(aClass, selector); - - if (object) - { - var template = [[BKThemeObjectTemplate alloc] init]; - - [template setValue:object forKey:@"themedObject"]; - [template setValue:BKLabelFromIdentifier(selector) forKey:@"label"]; - - [templates addObject:template]; - } - } - } - - return templates; -} - -function BKLabelFromIdentifier(anIdentifier) -{ - var string = anIdentifier.substr("themed".length); - index = 0, - count = string.length, - label = "", - lastCapital = null, - isLeadingCapital = YES; - - for (; index < count; ++index) - { - var character = string.charAt(index), - isCapital = /^[A-Z]/.test(character); - - if (isCapital) - { - if (!isLeadingCapital) - { - if (lastCapital === null) - label += ' ' + character.toLowerCase(); - else - label += character; - } - - lastCapital = character; - } - else - { - if (isLeadingCapital && lastCapital !== null) - label += lastCapital; - - label += character; - - lastCapital = null; - isLeadingCapital = NO; - } - } - - return label; -} - diff --git a/AppKit/Tools/BlendKit/BlendKit.j b/AppKit/Tools/BlendKit/BlendKit.j index 09821ddd7..9b0cf5122 100644 --- a/AppKit/Tools/BlendKit/BlendKit.j +++ b/AppKit/Tools/BlendKit/BlendKit.j @@ -1,3 +1,4 @@ @import "BKShowcaseController.j" +@import "BKThemeDescriptor.j" @import "BKUtilities.j" diff --git a/AppKit/Tools/BlendKit/Resources/dark-checkers.png b/AppKit/Tools/BlendKit/Resources/dark-checkers.png new file mode 100644 index 0000000000000000000000000000000000000000..838362cf07125ad4855555977e141b151f13d90b GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1SD^YpWXnZBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrH1%sd~CNhE&{2x^nq)vIFaMy;vvV#3ThK9yiyX8BR0)$!^-m c%wfRLGLd=V=_irPfEpM)UHx3vIVCg!0KPmYF8}}l literal 0 HcmV?d00001 diff --git a/AppKit/Tools/BlendKit/Resources/light-checkers.png b/AppKit/Tools/BlendKit/Resources/light-checkers.png new file mode 100644 index 0000000000000000000000000000000000000000..83499084f527444f7180658cfefc0dd462eecbc2 GIT binary patch literal 3471 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 literal 0 HcmV?d00001 diff --git a/AppKit/Tools/BlendKit/Resources/selection.png b/AppKit/Tools/BlendKit/Resources/selection.png new file mode 100644 index 0000000000000000000000000000000000000000..aafc65dcf4a393b7427afd4986d2b0dce3d26095 GIT binary patch literal 4090 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 literal 0 HcmV?d00001