clutter-bin-layout.c 24.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * Clutter.
 *
 * An OpenGL based 'interactive canvas' library.
 *
 * Copyright (C) 2009  Intel Corporation.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author:
 *   Emmanuele Bassi <ebassi@linux.intel.com>
 */

/**
 * SECTION:clutter-bin-layout
 * @short_description: A simple layout manager
 *
 * #ClutterBinLayout is a layout manager which implements the following
 * policy:
 *
Emmanuele Bassi's avatar
Emmanuele Bassi committed
32
 *   - the preferred size is the maximum preferred size
33
 *   between all the children of the container using the
Emmanuele Bassi's avatar
Emmanuele Bassi committed
34 35 36 37 38
 *   layout;
 *   - each child is allocated in "layers", on on top
 *   of the other;
 *   - for each layer there are horizontal and vertical
 *   alignment policies.
39
 *
Emmanuele Bassi's avatar
Emmanuele Bassi committed
40 41
 * The [bin-layout example](https://git.gnome.org/browse/clutter/tree/examples/bin-layout.c?h=clutter-1.18)
 * shows how to pack actors inside a #ClutterBinLayout.
42 43 44 45
 *
 * #ClutterBinLayout is available since Clutter 1.2
 */

Emmanuele Bassi's avatar
Emmanuele Bassi committed
46
#ifdef HAVE_CONFIG_H
47
#include "clutter-build-config.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
48 49
#endif

50 51
#include <math.h>

52 53
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "deprecated/clutter-container.h"
54
#include "deprecated/clutter-bin-layout.h"
55

56
#include "clutter-actor-private.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
57
#include "clutter-animatable.h"
58
#include "clutter-child-meta.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
59 60
#include "clutter-debug.h"
#include "clutter-enum-types.h"
61
#include "clutter-layout-meta.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
62 63
#include "clutter-private.h"

64 65 66 67 68
#define CLUTTER_TYPE_BIN_LAYER          (clutter_bin_layer_get_type ())
#define CLUTTER_BIN_LAYER(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYER, ClutterBinLayer))
#define CLUTTER_IS_BIN_LAYER(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYER))

typedef struct _ClutterBinLayer         ClutterBinLayer;
69
typedef struct _ClutterLayoutMetaClass  ClutterBinLayerClass;
70

Emmanuele Bassi's avatar
Emmanuele Bassi committed
71 72 73 74 75
struct _ClutterBinLayoutPrivate
{
  ClutterBinAlignment x_align;
  ClutterBinAlignment y_align;

76
  ClutterContainer *container;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
77 78
};

79 80
struct _ClutterBinLayer
{
81
  ClutterLayoutMeta parent_instance;
82 83 84 85 86 87 88 89 90 91

  ClutterBinAlignment x_align;
  ClutterBinAlignment y_align;
};

enum
{
  PROP_LAYER_0,

  PROP_LAYER_X_ALIGN,
92 93 94
  PROP_LAYER_Y_ALIGN,

  PROP_LAYER_LAST
95 96
};

Emmanuele Bassi's avatar
Emmanuele Bassi committed
97 98 99 100 101
enum
{
  PROP_0,

  PROP_X_ALIGN,
102 103 104
  PROP_Y_ALIGN,

  PROP_LAST
Emmanuele Bassi's avatar
Emmanuele Bassi committed
105 106
};

107 108
static GParamSpec *layer_props[PROP_LAYER_LAST] = { NULL, };
static GParamSpec *bin_props[PROP_LAST] = { NULL, };
109

110 111
GType clutter_bin_layer_get_type (void);

112 113
G_DEFINE_TYPE (ClutterBinLayer,
               clutter_bin_layer,
114
               CLUTTER_TYPE_LAYOUT_META)
115

116 117 118
G_DEFINE_TYPE_WITH_PRIVATE (ClutterBinLayout,
                            clutter_bin_layout,
                            CLUTTER_TYPE_LAYOUT_MANAGER)
Emmanuele Bassi's avatar
Emmanuele Bassi committed
119

120 121 122 123 124 125 126 127 128
/*
 * ClutterBinLayer
 */

