diff options
Diffstat (limited to 'src/gs-fixed-size-bin.c')
-rw-r--r-- | src/gs-fixed-size-bin.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/gs-fixed-size-bin.c b/src/gs-fixed-size-bin.c new file mode 100644 index 0000000..7d326ee --- /dev/null +++ b/src/gs-fixed-size-bin.c @@ -0,0 +1,237 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * + * Copyright (C) 2016 Rafał Lużyński <digitalfreak@lingonborough.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "config.h" + +#include "gs-fixed-size-bin.h" + +struct _GsFixedSizeBin { + GtkBin parent; + gint preferred_width; + gint preferred_height; + gint min_width; + gint min_height; +}; + +G_DEFINE_TYPE (GsFixedSizeBin, gs_fixed_size_bin, GTK_TYPE_BIN) + +enum { + PROP_0, + PROP_PREFERRED_WIDTH, + PROP_PREFERRED_HEIGHT +}; + +static void +gs_fixed_size_bin_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + GsFixedSizeBin *bin = GS_FIXED_SIZE_BIN (widget); + + if (bin->preferred_width >= 0 && + bin->preferred_width >= bin->min_width && + allocation->width > bin->preferred_width) { + /* Center the contents */ + allocation->x += (allocation->width - bin->preferred_width) / 2; + allocation->width = bin->preferred_width; + } + if (bin->preferred_height >= 0 && + bin->preferred_height >= bin->min_height && + allocation->height > bin->preferred_height) { + /* Align to the top */ + allocation->height = bin->preferred_height; + } + + GTK_WIDGET_CLASS (gs_fixed_size_bin_parent_class)->size_allocate (widget, allocation); +} + +static void +gs_fixed_size_bin_get_preferred_width (GtkWidget *widget, + gint *min, gint *nat) +{ + GsFixedSizeBin *bin = GS_FIXED_SIZE_BIN (widget); + gint m, n; + + GTK_WIDGET_CLASS (gs_fixed_size_bin_parent_class)->get_preferred_width (widget, &m, &n); + + bin->min_width = m; + if (bin->preferred_width >= 0 && n > bin->preferred_width) + n = MAX (m, bin->preferred_width); + if (min) + *min = m; + if (nat) + *nat = n; +} + +static void +gs_fixed_size_bin_get_preferred_height (GtkWidget *widget, + gint *min, gint *nat) +{ + GsFixedSizeBin *bin = GS_FIXED_SIZE_BIN (widget); + gint m, n; + + GTK_WIDGET_CLASS (gs_fixed_size_bin_parent_class)->get_preferred_height (widget, &m, &n); + + bin->min_height = m; + if (bin->preferred_height >= 0 && n > bin->preferred_height) + n = MAX (m, bin->preferred_height); + if (min) + *min = m; + if (nat) + *nat = n; +} + +static void +gs_fixed_size_bin_get_preferred_width_for_height (GtkWidget *widget, + gint for_height, + gint *min, gint *nat) +{ + GsFixedSizeBin *bin = GS_FIXED_SIZE_BIN (widget); + gint m, n; + + if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH) { + GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, + min, nat); + return; + } + + if (bin->preferred_height >= 0 && + for_height > bin->preferred_height) { + /* The height will be limited */ + for_height = MAX (bin->min_height, bin->preferred_height); + } + + GTK_WIDGET_CLASS (gs_fixed_size_bin_parent_class)->get_preferred_width_for_height ( + widget, for_height, &m, &n); + + bin->min_width = m; + if (bin->preferred_width >= 0 && n > bin->preferred_width) + n = MAX (m, bin->preferred_width); + if (min) + *min = m; + if (nat) + *nat = n; +} + +static void +gs_fixed_size_bin_get_preferred_height_for_width (GtkWidget *widget, + gint for_width, + gint *min, gint *nat) +{ + GsFixedSizeBin *bin = GS_FIXED_SIZE_BIN (widget); + gint m, n; + + if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT) { + GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, + min, nat); + return; + } + + if (bin->preferred_width >= 0 && + for_width > bin->preferred_width) { + /* The width will be limited */ + for_width = MAX (bin->min_width, bin->preferred_width); + } + + GTK_WIDGET_CLASS (gs_fixed_size_bin_parent_class)->get_preferred_height_for_width ( + widget, for_width, &m, &n); + + bin->min_height = m; + if (bin->preferred_height >= 0 && n > bin->preferred_height) + n = MAX (m, bin->preferred_height); + if (min) + *min = m; + if (nat) + *nat = n; +} + +static void +gs_fixed_size_bin_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsFixedSizeBin *bin = GS_FIXED_SIZE_BIN (object); + + switch (prop_id) { + case PROP_PREFERRED_WIDTH: + g_value_set_int (value, bin->preferred_width); + break; + case PROP_PREFERRED_HEIGHT: + g_value_set_int (value, bin->preferred_height); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gs_fixed_size_bin_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsFixedSizeBin *bin = GS_FIXED_SIZE_BIN (object); + + switch (prop_id) { + case PROP_PREFERRED_WIDTH: + bin->preferred_width = g_value_get_int (value); + gtk_widget_queue_resize (GTK_WIDGET (bin)); + break; + case PROP_PREFERRED_HEIGHT: + bin->preferred_height = g_value_get_int (value); + gtk_widget_queue_resize (GTK_WIDGET (bin)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gs_fixed_size_bin_init (GsFixedSizeBin *bin) +{ + gtk_widget_set_has_window (GTK_WIDGET (bin), FALSE); + bin->preferred_width = -1; + bin->preferred_height = -1; +} + +static void +gs_fixed_size_bin_class_init (GsFixedSizeBinClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + object_class->get_property = gs_fixed_size_bin_get_property; + object_class->set_property = gs_fixed_size_bin_set_property; + + widget_class->size_allocate = gs_fixed_size_bin_size_allocate; + widget_class->get_preferred_width = gs_fixed_size_bin_get_preferred_width; + widget_class->get_preferred_height = gs_fixed_size_bin_get_preferred_height; + widget_class->get_preferred_width_for_height = gs_fixed_size_bin_get_preferred_width_for_height; + widget_class->get_preferred_height_for_width = gs_fixed_size_bin_get_preferred_height_for_width; + + g_object_class_install_property (object_class, PROP_PREFERRED_WIDTH, + g_param_spec_int ("preferred-width", + "Preferred width", + "The width of this widget unless its parent is smaller or its child requires more", + -1, G_MAXINT, -1, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_PREFERRED_HEIGHT, + g_param_spec_int ("preferred-height", + "Preferred height", + "The height of this widget unless its parent is smaller or its child requires more", + -1, G_MAXINT, -1, + G_PARAM_READWRITE)); +} + +GtkWidget * +gs_fixed_size_bin_new (void) +{ + return g_object_new (GS_TYPE_FIXED_SIZE_BIN, NULL); +} |