/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2024 Olaf Wintermann. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#import "Container.h"
#import "GridLayout.h"
/* ------------------------- container classes ------------------------- */
@implementation BoxContainer
@synthesize label=_label;
@synthesize uilayout=_uilayout;
@synthesize newline=_newline;
- (BoxContainer*)init:(NSUserInterfaceLayoutOrientation)orientation spacing:(int)spacing {
self = [super init];
_label = NULL;
_uilayout = (UiLayout){ 0 };
_newline = false;
self.distribution = NSStackViewDistributionFillProportionally;
self.spacing = spacing;
self.orientation = orientation;
if(orientation == NSUserInterfaceLayoutOrientationHorizontal) {
self.alignment = NSLayoutAttributeHeight;
} else {
self.alignment = NSLayoutAttributeWidth;
}
return self;
}
- (void) addView:(NSView*)view fill:(BOOL)fill {
if(_uilayout.fill != UI_LAYOUT_UNDEFINED) {
fill = ui_lb2bool(_uilayout.fill);
}
[self addArrangedSubview:view];
if(self.orientation == NSUserInterfaceLayoutOrientationHorizontal) {
[view.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES;
if(!fill) {
[view.widthAnchor constraintEqualToConstant:view.intrinsicContentSize.width].active = YES;
}
} else {
[view.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES;
if(!fill) {
[view.heightAnchor constraintEqualToConstant:view.intrinsicContentSize.height].active = YES;
}
}
// at the moment, only the fill layout option needs to be reset
_uilayout.fill = UI_DEFAULT;
}
@end
/* -------------------- public container functions --------------------- */
static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, NSUserInterfaceLayoutOrientation orientation) {
BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args.spacing];
box.translatesAutoresizingMaskIntoConstraints = false;
// add box to the parent
UiLayout layout = UI_INIT_LAYOUT(args);
ui_container_add(obj, box, &layout, TRUE);
// add new box to the obj container chain
uic_object_push_container(obj, ui_create_container(obj, box));
return (__bridge void*)box;
}
UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
return ui_box_create(obj, args, NSUserInterfaceLayoutOrientationVertical);
}
UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
return ui_box_create(obj, args, NSUserInterfaceLayoutOrientationHorizontal);
}
UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
GridLayout *grid = [[GridLayout alloc] init];
grid.translatesAutoresizingMaskIntoConstraints = false;
// add box to the parent
UiLayout layout = UI_INIT_LAYOUT(args);
ui_container_add(obj, grid, &layout, TRUE);
// add new box to the obj container chain
uic_object_push_container(obj, ui_create_container(obj, grid));
return (__bridge void*)grid;
}
void ui_container_begin_close(UiObject *obj) {
UiContainerX *ct = obj->container_end;
ct->close = 1;
}
int ui_container_finish(UiObject *obj) {
UiContainerX *ct = obj->container_end;
if(ct->close) {
ui_end_new(obj);
return 0;
}
return 1;
}
/* ------------------------- private functions ------------------------- */
UiContainerX* ui_create_container(UiObject *obj, id<Container> container) {
UiContainerX *ctn = ui_malloc(obj->ctx, sizeof(UiContainerX));
ctn->container = (__bridge void*)container;
ctn->close = 0;
ctn->prev = NULL;
ctn->next = NULL;
return ctn;
}
void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout, UiBool fill) {
UiContainerX *ctn = obj->container_end;
id<Container> container = (__bridge id<Container>)ctn->container;
container.uilayout = *layout;
[container addView:view fill:fill];
}
/* ---------------------- public layout functions ----------------------- */
void ui_newline(UiObject *obj) {
UiContainerX *ctn = obj->container_end;
if(ctn) {
id<Container> container = (__bridge id<Container>)ctn->container;
container.newline = TRUE;
} else {
fprintf(stderr, "Error: obj has no container\n");
}
}