Exemplo n.º 1
0
/**
 * clutter_table_layout_get_span:
 * @layout: a #ClutterTableLayout
 * @actor: a #ClutterActor child of @layout
 * @column_span: (out): return location for the col span
 * @row_span: (out): return location for the row span
 *
 * Retrieves the row and column span for @actor as set using
 * clutter_table_layout_pack() or clutter_table_layout_set_span()
 *
 *
 */
void
clutter_table_layout_get_span (ClutterTableLayout *layout,
                               ClutterActor       *actor,
                               gint               *column_span,
                               gint               *row_span)
{
  ClutterTableLayoutPrivate *priv;
  ClutterLayoutManager *manager;
  ClutterLayoutMeta *meta;

  g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout));
  g_return_if_fail (CLUTTER_IS_ACTOR (actor));

  priv = layout->priv;

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

  manager = CLUTTER_LAYOUT_MANAGER (layout);
  meta = clutter_layout_manager_get_child_meta (manager,
                                                priv->container,
                                                actor);
  if (meta == NULL)
    {
      g_warning ("No layout meta found for the child of type '%s' "
                 "inside the layout manager of type '%s'",
                 G_OBJECT_TYPE_NAME (actor),
                 G_OBJECT_TYPE_NAME (manager));
      return;
    }

  g_assert (CLUTTER_IS_TABLE_CHILD (meta));

  if (column_span)
    *column_span = CLUTTER_TABLE_CHILD (meta)->col_span;

  if (row_span)
    *row_span = CLUTTER_TABLE_CHILD (meta)->row_span;
}
Exemplo n.º 2
0
static void
changed_cb (ClutterActor *actor,
            GParamSpec   *pspec,
            ClutterActor *text)
{
  ClutterActorAlign x_align, y_align;
  ClutterActor *box;
  ClutterLayoutManager *layout;
  ClutterLayoutMeta *meta;
  gboolean x_expand, y_expand;
  gchar *label;
  gint left, top, width, height;

  box = clutter_actor_get_parent (actor);
  layout = clutter_actor_get_layout_manager (box);
  meta = clutter_layout_manager_get_child_meta (layout,
                                                CLUTTER_CONTAINER (box),
                                                actor);

  g_object_get (actor,
                "x-align", &x_align,
                "y-align", &y_align,
                "x-expand", &x_expand,
                "y-expand", &y_expand,
                NULL);

  g_object_get (meta,
                "left-attach", &left,
                "top-attach", &top,
                "width", &width,
                "height", &height,
                NULL);

  label = g_strdup_printf ("attach: %d,%d\n"
                           "span: %d,%d\n"
                           "expand: %d,%d\n"
                           "align: %s,%s",
                           left, top, width, height,
                           x_expand, y_expand,
                           get_align_name (x_align),
                           get_align_name (y_align));
  clutter_text_set_text (CLUTTER_TEXT (text), label);
  g_free (label);
}
Exemplo n.º 3
0
/**
 * clutter_table_layout_pack:
 * @layout: a #ClutterTableLayout
 * @actor: a #ClutterActor
 * @column: the column the @actor should be put, or -1 to append
 * @row: the row the @actor should be put, or -1 to append
 *
 * Packs @actor inside the #ClutterContainer associated to @layout
 * at the given row and column.
 *
 *
 */
