/** * 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; }
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); }
/** * 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); }
/** * 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); }
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*); } }
/** * 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); } }
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--; } } } }
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--; } } } }
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); } }
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); } }