static void
set_layer_x_align (ClutterBinLayer     *self,
                   ClutterBinAlignment  alignment)
{
  ClutterLayoutManager *manager;
129
  ClutterLayoutMeta *meta;
130 131 132 133 134 135

  if (self->x_align == alignment)
    return;

  self->x_align = alignment;

136 137
  meta = CLUTTER_LAYOUT_META (self);
  manager = clutter_layout_meta_get_manager (meta);
138 139
  clutter_layout_manager_layout_changed (manager);

140
  g_object_notify_by_pspec (G_OBJECT (self), layer_props[PROP_LAYER_X_ALIGN]);
141 142 143 144 145 146 147
}

static void
set_layer_y_align (ClutterBinLayer     *self,
                   ClutterBinAlignment  alignment)
{
  ClutterLayoutManager *manager;
148
  ClutterLayoutMeta *meta;
149 150 151 152 153 154

  if (self->y_align == alignment)
    return;

  self->y_align = alignment;

155 156
  meta = CLUTTER_LAYOUT_META (self);
  manager = clutter_layout_meta_get_manager (meta);
157 158
  clutter_layout_manager_layout_changed (manager);

159
  g_object_notify_by_pspec (G_OBJECT (self), layer_props[PROP_LAYER_Y_ALIGN]);
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
}

