commit 8a5e9b3a1aa94d81042445f7bf7d8249bc96b3ba from: Onana Onana Xavier Manuel date: Wed Jun 24 19:04:37 2026 UTC Expand added to pack geometry manager - Rewrote pack to add expand and proper anchoring - Fixed order issue when using pack commit - 86de45269288906cd51d0b8d6d87bd0dca48e65c commit + 8a5e9b3a1aa94d81042445f7bf7d8249bc96b3ba blob - 8b61cd2a318aec2f93ebbb799ddd1ff423e21a8c blob + 6459d7e0ee558315dd667e8f5aeae620a782e001 --- layout.c +++ layout.c @@ -177,17 +177,7 @@ layout_organize(struct aui_widget *widget) break; } /* - * As far as I'm aware of, Tk's pack is just a rectangle that shrinks - * depending on the side of the widget being added. - * - * The fill attribute is a bit tricky. You can set it to x, y and both - * but you have to keep in mind that x only works on side top and bottom - * and y works on side left and right. - * - * Keep in mind that expand can make the fill atributte that doesn't - * usually work on a side to changes its geometry. - * - * Expand is pretty much dividing the remaining space among children. + * Lots of suffering into implementing this one :D */ case AUI_LAYOUT_PACK: { struct aui_geometry space = widget->geom; @@ -195,186 +185,289 @@ layout_organize(struct aui_widget *widget) unsigned int vexpand = 0; unsigned int req_w = 0; unsigned int req_h = 0; + int extra_w = 0; + int extra_h = 0; + int hextra = 0; + int vextra = 0; + /* + * Compute requested and extra space. hextra and vextra are only set + * if there is no top/bottom widgets succeeding it. This guarantees + * a proper request size. + */ TAILQ_FOREACH(child, &widget->queue, entries) { if (child->mapped == 0) continue; struct aui_geometry cgeom = child->in_ops->get_min_size(child); + switch (child->packpar.side) { + case AUI_SIDE_TOP: + case AUI_SIDE_BOTTOM: + vexpand = (child->packpar.expand) ? vexpand + 1 : vexpand; + if (vextra) vextra = 0; + req_h += cgeom.height; + hextra = (cgeom.width > hextra) ? cgeom.width : hextra; + break; + case AUI_SIDE_LEFT: + case AUI_SIDE_RIGHT: + hexpand = (child->packpar.expand) ? hexpand + 1 : hexpand; + if (hextra) hextra = 0; + vextra = (cgeom.height > vextra) ? cgeom.height : vextra; + req_w += cgeom.width; + break; + default: + break; + } + } + req_w += hextra; + req_h += vextra; + + if (req_w > space.width) + req_w = space.width; + + if (req_h > space.height) + req_h = space.height; + + extra_w = space.width - req_w; + extra_h = space.height - req_h; + + /* + * Making sure each widget consume space before expension + * for their area. + */ + TAILQ_FOREACH(child, &widget->queue, entries) { + if (child->mapped == 0) + continue; + + struct aui_geometry min = child->in_ops->get_min_size(child); + switch (child->packpar.side) { case AUI_SIDE_TOP: - cgeom.width = (cgeom.width > space.width) ? space.width : cgeom.width; - cgeom.height = (cgeom.height > space.height) ? space.height : cgeom.height; + child->packarea = (struct aui_geometry) { + .x = space.x, + .y = space.y, + .width = space.width, + .height = min.height, + }; - vexpand = (child->packpar.expand) ? vexpand + 1 : vexpand; + if (child->packarea.height > space.height) { + child->packarea.height = space.height; + } - switch (child->packpar.fill) { - case AUI_FILL_X: - cgeom.width = space.width; - break; - case AUI_FILL_BOTH: - cgeom.width = space.width; - break; - case AUI_FILL_NONE: - default: - break; + space.y += child->packarea.height; + space.height -= child->packarea.height; + break; + case AUI_SIDE_BOTTOM: + child->packarea = (struct aui_geometry) { + .x = space.x, + .y = space.y, + .width = space.width, + .height = min.height + }; + + if (child->packarea.height > space.height) { + child->packarea.height = space.height; } - switch (child->packpar.anchor) { - case AUI_ANCHOR_CENTER: - case AUI_ANCHOR_N: - case AUI_ANCHOR_S: - cgeom.x = space.x + space.width / 2 - cgeom.width / 2; - cgeom.y = space.y; - break; - case AUI_ANCHOR_NW: - case AUI_ANCHOR_SW: - case AUI_ANCHOR_W: - cgeom.x = space.x; - cgeom.y = space.y; - break; - case AUI_ANCHOR_NE: - case AUI_ANCHOR_SE: - case AUI_ANCHOR_E: - cgeom.x = space.x + space.width - cgeom.width; - cgeom.y = space.y; - break; - default: - break; - } - space.y += cgeom.height; - space.height -= cgeom.height; + + child->packarea.y = space.y + space.height - child->packarea.height; + + space.height -= child->packarea.height; break; case AUI_SIDE_LEFT: - cgeom.width = (cgeom.width > space.width) ? space.width : cgeom.width; - cgeom.height = (cgeom.height > space.height) ? space.height : cgeom.height; - cgeom.x = space.x; - cgeom.y = space.y + space.height / 2 - cgeom.height / 2; + child->packarea = (struct aui_geometry) { + .x = space.x, + .y = space.y, + .width = min.width, + .height = space.height + }; - hexpand = (child->packpar.expand) ? hexpand + 1 : hexpand; - - switch (child->packpar.fill) { - case AUI_FILL_Y: - cgeom.height = space.height; - break; - case AUI_FILL_BOTH: - cgeom.height = space.height; - break; - case AUI_FILL_NONE: - default: - break; + if (child->packarea.width > space.width) { + child->packarea.width = space.width; } - switch (child->packpar.anchor) { - case AUI_ANCHOR_CENTER: - case AUI_ANCHOR_E: - case AUI_ANCHOR_W: - cgeom.x = space.x; - cgeom.y = space.y + space.height / 2 - cgeom.height / 2; - break; - case AUI_ANCHOR_N: - case AUI_ANCHOR_NE: - case AUI_ANCHOR_NW: - cgeom.x = space.x; - cgeom.y = space.y; - break; - case AUI_ANCHOR_S: - case AUI_ANCHOR_SE: - case AUI_ANCHOR_SW: - cgeom.x = space.x; - cgeom.y = space.y + space.height - cgeom.height; - break; - default: - break; - } - space.width -= cgeom.width; - space.x += cgeom.width; + + space.x += child->packarea.width; + space.width -= child->packarea.width; break; case AUI_SIDE_RIGHT: - cgeom.width = (cgeom.width > space.width) ? space.width : cgeom.width; - cgeom.height = (cgeom.height > space.height) ? space.height : cgeom.height; + child->packarea = (struct aui_geometry) { + .x = space.x, + .y = space.y, + .width = min.width, + .height = space.height + }; - hexpand = (child->packpar.expand) ? hexpand + 1 : hexpand; + if (child->packarea.width > space.width) { + child->packarea.width = space.width; + } - switch (child->packpar.fill) { - case AUI_FILL_Y: - cgeom.height = space.height; - break; - case AUI_FILL_BOTH: - cgeom.height = space.height; - break; - case AUI_FILL_NONE: - default: - break; + child->packarea.x = space.x + space.width - child->packarea.width; + + space.width -= child->packarea.width; + break; + default: + break; + } + } + + int top = 0; + int bottom = 0; + int right = 0; + int left = 0; + + /* + * Consuming the remaining space if expanded + */ + TAILQ_FOREACH(child, &widget->queue, entries) { + if (child->mapped == 0) + continue; + + if (space.width == 0 && space.height == 0) + break; + + struct aui_geometry *area = &child->packarea; + + switch (child->packpar.side) { + case AUI_SIDE_TOP: + area->x += left; + area->y += top; + area->width -= left; + + area->width -= right; + + if (child->packpar.expand == 1) { + if (vexpand) { + top += extra_h / vexpand; + area->height += extra_h / vexpand; + extra_h -= extra_h / vexpand; + vexpand--; + } } - switch (child->packpar.anchor) { - case AUI_ANCHOR_CENTER: - case AUI_ANCHOR_E: - case AUI_ANCHOR_W: - cgeom.x = space.x + space.width - cgeom.width; - cgeom.y = space.y + space.height / 2 - cgeom.height / 2; - break; - case AUI_ANCHOR_N: - case AUI_ANCHOR_NE: - case AUI_ANCHOR_NW: - cgeom.x = space.x + space.width - cgeom.width; - cgeom.y = space.y; - break; - case AUI_ANCHOR_S: - case AUI_ANCHOR_SE: - case AUI_ANCHOR_SW: - cgeom.x = space.x + space.width - cgeom.width; - cgeom.y = space.y + space.height - cgeom.height; - break; - default: - break; - } - space.width -= cgeom.width; break; + case AUI_SIDE_BOTTOM: - cgeom.width = (cgeom.width > space.width) ? space.width : cgeom.width; - cgeom.height = (cgeom.height > space.height) ? space.height : cgeom.height; + area->x += left; + area->width -= left; - vexpand = (child->packpar.expand) ? vexpand + 1 : vexpand; + area->width -= right; + if (child->packpar.expand == 1) { + if (vexpand) { + bottom += extra_h / vexpand; + area->height += extra_h / vexpand; + area->y -= extra_h / vexpand; + extra_h -= extra_h / vexpand; + vexpand--; + } + } + break; + case AUI_SIDE_LEFT: + area->y += top; + area->x += left; + area->height -= top; + area->height -= bottom; - switch (child->packpar.fill) { - case AUI_FILL_X: - cgeom.width = space.width; - break; - case AUI_FILL_BOTH: - cgeom.width = space.width; - break; - case AUI_FILL_NONE: - default: - break; + if (child->packpar.expand == 1) { + if (hexpand) { + left += extra_w / hexpand; + area->width += extra_w / hexpand; + extra_w -= extra_w / hexpand; + hexpand--; + } } - switch (child->packpar.anchor) { - case AUI_ANCHOR_CENTER: - case AUI_ANCHOR_N: - case AUI_ANCHOR_S: - cgeom.x = space.x + space.width / 2 - cgeom.width / 2; - cgeom.y = space.y + space.height - cgeom.height; - break; - case AUI_ANCHOR_NW: - case AUI_ANCHOR_SW: - case AUI_ANCHOR_W: - cgeom.x = space.x; - cgeom.y = space.y + space.height - cgeom.height; - break; - case AUI_ANCHOR_NE: - case AUI_ANCHOR_SE: - case AUI_ANCHOR_E: - cgeom.x = space.x + space.width - cgeom.width; - cgeom.y = space.y + space.height - cgeom.height; - break; - default: - break; - } - space.height -= cgeom.height; break; + case AUI_SIDE_RIGHT: + area->y += top; + area->height -= top; + area->height -= bottom; + + if (child->packpar.expand == 1) { + if (hexpand) { + right += extra_w / hexpand; + area->x -= extra_w / hexpand; + area->width += extra_w / hexpand; + extra_w -= extra_w / hexpand; + hexpand--; + } + } default: + break; + } + } + + /* + * Setting geometry + */ + TAILQ_FOREACH(child, &widget->queue, entries) { + if (child->mapped == 0) continue; + + struct aui_geometry min = child->in_ops->get_min_size(child); + struct aui_geometry *area = &child->packarea; + + switch (child->packpar.fill) { + case AUI_FILL_NONE: + child->geom.width = (min.width > area->width) ? area->width : min.width; + child->geom.height = (min.height > area->height) ? area->height : min.height; + break; + case AUI_FILL_X: + child->geom.width = area->width; + child->geom.height = (min.height > area->height) ? area->height : min.height; + break; + case AUI_FILL_Y: + child->geom.width = (min.width > area->width) ? area->width : min.width; + child->geom.height = area->height; + break; + case AUI_FILL_BOTH: + child->geom.width = area->width; + child->geom.height = area->height; + break; + default: + break; } - child->in_ops->set_geometry(child, &cgeom); + + switch (child->packpar.anchor) { + case AUI_ANCHOR_NW: + child->geom.x = area->x; + child->geom.y = area->y; + break; + case AUI_ANCHOR_N: + child->geom.x = area->x + area->width / 2 - child->geom.width / 2; + child->geom.y = area->y; + break; + case AUI_ANCHOR_NE: + child->geom.x = area->x + area->width - child->geom.width; + child->geom.y = area->y; + break; + case AUI_ANCHOR_CENTER: + child->geom.x = area->x + area->width / 2 - child->geom.width / 2; + child->geom.y = area->y + area->height / 2 - child->geom.height / 2; + break; + case AUI_ANCHOR_SE: + child->geom.x = area->x + area->width - child->geom.width; + child->geom.y = area->y + area->height - child->geom.height; + break; + case AUI_ANCHOR_S: + child->geom.x = area->x + area->width / 2 - child->geom.width / 2; + child->geom.y = area->y + area->height - child->geom.height; + break; + case AUI_ANCHOR_SW: + child->geom.x = area->x; + child->geom.y = area->y + area->height - child->geom.height; + break; + case AUI_ANCHOR_W: + child->geom.x = area->x; + child->geom.y = area->y + area->height / 2 - child->geom.height / 2; + break; + case AUI_ANCHOR_E: + child->geom.x = area->x + area->width - child->geom.width; + child->geom.y = area->y + area->height / 2 - child->geom.height / 2; + break; + default: + break; + break; + } + + child->in_ops->set_geometry(child, &child->geom); } TAILQ_FOREACH(child, &widget->queue, entries) { @@ -432,6 +525,11 @@ aui_pack(struct aui_widget *widget, struct aui_packpar widget->mapped = 1; con->map_count++; + /* + * This is important for packing order + */ + widget_lead(widget->parent, widget); + layout_organize(parent); return 0; blob - 4804212e7cd8b12619f03db0f4fce2852bfe5b29 blob + 8aca33ab8d6a7d052137366229bb00cb080fe870 --- widget.c +++ widget.c @@ -27,6 +27,13 @@ widget_add(struct aui_widget *parent, struct aui_widge } void +widget_lead(struct aui_widget *parent, struct aui_widget *child) +{ + TAILQ_REMOVE(&parent->queue, child, entries); + TAILQ_INSERT_TAIL(&parent->queue, child, entries); +} + +void widget_remove(struct aui_widget *parent, struct aui_widget *child) { TAILQ_REMOVE(&parent->queue, child, entries); @@ -39,6 +46,10 @@ widget_draw(struct aui_widget *widget) return; struct primitive *prim; + + if (widget->geom.width == 0 || widget->geom.height == 0) + return; + for (int i = 0; i < widget->primitives.count; i++) { prim = widget->primitives.list[i]; blob - 841d4a6f6dcc8401e886327bf1226c5c7d7bbac2 blob + 57105def4f591701235448adc822f9681a83ba45 --- widget.h +++ widget.h @@ -32,6 +32,7 @@ struct aui_widget { struct aui_placepar placepar; struct aui_gridpar gridpar; struct aui_packpar packpar; + struct aui_geometry packarea; unsigned int mapped; @@ -97,6 +98,7 @@ void widget_init(struct aui_widget *); void widget_draw(struct aui_widget *); void widget_add(struct aui_widget *, struct aui_widget *); void widget_remove(struct aui_widget *, struct aui_widget *); +void widget_lead(struct aui_widget *, struct aui_widget *); int widget_collides_with_point(struct aui_widget*, uint16_t, uint16_t); #endif