Commit Diff


commit - 98d0e23f0c6d7384bfd5f4cfe5ac016c019f71e3
commit + 8964e49031e0a23aaa0d9d2155a62bba92b5d587
blob - 02ef472c17c38b13da36ebae7a87f31f33977bfc
blob + 526401143b87409307e1d991f80cabac3e6b3de6
--- Makefile
+++ Makefile
@@ -33,3 +33,6 @@ ${LIB}: ${OBJS}
 
 clean:
 	rm -rf ${PREFIX}/lib/${LIB}.so ${PREFIX}/include/${HDR} ${PREFIX}/lib/${LIB}.a ${OBJS}
+	make -C examples clean
+
+.PHONY: examples
blob - f38629d25d4e1a4e1308def65684adf2c6022363
blob + ccd50669b42d5dede1f47fd5c71ba7d1e2d0841c
--- aui.h
+++ aui.h
@@ -48,6 +48,8 @@ struct aui_packpar {
 struct aui_gridpar {
 	unsigned int column;
 	unsigned int row;
+	unsigned int columnspan;
+	unsigned int rowspan;
 };
 
 struct aui_widget;
@@ -79,7 +81,7 @@ struct aui_canvas_config {
 };
 
 struct aui_label_config {
-	const char *text;
+	char *text;
 	struct aui_color foreground;
 	struct aui_color bg;
 };
blob - 4c55709846422afb7b0a278df81d9c3cae5d277f
blob + 1b3320cb09ed30ffbbde8bfc71b9fe9ba82c5989
--- aui_run.3
+++ aui_run.3
@@ -1,4 +1,4 @@
-.Dd $Mdocdate: July 07 2026$
+.Dd $Mdocdate: July 08 2026$
 .Dt AUI_RUN 3
 .Os
 .Sh NAME
@@ -6,6 +6,13 @@
 .Nm aui_destroy ,
 .Nm aui_window_new ,
 .Nm aui_button_new ,
+.Nm aui_button_config ,
+.Nm aui_frame_new ,
+.Nm aui_frame_config ,
+.Nm aui_label_new ,
+.Nm aui_label_config ,
+.Nm aui_canvas_new ,
+.Nm aui_canvas_config ,
 .Nm aui_place ,
 .Nm aui_pack ,
 .Nm aui_grid ,
@@ -22,6 +29,8 @@
 .Fn aui_window_new "struct aui_window_config * config"
 .Ft struct aui_button*
 .Fn aui_button_new "struct aui_widget * parent" "struct aui_button_config * config"
+.Ft int
+.Fn aui_button_config "struct aui_widget * widget" "struct aui_button_config * config"
 .Ft struct aui_label*
 .Fn aui_label_new "struct aui_widget * parent" "struct aui_label_config * config"
 .Ft int
@@ -31,8 +40,10 @@
 .Ft int
 .Fn aui_frame_config "struct aui_widget * widget" "struct aui_frame_config * config"
 .Ft struct aui_canvas*
-.Fn aui_canvas_new "struct aui_widget * parent"
+.Fn aui_canvas_new "struct aui_widget * widget" "struct aui_canvas_config * config"
 .Ft int
+.Fn aui_canvas_config "struct aui_widget * parent" "struct aui_canvas_config * config"
+.Ft int
 .Fn aui_place "struct aui_widget * widget" "struct aui_placepar * par"
 .Ft int
 .Fn aui_grid "struct aui_widget * widget" "struct aui_gridpar * par"
blob - 8992755a9f908bfc20928dd3142f9154d9990df6
blob + 36661b64d6d1cac811398d1ce8ebc2207b00cdc3
--- button.c
+++ button.c
@@ -54,7 +54,8 @@ aui_button_new(struct aui_widget *parent, struct aui_b
 	widget->primitives.list[1] = driver->ops->create_rectangle();
 	widget->primitives.list[2] = driver->ops->create_text();
 
-	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[0], &color[0]);
+	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[0], 
+		&button->config.foreground);
 	driver->ops->set_rectangle_color(widget->window, widget->primitives.list[1], &color[1]);
 	driver->ops->set_text(widget->primitives.list[2], button->config.text, 0, 0);
 	driver->ops->set_text_color(widget->primitives.list[2], &button->config.foreground);
