mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
NEW: effectiveAppearance and new CPThemeState
Each default (and only supported) CPAppearance now have an associated theme state. As the appearance is correctly propagated in CPViews hierarchy, it is now possible to have dark controls when the an ancestor view has a dark appearance. Added automated tests
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/Foundation.j>
|
||||
@import "CPTheme.j"
|
||||
|
||||
CPAppearanceNameAqua = @"CPAppearanceNameAqua";
|
||||
CPAppearanceNameLightContent = @"CPAppearanceNameLightContent";
|
||||
@@ -41,6 +42,11 @@ var _CPAppearanceCurrent = nil,
|
||||
|
||||
@end
|
||||
|
||||
CPThemeStateAppearanceAqua = CPThemeState("appearance-aqua");
|
||||
CPThemeStateAppearanceLightContent = CPThemeState("appearance-light-content");
|
||||
CPThemeStateAppearanceVibrantLight = CPThemeState("appearance-vibrant-light");
|
||||
CPThemeStateAppearanceVibrantDark = CPThemeState("appearance-vibrant-dark");
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -51,9 +57,9 @@ var _CPAppearanceCurrent = nil,
|
||||
*/
|
||||
@implementation CPAppearance : CPObject
|
||||
{
|
||||
BOOL _allowsVibrancy @accessors(property=allowsVibrancy);
|
||||
BOOL _allowsVibrancy @accessors(property=allowsVibrancy);
|
||||
|
||||
CPString _name;
|
||||
CPString _name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+80
-8
@@ -242,7 +242,9 @@ var CPViewHighDPIDrawingEnabled = YES;
|
||||
BOOL _isObserving;
|
||||
|
||||
BOOL _allowsVibrancy @accessors(property=allowsVibrancy);
|
||||
CPAppearance _appearance @accessors(property=appearance);
|
||||
CPAppearance _appearance @accessors(getter=appearance);
|
||||
CPAppearance _effectiveAppearance;
|
||||
BOOL _effectiveAppearanceCached;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -372,6 +374,8 @@ var CPViewHighDPIDrawingEnabled = YES;
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_themeState = CPThemeStateNormal;
|
||||
|
||||
_effectiveAppearanceCached = NO;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement = DOMElementPrototype.cloneNode(false);
|
||||
AppKitTagDOMElement(self, _DOMElement);
|
||||
@@ -842,9 +846,10 @@ var CPViewHighDPIDrawingEnabled = YES;
|
||||
*/
|
||||
- (void)viewDidMoveToSuperview
|
||||
{
|
||||
// if (_graphicsContext)
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
[self _resetCachedEffectiveAppearance];
|
||||
[self _updateAppearanceThemeState];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -3515,21 +3520,87 @@ setBoundsOrigin:
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPView (Appeatance)
|
||||
@implementation CPView (Appearance)
|
||||
|
||||
/*! Returns the received appearance if any, or ask the superview and returns it.
|
||||
/*! Returns the receiver's appearance if any, or ask the superview and returns it.
|
||||
*/
|
||||
- (CPAppearance)effectiveAppearance
|
||||
{
|
||||
if (_appearance)
|
||||
return _appearance;
|
||||
|
||||
if (_superview)
|
||||
return [_superview appearance];
|
||||
if (_effectiveAppearanceCached)
|
||||
return _effectiveAppearance;
|
||||
|
||||
return nil;
|
||||
_effectiveAppearance = [_superview effectiveAppearance];
|
||||
_effectiveAppearanceCached = YES;
|
||||
|
||||
return _effectiveAppearance;
|
||||
}
|
||||
|
||||
- (void)setAppearance:(CPAppearance)anAppearance
|
||||
{
|
||||
if ([_appearance isEqual:anAppearance])
|
||||
return;
|
||||
|
||||
[self willChangeValueForKey:@"appearance"];
|
||||
_appearance = anAppearance;
|
||||
[self didChangeValueForKey:@"appearance"];
|
||||
|
||||
[self _resetCachedEffectiveAppearance];
|
||||
[self _updateAppearanceThemeState];
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
*/
|
||||
- (void)_resetCachedEffectiveAppearance
|
||||
{
|
||||
_effectiveAppearanceCached = NO;
|
||||
[_subviews makeObjectsPerformSelector:@selector(_resetCachedEffectiveAppearance)];
|
||||
}
|
||||
|
||||
- (void)_updateAppearanceThemeState
|
||||
{
|
||||
var effectiveAppearance = [self effectiveAppearance];
|
||||
|
||||
if ([effectiveAppearance isEqual:[CPAppearance appearanceNamed:CPAppearanceNameAqua]])
|
||||
{
|
||||
[self setThemeState:CPThemeStateAppearanceAqua];
|
||||
[self unsetThemeState:CPThemeStateAppearanceLightContent];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantLight];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantDark];
|
||||
}
|
||||
else if ([effectiveAppearance isEqual:[CPAppearance appearanceNamed:CPAppearanceNameLightContent]])
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateAppearanceAqua];
|
||||
[self setThemeState:CPThemeStateAppearanceLightContent];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantLight];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantDark];
|
||||
}
|
||||
else if ([effectiveAppearance isEqual:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight]])
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateAppearanceAqua];
|
||||
[self unsetThemeState:CPThemeStateAppearanceLightContent];
|
||||
[self setThemeState:CPThemeStateAppearanceVibrantLight];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantDark];
|
||||
}
|
||||
else if ([effectiveAppearance isEqual:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark]])
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateAppearanceAqua];
|
||||
[self unsetThemeState:CPThemeStateAppearanceLightContent];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantLight];
|
||||
[self setThemeState:CPThemeStateAppearanceVibrantDark];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateAppearanceAqua];
|
||||
[self unsetThemeState:CPThemeStateAppearanceLightContent];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantLight];
|
||||
[self unsetThemeState:CPThemeStateAppearanceVibrantDark];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
@@ -3669,6 +3740,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
}
|
||||
|
||||
_appearance = [aCoder decodeObjectForKey:CPViewAppearanceKey];
|
||||
_effectiveAppearanceCached = NO;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
|
||||
@@ -771,6 +771,101 @@ var methodCalled;
|
||||
[self assert:nil equals:view._toolTipFunctionOut];
|
||||
}
|
||||
|
||||
- (void)testAppearanceDefaultvalue
|
||||
{
|
||||
[self assert:nil equals:[view appearance]];
|
||||
[self assertFalse:view._effectiveAppearanceCached];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantDark]];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantLight]];
|
||||
[self assert:nil equals:[view effectiveAppearance]];
|
||||
[self assertTrue:view._effectiveAppearanceCached];
|
||||
}
|
||||
|
||||
- (void)testAppearanceWithVibrantDark
|
||||
{
|
||||
[view setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark]];
|
||||
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark] equals:[view appearance]];
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark] equals:[view effectiveAppearance]];
|
||||
[self assertTrue:[view hasThemeState:CPThemeStateAppearanceVibrantDark]];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantLight]];
|
||||
}
|
||||
|
||||
- (void)testAppearanceWithVibrantLight
|
||||
{
|
||||
[view setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight]];
|
||||
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight] equals:[view appearance]];
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight] equals:[view effectiveAppearance]];
|
||||
[self assertTrue:[view hasThemeState:CPThemeStateAppearanceVibrantLight]];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantDark]];
|
||||
}
|
||||
|
||||
- (void)testAppearanceReset
|
||||
{
|
||||
[view setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight]];
|
||||
[view setAppearance:nil];
|
||||
|
||||
[self assert:nil equals:[view appearance]];
|
||||
[self assert:nil equals:[view effectiveAppearance]];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantLight]];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantDark]];
|
||||
}
|
||||
|
||||
- (void)testEffectiveAppearance
|
||||
{
|
||||
var secondView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[self assertFalse:secondView._effectiveAppearanceCached];
|
||||
|
||||
[view addSubview:secondView];
|
||||
|
||||
[self assertTrue:secondView._effectiveAppearanceCached];
|
||||
[self assert:nil equals:[secondView appearance]];
|
||||
|
||||
[view setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight]];
|
||||
|
||||
[self assertFalse:secondView._effectiveAppearanceCached];
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight] equals:[secondView effectiveAppearance]];
|
||||
[self assertTrue:secondView._effectiveAppearanceCached];
|
||||
}
|
||||
|
||||
- (void)testEffectiveAppearanceWithMovingViews
|
||||
{
|
||||
var viewA = [[CPView alloc] initWithFrame:CGRectMakeZero()],
|
||||
viewB = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[viewA setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight]];
|
||||
[viewB setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark]];
|
||||
|
||||
[viewA addSubview:view];
|
||||
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight] equals:[view effectiveAppearance]];
|
||||
[self assertTrue:[view hasThemeState:CPThemeStateAppearanceVibrantLight]];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantDark]];
|
||||
|
||||
[viewB addSubview:view];
|
||||
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark] equals:[view effectiveAppearance]];
|
||||
[self assertFalse:[view hasThemeState:CPThemeStateAppearanceVibrantLight]];
|
||||
[self assertTrue:[view hasThemeState:CPThemeStateAppearanceVibrantDark]];
|
||||
}
|
||||
|
||||
- (void)testEffectiveAppearanceReset
|
||||
{
|
||||
var viewA = [[CPView alloc] initWithFrame:CGRectMakeZero()],
|
||||
viewB = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[viewA setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight]];
|
||||
[viewB setAppearance:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark]];
|
||||
|
||||
[viewA addSubview:view];
|
||||
[self assert:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight] equals:[view effectiveAppearance]];
|
||||
|
||||
[view removeFromSuperview];
|
||||
[self assert:nil equals:[view effectiveAppearance]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPLayoutView : CPView
|
||||
|
||||
Reference in New Issue
Block a user