ui/cocoa/GridLayout.m

changeset 100
d2bd73d28ff1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/cocoa/GridLayout.m	Thu Dec 12 20:01:43 2024 +0100
@@ -0,0 +1,214 @@
+/*
+ * 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 "GridLayout.h"
+
+
+
+@implementation GridLayout
+
+@synthesize label=_label;
+@synthesize uilayout=_uilayout;
+@synthesize newline=_newline;
+
+- (GridLayout*)init {
+    self = [super init];
+    _columnspacing = 0;
+    _rowspacing = 0;
+    _children = cxArrayListCreateSimple(sizeof(GridElm), 32);
+    
+    return self;
+}
+
+/*
+- (void) layout {
+    [super layout];
+    
+    NSRect r1 = _test.frame;
+    NSSize s1 = _test.intrinsicContentSize;
+    NSEdgeInsets e1 = _test.alignmentRectInsets;
+    
+    printf("fuck\n");
+}
+ */
+
+
+- (void) layout {
+    int ncols = _cols+1;
+    int nrows = _rows+1;
+    
+    GridDef *coldef = calloc(ncols, sizeof(GridDef));
+    GridDef *rowdef = calloc(nrows, sizeof(GridDef));
+    
+    NSRect viewFrame = self.frame;
+    
+    int colspacing = _columnspacing;
+    int rowspacing = _rowspacing;
+    
+    CxIterator i = cxListIterator(_children);
+    cx_foreach(GridElm *, elm, i) {
+        NSSize size = elm->view.intrinsicContentSize;
+        NSEdgeInsets alignment = elm->view.alignmentRectInsets;
+        if(size.width != NSViewNoIntrinsicMetric) {
+            CGFloat width = size.width + alignment.left + alignment.right;
+            if(width > coldef[elm->x].preferred_size) {
+                coldef[elm->x].preferred_size = width;
+            }
+        }
+        if(size.height != NSViewNoIntrinsicMetric) {
+            CGFloat height = size.height + alignment.top + alignment.right;
+            //CGFloat height = size.height;
+            if(height > rowdef[elm->y].preferred_size) {
+                rowdef[elm->y].preferred_size = height;
+            }
+        }
+        
+        if(elm->hexpand) {
+            coldef[elm->x].extend = TRUE;
+        }
+        if(elm->vexpand) {
+            rowdef[elm->y].extend = TRUE;
+        }
+    }
+    
+    int col_ext = 0;
+    int row_ext = 0;
+    
+    int preferred_width = 0;
+    int preferred_height = 0;
+    for(int j=0;j<ncols;j++) {
+        preferred_width += coldef[j].preferred_size + colspacing;
+        if(coldef[j].extend) {
+            col_ext++;
+        }
+    }
+    for(int j=0;j<nrows;j++) {
+        preferred_height += rowdef[j].preferred_size + rowspacing;
+        if(rowdef[j].extend) {
+            row_ext++;
+        }
+    }
+    
+    _preferredSize.width = preferred_width;
+    _preferredSize.height = preferred_height;
+    
+    
+    int hremaining = viewFrame.size.width - preferred_width;
+    int vremaining = viewFrame.size.height - preferred_height;
+    int hext = hremaining/col_ext;
+    int vext = vremaining/row_ext;
+    
+    for(int j=0;j<ncols;j++) {
+        GridDef *col = &coldef[j];
+        if(col->extend) {
+            col->size = col->preferred_size + hext;
+        } else {
+            col->size = col->preferred_size;
+        }
+    }
+    for(int j=0;j<nrows;j++) {
+        GridDef *row = &rowdef[j];
+        if(row->extend) {
+            row->size = row->preferred_size + vext;
+        } else {
+            row->size = row->preferred_size;
+        }
+    }
+    
+    int pos = 0;
+    for(int j=0;j<ncols;j++) {
+        coldef[j].pos = pos;
+        pos += coldef[j].size + colspacing;
+    }
+    pos = 0;
+    for(int j=0;j<nrows;j++) {
+        rowdef[j].pos = pos;
+        pos += rowdef[j].size + rowspacing;
+    }
+    
+    i = cxListIterator(_children);
+    cx_foreach(GridElm *, elm, i) {
+        //NSSize size = elm->view.intrinsicContentSize;
+        GridDef *col = &coldef[elm->x];
+        GridDef *row = &rowdef[elm->y];
+        
+        NSEdgeInsets alignment = elm->view.alignmentRectInsets;
+        NSRect frame;
+        frame.size.width = col->size;
+        frame.size.height = row->size;
+        frame.origin.x = col->pos - (alignment.left+alignment.right)/2;
+        frame.origin.y = viewFrame.size.height - row->pos - frame.size.height + ((alignment.top+alignment.right)/2);
+        elm->view.frame = frame;
+    }
+    
+    free(coldef);
+    free(rowdef);
+}
+ 
+
+- (NSSize)intrinsicContentSize {
+    return self.preferredSize;
+}
+
+- (void) addView:(NSView*)view fill:(BOOL)fill {
+    if(_newline) {
+        _y++;
+        _x = 0;
+        _newline = FALSE;
+    }
+    
+    GridElm elm;
+    elm.x = _x;
+    elm.y = _y;
+    elm.margin = 0;
+    elm.colspan = _uilayout.colspan;
+    elm.rowspan = _uilayout.rowspan;
+    elm.hfill = _uilayout.hfill;
+    elm.vfill = _uilayout.vfill;
+    elm.hexpand = _uilayout.hexpand;
+    elm.vexpand = _uilayout.vexpand;
+    elm.view = view;
+    cxListAdd(_children, &elm);
+    
+    [self addSubview:view];
+    self.needsLayout = YES;
+    
+    if(_x > _cols) {
+        _cols = _x;
+    }
+    if(_y > _rows) {
+        _rows = _y;
+    }
+    _x++;
+}
+
+- (void) dealloc {
+    cxListDestroy(_children);
+}
+
+@end

mercurial