blob - 67e29c8288c0653462bfe0dd6cc2f9ecfd0659b0
blob + ebeb86585fd96a64565a5fc6881784a9a9726eb3
--- label.c
+++ label.c
@@ -52,11 +52,22 @@ aui_label_config(struct aui_widget *widget, struct aui
 	struct aui_label *label = (struct aui_label *)widget;
 	struct aui_geometry geom = widget->geom;
 
-	label->config = (config == NULL) ? default_config : *config;
+	if (label->config.text) {
+		free(label->config.text);
+		label->config.text = NULL;
+	}
 
+	config = (config == NULL) ? &default_config : config;
+	label->config = *config;
+
+	if (config->text)
+		label->config.text = strdup(config->text);
+
 	driver->ops->set_text(widget->primitives.list[0], label->config.text, 0, 0);
 	driver->ops->set_text_color(widget->primitives.list[0], &label->config.foreground);
 	label_set_geometry(widget, &geom);
+
+	layout_organize(widget->parent);
 	return 0;
 }
 
blob - 73c2d50a0fe25487b2958c430bffdc2ff79a9416
blob + 3dffb8bcb5cb44e27c408169d974618992e39e19
--- layout.c
+++ layout.c
@@ -51,6 +51,461 @@ can_add(struct aui_widget *widget, enum aui_layout_typ
 }
 
 void