static void
clutter_bin_layer_set_property (GObject      *gobject,
                                guint         prop_id,
                                const GValue *value,
                                GParamSpec   *pspec)
{
  ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);

  switch (prop_id)
    {
    case PROP_LAYER_X_ALIGN:
      set_layer_x_align (layer, g_value_get_enum (value));
      break;

    case PROP_LAYER_Y_ALIGN:
      set_layer_y_align (layer, g_value_get_enum (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}

static void
clutter_bin_layer_get_property (GObject    *gobject,
                                guint       prop_id,
                                GValue     *value,
                                GParamSpec *pspec)
{
  ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);

  switch (prop_id)
    {
    case PROP_LAYER_X_ALIGN:
      g_value_set_enum (value, layer->x_align);
      break;

    case PROP_LAYER_Y_ALIGN:
      g_value_set_enum (value, layer->y_align);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}

static void
clutter_bin_layer_class_init (ClutterBinLayerClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->set_property = clutter_bin_layer_set_property;
  gobject_class->get_property = clutter_bin_layer_get_property;

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
  layer_props[PROP_LAYER_X_ALIGN] =
    g_param_spec_enum ("x-align",
                       P_("Horizontal Alignment"),
                       P_("Horizontal alignment for the actor "
                          "inside the layout manager"),
                       CLUTTER_TYPE_BIN_ALIGNMENT,
                       CLUTTER_BIN_ALIGNMENT_CENTER,
                       CLUTTER_PARAM_READWRITE);

  layer_props[PROP_LAYER_Y_ALIGN] =
    g_param_spec_enum ("y-align",
                       P_("Vertical Alignment"),
                       P_("Vertical alignment for the actor "
                          "inside the layout manager"),
                       CLUTTER_TYPE_BIN_ALIGNMENT,
                       CLUTTER_BIN_ALIGNMENT_CENTER,
                       CLUTTER_PARAM_READWRITE);

236 237 238
  g_object_class_install_properties (gobject_class,
                                     PROP_LAYER_LAST,
                                     layer_props);
239 240 241 242 243 244 245 246 247 248 249 250 251
}

static void
clutter_bin_layer_init (ClutterBinLayer *layer)
{
  layer->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
  layer->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
}

/*
 * ClutterBinLayout
 */

Emmanuele Bassi's avatar
Emmanuele Bassi committed
252 253 254 255 256 257 258 259
static void
set_x_align (ClutterBinLayout    *self,
             ClutterBinAlignment  alignment)
{
  ClutterBinLayoutPrivate *priv = self->priv;

  if (priv->x_align != alignment)
    {
260 261
      ClutterLayoutManager *manager;

Emmanuele Bassi's avatar
Emmanuele Bassi committed
262 263
      priv->x_align = alignment;

264 265 266
      manager = CLUTTER_LAYOUT_MANAGER (self);
      clutter_layout_manager_layout_changed (manager);

267
      g_object_notify_by_pspec (G_OBJECT (self), bin_props[PROP_X_ALIGN]);
Emmanuele Bassi's avatar
Emmanuele Bassi committed
268 269 270 271 272 273 274 275 276 277 278
    }
}

static void
set_y_align (ClutterBinLayout    *self,
             ClutterBinAlignment  alignment)
{
  ClutterBinLayoutPrivate *priv = self->priv;

  if (priv->y_align != alignment)
    {
279 280
      ClutterLayoutManager *manager;

Emmanuele Bassi's avatar
Emmanuele Bassi committed
281 282
      priv->y_align = alignment;

283 284 285
      manager = CLUTTER_LAYOUT_MANAGER (self);
      clutter_layout_manager_layout_changed (manager);

286
      g_object_notify_by_pspec (G_OBJECT (self), bin_props[PROP_Y_ALIGN]);
Emmanuele Bassi's avatar
Emmanuele Bassi committed
287 288 289 290 291 292 293 294 295 296
    }
}

static void
clutter_bin_layout_get_preferred_width (ClutterLayoutManager *manager,
                                        ClutterContainer     *container,
                                        gfloat                for_height,
                                        gfloat               *min_width_p,
                                        gfloat               *nat_width_p)
{
297
  ClutterActor *actor = CLUTTER_ACTOR (container);
298
  ClutterActorIter iter;
299
  ClutterActor *child;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
300 301 302 303
  gfloat min_width, nat_width;

  min_width = nat_width = 0.0;

304 305
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
Emmanuele Bassi's avatar
Emmanuele Bassi committed
306 307 308
    {
      gfloat minimum, natural;

309
      if (!clutter_actor_is_visible (child))
310 311
        continue;

Emmanuele Bassi's avatar
Emmanuele Bassi committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
      clutter_actor_get_preferred_width (child, for_height,
                                         &minimum,
                                         &natural);

      min_width = MAX (min_width, minimum);
      nat_width = MAX (nat_width, natural);
    }

  if (min_width_p)
    *min_width_p = min_width;

  if (nat_width_p)
    *nat_width_p = nat_width;
}

static void
clutter_bin_layout_get_preferred_height (ClutterLayoutManager *manager,
                                         ClutterContainer     *container,
                                         gfloat                for_width,
                                         gfloat               *min_height_p,
                                         gfloat               *nat_height_p)
{
334
  ClutterActor *actor = CLUTTER_ACTOR (container);
335
  ClutterActorIter iter;
336
  ClutterActor *child;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
337 338 339 340
  gfloat min_height, nat_height;

  min_height = nat_height = 0.0;

341 342
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
Emmanuele Bassi's avatar
Emmanuele Bassi committed
343 344 345
    {
      gfloat minimum, natural;

346
      if (!clutter_actor_is_visible (child))
347 348
        continue;

Emmanuele Bassi's avatar
Emmanuele Bassi committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
      clutter_actor_get_preferred_height (child, for_width,
                                          &minimum,
                                          &natural);

      min_height = MAX (min_height, minimum);
      nat_height = MAX (nat_height, natural);
    }

  if (min_height_p)
    *min_height_p = min_height;

  if (nat_height_p)
    *nat_height_p = nat_height;
}

static gdouble
365 366
get_bin_alignment_factor (ClutterBinAlignment alignment,
                          ClutterTextDirection text_dir)
Emmanuele Bassi's avatar
Emmanuele Bassi committed
367 368 369 370 371 372 373
{
  switch (alignment)
    {
    case CLUTTER_BIN_ALIGNMENT_CENTER:
      return 0.5;

    case CLUTTER_BIN_ALIGNMENT_START:
374
      return text_dir == CLUTTER_TEXT_DIRECTION_LTR ? 0.0 : 1.0;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
375 376

    case CLUTTER_BIN_ALIGNMENT_END:
377
      return text_dir == CLUTTER_TEXT_DIRECTION_LTR ? 1.0 : 0.0;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
378 379 380 381 382 383 384 385 386

    case CLUTTER_BIN_ALIGNMENT_FIXED:
    case CLUTTER_BIN_ALIGNMENT_FILL:
      return 0.0;
    }

  return 0.0;
}

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
static gdouble
get_actor_align_factor (ClutterActorAlign alignment)
{
  switch (alignment)
    {
    case CLUTTER_ACTOR_ALIGN_CENTER:
      return 0.5;

    case CLUTTER_ACTOR_ALIGN_START:
      return 0.0;

    case CLUTTER_ACTOR_ALIGN_END:
      return 1.0;

    case CLUTTER_ACTOR_ALIGN_FILL:
      return 0.0;
    }

  return 0.0;
}

Emmanuele Bassi's avatar
Emmanuele Bassi committed
408 409 410 411 412 413
static void
clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
                             ClutterContainer       *container,
                             const ClutterActorBox  *allocation,
                             ClutterAllocationFlags  flags)
{
414
  gfloat allocation_x, allocation_y;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
415
  gfloat available_w, available_h;
416
  ClutterActor *actor, *child;
417
  ClutterActorIter iter;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
418

419 420
  clutter_actor_box_get_origin (allocation, &allocation_x, &allocation_y);
  clutter_actor_box_get_size (allocation, &available_w, &available_h);
Emmanuele Bassi's avatar
Emmanuele Bassi committed
421

422 423
  actor = CLUTTER_ACTOR (container);

424 425
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
Emmanuele Bassi's avatar
Emmanuele Bassi committed
426
    {
427
      ClutterLayoutMeta *meta;
428
      ClutterBinLayer *layer;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
429
      ClutterActorBox child_alloc = { 0, };
430
      gdouble x_align, y_align;
431 432
      gboolean x_fill, y_fill, is_fixed_position_set;
      float fixed_x, fixed_y;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
433

434
      if (!clutter_actor_is_visible (child))
435 436
        continue;

437 438 439 440 441
      meta = clutter_layout_manager_get_child_meta (manager,
                                                    container,
                                                    child);
      layer = CLUTTER_BIN_LAYER (meta);

442 443 444 445 446 447 448 449 450 451 452 453
      fixed_x = fixed_y = 0.f;
      g_object_get (child,
                    "fixed-position-set", &is_fixed_position_set,
                    "fixed-x", &fixed_x,
                    "fixed-y", &fixed_y,
                    NULL);

      /* XXX:2.0 - remove the FIXED alignment, and just use the fixed position
       * of the actor if one is set
       */
      if (is_fixed_position_set ||
          layer->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
454
	{
455 456 457 458
          if (is_fixed_position_set)
            child_alloc.x1 = fixed_x;
          else
            child_alloc.x1 = clutter_actor_get_x (child);
459
	}
Emmanuele Bassi's avatar
Emmanuele Bassi committed
460
      else
461
        child_alloc.x1 = allocation_x;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
462

463 464
      if (is_fixed_position_set ||
          layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
465
	{
466 467 468
	  if (is_fixed_position_set)
            child_alloc.y1 = fixed_y;
          else
469 470
	    child_alloc.y1 = clutter_actor_get_y (child);
	}
Emmanuele Bassi's avatar
Emmanuele Bassi committed
471
      else
472
        child_alloc.y1 = allocation_y;
473

474 475
      child_alloc.x2 = allocation_x + available_w;
      child_alloc.y2 = allocation_y + available_h;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
476

477
      if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL))
478 479 480
        {
          ClutterActorAlign align;

481
          align = clutter_actor_get_x_align (child);
482 483 484 485 486
          x_fill = align == CLUTTER_ACTOR_ALIGN_FILL;
          x_align = get_actor_align_factor (align);
        }
      else
        {
487 488
          ClutterTextDirection text_dir;

489
          x_fill = (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL);
490

491 492
          text_dir = clutter_actor_get_text_direction (child);

493
          if (!is_fixed_position_set)
494
            x_align = get_bin_alignment_factor (layer->x_align, text_dir);
495 496
          else
            x_align = 0.0;
497 498
        }

499
      if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL))
500 501 502 503 504 505 506 507 508 509
        {
          ClutterActorAlign align;

          align = clutter_actor_get_y_align (child);
          y_fill = align == CLUTTER_ACTOR_ALIGN_FILL;
          y_align = get_actor_align_factor (align);
        }
      else
        {
          y_fill = (layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL);
510 511

          if (!is_fixed_position_set)
512 513
            y_align = get_bin_alignment_factor (layer->y_align,
                                                CLUTTER_TEXT_DIRECTION_LTR);
514 515
          else
            y_align = 0.0;
516
        }
Emmanuele Bassi's avatar
Emmanuele Bassi committed
517

518 519 520 521
      clutter_actor_allocate_align_fill (child, &child_alloc,
                                         x_align, y_align,
                                         x_fill, y_fill,
                                         flags);
Emmanuele Bassi's avatar
Emmanuele Bassi committed
522 523 524
    }
}