void
clutter_table_layout_pack (ClutterTableLayout  *layout,
                           ClutterActor        *actor,
                           gint                 column,
                           gint                 row)
{
  ClutterTableLayoutPrivate *priv;
  ClutterLayoutManager *manager;
  ClutterLayoutMeta *meta;

  g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout));
  g_return_if_fail (CLUTTER_IS_ACTOR (actor));

  priv = layout->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 (layout));
      return;
    }

  update_row_col (CLUTTER_TABLE_LAYOUT (layout), priv->container);

  clutter_actor_add_child (CLUTTER_ACTOR (priv->container), actor);

  manager = CLUTTER_LAYOUT_MANAGER (layout);
  meta = clutter_layout_manager_get_child_meta (manager,
                                                priv->container,
                                                actor);
  g_assert (CLUTTER_IS_TABLE_CHILD (meta));

  if (row < 0)
    row = priv->n_rows;

  if (column < 0)
    column = priv->n_cols;

  table_child_set_position (CLUTTER_TABLE_CHILD (meta), column, row);
}
Exemplo n.º 4
0
/**
 * clutter_bin_layout_set_alignment:
 * @self: a #ClutterBinLayout
 * @child: (allow-none): a child of @container
 * @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
 *
 * Sets the horizontal and vertical alignment policies to be applied
 * 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
 *
 * Since: 1.2
 */
void
clutter_bin_layout_set_alignment (ClutterBinLayout    *self,
                                  ClutterActor        *child,
                                  ClutterBinAlignment  x_align,
                                  ClutterBinAlignment  y_align)
{
  ClutterBinLayoutPrivate *priv;
  ClutterLayoutManager *manager;
  ClutterLayoutMeta *meta;

  g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
  g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));

  priv = self->priv;

  if (priv->container == NULL)
    {
      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));

      return;
    }

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

  set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align);
  set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align);
}
Exemplo n.º 5
0
static inline void
clutter_box_set_property_valist (ClutterBox   *box,
                                 ClutterActor *actor,
                                 const gchar  *first_property,
                                 va_list       var_args)
{
  ClutterContainer *container = CLUTTER_CONTAINER (box);
  ClutterBoxPrivate *priv = box->priv;
  ClutterLayoutMeta *meta;
  GObjectClass *klass;
  const gchar *pname;

  if (priv->manager == NULL)
    return;

  meta = clutter_layout_manager_get_child_meta (priv->manager,
                                                container,
                                                actor);

  if (meta == NULL)
    return;

  klass = G_OBJECT_GET_CLASS (meta);

  pname = first_property;
  while (pname)
    {
      GValue value = { 0, };
      GParamSpec *pspec;
      gchar *error;

      pspec = g_object_class_find_property (klass, pname);
      if (pspec == NULL)
        {
          g_warning ("%s: the layout property '%s' for managers "
                     "of type '%s' (meta type '%s') does not exist",
                     G_STRLOC,
                     pname,
                     G_OBJECT_TYPE_NAME (priv->manager),
                     G_OBJECT_TYPE_NAME (meta));
          break;
        }

      if (!(pspec->flags & G_PARAM_WRITABLE))
        {
          g_warning ("%s: the layout property '%s' for managers "
                     "of type '%s' (meta type '%s') is not writable",
                     G_STRLOC,
                     pspec->name,
                     G_OBJECT_TYPE_NAME (priv->manager),
                     G_OBJECT_TYPE_NAME (meta));
          break;
        }

      G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec),
                            var_args, 0,
                            &error);

      if (error)
        {
          g_warning ("%s: %s", G_STRLOC, error);
          g_free (error);
          break;
        }

      clutter_layout_manager_child_set_property (priv->manager,
                                                 container, actor,
                                                 pspec->name, &value);

      g_value_unset (&value);

      pname = va_arg (var_args, gchar*);
    }
}
Exemplo n.º 6
0
/**
 * clutter_box_packv:
 * @box: a #ClutterBox
 * @actor: a #ClutterActor
 * @n_properties: the number of properties to set
 * @properties: (array length=n_properties) (element-type utf8): a vector
 *   containing the property names to set
 * @values: (array length=n_properties): a vector containing the property
 *   values to set
 *
 * Vector-based variant of clutter_box_pack(), intended for language
 * bindings to use
 *
 * Since: 1.2
 */
