Rewrote darwin/box.m's layout code to create constraints directly. Let's try this out.

This commit is contained in:
Pietro Gagliardi 2016-04-30 17:45:44 -04:00
parent 835c711a24
commit c87a932a6d
3 changed files with 128 additions and 109 deletions

View File

@ -18,6 +18,11 @@ NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRela
return c; return c;
} }
void setHuggingPri(NSView *view, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation)
{
[view setContentHuggingPriority:priority forOrientation:orientation];
}
NSLayoutPriority horzHuggingPri(NSView *view) NSLayoutPriority horzHuggingPri(NSView *view)
{ {
return [view contentHuggingPriorityForOrientation:NSLayoutConstraintOrientationHorizontal]; return [view contentHuggingPriorityForOrientation:NSLayoutConstraintOrientationHorizontal];

View File

@ -17,8 +17,11 @@ struct uiBox {
NSMutableArray *stretchy; // []NSNumber NSMutableArray *stretchy; // []NSNumber
// this view is made stretchy if there are no stretchy views // this view is made stretchy if there are no stretchy views
NSView *noStretchyView; NSView *noStretchyView;
NSString *primaryDirPrefix; NSLayoutAttribute primaryStart;
NSString *secondaryDirPrefix; NSLayoutAttribute primaryEnd;
NSLayoutAttribute secondaryStart;
NSLayoutAttribute secondaryEnd;
NSLayoutAttribute primarySize;
NSLayoutConstraintOrientation primaryOrientation; NSLayoutConstraintOrientation primaryOrientation;
NSLayoutConstraintOrientation secondaryOrientation; NSLayoutConstraintOrientation secondaryOrientation;
}; };
@ -85,21 +88,6 @@ static void uiBoxSyncEnableState(uiDarwinControl *c, int enabled)
uiDarwinControlDefaultSetSuperview(uiBox, view) uiDarwinControlDefaultSetSuperview(uiBox, view)
static NSString *viewName(uintmax_t n)
{
return [NSString stringWithFormat:@"view%ju", n];
}
static NSString *widthMetricName(uintmax_t n)
{
return [NSString stringWithFormat:@"view%juwidth", n];
}
static NSString *heightMetricName(uintmax_t n)
{
return [NSString stringWithFormat:@"view%juheight", n];
}
static int isStretchy(uiBox *b, uintmax_t n) static int isStretchy(uiBox *b, uintmax_t n)
{ {
NSNumber *num; NSNumber *num;
@ -108,117 +96,135 @@ static int isStretchy(uiBox *b, uintmax_t n)
return [num intValue]; return [num intValue];
} }
// TODO do we still need to set hugging? I think we do for stretchy controls... static NSView *boxView(uiBox *b, uintmax_t n)
// TODO try unsetting spinbox intrinsics and seeing what happens
static void relayout(uiBox *b)
{ {
NSMutableDictionary *metrics; NSValue *val;
NSMutableDictionary *views; uiControl *c;
uintmax_t i, n;
BOOL hasStretchy;
uintmax_t firstStretchy;
NSMutableString *constraint;
if ([b->children count] == 0) val = (NSValue *) [b->children objectAtIndex:n];
return; c = (uiControl *) [val pointerValue];
return (NSView *) uiControlHandle(c);
[b->view removeConstraints:[b->view constraints]];
// first lay out all children, collect the views and their fitting sizes (for non-stretchy controls)
// also figure out which is the first stretchy control, if any
metrics = [NSMutableDictionary new];
views = [NSMutableDictionary new];
hasStretchy = NO;
n = 0;
while (n < [b->children count]) {
uiControl *child;
uiDarwinControl *cc;
NSView *childView;
NSSize fittingSize;
child = childAt(b, n);
cc = uiDarwinControl(child);
childView = (NSView *) uiControlHandle(child);
[views setObject:childView forKey:viewName(n)];
//TODO (*(cc->Relayout))(cc);
fittingSize = fittingAlignmentSize(childView);
[metrics setObject:[NSNumber numberWithDouble:fittingSize.width]
forKey:widthMetricName(n)];
[metrics setObject:[NSNumber numberWithDouble:fittingSize.height]
forKey:heightMetricName(n)];
if (!hasStretchy && isStretchy(b, n)) {
hasStretchy = YES;
firstStretchy = n;
}
n++;
} }
// if there are no stretchy controls, we must add the no-stretchy view static void addRemoveNoStretchyView(uiBox *b, BOOL hasStretchy)
// if there are, we must remove it {
if (!hasStretchy) { if (!hasStretchy) {
if ([b->noStretchyView superview] == nil) if ([b->noStretchyView superview] == nil)
[b->view addSubview:b->noStretchyView]; [b->view addSubview:b->noStretchyView];
[views setObject:b->noStretchyView forKey:@"noStretchyView"];
} else { } else {
if ([b->noStretchyView superview] != nil) if ([b->noStretchyView superview] != nil)
[b->noStretchyView removeFromSuperview]; [b->noStretchyView removeFromSuperview];
} }
}
// TODO do we still need to set hugging? I think we do for stretchy controls...
// TODO try unsetting spinbox intrinsics and seeing what happens
static void relayout(uiBox *b)
{
NSLayoutConstraint *constraint;
uintmax_t i, n;
BOOL hasStretchy;
NSView *firstStretchy = nil;
CGFloat padding;
NSView *prev, *next;
if ([b->children count] == 0)
return;
padding = 0;
if (b->padded)
padding = 8.0; // TODO named constant
[b->view removeConstraints:[b->view constraints]];
// first, attach the first view to the leading
prev = boxView(b, 0);
[b->view addConstraint:mkConstraint(prev, b->primaryStart,
NSLayoutRelationEqual,
b->view, b->primaryStart,
1, 0,
@"uiBox first primary constraint")];
// next, assemble the views in the primary direction // next, assemble the views in the primary direction
// they all go in a straight line // they all go in a straight line
constraint = [NSMutableString new]; // also figure out whether we have stretchy controls, and which is the first
[constraint appendString:b->primaryDirPrefix]; if (isStretchy(b, 0)) {
[constraint appendString:@"|"]; hasStretchy = YES;
for (i = 0; i < n; i++) { firstStretchy = prev;
if (b->padded && i != 0) } else
[constraint appendString:@"-"]; hasStretchy = NO;
[constraint appendString:@"["]; for (i = 1; i < n; i++) {
[constraint appendString:viewName(i)]; next = boxView(b, i);
// implement multiple stretchiness properly if (!hasStretchy && isStretchy(b, i)) {
if (isStretchy(b, i) && i != firstStretchy) { hasStretchy = YES;
[constraint appendString:@"(=="]; firstStretchy = next;
[constraint appendString:viewName(firstStretchy)];
[constraint appendString:@")"];
} }
// if the control is not stretchy, restrict it to the fitting size [b->view addConstraint:mkConstraint(next, b->primaryStart,
if (!isStretchy(b, i)) { NSLayoutRelationEqual,
[constraint appendString:@"(=="]; prev, b->primaryEnd,
if (b->vertical) 1, padding,
[constraint appendString:heightMetricName(i)]; @"uiBox later primary constraint")];
else prev = next;
[constraint appendString:widthMetricName(i)];
[constraint appendString:@")"];
} }
[constraint appendString:@"]"];
// if there is a stretchy control, add the no-stretchy view
addRemoveNoStretchyView(b, hasStretchy);
if (hasStretchy)
[b->view addConstraint:mkConstraint(b->noStretchyView, b->primaryStart,
NSLayoutRelationEqual,
prev, b->primaryEnd,
1, 0, // don't space between the last control and the no-stretchy view
@"uiBox no-stretchy primary constraint")];
prev = b->noStretchyView;
} }
if (!hasStretchy)
// don't space between the last control and the no-stretchy view // and finally end the primary direction
[constraint appendString:@"[noStretchyView]"]; [b->view addConstraint:mkConstraint(prev, p->primaryEnd,
[constraint appendString:@"|"]; NSLayoutRelationEqual,
addConstraint(b->view, constraint, metrics, views); b->view, b->primaryEnd,
[constraint release]; 1, 0,
@"uiBox last primary constraint"];
// next: assemble the views in the secondary direction // next: assemble the views in the secondary direction
// each of them will span the secondary direction // each of them will span the secondary direction
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
constraint = [NSMutableString new]; [b->view addConstraint:mkConstraint(boxView(b, i), b->secondaryStart,
[constraint appendString:b->secondaryDirPrefix]; NSLayoutRelationEqual,
[constraint appendString:@"|["]; b->view, b->secondaryStart,
[constraint appendString:viewName(i)]; 1, 0,
[constraint appendString:@"]|"]; @"uiBox start secondary constraint")];
addConstraint(b->view, constraint, nil, views); [b->view addConstraint:mkConstraint(boxView(b, i), b->secondaryEnd,
[constraint release]; NSLayoutRelationEqual,
b->view, b->secondaryEnd,
1, 0,
@"uiBox start secondary constraint")];
} }
if (!hasStretchy) { // and again to the no-stretchy view if (!hasStretchy) { // and again to the no-stretchy view
constraint = [NSMutableString new]; [b->view addConstraint:mkConstraint(b->noStretchyView, b->secondaryStart,
[constraint appendString:b->secondaryDirPrefix]; NSLayoutRelationEqual,
[constraint appendString:@"|[noStretchyView]|"]; b->view, b->secondaryStart,
addConstraint(b->view, constraint, nil, views); 1, 0,
[constraint release]; @"uiBox no-stretchy view start secondary constraint")];
[b->view addConstraint:mkConstraint(b->noStretchyView, b->secondaryEnd,
NSLayoutRelationEqual,
b->view, b->secondaryEnd,
1, 0,
@"uiBox no-stretchy view start secondary constraint")];
} }
[metrics release]; // finally, set sizes for stretchy controls
[views release]; if (hasStretchy)
for (i = 0; i < n; i++) {
if (!isStretchy(b, i))
continue;
prev = boxView(b, i);
if (prev == firstStretchy)
continue;
[b->view addConstraint:mkConstraint(prev, b->primarySize,
NSLayoutRelationEqual,
firstStretchy, b->primarySize,
1, 0,
@"uiBox stretchy sizing")];
}
} }
void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) void uiBoxAppend(uiBox *b, uiControl *c, int stretchy)
@ -287,13 +293,19 @@ static uiBox *finishNewBox(BOOL vertical)
b->vertical = vertical; b->vertical = vertical;
if (b->vertical) { if (b->vertical) {
b->primaryDirPrefix = @"V:"; b->primaryStart = NSLayoutAttributeTop;
b->secondaryDirPrefix = @"H:"; b->primaryEnd = NSLayoutAttributeBottom;
b->secondaryStart = NSLayoutAttributeLeading;
b->secondaryEnd = NSLayoutAttributeTrailing;
b->primarySize = NSLayoutAttributeHeight;
b->primaryOrientation = NSLayoutConstraintOrientationVertical; b->primaryOrientation = NSLayoutConstraintOrientationVertical;
b->secondaryOrientation = NSLayoutConstraintOrientationHorizontal; b->secondaryOrientation = NSLayoutConstraintOrientationHorizontal;
} else { } else {
b->primaryDirPrefix = @"H:"; b->primaryStart = NSLayoutAttributeLeading;
b->secondaryDirPrefix = @"V:"; b->primaryEnd = NSLayoutAttributeTrailing;
b->secondaryStart = NSLayoutAttributeTop;
b->secondaryEnd = NSLayoutAttributeBottom;
b->primarySize = NSLayoutAttributeWidth;
b->primaryOrientation = NSLayoutConstraintOrientationHorizontal; b->primaryOrientation = NSLayoutConstraintOrientationHorizontal;
b->secondaryOrientation = NSLayoutConstraintOrientationVertical; b->secondaryOrientation = NSLayoutConstraintOrientationVertical;
} }

View File

@ -58,6 +58,8 @@ extern void uninitAlloc(void);
// autolayout.m // autolayout.m
extern NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRelation relation, id view2, NSLayoutAttribute attr2, CGFloat multiplier, CGFloat c, NSString *desc); extern NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRelation relation, id view2, NSLayoutAttribute attr2, CGFloat multiplier, CGFloat c, NSString *desc);
extern NSLayoutPriority horzHuggingPri(NSView *view); extern NSLayoutPriority horzHuggingPri(NSView *view);
extern void setHuggingPri(NSView *view, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation);
extern NSLayoutPriority horzHuggingPri(NSView *view);
extern void setHorzHuggingPri(NSView *view, NSLayoutPriority priority); extern void setHorzHuggingPri(NSView *view, NSLayoutPriority priority);
extern NSLayoutPriority vertHuggingPri(NSView *view); extern NSLayoutPriority vertHuggingPri(NSView *view);
extern void setVertHuggingPri(NSView *view, NSLayoutPriority priority); extern void setVertHuggingPri(NSView *view, NSLayoutPriority priority);