525 526 527 528 529 530
static GType
clutter_bin_layout_get_child_meta_type (ClutterLayoutManager *manager)
{
  return CLUTTER_TYPE_BIN_LAYER;
}

531
static ClutterLayoutMeta *
532 533 534 535 536 537 538 539
clutter_bin_layout_create_child_meta (ClutterLayoutManager *manager,
                                      ClutterContainer     *container,
                                      ClutterActor         *actor)
{
  ClutterBinLayoutPrivate *priv;

  priv = CLUTTER_BIN_LAYOUT (manager)->priv;

540
  return g_object_new (CLUTTER_TYPE_BIN_LAYER,
541 542
                       "container", container,
                       "actor", actor,
543
                       "manager", manager,
544 545 546 547 548
                       "x-align", priv->x_align,
                       "y_align", priv->y_align,
                       NULL);
}

549 550 551 552 553
static void
clutter_bin_layout_set_container (ClutterLayoutManager *manager,
                                  ClutterContainer     *container)
{
  ClutterBinLayoutPrivate *priv;
554
  ClutterLayoutManagerClass *parent_class;
555 556 557

  priv = CLUTTER_BIN_LAYOUT (manager)->priv;
  priv->container = container;
558 559 560

  parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_bin_layout_parent_class);
  parent_class->set_container (manager, container);
