// 7 april 2015
#include "uipriv_unix.h"

struct boxChild {
	uiControl *c;
	int stretchy;
	gboolean oldhexpand;
	GtkAlign oldhalign;
	gboolean oldvexpand;
	GtkAlign oldvalign;
};

struct uiBox {
	uiUnixControl c;
	GtkWidget *widget;
	GtkContainer *container;
	GtkBox *box;
	GArray *controls;
	int vertical;
	int padded;
	GtkSizeGroup *stretchygroup;		// ensures all stretchy controls have the same size
};

uiUnixControlAllDefaultsExceptDestroy(uiBox)

#define ctrl(b, i) &g_array_index(b->controls, struct boxChild, i)

static void uiBoxDestroy(uiControl *c)
{
	uiBox *b = uiBox(c);
	struct boxChild *bc;
	guint i;

	// kill the size group
	g_object_unref(b->stretchygroup);
	// free all controls
	for (i = 0; i < b->controls->len; i++) {
		bc = ctrl(b, i);
		uiControlSetParent(bc->c, NULL);
		// and make sure the widget itself stays alive
		uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE);
		uiControlDestroy(bc->c);
	}
	g_array_free(b->controls, TRUE);
	// and then ourselves
	g_object_unref(b->widget);
	uiFreeControl(uiControl(b));
}

void uiBoxAppend(uiBox *b, uiControl *c, int stretchy)
{
	struct boxChild bc;
	GtkWidget *widget;

	bc.c = c;
	bc.stretchy = stretchy;
	widget = GTK_WIDGET(uiControlHandle(bc.c));
	bc.oldhexpand = gtk_widget_get_hexpand(widget);
	bc.oldhalign = gtk_widget_get_halign(widget);
	bc.oldvexpand = gtk_widget_get_vexpand(widget);
	bc.oldvalign = gtk_widget_get_valign(widget);

	if (bc.stretchy) {
		if (b->vertical) {
			gtk_widget_set_vexpand(widget, TRUE);
			gtk_widget_set_valign(widget, GTK_ALIGN_FILL);
		} else {
			gtk_widget_set_hexpand(widget, TRUE);
			gtk_widget_set_halign(widget, GTK_ALIGN_FILL);
		}
		gtk_size_group_add_widget(b->stretchygroup, widget);
	} else
		if (b->vertical)
			gtk_widget_set_vexpand(widget, FALSE);
		else
			gtk_widget_set_hexpand(widget, FALSE);
	// and make them fill the opposite direction
	if (b->vertical) {
		gtk_widget_set_hexpand(widget, TRUE);
		gtk_widget_set_halign(widget, GTK_ALIGN_FILL);
	} else {
		gtk_widget_set_vexpand(widget, TRUE);
		gtk_widget_set_valign(widget, GTK_ALIGN_FILL);
	}

	uiControlSetParent(bc.c, uiControl(b));
	uiUnixControlSetContainer(uiUnixControl(bc.c), b->container, FALSE);
	g_array_append_val(b->controls, bc);
}

void uiBoxDelete(uiBox *b, int index)
{
	struct boxChild *bc;
	GtkWidget *widget;

	bc = ctrl(b, index);
	widget = GTK_WIDGET(uiControlHandle(bc->c));

	uiControlSetParent(bc->c, NULL);
	uiUnixControlSetContainer(uiUnixControl(bc->c), b->container, TRUE);

	if (bc->stretchy)
		gtk_size_group_remove_widget(b->stretchygroup, widget);
	gtk_widget_set_hexpand(widget, bc->oldhexpand);
	gtk_widget_set_halign(widget, bc->oldhalign);
	gtk_widget_set_vexpand(widget, bc->oldvexpand);
	gtk_widget_set_valign(widget, bc->oldvalign);

	g_array_remove_index(b->controls, index);
}

int uiBoxNumChildren(uiBox *b)
{
	return (int) b->controls->len;
}

int uiBoxPadded(uiBox *b)
{
	return b->padded;
}

void uiBoxSetPadded(uiBox *b, int padded)
{
	b->padded = padded;
	if (b->padded)
		if (b->vertical)
			gtk_box_set_spacing(b->box, uiprivGTKYPadding);
		else
			gtk_box_set_spacing(b->box, uiprivGTKXPadding);
	else
		gtk_box_set_spacing(b->box, 0);
}

static uiBox *finishNewBox(GtkOrientation orientation)
{
	uiBox *b;

	uiUnixNewControl(uiBox, b);

	b->widget = gtk_box_new(orientation, 0);
	b->container = GTK_CONTAINER(b->widget);
	b->box = GTK_BOX(b->widget);

	b->vertical = orientation == GTK_ORIENTATION_VERTICAL;

	if (b->vertical)
		b->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL);
	else
		b->stretchygroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);

	b->controls = g_array_new(FALSE, TRUE, sizeof (struct boxChild));

	return b;
}

uiBox *uiNewHorizontalBox(void)
{
	return finishNewBox(GTK_ORIENTATION_HORIZONTAL);
}

uiBox *uiNewVerticalBox(void)
{
	return finishNewBox(GTK_ORIENTATION_VERTICAL);
}
