libs-gui/Source/NSLayoutConstraint.m

580 lines
14 KiB
Mathematica
Raw Normal View History

/* Implementation of class NSLayoutConstraint
Copyright (C) 2020 Free Software Foundation, Inc.
By: Gregory Casamento <greg.casamento@gmail.com>
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"
#import "AppKit/NSLayoutConstraint.h"
#import "AppKit/NSWindow.h"
static NSMutableArray *activeConstraints = nil;
static NSNotificationCenter *nc = nil;
2020-05-10 12:22:12 +00:00
@implementation NSLayoutConstraint
2020-06-01 06:27:49 +00:00
+ (void) initialize
{
if (self == [NSLayoutConstraint class])
{
[self setVersion: 1];
activeConstraints = [[NSMutableArray alloc] initWithCapacity: 10];
nc = [NSNotificationCenter defaultCenter];
2020-06-01 06:27:49 +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;
}
+ (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;
}
+ (void) _addActiveConstraint: (NSLayoutConstraint *)constraint
{
NSUInteger idx = 0;
NSEnumerator *en = [activeConstraints objectEnumerator];
NSLayoutConstraint *c = nil;
while ((c = [en nextObject]) != nil)
{
if ([activeConstraints containsObject: c])
break; // if it contains the current constraint, skip...
if ([c priority] < [constraint priority])
{
idx++;
}
else
{
break;
}
}
[nc addObserver: constraint
selector: @selector(_handleWindowResize:)
name: NSWindowDidResizeNotification
object: [[c firstItem] window]];
[activeConstraints insertObject: constraint
atIndex: idx];
}
+ (void) _removeConstraint: (NSLayoutConstraint *)constraint
{
[activeConstraints removeObject: constraint];
[nc removeObserver: constraint];
}
+ (NSArray *) constraintsWithVisualFormat: (NSString *)fmt
options: (NSLayoutFormatOptions)opt
metrics: (NSDictionary *)metrics
views: (NSDictionary *)views
2020-05-10 12:22:12 +00:00
{
2020-06-01 06:27:49 +00:00
NSMutableArray *array = [NSMutableArray arrayWithCapacity: 10];
return array;
2020-05-10 12:22:12 +00:00
}
// Designated initializer...
+ (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
constant: c];
AUTORELEASE(constraint);
return constraint;
}
+ (void) activateConstraints: (NSArray *)constraints
{
NSEnumerator *en = [constraints objectEnumerator];
NSLayoutConstraint *c = nil;
while ((c = [en nextObject]) != nil)
{
[NSLayoutConstraint _addActiveConstraint: c];
}
}
+ (void) deactivateConstraints: (NSArray *)constraints
{
NSEnumerator *en = [constraints objectEnumerator];
NSLayoutConstraint *c = nil;
while ((c = [en nextObject]) != nil)
{
[NSLayoutConstraint _removeConstraint: c];
}
}
2020-05-10 18:49:06 +00:00
- (instancetype) initWithItem: (id)firstItem
attribute: (NSLayoutAttribute)firstAttribute
relatedBy: (NSLayoutRelation)relation
2020-05-10 18:49:06 +00:00
toItem: (id)secondItem
attribute: (NSLayoutAttribute)secondAttribute
multiplier: (CGFloat)multiplier
constant: (CGFloat)constant;
{
self = [super init];
if (self != nil)
{
2020-05-10 18:49:06 +00:00
_firstItem = firstItem;
_secondItem = secondItem;
_firstAttribute = firstAttribute;
_secondAttribute = secondAttribute;
_relation = relation;
2020-05-10 18:49:06 +00:00
_multiplier = multiplier;
_constant = constant;
2020-06-02 08:58:13 +00:00
[NSLayoutConstraint _addActiveConstraint: self];
}
return self;
}
2020-05-10 12:22:12 +00:00
// Active
- (BOOL) isActive
{
return [activeConstraints containsObject: self];
}
- (void) setActive: (BOOL)flag
{
if (flag)
{
[NSLayoutConstraint _addActiveConstraint: self];
2020-05-10 12:22:12 +00:00
}
else
{
[NSLayoutConstraint _removeConstraint: self];
2020-05-10 12:22:12 +00:00
}
}
// compare and isEqual...
- (NSComparisonResult) compare: (NSLayoutConstraint *)constraint
{
if ([self priority] < [constraint priority])
{
return NSOrderedAscending;
}
else if ([self priority] > [constraint priority])
{
return NSOrderedDescending;
}
return NSOrderedSame;
}
- (BOOL) isEqual: (NSLayoutConstraint *)constraint
{
BOOL result = NO;
if (YES == [super isEqual: constraint])
{
result = YES;
}
else
{
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;
}
- (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"];
}
if ([coder containsValueForKey: @"NSPriority"])
{
_priority = [coder decodeFloatForKey: @"NSPriority"];
}
else
{
_priority = NSLayoutPriorityRequired; // if it is not present, this defaults to 1000... per testing with Cocoa.
}
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];
_firstItem = [coder decodeObject];
[coder decodeValueOfObjCType: @encode(NSUInteger)
2020-05-10 19:03:31 +00:00
at: &_secondAttribute];
_secondItem = [coder decodeObject];
[coder decodeValueOfObjCType: @encode(float)
at: &_priority];
2020-05-10 18:49:06 +00:00
}
}
[NSLayoutConstraint _addActiveConstraint: 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"];
[coder encodeFloat: _priority
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];
[coder encodeValueOfObjCType: @encode(NSUInteger)
2020-05-10 19:03:31 +00:00
at: &_secondAttribute];
[coder encodeObject: _secondItem];
[coder encodeValueOfObjCType: @encode(float)
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
constant: _constant];
[constraint setPriority: [self priority]];
2020-05-10 18:49:06 +00:00
return constraint;
}
2020-06-01 06:27:49 +00:00
- (void) dealloc
{
[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 = %@, "
"secondAttribute = %ld, multiplier = %f, constant = %f, priority = %f>",
2020-05-26 19:06:28 +00:00
[super description],
_firstItem,
_firstAttribute,
_relation,
_secondItem,
_secondAttribute,
_multiplier,
_constant,
_priority];
}
- (void) _applyConstraint
{
NSLog(@"activeConstraints = %@", activeConstraints);
2020-05-26 19:06:28 +00:00
}
- (void) _handleWindowResize: (NSNotification *)notification
{
NSLayoutConstraint *c = nil;
NSEnumerator *en = [activeConstraints objectEnumerator];
while ((c = [en nextObject]) != nil)
{
[c _applyConstraint];
}
}
@end