mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-07 17:38:02 +00:00
Fixed: Aristo3 ready and modern Cocoa behavior for CPBox (#2924)
This commit is contained in:
1 parent
010057d9e1
commit
412baf7872
2 files changed
+321
-75
No files matched your search
+319
-74
@@ -22,13 +22,14 @@
|
||||
|
||||
@import "CPTextField.j"
|
||||
@import "CPView.j"
|
||||
@import <Foundation/CPGeometry.j>
|
||||
|
||||
// CPBoxType
|
||||
@typedef CPBoxType
|
||||
CPBoxPrimary = 0;
|
||||
CPBoxSecondary = 1;
|
||||
CPBoxSecondary = 1; // Deprecated
|
||||
CPBoxSeparator = 2;
|
||||
CPBoxOldStyle = 3;
|
||||
CPBoxOldStyle = 3; // Deprecated
|
||||
CPBoxCustom = 4;
|
||||
|
||||
// CPBorderType
|
||||
@@ -58,11 +59,13 @@ CPBelowBottom = 6;
|
||||
@implementation CPBox : CPView
|
||||
{
|
||||
CPBoxType _boxType;
|
||||
CPBorderType _borderType;
|
||||
CPBorderType _borderType; // deprecated
|
||||
CPView _contentView;
|
||||
CPView _boxView; // needed for CSS theming, will be transparent for non CSS themes
|
||||
BOOL _transparent @accessors(getter=isTransparent);
|
||||
|
||||
CPString _title @accessors(getter=title);
|
||||
int _titlePosition @accessors(getter=titlePosition);
|
||||
CPString _title @accessors(getter=title);
|
||||
int _titlePosition @accessors(getter=titlePosition);
|
||||
CPTextField _titleView;
|
||||
}
|
||||
|
||||
@@ -90,8 +93,15 @@ CPBelowBottom = 6;
|
||||
@"inner-shadow-size": 6.0,
|
||||
@"inner-shadow-color": [CPNull null],
|
||||
@"content-margin": CGSizeMakeZero(),
|
||||
@"nib2cib-adjustment-primary-frame": CGRectMake(4, -4, -8, -6)
|
||||
};
|
||||
@"title-font": [CPNull null],
|
||||
@"title-left-offset": 5.0,
|
||||
@"title-top-offset": 0.0,
|
||||
@"title-color": [CPNull null],
|
||||
@"nib2cib-adjustment-primary-frame": CGRectMake(4, -4, -8, -6),
|
||||
@"content-adjustment": CGRectMakeZero(),
|
||||
@"min-y-correction-no-title": 0,
|
||||
@"min-y-correction-title": 0
|
||||
};
|
||||
}
|
||||
|
||||
+ (id)boxEnclosingView:(CPView)aView
|
||||
@@ -115,16 +125,26 @@ CPBelowBottom = 6;
|
||||
|
||||
if (self)
|
||||
{
|
||||
_borderType = CPBezelBorder;
|
||||
_borderType = CPGrooveBorder; // Was CPBezelBorder but Cocoa default is CPGrooveBorder
|
||||
_boxType = CPBoxPrimary;
|
||||
|
||||
_titlePosition = CPNoTitle;
|
||||
_titleView = [CPTextField labelWithTitle:@""];
|
||||
[_titleView setFont:[self titleFont]];
|
||||
[_titleView setTextColor:[self titleColor]];
|
||||
|
||||
_boxView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_boxView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[self addSubview:_contentView];
|
||||
[self addSubview:_boxView];
|
||||
[_boxView setAutoresizesSubviews:YES];
|
||||
[_boxView addSubview:_contentView];
|
||||
|
||||
[self sizeToFit];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -156,6 +176,8 @@ CPBelowBottom = 6;
|
||||
*/
|
||||
- (CPBorderType)borderType
|
||||
{
|
||||
CPLog.warn("CPBox borderType is deprecated.");
|
||||
|
||||
return _borderType;
|
||||
}
|
||||
|
||||
@@ -178,7 +200,8 @@ CPBelowBottom = 6;
|
||||
return;
|
||||
|
||||
_borderType = aBorderType;
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
[self refreshDisplay];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -218,13 +241,30 @@ CPBelowBottom = 6;
|
||||
*/
|
||||
- (void)setBoxType:(CPBoxType)aBoxType
|
||||
{
|
||||
if ((aBoxType == CPBoxSecondary) || (aBoxType == CPBoxOldStyle))
|
||||
CPLog.warn("CPBox setBoxType: CPBoxSecondary and CPBoxOldStyle are deprecated.");
|
||||
|
||||
if (_boxType === aBoxType)
|
||||
return;
|
||||
|
||||
_boxType = aBoxType;
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
[self refreshDisplay];
|
||||
}
|
||||
|
||||
- (void)setTransparent:(BOOL)shouldBeTransparent
|
||||
{
|
||||
if (_transparent == shouldBeTransparent)
|
||||
return;
|
||||
|
||||
_transparent = shouldBeTransparent;
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
}
|
||||
|
||||
/*!
|
||||
The receiver’s border color. It must be a custom box (that is, it has a type of CPBoxCustom) and it must have a border style of CPLineBorder.
|
||||
*/
|
||||
- (CPColor)borderColor
|
||||
{
|
||||
return [self valueForThemeAttribute:@"border-color"];
|
||||
@@ -232,12 +272,21 @@ CPBelowBottom = 6;
|
||||
|
||||
- (void)setBorderColor:(CPColor)color
|
||||
{
|
||||
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||
{
|
||||
CPLog.warn("CPBox setBorderColor: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setBorderColor. Ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ([color isEqual:[self borderColor]])
|
||||
return;
|
||||
|
||||
[self setValue:color forThemeAttribute:@"border-color"];
|
||||
}
|
||||
|
||||
/*!
|
||||
The receiver’s border width. It must be a custom box (that is, it has a type of CPBoxCustom) and it must have a border style of CPLineBorder.
|
||||
*/
|
||||
- (float)borderWidth
|
||||
{
|
||||
return [self valueForThemeAttribute:@"border-width"];
|
||||
@@ -245,12 +294,21 @@ CPBelowBottom = 6;
|
||||
|
||||
- (void)setBorderWidth:(float)width
|
||||
{
|
||||
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||
{
|
||||
CPLog.warn("CPBox setBorderWidth: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setBorderWidth. Ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (width === [self borderWidth])
|
||||
return;
|
||||
|
||||
[self setValue:width forThemeAttribute:@"border-width"];
|
||||
}
|
||||
|
||||
/*!
|
||||
The receiver’s corner radius. It must be a custom box (that is, it has a type of CPBoxCustom) and it must have a border style of CPLineBorder.
|
||||
*/
|
||||
- (float)cornerRadius
|
||||
{
|
||||
return [self valueForThemeAttribute:@"corner-radius"];
|
||||
@@ -258,12 +316,21 @@ CPBelowBottom = 6;
|
||||
|
||||
- (void)setCornerRadius:(float)radius
|
||||
{
|
||||
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||
{
|
||||
CPLog.warn("CPBox setCornerRadius: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setCornerRadius. Ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (radius === [self cornerRadius])
|
||||
return;
|
||||
|
||||
[self setValue:radius forThemeAttribute:@"corner-radius"];
|
||||
}
|
||||
|
||||
/*!
|
||||
The receiver’s background color. It must be a custom box (that is, it has a type of CPBoxCustom) and it must have a border style of CPLineBorder.
|
||||
*/
|
||||
- (CPColor)fillColor
|
||||
{
|
||||
return [self valueForThemeAttribute:@"background-color"];
|
||||
@@ -271,6 +338,12 @@ CPBelowBottom = 6;
|
||||
|
||||
- (void)setFillColor:(CPColor)color
|
||||
{
|
||||
if ((_boxType !== CPBoxCustom) || (_borderType !== CPLineBorder))
|
||||
{
|
||||
CPLog.warn("CPBox setFillColor: the box must be of type CPBoxCustom AND border of type CPLineBorder in order to use setFillColor. Ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ([color isEqual:[self fillColor]])
|
||||
return;
|
||||
|
||||
@@ -287,21 +360,20 @@ CPBelowBottom = 6;
|
||||
if (aView === _contentView)
|
||||
return;
|
||||
|
||||
var borderWidth = [self borderWidth],
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
||||
|
||||
[aView setFrame:CGRectInset([self bounds], contentMargin.width + borderWidth, contentMargin.height + borderWidth)];
|
||||
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
// A nil contentView is allowed (tested in Cocoa 2013-02-22).
|
||||
if (!aView)
|
||||
[_contentView removeFromSuperview];
|
||||
else if (_contentView)
|
||||
[self replaceSubview:_contentView with:aView];
|
||||
[_boxView replaceSubview:_contentView with:aView];
|
||||
else
|
||||
[self addSubview:aView];
|
||||
[_boxView addSubview:aView];
|
||||
|
||||
_contentView = aView;
|
||||
|
||||
[self sizeToFit];
|
||||
[self refreshDisplay];
|
||||
}
|
||||
|
||||
- (CGSize)contentViewMargins
|
||||
@@ -321,9 +393,14 @@ CPBelowBottom = 6;
|
||||
{
|
||||
var offset = [self _titleHeightOffset],
|
||||
borderWidth = [self borderWidth],
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"],
|
||||
contentAdjustment = [self valueForThemeAttribute:@"content-adjustment"],
|
||||
minYCorrection = [self valueForThemeAttribute:(_titlePosition === CPNoTitle ? @"min-y-correction-no-title" : @"min-y-correction-title")];
|
||||
|
||||
[self setFrame:CGRectInset(aRect, -(contentMargin.width + borderWidth), -(contentMargin.height + offset[0] + borderWidth))];
|
||||
[self setFrame:CGRectMake(aRect.origin.x - contentAdjustment.origin.x - contentMargin.width + borderWidth,
|
||||
aRect.origin.y - contentAdjustment.origin.y - contentMargin.height + borderWidth - minYCorrection,
|
||||
aRect.size.width + 2 * contentMargin.width - contentAdjustment.size.width,
|
||||
aRect.size.height + 2 * contentMargin.height - contentAdjustment.size.height)];
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
@@ -348,14 +425,42 @@ CPBelowBottom = 6;
|
||||
|
||||
- (CPFont)titleFont
|
||||
{
|
||||
return [_titleView font];
|
||||
if ([self hasThemeAttribute:@"title-font"])
|
||||
return [self valueForThemeAttribute:@"title-font"];
|
||||
else
|
||||
return [_titleView font];
|
||||
}
|
||||
|
||||
- (void)setTitleFont:(CPFont)aFont
|
||||
{
|
||||
if ([aFont isEqual:[self titleFont]])
|
||||
return;
|
||||
|
||||
if ([self hasThemeAttribute:@"title-font"])
|
||||
[self setValue:aFont forThemeAttribute:@"title-font"];
|
||||
|
||||
[_titleView setFont:aFont];
|
||||
}
|
||||
|
||||
- (CPColor)titleColor
|
||||
{
|
||||
if ([self hasThemeAttribute:@"title-color"])
|
||||
return [self valueForThemeAttribute:@"title-color"];
|
||||
else
|
||||
return [_titleView textColor];
|
||||
}
|
||||
|
||||
- (void)setTitleColor:(CPColor)aColor
|
||||
{
|
||||
if ([aColor isEqual:[self titleColor]])
|
||||
return;
|
||||
|
||||
if ([self hasThemeAttribute:@"title-color"])
|
||||
[self setValue:aColor forThemeAttribute:@"title-color"];
|
||||
|
||||
[_titleView setTextColor:aColor];
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the text field used to display the receiver's title.
|
||||
|
||||
@@ -366,25 +471,39 @@ CPBelowBottom = 6;
|
||||
return _titleView;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the rectangle in which the receiver’s title is drawn.
|
||||
*/
|
||||
- (CGRect)titleRect
|
||||
{
|
||||
return [_titleView frame];
|
||||
}
|
||||
|
||||
- (void)_manageTitlePositioning
|
||||
{
|
||||
if (_titlePosition == CPNoTitle)
|
||||
if ((_titlePosition == CPNoTitle) || _transparent)
|
||||
{
|
||||
[_titleView removeFromSuperview];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
if (_boxType !== CPBoxSeparator)
|
||||
[self sizeToFit];
|
||||
|
||||
[self refreshDisplay];
|
||||
return;
|
||||
}
|
||||
|
||||
[_titleView setStringValue:_title];
|
||||
[_titleView sizeToFit];
|
||||
[self addSubview:_titleView];
|
||||
|
||||
var titleLeftOffset = [self valueForThemeAttribute:@"title-left-offset"],
|
||||
titleTopOffset = [self valueForThemeAttribute:@"title-top-offset"];
|
||||
|
||||
switch (_titlePosition)
|
||||
{
|
||||
case CPAtTop:
|
||||
case CPAboveTop:
|
||||
case CPBelowTop:
|
||||
[_titleView setFrameOrigin:CGPointMake(5.0, 0.0)];
|
||||
[_titleView setFrameOrigin:CGPointMake(titleLeftOffset, titleTopOffset)]; // FIXME: was 0.0
|
||||
[_titleView setAutoresizingMask:CPViewNotSizable];
|
||||
break;
|
||||
|
||||
@@ -392,39 +511,51 @@ CPBelowBottom = 6;
|
||||
case CPAtBottom:
|
||||
case CPBelowBottom:
|
||||
var h = [_titleView frameSize].height;
|
||||
[_titleView setFrameOrigin:CGPointMake(5.0, [self frameSize].height - h)];
|
||||
[_titleView setFrameOrigin:CGPointMake(titleLeftOffset, [self frameSize].height - h - titleTopOffset)];
|
||||
[_titleView setAutoresizingMask:CPViewMinYMargin];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_transparent)
|
||||
[self addSubview:_titleView];
|
||||
|
||||
[self sizeToFit];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self refreshDisplay];
|
||||
}
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var contentFrame = [_contentView frame],
|
||||
offset = [self _titleHeightOffset],
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"];
|
||||
var offset = [self _titleHeightOffset],
|
||||
size = [self frameSize];
|
||||
|
||||
if (!contentFrame)
|
||||
[_boxView setFrame:CGRectMake(0, offset[1], size.width, size.height - offset[0])];
|
||||
|
||||
if (!_contentView)
|
||||
return;
|
||||
|
||||
[_contentView setFrameOrigin:CGPointMake(contentMargin.width, contentMargin.height + offset[1])];
|
||||
var boxSize = [_boxView frameSize],
|
||||
contentMargin = [self valueForThemeAttribute:@"content-margin"],
|
||||
contentAdjustment = [self valueForThemeAttribute:@"content-adjustment"],
|
||||
borderWidth = [self valueForThemeAttribute:@"border-width"],
|
||||
minYCorrection = [self valueForThemeAttribute:(_titlePosition === CPNoTitle ? @"min-y-correction-no-title" : @"min-y-correction-title")];
|
||||
|
||||
[_contentView setFrame:CGRectMake(contentAdjustment.origin.x + contentMargin.width - borderWidth,
|
||||
contentAdjustment.origin.y + contentMargin.height - borderWidth + minYCorrection,
|
||||
boxSize.width - 2 * contentMargin.width + contentAdjustment.size.width,
|
||||
boxSize.height - 2 * contentMargin.height + contentAdjustment.size.height)];
|
||||
}
|
||||
|
||||
- (float)_titleHeightOffset
|
||||
- (CPArray)_titleHeightOffset
|
||||
{
|
||||
if (_titlePosition == CPNoTitle)
|
||||
return [0.0, 0.0];
|
||||
var titleTopOffset = [self valueForThemeAttribute:@"title-top-offset"];
|
||||
|
||||
switch (_titlePosition)
|
||||
{
|
||||
case CPAtTop:
|
||||
return [[_titleView frameSize].height, [_titleView frameSize].height];
|
||||
return [[_titleView frameSize].height + titleTopOffset, [_titleView frameSize].height + titleTopOffset];
|
||||
|
||||
case CPAtBottom:
|
||||
return [[_titleView frameSize].height, 0.0];
|
||||
return [[_titleView frameSize].height + titleTopOffset, 0.0];
|
||||
|
||||
default:
|
||||
return [0.0, 0.0];
|
||||
@@ -441,21 +572,24 @@ CPBelowBottom = 6;
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
if ([self isCSSBased] && (_boxType !== CPBoxCustom))
|
||||
return;
|
||||
|
||||
var bounds = [self bounds];
|
||||
|
||||
switch (_boxType)
|
||||
if (_boxType === CPBoxSeparator)
|
||||
{
|
||||
case CPBoxSeparator:
|
||||
// NSBox does not include a horizontal flag for the separator type. We have to determine
|
||||
// the type of separator to draw by the width and height of the frame.
|
||||
if (CGRectGetWidth(bounds) === 5.0)
|
||||
return [self _drawVerticalSeparatorInRect:bounds];
|
||||
else if (CGRectGetHeight(bounds) === 5.0)
|
||||
return [self _drawHorizontalSeparatorInRect:bounds];
|
||||
|
||||
break;
|
||||
// NSBox does not include a horizontal flag for the separator type. We have to determine
|
||||
// the type of separator to draw by the width and height of the frame.
|
||||
if (CGRectGetWidth(bounds) === 5.0)
|
||||
return [self _drawVerticalSeparatorInRect:bounds];
|
||||
else if (CGRectGetHeight(bounds) === 5.0)
|
||||
return [self _drawHorizontalSeparatorInRect:bounds];
|
||||
}
|
||||
|
||||
if (_transparent)
|
||||
return;
|
||||
|
||||
if (_titlePosition == CPAtTop)
|
||||
{
|
||||
bounds.origin.y += [_titleView frameSize].height;
|
||||
@@ -476,9 +610,6 @@ CPBelowBottom = 6;
|
||||
switch (_borderType)
|
||||
{
|
||||
case CPBezelBorder:
|
||||
[self _drawBezelBorderInRect:bounds];
|
||||
break;
|
||||
|
||||
case CPGrooveBorder:
|
||||
case CPLineBorder:
|
||||
[self _drawLineBorderInRect:bounds];
|
||||
@@ -595,12 +726,70 @@ CPBelowBottom = 6;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation CPBox (CSSTheming)
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (![self isCSSBased] || (_boxType === CPBoxCustom))
|
||||
return;
|
||||
|
||||
var bounds = [self bounds];
|
||||
|
||||
if (_boxType === CPBoxSeparator)
|
||||
{
|
||||
if (bounds.size.width === 5.0)
|
||||
{
|
||||
// Vertical separator
|
||||
[_boxView setFrame:CGRectMake(2,0,1,bounds.size.height)];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Horizontal separator
|
||||
[_boxView setFrame:CGRectMake(0,2,bounds.size.width,1)];
|
||||
}
|
||||
|
||||
[_boxView setBackgroundColor:[self valueForThemeAttribute:@"border-color"]];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// All types of boxes (beside custom which is not covered here) always draw the same way, unless they are CPNoBorder.
|
||||
if ((_borderType !== CPNoBorder) && !_transparent)
|
||||
{
|
||||
[_boxView setBackgroundColor:[self valueForThemeAttribute:@"background-color"]];
|
||||
return;
|
||||
}
|
||||
|
||||
// No border or transparent
|
||||
[_boxView setBackgroundColor:nil];
|
||||
}
|
||||
|
||||
- (BOOL)isCSSBased
|
||||
{
|
||||
return [[self theme] isCSSBased];
|
||||
}
|
||||
|
||||
- (void)refreshDisplay
|
||||
{
|
||||
if ([self isCSSBased] && (_boxType !== CPBoxCustom))
|
||||
[self setNeedsLayout:YES];
|
||||
else
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
||||
CPBoxTitle = @"CPBoxTitle",
|
||||
CPBoxTitlePosition = @"CPBoxTitlePosition",
|
||||
CPBoxTitleView = @"CPBoxTitleView",
|
||||
CPBoxContentView = @"CPBoxContentView";
|
||||
CPBoxTitleKey = @"CPBoxTitleKey",
|
||||
CPBoxTitlePositionKey = @"CPBoxTitlePositionKey",
|
||||
CPBoxTitleViewKey = @"CPBoxTitleViewKey",
|
||||
CPBoxContentViewKey = @"CPBoxContentViewKey",
|
||||
CPBoxBoxViewKey = @"CPBoxBoxViewKey";
|
||||
|
||||
@implementation CPBox (CPCoding)
|
||||
|
||||
@@ -613,33 +802,56 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
|
||||
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
||||
|
||||
_title = [aCoder decodeObjectForKey:CPBoxTitle];
|
||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
|
||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
|
||||
_title = [aCoder decodeObjectForKey:CPBoxTitleKey];
|
||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePositionKey];
|
||||
|
||||
if (_boxType != CPBoxSeparator)
|
||||
// Important : see comment on encodeWithCoder below
|
||||
|
||||
_boxView = [aCoder decodeObjectForKey:CPBoxBoxViewKey];
|
||||
|
||||
if (!_boxView)
|
||||
{
|
||||
// FIXME: we have a problem with CIB decoding here.
|
||||
// We should be able to simply add : _contentView = [self subviews][0]
|
||||
// but first box subview seems to be malformed (badly decoded).
|
||||
// For example, when deployed, this view doesn't have its _trackingAreas array initialized.
|
||||
// As a (temporary) workaround, we encode/decode the _contentView property. We then transfer the subview hierarchy
|
||||
// and replace the first (and only) box subview with this _contentView
|
||||
// We're coming from nib2cib.
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPBoxContentView] || [[CPView alloc] initWithFrame:[self bounds]];
|
||||
var malformedContentView = [self subviews][0];
|
||||
[_contentView setSubviews:[malformedContentView subviews]];
|
||||
[self replaceSubview:malformedContentView with:_contentView];
|
||||
_boxView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
_titleView = [CPTextField labelWithTitle:_title];
|
||||
}
|
||||
else
|
||||
{
|
||||
_titlePosition = CPNoTitle;
|
||||
// We're coming from elsewhere
|
||||
|
||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleViewKey];
|
||||
}
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPBoxContentViewKey];
|
||||
|
||||
// FIXME: super-mega-hyper-trick : _contentView has a superview which is not normal !
|
||||
// FIXME: (see encodeWithCoder to understand why this is not possible)
|
||||
// FIXME: we fix this by hand. This is horrible so please find a structural solution !
|
||||
|
||||
if (_contentView)
|
||||
_contentView._superview = nil;
|
||||
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_boxView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_boxView setAutoresizesSubviews:YES];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
|
||||
if (_contentView)
|
||||
[_boxView setSubviews:@[_contentView]];
|
||||
|
||||
[self addSubview:_boxView];
|
||||
[self addSubview:_titleView];
|
||||
|
||||
if (_boxType === CPBoxSeparator)
|
||||
_titlePosition = CPNoTitle;
|
||||
|
||||
[_titleView setFont:[self titleFont]];
|
||||
[_titleView setTextColor:[self titleColor]];
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
|
||||
[self refreshDisplay];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -647,14 +859,47 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
// We have to distinguish between 2 cases :
|
||||
// - we come from nib2cib
|
||||
// - we come from elsewhere
|
||||
//
|
||||
// When coming from nib2cib, we have no _boxView, _contentView, _titleView.
|
||||
// We fix _contentView to be the first (and only) subview.
|
||||
// They will have to be added on decoding.
|
||||
//
|
||||
// When coming from elsewhere, we remove _boxView (and thus _contentView) and _titleView
|
||||
// from the view hierarchy as we'll already encode them via variables.
|
||||
// They will be putted back during decoding. This way, we reduce the space and speed needed for coding.
|
||||
|
||||
var subviews = [self subviews];
|
||||
|
||||
if (!_boxView)
|
||||
{
|
||||
// We're coming from nib2cib.
|
||||
|
||||
_contentView = subviews[0];
|
||||
|
||||
[_contentView removeFromSuperview];
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're coming from elsewhere.
|
||||
|
||||
[_boxView removeFromSuperview];
|
||||
[_titleView removeFromSuperview];
|
||||
}
|
||||
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[self setSubviews:subviews];
|
||||
|
||||
[aCoder encodeInt:_boxType forKey:CPBoxTypeKey];
|
||||
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
|
||||
[aCoder encodeObject:_title forKey:CPBoxTitle];
|
||||
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePosition];
|
||||
[aCoder encodeObject:_titleView forKey:CPBoxTitleView];
|
||||
[aCoder encodeObject:_contentView forKey:CPBoxContentView];
|
||||
[aCoder encodeObject:_title forKey:CPBoxTitleKey];
|
||||
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePositionKey];
|
||||
[aCoder encodeConditionalObject:_contentView forKey:CPBoxContentViewKey];
|
||||
[aCoder encodeConditionalObject:_titleView forKey:CPBoxTitleViewKey];
|
||||
[aCoder encodeConditionalObject:_boxView forKey:CPBoxBoxViewKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -32,6 +32,7 @@
|
||||
{
|
||||
_boxType = [aCoder decodeIntForKey:@"NSBoxType"];
|
||||
_borderType = [aCoder decodeIntForKey:@"NSBorderType"];
|
||||
_transparent = [aCoder decodeBoolForKey:@"NSTransparent"];
|
||||
|
||||
var borderColor = [aCoder decodeObjectForKey:@"NSBorderColor2"],
|
||||
fillColor = [aCoder decodeObjectForKey:@"NSFillColor2"],
|
||||
@@ -70,7 +71,7 @@
|
||||
|
||||
- (CGRect)_nib2CibAdjustment
|
||||
{
|
||||
if ((_boxType === CPBoxPrimary) || (_boxType === CPBoxSecondary))
|
||||
if ((_boxType !== CPBoxSeparator) && ((_boxType === CPBoxPrimary) || (_boxType === CPBoxSecondary)))
|
||||
{
|
||||
// We use a special nib2cib-adjustment-frame for primary/secondary boxes
|
||||
var theme = [Nib2Cib defaultTheme],
|
||||
|
||||
Reference in new issue
Block a user