~ubuntu-branches/ubuntu/precise/clutter-1.0/precise

« back to all changes in this revision

Viewing changes to clutter/clutter-bin-layout.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental) (1.3.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Clutter.
 
3
 *
 
4
 * An OpenGL based 'interactive canvas' library.
 
5
 *
 
6
 * Copyright (C) 2009  Intel Corporation.
 
7
 *
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Lesser General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 * Author:
 
22
 *   Emmanuele Bassi <ebassi@linux.intel.com>
 
23
 */
 
24
 
 
25
/**
 
26
 * SECTION:clutter-bin-layout
 
27
 * @short_description: A simple layout manager
 
28
 *
 
29
 * #ClutterBinLayout is a layout manager which implements the following
 
30
 * policy:
 
31
 *
 
32
 * <itemizedlist>
 
33
 *   <listitem><simpara>the preferred size is the maximum preferred size
 
34
 *   between all the children of the container using the
 
35
 *   layout;</simpara></listitem>
 
36
 *   <listitem><simpara>each child is allocated in "layers", on on top
 
37
 *   of the other;</simpara></listitem>
 
38
 *   <listitem><simpara>for each layer there are horizontal and vertical
 
39
 *   alignment policies.</simpara></listitem>
 
40
 * </itemizedlist>
 
41
 *
 
42
 * <figure id="bin-layout">
 
43
 *   <title>Bin layout</title>
 
44
 *   <para>The image shows a #ClutterBinLayout with three layers:
 
45
 *   a background #ClutterCairoTexture, set to fill on both the X
 
46
 *   and Y axis; a #ClutterTexture, set to center on both the X and
 
47
 *   Y axis; and a #ClutterRectangle, set to %CLUTTER_BIN_ALIGNMENT_END
 
48
 *   on both the X and Y axis.</para>
 
49
 *   <graphic fileref="bin-layout.png" format="PNG"/>
 
50
 * </figure>
 
51
 *
 
52
 * <example id="example-clutter-bin-layout">
 
53
 *  <title>How to pack actors inside a BinLayout</title>
 
54
 *  <para>The following code shows how to build a composite actor with
 
55
 *  a texture and a background, and add controls overlayed on top. The
 
56
 *  background is set to fill the whole allocation, whilst the texture
 
57
 *  is centered; there is a control in the top right corner and a label
 
58
 *  in the bottom, filling out the whole allocated width.</para>
 
59
 *  <programlisting>
 
60
 *  ClutterLayoutManager *manager;
 
61
 *  ClutterActor *box;
 
62
 *
 
63
 *  /&ast; create the layout first &ast;/
 
64
 *  layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
 
65
 *                                   CLUTTER_BIN_ALIGNMENT_CENTER);
 
66
 *  box = clutter_box_new (layout); /&ast; then the container &ast;/
 
67
 *
 
68
 *  /&ast; we can use the layout object to add actors &ast;/
 
69
 *  clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), background,
 
70
 *                          CLUTTER_BIN_ALIGNMENT_FILL,
 
71
 *                          CLUTTER_BIN_ALIGNMENT_FILL);
 
72
 *  clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), icon,
 
73
 *                          CLUTTER_BIN_ALIGNMENT_CENTER,
 
74
 *                          CLUTTER_BIN_ALIGNMENT_CENTER);
 
75
 *
 
76
 *  /&ast; align to the bottom left &ast;/
 
77
 *  clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), label,
 
78
 *                          CLUTTER_BIN_ALIGNMENT_START,
 
79
 *                          CLUTTER_BIN_ALIGNMENT_END);
 
80
 *  /&ast; align to the top right &ast;/
 
81
 *  clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), button,
 
82
 *                          CLUTTER_BIN_ALIGNMENT_END,
 
83
 *                          CLUTTER_BIN_ALIGNMENT_START);
 
84
 *  </programlisting>
 
85
 * </example>
 
86
 *
 
87
 * #ClutterBinLayout is available since Clutter 1.2
 
88
 */
 
89
 
 
90
#ifdef HAVE_CONFIG_H
 
91
#include "config.h"
 
92
#endif
 
93
 
 
94
#include <math.h>
 
95
 
 
96
#include "clutter-actor.h"
 
97
#include "clutter-animatable.h"
 
98
#include "clutter-bin-layout.h"
 
99
#include "clutter-child-meta.h"
 
100
#include "clutter-debug.h"
 
101
#include "clutter-enum-types.h"
 
102
#include "clutter-layout-meta.h"
 
103
#include "clutter-private.h"
 
104
 
 
105
#define CLUTTER_TYPE_BIN_LAYER          (clutter_bin_layer_get_type ())
 
106
#define CLUTTER_BIN_LAYER(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYER, ClutterBinLayer))
 
107
#define CLUTTER_IS_BIN_LAYER(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYER))
 
108
 
 
109
#define CLUTTER_BIN_LAYOUT_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutPrivate))
 
110
 
 
111
typedef struct _ClutterBinLayer         ClutterBinLayer;
 
112
typedef struct _ClutterLayoutMetaClass  ClutterBinLayerClass;
 
113
 
 
114
struct _ClutterBinLayoutPrivate
 
115
{
 
116
  ClutterBinAlignment x_align;
 
117
  ClutterBinAlignment y_align;
 
118
 
 
119
  ClutterContainer *container;
 
120
};
 
121
 
 
122
struct _ClutterBinLayer
 
123
{
 
124
  ClutterLayoutMeta parent_instance;
 
125
 
 
126
  ClutterBinAlignment x_align;
 
127
  ClutterBinAlignment y_align;
 
128
};
 
129
 
 
130
enum
 
131
{
 
132
  PROP_LAYER_0,
 
133
 
 
134
  PROP_LAYER_X_ALIGN,
 
135
  PROP_LAYER_Y_ALIGN
 
136
};
 
137
 
 
138
enum
 
139
{
 
140
  PROP_0,
 
141
 
 
142
  PROP_X_ALIGN,
 
143
  PROP_Y_ALIGN
 
144
};
 
145
 
 
146
G_DEFINE_TYPE (ClutterBinLayer,
 
147
               clutter_bin_layer,
 
148
               CLUTTER_TYPE_LAYOUT_META);
 
149
 
 
150
G_DEFINE_TYPE (ClutterBinLayout,
 
151
               clutter_bin_layout,
 
152
               CLUTTER_TYPE_LAYOUT_MANAGER);
 
153
 
 
154
/*
 
155
 * ClutterBinLayer
 
156
 */
 
157
 
 
158
static void
 
159
set_layer_x_align (ClutterBinLayer     *self,
 
160
                   ClutterBinAlignment  alignment)
 
161
{
 
162
  ClutterLayoutManager *manager;
 
163
  ClutterLayoutMeta *meta;
 
164
 
 
165
  if (self->x_align == alignment)
 
166
    return;
 
167
 
 
168
  self->x_align = alignment;
 
169
 
 
170
  meta = CLUTTER_LAYOUT_META (self);
 
171
  manager = clutter_layout_meta_get_manager (meta);
 
172
  clutter_layout_manager_layout_changed (manager);
 
173
 
 
174
  g_object_notify (G_OBJECT (self), "x-align");
 
175
}
 
176
 
 
177
static void
 
178
set_layer_y_align (ClutterBinLayer     *self,
 
179
                   ClutterBinAlignment  alignment)
 
180
{
 
181
  ClutterLayoutManager *manager;
 
182
  ClutterLayoutMeta *meta;
 
183
 
 
184
  if (self->y_align == alignment)
 
185
    return;
 
186
 
 
187
  self->y_align = alignment;
 
188
 
 
189
  meta = CLUTTER_LAYOUT_META (self);
 
190
  manager = clutter_layout_meta_get_manager (meta);
 
191
  clutter_layout_manager_layout_changed (manager);
 
192
 
 
193
  g_object_notify (G_OBJECT (self), "y-align");
 
194
}
 
195
 
 
196
static void
 
197
clutter_bin_layer_set_property (GObject      *gobject,
 
198
                                guint         prop_id,
 
199
                                const GValue *value,
 
200
                                GParamSpec   *pspec)
 
201
{
 
202
  ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
 
203
 
 
204
  switch (prop_id)
 
205
    {
 
206
    case PROP_LAYER_X_ALIGN:
 
207
      set_layer_x_align (layer, g_value_get_enum (value));
 
208
      break;
 
209
 
 
210
    case PROP_LAYER_Y_ALIGN:
 
211
      set_layer_y_align (layer, g_value_get_enum (value));
 
212
      break;
 
213
 
 
214
    default:
 
215
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
216
      break;
 
217
    }
 
218
}
 
219
 
 
220
static void
 
221
clutter_bin_layer_get_property (GObject    *gobject,
 
222
                                guint       prop_id,
 
223
                                GValue     *value,
 
224
                                GParamSpec *pspec)
 
225
{
 
226
  ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
 
227
 
 
228
  switch (prop_id)
 
229
    {
 
230
    case PROP_LAYER_X_ALIGN:
 
231
      g_value_set_enum (value, layer->x_align);
 
232
      break;
 
233
 
 
234
    case PROP_LAYER_Y_ALIGN:
 
235
      g_value_set_enum (value, layer->y_align);
 
236
      break;
 
237
 
 
238
    default:
 
239
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
240
      break;
 
241
    }
 
242
}
 
243
 
 
244
static void
 
245
clutter_bin_layer_class_init (ClutterBinLayerClass *klass)
 
246
{
 
247
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
248
  GParamSpec *pspec;
 
249
 
 
250
  gobject_class->set_property = clutter_bin_layer_set_property;
 
251
  gobject_class->get_property = clutter_bin_layer_get_property;
 
252
 
 
253
  pspec = g_param_spec_enum ("x-align",
 
254
                             "Horizontal Alignment",
 
255
                             "Horizontal alignment for the actor "
 
256
                             "inside the layer",
 
257
                             CLUTTER_TYPE_BIN_ALIGNMENT,
 
258
                             CLUTTER_BIN_ALIGNMENT_CENTER,
 
259
                             CLUTTER_PARAM_READWRITE);
 
260
  g_object_class_install_property (gobject_class,
 
261
                                   PROP_LAYER_X_ALIGN,
 
262
                                   pspec);
 
263
 
 
264
  pspec = g_param_spec_enum ("y-align",
 
265
                             "Vertical Alignment",
 
266
                             "Vertical alignment for the actor "
 
267
                             "inside the layer manager",
 
268
                             CLUTTER_TYPE_BIN_ALIGNMENT,
 
269
                             CLUTTER_BIN_ALIGNMENT_CENTER,
 
270
                             CLUTTER_PARAM_READWRITE);
 
271
  g_object_class_install_property (gobject_class,
 
272
                                   PROP_LAYER_Y_ALIGN,
 
273
                                   pspec);
 
274
}
 
275
 
 
276
static void
 
277
clutter_bin_layer_init (ClutterBinLayer *layer)
 
278
{
 
279
  layer->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
 
280
  layer->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
 
281
}
 
282
 
 
283
/*
 
284
 * ClutterBinLayout
 
285
 */
 
286
 
 
287
static void
 
288
set_x_align (ClutterBinLayout    *self,
 
289
             ClutterBinAlignment  alignment)
 
290
{
 
291
  ClutterBinLayoutPrivate *priv = self->priv;
 
292
 
 
293
  if (priv->x_align != alignment)
 
294
    {
 
295
      ClutterLayoutManager *manager;
 
296
 
 
297
      priv->x_align = alignment;
 
298
 
 
299
      manager = CLUTTER_LAYOUT_MANAGER (self);
 
300
      clutter_layout_manager_layout_changed (manager);
 
301
 
 
302
      g_object_notify (G_OBJECT (self), "x-align");
 
303
    }
 
304
}
 
305
 
 
306
static void
 
307
set_y_align (ClutterBinLayout    *self,
 
308
             ClutterBinAlignment  alignment)
 
309
{
 
310
  ClutterBinLayoutPrivate *priv = self->priv;
 
311
 
 
312
  if (priv->y_align != alignment)
 
313
    {
 
314
      ClutterLayoutManager *manager;
 
315
 
 
316
      priv->y_align = alignment;
 
317
 
 
318
      manager = CLUTTER_LAYOUT_MANAGER (self);
 
319
      clutter_layout_manager_layout_changed (manager);
 
320
 
 
321
      g_object_notify (G_OBJECT (self), "y-align");
 
322
    }
 
323
}
 
324
 
 
325
static void
 
326
clutter_bin_layout_get_preferred_width (ClutterLayoutManager *manager,
 
327
                                        ClutterContainer     *container,
 
328
                                        gfloat                for_height,
 
329
                                        gfloat               *min_width_p,
 
330
                                        gfloat               *nat_width_p)
 
331
{
 
332
  GList *children = clutter_container_get_children (container);
 
333
  GList *l;
 
334
  gfloat min_width, nat_width;
 
335
 
 
336
  min_width = nat_width = 0.0;
 
337
 
 
338
  for (l = children; l != NULL; l = l->next)
 
339
    {
 
340
      ClutterActor *child = l->data;
 
341
      gfloat minimum, natural;
 
342
 
 
343
      clutter_actor_get_preferred_width (child, for_height,
 
344
                                         &minimum,
 
345
                                         &natural);
 
346
 
 
347
      min_width = MAX (min_width, minimum);
 
348
      nat_width = MAX (nat_width, natural);
 
349
    }
 
350
 
 
351
  if (min_width_p)
 
352
    *min_width_p = min_width;
 
353
 
 
354
  if (nat_width_p)
 
355
    *nat_width_p = nat_width;
 
356
}
 
357
 
 
358
static void
 
359
clutter_bin_layout_get_preferred_height (ClutterLayoutManager *manager,
 
360
                                         ClutterContainer     *container,
 
361
                                         gfloat                for_width,
 
362
                                         gfloat               *min_height_p,
 
363
                                         gfloat               *nat_height_p)
 
364
{
 
365
  GList *children = clutter_container_get_children (container);
 
366
  GList *l;
 
367
  gfloat min_height, nat_height;
 
368
 
 
369
  min_height = nat_height = 0.0;
 
370
 
 
371
  for (l = children; l != NULL; l = l->next)
 
372
    {
 
373
      ClutterActor *child = l->data;
 
374
      gfloat minimum, natural;
 
375
 
 
376
      clutter_actor_get_preferred_height (child, for_width,
 
377
                                          &minimum,
 
378
                                          &natural);
 
379
 
 
380
      min_height = MAX (min_height, minimum);
 
381
      nat_height = MAX (nat_height, natural);
 
382
    }
 
383
 
 
384
  if (min_height_p)
 
385
    *min_height_p = min_height;
 
386
 
 
387
  if (nat_height_p)
 
388
    *nat_height_p = nat_height;
 
389
}
 
390
 
 
391
static gdouble
 
392
get_bin_alignment_factor (ClutterBinAlignment alignment)
 
393
{
 
394
  switch (alignment)
 
395
    {
 
396
    case CLUTTER_BIN_ALIGNMENT_CENTER:
 
397
      return 0.5;
 
398
 
 
399
    case CLUTTER_BIN_ALIGNMENT_START:
 
400
      return 0.0;
 
401
 
 
402
    case CLUTTER_BIN_ALIGNMENT_END:
 
403
      return 1.0;
 
404
 
 
405
    case CLUTTER_BIN_ALIGNMENT_FIXED:
 
406
    case CLUTTER_BIN_ALIGNMENT_FILL:
 
407
      return 0.0;
 
408
    }
 
409
 
 
410
  return 0.0;
 
411
}
 
412
 
 
413
static void
 
414
clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
 
415
                             ClutterContainer       *container,
 
416
                             const ClutterActorBox  *allocation,
 
417
                             ClutterAllocationFlags  flags)
 
