#include "paint.h" typedef struct Aux { Point dim; } Aux; static Rdims maxdims(Widget *w) { Aux *aux; Rdims d; aux = w->aux; d = w->children->dims(w->children); d.des.x = min(d.des.x, aux->dim.x); d.des.y = min(d.des.y, aux->dim.y); d.max.x = min(d.max.x, aux->dim.x); d.max.y = min(d.max.y, aux->dim.y); return d; } static void resizemax(Widget *w, Point dim) { w->children->resize(w->children, dim); w->r = rectaddpt(Rpt(ZP, dim), w->r.min); } static void freeaux(Widget *w) { free(w->aux); freewidget(w); } Widget * mklayoutmaxwidget(Point dim, Widget *c) { Widget *w; Aux *aux; aux = emalloc(sizeof(*aux)); aux->dim = dim; if((w = mkwidget(ZR, widgetmousedescend, widgetsyncnop, widgetredrawdescend, maxdims, resizemax, freeaux, aux)) == nil ) sysfatal("mklayoutmaxwidget: %r"); addchildwidget(w, c, ZP); return w; } typedef struct Constraint { Widget *w; Rdims d; int min; int des; int max; int result; } Constraint; static void fit(int box, Constraint *a, int n) { int totalmin, totaldes, totalmax; int i; totalmin = totaldes = totalmax = 0; for(i = 0; i < n; i++) { totalmin = adddim(totalmin, a[i].min); totaldes = adddim(totaldes, a[i].des); totalmax = adddim(totalmax, a[i].max); } if(totaldes == totalmin) { for(i = 0; i < n; i++) a[i].result = a[i].min; return; } for(i = 0; i < n; i++) a[i].result = a[i].min + (a[i].des - a[i].min) * (box - totalmin) / (totaldes - totalmin); } static void xautolayoutresize(Widget *w, Point dim) { Widget *c; Constraint *a, *aa; Rdims d; int n, i, x; w->r = Rpt(w->r.min, addpt(w->r.min, dim)); for(n = 0, c = w->children; c != nil; n++, c = c->next) ; a = emalloc(n*sizeof(*a)); for(aa = a, c = w->children; c != nil; aa++, c = c->next) { d = c->dims(c); *aa = (Constraint){c, d, d.min.x, d.des.x, d.max.x, 0}; } fit(dim.x, a, n); for(i = 0; i < n; i++) { if(a[i].result > a[i].max) a[i].min = a[i].des = a[i].max; } fit(dim.x, a, n); x = 0; for(i = 0; i < n; i++) { a[i].w->resize(a[i].w, Pt(a[i].result, clampint(a[i].d.min.y, dim.y, a[i].d.max.y))); movewidget(a[i].w, Pt(x, 0), a[i].w->screen); x += a[i].result; } free(a); } Widget * mkxautolayout(void) { return mkwidget(ZR, widgetmousedescend, widgetsyncnop, widgetredrawdescend, widgetdimsdescend, xautolayoutresize, freewidget, nil ); } typedef struct Margin { int left; int right; int top; int bottom; } Margin; static Rdims margindims(Widget *w) { Margin *m; Point p; m = w->aux; p = Pt(m->left + m->right, m->top + m->bottom); return adddims((Rdims){p, p, p}, widgetdimsdescend(w)); } static void marginresize(Widget *w, Point dim) { Margin *m; m = w->aux; w->r = rectaddpt(Rpt(ZP, subpt(dim, Pt(m->left + m->right, m->top + m->bottom))), w->r.min); movewidget(w, Pt(m->left, m->top), w->screen); widgetresizedescend(w, subpt(dim, Pt(m->left + m->right, m->top + m->bottom))); } Widget * mkmargin(int left, int right, int top, int bottom) { Widget *w; Margin *m; if((m = malloc(sizeof(*m))) == nil) return nil; *m = (Margin){left, right, top, bottom}; if((w = mkwidget(ZR, widgetmousedescend, widgetsyncnop, widgetredrawdescend, margindims, marginresize, freeaux, m)) == nil ) free(m); return w; }