1#include "demolayout.h"
2
3struct _DemoLayout
4{
5 GtkLayoutManager parent_instance;
6
7 float position;
8 int pos[16];
9};
10
11struct _DemoLayoutClass
12{
13 GtkLayoutManagerClass parent_class;
14};
15
16G_DEFINE_TYPE (DemoLayout, demo_layout, GTK_TYPE_LAYOUT_MANAGER)
17
18static void
19demo_layout_measure (GtkLayoutManager *layout_manager,
20 GtkWidget *widget,
21 GtkOrientation orientation,
22 int for_size,
23 int *minimum,
24 int *natural,
25 int *minimum_baseline,
26 int *natural_baseline)
27{
28 GtkWidget *child;
29 int minimum_size = 0;
30 int natural_size = 0;
31
32 for (child = gtk_widget_get_first_child (widget);
33 child != NULL;
34 child = gtk_widget_get_next_sibling (widget: child))
35 {
36 int child_min = 0, child_nat = 0;
37
38 if (!gtk_widget_should_layout (widget: child))
39 continue;
40
41 gtk_widget_measure (widget: child, orientation, for_size: -1,
42 minimum: &child_min, natural: &child_nat,
43 NULL, NULL);
44 minimum_size = MAX (minimum_size, child_min);
45 natural_size = MAX (natural_size, child_nat);
46 }
47
48 /* A back-of-a-napkin calculation to reserve enough
49 * space for arranging 16 children in a circle.
50 */
51 *minimum = 16 * minimum_size / G_PI + minimum_size;
52 *natural = 16 * natural_size / G_PI + natural_size;
53}
54
55static void
56demo_layout_allocate (GtkLayoutManager *layout_manager,
57 GtkWidget *widget,
58 int width,
59 int height,
60 int baseline)
61{
62 DemoLayout *self = DEMO_LAYOUT (ptr: layout_manager);
63 GtkWidget *child;
64 int i;
65 int child_width = 0;
66 int child_height = 0;
67 int x0, y0;
68 float r;
69 float t;
70
71 t = self->position;
72
73 for (child = gtk_widget_get_first_child (widget);
74 child != NULL;
75 child = gtk_widget_get_next_sibling (widget: child))
76 {
77 GtkRequisition child_req;
78
79 if (!gtk_widget_should_layout (widget: child))
80 continue;
81
82 gtk_widget_get_preferred_size (widget: child, minimum_size: &child_req, NULL);
83
84 child_width = MAX (child_width, child_req.width);
85 child_height = MAX (child_height, child_req.height);
86 }
87
88 /* the center of our layout */
89 x0 = (width / 2);
90 y0 = (height / 2);
91
92 /* the radius for our circle of children */
93 r = 8 * child_width / G_PI;
94
95 for (child = gtk_widget_get_first_child (widget), i = 0;
96 child != NULL;
97 child = gtk_widget_get_next_sibling (widget: child), i++)
98 {
99 GtkRequisition child_req;
100 float a = self->pos[i] * G_PI / 8;
101 int gx, gy;
102 int cx, cy;
103 int x, y;
104
105 if (!gtk_widget_should_layout (widget: child))
106 continue;
107
108 gtk_widget_get_preferred_size (widget: child, minimum_size: &child_req, NULL);
109
110 /* The grid position of child. */
111 gx = x0 + (i % 4 - 2) * child_width;
112 gy = y0 + (i / 4 - 2) * child_height;
113
114 /* The circle position of child. Note that we
115 * are adjusting the position by half the child size
116 * to place the center of child on a centered circle.
117 * This assumes that the children don't use align flags
118 * or uneven margins that would shift the center.
119 */
120 cx = x0 + sin (x: a) * r - child_req.width / 2;
121 cy = y0 + cos (x: a) * r - child_req.height / 2;
122
123 /* we interpolate between the two layouts according to
124 * the position value that has been set on the layout.
125 */
126 x = t * cx + (1 - t) * gx;
127 y = t * cy + (1 - t) * gy;
128
129 gtk_widget_size_allocate (widget: child,
130 allocation: &(const GtkAllocation){ x, y, child_width, child_height},
131 baseline: -1);
132 }
133}
134
135static GtkSizeRequestMode
136demo_layout_get_request_mode (GtkLayoutManager *layout_manager,
137 GtkWidget *widget)
138{
139 return GTK_SIZE_REQUEST_CONSTANT_SIZE;
140}
141
142static void
143demo_layout_class_init (DemoLayoutClass *klass)
144{
145 GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (ptr: klass);
146
147 layout_class->get_request_mode = demo_layout_get_request_mode;
148 layout_class->measure = demo_layout_measure;
149 layout_class->allocate = demo_layout_allocate;
150}
151
152static void
153demo_layout_init (DemoLayout *self)
154{
155 int i;
156
157 for (i = 0; i < 16; i++)
158 self->pos[i] = i;
159}
160
161GtkLayoutManager *
162demo_layout_new (void)
163{
164 return g_object_new (DEMO_TYPE_LAYOUT, NULL);
165}
166
167void
168demo_layout_set_position (DemoLayout *layout,
169 float position)
170{
171 layout->position = position;
172}
173
174/* Shuffle the circle positions of the children.
175 * Should be called when we are in the grid layout.
176 */
177void
178demo_layout_shuffle (DemoLayout *layout)
179{
180 int i, j, tmp;
181
182 for (i = 0; i < 16; i++)
183 {
184 j = g_random_int_range (begin: 0, end: i + 1);
185 tmp = layout->pos[i];
186 layout->pos[i] = layout->pos[j];
187 layout->pos[j] = tmp;
188 }
189}
190

source code of gtk/demos/gtk-demo/demolayout.c