~ubuntu-branches/ubuntu/quantal/gnome-documents/quantal

« back to all changes in this revision

Viewing changes to src/lib/gd-margin-container.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2012-08-22 10:01:18 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20120822100118-3837rqfy72e1op72
Tags: 3.5.90-0ubuntu1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2011 Red Hat, Inc.
3
 
 *
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.
8
 
 *
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.
13
 
 *
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
17
 
 *
18
 
 * Author: Cosimo Cecchi <cosimoc@redhat.com>
19
 
 *
20
 
 */
21
 
 
22
 
#include "config.h"
23
 
 
24
 
#include "gd-margin-container.h"
25
 
 
26
 
G_DEFINE_TYPE_WITH_CODE (GdMarginContainer, gd_margin_container, GTK_TYPE_BIN,
27
 
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
28
 
                                                NULL))
29
 
 
30
 
struct _GdMarginContainerPrivate {
31
 
  gint min_margin;
32
 
  gint max_margin;
33
 
 
34
 
  GtkOrientation orientation;
35
 
};
36
 
 
37
 
enum {
38
 
  PROP_MIN_MARGIN = 1,
39
 
  PROP_MAX_MARGIN,
40
 
  PROP_ORIENTATION,
41
 
  NUM_PROPERTIES
42
 
};
43
 
 
44
 
static void
45
 
gd_margin_container_queue_redraw (GdMarginContainer *self)
46
 
{
47
 
  GtkWidget *child;
48
 
 
49
 
  /* Make sure that the widget and children are redrawn with the new setting: */
50
 
  child = gtk_bin_get_child (GTK_BIN (self));
51
 
  if (child)
52
 
    gtk_widget_queue_resize (child);
53
 
 
54
 
  gtk_widget_queue_draw (GTK_WIDGET (self));
55
 
}
56
 
 
57
 
static void
58
 
gd_margin_container_set_orientation (GdMarginContainer *self,
59
 
                                     GtkOrientation orientation)
60
 
{
61
 
  if (self->priv->orientation != orientation)
62
 
    {
63
 
      self->priv->orientation = orientation;
64
 
      g_object_notify (G_OBJECT (self), "orientation");
65
 
 
66
 
      gd_margin_container_queue_redraw (self);
67
 
    }
68
 
}
69
 
 
70
 
static void
71
 
gd_margin_container_set_min_margin (GdMarginContainer *self,
72
 
                                    gint min_margin)
73
 
{
74
 
  if (self->priv->min_margin != min_margin)
75
 
    {
76
 
      self->priv->min_margin = min_margin;
77
 
      g_object_notify (G_OBJECT (self), "min-margin");
78
 
 
79
 
      gd_margin_container_queue_redraw (self);
80
 
    }
81
 
}
82
 
 
83
 
static void
84
 
gd_margin_container_set_max_margin (GdMarginContainer *self,
85
 
                                    gint max_margin)
86
 
{
87
 
  if (self->priv->max_margin != max_margin)
88
 
    {
89
 
      self->priv->max_margin = max_margin;
90
 
      g_object_notify (G_OBJECT (self), "max-margin");
91
 
 
92
 
      gd_margin_container_queue_redraw (self);
93
 
    }
94
 
}
95
 
 
96
 
static void
97
 
gd_margin_container_set_property (GObject      *object,
98
 
                                  guint         property_id,
99
 
                                  const GValue *value,
100
 
                                  GParamSpec   *pspec)
101
 
{
102
 
  GdMarginContainer *self = GD_MARGIN_CONTAINER (object);
103
 
 
104
 
  switch (property_id)
105
 
    {
106
 
    case PROP_MIN_MARGIN:
107
 
      gd_margin_container_set_min_margin (self, g_value_get_int (value));
108
 
      break;
109
 
    case PROP_MAX_MARGIN:
110
 
      gd_margin_container_set_max_margin (self, g_value_get_int (value));
111
 
      break;
112
 
    case PROP_ORIENTATION:
113
 
      gd_margin_container_set_orientation (self, g_value_get_enum (value));
114
 
      break;
115
 
    default:
116
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
117
 
      break;
118
 
    }
119
 
}
120
 
 
121
 
static void
122
 
gd_margin_container_get_property (GObject    *object,
123
 
                                  guint       property_id,
124
 
                                  GValue     *value,
125
 
                                  GParamSpec *pspec) 
126
 
{
127
 
  GdMarginContainer *self = GD_MARGIN_CONTAINER (object);
128
 
 
129
 
  switch (property_id)
130
 
    {
131
 
    case PROP_MIN_MARGIN: 
132
 
      g_value_set_int (value, self->priv->min_margin);
133
 
      break;
134
 
    case PROP_MAX_MARGIN:
135
 
      g_value_set_int (value, self->priv->max_margin);
136
 
      break;
137
 
    case PROP_ORIENTATION:
138
 
      g_value_set_enum (value, self->priv->orientation);
139
 
      break;
140
 
    default:
141
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
142
 
      break;
143
 
    }
144
 
}
145
 
 
146
 
