3 #include <clutter/clutter.h>
5 typedef struct _MultiLayout MultiLayout;
6 typedef struct _MultiLayoutClass MultiLayoutClass;
15 ClutterLayoutManager parent_instance;
17 /* the state of the layout */
18 MultiLayoutState state;
20 /* spacing between children */
28 struct _MultiLayoutClass
30 ClutterLayoutManagerClass parent_class;
33 GType multi_layout_get_type (void);
35 ClutterLayoutManager * multi_layout_new (void);
36 void multi_layout_set_state (MultiLayout *layout,
37 MultiLayoutState state);
38 void multi_layout_set_spacing (MultiLayout *layout,
41 G_DEFINE_TYPE (MultiLayout, multi_layout, CLUTTER_TYPE_LAYOUT_MANAGER)
44 multi_layout_get_preferred_width (ClutterLayoutManager *manager,
45 ClutterContainer *container,
50 MultiLayout *self = (MultiLayout *) manager;
51 float minimum, natural;
52 float max_natural_width;
53 ClutterActorIter iter;
57 minimum = natural = 0.f;
58 max_natural_width = 0.f;
61 clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container));
62 while (clutter_actor_iter_next (&iter, &child))
64 float child_minimum, child_natural;
66 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
69 clutter_actor_get_preferred_width (child, -1.f,
73 max_natural_width = MAX (max_natural_width, child_natural);
75 if (self->state == MULTI_LAYOUT_GRID)
77 minimum += child_minimum;
78 natural += child_natural;
80 else if (self->state == MULTI_LAYOUT_CIRCLE)
82 minimum = MAX (minimum, child_minimum);
83 natural = MAX (natural, child_natural);
89 self->cell_width = max_natural_width;
91 minimum += (self->spacing * (n_children - 1));
92 natural += (self->spacing * (n_children - 1));
94 if (min_width_p != NULL)
95 *min_width_p = minimum;
97 if (nat_width_p != NULL)
98 *nat_width_p = natural;
102 multi_layout_get_preferred_height (ClutterLayoutManager *manager,
103 ClutterContainer *container,
108 MultiLayout *self = (MultiLayout *) manager;
109 float minimum, natural;
110 ClutterActorIter iter;
114 minimum = natural = self->spacing * 2.f;
117 clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container));
118 while (clutter_actor_iter_next (&iter, &child))
120 float child_minimum, child_natural;
122 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
125 clutter_actor_get_preferred_height (child, -1.f,
129 minimum = MAX (minimum, child_minimum);
130 natural = MAX (natural, child_natural);
135 self->cell_height = natural;
137 minimum += (self->spacing * (n_children - 1));
138 natural += (self->spacing * (n_children - 1));
140 if (min_height_p != NULL)
141 *min_height_p = minimum;
143 if (nat_height_p != NULL)
144 *nat_height_p = natural;
148 get_items_per_row (MultiLayout *self,
156 if (self->cell_width <= 0)
159 n_columns = (int) ((for_width + self->spacing) / (self->cell_width + self->spacing));
161 return MAX (n_columns, 1);
165 get_visible_children (ClutterActor *actor)
167 ClutterActorIter iter;
169 int n_visible_children = 0;
171 clutter_actor_iter_init (&iter, actor);
172 while (clutter_actor_iter_next (&iter, &child))
174 if (CLUTTER_ACTOR_IS_VISIBLE (child))
175 n_visible_children += 1;
178 return n_visible_children;
182 multi_layout_allocate (ClutterLayoutManager *manager,
183 ClutterContainer *container,
184 const ClutterActorBox *allocation,
185 ClutterAllocationFlags flags)
187 MultiLayout *self = (MultiLayout *) manager;
188 float avail_width, avail_height;
189 float x_offset, y_offset;
190 ClutterActorIter iter;
192 float item_x = 0.f, item_y = 0.f;
193 int n_items, n_items_per_row = 0, item_index;
194 ClutterPoint center = CLUTTER_POINT_INIT_ZERO;
195 double radius = 0, theta = 0;
196 gboolean use_animations;
197 ClutterAnimationMode easing_mode;
198 guint easing_duration, easing_delay;
200 n_items = get_visible_children (CLUTTER_ACTOR (container));
204 clutter_actor_box_get_origin (allocation, &x_offset, &y_offset);
205 clutter_actor_box_get_size (allocation, &avail_width, &avail_height);
207 /* ensure we have an updated value of cell_width and cell_height */
208 multi_layout_get_preferred_width (manager, container, avail_width, NULL, NULL);
209 multi_layout_get_preferred_height (manager, container, avail_height, NULL, NULL);
213 if (self->state == MULTI_LAYOUT_GRID)
215 n_items_per_row = get_items_per_row (self, avail_width);
219 else if (self->state == MULTI_LAYOUT_CIRCLE)
221 center.x = allocation->x2 / 2.f;
222 center.y = allocation->y2 / 2.f;
223 radius = MIN ((avail_width - self->cell_width) / 2.0,
224 (avail_height - self->cell_height) / 2.0);
227 use_animations = clutter_layout_manager_get_easing_state (manager,
232 clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container));
233 while (clutter_actor_iter_next (&iter, &child))
235 ClutterActorBox child_allocation = CLUTTER_ACTOR_BOX_INIT (0, 0, 0, 0);
237 if (!CLUTTER_ACTOR_IS_VISIBLE (child))
240 if (self->state == MULTI_LAYOUT_GRID)
242 if (item_index == n_items_per_row)
246 item_y += self->cell_height + self->spacing;
249 child_allocation.x1 = item_x;
250 child_allocation.y1 = item_y;
251 child_allocation.x2 = child_allocation.x1 + self->cell_width;
252 child_allocation.y2 = child_allocation.y1 + self->cell_height;
254 item_x += self->cell_width + self->spacing;
256 else if (self->state == MULTI_LAYOUT_CIRCLE)
258 theta = 2.0 * G_PI / n_items * item_index;
259 child_allocation.x1 = center.x + radius * sinf (theta) - (self->cell_width / 2.f);
260 child_allocation.y1 = center.y + radius * -cosf (theta) - (self->cell_height / 2.f);
261 child_allocation.x2 = child_allocation.x1 + self->cell_width;
262 child_allocation.y2 = child_allocation.y1 + self->cell_height;
267 clutter_actor_save_easing_state (child);
268 clutter_actor_set_easing_mode (child, easing_mode);
269 clutter_actor_set_easing_duration (child, easing_duration);
270 clutter_actor_set_easing_delay (child, easing_delay);
273 clutter_actor_allocate (child, &child_allocation, flags);
276 clutter_actor_restore_easing_state (child);
283 multi_layout_class_init (MultiLayoutClass *klass)
285 ClutterLayoutManagerClass *manager_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass);
287 manager_class->get_preferred_width = multi_layout_get_preferred_width;
288 manager_class->get_preferred_height = multi_layout_get_preferred_height;
289 manager_class->allocate = multi_layout_allocate;
293 multi_layout_init (MultiLayout *self)
295 self->state = MULTI_LAYOUT_GRID;
297 self->cell_width = -1.f;
298 self->cell_height = -1.f;
303 ClutterLayoutManager *
304 multi_layout_new (void)
306 return g_object_new (multi_layout_get_type (), NULL);
310 multi_layout_set_state (MultiLayout *self,
311 MultiLayoutState state)
313 if (self->state == state)
318 clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (self));
322 multi_layout_set_spacing (MultiLayout *self,
325 self->spacing = spacing;
327 clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (self));
331 #define RECT_SIZE 64.0
334 #define BOX_SIZE (RECT_SIZE * (N_RECTS / N_ROWS) + PADDING * (N_RECTS / N_ROWS - 1))
337 on_key_press (ClutterActor *stage,
341 guint keysym = clutter_event_get_key_symbol (event);
342 MultiLayout *layout = (MultiLayout *) clutter_actor_get_layout_manager (box);
344 if (keysym == CLUTTER_KEY_q)
346 clutter_main_quit ();
347 return CLUTTER_EVENT_STOP;
353 multi_layout_set_state (layout, MULTI_LAYOUT_GRID);
357 multi_layout_set_state (layout, MULTI_LAYOUT_CIRCLE);
364 return CLUTTER_EVENT_STOP;
368 main (int argc, char *argv[])
370 ClutterActor *stage, *box, *label;
371 ClutterLayoutManager *manager;
372 ClutterMargin margin;
375 if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
378 stage = clutter_stage_new ();
379 clutter_stage_set_title (CLUTTER_STAGE (stage), "Multi-layout");
380 g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
381 clutter_actor_show (stage);
383 manager = multi_layout_new ();
384 multi_layout_set_spacing ((MultiLayout *) manager, PADDING);
385 clutter_layout_manager_set_use_animations (manager, TRUE);
387 margin.top = margin.bottom = margin.left = margin.right = PADDING;
389 box = clutter_actor_new ();
390 clutter_actor_set_margin (box, &margin);
391 clutter_actor_set_layout_manager (box, manager);
392 clutter_actor_set_size (box, BOX_SIZE, BOX_SIZE);
393 clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
394 clutter_actor_add_child (stage, box);
396 for (i = 0; i < N_RECTS; i++)
398 ClutterActor *rect = clutter_actor_new ();
401 clutter_color_from_hls (&color,
406 color.alpha = 128 + 128 / N_RECTS * i;
408 clutter_actor_set_size (rect, RECT_SIZE, RECT_SIZE);
409 clutter_actor_set_background_color (rect, &color);
410 clutter_actor_add_child (box, rect);
413 label = clutter_text_new ();
414 clutter_text_set_text (CLUTTER_TEXT (label),
415 "Press g\t\342\236\236\tGrid layout\n"
416 "Press c\t\342\236\236\tCircular layout\n"
417 "Press q\t\342\236\236\tQuit");
418 clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
419 clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.95));
420 clutter_actor_add_child (stage, label);
422 g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), box);