418
{
 
419
  GList *children = clutter_container_get_children (container);
 
420
  GList *l;
 
421
  gfloat available_w, available_h;
 
422
 
 
423
  available_w = clutter_actor_box_get_width (allocation);
 
424
  available_h = clutter_actor_box_get_height (allocation);
 
425
 
 
426
  for (l = children; l != NULL; l = l->next)
 
427
    {
 
428
      ClutterActor *child = l->data;
 
429
      ClutterLayoutMeta *meta;
 
430
      ClutterBinLayer *layer;
 
431
      ClutterActorBox child_alloc = { 0, };
 
432
      gfloat child_width, child_height;
 
433
      ClutterRequestMode request;
 
434
 
 
435
      meta = clutter_layout_manager_get_child_meta (manager,
 
436
                                                    container,
 
437
                                                    child);
 
438
      layer = CLUTTER_BIN_LAYER (meta);
 
439
 
 
440
      if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL)
 
441
        {
 
442
          child_alloc.x1 = 0;
 
443
          child_alloc.x2 = ceilf (available_w);
 
444
        }
 
445
 
 
446
      if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
 
447
        {
 
448
          child_alloc.y1 = 0;
 
449
          child_alloc.y2 = ceilf (available_h);
 
450
        }
 
451
 
 
452
      /* if we are filling horizontally and vertically then we
 
453
       * can break here because we already have a full allocation
 
454
       */
 
455
      if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL &&
 
456
          layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
 
457
        {
 
458
          clutter_actor_allocate (child, &child_alloc, flags);
 
459
          continue;
 
460
        }
 
461
 
 
462
      child_width = child_height = 0;
 
463
      request = clutter_actor_get_request_mode (child);
 
464
      if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
 
465
        {
 
466
          gfloat min_width, nat_width;
 
467
          gfloat min_height, nat_height;
 
468
 
 
469
          clutter_actor_get_preferred_width (child, available_h,
 
470
                                             &min_width,
 
471
                                             &nat_width);
 
472
          child_width = CLAMP (nat_width, min_width, available_w);
 
473
 
 
474
          clutter_actor_get_preferred_height (child, child_width,
 
475
                                              &min_height,
 
476
                                              &nat_height);
 
477
          child_height = CLAMP (nat_height, min_height, available_h);
 
478
        }
 
479
      else if (request == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
 
480
        {
 
481
          gfloat min_width, nat_width;
 
482
          gfloat min_height, nat_height;
 
483
 
 
484
          clutter_actor_get_preferred_height (child, available_w,
 
485
                                              &min_height,
 
486
                                              &nat_height);
 
487
          child_height = CLAMP (nat_height, min_height, available_h);
 
488
 
 
489
          clutter_actor_get_preferred_width (child, child_height,
 
490
                                             &min_width,
 
491
                                             &nat_width);
 
492
          child_width = CLAMP (nat_width, min_width, available_w);
 
493
        }
 
494
 
 
495
      if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
 
496
        {
 
497
          child_alloc.x1 = ceilf (clutter_actor_get_x (child));
 
498
          child_alloc.x2 = ceilf (child_alloc.x1 + child_width);
 
499
        }
 
500
      else
 
501
        {
 
502
          gdouble x_align = get_bin_alignment_factor (layer->x_align);
 
503
 
 
504
          if (layer->x_align != CLUTTER_BIN_ALIGNMENT_FILL)
 
505
            {
 
506
              child_alloc.x1 = ceilf ((available_w - child_width) * x_align);
 
507
              child_alloc.x2 = ceilf (child_alloc.x1 + child_width);
 
508
            }
 
509
        }
 
510
 
 
511
      if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
 
512
        {
 
513
          child_alloc.y1 = ceilf (clutter_actor_get_y (child));
 
514
          child_alloc.y2 = ceilf (child_alloc.y1 + child_height);
 
515
        }
 
516
      else
 
517
        {
 
518
          gdouble y_align = get_bin_alignment_factor (layer->y_align);
 
519
 
 
520
          if (layer->y_align != CLUTTER_BIN_ALIGNMENT_FILL)
 
521
            {
 
522
              child_alloc.y1 = ceilf ((available_h - child_height) * y_align);
 
523
              child_alloc.y2 = ceilf (child_alloc.y1 + child_height);
 
524
            }
 
525
        }
 
526
 
 
527
      clutter_actor_allocate (child, &child_alloc, flags);
 
528
    }
 
529
 
 
530
  g_list_free (children);
 
531
}
 
