/* Dump actors */ static void _xfdashboard_dump_actor_internal(ClutterActor *inActor, gint inLevel) { ClutterActorIter iter; ClutterActor *child; gint i; g_return_if_fail(CLUTTER_IS_ACTOR(inActor)); g_return_if_fail(inLevel>=0); clutter_actor_iter_init(&iter, CLUTTER_ACTOR(inActor)); while(clutter_actor_iter_next(&iter, &child)) { for(i=0; i<inLevel; i++) g_print(" "); g_print("+- %s@%p - name: %s - geometry: %.2f,%.2f [%.2fx%.2f], mapped: %s, visible: %s, children: %d\n", G_OBJECT_TYPE_NAME(child), child, clutter_actor_get_name(child), clutter_actor_get_x(child), clutter_actor_get_y(child), clutter_actor_get_width(child), clutter_actor_get_height(child), clutter_actor_is_mapped(child) ? "yes" : "no", clutter_actor_is_visible(child) ? "yes" : "no", clutter_actor_get_n_children(child)); if(clutter_actor_get_n_children(child)>0) _xfdashboard_dump_actor_internal(child, inLevel+1); } }
/* Dump actors */ static void _xfdashboard_dump_actor_print(ClutterActor *inActor, gint inLevel) { XfdashboardStylable *stylable; ClutterActorBox allocation; gint i; g_return_if_fail(CLUTTER_IS_ACTOR(inActor)); g_return_if_fail(inLevel>=0); /* Check if actor is stylable to retrieve style configuration */ stylable=NULL; if(XFDASHBOARD_IS_STYLABLE(inActor)) stylable=XFDASHBOARD_STYLABLE(inActor); /* Dump actor */ for(i=0; i<inLevel; i++) g_print(" "); clutter_actor_get_allocation_box(inActor, &allocation); g_print("+- %s@%p [%s%s%s%s%s%s] - geometry: %.2f,%.2f [%.2fx%.2f], mapped: %s, visible: %s, layout: %s, children: %d\n", G_OBJECT_TYPE_NAME(inActor), inActor, clutter_actor_get_name(inActor) ? " #" : "", clutter_actor_get_name(inActor) ? clutter_actor_get_name(inActor) : "", stylable && xfdashboard_stylable_get_classes(stylable) ? "." : "", stylable && xfdashboard_stylable_get_classes(stylable) ? xfdashboard_stylable_get_classes(stylable) : "", stylable && xfdashboard_stylable_get_pseudo_classes(stylable) ? ":" : "", stylable && xfdashboard_stylable_get_pseudo_classes(stylable) ? xfdashboard_stylable_get_pseudo_classes(stylable) : "", allocation.x1, allocation.y1, allocation.x2-allocation.x1, allocation.y2-allocation.y1, clutter_actor_is_mapped(inActor) ? "yes" : "no", clutter_actor_is_visible(inActor) ? "yes" : "no", clutter_actor_get_layout_manager(inActor) ? G_OBJECT_TYPE_NAME(clutter_actor_get_layout_manager(inActor)) : "none", clutter_actor_get_n_children(inActor)); }
/** * clutter_group_get_n_children: * @self: A #ClutterGroup * * Gets the number of actors held in the group. * * Return value: The number of child actors held in the group. * * Since: 0.2 * * Deprecated: 1.10: Use clutter_actor_get_n_children() instead. */ gint clutter_group_get_n_children (ClutterGroup *self) { g_return_val_if_fail (CLUTTER_IS_GROUP (self), 0); return clutter_actor_get_n_children (CLUTTER_ACTOR (self)); }
static void st_box_layout_paint (ClutterActor *actor) { StBoxLayout *self = ST_BOX_LAYOUT (actor); StBoxLayoutPrivate *priv = self->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); gdouble x, y; ClutterActorBox allocation_box; ClutterActorBox content_box; ClutterActor *child; get_border_paint_offsets (self, &x, &y); if (x != 0 || y != 0) { cogl_push_matrix (); cogl_translate ((int)x, (int)y, 0); } st_widget_paint_background (ST_WIDGET (actor)); if (x != 0 || y != 0) { cogl_pop_matrix (); } if (clutter_actor_get_n_children (actor) == 0) return; clutter_actor_get_allocation_box (actor, &allocation_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); content_box.x1 += x; content_box.y1 += y; content_box.x2 += x; content_box.y2 += y; /* The content area forms the viewport into the scrolled contents, while * the borders and background stay in place; after drawing the borders and * background, we clip to the content area */ if (priv->hadjustment || priv->vadjustment) cogl_clip_push_rectangle ((int)content_box.x1, (int)content_box.y1, (int)content_box.x2, (int)content_box.y2); for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) clutter_actor_paint (child); if (priv->hadjustment || priv->vadjustment) cogl_clip_pop (); }
/** * clutter_group_get_nth_child: * @self: A #ClutterGroup * @index_: the position of the requested actor. * * Gets a groups child held at @index_ in stack. * * Return value: (transfer none): A Clutter actor, or %NULL if * @index_ is invalid. * * Since: 0.2 * * Deprecated: 1.10: Use clutter_actor_get_child_at_index() instead. */ ClutterActor * clutter_group_get_nth_child (ClutterGroup *self, gint index_) { ClutterActor *actor; g_return_val_if_fail (CLUTTER_IS_GROUP (self), NULL); actor = CLUTTER_ACTOR (self); g_return_val_if_fail (index_ <= clutter_actor_get_n_children (actor), NULL); return clutter_actor_get_child_at_index (actor, index_); }
static void st_box_layout_pick (ClutterActor *actor, const ClutterColor *color) { StBoxLayout *self = ST_BOX_LAYOUT (actor); StBoxLayoutPrivate *priv = self->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); gdouble x, y; ClutterActorBox allocation_box; ClutterActorBox content_box; ClutterActor *child; get_border_paint_offsets (self, &x, &y); if (x != 0 || y != 0) { cogl_push_matrix (); cogl_translate ((int)x, (int)y, 0); } CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, color); if (x != 0 || y != 0) { cogl_pop_matrix (); } if (clutter_actor_get_n_children (actor) == 0) return; clutter_actor_get_allocation_box (actor, &allocation_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); content_box.x1 += x; content_box.y1 += y; content_box.x2 += x; content_box.y2 += y; if (priv->hadjustment || priv->vadjustment) cogl_clip_push_rectangle ((int)content_box.x1, (int)content_box.y1, (int)content_box.x2, (int)content_box.y2); for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) clutter_actor_paint (child); if (priv->hadjustment || priv->vadjustment) cogl_clip_pop (); }
static void _xfdashboard_dump_actor_internal(ClutterActor *inActor, gint inLevel) { ClutterActorIter iter; ClutterActor *child; g_return_if_fail(CLUTTER_IS_ACTOR(inActor)); g_return_if_fail(inLevel>0); /* Dump children */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(inActor)); while(clutter_actor_iter_next(&iter, &child)) { _xfdashboard_dump_actor_print(child, inLevel); if(clutter_actor_get_n_children(child)>0) _xfdashboard_dump_actor_internal(child, inLevel+1); } }
static void clutter_flow_layout_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv; ClutterActor *actor, *child; ClutterActorIter iter; gfloat x_off, y_off; gfloat avail_width, avail_height; gfloat item_x, item_y; gint line_item_count; gint items_per_line; gint line_index; actor = CLUTTER_ACTOR (container); if (clutter_actor_get_n_children (actor) == 0) return; clutter_actor_box_get_origin (allocation, &x_off, &y_off); clutter_actor_box_get_size (allocation, &avail_width, &avail_height); /* blow the cached preferred size and re-compute with the given * available size in case the FlowLayout wasn't given the exact * size it requested */ if ((priv->req_width >= 0 && avail_width != priv->req_width) || (priv->req_height >= 0 && avail_height != priv->req_height)) { clutter_flow_layout_get_preferred_width (manager, container, avail_height, NULL, NULL); clutter_flow_layout_get_preferred_height (manager, container, avail_width, NULL, NULL); } items_per_line = compute_lines (CLUTTER_FLOW_LAYOUT (manager), avail_width, avail_height); item_x = x_off; item_y = y_off; line_item_count = 0; line_index = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { ClutterActorBox child_alloc; gfloat item_width, item_height; gfloat new_x, new_y; gfloat child_min, child_natural; if (!CLUTTER_ACTOR_IS_VISIBLE (child)) continue; new_x = new_y = 0; if (!priv->snap_to_grid) clutter_actor_get_preferred_size (child, NULL, NULL, &item_width, &item_height); if (priv->orientation == CLUTTER_FLOW_HORIZONTAL) { if ((priv->snap_to_grid && line_item_count == items_per_line && line_item_count > 0) || (!priv->snap_to_grid && item_x + item_width > avail_width)) { item_y += g_array_index (priv->line_natural, gfloat, line_index); if (line_index >= 0) item_y += priv->row_spacing; line_item_count = 0; line_index += 1; item_x = x_off; } if (priv->snap_to_grid) { new_x = x_off + ((line_item_count + 1) * (avail_width + priv->col_spacing)) / items_per_line; item_width = new_x - item_x - priv->col_spacing; } else { new_x = item_x + item_width + priv->col_spacing; } item_height = g_array_index (priv->line_natural, gfloat, line_index); } else { if ((priv->snap_to_grid && line_item_count == items_per_line && line_item_count > 0) || (!priv->snap_to_grid && item_y + item_height > avail_height)) { item_x += g_array_index (priv->line_natural, gfloat, line_index); if (line_index >= 0) item_x += priv->col_spacing; line_item_count = 0; line_index += 1; item_y = y_off; } if (priv->snap_to_grid) { new_y = y_off + ((line_item_count + 1) * (avail_height + priv->row_spacing)) / items_per_line; item_height = new_y - item_y - priv->row_spacing; } else { new_y = item_y + item_height + priv->row_spacing; } item_width = g_array_index (priv->line_natural, gfloat, line_index); } if (!priv->is_homogeneous && !clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL)) { clutter_actor_get_preferred_width (child, item_height, &child_min, &child_natural); item_width = MIN (item_width, child_natural); } if (!priv->is_homogeneous && !clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL)) { clutter_actor_get_preferred_height (child, item_width, &child_min, &child_natural); item_height = MIN (item_height, child_natural); } CLUTTER_NOTE (LAYOUT, "flow[line:%d, item:%d/%d] =" "{ %.2f, %.2f, %.2f, %.2f }", line_index, line_item_count + 1, items_per_line, item_x, item_y, item_width, item_height); child_alloc.x1 = ceil (item_x); child_alloc.y1 = ceil (item_y); child_alloc.x2 = ceil (child_alloc.x1 + item_width); child_alloc.y2 = ceil (child_alloc.y1 + item_height); clutter_actor_allocate (child, &child_alloc, flags); if (priv->orientation == CLUTTER_FLOW_HORIZONTAL) item_x = new_x; else item_y = new_y; line_item_count += 1; } }
static void clutter_flow_layout_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv; gint n_columns, line_item_count, line_count; gfloat total_min_height, total_natural_height; gfloat line_min_height, line_natural_height; gfloat max_min_height, max_natural_height; ClutterActor *actor, *child; ClutterActorIter iter; gfloat item_x; n_columns = get_columns (CLUTTER_FLOW_LAYOUT (manager), for_width); total_min_height = 0; total_natural_height = 0; line_min_height = 0; line_natural_height = 0; line_item_count = 0; line_count = 0; item_x = 0; actor = CLUTTER_ACTOR (container); /* clear the line height arrays */ if (priv->line_min != NULL) g_array_free (priv->line_min, TRUE); if (priv->line_natural != NULL) g_array_free (priv->line_natural, TRUE); priv->line_min = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); priv->line_natural = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); if (clutter_actor_get_n_children (actor) != 0) line_count = 1; max_min_height = max_natural_height = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_min, child_natural; gfloat new_x, item_width; if (!CLUTTER_ACTOR_IS_VISIBLE (child)) continue; if (priv->orientation == CLUTTER_FLOW_HORIZONTAL && for_width > 0) { clutter_actor_get_preferred_width (child, -1, &child_min, &child_natural); if ((priv->snap_to_grid && line_item_count == n_columns) || (!priv->snap_to_grid && item_x + child_natural > for_width)) { total_min_height += line_min_height; total_natural_height += line_natural_height; g_array_append_val (priv->line_min, line_min_height); g_array_append_val (priv->line_natural, line_natural_height); line_min_height = line_natural_height = 0; line_item_count = 0; line_count += 1; item_x = 0; } if (priv->snap_to_grid) { new_x = ((line_item_count + 1) * (for_width + priv->col_spacing)) / n_columns; item_width = new_x - item_x - priv->col_spacing; } else { new_x = item_x + child_natural + priv->col_spacing; item_width = child_natural; } clutter_actor_get_preferred_height (child, item_width, &child_min, &child_natural); line_min_height = MAX (line_min_height, child_min); line_natural_height = MAX (line_natural_height, child_natural); item_x = new_x; line_item_count += 1; max_min_height = MAX (max_min_height, line_min_height); max_natural_height = MAX (max_natural_height, line_natural_height); } else { clutter_actor_get_preferred_height (child, for_width, &child_min, &child_natural); max_min_height = MAX (max_min_height, child_min); max_natural_height = MAX (max_natural_height, child_natural); total_min_height += max_min_height; total_natural_height += max_natural_height; line_count += 1; } } priv->row_height = max_natural_height; if (priv->max_row_height > 0 && priv->row_height > priv->max_row_height) priv->row_height = MAX (priv->max_row_height, max_min_height); if (priv->row_height < priv->min_row_height) priv->row_height = priv->min_row_height; if (priv->orientation == CLUTTER_FLOW_HORIZONTAL && for_width > 0) { /* if we have a non-full row we need to add it */ if (line_item_count > 0) { total_min_height += line_min_height; total_natural_height += line_natural_height; g_array_append_val (priv->line_min, line_min_height); g_array_append_val (priv->line_natural, line_natural_height); } priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->row_spacing * (priv->line_count - 1); total_min_height += total_spacing; total_natural_height += total_spacing; } } else { g_array_append_val (priv->line_min, line_min_height); g_array_append_val (priv->line_natural, line_natural_height); priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->col_spacing * priv->line_count; total_min_height += total_spacing; total_natural_height += total_spacing; } } CLUTTER_NOTE (LAYOUT, "Flow[h]: %d lines (%d per line): w [ %.2f, %.2f ] for h %.2f", n_columns, priv->line_count, total_min_height, total_natural_height, for_width); priv->req_width = for_width; if (min_height_p) *min_height_p = max_min_height; if (nat_height_p) *nat_height_p = total_natural_height; }
static void clutter_flow_layout_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv; gint n_rows, line_item_count, line_count; gfloat total_min_width, total_natural_width; gfloat line_min_width, line_natural_width; gfloat max_min_width, max_natural_width; ClutterActor *actor, *child; ClutterActorIter iter; gfloat item_y; n_rows = get_rows (CLUTTER_FLOW_LAYOUT (manager), for_height); total_min_width = 0; total_natural_width = 0; line_min_width = 0; line_natural_width = 0; line_item_count = 0; line_count = 0; item_y = 0; actor = CLUTTER_ACTOR (container); /* clear the line width arrays */ if (priv->line_min != NULL) g_array_free (priv->line_min, TRUE); if (priv->line_natural != NULL) g_array_free (priv->line_natural, TRUE); priv->line_min = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); priv->line_natural = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); if (clutter_actor_get_n_children (actor) != 0) line_count = 1; max_min_width = max_natural_width = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_min, child_natural; gfloat new_y, item_height; if (!CLUTTER_ACTOR_IS_VISIBLE (child)) continue; if (priv->orientation == CLUTTER_FLOW_VERTICAL && for_height > 0) { if (line_item_count == n_rows) { total_min_width += line_min_width; total_natural_width += line_natural_width; g_array_append_val (priv->line_min, line_min_width); g_array_append_val (priv->line_natural, line_natural_width); line_min_width = line_natural_width = 0; line_item_count = 0; line_count += 1; item_y = 0; } new_y = ((line_item_count + 1) * (for_height + priv->row_spacing)) / n_rows; item_height = new_y - item_y - priv->row_spacing; clutter_actor_get_preferred_width (child, item_height, &child_min, &child_natural); line_min_width = MAX (line_min_width, child_min); line_natural_width = MAX (line_natural_width, child_natural); item_y = new_y; line_item_count += 1; max_min_width = MAX (max_min_width, line_min_width); max_natural_width = MAX (max_natural_width, line_natural_width); } else { clutter_actor_get_preferred_width (child, for_height, &child_min, &child_natural); max_min_width = MAX (max_min_width, child_min); max_natural_width = MAX (max_natural_width, child_natural); total_min_width += max_min_width; total_natural_width += max_natural_width; line_count += 1; } } priv->col_width = max_natural_width; if (priv->max_col_width > 0 && priv->col_width > priv->max_col_width) priv->col_width = MAX (priv->max_col_width, max_min_width); if (priv->col_width < priv->min_col_width) priv->col_width = priv->min_col_width; if (priv->orientation == CLUTTER_FLOW_VERTICAL && for_height > 0) { /* if we have a non-full row we need to add it */ if (line_item_count > 0) { total_min_width += line_min_width; total_natural_width += line_natural_width; g_array_append_val (priv->line_min, line_min_width); g_array_append_val (priv->line_natural, line_natural_width); } priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->col_spacing * (priv->line_count - 1); total_min_width += total_spacing; total_natural_width += total_spacing; } } else { g_array_append_val (priv->line_min, line_min_width); g_array_append_val (priv->line_natural, line_natural_width); priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->col_spacing * (priv->line_count - 1); total_min_width += total_spacing; total_natural_width += total_spacing; } } CLUTTER_NOTE (LAYOUT, "Flow[w]: %d lines (%d per line): w [ %.2f, %.2f ] for h %.2f", n_rows, priv->line_count, total_min_width, total_natural_width, for_height); priv->req_height = for_height; if (min_width_p) *min_width_p = max_min_width; if (nat_width_p) *nat_width_p = total_natural_width; }
static void st_box_layout_allocate (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags) { StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv; StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); ClutterActorBox content_box; gfloat avail_width, avail_height, min_width, natural_width, min_height, natural_height; gfloat position, next_position; gint n_expand_children = 0, i; gfloat expand_amount, shrink_amount; BoxChildShrink *shrinks = NULL; // Home-made logical xor gboolean flip = (!(st_widget_get_direction (ST_WIDGET (actor)) == ST_TEXT_DIRECTION_RTL) != !priv->is_align_end); gboolean reverse_order = (!priv->is_align_end != !priv->is_pack_start); ClutterActor *child; clutter_actor_set_allocation (actor, box, flags); st_theme_node_get_content_box (theme_node, box, &content_box); avail_width = content_box.x2 - content_box.x1; avail_height = content_box.y2 - content_box.y1; get_content_preferred_width (ST_BOX_LAYOUT (actor), avail_height, &min_width, &natural_width); get_content_preferred_height (ST_BOX_LAYOUT (actor), MAX (avail_width, min_width), &min_height, &natural_height); /* update adjustments for scrolling */ if (priv->vadjustment) { gdouble prev_value; g_object_set (G_OBJECT (priv->vadjustment), "lower", 0.0, "upper", MAX (min_height, avail_height), "page-size", avail_height, "step-increment", avail_height / 6, "page-increment", avail_height - avail_height / 6, NULL); prev_value = st_adjustment_get_value (priv->vadjustment); st_adjustment_set_value (priv->vadjustment, prev_value); } if (priv->hadjustment) { gdouble prev_value; g_object_set (G_OBJECT (priv->hadjustment), "lower", 0.0, "upper", MAX (min_width, avail_width), "page-size", avail_width, "step-increment", avail_width / 6, "page-increment", avail_width - avail_width / 6, NULL); prev_value = st_adjustment_get_value (priv->hadjustment); st_adjustment_set_value (priv->hadjustment, prev_value); } if (avail_height < min_height) { avail_height = min_height; content_box.y2 = content_box.y1 + avail_height; } if (avail_width < min_width) { avail_width = min_width; content_box.x2 = content_box.x1 + avail_width; } if (priv->is_vertical) { expand_amount = MAX (0, avail_height - natural_height); shrink_amount = MAX (0, natural_height - avail_height); } else { expand_amount = MAX (0, avail_width - natural_width); shrink_amount = MAX (0, natural_width - avail_width); } if (expand_amount > 0) { /* count the number of children with expand set to TRUE */ n_expand_children = 0; for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { gboolean expand; if (!CLUTTER_ACTOR_IS_VISIBLE (child) || clutter_actor_get_fixed_position_set (child)) continue; clutter_container_child_get ((ClutterContainer *) actor, child, "expand", &expand, NULL); if (expand) n_expand_children++; } if (n_expand_children == 0) expand_amount = 0; } else if (shrink_amount > 0) { shrinks = compute_shrinks (ST_BOX_LAYOUT (actor), priv->is_vertical ? avail_width : avail_height, shrink_amount); } if (priv->is_vertical) { if (flip) { position = content_box.y2; } else { position = content_box.y1; } } else { if (flip) { position = content_box.x2; } else { position = content_box.x1; } } if (reverse_order) { child = clutter_actor_get_last_child (actor); i = clutter_actor_get_n_children (actor) - 1; } else { child = clutter_actor_get_first_child (actor); i = 0; } gfloat init_padding = (avail_width/2) - (natural_width/2); while (child != NULL) { ClutterActorBox child_box; gfloat child_min, child_nat, child_allocated; gboolean xfill, yfill, expand, fixed; StAlign xalign, yalign; if (!CLUTTER_ACTOR_IS_VISIBLE (child)) goto next_child; fixed = clutter_actor_get_fixed_position_set (child); if (fixed) { clutter_actor_allocate_preferred_size (child, flags); goto next_child; } clutter_container_child_get ((ClutterContainer*) actor, child, "x-fill", &xfill, "y-fill", &yfill, "x-align", &xalign, "y-align", &yalign, "expand", &expand, NULL); if (priv->is_vertical) { _st_actor_get_preferred_height (child, avail_width, xfill, &child_min, &child_nat); } else { _st_actor_get_preferred_width (child, avail_height, yfill, &child_min, &child_nat); } child_allocated = child_nat; if (expand_amount > 0 && expand) child_allocated += expand_amount / n_expand_children; else if (shrink_amount > 0) child_allocated -= shrinks[i].shrink_amount; if (flip) { next_position = position - child_allocated; } else { next_position = position + child_allocated; } if (priv->is_vertical) { if (flip) { child_box.y1 = (int)(0.5 + next_position); child_box.y2 = (int)(0.5 + position); } else { child_box.y1 = (int)(0.5 + position); child_box.y2 = (int)(0.5 + next_position); } child_box.x1 = content_box.x1; child_box.x2 = content_box.x2; _st_allocate_fill (ST_WIDGET (actor), child, &child_box, xalign, yalign, xfill, yfill); clutter_actor_allocate (child, &child_box, flags); } else { if (flip) { child_box.x1 = (int)(0.5 + next_position); child_box.x2 = (int)(0.5 + position); } else { child_box.x1 = (int)(0.5 + position); child_box.x2 = (int)(0.5 + next_position); } child_box.y1 = content_box.y1; child_box.y2 = content_box.y2; _st_allocate_fill (ST_WIDGET (actor), child, &child_box, xalign, yalign, xfill, yfill); clutter_actor_allocate (child, &child_box, flags); } if (flip) position = next_position - priv->spacing; else position = next_position + priv->spacing; next_child: if (reverse_order) { child = clutter_actor_get_previous_sibling (child); i--; } else { child = clutter_actor_get_next_sibling (child); i++; } } if (shrinks) g_free (shrinks); }
static BoxChildShrink * compute_shrinks (StBoxLayout *self, gfloat for_length, gfloat total_shrink) { StBoxLayoutPrivate *priv = self->priv; int n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self)); BoxChildShrink *shrinks = g_new0 (BoxChildShrink, n_children); gfloat shrink_so_far; gfloat base_shrink = 0; /* the "= 0" is just to make gcc happy */ int n_shrink_children; ClutterActor *child; int i = 0; /* The effect that we want is that all the children get an equal chance * to expand from their minimum size up to the natural size. Or to put * it a different way, we want to start by shrinking only the child that * can shrink most, then shrink that and the next most shrinkable child, * to the point where we are shrinking everything. */ /* Find the amount of possible shrink for each child */ int n_possible_shrink_children = 0; for (child = clutter_actor_get_first_child (CLUTTER_ACTOR (self)); child != NULL; child = clutter_actor_get_next_sibling (child)) { gfloat child_min, child_nat; gboolean child_fill; gboolean fixed; fixed = clutter_actor_get_fixed_position_set (child); shrinks[i].child_index = i; if (CLUTTER_ACTOR_IS_VISIBLE (child) && !fixed) { if (priv->is_vertical) { clutter_container_child_get ((ClutterContainer*) self, child, "x-fill", &child_fill, NULL); _st_actor_get_preferred_height (child, for_length, child_fill, &child_min, &child_nat); } else { clutter_container_child_get ((ClutterContainer*) self, child, "y-fill", &child_fill, NULL); _st_actor_get_preferred_width (child, for_length, child_fill, &child_min, &child_nat); } shrinks[i].shrink_amount = MAX (0., child_nat - child_min); n_possible_shrink_children++; } else { shrinks[i].shrink_amount = -1.; } i++; } /* We want to process children starting from the child with the maximum available * shrink, so sort in this order; !visible children end up at the end */ qsort (shrinks, n_children, sizeof (BoxChildShrink), compare_by_shrink_amount); /* +--+ * | | * | | +-- * | | | | * | | | | +-+ * --+--+-+-+-+-+---------- * | | | | | | +-+ +-+ * | | | | | | | | | | * --+--+-+-+-+-+-+-+------ * * We are trying to find the correct position for the upper line the "water mark" * so that total of the portion of the bars above the line is equal to the total * amount we want to shrink. */ /* Start by moving the line downward, top-of-bar by top-of-bar */ shrink_so_far = 0; for (n_shrink_children = 1; n_shrink_children <= n_possible_shrink_children; n_shrink_children++) { if (n_shrink_children < n_possible_shrink_children) base_shrink = shrinks[n_shrink_children].shrink_amount; else base_shrink = 0; shrink_so_far += n_shrink_children * (shrinks[n_shrink_children - 1].shrink_amount - base_shrink); if (shrink_so_far >= total_shrink || n_shrink_children == n_possible_shrink_children) break; } /* OK, we found enough shrinkage, move it back upwards to the right position */ base_shrink += (shrink_so_far - total_shrink) / n_shrink_children; if (base_shrink < 0) /* can't shrink that much, probably round-off error */ base_shrink = 0; /* Assign the portion above the base shrink line to the shrink_amount */ for (i = 0; i < n_shrink_children; i++) shrinks[i].shrink_amount -= base_shrink; for (; i < n_children; i++) shrinks[i].shrink_amount = 0; /* And sort back to their original order */ qsort (shrinks, n_children, sizeof (BoxChildShrink), compare_by_child_index); return shrinks; }
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); } }