1 | /* Lists/Characters |
2 | * |
3 | * This demo shows a multi-column representation of some parts |
4 | * of the Unicode Character Database, or UCD. |
5 | * |
6 | * The dataset used here has 33 796 items. |
7 | */ |
8 | |
9 | #include <gtk/gtk.h> |
10 | #include "script-names.h" |
11 | #include "unicode-names.h" |
12 | |
13 | |
14 | #define UCD_TYPE_ITEM (ucd_item_get_type ()) |
15 | G_DECLARE_FINAL_TYPE (UcdItem, ucd_item, UCD, ITEM, GObject) |
16 | |
17 | struct _UcdItem |
18 | { |
19 | GObject parent_instance; |
20 | gunichar codepoint; |
21 | const char *name; |
22 | }; |
23 | |
24 | struct _UcdItemClass |
25 | { |
26 | GObjectClass parent_class; |
27 | }; |
28 | |
29 | G_DEFINE_TYPE (UcdItem, ucd_item, G_TYPE_OBJECT) |
30 | |
31 | static void |
32 | ucd_item_init (UcdItem *item) |
33 | { |
34 | } |
35 | |
36 | static void |
37 | ucd_item_class_init (UcdItemClass *class) |
38 | { |
39 | } |
40 | |
41 | static UcdItem * |
42 | ucd_item_new (gunichar codepoint, |
43 | const char *name) |
44 | { |
45 | UcdItem *item; |
46 | |
47 | item = g_object_new (UCD_TYPE_ITEM, NULL); |
48 | |
49 | item->codepoint = codepoint; |
50 | item->name = name; |
51 | |
52 | return item; |
53 | } |
54 | |
55 | static gunichar |
56 | ucd_item_get_codepoint (UcdItem *item) |
57 | { |
58 | return item->codepoint; |
59 | } |
60 | |
61 | static const char * |
62 | ucd_item_get_name (UcdItem *item) |
63 | { |
64 | return item->name; |
65 | } |
66 | |
67 | static GListModel * |
68 | ucd_model_new (void) |
69 | { |
70 | GBytes *bytes; |
71 | GVariant *v; |
72 | GVariantIter *iter; |
73 | GListStore *store; |
74 | guint u; |
75 | char *name; |
76 | |
77 | bytes = g_resources_lookup_data (path: "/listview_ucd_data/ucdnames.data" , lookup_flags: 0, NULL); |
78 | v = g_variant_ref_sink (value: g_variant_new_from_bytes (G_VARIANT_TYPE ("a(us)" ), bytes, TRUE)); |
79 | |
80 | iter = g_variant_iter_new (value: v); |
81 | |
82 | store = g_list_store_new (G_TYPE_OBJECT); |
83 | while (g_variant_iter_next (iter, format_string: "(u&s)" , &u, &name)) |
84 | { |
85 | if (u == 0) |
86 | continue; |
87 | |
88 | UcdItem *item = ucd_item_new (codepoint: u, name); |
89 | g_list_store_append (store, item); |
90 | g_object_unref (object: item); |
91 | } |
92 | |
93 | g_variant_iter_free (iter); |
94 | g_variant_unref (value: v); |
95 | g_bytes_unref (bytes); |
96 | |
97 | return G_LIST_MODEL (ptr: store); |
98 | } |
99 | |
100 | static void |
101 | setup_centered_label (GtkSignalListItemFactory *factory, |
102 | GObject *listitem) |
103 | { |
104 | GtkWidget *label; |
105 | label = gtk_label_new (str: "" ); |
106 | gtk_list_item_set_child (GTK_LIST_ITEM (listitem), child: label); |
107 | } |
108 | |
109 | static void |
110 | setup_label (GtkSignalListItemFactory *factory, |
111 | GObject *listitem) |
112 | { |
113 | GtkWidget *label; |
114 | label = gtk_label_new (str: "" ); |
115 | gtk_label_set_xalign (GTK_LABEL (label), xalign: 0); |
116 | gtk_list_item_set_child (GTK_LIST_ITEM (listitem), child: label); |
117 | } |
118 | |
119 | static void |
120 | setup_ellipsizing_label (GtkSignalListItemFactory *factory, |
121 | GObject *listitem) |
122 | { |
123 | GtkWidget *label; |
124 | label = gtk_label_new (str: "" ); |
125 | gtk_label_set_xalign (GTK_LABEL (label), xalign: 0); |
126 | gtk_label_set_ellipsize (GTK_LABEL (label), mode: PANGO_ELLIPSIZE_END); |
127 | gtk_label_set_width_chars (GTK_LABEL (label), n_chars: 20); |
128 | gtk_list_item_set_child (GTK_LIST_ITEM (listitem), child: label); |
129 | } |
130 | |
131 | static void |
132 | bind_codepoint (GtkSignalListItemFactory *factory, |
133 | GObject *listitem) |
134 | { |
135 | GtkWidget *label; |
136 | GObject *item; |
137 | gunichar codepoint; |
138 | char buffer[16] = { 0, }; |
139 | |
140 | label = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); |
141 | item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); |
142 | codepoint = ucd_item_get_codepoint (item: UCD_ITEM (ptr: item)); |
143 | |
144 | g_snprintf (string: buffer, n: 10, format: "%#06x" , codepoint); |
145 | gtk_label_set_label (GTK_LABEL (label), str: buffer); |
146 | } |
147 | |
148 | static void |
149 | bind_char (GtkSignalListItemFactory *factory, |
150 | GObject *listitem) |
151 | { |
152 | GtkWidget *label; |
153 | GObject *item; |
154 | gunichar codepoint; |
155 | char buffer[16] = { 0, }; |
156 | |
157 | label = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); |
158 | item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); |
159 | codepoint = ucd_item_get_codepoint (item: UCD_ITEM (ptr: item)); |
160 | |
161 | if (g_unichar_isprint (c: codepoint)) |
162 | g_unichar_to_utf8 (c: codepoint, outbuf: buffer); |
163 | |
164 | gtk_label_set_label (GTK_LABEL (label), str: buffer); |
165 | } |
166 | |
167 | static void |
168 | bind_name (GtkSignalListItemFactory *factory, |
169 | GObject *listitem) |
170 | { |
171 | GtkWidget *label; |
172 | GObject *item; |
173 | const char *name; |
174 | |
175 | label = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); |
176 | item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); |
177 | name = ucd_item_get_name (item: UCD_ITEM (ptr: item)); |
178 | |
179 | gtk_label_set_label (GTK_LABEL (label), str: name); |
180 | } |
181 | |
182 | static void |
183 | bind_type (GtkSignalListItemFactory *factory, |
184 | GObject *listitem) |
185 | { |
186 | GtkWidget *label; |
187 | GObject *item; |
188 | gunichar codepoint; |
189 | |
190 | label = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); |
191 | item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); |
192 | codepoint = ucd_item_get_codepoint (item: UCD_ITEM (ptr: item)); |
193 | |
194 | gtk_label_set_label (GTK_LABEL (label), str: get_unicode_type_name (type: g_unichar_type (c: codepoint))); |
195 | } |
196 | |
197 | static void |
198 | bind_break_type (GtkSignalListItemFactory *factory, |
199 | GObject *listitem) |
200 | { |
201 | GtkWidget *label; |
202 | GObject *item; |
203 | gunichar codepoint; |
204 | |
205 | label = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); |
206 | item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); |
207 | codepoint = ucd_item_get_codepoint (item: UCD_ITEM (ptr: item)); |
208 | |
209 | gtk_label_set_label (GTK_LABEL (label), str: get_break_type_name (type: g_unichar_break_type (c: codepoint))); |
210 | } |
211 | |
212 | static void |
213 | bind_combining_class (GtkSignalListItemFactory *factory, |
214 | GObject *listitem) |
215 | { |
216 | GtkWidget *label; |
217 | GObject *item; |
218 | gunichar codepoint; |
219 | |
220 | label = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); |
221 | item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); |
222 | codepoint = ucd_item_get_codepoint (item: UCD_ITEM (ptr: item)); |
223 | |
224 | gtk_label_set_label (GTK_LABEL (label), str: get_combining_class_name (cclass: g_unichar_combining_class (uc: codepoint))); |
225 | } |
226 | |
227 | static void |
228 | bind_script (GtkSignalListItemFactory *factory, |
229 | GObject *listitem) |
230 | { |
231 | GtkWidget *label; |
232 | GObject *item; |
233 | gunichar codepoint; |
234 | GUnicodeScript script; |
235 | |
236 | label = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); |
237 | item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); |
238 | codepoint = ucd_item_get_codepoint (item: UCD_ITEM (ptr: item)); |
239 | script = g_unichar_get_script (ch: codepoint); |
240 | |
241 | gtk_label_set_label (GTK_LABEL (label), str: get_script_name (script)); |
242 | } |
243 | |
244 | static void |
245 | selection_changed (GObject *object, |
246 | GParamSpec *pspec, |
247 | GtkWidget *label) |
248 | { |
249 | UcdItem *item; |
250 | guint codepoint; |
251 | char buffer[16] = { 0, }; |
252 | |
253 | item = gtk_single_selection_get_selected_item (self: GTK_SINGLE_SELECTION (ptr: object)); |
254 | codepoint = ucd_item_get_codepoint (item); |
255 | |
256 | if (g_unichar_isprint (c: codepoint)) |
257 | g_unichar_to_utf8 (c: codepoint, outbuf: buffer); |
258 | |
259 | gtk_label_set_label (GTK_LABEL (label), str: buffer); |
260 | } |
261 | |
262 | GtkWidget * |
263 | create_ucd_view (GtkWidget *label) |
264 | { |
265 | GtkWidget *cv; |
266 | GListModel *ucd_model; |
267 | GtkSingleSelection *selection; |
268 | GtkListItemFactory *factory; |
269 | GtkColumnViewColumn *column; |
270 | |
271 | ucd_model = ucd_model_new (); |
272 | |
273 | selection = gtk_single_selection_new (model: ucd_model); |
274 | gtk_single_selection_set_autoselect (self: selection, TRUE); |
275 | gtk_single_selection_set_can_unselect (self: selection, FALSE); |
276 | if (label) |
277 | g_signal_connect (selection, "notify::selected" , G_CALLBACK (selection_changed), label); |
278 | |
279 | cv = gtk_column_view_new (model: GTK_SELECTION_MODEL (ptr: selection)); |
280 | gtk_column_view_set_show_column_separators (GTK_COLUMN_VIEW (cv), TRUE); |
281 | |
282 | factory = gtk_signal_list_item_factory_new (); |
283 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_centered_label), NULL); |
284 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_codepoint), NULL); |
285 | column = gtk_column_view_column_new (title: "Codepoint" , factory); |
286 | gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column); |
287 | g_object_unref (object: column); |
288 | |
289 | factory = gtk_signal_list_item_factory_new (); |
290 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_centered_label), NULL); |
291 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_char), NULL); |
292 | column = gtk_column_view_column_new (title: "Char" , factory); |
293 | gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column); |
294 | g_object_unref (object: column); |
295 | |
296 | factory = gtk_signal_list_item_factory_new (); |
297 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_ellipsizing_label), NULL); |
298 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_name), NULL); |
299 | column = gtk_column_view_column_new (title: "Name" , factory); |
300 | gtk_column_view_column_set_resizable (self: column, TRUE); |
301 | gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column); |
302 | g_object_unref (object: column); |
303 | |
304 | factory = gtk_signal_list_item_factory_new (); |
305 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_ellipsizing_label), NULL); |
306 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_type), NULL); |
307 | column = gtk_column_view_column_new (title: "Type" , factory); |
308 | gtk_column_view_column_set_resizable (self: column, TRUE); |
309 | gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column); |
310 | g_object_unref (object: column); |
311 | |
312 | factory = gtk_signal_list_item_factory_new (); |
313 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_ellipsizing_label), NULL); |
314 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_break_type), NULL); |
315 | column = gtk_column_view_column_new (title: "Break Type" , factory); |
316 | gtk_column_view_column_set_resizable (self: column, TRUE); |
317 | gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column); |
318 | g_object_unref (object: column); |
319 | |
320 | factory = gtk_signal_list_item_factory_new (); |
321 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_label), NULL); |
322 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_combining_class), NULL); |
323 | column = gtk_column_view_column_new (title: "Combining Class" , factory); |
324 | gtk_column_view_column_set_resizable (self: column, TRUE); |
325 | gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column); |
326 | g_object_unref (object: column); |
327 | |
328 | factory = gtk_signal_list_item_factory_new (); |
329 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_label), NULL); |
330 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_script), NULL); |
331 | column = gtk_column_view_column_new (title: "Script" , factory); |
332 | gtk_column_view_column_set_resizable (self: column, TRUE); |
333 | gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column); |
334 | g_object_unref (object: column); |
335 | |
336 | return cv; |
337 | } |
338 | |
339 | static GtkWidget *window; |
340 | |
341 | GtkWidget * |
342 | do_listview_ucd (GtkWidget *do_widget) |
343 | { |
344 | if (window == NULL) |
345 | { |
346 | GtkWidget *listview, *sw; |
347 | GtkWidget *box, *label; |
348 | GtkCssProvider *provider; |
349 | |
350 | window = gtk_window_new (); |
351 | gtk_window_set_default_size (GTK_WINDOW (window), width: 800, height: 400); |
352 | gtk_window_set_title (GTK_WINDOW (window), title: "Characters" ); |
353 | gtk_window_set_display (GTK_WINDOW (window), |
354 | display: gtk_widget_get_display (widget: do_widget)); |
355 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *) &window); |
356 | |
357 | box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0); |
358 | label = gtk_label_new (str: "" ); |
359 | gtk_label_set_width_chars (GTK_LABEL (label), n_chars: 2); |
360 | gtk_widget_add_css_class (widget: label, css_class: "enormous" ); |
361 | provider = gtk_css_provider_new (); |
362 | gtk_css_provider_load_from_data (css_provider: provider, data: "label.enormous { font-size: 80px; }" , length: -1); |
363 | gtk_style_context_add_provider (context: gtk_widget_get_style_context (widget: label), GTK_STYLE_PROVIDER (provider), priority: 800); |
364 | gtk_widget_set_hexpand (widget: label, TRUE); |
365 | gtk_box_append (GTK_BOX (box), child: label); |
366 | |
367 | sw = gtk_scrolled_window_new (); |
368 | gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (sw), TRUE); |
369 | listview = create_ucd_view (label); |
370 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: listview); |
371 | gtk_box_prepend (GTK_BOX (box), child: sw); |
372 | gtk_window_set_child (GTK_WINDOW (window), child: box); |
373 | } |
374 | |
375 | if (!gtk_widget_get_visible (widget: window)) |
376 | gtk_widget_show (widget: window); |
377 | else |
378 | gtk_window_destroy (GTK_WINDOW (window)); |
379 | |
380 | return window; |
381 | } |
382 | |
383 | |