532
 
 
533
static GType
 
534
clutter_bin_layout_get_child_meta_type (ClutterLayoutManager *manager)
 
535
{
 
536
  return CLUTTER_TYPE_BIN_LAYER;
 
537
}
 
538
 
 
539
static ClutterLayoutMeta *
 
540
clutter_bin_layout_create_child_meta (ClutterLayoutManager *manager,
 
541
                                      ClutterContainer     *container,
 
542
                                      ClutterActor         *actor)
 
543
{
 
544
  ClutterBinLayoutPrivate *priv;
 
545
 
 
546
  priv = CLUTTER_BIN_LAYOUT (manager)->priv;
 
547
 
 
548
  return g_object_new (CLUTTER_TYPE_BIN_LAYER,
 
549
                       "container", container,
 
550
                       "actor", actor,
 
551
                       "manager", manager,
 
552
                       "x-align", priv->x_align,
 
553
                       "y_align", priv->y_align,
 
554
                       NULL);
 
555
}
 
556
 
 
557
static void
 
558
clutter_bin_layout_set_container (ClutterLayoutManager *manager,
 
559
                                  ClutterContainer     *container)
 
560
{
 
561
  ClutterBinLayoutPrivate *priv;
 
562
 
 
563
  priv = CLUTTER_BIN_LAYOUT (manager)->priv;
 
564
  priv->container = container;
 
565
}
 