561 562
}

Emmanuele Bassi's avatar
Emmanuele Bassi committed
563 564 565 566 567 568
static void
clutter_bin_layout_set_property (GObject      *gobject,
                                 guint         prop_id,
                                 const GValue *value,
                                 GParamSpec   *pspec)
{
569 570
  ClutterBinLayout *layout = CLUTTER_BIN_LAYOUT (gobject);

Emmanuele Bassi's avatar
Emmanuele Bassi committed
571 572 573
  switch (prop_id)
    {
    case PROP_X_ALIGN:
574
      set_x_align (layout, g_value_get_enum (value));
Emmanuele Bassi's avatar
Emmanuele Bassi committed
575 576 577
      break;

    case PROP_Y_ALIGN:
578
      set_y_align (layout, g_value_get_enum (value));
Emmanuele Bassi's avatar
Emmanuele Bassi committed
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}

static void
clutter_bin_layout_get_property (GObject    *gobject,
                                 guint       prop_id,
                                 GValue     *value,
                                 GParamSpec *pspec)
{
  ClutterBinLayoutPrivate *priv;

  priv = CLUTTER_BIN_LAYOUT (gobject)->priv;

  switch (prop_id)
    {
    case PROP_X_ALIGN:
      g_value_set_enum (value, priv->x_align);
      break;

    case PROP_Y_ALIGN:
      g_value_set_enum (value, priv->y_align);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}

static void
clutter_bin_layout_class_init (ClutterBinLayoutClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  ClutterLayoutManagerClass *layout_class =
    CLUTTER_LAYOUT_MANAGER_CLASS (klass);

620 621 622
  /**
   * ClutterBinLayout:x-align:
   *
623 624
   * The default horizontal alignment policy for actors managed
   * by the #ClutterBinLayout
625 626
   *
   * Since: 1.2
627 628 629
   *
   * Deprecated: 1.12: Use the #ClutterActor:x-expand and the
   *   #ClutterActor:x-align properties on #ClutterActor instead.
630
   */
631 632 633 634 635 636 637 638
  bin_props[PROP_X_ALIGN] =
    g_param_spec_enum ("x-align",
                       P_("Horizontal Alignment"),
                       P_("Default horizontal alignment for the actors "
                          "inside the layout manager"),
                       CLUTTER_TYPE_BIN_ALIGNMENT,
                       CLUTTER_BIN_ALIGNMENT_CENTER,
                       CLUTTER_PARAM_READWRITE);
Emmanuele Bassi's avatar
Emmanuele Bassi committed
639

640 641 642
  /**
   * ClutterBinLayout:y-align:
   *
643 644
   * The default vertical alignment policy for actors managed
   * by the #ClutterBinLayout
645 646
   *
   * Since: 1.2
647 648 649
   *
   * Deprecated: 1.12: Use the #ClutterActor:y-expand and the
   *   #ClutterActor:y-align properties on #ClutterActor instead.
650
   */
651 652 653 654 655 656 657 658 659 660 661
  bin_props[PROP_Y_ALIGN] =
    g_param_spec_enum ("y-align",
                       P_("Vertical Alignment"),
                       P_("Default vertical alignment for the actors "
                          "inside the layout manager"),
                       CLUTTER_TYPE_BIN_ALIGNMENT,
                       CLUTTER_BIN_ALIGNMENT_CENTER,
                       CLUTTER_PARAM_READWRITE);

  gobject_class->set_property = clutter_bin_layout_set_property;
  gobject_class->get_property = clutter_bin_layout_get_property;
662 663 664 665 666 667 668 669
  g_object_class_install_properties (gobject_class, PROP_LAST, bin_props);

  layout_class->get_preferred_width = clutter_bin_layout_get_preferred_width;
  layout_class->get_preferred_height = clutter_bin_layout_get_preferred_height;
  layout_class->allocate = clutter_bin_layout_allocate;
  layout_class->create_child_meta = clutter_bin_layout_create_child_meta;
  layout_class->get_child_meta_type = clutter_bin_layout_get_child_meta_type;
  layout_class->set_container = clutter_bin_layout_set_container;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
670 671 672 673 674
}

static void
clutter_bin_layout_init (ClutterBinLayout *self)
{
675
  self->priv = clutter_bin_layout_get_instance_private (self);
Emmanuele Bassi's avatar
Emmanuele Bassi committed
676 677 678 679 680

  self->priv->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
  self->priv->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
}

681 682
/**
 * clutter_bin_layout_new:
683
 * @x_align: the default alignment policy to be used on the
684
 *   horizontal axis
685
 * @y_align: the default alignment policy to be used on the
686 687 688 689 690 691 692 693
 *   vertical axis
 *
 * Creates a new #ClutterBinLayout layout manager
 *
 * Return value: the newly created layout manager
 *
 * Since: 1.2
 */
Emmanuele Bassi's avatar
Emmanuele Bassi committed
694 695 696 697 698 699 700 701 702 703
ClutterLayoutManager *
clutter_bin_layout_new (ClutterBinAlignment x_align,
                        ClutterBinAlignment y_align)
{
  return g_object_new (CLUTTER_TYPE_BIN_LAYOUT,
                       "x-align", x_align,
                       "y-align", y_align,
                       NULL);
}

704 705 706
/**
 * clutter_bin_layout_set_alignment:
 * @self: a #ClutterBinLayout
707
 * @child: (allow-none): a child of @container
708 709 710 711
 * @x_align: the horizontal alignment policy to be used for the @child
 *   inside @container
 * @y_align: the vertical aligment policy to be used on the @child
 *   inside @container
712
 *
713
 * Sets the horizontal and vertical alignment policies to be applied
714 715 716 717
 * to a @child of @self
 *
 * If @child is %NULL then the @x_align and @y_align values will
 * be set as the default alignment policies
718 719
 *
 * Since: 1.2
720 721 722
 *
 * Deprecated: 1.12: Use the #ClutterActor:x-align and
 *   #ClutterActor:y-align properties of #ClutterActor instead.
723
 */
Emmanuele Bassi's avatar
Emmanuele Bassi committed
724 725
void
clutter_bin_layout_set_alignment (ClutterBinLayout    *self,
726
                                  ClutterActor        *child,
Emmanuele Bassi's avatar
Emmanuele Bassi committed
727 728 729
                                  ClutterBinAlignment  x_align,
                                  ClutterBinAlignment  y_align)
{
730
  ClutterBinLayoutPrivate *priv;
731
  ClutterLayoutManager *manager;
732
  ClutterLayoutMeta *meta;
733

Emmanuele Bassi's avatar
Emmanuele Bassi committed
734
  g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
735
  g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
Emmanuele Bassi's avatar
Emmanuele Bassi committed
736

737 738
  priv = self->priv;

739
  if (priv->container == NULL)
740
    {
741 742 743 744 745 746 747 748 749 750
      if (child == NULL)
        {
          set_x_align (self, x_align);
          set_y_align (self, y_align);
        }
      else
        g_warning ("The layout of type '%s' must be associated to "
                   "a ClutterContainer before setting the alignment "
                   "on its children",
                   G_OBJECT_TYPE_NAME (self));
751 752 753 754

      return;
    }

755
  manager = CLUTTER_LAYOUT_MANAGER (self);
756 757 758
  meta = clutter_layout_manager_get_child_meta (manager,
                                                priv->container,
                                                child);
759
  g_assert (CLUTTER_IS_BIN_LAYER (meta));
760

761 762
  set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
  set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
Emmanuele Bassi's avatar
Emmanuele Bassi committed
763 764
}

765 766 767
/**
 * clutter_bin_layout_get_alignment:
 * @self: a #ClutterBinLayout
768
 * @child: (allow-none): a child of @container
769 770 771 772 773
 * @x_align: (out) (allow-none): return location for the horizontal
 *   alignment policy
 * @y_align: (out) (allow-none): return location for the vertical
 *   alignment policy
 *
774 775 776 777 778
 * Retrieves the horizontal and vertical alignment policies for
 * a child of @self
 *
 * If @child is %NULL the default alignment policies will be returned
 * instead
779 780
 *
 * Since: 1.2
781 782 783
 *
 * Deprecated: 1.12: Use the #ClutterActor:x-align and the
 *   #ClutterActor:y-align properties of #ClutterActor instead.
784
 */
Emmanuele Bassi's avatar
Emmanuele Bassi committed
785 786
void
clutter_bin_layout_get_alignment (ClutterBinLayout    *self,
787
                                  ClutterActor        *child,
Emmanuele Bassi's avatar
Emmanuele Bassi committed
788 789 790
                                  ClutterBinAlignment *x_align,
                                  ClutterBinAlignment *y_align)
{
791
  ClutterBinLayoutPrivate *priv;
792
  ClutterLayoutManager *manager;
793
  ClutterLayoutMeta *meta;
794 795
  ClutterBinLayer *layer;

Emmanuele Bassi's avatar
Emmanuele Bassi committed
796 797
  g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));

798 799
  priv = self->priv;

800
  if (priv->container == NULL)
801
    {
802 803 804 805
      if (child == NULL)
        {
          if (x_align)
            *x_align = priv->x_align;
806

807 808 809 810 811 812 813 814
          if (y_align)
            *y_align = priv->y_align;
        }
      else
        g_warning ("The layout of type '%s' must be associated to "
                   "a ClutterContainer before getting the alignment "
                   "of its children",
                   G_OBJECT_TYPE_NAME (self));
815 816 817 818

      return;
    }

819
  manager = CLUTTER_LAYOUT_MANAGER (self);
820 821 822
  meta = clutter_layout_manager_get_child_meta (manager,
                                                priv->container,
                                                child);
823
  g_assert (CLUTTER_IS_BIN_LAYER (meta));
824 825 826

  layer = CLUTTER_BIN_LAYER (meta);

Emmanuele Bassi's avatar
Emmanuele Bassi committed
827
  if (x_align)
828
    *x_align = layer->x_align;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
829 830

  if (y_align)
831
    *y_align = layer->y_align;
Emmanuele Bassi's avatar
Emmanuele Bassi committed
832
}
833 834 835 836 837 838 839 840 841 842 843 844

