2
* Copyright (c) 2011 Red Hat, Inc.
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or (at your
7
* option) any later version.
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12
* License for more details.
14
* You should have received a copy of the GNU Lesser General Public License
15
* along with this program; if not, write to the Free Software Foundation,
16
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
* Author: Cosimo Cecchi <cosimoc@redhat.com>
24
#include "gd-margin-container.h"
26
G_DEFINE_TYPE_WITH_CODE (GdMarginContainer, gd_margin_container, GTK_TYPE_BIN,
27
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
30
struct _GdMarginContainerPrivate {
34
GtkOrientation orientation;
45
gd_margin_container_queue_redraw (GdMarginContainer *self)
49
/* Make sure that the widget and children are redrawn with the new setting: */
50
child = gtk_bin_get_child (GTK_BIN (self));
52
gtk_widget_queue_resize (child);
54
gtk_widget_queue_draw (GTK_WIDGET (self));
58
gd_margin_container_set_orientation (GdMarginContainer *self,
59
GtkOrientation orientation)
61
if (self->priv->orientation != orientation)
63
self->priv->orientation = orientation;
64
g_object_notify (G_OBJECT (self), "orientation");
66
gd_margin_container_queue_redraw (self);
71
gd_margin_container_set_min_margin (GdMarginContainer *self,
74
if (self->priv->min_margin != min_margin)
76
self->priv->min_margin = min_margin;
77
g_object_notify (G_OBJECT (self), "min-margin");
79
gd_margin_container_queue_redraw (self);
84
gd_margin_container_set_max_margin (GdMarginContainer *self,
87
if (self->priv->max_margin != max_margin)
89
self->priv->max_margin = max_margin;
90
g_object_notify (G_OBJECT (self), "max-margin");
92
gd_margin_container_queue_redraw (self);
97
gd_margin_container_set_property (GObject *object,
102
GdMarginContainer *self = GD_MARGIN_CONTAINER (object);
106
case PROP_MIN_MARGIN:
107
gd_margin_container_set_min_margin (self, g_value_get_int (value));
109
case PROP_MAX_MARGIN:
110
gd_margin_container_set_max_margin (self, g_value_get_int (value));
112
case PROP_ORIENTATION:
113
gd_margin_container_set_orientation (self, g_value_get_enum (value));
116
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
122
gd_margin_container_get_property (GObject *object,
127
GdMarginContainer *self = GD_MARGIN_CONTAINER (object);
131
case PROP_MIN_MARGIN:
132
g_value_set_int (value, self->priv->min_margin);
134
case PROP_MAX_MARGIN:
135
g_value_set_int (value, self->priv->max_margin);
137
case PROP_ORIENTATION:
138
g_value_set_enum (value, self->priv->orientation);
141
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
147
gd_margin_container_size_allocate (GtkWidget *widget,
148
GtkAllocation *allocation)
150
GdMarginContainer *self = GD_MARGIN_CONTAINER (widget);
152
GtkAllocation child_allocation;
153
gint avail_width, avail_height;
155
child = gtk_bin_get_child (GTK_BIN (widget));
156
gtk_widget_set_allocation (widget, allocation);
158
if (child && gtk_widget_get_visible (child))
160
gint child_nat_width;
161
gint child_nat_height;
162
gint child_width, child_height;
166
avail_width = allocation->width;
167
avail_height = allocation->height;
169
if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
170
avail_width = MAX (1, avail_width - 2 * self->priv->min_margin);
172
avail_height = MAX (1, avail_height - 2 * self->priv->min_margin);
174
if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
176
gtk_widget_get_preferred_width (child, NULL, &child_nat_width);
177
child_width = MIN (avail_width, child_nat_width);
179
gtk_widget_get_preferred_height_for_width (child, child_width, NULL, &child_nat_height);
180
child_height = MIN (avail_height, child_nat_height);
182
offset = MIN ((gint) ((avail_height - child_height) / 2), self->priv->max_margin);
185
child_allocation.height = avail_height - (offset * 2);
187
child_allocation.height = avail_height;
189
child_allocation.width = MIN (avail_width, child_nat_width);
193
gtk_widget_get_preferred_height (child, NULL, &child_nat_height);
194
child_height = MIN (avail_height, child_nat_height);
196
gtk_widget_get_preferred_width_for_height (child, child_height, NULL, &child_nat_width);
197
child_width = MIN (avail_width, child_nat_width);
199
offset = MIN ((gint) ((avail_width - child_width) / 2), self->priv->max_margin);
202
child_allocation.width = avail_width - (offset * 2);
204
child_allocation.width = avail_width;
206
child_allocation.height = MIN (avail_height, child_nat_height);
209
child_allocation.x = offset + allocation->x;
210
child_allocation.y = (avail_height - child_allocation.height) + allocation->y;
212
if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
213
child_allocation.x += self->priv->min_margin;
215
child_allocation.y += self->priv->min_margin;
217
gtk_widget_size_allocate (child, &child_allocation);
222
gd_margin_container_get_preferred_size (GtkWidget *widget,
223
GtkOrientation orientation,
228
GdMarginContainer *self = GD_MARGIN_CONTAINER (widget);
229
guint natural, minimum;
232
if (orientation == self->priv->orientation)
234
minimum = self->priv->min_margin * 2;
235
natural = self->priv->max_margin * 2;
243
if ((child = gtk_bin_get_child (GTK_BIN (widget))) && gtk_widget_get_visible (child))
245
gint child_min, child_nat;
247
if (orientation == GTK_ORIENTATION_HORIZONTAL)
250
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
255
gtk_widget_get_preferred_height (child, &min_height, NULL);
256
for_size -= 2 * self->priv->min_margin;
258
gtk_widget_get_preferred_width_for_height (child, for_size, &child_min, &child_nat);
264
gtk_widget_get_preferred_height (child, &child_min, &child_nat);
269
gtk_widget_get_preferred_width (child, &min_width, NULL);
270
for_size -= 2 * self->priv->min_margin;
272
gtk_widget_get_preferred_height_for_width (child, for_size, &child_min, &child_nat);
276
natural += child_nat;
278
if (orientation != self->priv->orientation)
279
minimum += child_min;
282
if (minimum_size != NULL)
283
*minimum_size = minimum;
284
if (natural_size != NULL)
285
*natural_size = natural;
289
gd_margin_container_get_preferred_width (GtkWidget *widget,
293
gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL,
294
-1, minimum_size, natural_size);
298
gd_margin_container_get_preferred_height (GtkWidget *widget,
302
gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL,
303
-1, minimum_size, natural_size);
307
gd_margin_container_get_preferred_width_for_height (GtkWidget *widget,
312
gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL,
313
for_size, minimum_size, natural_size);
317
gd_margin_container_get_preferred_height_for_width (GtkWidget *widget,
322
gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL,
323
for_size, minimum_size, natural_size);
327
gd_margin_container_init (GdMarginContainer *self)
329
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GD_TYPE_MARGIN_CONTAINER,
330
GdMarginContainerPrivate);
332
self->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
334
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
335
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (self), FALSE);
339
gd_margin_container_class_init (GdMarginContainerClass *klass)
341
GObjectClass *oclass = G_OBJECT_CLASS (klass);
342
GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass);
344
oclass->get_property = gd_margin_container_get_property;
345
oclass->set_property = gd_margin_container_set_property;
347
wclass->size_allocate = gd_margin_container_size_allocate;
348
wclass->get_preferred_width = gd_margin_container_get_preferred_width;
349
wclass->get_preferred_height = gd_margin_container_get_preferred_height;
350
wclass->get_preferred_width_for_height = gd_margin_container_get_preferred_width_for_height;
351
wclass->get_preferred_height_for_width = gd_margin_container_get_preferred_height_for_width;
353
gtk_container_class_handle_border_width (GTK_CONTAINER_CLASS (klass));
355
g_object_class_install_property (oclass, PROP_MIN_MARGIN,
356
g_param_spec_int ("min-margin",
358
"Minimum margin around the child",
362
g_object_class_install_property (oclass, PROP_MAX_MARGIN,
363
g_param_spec_int ("max-margin",
365
"Maximum margin around the child",
369
g_object_class_override_property (oclass, PROP_ORIENTATION,
372
g_type_class_add_private (klass, sizeof (GdMarginContainerPrivate));
376
gd_margin_container_new (void)
378
return g_object_new (GD_TYPE_MARGIN_CONTAINER, NULL);