2020-05-10 06:26:06 +00:00
|
|
|
|
/* Implementation of class NSLayoutConstraint
|
|
|
|
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
|
|
|
|
|
2020-05-10 10:38:06 +00:00
|
|
|
|
By: Gregory Casamento <greg.casamento@gmail.com>
|
2020-05-10 06:26:06 +00:00
|
|
|
|
Date: Sat May 9 16:30:22 EDT 2020
|
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Library.
|
|
|
|
|
|
|
|
|
|
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 USA.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-10 12:22:12 +00:00
|
|
|
|
#import <Foundation/NSArray.h>
|
|
|
|
|
#import <Foundation/NSDictionary.h>
|
2020-05-10 18:49:06 +00:00
|
|
|
|
#import <Foundation/NSKeyedArchiver.h>
|
2020-05-10 12:22:12 +00:00
|
|
|
|
|
|
|
|
|
#import "AppKit/NSControl.h"
|
|
|
|
|
#import "AppKit/NSView.h"
|
|
|
|
|
#import "AppKit/NSAnimation.h"
|
2020-05-10 06:26:06 +00:00
|
|
|
|
#import "AppKit/NSLayoutConstraint.h"
|
2023-02-20 07:09:23 +00:00
|
|
|
|
#import "NSViewPrivate.h"
|
2023-02-27 08:56:37 +00:00
|
|
|
|
#import "NSWindowPrivate.h"
|
2020-06-03 11:12:31 +00:00
|
|
|
|
#import "AppKit/NSWindow.h"
|
2020-06-14 08:23:13 +00:00
|
|
|
|
#import "AppKit/NSApplication.h"
|
2023-02-19 04:00:01 +00:00
|
|
|
|
#import "NSAutoresizingMaskLayoutConstraint.h"
|
|
|
|
|
#import "GSFastEnumeration.h"
|
2022-11-05 04:45:06 +00:00
|
|
|
|
#import "GSAutoLayoutVFLParser.h"
|
2023-02-26 02:28:15 +00:00
|
|
|
|
#import "GSAutoLayoutEngine.h"
|
2020-05-10 06:26:06 +00:00
|
|
|
|
|
2020-06-14 03:45:08 +00:00
|
|
|
|
static NSMutableArray *activeConstraints = nil;
|
2020-07-30 09:10:37 +00:00
|
|
|
|
// static NSNotificationCenter *nc = nil;
|
2020-05-10 12:22:12 +00:00
|
|
|
|
|
2020-05-10 06:26:06 +00:00
|
|
|
|
@implementation NSLayoutConstraint
|
2020-05-10 12:41:10 +00:00
|
|
|
|
|
2020-06-01 06:27:49 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSLayoutConstraint class])
|
|
|
|
|
{
|
|
|
|
|
[self setVersion: 1];
|
2020-06-14 07:29:39 +00:00
|
|
|
|
activeConstraints = [[NSMutableArray alloc] initWithCapacity: 10];
|
2020-07-30 08:56:32 +00:00
|
|
|
|
// nc = [NSNotificationCenter defaultCenter];
|
2020-06-14 08:23:13 +00:00
|
|
|
|
|
2020-07-30 08:56:32 +00:00
|
|
|
|
// [nc addObserver: self
|
|
|
|
|
// selector: @selector(_setupNotifications:)
|
|
|
|
|
// name: NSApplicationDidFinishLaunchingNotification
|
|
|
|
|
// object: nil];
|
2020-06-14 08:23:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) _setupNotifications: (NSNotification *)n
|
|
|
|
|
{
|
2020-07-30 08:56:32 +00:00
|
|
|
|
/*
|
2020-06-14 10:02:19 +00:00
|
|
|
|
[nc addObserver: self
|
|
|
|
|
selector: @selector(_handleWindowResize:)
|
|
|
|
|
name: NSWindowDidResizeNotification
|
|
|
|
|
object: nil];
|
2020-07-30 08:56:32 +00:00
|
|
|
|
*/
|
2020-06-01 06:27:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-27 23:04:42 +00:00
|
|
|
|
+ (NSString *) _attributeToString: (NSLayoutAttribute)attr
|
|
|
|
|
{
|
|
|
|
|
NSString *name = nil;
|
|
|
|
|
|
|
|
|
|
switch (attr)
|
|
|
|
|
{
|
|
|
|
|
case NSLayoutAttributeLeft:
|
|
|
|
|
name = @"Left";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeRight:
|
|
|
|
|
name = @"Right";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeTop:
|
|
|
|
|
name = @"Top";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeBottom:
|
|
|
|
|
name = @"Bottom";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeLeading:
|
|
|
|
|
name = @"Leading";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeTrailing:
|
|
|
|
|
name = @"Trailing";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeWidth:
|
|
|
|
|
name = @"Width";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeHeight:
|
|
|
|
|
name = @"Height";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeCenterX:
|
|
|
|
|
name = @"CenterX";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeCenterY:
|
|
|
|
|
name = @"CenterY";
|
|
|
|
|
break;
|
|
|
|
|
//case NSLayoutAttributeLastBaseline:
|
|
|
|
|
//name = @"LastBaseline";
|
|
|
|
|
//break;
|
|
|
|
|
case NSLayoutAttributeBaseline:
|
|
|
|
|
name = @"Baseline";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeFirstBaseline:
|
|
|
|
|
name = @"FirstBaseline";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutAttributeNotAnAttribute:
|
|
|
|
|
name = @"NotAnAttribute";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-30 10:40:16 +00:00
|
|
|
|
+ (NSLayoutAttribute) _stringToAttribute: (NSString *)str
|
|
|
|
|
{
|
|
|
|
|
NSLayoutAttribute a = 0;
|
|
|
|
|
|
|
|
|
|
if ([@"Left" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeLeft;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Right" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeRight;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Top" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeTop;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Bottom" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeBottom;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Leading" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeLeading;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Trailing" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeTrailing;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Width" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeWidth;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Height" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeHeight;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"CenterX" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeCenterX;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"CenterY" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeCenterY;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"Baseline" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeBaseline;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"FirstBaseline" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeFirstBaseline;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"NotAnAttribute" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
a = NSLayoutAttributeNotAnAttribute;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-27 23:04:42 +00:00
|
|
|
|
+ (NSString *) _relationToString: (NSLayoutRelation)rel
|
|
|
|
|
{
|
|
|
|
|
NSString *relation = nil;
|
|
|
|
|
|
|
|
|
|
switch (rel)
|
|
|
|
|
{
|
|
|
|
|
case NSLayoutRelationLessThanOrEqual:
|
|
|
|
|
relation = @"<=";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutRelationEqual:
|
|
|
|
|
relation = @"=";
|
|
|
|
|
break;
|
|
|
|
|
case NSLayoutRelationGreaterThanOrEqual:
|
|
|
|
|
relation = @">=";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return relation;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-30 10:40:16 +00:00
|
|
|
|
+ (NSLayoutRelation) _stringToRelation: (NSString *)str
|
|
|
|
|
{
|
|
|
|
|
NSLayoutRelation r = 0;
|
|
|
|
|
|
|
|
|
|
if ([@"<=" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
r = NSLayoutRelationLessThanOrEqual;
|
|
|
|
|
}
|
|
|
|
|
else if ([@"=" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
r = NSLayoutRelationEqual;
|
|
|
|
|
}
|
|
|
|
|
else if ([@">=" isEqualToString: str])
|
|
|
|
|
{
|
|
|
|
|
r = NSLayoutRelationGreaterThanOrEqual;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 08:23:13 +00:00
|
|
|
|
+ (void) _activateConstraint: (NSLayoutConstraint *)constraint
|
2020-06-14 03:45:08 +00:00
|
|
|
|
{
|
2020-07-30 08:56:32 +00:00
|
|
|
|
// [activeConstraints addObject: constraint];
|
|
|
|
|
// activeConstraints = [[activeConstraints sortedArrayUsingSelector: @selector(compare:)] mutableCopy];
|
2020-06-14 03:45:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 07:29:39 +00:00
|
|
|
|
+ (void) _removeConstraint: (NSLayoutConstraint *)constraint
|
|
|
|
|
{
|
|
|
|
|
[activeConstraints removeObject: constraint];
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-10 12:35:49 +00:00
|
|
|
|
+ (NSArray *) constraintsWithVisualFormat: (NSString *)fmt
|
|
|
|
|
options: (NSLayoutFormatOptions)opt
|
|
|
|
|
metrics: (NSDictionary *)metrics
|
|
|
|
|
views: (NSDictionary *)views
|
2020-05-10 12:22:12 +00:00
|
|
|
|
{
|
2022-11-05 04:45:06 +00:00
|
|
|
|
GSAutoLayoutVFLParser *parser = [[GSAutoLayoutVFLParser alloc]
|
|
|
|
|
initWithFormat: fmt
|
|
|
|
|
options: opt
|
|
|
|
|
metrics: metrics
|
|
|
|
|
views: views];
|
|
|
|
|
NSArray *constraints = [parser parse];
|
|
|
|
|
|
2022-11-12 01:09:29 +00:00
|
|
|
|
RELEASE(parser);
|
2022-11-05 04:45:06 +00:00
|
|
|
|
|
|
|
|
|
return constraints;
|
2020-05-10 12:22:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 10:57:26 +00:00
|
|
|
|
- (instancetype) initWithItem: (id)firstItem
|
|
|
|
|
attribute: (NSLayoutAttribute)firstAttribute
|
|
|
|
|
relatedBy: (NSLayoutRelation)relation
|
|
|
|
|
toItem: (id)secondItem
|
|
|
|
|
attribute: (NSLayoutAttribute)secondAttribute
|
|
|
|
|
multiplier: (CGFloat)multiplier
|
|
|
|
|
constant: (CGFloat)constant
|
|
|
|
|
priority: (CGFloat)priority;
|
|
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (self != nil)
|
|
|
|
|
{
|
|
|
|
|
_firstItem = firstItem;
|
|
|
|
|
_secondItem = secondItem;
|
|
|
|
|
_firstAttribute = firstAttribute;
|
|
|
|
|
_secondAttribute = secondAttribute;
|
|
|
|
|
_relation = relation;
|
|
|
|
|
_multiplier = multiplier;
|
|
|
|
|
_constant = constant;
|
|
|
|
|
_priority = priority;
|
|
|
|
|
|
|
|
|
|
[NSLayoutConstraint _activateConstraint: self];
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 06:31:18 +00:00
|
|
|
|
+ (instancetype) constraintWithItem: (id)view1
|
|
|
|
|
attribute: (NSLayoutAttribute)attr1
|
|
|
|
|
relatedBy: (NSLayoutRelation)relation
|
|
|
|
|
toItem: (id)view2
|
|
|
|
|
attribute: (NSLayoutAttribute)attr2
|
|
|
|
|
multiplier: (CGFloat)mult
|
|
|
|
|
constant: (CGFloat)c
|
|
|
|
|
{
|
|
|
|
|
NSLayoutConstraint *constraint =
|
|
|
|
|
[[NSLayoutConstraint alloc] initWithItem: view1
|
|
|
|
|
attribute: attr1
|
|
|
|
|
relatedBy: relation
|
|
|
|
|
toItem: view2
|
|
|
|
|
attribute: attr2
|
|
|
|
|
multiplier: mult
|
2020-06-14 10:57:26 +00:00
|
|
|
|
constant: c
|
2020-06-14 14:55:05 +00:00
|
|
|
|
priority: NSLayoutPriorityRequired];
|
2020-06-14 06:31:18 +00:00
|
|
|
|
|
|
|
|
|
AUTORELEASE(constraint);
|
|
|
|
|
return constraint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) activateConstraints: (NSArray *)constraints
|
|
|
|
|
{
|
2020-06-14 07:29:39 +00:00
|
|
|
|
NSEnumerator *en = [constraints objectEnumerator];
|
|
|
|
|
NSLayoutConstraint *c = nil;
|
|
|
|
|
|
|
|
|
|
while ((c = [en nextObject]) != nil)
|
|
|
|
|
{
|
2020-06-14 08:23:13 +00:00
|
|
|
|
[NSLayoutConstraint _activateConstraint: c];
|
2020-06-14 07:29:39 +00:00
|
|
|
|
}
|
2020-06-14 06:31:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) deactivateConstraints: (NSArray *)constraints
|
|
|
|
|
{
|
2020-06-14 07:29:39 +00:00
|
|
|
|
NSEnumerator *en = [constraints objectEnumerator];
|
|
|
|
|
NSLayoutConstraint *c = nil;
|
|
|
|
|
|
|
|
|
|
while ((c = [en nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
[NSLayoutConstraint _removeConstraint: c];
|
|
|
|
|
}
|
2020-06-14 06:31:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-10 12:22:12 +00:00
|
|
|
|
// Active
|
|
|
|
|
- (BOOL) isActive
|
|
|
|
|
{
|
|
|
|
|
return [activeConstraints containsObject: self];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setActive: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
if (flag)
|
|
|
|
|
{
|
2020-06-14 08:23:13 +00:00
|
|
|
|
[NSLayoutConstraint _activateConstraint: self];
|
2020-05-10 12:22:12 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-06-14 07:29:39 +00:00
|
|
|
|
[NSLayoutConstraint _removeConstraint: self];
|
2020-05-10 12:22:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 06:31:18 +00:00
|
|
|
|
// compare and isEqual...
|
|
|
|
|
- (NSComparisonResult) compare: (NSLayoutConstraint *)constraint
|
2020-06-14 03:45:08 +00:00
|
|
|
|
{
|
|
|
|
|
if ([self priority] < [constraint priority])
|
|
|
|
|
{
|
|
|
|
|
return NSOrderedAscending;
|
|
|
|
|
}
|
|
|
|
|
else if ([self priority] > [constraint priority])
|
|
|
|
|
{
|
|
|
|
|
return NSOrderedDescending;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NSOrderedSame;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 06:31:18 +00:00
|
|
|
|
- (BOOL) isEqual: (NSLayoutConstraint *)constraint
|
|
|
|
|
{
|
2020-06-14 09:00:50 +00:00
|
|
|
|
BOOL result = [super isEqual: constraint];
|
2020-06-14 10:02:19 +00:00
|
|
|
|
|
2020-06-14 09:00:50 +00:00
|
|
|
|
if (result == NO)
|
2020-06-14 06:31:18 +00:00
|
|
|
|
{
|
|
|
|
|
result = (_firstItem == [constraint firstItem] &&
|
|
|
|
|
_secondItem == [constraint secondItem] &&
|
|
|
|
|
_firstAttribute == [constraint firstAttribute] &&
|
|
|
|
|
_secondAttribute == [constraint secondAttribute] &&
|
|
|
|
|
_relation == [constraint relation] &&
|
|
|
|
|
_multiplier == [constraint multiplier] &&
|
|
|
|
|
_constant == [constraint constant] &&
|
|
|
|
|
_priority == [constraint priority]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-10 12:22:12 +00:00
|
|
|
|
// Items
|
|
|
|
|
- (id) firstItem
|
|
|
|
|
{
|
|
|
|
|
return _firstItem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSLayoutAttribute) firstAttribute
|
|
|
|
|
{
|
|
|
|
|
return _firstAttribute;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSLayoutRelation) relation
|
|
|
|
|
{
|
|
|
|
|
return _relation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) secondItem
|
|
|
|
|
{
|
|
|
|
|
return _secondItem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSLayoutAttribute) secondAttribute
|
|
|
|
|
{
|
|
|
|
|
return _secondAttribute;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (CGFloat) multiplier
|
|
|
|
|
{
|
|
|
|
|
return _multiplier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (CGFloat) constant
|
|
|
|
|
{
|
|
|
|
|
return _constant;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSLayoutAnchor *) firstAnchor
|
|
|
|
|
{
|
|
|
|
|
return _firstAnchor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSLayoutAnchor *) secondAnchor
|
|
|
|
|
{
|
|
|
|
|
return _secondAnchor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSLayoutPriority) priority
|
|
|
|
|
{
|
|
|
|
|
return _priority;
|
|
|
|
|
}
|
2020-05-10 06:26:06 +00:00
|
|
|
|
|
2020-06-09 11:34:40 +00:00
|
|
|
|
- (void) setPriority: (NSLayoutPriority)priority
|
|
|
|
|
{
|
|
|
|
|
_priority = priority;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-10 18:49:06 +00:00
|
|
|
|
// Coding...
|
|
|
|
|
- (instancetype) initWithCoder: (NSCoder *)coder
|
|
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (self != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([coder allowsKeyedCoding])
|
|
|
|
|
{
|
|
|
|
|
if ([coder containsValueForKey: @"NSConstant"])
|
|
|
|
|
{
|
|
|
|
|
_constant = [coder decodeFloatForKey: @"NSConstant"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([coder containsValueForKey: @"NSFirstAttribute"])
|
|
|
|
|
{
|
|
|
|
|
_firstAttribute = [coder decodeIntegerForKey: @"NSFirstAttribute"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([coder containsValueForKey: @"NSFirstItem"])
|
|
|
|
|
{
|
|
|
|
|
_firstItem = [coder decodeObjectForKey: @"NSFirstItem"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([coder containsValueForKey: @"NSSecondAttribute"])
|
|
|
|
|
{
|
|
|
|
|
_secondAttribute = [coder decodeIntegerForKey: @"NSSecondAttribute"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([coder containsValueForKey: @"NSSecondItem"])
|
|
|
|
|
{
|
|
|
|
|
_secondItem = [coder decodeObjectForKey: @"NSSecondItem"];
|
|
|
|
|
}
|
2020-06-09 11:27:06 +00:00
|
|
|
|
|
2020-06-14 10:57:26 +00:00
|
|
|
|
if ([coder containsValueForKey: @"NSMultiplier"])
|
|
|
|
|
{
|
|
|
|
|
_multiplier = [coder decodeFloatForKey: @"NSMultiplier"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_multiplier = 1.0; // identity multiplier if not present
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([coder containsValueForKey: @"NSRelation"])
|
|
|
|
|
{
|
|
|
|
|
_relation = [coder decodeIntegerForKey: @"NSRelation"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_relation = NSLayoutRelationEqual;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-09 11:27:06 +00:00
|
|
|
|
if ([coder containsValueForKey: @"NSPriority"])
|
|
|
|
|
{
|
2020-06-09 11:34:40 +00:00
|
|
|
|
_priority = [coder decodeFloatForKey: @"NSPriority"];
|
2020-06-09 11:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-06-09 11:34:40 +00:00
|
|
|
|
_priority = NSLayoutPriorityRequired; // if it is not present, this defaults to 1000... per testing with Cocoa.
|
2020-06-09 11:27:06 +00:00
|
|
|
|
}
|
2020-05-10 18:49:06 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-05-10 19:03:31 +00:00
|
|
|
|
[coder decodeValueOfObjCType: @encode(float)
|
|
|
|
|
at: &_constant];
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSUInteger)
|
|
|
|
|
at: &_firstAttribute];
|
2020-06-14 23:13:17 +00:00
|
|
|
|
_firstItem = RETAIN([coder decodeObject]);
|
2020-06-09 11:34:40 +00:00
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSUInteger)
|
2020-05-10 19:03:31 +00:00
|
|
|
|
at: &_secondAttribute];
|
2020-06-14 23:13:17 +00:00
|
|
|
|
_secondItem = RETAIN([coder decodeObject]);
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(float)
|
|
|
|
|
at: &_multiplier];
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSUInteger)
|
|
|
|
|
at: &_relation];
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(float)
|
2020-06-09 11:27:06 +00:00
|
|
|
|
at: &_priority];
|
2020-05-10 18:49:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-03 11:12:31 +00:00
|
|
|
|
|
2020-06-14 08:23:13 +00:00
|
|
|
|
[NSLayoutConstraint _activateConstraint: self];
|
2020-06-01 06:27:49 +00:00
|
|
|
|
|
2020-05-10 18:49:06 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder *)coder
|
|
|
|
|
{
|
|
|
|
|
if ([coder allowsKeyedCoding])
|
|
|
|
|
{
|
2020-05-10 19:03:31 +00:00
|
|
|
|
[coder encodeFloat: _constant
|
|
|
|
|
forKey: @"NSConstant"];
|
|
|
|
|
[coder encodeInteger: _firstAttribute
|
|
|
|
|
forKey: @"NSFirstAttribute"];
|
|
|
|
|
[coder encodeObject: _firstItem
|
|
|
|
|
forKey: @"NSFirstItem"];
|
|
|
|
|
[coder encodeInteger: _secondAttribute
|
|
|
|
|
forKey: @"NSSecondAttribute"];
|
|
|
|
|
[coder encodeObject: _secondItem
|
|
|
|
|
forKey: @"NSSecondItem"];
|
2020-06-14 23:13:17 +00:00
|
|
|
|
[coder encodeFloat: _multiplier
|
|
|
|
|
forKey: @"NSMultiplier"];
|
|
|
|
|
[coder encodeInteger: _relation
|
|
|
|
|
forKey: @"NSRelation"];
|
2020-06-09 11:34:40 +00:00
|
|
|
|
[coder encodeFloat: _priority
|
2020-06-09 11:27:06 +00:00
|
|
|
|
forKey: @"NSPriority"];
|
2020-05-10 18:49:06 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-05-10 19:03:31 +00:00
|
|
|
|
[coder encodeValueOfObjCType: @encode(float)
|
|
|
|
|
at: &_constant];
|
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSUInteger)
|
|
|
|
|
at: &_firstAttribute];
|
|
|
|
|
[coder encodeObject: _firstItem];
|
2020-06-09 11:34:40 +00:00
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSUInteger)
|
2020-05-10 19:03:31 +00:00
|
|
|
|
at: &_secondAttribute];
|
|
|
|
|
[coder encodeObject: _secondItem];
|
2020-06-14 23:13:17 +00:00
|
|
|
|
[coder encodeValueOfObjCType: @encode(float)
|
|
|
|
|
at: &_multiplier];
|
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSUInteger)
|
|
|
|
|
at: &_relation];
|
2020-06-09 11:34:40 +00:00
|
|
|
|
[coder encodeValueOfObjCType: @encode(float)
|
2020-06-09 11:27:06 +00:00
|
|
|
|
at: &_priority];
|
2020-05-10 18:49:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone *)z
|
|
|
|
|
{
|
|
|
|
|
NSLayoutConstraint *constraint = [[NSLayoutConstraint allocWithZone: z]
|
|
|
|
|
initWithItem: _firstItem
|
|
|
|
|
attribute: _firstAttribute
|
|
|
|
|
relatedBy: _relation
|
|
|
|
|
toItem: _secondItem
|
|
|
|
|
attribute: _secondAttribute
|
|
|
|
|
multiplier: _multiplier
|
2020-06-14 10:57:26 +00:00
|
|
|
|
constant: _constant
|
|
|
|
|
priority: _priority];
|
2020-05-10 18:49:06 +00:00
|
|
|
|
return constraint;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-01 06:27:49 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2020-06-14 07:29:39 +00:00
|
|
|
|
[NSLayoutConstraint _removeConstraint: self];
|
2020-06-01 06:27:49 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-26 19:06:28 +00:00
|
|
|
|
- (NSString *) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"%@ <firstItem = %@, firstAttribute = %ld, relation = %ld, secondItem = %@, "
|
2020-06-14 03:45:08 +00:00
|
|
|
|
"secondAttribute = %ld, multiplier = %f, constant = %f, priority = %f>",
|
2020-05-26 19:06:28 +00:00
|
|
|
|
[super description],
|
|
|
|
|
_firstItem,
|
|
|
|
|
_firstAttribute,
|
|
|
|
|
_relation,
|
|
|
|
|
_secondItem,
|
|
|
|
|
_secondAttribute,
|
|
|
|
|
_multiplier,
|
2020-06-14 03:45:08 +00:00
|
|
|
|
_constant,
|
|
|
|
|
_priority];
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 08:23:13 +00:00
|
|
|
|
// item1.attribute1 = multiplier × item2.attribute2 + constant
|
2020-06-14 03:45:08 +00:00
|
|
|
|
- (void) _applyConstraint
|
|
|
|
|
{
|
2020-06-14 16:39:19 +00:00
|
|
|
|
// Currently not implemented.
|
2020-05-26 19:06:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 08:23:13 +00:00
|
|
|
|
+ (void) _handleWindowResize: (NSNotification *)notification
|
2020-06-03 11:12:31 +00:00
|
|
|
|
{
|
2020-07-30 08:56:32 +00:00
|
|
|
|
/*
|
2020-06-14 03:45:08 +00:00
|
|
|
|
NSLayoutConstraint *c = nil;
|
|
|
|
|
NSEnumerator *en = [activeConstraints objectEnumerator];
|
|
|
|
|
|
2020-06-14 10:02:19 +00:00
|
|
|
|
// Only apply to the window in the notification...
|
2020-06-14 03:45:08 +00:00
|
|
|
|
while ((c = [en nextObject]) != nil)
|
|
|
|
|
{
|
2020-06-14 10:02:19 +00:00
|
|
|
|
NSWindow *w = [[c firstItem] window];
|
|
|
|
|
if (w == [notification object])
|
|
|
|
|
{
|
|
|
|
|
[c _applyConstraint];
|
|
|
|
|
}
|
2020-06-14 03:45:08 +00:00
|
|
|
|
}
|
2020-07-30 08:56:32 +00:00
|
|
|
|
*/
|
2020-06-03 11:12:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-10 06:26:06 +00:00
|
|
|
|
@end
|
2023-02-19 04:00:01 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSView (NSConstraintBasedLayoutCoreMethods)
|
|
|
|
|
|
|
|
|
|
- (void) updateConstraintsForSubtreeIfNeeded
|
|
|
|
|
{
|
|
|
|
|
NSArray *subviews = [self subviews];
|
|
|
|
|
FOR_IN (NSView *, subview, subviews)
|
|
|
|
|
[subview updateConstraintsForSubtreeIfNeeded];
|
|
|
|
|
END_FOR_IN (subviews);
|
|
|
|
|
|
|
|
|
|
if ([self needsUpdateConstraints])
|
|
|
|
|
{
|
|
|
|
|
[self updateConstraints];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) updateConstraints
|
|
|
|
|
{
|
|
|
|
|
if ([self translatesAutoresizingMaskIntoConstraints] &&
|
|
|
|
|
[self superview] != nil)
|
|
|
|
|
{
|
|
|
|
|
NSArray *autoresizingConstraints = [NSAutoresizingMaskLayoutConstraint
|
|
|
|
|
constraintsWithAutoresizingMask: [self autoresizingMask]
|
|
|
|
|
subitem: self
|
|
|
|
|
frame: [self frame]
|
|
|
|
|
superitem: [self superview]
|
|
|
|
|
bounds: [[self superview] bounds]];
|
2023-02-23 01:29:28 +00:00
|
|
|
|
[self addConstraints: autoresizingConstraints];
|
2023-02-19 04:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-20 07:09:23 +00:00
|
|
|
|
[self _setNeedsUpdateConstraints: NO];
|
2023-02-19 04:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSView (NSConstraintBasedLayoutInstallingConstraints)
|
|
|
|
|
|
2023-02-27 08:56:37 +00:00
|
|
|
|
- (GSAutoLayoutEngine*) _getOrCreateLayoutEngine
|
2023-02-26 02:28:15 +00:00
|
|
|
|
{
|
2023-02-27 08:56:37 +00:00
|
|
|
|
if (![self window])
|
2023-02-26 02:28:15 +00:00
|
|
|
|
{
|
2023-02-27 08:56:37 +00:00
|
|
|
|
return nil;
|
2023-02-26 02:28:15 +00:00
|
|
|
|
}
|
2023-02-27 08:56:37 +00:00
|
|
|
|
if (![[self window] _layoutEngine])
|
2023-02-26 02:28:15 +00:00
|
|
|
|
{
|
2023-02-27 08:56:37 +00:00
|
|
|
|
[[self window] _bootstrapAutoLayout];
|
2023-02-26 02:28:15 +00:00
|
|
|
|
}
|
2023-02-27 08:56:37 +00:00
|
|
|
|
|
|
|
|
|
return [[self window] _layoutEngine];
|
|
|
|
|
}
|
2023-02-26 02:28:15 +00:00
|
|
|
|
|
2023-02-19 04:00:01 +00:00
|
|
|
|
- (void) addConstraint: (NSLayoutConstraint *)constraint
|
|
|
|
|
{
|
2023-02-27 08:56:37 +00:00
|
|
|
|
if (![self _getOrCreateLayoutEngine])
|
2023-02-26 02:28:15 +00:00
|
|
|
|
{
|
2023-02-27 08:56:37 +00:00
|
|
|
|
return;
|
2023-02-26 02:28:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[self _layoutEngine] addConstraint: constraint];
|
2023-02-19 04:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) addConstraints: (NSArray*)constraints
|
|
|
|
|
{
|
2023-02-27 08:56:37 +00:00
|
|
|
|
if (![self _getOrCreateLayoutEngine])
|
2023-02-26 02:28:15 +00:00
|
|
|
|
{
|
2023-02-27 08:56:37 +00:00
|
|
|
|
return;
|
2023-02-26 02:28:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[self _layoutEngine] addConstraints: constraints];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeConstraint: (NSLayoutConstraint *)constraint
|
|
|
|
|
{
|
|
|
|
|
if (![self _layoutEngine])
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[self _layoutEngine] removeConstraint: constraint];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeConstraints: (NSArray *)constraints
|
|
|
|
|
{
|
|
|
|
|
if (![self _layoutEngine])
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[self _layoutEngine] removeConstraints: constraints];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) constraints
|
|
|
|
|
{
|
|
|
|
|
GSAutoLayoutEngine *engine = [self _layoutEngine];
|
|
|
|
|
if (!engine)
|
|
|
|
|
{
|
|
|
|
|
return [NSArray array];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [engine constraintsForView: self];
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-19 04:00:01 +00:00
|
|
|
|
@end
|
2023-02-26 02:28:15 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSWindow (NSConstraintBasedLayoutCoreMethods)
|
|
|
|
|
|
|
|
|
|
- (void) layoutIfNeeded
|
|
|
|
|
{
|
|
|
|
|
[self updateConstraintsIfNeeded];
|
|
|
|
|
[[self contentView] _layoutViewAndSubViews];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) updateConstraintsIfNeeded
|
|
|
|
|
{
|
|
|
|
|
[[self contentView] updateConstraintsForSubtreeIfNeeded];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _bootstrapAutoLayout
|
|
|
|
|
{
|
2023-02-28 08:16:27 +00:00
|
|
|
|
GSAutoLayoutEngine *layoutEngine = [[GSAutoLayoutEngine alloc] init];
|
|
|
|
|
[self _setLayoutEngine: layoutEngine];
|
|
|
|
|
AUTORELEASE(layoutEngine);
|
2023-02-26 02:28:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|