/**
 * clutter_bin_layout_add:
 * @self: a #ClutterBinLayout
 * @child: a #ClutterActor
 * @x_align: horizontal alignment policy for @child
 * @y_align: vertical alignment policy for @child
 *
 * Adds a #ClutterActor to the container using @self and
 * sets the alignment policies for it
 *
 * This function is equivalent to clutter_container_add_actor()
845 846 847
 * and clutter_layout_manager_child_set_property() but it does not
 * require a pointer to the #ClutterContainer associated to the
 * #ClutterBinLayout
848 849
 *
 * Since: 1.2
850 851
 *
 * Deprecated: 1.12: Use clutter_actor_add_child() instead.
852 853 854 855 856 857 858 859
 */
void
clutter_bin_layout_add (ClutterBinLayout    *self,
                        ClutterActor        *child,
                        ClutterBinAlignment  x_align,
                        ClutterBinAlignment  y_align)
{
  ClutterBinLayoutPrivate *priv;
860 861
  ClutterLayoutManager *manager;
  ClutterLayoutMeta *meta;
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883

  g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
  g_return_if_fail (CLUTTER_IS_ACTOR (child));

  priv = self->priv;

  if (priv->container == NULL)
    {
      g_warning ("The layout of type '%s' must be associated to "
                 "a ClutterContainer before adding children",
                 G_OBJECT_TYPE_NAME (self));
      return;
    }

  clutter_container_add_actor (priv->container, child);

  manager = CLUTTER_LAYOUT_MANAGER (self);
  meta = clutter_layout_manager_get_child_meta (manager,
                                                priv->container,
                                                child);
  g_assert (CLUTTER_IS_BIN_LAYER (meta));

884 885
  set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
  set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
886
}