Commit Diff


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