566
 
 
567
static void
 
568
clutter_bin_layout_set_property (GObject      *gobject,
 
569
                                 guint         prop_id,
 
570
                                 const GValue *value,
 
571
                                 GParamSpec   *pspec)
 
572
{
 
573
  ClutterBinLayout *layout = CLUTTER_BIN_LAYOUT (gobject);
 
574
 
 
575
  switch (prop_id)
 
576
    {
 
577
    case PROP_X_ALIGN:
 
578
      set_x_align (layout, g_value_get_enum (value));
 
579
      break;
 
580
 
 
581
    case PROP_Y_ALIGN:
 
582
      set_y_align (layout, g_value_get_enum (value));
 
583
      break;
 
584
 
 
585
    default:
 
586
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
587
      break;
 
588
    }
 
589
}
 
590
 
 
591
static void
 
592
clutter_bin_layout_get_property (GObject    *gobject,
 
593
                                 guint       prop_id,
 
594
                                 GValue     *value,
 
595
                                 GParamSpec *pspec)
 
596
{
 
597
  ClutterBinLayoutPrivate *priv;
 
598
 
 
599
  priv = CLUTTER_BIN_LAYOUT (gobject)->priv;
 
600
 
 
601
  switch (prop_id)
 
602
    {
 
603
    case PROP_X_ALIGN:
 
604
      g_value_set_enum (value, priv->x_align);
 
605
      break;
 
606
 
 
607
    case PROP_Y_ALIGN:
 
608
      g_value_set_enum (value, priv->y_align);
 
609
      break;
 
610
 
 
611
    default:
 
612
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
613
      break;
 
614
    }
 
615
}
 