+place(struct aui_widget *widget)
+{
+	struct aui_widget *child;
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_placepar *par = &child->placepar;
+		int dx = 0, dy = 0;
+
+		struct aui_geometry geom = { 
+			.x = widget->geom.x + child->placepar.x + widget->geom.width * child->placepar.relx,
+			.y = widget->geom.y + child->placepar.y + widget->geom.height * child->placepar.rely,
+			.width = child->placepar.width + child->placepar.relwidth * widget->geom.width,
+			.height = child->placepar.height + child->placepar.relheight * widget->geom.height };
+
+		switch (par->anchor) {
+		case AUI_ANCHOR_NW:
+			dx = 0;
+			dy = 0;
+			break;
+		case AUI_ANCHOR_NE:
+			dx = -geom.width;
+			dy = 0;
+			break;
+		case AUI_ANCHOR_N:
+			dx = -geom.width / 2;
+			dy = 0;
+			break;
+		case AUI_ANCHOR_W:
+			dx = 0;
+			dy = -geom.height / 2;
+			break;
+		case AUI_ANCHOR_E:
+			dx = -geom.width;
+			dy = -geom.height /2;
+			break;
+		case AUI_ANCHOR_SE:
+			dx = -geom.width;
+			dy = -geom.height;
+			break;
+		case AUI_ANCHOR_SW:
+			dx = 0;
+			dy = -geom.height;
+			break;
+		case AUI_ANCHOR_S:
+			dx = -geom.width / 2;
+			dy = -geom.height;
+			break;
+		case AUI_ANCHOR_CENTER:
+			dx = -geom.width / 2;
+			dy = -geom.height / 2;
+			break;
+		default:
+			break;
+		}
+
+		geom.x += dx;
+		geom.y += dy;
+		child->ops->set_geometry(child, &geom); 
+
+		switch (child->type) {
+		case WIDGET_TYPE_FRAME:
+			layout_organize(child);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+grid(struct aui_widget *widget)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	uint8_t *rmap = con->row_maps;
+	uint8_t *cmap = con->col_maps;
+	struct aui_widget *child;
+
+	unsigned int *rsize = con->row_sizes;
+	unsigned int *csize = con->col_sizes;
+
+	memset(con->row_sizes, 0, sizeof(*con->row_sizes) * con->grid_size[1]);
+	memset(con->col_sizes, 0, sizeof(*con->col_sizes) * con->grid_size[0]);
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry min = child->ops->get_min_size(child);
+
+		rmap[child->gridpar.row] = 1;
+		cmap[child->gridpar.column] = 1;
+
+		rsize[child->gridpar.row] = (rsize[child->gridpar.row] < min.height) ?
+			min.height : rsize[child->gridpar.row];
+
+		csize[child->gridpar.column] = (csize[child->gridpar.column] < min.width) ?
+			min.width : csize[child->gridpar.column];
+	}
+
+	unsigned int *rpos = con->row_pos;
+	unsigned int *cpos = con->col_pos;
+
+	unsigned int rowdt = 0;
+	unsigned int coldt = 0;
+
+	for (int r = 0; r < con->grid_size[1]; r++) {
+		rpos[r] = rowdt;
+		rowdt = (rmap[r] == 1) ? rowdt + rsize[r] : rowdt;
+	}
+
+	for (int c = 0; c < con->grid_size[0]; c++) {
+		cpos[c] = coldt;
+		coldt = (cmap[c] == 1) ? coldt + csize[c] : coldt;
+	}
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry min = child->ops->get_min_size(child);
+		struct aui_geometry geom = { 0 };
+
+		int dx = (csize[child->gridpar.column] - min.width);
+		int dy = (rsize[child->gridpar.row] - min.height);
+
+		geom.x = widget->geom.x + cpos[child->gridpar.column] + dx / 2;
+		geom.y = widget->geom.y + rpos[child->gridpar.row] + dy / 2;
+		geom.width = min.width;
+		geom.height = min.height;
+
+		child->ops->set_geometry(child, &geom);
+	}
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		switch (child->type) {
+		case WIDGET_TYPE_FRAME:
+			layout_organize(child);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+pack(struct aui_widget *widget)
+{
+	struct aui_container *con = (struct aui_container *)widget;
+	struct aui_widget *child;
+	struct aui_geometry space = widget->geom;
+	unsigned int hexpand = 0;
+	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->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->ops->get_min_size(child);
+
+		switch (child->packpar.side) {
+		case AUI_SIDE_TOP:
+			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;
+			}
+
+			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;
+			}
+
+			child->packarea.y = space.y + space.height - child->packarea.height;
+
+			space.height -= child->packarea.height;
+			break;
+		case AUI_SIDE_LEFT:
+			child->packarea = (struct aui_geometry) {
+				.x = space.x,
+				.y = space.y,
+				.width = min.width,
+				.height = space.height
+			};
+
+			if (child->packarea.width > space.width) {
+				child->packarea.width = space.width;
+			}
+
+			space.x += child->packarea.width;
+			space.width -= child->packarea.width;
+			break;
+		case AUI_SIDE_RIGHT:
+			child->packarea = (struct aui_geometry) {
+				.x = space.x,
+				.y = space.y,
+				.width = min.width,
+				.height = space.height
+			};
+
+			if (child->packarea.width > space.width) {
+				child->packarea.width = space.width;
+			}
+
+			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--;
+				}
+			}
+			break;
+
+		case AUI_SIDE_BOTTOM:
+			area->x += left;
+			area->width -= left;
+
+			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;
+
+			if (child->packpar.expand == 1) {
+				if (hexpand) {
+					left += extra_w / hexpand;
+					area->width += extra_w / hexpand;
+					extra_w -= extra_w / hexpand;
+					hexpand--;
+				}
+			}
+			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--;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * Setting geometry
+	 */
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		if (child->mapped == 0)
+			continue;
+
+		struct aui_geometry min = child->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;
+		}
+
+		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->ops->set_geometry(child, &child->geom);
+	}
+
+	TAILQ_FOREACH(child, &widget->queue, entries) {
+		switch (child->type) {
+		case WIDGET_TYPE_FRAME:
+			layout_organize(child);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
 layout_organize(struct aui_widget *widget)
 {
 	struct aui_container *con = (struct aui_container *)widget;
@@ -58,454 +513,17 @@ layout_organize(struct aui_widget *widget)
 
 	switch (con->layout_type) {
 	case AUI_LAYOUT_PLACE:
-		TAILQ_FOREACH(child, &widget->queue, entries) {
-			if (child->mapped == 0)
-				continue;
-
-			struct aui_placepar *par = &child->placepar;
-			int dx = 0, dy = 0;
-
-			struct aui_geometry geom = { 
-				.x = widget->geom.x + child->placepar.x + widget->geom.width * child->placepar.relx,
-				.y = widget->geom.y + child->placepar.y + widget->geom.height * child->placepar.rely,
-				.width = child->placepar.width + child->placepar.relwidth * widget->geom.width,
-				.height = child->placepar.height + child->placepar.relheight * widget->geom.height };
-
-			switch (par->anchor) {
-			case AUI_ANCHOR_NW:
-				dx = 0;
-				dy = 0;
-				break;
-			case AUI_ANCHOR_NE:
-				dx = -geom.width;
-				dy = 0;
-				break;
-			case AUI_ANCHOR_N:
-				dx = -geom.width / 2;
-				dy = 0;
-				break;
-			case AUI_ANCHOR_W:
-				dx = 0;
-				dy = -geom.height / 2;
-				break;
-			case AUI_ANCHOR_E:
-				dx = -geom.width;
-				dy = -geom.height /2;
-				break;
-			case AUI_ANCHOR_SE:
-				dx = -geom.width;
-				dy = -geom.height;
-				break;
-			case AUI_ANCHOR_SW:
-				dx = 0;
-				dy = -geom.height;
-				break;
-			case AUI_ANCHOR_S:
-				dx = -geom.width / 2;
-				dy = -geom.height;
-				break;
-			case AUI_ANCHOR_CENTER:
-				dx = -geom.width / 2;
-				dy = -geom.height / 2;
-				break;
-			default:
-				break;
-			}
-
-			geom.x += dx;
-			geom.y += dy;
-			child->ops->set_geometry(child, &geom); 
-
-			switch (child->type) {
-			case WIDGET_TYPE_FRAME:
-				layout_organize(child);
-				break;
-			default:
-				break;
-			}
-		}
+		place(widget);
 		break;
-	case AUI_LAYOUT_GRID: {
-		uint8_t *rmap = calloc(con->grid_size[1], sizeof(uint8_t));
-		uint8_t *cmap = calloc(con->grid_size[0], sizeof(uint8_t));
-
-		unsigned int *rsize = calloc(con->grid_size[1], sizeof(unsigned int));
-		unsigned int *csize = calloc(con->grid_size[0], sizeof(unsigned int));
-
-		TAILQ_FOREACH(child, &widget->queue, entries) {
-			if (child->mapped == 0)
-				continue;
-
-			struct aui_geometry min = child->ops->get_min_size(child);
-
-			rmap[child->gridpar.row] = 1;
-			cmap[child->gridpar.column] = 1;
-
-			rsize[child->gridpar.row] = (rsize[child->gridpar.row] < min.height) ?
-				min.height : rsize[child->gridpar.row];
-
-			csize[child->gridpar.column] = (csize[child->gridpar.column] < min.width) ?
-				min.width : csize[child->gridpar.column];
-		}
-
-		unsigned int *rpos = calloc(con->grid_size[1], sizeof(unsigned int));
-		unsigned int *cpos = calloc(con->grid_size[0], sizeof(unsigned int));
-
-		unsigned int rowdt = 0;
-		unsigned int coldt = 0;
-
-		for (int r = 0; r < con->grid_size[1]; r++) {
-			rpos[r] = rowdt;
-			rowdt = (rmap[r] == 1) ? rowdt + rsize[r] : rowdt;
-		}
-
-		for (int c = 0; c < con->grid_size[0]; c++) {
-			cpos[c] = coldt;
-			coldt = (cmap[c] == 1) ? coldt + csize[c] : coldt;
-		}
-
-		TAILQ_FOREACH(child, &widget->queue, entries) {
-			if (child->mapped == 0)
-				continue;
-
-			struct aui_geometry min = child->ops->get_min_size(child);
-			struct aui_geometry geom = { 0 };
-
-			int dx = (csize[child->gridpar.column] - min.width);
-			int dy = (rsize[child->gridpar.row] - min.height);
-
-			geom.x = widget->geom.x + cpos[child->gridpar.column] + dx / 2;
-			geom.y = widget->geom.y + rpos[child->gridpar.row] + dy / 2;
-			geom.width = min.width;
-			geom.height = min.height;
-
-			child->ops->set_geometry(child, &geom);
-		}
-
-		free(rsize);
-		free(csize);
-		free(rpos);
-		free(cpos);
-		free(rmap);
-		free(cmap);
-
-		TAILQ_FOREACH(child, &widget->queue, entries) {
-			switch (child->type) {
-			case WIDGET_TYPE_FRAME:
-				layout_organize(child);
-				break;
-			default:
-				break;
-			}
-		}
+	case AUI_LAYOUT_GRID: 
+		grid(widget);
 		break;
-	}
 	/*
 	 * Lots of suffering into implementing this one :D
 	 */
-	case AUI_LAYOUT_PACK: {
-		struct aui_geometry space = widget->geom;
-		unsigned int hexpand = 0;
-		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->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->ops->get_min_size(child);
-
-			switch (child->packpar.side) {
-			case AUI_SIDE_TOP:
-				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;
-				}
-
-				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;
-				}
-
-				child->packarea.y = space.y + space.height - child->packarea.height;
-
-				space.height -= child->packarea.height;
-				break;
-			case AUI_SIDE_LEFT:
-				child->packarea = (struct aui_geometry) {
-					.x = space.x,
-					.y = space.y,
-					.width = min.width,
-					.height = space.height
-				};
-
-				if (child->packarea.width > space.width) {
-					child->packarea.width = space.width;
-				}
-
-				space.x += child->packarea.width;
-				space.width -= child->packarea.width;
-				break;
-			case AUI_SIDE_RIGHT:
-				child->packarea = (struct aui_geometry) {
-					.x = space.x,
-					.y = space.y,
-					.width = min.width,
-					.height = space.height
-				};
-
-				if (child->packarea.width > space.width) {
-					child->packarea.width = space.width;
-				}
-
-				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--;
-					}
-				}
-				break;
-
-			case AUI_SIDE_BOTTOM:
-				area->x += left;
-				area->width -= left;
-
-				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;
-
-				if (child->packpar.expand == 1) {
-					if (hexpand) {
-						left += extra_w / hexpand;
-						area->width += extra_w / hexpand;
-						extra_w -= extra_w / hexpand;
-						hexpand--;
-					}
-				}
-				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--;
-					}
-				}
-				break;
-			default:
-				break;
-			}
-		}
-
-		/*
-		 * Setting geometry
-		 */
-		TAILQ_FOREACH(child, &widget->queue, entries) {
-			if (child->mapped == 0)
-				continue;
-
-			struct aui_geometry min = child->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;
-			}
-
-			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->ops->set_geometry(child, &child->geom);
-		}
-
-		TAILQ_FOREACH(child, &widget->queue, entries) {
-			switch (child->type) {
-			case WIDGET_TYPE_FRAME:
-				layout_organize(child);
-				break;
-			default:
-				break;
-			}
-		}
+	case AUI_LAYOUT_PACK:
+		pack(widget);
 		break;
