1
2
3#include <gtk/gtk.h>
4
5static const char *css =
6"test>button {"
7" all: unset; "
8" background-color: white;"
9" border: 30px solid teal;"
10" margin: 40px;"
11" padding: 40px;"
12"}"
13"test>button:hover {"
14" background-color: blue;"
15"}"
16"test image {"
17" background-color: purple;"
18"}"
19;
20
21/* Just so we can avoid a signal */
22GtkWidget *transform_tester;
23GtkWidget *test_widget;
24GtkWidget *test_child;
25float scale = 1;
26gboolean do_picking = TRUE;
27
28static const GdkRGBA RED = {1, 0, 0, 0.4};
29static const GdkRGBA GREEN = {0, 1, 0, 0.7};
30static const GdkRGBA BLUE = {0, 0, 1, 0.4};
31static const GdkRGBA BLACK = {0, 0, 0, 1 };
32
33
34
35/* ######################################################################### */
36/* ############################## MatrixChooser ############################ */
37/* ######################################################################### */
38
39
40#define GTK_TYPE_MATRIX_CHOOSER (gtk_matrix_chooser_get_type ())
41G_DECLARE_FINAL_TYPE (GtkMatrixChooser, gtk_matrix_chooser, GTK, MATRIX_CHOOSER, GtkWidget)
42
43struct _GtkMatrixChooser
44{
45 GtkWidget parent_instance;
46};
47
48G_DEFINE_TYPE (GtkMatrixChooser, gtk_matrix_chooser, GTK_TYPE_WIDGET)
49
50static void
51gtk_matrix_chooser_init (GtkMatrixChooser *self)
52{
53}
54
55static void
56gtk_matrix_chooser_class_init (GtkMatrixChooserClass *klass)
57{
58
59}
60
61
62/* ######################################################################### */
63/* ############################# TransformTester ########################### */
64/* ######################################################################### */
65
66#define TEST_WIDGET_MIN_SIZE 100
67
68#define GTK_TYPE_TRANSFORM_TESTER (gtk_transform_tester_get_type ())
69G_DECLARE_FINAL_TYPE (GtkTransformTester, gtk_transform_tester, GTK, TRANSFORM_TESTER, GtkWidget);
70
71struct _GtkTransformTester
72{
73 GtkWidget parent_instance;
74
75 GtkWidget *test_widget;
76 int pick_increase;
77};
78
79G_DEFINE_TYPE (GtkTransformTester, gtk_transform_tester, GTK_TYPE_WIDGET);
80
81static void
82gtk_transform_tester_measure (GtkWidget *widget,
83 GtkOrientation orientation,
84 int for_size,
85 int *minimum,
86 int *natural,
87 int *minimum_baseline,
88 int *natural_baseline)
89{
90 GtkTransformTester *self = (GtkTransformTester *)widget;
91
92 if (self->test_widget)
93 {
94 gtk_widget_measure (widget: self->test_widget, orientation, for_size,
95 minimum, natural, NULL, NULL);
96 }
97}
98
99static void
100gtk_transform_tester_size_allocate (GtkWidget *widget,
101 int width,
102 int height,
103 int baseline)
104{
105 GtkTransformTester *self = (GtkTransformTester *)widget;
106 GskTransform *global_transform;
107 int w, h;
108
109 if (!self->test_widget)
110 return;
111
112 scale += 2.5f;
113
114 gtk_widget_measure (widget: self->test_widget, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1,
115 minimum: &w, NULL, NULL, NULL);
116 gtk_widget_measure (widget: self->test_widget, orientation: GTK_ORIENTATION_VERTICAL, for_size: w,
117 minimum: &h, NULL, NULL, NULL);
118
119 g_message ("%s: %d, %d", __FUNCTION__, w, h);
120
121 global_transform = NULL;
122
123 global_transform = gsk_transform_translate (next: global_transform, point: &GRAPHENE_POINT_INIT (width / 2.0f, height / 2.0f));
124 global_transform = gsk_transform_rotate (next: global_transform, angle: scale);
125 global_transform = gsk_transform_translate (next: global_transform, point: &GRAPHENE_POINT_INIT (-w / 2.0f, -h / 2.0f));
126
127 gtk_widget_allocate (widget: self->test_widget,
128 width: w, height: h,
129 baseline: -1,
130 transform: global_transform);
131}
132
133static void
134gtk_transform_tester_snapshot (GtkWidget *widget,
135 GtkSnapshot *snapshot)
136{
137 GtkTransformTester *self = (GtkTransformTester *)widget;
138 const int width = gtk_widget_get_width (widget);
139 const int height = gtk_widget_get_height (widget);
140 const int inc = self->pick_increase;
141 graphene_rect_t child_bounds;
142 graphene_rect_t self_bounds;
143 int x, y;
144
145 GTK_WIDGET_CLASS (gtk_transform_tester_parent_class)->snapshot (widget, snapshot);
146
147 if (!do_picking ||
148 !gtk_widget_compute_bounds (widget: self->test_widget, target: widget, out_bounds: &child_bounds) ||
149 !gtk_widget_compute_bounds (widget: self->test_widget, target: self->test_widget, out_bounds: &self_bounds))
150 return;
151
152 {
153 const struct {
154 graphene_point_t coords;
155 GdkRGBA color;
156 } points[4] = {
157 { self_bounds.origin, {1, 0, 0, 1} },
158 { GRAPHENE_POINT_INIT (self_bounds.origin.x + self_bounds.size.width, self_bounds.origin.y), {0, 1, 0, 1} },
159 { GRAPHENE_POINT_INIT (self_bounds.origin.x + self_bounds.size.width, self_bounds.origin.y + self_bounds.size.height), {0, 0, 1, 1} },
160 { GRAPHENE_POINT_INIT (self_bounds.origin.x, self_bounds.origin.y + self_bounds.size.height), {1, 0, 1, 1} }
161 };
162
163 for (x = 0; x < G_N_ELEMENTS (points); x ++)
164 {
165 double px, py;
166
167 gtk_widget_translate_coordinates (src_widget: self->test_widget, dest_widget: widget,
168 src_x: points[x].coords.x, src_y: points[x].coords.y,
169 dest_x: &px, dest_y: &py);
170
171 gtk_snapshot_append_color (snapshot, color: &points[x].color,
172 bounds: &GRAPHENE_RECT_INIT (px, py,
173 4,
174 4));
175 }
176 }
177
178 /* Now add custom drawing */
179 for (x = 0; x < width; x += inc)
180 {
181 for (y = 0; y < height; y += inc)
182 {
183 const float px = x;
184 const float py = y;
185 GtkWidget *picked;
186#if 1
187 picked = gtk_widget_pick (widget, x: px, y: py, flags: GTK_PICK_DEFAULT);
188#else
189 {
190 int dx, dy;
191 gtk_widget_translate_coordinates (widget, self->test_widget, px, py, &dx, &dy);
192 picked = gtk_widget_pick (self->test_widget, dx, dy, GTK_PICK_DEFAULT);
193 }
194#endif
195
196 if (picked == self->test_widget)
197 gtk_snapshot_append_color (snapshot, color: &GREEN,
198 bounds: &GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
199 else if (picked == test_child)
200 gtk_snapshot_append_color (snapshot, color: &BLUE,
201 bounds: &GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
202
203 else
204 gtk_snapshot_append_color (snapshot, color: &RED,
205 bounds: &GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
206 }
207 }
208
209 gtk_snapshot_append_color (snapshot, color: &BLACK,
210 bounds: &GRAPHENE_RECT_INIT (child_bounds.origin.x,
211 child_bounds.origin.y,
212 child_bounds.size.width,
213 1));
214
215 gtk_snapshot_append_color (snapshot, color: &BLACK,
216 bounds: &GRAPHENE_RECT_INIT (child_bounds.origin.x + child_bounds.size.width,
217 child_bounds.origin.y,
218 1,
219 child_bounds.size.height));
220
221 gtk_snapshot_append_color (snapshot, color: &BLACK,
222 bounds: &GRAPHENE_RECT_INIT (child_bounds.origin.x,
223 child_bounds.origin.y + child_bounds.size.height,
224 child_bounds.size.width,
225 1));
226
227 gtk_snapshot_append_color (snapshot, color: &BLACK,
228 bounds: &GRAPHENE_RECT_INIT (child_bounds.origin.x,
229 child_bounds.origin.y,
230 1,
231 child_bounds.size.height));
232}
233
234static void
235gtk_transform_tester_init (GtkTransformTester *self)
236{
237 self->pick_increase = 4;
238}
239
240static void
241gtk_transform_tester_class_init (GtkTransformTesterClass *klass)
242{
243 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
244
245 widget_class->measure = gtk_transform_tester_measure;
246 widget_class->size_allocate = gtk_transform_tester_size_allocate;
247 widget_class->snapshot = gtk_transform_tester_snapshot;
248
249 gtk_widget_class_set_css_name (widget_class, name: "test");
250}
251
252static gboolean
253tick_cb (GtkWidget *widget,
254 GdkFrameClock *frame_clock,
255 gpointer user_data)
256{
257 gtk_widget_queue_allocate (widget);
258
259 return G_SOURCE_CONTINUE;
260}
261
262static void
263gtk_transform_tester_set_test_widget (GtkTransformTester *self,
264 GtkWidget *widget)
265{
266 g_assert (!self->test_widget);
267
268 self->test_widget = widget;
269 gtk_widget_set_parent (widget, parent: (GtkWidget *)self);
270
271 gtk_widget_add_tick_callback (GTK_WIDGET (self), callback: tick_cb, NULL, NULL);
272}
273
274static void
275toggled_cb (GtkToggleButton *source,
276 gpointer user_data)
277{
278 do_picking = gtk_toggle_button_get_active (toggle_button: source);
279}
280
281static void
282quit_cb (GtkWidget *widget,
283 gpointer data)
284{
285 gboolean *done = data;
286
287 *done = TRUE;
288
289 g_main_context_wakeup (NULL);
290}
291
292int
293main (int argc, char **argv)
294{
295 GtkWidget *window;
296 GtkWidget *matrix_chooser;
297 GtkWidget *box;
298 GtkWidget *titlebar;
299 GtkWidget *toggle_button;
300 GtkCssProvider *provider;
301 gboolean done = FALSE;
302
303 gtk_init ();
304
305 provider = gtk_css_provider_new ();
306 gtk_css_provider_load_from_data (css_provider: provider, data: css, length: -1);
307 gtk_style_context_add_provider_for_display (display: gdk_display_get_default (),
308 GTK_STYLE_PROVIDER (provider),
309 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
310
311 window = gtk_window_new ();
312 matrix_chooser = g_object_new (GTK_TYPE_MATRIX_CHOOSER, NULL);
313 transform_tester = g_object_new (GTK_TYPE_TRANSFORM_TESTER, NULL);
314 box = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 12);
315 titlebar = gtk_header_bar_new ();
316
317 gtk_window_set_titlebar (GTK_WINDOW (window), titlebar);
318
319 toggle_button = gtk_toggle_button_new ();
320 gtk_button_set_label (GTK_BUTTON (toggle_button), label: "Picking");
321 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_button), is_active: do_picking);
322 g_signal_connect (toggle_button, "toggled", G_CALLBACK (toggled_cb), NULL);
323 gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), child: toggle_button);
324
325 test_widget = gtk_button_new ();
326 gtk_widget_set_size_request (widget: test_widget, TEST_WIDGET_MIN_SIZE, TEST_WIDGET_MIN_SIZE);
327 gtk_widget_set_halign (widget: test_widget, align: GTK_ALIGN_CENTER);
328 gtk_widget_set_valign (widget: test_widget, align: GTK_ALIGN_CENTER);
329
330
331 test_child = gtk_image_new_from_icon_name (icon_name: "weather-clear");
332 gtk_widget_set_halign (widget: test_child, align: GTK_ALIGN_CENTER);
333 gtk_widget_set_valign (widget: test_child, align: GTK_ALIGN_CENTER);
334 gtk_widget_set_size_request (widget: test_child, TEST_WIDGET_MIN_SIZE / 2, TEST_WIDGET_MIN_SIZE / 2);
335 gtk_button_set_child (GTK_BUTTON (test_widget), child: test_child);
336
337
338 gtk_transform_tester_set_test_widget (self: GTK_TRANSFORM_TESTER (ptr: transform_tester), widget: test_widget);
339
340 gtk_widget_set_vexpand (widget: transform_tester, TRUE);
341 gtk_box_append (GTK_BOX (box), child: transform_tester);
342 gtk_box_append (GTK_BOX (box), child: matrix_chooser);
343 gtk_window_set_child (GTK_WINDOW (window), child: box);
344
345 gtk_window_set_default_size (window: (GtkWindow *)window, width: 200, height: 200);
346 g_signal_connect (window, "close-request", G_CALLBACK (quit_cb), &done);
347 gtk_widget_show (widget: window);
348
349 while (!done)
350 g_main_context_iteration (NULL, TRUE);
351
352 return 0;
353}
354

source code of gtk/tests/testwidgettransforms.c