616
 
 
617
static void
 
618
clutter_bin_layout_class_init (ClutterBinLayoutClass *klass)
 
619
{
 
620
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
621
  ClutterLayoutManagerClass *layout_class =
 
622
    CLUTTER_LAYOUT_MANAGER_CLASS (klass);
 
623
  GParamSpec *pspec;
 
624
 
 
625
  g_type_class_add_private (klass, sizeof (ClutterBinLayoutPrivate));
 
626
 
 
627
  gobject_class->set_property = clutter_bin_layout_set_property;
 
628
  gobject_class->get_property = clutter_bin_layout_get_property;
 
629
 
 
630
  /**
 
631
   * ClutterBinLayout:x-align:
 
632
   *
 
633
   * The default horizontal alignment policy for actors managed
 
634
   * by the #ClutterBinLayout
 
635
   *
 
636
   * Since: 1.2
 
637
   */
 
638
  pspec = g_param_spec_enum ("x-align",
 
639
                             "Horizontal Alignment",
 
640
                             "Default horizontal alignment for the actors "
 
641
                             "inside the layout manager",
 
642
                             CLUTTER_TYPE_BIN_ALIGNMENT,
 
643
                             CLUTTER_BIN_ALIGNMENT_CENTER,
 
644
                             CLUTTER_PARAM_READWRITE);
 
645
  g_object_class_install_property (gobject_class, PROP_X_ALIGN, pspec);
 
646
 
 
647
  /**
 
648
   * ClutterBinLayout:y-align:
 
649
   *
 
650
   * The default vertical alignment policy for actors managed
 
651
   * by the #ClutterBinLayout
 
652
   *
 
653
   * Since: 1.2
 
654
   */
 
655
  pspec = g_param_spec_enum ("y-align",
 
656
                             "Vertical Alignment",
 
657
                             "Default vertical alignment for the actors "
 
658
                             "inside the layout manager",
 
659
                             CLUTTER_TYPE_BIN_ALIGNMENT,
 
660
                             CLUTTER_BIN_ALIGNMENT_CENTER,
 
661
                             CLUTTER_PARAM_READWRITE);
 
662
  g_object_class_install_property (gobject_class, PROP_Y_ALIGN, pspec);
 
663
 
 
664
  layout_class->get_preferred_width =
 
665
    clutter_bin_layout_get_preferred_width;
 
666
  layout_class->get_preferred_height =
 
667
    clutter_bin_layout_get_preferred_height;
 
668
  layout_class->allocate =
 
669
    clutter_bin_layout_allocate;
 
670
  layout_class->create_child_meta =
 
671
    clutter_bin_layout_create_child_meta;
 
672
  layout_class->get_child_meta_type =
 
673
    clutter_bin_layout_get_child_meta_type;
 
674
  layout_class->set_container =
 
675
    clutter_bin_layout_set_container;
 
676
}
 