static void
147
 
gd_margin_container_size_allocate (GtkWidget *widget,
148
 
                                   GtkAllocation *allocation)
149
 
{
150
 
  GdMarginContainer *self = GD_MARGIN_CONTAINER (widget);
151
 
  GtkWidget *child;
152
 
  GtkAllocation child_allocation;
153
 
  gint avail_width, avail_height;
154
 
 
155
 
  child = gtk_bin_get_child (GTK_BIN (widget));
156
 
  gtk_widget_set_allocation (widget, allocation);
157
 
 
158
 
  if (child && gtk_widget_get_visible (child))
159
 
    {
160
 
      gint child_nat_width;
161
 
      gint child_nat_height;
162
 
      gint child_width, child_height;
163
 
      gint offset;
164
 
 
165
 
      /* available */
166
 
      avail_width = allocation->width;
167
 
      avail_height = allocation->height;
168
 
 
169
 
      if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
170
 
        avail_width  = MAX (1, avail_width - 2 * self->priv->min_margin);
171
 
      else
172
 
        avail_height = MAX (1, avail_height - 2 * self->priv->min_margin);
173
 
 
174
 
      if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
175
 
        {
176
 
          gtk_widget_get_preferred_width (child, NULL, &child_nat_width);
177
 
          child_width = MIN (avail_width, child_nat_width);
178
 
 
179
 
          gtk_widget_get_preferred_height_for_width (child, child_width, NULL, &child_nat_height);
180
 
          child_height = MIN (avail_height, child_nat_height);
181
 
 
182
 
          offset = MIN ((gint) ((avail_height - child_height) / 2), self->priv->max_margin);
183
 
 
184
 
          if (offset > 0)
185
 
            child_allocation.height = avail_height  - (offset * 2);
186
 
          else
187
 
            child_allocation.height = avail_height;
188
 
 
189
 
          child_allocation.width = MIN (avail_width, child_nat_width);
190
 
        }
191
 
      else
192
 
        {
193
 
          gtk_widget_get_preferred_height (child, NULL, &child_nat_height);
194
 
          child_height = MIN (avail_height, child_nat_height);
195
 
 
196
 
          gtk_widget_get_preferred_width_for_height (child, child_height, NULL, &child_nat_width);
197
 
          child_width = MIN (avail_width, child_nat_width);
198
 
 
199
 
          offset = MIN ((gint) ((avail_width - child_width) / 2), self->priv->max_margin);
200
 
 
201
 
          if (offset > 0)
202
 
            child_allocation.width = avail_width - (offset * 2);
203
 
          else
204
 
            child_allocation.width = avail_width;
205
 
 
206
 
          child_allocation.height = MIN (avail_height, child_nat_height);
207
 
        }
208
 
 
209
 
      child_allocation.x = offset + allocation->x;
210
 
      child_allocation.y = (avail_height - child_allocation.height) + allocation->y;
211
 
 
212
 
      if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
213
 
        child_allocation.x += self->priv->min_margin;
214
 
      else
215
 
        child_allocation.y += self->priv->min_margin;
216
 
 
217
 
      gtk_widget_size_allocate (child, &child_allocation);
218
 
    }
219
 
}
220
 
 
221
 
static void
222
 
gd_margin_container_get_preferred_size (GtkWidget *widget,
223
 
                                        GtkOrientation orientation,
224
 
                                        gint for_size,
225
 
                                        gint *minimum_size,
226
 
                                        gint *natural_size)
227
 
