2015-07-31 22:25:59 -05:00
|
|
|
// 31 july 2015
|
|
|
|
#import "osxaltest.h"
|
|
|
|
|
2015-08-01 13:22:45 -05:00
|
|
|
@implementation tBox {
|
2015-07-31 22:25:59 -05:00
|
|
|
NSMutableArray *children;
|
2015-08-01 21:38:01 -05:00
|
|
|
NSMutableArray *stretchy;
|
2015-07-31 22:25:59 -05:00
|
|
|
NSView *sv;
|
2015-08-01 01:16:35 -05:00
|
|
|
BOOL vertical;
|
2015-08-01 20:41:36 -05:00
|
|
|
id<tControl> parent;
|
2015-07-31 22:25:59 -05:00
|
|
|
}
|
|
|
|
|
2015-08-01 13:22:45 -05:00
|
|
|
- (id)tInitVertical:(BOOL)vert
|
2015-07-31 22:25:59 -05:00
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (self) {
|
|
|
|
self->children = [NSMutableArray new];
|
2015-08-01 21:38:01 -05:00
|
|
|
self->stretchy = [NSMutableArray new];
|
2015-07-31 22:25:59 -05:00
|
|
|
self->sv = nil;
|
2015-08-01 01:16:35 -05:00
|
|
|
self->vertical = vert;
|
2015-08-01 20:41:36 -05:00
|
|
|
self->parent = nil;
|
2015-07-31 22:25:59 -05:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2015-08-01 13:22:45 -05:00
|
|
|
- (void)tAddControl:(id<tControl>)c stretchy:(BOOL)s
|
2015-07-31 22:25:59 -05:00
|
|
|
{
|
2015-08-01 14:08:33 -05:00
|
|
|
if (self->sv != nil)
|
2015-08-02 17:16:44 -05:00
|
|
|
[c tSetParent:self addToView:self->sv relayout:NO];
|
2015-08-01 14:08:33 -05:00
|
|
|
[self->children addObject:c];
|
2015-08-01 21:38:01 -05:00
|
|
|
[self->stretchy addObject:[NSNumber numberWithBool:s]];
|
2015-08-01 14:08:33 -05:00
|
|
|
// TODO mark as needing relayout
|
2015-08-01 21:13:41 -05:00
|
|
|
[self tRelayout];
|
2015-07-31 22:25:59 -05:00
|
|
|
}
|
|
|
|
|
2015-08-02 17:16:44 -05:00
|
|
|
- (void)tSetParent:(id<tControl>)p addToView:(NSView *)v relayout:(BOOL)relayout
|
2015-07-31 22:25:59 -05:00
|
|
|
{
|
2015-08-01 20:41:36 -05:00
|
|
|
self->parent = p;
|
2015-07-31 22:25:59 -05:00
|
|
|
self->sv = v;
|
2015-08-01 01:16:35 -05:00
|
|
|
[self->children enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
|
2015-08-01 14:08:33 -05:00
|
|
|
id<tControl> c;
|
2015-08-01 01:16:35 -05:00
|
|
|
|
2015-08-01 14:08:33 -05:00
|
|
|
c = (id<tControl>) obj;
|
2015-08-02 17:16:44 -05:00
|
|
|
[c tSetParent:self addToView:self->sv relayout:NO];
|
2015-08-01 01:16:35 -05:00
|
|
|
}];
|
2015-08-02 17:16:44 -05:00
|
|
|
if (relayout)
|
|
|
|
[self tRelayout];
|
2015-07-31 22:25:59 -05:00
|
|
|
}
|
|
|
|
|
2015-08-02 15:55:21 -05:00
|
|
|
// TODO MASSIVE CLEANUP and comments everywhere too
|
2015-08-02 10:25:39 -05:00
|
|
|
- (void)tFillAutoLayout:(tAutoLayoutParams *)p
|
2015-08-01 01:16:35 -05:00
|
|
|
{
|
2015-08-01 17:05:50 -05:00
|
|
|
NSMutableArray *subhorz, *subvert;
|
2015-08-02 13:49:10 -05:00
|
|
|
NSMutableArray *subhorzleft, *subhorzright;
|
|
|
|
NSMutableArray *subverttop, *subvertbottom;
|
2015-08-02 18:27:55 -05:00
|
|
|
__block uintmax_t *first;
|
2015-08-01 17:05:50 -05:00
|
|
|
NSUInteger i;
|
2015-08-02 10:25:39 -05:00
|
|
|
tAutoLayoutParams pp;
|
2015-08-02 17:16:44 -05:00
|
|
|
void (^buildPrimary)(NSMutableArray *in, BOOL first, BOOL last,
|
|
|
|
NSMutableArray *out, NSMutableArray *outstart, NSMutableArray *outend);
|
2015-08-01 01:16:35 -05:00
|
|
|
|
2015-08-01 17:05:50 -05:00
|
|
|
first = (uintmax_t *) malloc([self->children count] * sizeof (uintmax_t));
|
|
|
|
if (first == NULL)
|
|
|
|
abort();
|
|
|
|
subhorz = [NSMutableArray new];
|
2015-08-02 13:49:10 -05:00
|
|
|
subhorzleft = [NSMutableArray new];
|
|
|
|
subhorzright = [NSMutableArray new];
|
2015-08-01 17:05:50 -05:00
|
|
|
subvert = [NSMutableArray new];
|
2015-08-02 13:49:10 -05:00
|
|
|
subverttop = [NSMutableArray new];
|
|
|
|
subvertbottom = [NSMutableArray new];
|
2015-08-02 10:25:39 -05:00
|
|
|
|
|
|
|
pp.horz = subhorz;
|
2015-08-02 13:49:10 -05:00
|
|
|
pp.horzAttachLeft = subhorzleft;
|
|
|
|
pp.horzAttachRight = subhorzright;
|
2015-08-02 10:25:39 -05:00
|
|
|
pp.vert = subvert;
|
2015-08-02 13:49:10 -05:00
|
|
|
pp.vertAttachTop = subverttop;
|
|
|
|
pp.vertAttachBottom = subvertbottom;
|
2015-08-02 10:25:39 -05:00
|
|
|
pp.views = p->views;
|
|
|
|
pp.n = p->n;
|
2015-08-02 17:54:33 -05:00
|
|
|
if (self->vertical) {
|
|
|
|
pp.vertFirstStretchy = YES;
|
|
|
|
pp.horzStretchy = YES;
|
|
|
|
pp.horzFirstStretchy = YES;
|
|
|
|
} else {
|
|
|
|
pp.horzFirstStretchy = YES;
|
|
|
|
pp.vertStretchy = YES;
|
|
|
|
pp.vertFirstStretchy = YES;
|
|
|
|
}
|
2015-08-01 17:05:50 -05:00
|
|
|
for (i = 0; i < [self->children count]; i++) {
|
|
|
|
id<tControl> cur;
|
2015-08-02 11:52:24 -05:00
|
|
|
NSNumber *isStretchy;
|
2015-08-01 01:16:35 -05:00
|
|
|
|
2015-08-02 10:25:39 -05:00
|
|
|
first[i] = pp.n;
|
2015-08-01 17:05:50 -05:00
|
|
|
cur = (id<tControl>) [self->children objectAtIndex:i];
|
2015-08-02 11:52:24 -05:00
|
|
|
isStretchy = (NSNumber *) [self->stretchy objectAtIndex:i];
|
2015-08-02 15:55:21 -05:00
|
|
|
if (self->vertical) {
|
2015-08-02 17:54:33 -05:00
|
|
|
pp.vertStretchy = [isStretchy boolValue];
|
2015-08-02 15:55:21 -05:00
|
|
|
pp.vertFirst = p->vertFirst && i == 0;
|
|
|
|
pp.vertLast = p->vertLast && i == ([self->children count] - 1);
|
|
|
|
pp.horzFirst = p->horzFirst;
|
|
|
|
pp.horzLast = p->horzLast;
|
|
|
|
} else {
|
2015-08-02 17:54:33 -05:00
|
|
|
pp.horzStretchy = [isStretchy boolValue];
|
2015-08-02 15:55:21 -05:00
|
|
|
pp.horzFirst = p->horzFirst && i == 0;
|
|
|
|
pp.horzLast = p->horzLast && i == ([self->children count] - 1);
|
|
|
|
pp.vertFirst = p->vertFirst;
|
|
|
|
pp.vertLast = p->vertLast;
|
|
|
|
}
|
2015-08-02 10:25:39 -05:00
|
|
|
[cur tFillAutoLayout:&pp];
|
2015-08-02 17:54:33 -05:00
|
|
|
if (self->vertical) {
|
|
|
|
if (pp.vertStretchy && pp.vertFirstStretchy) {
|
|
|
|
pp.vertFirstStretchy = NO;
|
|
|
|
pp.vertStretchyTo = first[i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (pp.horzStretchy && pp.horzFirstStretchy) {
|
|
|
|
pp.horzFirstStretchy = NO;
|
|
|
|
pp.horzStretchyTo = first[i];
|
|
|
|
}
|
2015-08-02 11:35:48 -05:00
|
|
|
}
|
2015-08-01 17:05:50 -05:00
|
|
|
}
|
2015-08-02 10:25:39 -05:00
|
|
|
p->n = pp.n;
|
|
|
|
|
2015-08-02 17:16:44 -05:00
|
|
|
buildPrimary = ^(NSMutableArray *in, BOOL first, BOOL last,
|
|
|
|
NSMutableArray *out, NSMutableArray *outstart, NSMutableArray *outend) {
|
|
|
|
NSMutableString *outstr;
|
|
|
|
|
|
|
|
outstr = [NSMutableString new];
|
|
|
|
[in enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
|
|
|
|
//TODO if (index != 0)
|
|
|
|
//TODO [outstr appendString:@"-"];
|
|
|
|
[outstr appendString:((NSString *) obj)];
|
|
|
|
}];
|
|
|
|
[out addObject:outstr];
|
|
|
|
[outstart addObject:[NSNumber numberWithBool:first]];
|
|
|
|
[outend addObject:[NSNumber numberWithBool:last]];
|
|
|
|
};
|
|
|
|
|
2015-08-02 11:22:24 -05:00
|
|
|
if (self->vertical) {
|
2015-08-02 17:16:44 -05:00
|
|
|
buildPrimary(subvert, p->vertFirst, p->vertLast,
|
|
|
|
p->vert, p->vertAttachTop, p->vertAttachBottom);
|
|
|
|
[p->horz addObjectsFromArray:subhorz];
|
|
|
|
[p->horzAttachLeft addObjectsFromArray:subhorzleft];
|
|
|
|
[p->horzAttachRight addObjectsFromArray:subhorzright];
|
|
|
|
} else {
|
|
|
|
buildPrimary(subhorz, p->horzFirst, p->horzLast,
|
|
|
|
p->horz, p->horzAttachLeft, p->horzAttachRight);
|
|
|
|
[p->vert addObjectsFromArray:subvert];
|
|
|
|
[p->vertAttachTop addObjectsFromArray:subverttop];
|
|
|
|
[p->vertAttachBottom addObjectsFromArray:subvertbottom];
|
2015-08-02 11:22:24 -05:00
|
|
|
}
|
2015-08-02 10:25:39 -05:00
|
|
|
|
2015-08-02 18:27:55 -05:00
|
|
|
// now constrain the lateral dimension
|
|
|
|
// all children of item i must be next to the first child of item i+1
|
|
|
|
// this is so sub-boxes are on the same "line"
|
|
|
|
// TODO move this declaration above
|
|
|
|
void (^lateral)(NSMutableArray *, BOOL, BOOL, NSMutableArray *, NSMutableArray *) = ^(NSMutableArray *out, BOOL xfirst, BOOL last, NSMutableArray *outstart, NSMutableArray *outend) {
|
|
|
|
NSUInteger i;
|
|
|
|
uintmax_t j;
|
|
|
|
|
|
|
|
for (i = 0; i < [self->children count] - 1; i++)
|
|
|
|
for (j = first[i]; j < first[i + 1]; j++) {
|
|
|
|
NSString *c1, *c2;
|
|
|
|
NSString *constraint;
|
|
|
|
|
|
|
|
c1 = tAutoLayoutKey(j);
|
|
|
|
c2 = tAutoLayoutKey(first[i + 1]);
|
|
|
|
constraint = [NSString stringWithFormat:@"[%@][%@]", c1, c2];
|
|
|
|
[out addObject:constraint];
|
|
|
|
[outstart addObject:[NSNumber numberWithBool:xfirst]];
|
|
|
|
[outend addObject:[NSNumber numberWithBool:last]];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (self->vertical)
|
|
|
|
lateral(p->vert, p->vertFirst, p->vertLast, p->vertAttachTop, p->vertAttachBottom);
|
|
|
|
else
|
|
|
|
lateral(p->horz, p->horzFirst, p->horzLast, p->horzAttachLeft, p->horzAttachRight);
|
|
|
|
|
2015-08-01 17:05:50 -05:00
|
|
|
[subhorz release];
|
2015-08-02 13:49:10 -05:00
|
|
|
[subhorzleft release];
|
|
|
|
[subhorzright release];
|
2015-08-01 17:05:50 -05:00
|
|
|
[subvert release];
|
2015-08-02 13:49:10 -05:00
|
|
|
[subverttop release];
|
|
|
|
[subvertbottom release];
|
2015-08-01 17:05:50 -05:00
|
|
|
free(first);
|
2015-08-01 01:16:35 -05:00
|
|
|
}
|
2015-07-31 22:25:59 -05:00
|
|
|
|
2015-08-01 17:05:50 -05:00
|
|
|
// TODOs:
|
|
|
|
// - lateral dimension: for each view of n+1, make other dimension next to first n
|
|
|
|
// this way, subelement views get positioned right
|
2015-08-02 17:54:33 -05:00
|
|
|
// - don't pin to end if no controls are stretchy
|
2015-08-01 17:05:50 -05:00
|
|
|
|
2015-08-01 21:13:41 -05:00
|
|
|
- (void)tRelayout
|
|
|
|
{
|
|
|
|
if (self->parent != nil)
|
|
|
|
[self->parent tRelayout];
|
|
|
|
}
|
|
|
|
|
2015-07-31 22:25:59 -05:00
|
|
|
@end
|