void
clutter_box_packv (ClutterBox          *box,
                   ClutterActor        *actor,
                   guint                n_properties,
                   const gchar * const  properties[],
                   const GValue        *values)
{
  ClutterContainer *container;
  ClutterBoxPrivate *priv;
  ClutterLayoutMeta *meta;
  GObjectClass *klass;
  gint i;

  g_return_if_fail (CLUTTER_IS_BOX (box));
  g_return_if_fail (CLUTTER_IS_ACTOR (actor));

  container = CLUTTER_CONTAINER (box);
  clutter_container_add_actor (container, actor);

  priv = box->priv;

  meta = clutter_layout_manager_get_child_meta (priv->manager,
                                                container,
                                                actor);

  if (meta == NULL)
    return;

  klass = G_OBJECT_GET_CLASS (meta);

  for (i = 0; i < n_properties; i++)
    {
      const gchar *pname = properties[i];
      GParamSpec *pspec;

      pspec = g_object_class_find_property (klass, pname);
      if (pspec == NULL)
        {
          g_warning ("%s: the layout property '%s' for managers "
                     "of type '%s' (meta type '%s') does not exist",
                     G_STRLOC,
                     pname,
                     G_OBJECT_TYPE_NAME (priv->manager),
                     G_OBJECT_TYPE_NAME (meta));
          break;
        }

      if (!(pspec->flags & G_PARAM_WRITABLE))
        {
          g_warning ("%s: the layout property '%s' for managers "
                     "of type '%s' (meta type '%s') is not writable",
                     G_STRLOC,
                     pspec->name,
                     G_OBJECT_TYPE_NAME (priv->manager),
                     G_OBJECT_TYPE_NAME (meta));
          break;
        }

      clutter_layout_manager_child_set_property (priv->manager,
                                                 container, actor,
                                                 pname, &values[i]);
    }
}
static void
clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
                             ClutterContainer       *container,
                             const ClutterActorBox  *allocation,
                             ClutterAllocationFlags  flags)
{
  gfloat allocation_x, allocation_y;
  gfloat available_w, available_h;
  ClutterActor *actor, *child;
  ClutterActorIter iter;
  gboolean use_animations;
  ClutterAnimationMode easing_mode;
  guint easing_duration, easing_delay;

  clutter_actor_box_get_origin (allocation, &allocation_x, &allocation_y);
  clutter_actor_box_get_size (allocation, &available_w, &available_h);

  actor = CLUTTER_ACTOR (container);

  use_animations = clutter_layout_manager_get_easing_state (manager,
                                                            &easing_mode,
                                                            &easing_duration,
                                                            &easing_delay);
  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
    {
      ClutterLayoutMeta *meta;
      ClutterBinLayer *layer;
      ClutterActorBox child_alloc = { 0, };
      gdouble x_align, y_align;
      gboolean x_fill, y_fill;

      meta = clutter_layout_manager_get_child_meta (manager,
                                                    container,
                                                    child);
      layer = CLUTTER_BIN_LAYER (meta);

      if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
        child_alloc.x1 = clutter_actor_get_x (child);
      else
        child_alloc.x1 = allocation_x;

      if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
        child_alloc.y1 = clutter_actor_get_y (child);
      else
        child_alloc.y1 = allocation_y;

      child_alloc.x2 = available_w;
      child_alloc.y2 = available_h;

      if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL))
        {
          ClutterActorAlign align;

          align = _clutter_actor_get_effective_x_align (child);
          x_fill = align == CLUTTER_ACTOR_ALIGN_FILL;
          x_align = get_actor_align_factor (align);
        }
      else
        {
          x_fill = (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL);
          x_align = get_bin_alignment_factor (layer->x_align);
        }

      if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL))
        {
          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);
          y_align = get_bin_alignment_factor (layer->y_align);
        }

      if (use_animations)
        {
          clutter_actor_save_easing_state (child);
          clutter_actor_set_easing_mode (child, easing_mode);
          clutter_actor_set_easing_duration (child, easing_duration);
          clutter_actor_set_easing_delay (child, easing_delay);
        }

      clutter_actor_allocate_align_fill (child, &child_alloc,
                                         x_align, y_align,
                                         x_fill, y_fill,
                                         flags);

      if (use_animations)
        clutter_actor_restore_easing_state (child);
    }
}
Exemplo n.º 8
0
static void
calculate_row_heights (ClutterTableLayout *self,
                       ClutterContainer   *container,
                       gint                for_height)
{
  ClutterTableLayoutPrivate *priv = self->priv;
  ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (self);
  ClutterActor *actor, *child;
  gint i;
  DimensionData *rows, *columns;
  ClutterOrientation orientation = CLUTTER_ORIENTATION_VERTICAL;

  update_row_col (self, container);
  g_array_set_size (priv->rows, 0);
  g_array_set_size (priv->rows, self->priv->n_rows);

  rows = (DimensionData *) (void *) priv->rows->data;
  columns = (DimensionData *) (void *) priv->columns->data;

  /* reset the visibility of all rows */
  priv->visible_rows = 0;
  for (i = 0; i < priv->n_rows; i++)
    {
      rows[i].expand = FALSE;
      rows[i].visible = FALSE;
    }

  actor = CLUTTER_ACTOR (container);

  /* STAGE ONE: calculate row heights for non-spanned children */
  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    {
      ClutterTableChild *meta;
      DimensionData *row;
      gfloat c_min, c_pref;

      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      meta =
        CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager,
                                                                    container,
                                                                    child));

      if (meta->row_span > 1)
        continue;

      row = &rows[meta->row];

      if (!row->visible)
        {
          row->visible = TRUE;
          priv->visible_rows += 1;
        }

      clutter_actor_get_preferred_height (child, columns[meta->col].final_size,
                                          &c_min, &c_pref);

      row->min_size = MAX (row->min_size, c_min);
      row->pref_size = MAX (row->pref_size, c_pref);

      if (!row->expand)
        row->expand = clutter_actor_needs_expand (child, orientation);
    }

  /* STAGE TWO: take spanning children into account */
  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    {
      ClutterTableChild *meta;
      gfloat c_min, c_pref;
      gfloat min_height, pref_height;
      gint start_row, end_row;
      gint n_expand;

      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      meta =
        CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager,
                                                                    container,
                                                                    child));

      if (meta->row_span < 2)
        continue;

      start_row = meta->row;
      end_row = meta->row + meta->row_span - 1;

      clutter_actor_get_preferred_height (child, columns[meta->col].final_size,
                                         &c_min, &c_pref);


      /* check there is enough room for this actor */
      min_height = 0;
      pref_height = 0;
      n_expand = 0;
      for (i = start_row; i <= end_row; i++)
        {
          min_height += rows[i].min_size;
          pref_height += rows[i].pref_size;

          if (rows[i].expand)
            n_expand++;

          if (!rows[i].visible)
            {
              rows[i].visible = TRUE;
              priv->visible_rows += 1;
            }

          if (!rows[i].expand)
            rows[i].expand = clutter_actor_needs_expand (child, orientation);
        }

      min_height += priv->row_spacing * (meta->row_span - 1);
      pref_height += priv->row_spacing * (meta->row_span - 1);

      /* 1) If the minimum height of the rows spanned is less than the
       *    minimum height of the child that is spanning them, then we
       *    must increase the minimum height of the rows spanned.
       *
       * 2) If the preferred height of the spanned rows is more than
       *    the minimum height of the spanning child, then we can start
       *    at this size and decrease each row evenly.
       *
       * 3) If the preferred height of the rows is more than the minimum
       *    height of the spanned child, then we can start at the preferred
       *    height and expand.
       */

      /* (1) */
      if (c_min > min_height)
        {

          /* (2) */
          /* we can start from preferred height and decrease */
          if (pref_height > c_min)
            {
              for (i = start_row; i <= end_row; i++)
                rows[i].final_size = rows[i].pref_size;

              while (pref_height > c_min)
                {
                  for (i = start_row; i <= end_row; i++)
                    {
                      if (rows[i].final_size > rows[i].min_size)
                        {
                          rows[i].final_size--;
                          pref_height--;
                        }
                    }
                }

              for (i = start_row; i <= end_row; i++)
                rows[i].min_size = rows[i].final_size;
            }
          else
            {
              /* (3) */
              /* we can expand from preferred size */
              gfloat expand_by = c_pref - pref_height;

              for (i = start_row; i <= end_row; i++)
                {
                  if (n_expand)
                    {
                      if (rows[i].expand)
                        rows[i].min_size = rows[i].pref_size
                                         + expand_by / n_expand;
                    }
                  else
                    rows[i].min_size = rows[i].pref_size
                                     + expand_by / meta->row_span;
                }
            }
        }
    }

  /* calculate final heights */
  if (for_height >= 0)
    {
      gfloat min_height, pref_height;
      gint n_expand;

      min_height = 0;
      pref_height = 0;
      n_expand = 0;

      for (i = 0; i < self->priv->n_rows; i++)
        {
          pref_height += rows[i].pref_size;
          min_height += rows[i].min_size;
          if (rows[i].expand)
            n_expand++;
        }

      pref_height += priv->row_spacing * (priv->n_rows - 1);
      min_height += priv->row_spacing * (priv->n_rows - 1);

      if (for_height <= min_height)
        {
          /* erk, we can't shrink this! */
          for (i = 0; i < self->priv->n_rows; i++)
            rows[i].final_size = rows[i].min_size;

          return;
        }

      if (for_height == pref_height)
        {
          /* perfect! */
          for (i = 0; i < self->priv->n_rows; i++)
            rows[i].final_size = rows[i].pref_size;

          return;
        }

      /* for_height is between min_height and pref_height */
      if (for_height < pref_height && for_height > min_height)
        {
          gfloat height;

          /* shrink rows until they reach min_height */

          /* start with all rows at preferred size */
          for (i = 0; i < self->priv->n_rows; i++)
            rows[i].final_size = rows[i].pref_size;

          height = pref_height;

          while (height > for_height)
            {
              for (i = 0; i < priv->n_rows; i++)
                {
                  if (rows[i].final_size > rows[i].min_size)
                    {
                      rows[i].final_size--;
                      height--;
                    }
                }
            }

          return;
        }

      /* expand rows */
      if (for_height > pref_height)
        {
          gfloat extra_height = for_height - pref_height;
          gint remaining;

          if (n_expand)
            remaining = (gint) extra_height % n_expand;
          else
            remaining = (gint) extra_height % self->priv->n_rows;

          for (i = 0; i < self->priv->n_rows; i++)
            {
              if (rows[i].expand)
                {
                  rows[i].final_size = rows[i].pref_size
                                     + (extra_height / n_expand);
                }
              else
                rows[i].final_size = rows[i].pref_size;
            }

          /* distribute the remainder among children */
          i = 0;
          while (remaining)
            {
              rows[i].final_size++;
              i++;
              remaining--;
            }
        }
    }

}
Exemplo n.º 9
0
static void
calculate_col_widths (ClutterTableLayout *self,
                      ClutterContainer   *container,
                      gint                for_width)
{
  ClutterTableLayoutPrivate *priv = self->priv;
  ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (self);
  ClutterActor *actor, *child;
  gint i;
  DimensionData *columns;
  ClutterOrientation orientation = CLUTTER_ORIENTATION_HORIZONTAL;

  update_row_col (self, container);
  g_array_set_size (priv->columns, 0);
  g_array_set_size (priv->columns, priv->n_cols);
  columns = (DimensionData *) (void *) priv->columns->data;

  /* reset the visibility of all columns */
  priv->visible_cols = 0;
  for (i = 0; i < priv->n_cols; i++)
    {
      columns[i].expand = FALSE;
      columns[i].visible = FALSE;
    }

  actor = CLUTTER_ACTOR (container);

  /* STAGE ONE: calculate column widths for non-spanned children */
  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    {
      ClutterTableChild *meta;
      DimensionData *col;
      gfloat c_min, c_pref;

      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      meta =
        CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager,
                                                                    container,
                                                                    child));

      if (meta->col_span > 1)
        continue;

      col = &columns[meta->col];

      if (!col->visible)
        {
          col->visible = TRUE;
          priv->visible_cols += 1;
        }

      clutter_actor_get_preferred_width (child, -1, &c_min, &c_pref);

      col->min_size = MAX (col->min_size, c_min);
      col->pref_size = MAX (col->pref_size, c_pref);

      if (!col->expand)
        col->expand = clutter_actor_needs_expand (child, orientation);
    }

  /* STAGE TWO: take spanning children into account */
  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    {
      ClutterTableChild *meta;
      gfloat c_min, c_pref;
      gfloat min_width, pref_width;
      gint start_col, end_col;
      gint n_expand;

      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      meta =
        CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager,
                                                                    container,
                                                                    child));

      if (meta->col_span < 2)
        continue;

      start_col = meta->col;
      end_col = meta->col + meta->col_span - 1;

      clutter_actor_get_preferred_width (child, -1, &c_min, &c_pref);

      /* check there is enough room for this actor */
      min_width = 0;
      pref_width = 0;
      n_expand = 0;
      for (i = start_col; i <= end_col; i++)
        {
          min_width += columns[i].min_size;
          pref_width += columns[i].pref_size;

          if (columns[i].expand)
            n_expand++;

          if (!columns[i].visible)
            {
              columns[i].visible = TRUE;
              priv->visible_cols += 1;
            }

          if (!columns[i].expand)
            columns[i].expand = clutter_actor_needs_expand (child, orientation);
        }

      min_width += priv->col_spacing * (meta->col_span - 1);
      pref_width += priv->col_spacing * (meta->col_span - 1);

      /* see calculate_row_heights() for comments */
      /* (1) */
      if (c_min > min_width)
        {

          /* (2) */
          /* we can start from preferred width and decrease */
          if (pref_width > c_min)
            {
              for (i = start_col; i <= end_col; i++)
                columns[i].final_size = columns[i].pref_size;

              while (pref_width > c_min)
                {
                  for (i = start_col; i <= end_col; i++)
                    {
                      if (columns[i].final_size > columns[i].min_size)
                        {
                          columns[i].final_size--;
                          pref_width--;
                        }
                    }
                }

              for (i = start_col; i <= end_col; i++)
                columns[i].min_size = columns[i].final_size;
            }
          else
            {
              /* (3) */
              /* we can expand from preferred size */
              gfloat expand_by;

              expand_by = c_pref - pref_width;

              for (i = start_col; i <= end_col; i++)
                {
                  if (n_expand)
                    {
                      if (columns[i].expand)
                        columns[i].min_size = columns[i].pref_size
                                            + expand_by / n_expand;
                    }
                  else
                    columns[i].min_size = columns[i].pref_size
                                        + expand_by / meta->col_span;
                }
            }
        }
    }

  /* calculate final widths */
  if (for_width >= 0)
    {
      gfloat min_width, pref_width;
      gint n_expand;

      min_width = 0;
      pref_width = 0;
      n_expand = 0;

      for (i = 0; i < self->priv->n_cols; i++)
        {
          pref_width += columns[i].pref_size;
          min_width += columns[i].min_size;
          if (columns[i].expand)
            n_expand++;
        }

      pref_width += priv->col_spacing * (priv->n_cols - 1);
      min_width += priv->col_spacing * (priv->n_cols - 1);

      if (for_width <= min_width)
        {
          /* erk, we can't shrink this! */
          for (i = 0; i < priv->n_cols; i++)
            columns[i].final_size = columns[i].min_size;

          return;
        }

      if (for_width == pref_width)
        {
          /* perfect! */
          for (i = 0; i < self->priv->n_cols; i++)
            columns[i].final_size = columns[i].pref_size;

          return;
        }

      /* for_width is between min_width and pref_width */
      if (for_width < pref_width && for_width > min_width)
        {
          gfloat width;

          /* shrink columns until they reach min_width */

          /* start with all columns at preferred size */
          for (i = 0; i < self->priv->n_cols; i++)
            columns[i].final_size = columns[i].pref_size;

          width = pref_width;

          while (width > for_width)
            {
              for (i = 0; i < self->priv->n_cols; i++)
                {
                  if (columns[i].final_size > columns[i].min_size)
                    {
                      columns[i].final_size--;
                      width--;
                    }
                }
            }

          return;
        }

      /* expand columns */
      if (for_width > pref_width)
        {
          gfloat extra_width = for_width - pref_width;
          gint remaining;

          if (n_expand)
            remaining = (gint) extra_width % n_expand;
          else
            remaining = (gint) extra_width % priv->n_cols;

          for (i = 0; i < self->priv->n_cols; i++)
            {
              if (columns[i].expand)
                {
                  columns[i].final_size = columns[i].pref_size
                                        + (extra_width / n_expand);
                }
              else
                columns[i].final_size = columns[i].pref_size;
            }

          /* distribute the remainder among children */
          i = 0;
          while (remaining)
            {
              columns[i].final_size++;
              i++;
              remaining--;
            }
        }
    }

}
Exemplo n.º 10
0
static void
clutter_table_layout_allocate (ClutterLayoutManager   *layout,
                               ClutterContainer       *container,
                               const ClutterActorBox  *box,
                               ClutterAllocationFlags  flags)
{
  ClutterTableLayout *self = CLUTTER_TABLE_LAYOUT (layout);
  ClutterTableLayoutPrivate *priv = self->priv;
  ClutterActor *actor, *child;
  gint row_spacing, col_spacing;
  gint i;
  DimensionData *rows, *columns;

  update_row_col (self, container);
  if (priv->n_cols < 1 || priv->n_rows < 1)
    return;

  actor = CLUTTER_ACTOR (container);

  if (clutter_actor_get_n_children (actor) == 0)
    return;

  col_spacing = (priv->col_spacing);
  row_spacing = (priv->row_spacing);

  calculate_table_dimensions (self, container,
                              box->x2 - box->x1,
                              box->y2 - box->y1);

  rows = (DimensionData *) (void *) priv->rows->data;
  columns = (DimensionData *) (void *) priv->columns->data;

  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    {
      gint row, col, row_span, col_span;
      gint col_width, row_height;
      ClutterTableChild *meta;
      ClutterActorBox childbox;
      gint child_x, child_y;

      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      meta =
        CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (layout,
                                                                    container,
                                                                    child));

      /* get child properties */
      col = meta->col;
      row = meta->row;
      row_span = meta->row_span;
      col_span = meta->col_span;

      /* initialise the width and height */
      col_width = columns[col].final_size;
      row_height = rows[row].final_size;

      /* Add the widths of the spanned columns:
       *
       * First check that we have a non-zero span. Then we loop over each of
       * the columns that we're spanning but we stop short if we go past the
       * number of columns in the table. This is necessary to avoid accessing
       * uninitialised memory. We add the spacing in here too since we only
       * want to add as much spacing as times we successfully span.
       */
      if (col + col_span > priv->n_cols)
        g_warning (G_STRLOC ": column-span exceeds number of columns");
      if (row + row_span > priv->n_rows)
        g_warning (G_STRLOC ": row-span exceeds number of rows");

      if (col_span > 1)
        {
          for (i = col + 1; i < col + col_span && i < priv->n_cols; i++)
            {
              col_width += columns[i].final_size;
              col_width += col_spacing;
            }
        }

      /* add the height of the spanned rows */
      if (row_span > 1)
        {
          for (i = row + 1; i < row + row_span && i < priv->n_rows; i++)
            {
              row_height += rows[i].final_size;
              row_height += row_spacing;
            }
        }

      /* calculate child x */
      child_x = clutter_actor_box_get_x (box);
      for (i = 0; i < col; i++)
        {
          if (columns[i].visible)
            {
              child_x += columns[i].final_size;
              child_x += col_spacing;
            }
        }

      /* calculate child y */
      child_y = clutter_actor_box_get_y (box);
      for (i = 0; i < row; i++)
        {
          if (rows[i].visible)
            {
              child_y += rows[i].final_size;
              child_y += row_spacing;
            }
        }

      /* set up childbox */
      childbox.x1 = (float) child_x;
      childbox.x2 = (float) MAX (0, child_x + col_width);

      childbox.y1 = (float) child_y;
      childbox.y2 = (float) MAX (0, child_y + row_height);

      clutter_actor_allocate (child, &childbox, flags);
    }
}
Exemplo n.º 11
0
static void
clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
                             ClutterContainer       *container,
                             const ClutterActorBox  *allocation,
                             ClutterAllocationFlags  flags)
{
  gfloat allocation_x, allocation_y;
  gfloat available_w, available_h;
  ClutterActor *actor, *child;
  ClutterActorIter iter;

  clutter_actor_box_get_origin (allocation, &allocation_x, &allocation_y);
  clutter_actor_box_get_size (allocation, &available_w, &available_h);

  actor = CLUTTER_ACTOR (container);

  clutter_actor_iter_init (&iter, actor);
  while (clutter_actor_iter_next (&iter, &child))
    {
      ClutterLayoutMeta *meta;
      ClutterBinLayer *layer;
      ClutterActorBox child_alloc = { 0, };
      gdouble x_align, y_align;
      gboolean x_fill, y_fill, is_fixed_position_set;
      float fixed_x, fixed_y;

      if (!clutter_actor_is_visible (child))
        continue;

      meta = clutter_layout_manager_get_child_meta (manager,
                                                    container,
                                                    child);
      layer = CLUTTER_BIN_LAYER (meta);

      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)
	{
          if (is_fixed_position_set)
            child_alloc.x1 = fixed_x;
          else
            child_alloc.x1 = clutter_actor_get_x (child);
	}
      else
        child_alloc.x1 = allocation_x;

      if (is_fixed_position_set ||
          layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
	{
	  if (is_fixed_position_set)
            child_alloc.y1 = fixed_y;
          else
	    child_alloc.y1 = clutter_actor_get_y (child);
	}
      else
        child_alloc.y1 = allocation_y;

      child_alloc.x2 = allocation_x + available_w;
      child_alloc.y2 = allocation_y + available_h;

      if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL))
        {
          ClutterActorAlign align;

          align = clutter_actor_get_x_align (child);
          x_fill = align == CLUTTER_ACTOR_ALIGN_FILL;
          x_align = get_actor_align_factor (align);
        }
      else
        {
          ClutterTextDirection text_dir;

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

          text_dir = clutter_actor_get_text_direction (child);

          if (!is_fixed_position_set)
            x_align = get_bin_alignment_factor (layer->x_align, text_dir);
          else
            x_align = 0.0;
        }

      if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL))
        {
          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);

          if (!is_fixed_position_set)
            y_align = get_bin_alignment_factor (layer->y_align,
                                                CLUTTER_TEXT_DIRECTION_LTR);
          else
            y_align = 0.0;
        }

      clutter_actor_allocate_align_fill (child, &child_alloc,
                                         x_align, y_align,
                                         x_fill, y_fill,
                                         flags);
    }
}