677
 
 
678
static void
 
679
clutter_bin_layout_init (ClutterBinLayout *self)
 
680
{
 
681
  self->priv = CLUTTER_BIN_LAYOUT_GET_PRIVATE (self);
 
682
 
 
683
  self->priv->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
 
684
  self->priv->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
 
685
}
 
686
 
 
687
/**
 
688
 * clutter_bin_layout_new:
 
689
 * @x_align: the default alignment policy to be used on the
 
690
 *   horizontal axis
 
691
 * @y_align: the default alignment policy to be used on the
 
692
 *   vertical axis
 
693
 *
 
694
 * Creates a new #ClutterBinLayout layout manager
 
695
 *
 
696
 * Return value: the newly created layout manager
 
697
 *
 
698
 * Since: 1.2
 
699
 */
 
700
ClutterLayoutManager *
 
701
clutter_bin_layout_new (ClutterBinAlignment x_align,
 
702
                        ClutterBinAlignment y_align)
 
703
{
 
704
  return g_object_new (CLUTTER_TYPE_BIN_LAYOUT,
 
705
                       "x-align", x_align,
 
706
                       "y-align", y_align,
 
707
                       NULL);
 
708
}
 
709
 
 
710
/**
 
711
 * clutter_bin_layout_set_alignment:
 
712
 * @self: a #ClutterBinLayout
 
713
 * @child: (allow-none): a child of @container
 
714
 * @x_align: the horizontal alignment policy to be used for the @child
 
715
 *   inside @container
 
716
 * @y_align: the vertical aligment policy to be used on the @child
 
717
 *   inside @container
 
718
 *
 
719
 * Sets the horizontal and vertical alignment policies to be applied
 
720
 * to a @child of @self
 
721
 *
 
722
 * If @child is %NULL then the @x_align and @y_align values will
 
723
 * be set as the default alignment policies
 
724
 *
 
725
 * Since: 1.2
 
726
 */
 
