1 | /* Benchmark/Scrolling |
2 | * #Keywords: GtkScrolledWindow |
3 | * |
4 | * This demo scrolls a view with various content. |
5 | */ |
6 | |
7 | #include <gtk/gtk.h> |
8 | |
9 | static guint tick_cb; |
10 | static GtkAdjustment *hadjustment; |
11 | static GtkAdjustment *vadjustment; |
12 | static GtkWidget *window = NULL; |
13 | static GtkWidget *scrolledwindow; |
14 | static int selected; |
15 | |
16 | #define N_WIDGET_TYPES 8 |
17 | |
18 | |
19 | static int hincrement = 5; |
20 | static int vincrement = 5; |
21 | |
22 | static gboolean |
23 | scroll_cb (GtkWidget *widget, |
24 | GdkFrameClock *frame_clock, |
25 | gpointer data) |
26 | { |
27 | double value; |
28 | |
29 | value = gtk_adjustment_get_value (adjustment: vadjustment); |
30 | if (value + vincrement <= gtk_adjustment_get_lower (adjustment: vadjustment) || |
31 | (value + vincrement >= gtk_adjustment_get_upper (adjustment: vadjustment) - gtk_adjustment_get_page_size (adjustment: vadjustment))) |
32 | vincrement = - vincrement; |
33 | |
34 | gtk_adjustment_set_value (adjustment: vadjustment, value: value + vincrement); |
35 | |
36 | value = gtk_adjustment_get_value (adjustment: hadjustment); |
37 | if (value + hincrement <= gtk_adjustment_get_lower (adjustment: hadjustment) || |
38 | (value + hincrement >= gtk_adjustment_get_upper (adjustment: hadjustment) - gtk_adjustment_get_page_size (adjustment: hadjustment))) |
39 | hincrement = - hincrement; |
40 | |
41 | gtk_adjustment_set_value (adjustment: hadjustment, value: value + hincrement); |
42 | |
43 | return G_SOURCE_CONTINUE; |
44 | } |
45 | |
46 | extern GtkWidget *create_icon (void); |
47 | |
48 | static void |
49 | populate_icons (void) |
50 | { |
51 | GtkWidget *grid; |
52 | int top, left; |
53 | |
54 | grid = gtk_grid_new (); |
55 | gtk_widget_set_halign (widget: grid, align: GTK_ALIGN_CENTER); |
56 | gtk_widget_set_margin_start (widget: grid, margin: 10); |
57 | gtk_widget_set_margin_end (widget: grid, margin: 10); |
58 | gtk_widget_set_margin_top (widget: grid, margin: 10); |
59 | gtk_widget_set_margin_bottom (widget: grid, margin: 10); |
60 | gtk_grid_set_row_spacing (GTK_GRID (grid), spacing: 10); |
61 | gtk_grid_set_column_spacing (GTK_GRID (grid), spacing: 10); |
62 | |
63 | for (top = 0; top < 100; top++) |
64 | for (left = 0; left < 15; left++) |
65 | gtk_grid_attach (GTK_GRID (grid), child: create_icon (), column: left, row: top, width: 1, height: 1); |
66 | |
67 | hincrement = 0; |
68 | vincrement = 5; |
69 | |
70 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), |
71 | hscrollbar_policy: GTK_POLICY_NEVER, |
72 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
73 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), child: grid); |
74 | } |
75 | |
76 | static char *content; |
77 | static gsize content_len; |
78 | |
79 | extern void fontify (const char *format, GtkTextBuffer *buffer); |
80 | |
81 | static void |
82 | populate_text (gboolean highlight) |
83 | { |
84 | GtkWidget *textview; |
85 | GtkTextBuffer *buffer; |
86 | |
87 | if (!content) |
88 | { |
89 | GBytes *bytes; |
90 | |
91 | bytes = g_resources_lookup_data (path: "/sources/font_features.c" , lookup_flags: 0, NULL); |
92 | content = g_bytes_unref_to_data (bytes, size: &content_len); |
93 | } |
94 | |
95 | buffer = gtk_text_buffer_new (NULL); |
96 | gtk_text_buffer_set_text (buffer, text: content, len: (int)content_len); |
97 | |
98 | if (highlight) |
99 | fontify (format: "c" , buffer); |
100 | |
101 | textview = gtk_text_view_new (); |
102 | gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer); |
103 | |
104 | hincrement = 0; |
105 | vincrement = 5; |
106 | |
107 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), |
108 | hscrollbar_policy: GTK_POLICY_NEVER, |
109 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
110 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), child: textview); |
111 | } |
112 | |
113 | static void |
114 | populate_emoji_text (void) |
115 | { |
116 | GtkWidget *textview; |
117 | GtkTextBuffer *buffer; |
118 | GString *s; |
119 | GtkTextIter iter; |
120 | |
121 | s = g_string_sized_new (dfl_size: 500 * 30 * 4); |
122 | |
123 | for (int i = 0; i < 500; i++) |
124 | { |
125 | if (i % 2) |
126 | g_string_append (string: s, val: "<span underline=\"single\" underline_color=\"red\">x</span>" ); |
127 | for (int j = 0; j < 30; j++) |
128 | { |
129 | g_string_append (string: s, val: "💓" ); |
130 | g_string_append (string: s, val: "<span underline=\"single\" underline_color=\"red\">x</span>" ); |
131 | } |
132 | g_string_append (string: s, val: "\n" ); |
133 | } |
134 | |
135 | buffer = gtk_text_buffer_new (NULL); |
136 | gtk_text_buffer_get_start_iter (buffer, iter: &iter); |
137 | gtk_text_buffer_insert_markup (buffer, iter: &iter, markup: s->str, len: s->len); |
138 | |
139 | g_string_free (string: s, TRUE); |
140 | |
141 | textview = gtk_text_view_new (); |
142 | gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer); |
143 | |
144 | hincrement = 0; |
145 | vincrement = 5; |
146 | |
147 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), |
148 | hscrollbar_policy: GTK_POLICY_NEVER, |
149 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
150 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), child: textview); |
151 | } |
152 | |
153 | static void |
154 | populate_image (void) |
155 | { |
156 | GtkWidget *image; |
157 | |
158 | if (!content) |
159 | { |
160 | GBytes *bytes; |
161 | |
162 | bytes = g_resources_lookup_data (path: "/sources/font_features.c" , lookup_flags: 0, NULL); |
163 | content = g_bytes_unref_to_data (bytes, size: &content_len); |
164 | } |
165 | |
166 | image = gtk_picture_new_for_resource (resource_path: "/sliding_puzzle/portland-rose.jpg" ); |
167 | gtk_picture_set_can_shrink (self: GTK_PICTURE (ptr: image), FALSE); |
168 | |
169 | hincrement = 5; |
170 | vincrement = 5; |
171 | |
172 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), |
173 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
174 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
175 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), child: image); |
176 | } |
177 | |
178 | extern GtkWidget *create_weather_view (void); |
179 | |
180 | static void |
181 | populate_list (void) |
182 | { |
183 | GtkWidget *list; |
184 | |
185 | list = create_weather_view (); |
186 | |
187 | hincrement = 5; |
188 | vincrement = 0; |
189 | |
190 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), |
191 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
192 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
193 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), child: list); |
194 | } |
195 | |
196 | extern GtkWidget *create_color_grid (void); |
197 | extern GListModel *gtk_color_list_new (guint size); |
198 | |
199 | static void |
200 | populate_grid (void) |
201 | { |
202 | GtkWidget *list; |
203 | GtkNoSelection *selection; |
204 | |
205 | list = create_color_grid (); |
206 | |
207 | selection = gtk_no_selection_new (model: gtk_color_list_new (size: 2097152)); |
208 | gtk_grid_view_set_model (GTK_GRID_VIEW (list), model: GTK_SELECTION_MODEL (ptr: selection)); |
209 | g_object_unref (object: selection); |
210 | |
211 | hincrement = 0; |
212 | vincrement = 5; |
213 | |
214 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), |
215 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
216 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
217 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), child: list); |
218 | } |
219 | |
220 | extern GtkWidget *create_ucd_view (GtkWidget *label); |
221 | |
222 | static void |
223 | populate_list2 (void) |
224 | { |
225 | GtkWidget *list; |
226 | |
227 | list = create_ucd_view (NULL); |
228 | |
229 | hincrement = 0; |
230 | vincrement = 5; |
231 | |
232 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), |
233 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, |
234 | vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
235 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), child: list); |
236 | } |
237 | |
238 | static void |
239 | set_widget_type (int type) |
240 | { |
241 | if (tick_cb) |
242 | gtk_widget_remove_tick_callback (widget: window, id: tick_cb); |
243 | |
244 | if (gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (scrolledwindow))) |
245 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), NULL); |
246 | |
247 | selected = type; |
248 | |
249 | switch (selected) |
250 | { |
251 | case 0: |
252 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling icons" ); |
253 | populate_icons (); |
254 | break; |
255 | |
256 | case 1: |
257 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling plain text" ); |
258 | populate_text (FALSE); |
259 | break; |
260 | |
261 | case 2: |
262 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling complex text" ); |
263 | populate_text (TRUE); |
264 | break; |
265 | |
266 | case 3: |
267 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling text with Emoji" ); |
268 | populate_emoji_text (); |
269 | break; |
270 | |
271 | case 4: |
272 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling a big image" ); |
273 | populate_image (); |
274 | break; |
275 | |
276 | case 5: |
277 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling a list" ); |
278 | populate_list (); |
279 | break; |
280 | |
281 | case 6: |
282 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling a columned list" ); |
283 | populate_list2 (); |
284 | break; |
285 | |
286 | case 7: |
287 | gtk_window_set_title (GTK_WINDOW (window), title: "Scrolling a grid" ); |
288 | populate_grid (); |
289 | break; |
290 | |
291 | default: |
292 | g_assert_not_reached (); |
293 | } |
294 | |
295 | tick_cb = gtk_widget_add_tick_callback (widget: window, callback: scroll_cb, NULL, NULL); |
296 | } |
297 | |
298 | G_MODULE_EXPORT void |
299 | iconscroll_next_clicked_cb (GtkButton *source, |
300 | gpointer user_data) |
301 | { |
302 | int new_index; |
303 | |
304 | if (selected + 1 >= N_WIDGET_TYPES) |
305 | new_index = 0; |
306 | else |
307 | new_index = selected + 1; |
308 | |
309 | |
310 | set_widget_type (new_index); |
311 | } |
312 | |
313 | G_MODULE_EXPORT void |
314 | iconscroll_prev_clicked_cb (GtkButton *source, |
315 | gpointer user_data) |
316 | { |
317 | int new_index; |
318 | |
319 | if (selected - 1 < 0) |
320 | new_index = N_WIDGET_TYPES - 1; |
321 | else |
322 | new_index = selected - 1; |
323 | |
324 | set_widget_type (new_index); |
325 | } |
326 | |
327 | static gboolean |
328 | update_fps (gpointer data) |
329 | { |
330 | GtkWidget *label = data; |
331 | GdkFrameClock *frame_clock; |
332 | double fps; |
333 | char *str; |
334 | |
335 | frame_clock = gtk_widget_get_frame_clock (widget: label); |
336 | |
337 | fps = gdk_frame_clock_get_fps (frame_clock); |
338 | str = g_strdup_printf (format: "%.2f fps" , fps); |
339 | gtk_label_set_label (GTK_LABEL (label), str); |
340 | g_free (mem: str); |
341 | |
342 | return G_SOURCE_CONTINUE; |
343 | } |
344 | |
345 | static void |
346 | remove_timeout (gpointer data) |
347 | { |
348 | g_source_remove (GPOINTER_TO_UINT (data)); |
349 | } |
350 | |
351 | G_MODULE_EXPORT GtkWidget * |
352 | do_iconscroll (GtkWidget *do_widget) |
353 | { |
354 | if (!window) |
355 | { |
356 | GtkBuilder *builder; |
357 | GtkWidget *label; |
358 | guint id; |
359 | |
360 | builder = gtk_builder_new_from_resource (resource_path: "/iconscroll/iconscroll.ui" ); |
361 | window = GTK_WIDGET (gtk_builder_get_object (builder, "window" )); |
362 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window); |
363 | gtk_window_set_display (GTK_WINDOW (window), |
364 | display: gtk_widget_get_display (widget: do_widget)); |
365 | |
366 | scrolledwindow = GTK_WIDGET (gtk_builder_get_object (builder, "scrolledwindow" )); |
367 | gtk_widget_realize (widget: window); |
368 | hadjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "hadjustment" )); |
369 | vadjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "vadjustment" )); |
370 | set_widget_type (0); |
371 | |
372 | label = GTK_WIDGET (gtk_builder_get_object (builder, "fps_label" )); |
373 | id = g_timeout_add (interval: 500, function: update_fps, data: label); |
374 | g_object_set_data_full (G_OBJECT (label), key: "timeout" , |
375 | GUINT_TO_POINTER (id), destroy: remove_timeout); |
376 | |
377 | g_object_unref (object: builder); |
378 | } |
379 | |
380 | if (!gtk_widget_get_visible (widget: window)) |
381 | gtk_widget_show (widget: window); |
382 | else |
383 | gtk_window_destroy (GTK_WINDOW (window)); |
384 | |
385 | return window; |
386 | } |
387 | |