-	}
 	default:
 		break;
 	}
@@ -572,6 +590,12 @@ aui_grid(struct aui_widget *widget, struct aui_gridpar
 	int check = can_add(widget, AUI_LAYOUT_GRID);
 	struct aui_widget *parent;
 	struct aui_container *con;
+	unsigned int *rsizes;
+	unsigned int *csizes;
+	unsigned int *rpos;
+	unsigned int *cpos;
+	uint8_t *rmaps;
+	uint8_t *cmaps;
 
 	if (check == -1)
 		return -1;
@@ -589,6 +613,49 @@ aui_grid(struct aui_widget *widget, struct aui_gridpar
 	con->grid_size[0] = (con->grid_size[0] > par->column + 1) ? con->grid_size[0] : par->column + 1;
 	con->grid_size[1] = (con->grid_size[1] > par->row + 1) ? con->grid_size[1] : par->row + 1;
 
+	rmaps = reallocarray(con->row_maps, con->grid_size[1], sizeof(*con->row_maps));
+	if (rmaps == NULL) {
+		fprintf(stderr, "libaui: failed to allocate row maps\n");
+		return -1;
+	}
+	con->row_maps = rmaps;
+
+	cmaps = reallocarray(con->col_maps, con->grid_size[0], sizeof(*con->col_maps));
+	if (cmaps == NULL) {
+		fprintf(stderr, "libaui: failed to allocate col maps\n");
+		return -1;
+	}
+	con->col_maps = cmaps;
+
+
+	rsizes = reallocarray(con->row_sizes, con->grid_size[1], sizeof(*con->row_sizes));
+	if (rsizes == NULL) {
+		fprintf(stderr, "libaui: failed to allocated row sizes\n");
+		return -1;
+	}
+	con->row_sizes = rsizes;
+
+	csizes = reallocarray(con->col_sizes, con->grid_size[0], sizeof(*con->col_sizes));
+	if (csizes == NULL) {
+		fprintf(stderr, "libaui: failed to allocated col sizes\n");
+		return -1;
+	}
+	con->col_sizes = csizes;
+
+	rpos = reallocarray(con->row_pos, con->grid_size[1], sizeof(*con->row_pos));
+	if (rpos == NULL) {
+		fprintf(stderr, "libaui: failed to allocate row positions\n");
+		return -1;
+	}
+	con->row_pos = rpos;
+
+	cpos = reallocarray(con->col_pos, con->grid_size[0], sizeof(*con->col_pos));
+	if (cpos == NULL) {
+		fprintf(stderr, "libaui: failed to allocate col positions\n");
+		return -1;
+	}
+	con->col_pos = cpos;
+
 	layout_organize(parent);
 
 	return 0;
blob - f5e91b8a3d37b22614a38538601fcc76e0b3ea3e
blob + 7a83c3dbf2d1c03d32bd4dd5371081607aaee0b2
--- widget.h
+++ widget.h
@@ -61,9 +61,19 @@ struct widget_ops {
 struct aui_container {
 	struct aui_widget widget;
 	enum aui_layout_type layout_type;
-	uint32_t grid_size[2];
 	unsigned int map_count;
 
+	/*
+	 * Grid members
+	 */
+	uint8_t *row_maps;
+	uint8_t *col_maps;
+	uint32_t grid_size[2];
+	unsigned int *row_sizes;
+	unsigned int *col_sizes;
+	unsigned int *row_pos;
+	unsigned int *col_pos;
+
 	struct container_focus {
 		struct aui_widget *press;
 		struct aui_widget *hover;