727
void
 
728
clutter_bin_layout_set_alignment (ClutterBinLayout    *self,
 
729
                                  ClutterActor        *child,
 
730
                                  ClutterBinAlignment  x_align,
 
731
                                  ClutterBinAlignment  y_align)
 
732
{
 
733
  ClutterBinLayoutPrivate *priv;
 
734
  ClutterLayoutManager *manager;
 
735
  ClutterLayoutMeta *meta;
 
736
 
 
737
  g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
 
738
  g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
 
739
 
 
740
  priv = self->priv;
 
741
 
 
742
  if (priv->container == NULL)
 
743
    {
 
744
      if (child == NULL)
 
745
        {
 
746
          set_x_align (self, x_align);
 
747
          set_y_align (self, y_align);
 
748
        }
 
749
      else
 
750
        g_warning ("The layout of type '%s' must be associated to "
 
751
                   "a ClutterContainer before setting the alignment "
 
752
                   "on its children",
 
753
                   G_OBJECT_TYPE_NAME (self));
 
754
 
 
755
      return;
 
756
    }
 
757
 
 
758
  manager = CLUTTER_LAYOUT_MANAGER (self);
 
759
  meta = clutter_layout_manager_get_child_meta (manager,
 
760
                                                priv->container,
 
761
                                                child);
 
762
  g_assert (CLUTTER_IS_BIN_LAYER (meta));
 
763
 
 
764
  set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
 
765
  set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
 
766
}
 
