X-Git-Url: https://git.draconx.ca/gitweb/aspectbin.git/blobdiff_plain/e6565598a4a1c371cfc091c00ba905b5e96ecc15..4451ba5e2b5ef8d480549c4a6a5b7283b4654ff2:/aspectbin.c diff --git a/aspectbin.c b/aspectbin.c index c9fe6a5..2ce72bd 100644 --- a/aspectbin.c +++ b/aspectbin.c @@ -1,31 +1,59 @@ #include #include "aspectbin.h" +enum { + PROP_0, + PROP_CONSTRAIN, +}; + static void aspect_bin_size_request(GtkWidget *, GtkRequisition *); static void aspect_bin_size_allocate(GtkWidget *, GtkAllocation *); +static void aspect_bin_add(GtkContainer *, GtkWidget *); static void aspect_bin_remove(GtkContainer *, GtkWidget *); static void aspect_bin_forall(GtkContainer *, gboolean, GtkCallback, gpointer); +static GType aspect_bin_child_type(GtkContainer *); + +static void aspect_bin_get_property(GObject *, guint, GValue *, GParamSpec *); +static void aspect_bin_set_property(GObject *, guint, const GValue *, + GParamSpec *); -G_DEFINE_TYPE(AspectBin, aspect_bin, GTK_TYPE_BIN) +G_DEFINE_TYPE(AspectBin, aspect_bin, GTK_TYPE_CONTAINER) -static void aspect_bin_init(AspectBin *ab) +static void aspect_bin_init(AspectBin *abin) { - ab->child = NULL; - ab->ratio = 1; - ab->constrain = FALSE; - ab->align = 0; + GTK_WIDGET_SET_FLAGS(abin, GTK_NO_WINDOW); + + abin->body = NULL; + abin->side = NULL; + abin->ratio = 1; + abin->align = 0; + abin->constrain = FALSE; } -static void aspect_bin_class_init(AspectBinClass *abc) +static void aspect_bin_class_init(AspectBinClass *class) { - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(abc); - GtkContainerClass *container_class = GTK_CONTAINER_CLASS(abc); + GObjectClass *object_class = G_OBJECT_CLASS(class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS(class); widget_class->size_request = aspect_bin_size_request; widget_class->size_allocate = aspect_bin_size_allocate; - container_class->remove = aspect_bin_remove; - container_class->forall = aspect_bin_forall; + container_class->add = aspect_bin_add; + container_class->remove = aspect_bin_remove; + container_class->forall = aspect_bin_forall; + container_class->child_type = aspect_bin_child_type; + + object_class->set_property = aspect_bin_set_property; + object_class->get_property = aspect_bin_get_property; + + g_object_class_install_property(object_class, PROP_CONSTRAIN, + g_param_spec_boolean("constrain", + "Constrain", + "TRUE if side child should expand only as much as the" + " body", + FALSE, + G_PARAM_READWRITE)); } GtkWidget *aspect_bin_new(void) @@ -33,15 +61,61 @@ GtkWidget *aspect_bin_new(void) return GTK_WIDGET(g_object_new(ASPECT_BIN_TYPE, NULL)); } +static void aspect_bin_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + AspectBin *abin = ASPECT_BIN(object); + + switch (prop_id) { + case PROP_CONSTRAIN: + abin->constrain = g_value_get_boolean(value); + gtk_widget_queue_resize(GTK_WIDGET(abin)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void aspect_bin_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AspectBin *abin = ASPECT_BIN(object); + + switch (prop_id) { + case PROP_CONSTRAIN: + g_value_set_boolean(value, abin->constrain); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void aspect_bin_add(GtkContainer *container, GtkWidget *widget) +{ + AspectBin *abin; + g_return_if_fail(IS_ASPECT_BIN(container)); + abin = ASPECT_BIN(container); + + if (!abin->body) + aspect_bin_set_body(abin, widget, 1); + else if (!abin->side) + aspect_bin_set_side(abin, widget); + else + g_warning("AspectBin cannot have more than 2 children.\n"); +} + static void aspect_bin_remove(GtkContainer *container, GtkWidget *child) { AspectBin *abin = ASPECT_BIN(container); - if (abin->child == child) { - aspect_bin_set_body_widget(abin, NULL, 1); - } else { - GTK_CONTAINER_CLASS(aspect_bin_parent_class)->remove - (container, child); + if (abin->body == child) { + aspect_bin_set_body(abin, NULL, 1); + } else if (abin->side == child) { + aspect_bin_set_side(abin, NULL); } } @@ -51,29 +125,34 @@ static void aspect_bin_forall(GtkContainer *container, gpointer callback_data) { AspectBin *abin = ASPECT_BIN(container); - GtkBin *bin = GTK_BIN(container); + g_return_if_fail(callback != NULL); + + if (abin->body) + callback(abin->body, callback_data); + if (abin->side) + callback(abin->side, callback_data); +} - if (bin->child) - callback(bin->child, callback_data); - - if (abin->child) - callback(abin->child, callback_data); +static GType aspect_bin_child_type(GtkContainer *container) +{ + if (!ASPECT_BIN(container)->body || !ASPECT_BIN(container)->side) + return GTK_TYPE_WIDGET; + return G_TYPE_NONE; } static void aspect_bin_size_request(GtkWidget *widget, GtkRequisition *requisition) { AspectBin *abin = ASPECT_BIN(widget); - GtkBin *bin = GTK_BIN(widget); GtkRequisition creq = {0}, areq = {0}; - if (bin->child && GTK_WIDGET_VISIBLE(bin->child)) { - gtk_widget_size_request(bin->child, &creq); + if (abin->side && GTK_WIDGET_VISIBLE(abin->side)) { + gtk_widget_size_request(abin->side, &creq); } - if (abin->child && GTK_WIDGET_VISIBLE(abin->child)) { + if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) { int wtmp, htmp; - gtk_widget_size_request(abin->child, &areq); + gtk_widget_size_request(abin->body, &areq); wtmp = areq.height * abin->ratio + 0.5; htmp = areq.width / abin->ratio + 0.5; @@ -92,12 +171,11 @@ static void aspect_bin_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { AspectBin *abin = ASPECT_BIN(widget); - GtkBin *bin = GTK_BIN(widget); GtkRequisition creq = {0}; GtkAllocation csize = {0}, asize = {0}; - - /* First find the best fit for the constrained child. */ - if (abin->child && GTK_WIDGET_VISIBLE(abin->child)) { + + /* First find the best fit for the body. */ + if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) { asize.height = allocation->height; asize.width = asize.height * abin->ratio + 0.5; @@ -107,9 +185,9 @@ aspect_bin_size_allocate(GtkWidget *widget, GtkAllocation *allocation) } } - /* Now try to fit the other child. */ - if (bin->child && GTK_WIDGET_VISIBLE(bin->child)) { - gtk_widget_get_child_requisition(bin->child, &creq); + /* Now try to fit the side. */ + if (abin->side && GTK_WIDGET_VISIBLE(abin->side)) { + gtk_widget_get_child_requisition(abin->side, &creq); if (allocation->width - asize.width < creq.width) { /* It didn't fit, squish the constrained guy. */ @@ -128,35 +206,50 @@ aspect_bin_size_allocate(GtkWidget *widget, GtkAllocation *allocation) csize.y = (allocation->height - csize.height) * abin->align + 0.5; asize.y = (allocation->height - asize.height) * abin->align + 0.5; - if (bin->child) - gtk_widget_size_allocate(bin->child, &csize); - if (abin->child) - gtk_widget_size_allocate(abin->child, &asize); + if (abin->body) + gtk_widget_size_allocate(abin->body, &asize); + if (abin->side) + gtk_widget_size_allocate(abin->side, &csize); } -void -aspect_bin_set_body_widget(AspectBin *ab, GtkWidget *widget, gfloat ratio) +static gboolean +set_widget(GtkWidget **dest, GtkWidget *parent, GtkWidget *widget) { gboolean need_resize = FALSE; - g_return_if_fail(IS_ASPECT_BIN(ab)); - g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget)); - g_return_if_fail(widget == NULL || widget->parent == NULL); + if (*dest == widget) + return FALSE; - if (ab->child == widget) - return; - - if (ab->child) { - need_resize |= GTK_WIDGET_VISIBLE(ab->child); - gtk_widget_unparent(ab->child); + if (*dest) { + need_resize |= GTK_WIDGET_VISIBLE(*dest); + gtk_widget_unparent(*dest); } - ab->child = widget; + *dest = widget; if (widget) { - gtk_widget_set_parent(widget, GTK_WIDGET(ab)); + gtk_widget_set_parent(widget, parent); need_resize |= GTK_WIDGET_VISIBLE(widget); } - if (GTK_WIDGET_VISIBLE(ab) && need_resize) - gtk_widget_queue_resize(GTK_WIDGET(ab)); + return GTK_WIDGET_VISIBLE(parent) && need_resize; +} + +void aspect_bin_set_body(AspectBin *abin, GtkWidget *widget, gfloat ratio) +{ + g_return_if_fail(IS_ASPECT_BIN(abin)); + g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget)); + g_return_if_fail(widget == NULL || widget->parent == NULL); + + if (set_widget(&abin->body, GTK_WIDGET(abin), widget)) + gtk_widget_queue_resize(GTK_WIDGET(abin)); +} + +void aspect_bin_set_side(AspectBin *abin, GtkWidget *widget) +{ + g_return_if_fail(IS_ASPECT_BIN(abin)); + g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget)); + g_return_if_fail(widget == NULL || widget->parent == NULL); + + if (set_widget(&abin->side, GTK_WIDGET(abin), widget)) + gtk_widget_queue_resize(GTK_WIDGET(abin)); }