{
228
 
  GdMarginContainer *self = GD_MARGIN_CONTAINER (widget);
229
 
  guint natural, minimum;
230
 
  GtkWidget *child;
231
 
 
232
 
  if (orientation == self->priv->orientation)
233
 
    {
234
 
      minimum = self->priv->min_margin * 2;
235
 
      natural = self->priv->max_margin * 2;
236
 
    }
237
 
  else
238
 
    {
239
 
      minimum = 0;
240
 
      natural = 0;
241
 
    }
242
 
 
243
 
  if ((child = gtk_bin_get_child (GTK_BIN (widget))) && gtk_widget_get_visible (child))
244
 
    {
245
 
      gint child_min, child_nat;
246
 
 
247
 
      if (orientation == GTK_ORIENTATION_HORIZONTAL)
248
 
        {
249
 
          if (for_size < 0)
250
 
            gtk_widget_get_preferred_width (child, &child_min, &child_nat);
251
 
          else
252
 
            {
253
 
              gint min_height;
254
 
 
255
 
              gtk_widget_get_preferred_height (child, &min_height, NULL);
256
 
              for_size -= 2 * self->priv->min_margin;
257
 
 
258
 
              gtk_widget_get_preferred_width_for_height (child, for_size, &child_min, &child_nat);
259
 
            }
260
 
        }
261
 
      else
262
 
        {
263
 
          if (for_size < 0)
264
 
            gtk_widget_get_preferred_height (child, &child_min, &child_nat);
265
 
          else
266
 
            {
267
 
              gint min_width;
268
 
 
269
 
              gtk_widget_get_preferred_width (child, &min_width, NULL);
270
 
              for_size -= 2 * self->priv->min_margin;
271
 
 
272
 
              gtk_widget_get_preferred_height_for_width (child, for_size, &child_min, &child_nat);
273
 
            }
274
 
        }
275
 
 
276
 
      natural += child_nat;
277
 
 
278
 
      if (orientation != self->priv->orientation)
279
 
        minimum += child_min;
280
 
    }
281
 
 
282
 
  if (minimum_size != NULL)
283
 
    *minimum_size = minimum;
284
 
  if (natural_size != NULL)
285
 
    *natural_size = natural;
286
 
}
287
 
 
288
 
static void
289
 
gd_margin_container_get_preferred_width (GtkWidget *widget,
290
 
                                         gint      *minimum_size,
291
 
                                         gint      *natural_size)
292
 
{
293
 
  gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL,
294
 
                                          -1, minimum_size, natural_size);
295
 
}
296
 
 
297
 
static void
298
 
gd_margin_container_get_preferred_height (GtkWidget *widget,
299
 
                                          gint      *minimum_size,
300
 
                                          gint      *natural_size)
301
 
{
302
 
  gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL,
303
 
                                          -1, minimum_size, natural_size);
304
 
}
305
 
 
306
 
static void 
307
 
gd_margin_container_get_preferred_width_for_height (GtkWidget *widget,
308
 
                                                    gint       for_size,
309
 
                                                    gint      *minimum_size,
310
 
                                                    gint      *natural_size)
311
 
{
312
 
  gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL,
313
 
                                          for_size, minimum_size, natural_size);
314
 
}
315
 
 
316
 
static void 
317
 
gd_margin_container_get_preferred_height_for_width (GtkWidget *widget,
318
 
                                                    gint       for_size,
319
 
                                                    gint      *minimum_size,
320
 
                                                    gint      *natural_size)
321
 
{
322
 
  gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL,
323
 
                                          for_size, minimum_size, natural_size);
324
 
}
325
 
 
326
 
static void
327
 
gd_margin_container_init (GdMarginContainer *self)
328
 
{
329
 
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GD_TYPE_MARGIN_CONTAINER,
330
 
                                            GdMarginContainerPrivate);
331
 
 
332
 
  self->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
333
 
 
334
 
  gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
335
 
  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (self), FALSE);
336
 
}
337
 
 
338
 
static void
339
 
gd_margin_container_class_init (GdMarginContainerClass *klass)
340
 
{
341
 
  GObjectClass *oclass = G_OBJECT_CLASS (klass);
342
 
  GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass);
343
 
 
344
 
  oclass->get_property = gd_margin_container_get_property;
345
 
  oclass->set_property = gd_margin_container_set_property;
346
 
 
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;
352
 
 
353
 
  gtk_container_class_handle_border_width (GTK_CONTAINER_CLASS (klass));
354
 
 
355
 
  g_object_class_install_property (oclass, PROP_MIN_MARGIN,
356
 
                                   g_param_spec_int ("min-margin",
357
 
                                                     "Min margin",
358
 
                                                     "Minimum margin around the child",
359
 
                                                     0, G_MAXINT, 6,
360
 
                                                     G_PARAM_READWRITE |
361
 
                                                     G_PARAM_CONSTRUCT));
362
 
  g_object_class_install_property (oclass, PROP_MAX_MARGIN,
363
 
                                   g_param_spec_int ("max-margin",
364
 
                                                     "Max margin",
365
 
                                                     "Maximum margin around the child",
366
 
                                                     0, G_MAXINT, 6,
367
 
                                                     G_PARAM_READWRITE |
368
 
                                                     G_PARAM_CONSTRUCT));
369
 
  g_object_class_override_property (oclass, PROP_ORIENTATION,
370
 
                                    "orientation");
371
 
;
372
 
  g_type_class_add_private (klass, sizeof (GdMarginContainerPrivate));
373
 
}
374
 
 
375
 
GdMarginContainer *
376
 
gd_margin_container_new (void)
377
 
{
378
 
  return g_object_new (GD_TYPE_MARGIN_CONTAINER, NULL);
379
 
}