767
 
 
768
/**
 
769
 * clutter_bin_layout_get_alignment:
 
770
 * @self: a #ClutterBinLayout
 
771
 * @child: (allow-none): a child of @container
 
772
 * @x_align: (out) (allow-none): return location for the horizontal
 
773
 *   alignment policy
 
774
 * @y_align: (out) (allow-none): return location for the vertical
 
775
 *   alignment policy
 
776
 *
 
777
 * Retrieves the horizontal and vertical alignment policies for
 
778
 * a child of @self
 
779
 *
 
780
 * If @child is %NULL the default alignment policies will be returned
 
781
 * instead
 
782
 *
 
783
 * Since: 1.2
 
784
 */
 
785
void
 
786
clutter_bin_layout_get_alignment (ClutterBinLayout    *self,
 
787
                                  ClutterActor        *child,
 
788
                                  ClutterBinAlignment *x_align,
 
789
                                  ClutterBinAlignment *y_align)
 
790
{
 
791
  ClutterBinLayoutPrivate *priv;
 
792
  ClutterLayoutManager *manager;
 
793
  ClutterLayoutMeta *meta;
 
794
  ClutterBinLayer *layer;
 
795
 
 
796
  g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
 
797
 
 
798
  priv = self->priv;
 
799
 
 
800
  if (priv->container == NULL)
 
801
    {
 
802
      if (child == NULL)
 
803
        {
 
804
          if (x_align)
 
805
            *x_align = priv->x_align;
 
806
 
 
807
          if (y_align)
 
808
            *y_align = priv->y_align;
 
809
        }
 
810
      else
 
811
        g_warning ("The layout of type '%s' must be associated to "
 
812
                   "a ClutterContainer before getting the alignment "
 
813
                   "of its children",
 
814
                   G_OBJECT_TYPE_NAME (self));
 
815
 
 
816
      return;
 
817
    }
 
818
 
 
819
  manager = CLUTTER_LAYOUT_MANAGER (self);
 
820
  meta = clutter_layout_manager_get_child_meta (manager,
 
821
                                                priv->container,
 
822
                                                child);
 
823
  g_assert (CLUTTER_IS_BIN_LAYER (meta));
 
824
 
 
825
  layer = CLUTTER_BIN_LAYER (meta);
 
826
 
 
827
  if (x_align)
 
828
    *x_align = layer->x_align;
 
829
 
 
830
  if (y_align)
 
831
    *y_align = layer->y_align;
 
832
}
 
833
 
 
834
/**
 
835
 * clutter_bin_layout_add:
 
836
 * @self: a #ClutterBinLayout
 
837
 * @child: a #ClutterActor
 
838
 * @x_align: horizontal alignment policy for @child
 
839
 * @y_align: vertical alignment policy for @child
 
840
 *
 
841
 * Adds a #ClutterActor to the container using @self and
 
842
 * sets the alignment policies for it
 
843
 *
 
844
 * This function is equivalent to clutter_container_add_actor()
 
845
 * and clutter_layout_manager_child_set_property() but it does not
 
846
 * require a pointer to the #ClutterContainer associated to the
 
847
 * #ClutterBinLayout
 
848
 *
 
849
 * Since: 1.2
 
850
 */
 
851
void
 
852
clutter_bin_layout_add (ClutterBinLayout    *self,
 
853
                        ClutterActor        *child,
 
854
                        ClutterBinAlignment  x_align,
 
855
                        ClutterBinAlignment  y_align)
 
856
{
 
857
  ClutterBinLayoutPrivate *priv;
 
858
  ClutterLayoutManager *manager;
 
859
  ClutterLayoutMeta *meta;
 
860
 
 
861
  g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
 
862
  g_return_if_fail (CLUTTER_IS_ACTOR (child));
 
863
 
 
864
  priv = self->priv;
 
865
 
 
866
  if (priv->container == NULL)
 
867
    {
 
868
      g_warning ("The layout of type '%s' must be associated to "
 
869
                 "a ClutterContainer before adding children",
 
870
                 G_OBJECT_TYPE_NAME (self));
 
871
      return;
 
872
    }
 
873
 
 
874
  clutter_container_add_actor (priv->container, child);
 
875
 
 
876
  manager = CLUTTER_LAYOUT_MANAGER (self);
 
877
  meta = clutter_layout_manager_get_child_meta (manager,
 
878
                                                priv->container,
 
879
                                                child);
 
880
  g_assert (CLUTTER_IS_BIN_LAYER (meta));
 
881
 
 
882
  set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
 
883
  set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
 
884
}