1 | /* Paintable/Emblems |
2 | * |
3 | * This demo shows how GdkPaintable can be used to |
4 | * overlay an emblem on top of an icon. The emblem |
5 | * can either be another icon, or an arbitrary |
6 | * paintable. |
7 | */ |
8 | |
9 | #include <gtk/gtk.h> |
10 | |
11 | #include "paintable.h" |
12 | |
13 | static GtkWidget *window = NULL; |
14 | |
15 | #define DEMO_TYPE_ICON (demo_icon_get_type ()) |
16 | G_DECLARE_FINAL_TYPE (DemoIcon, demo_icon, DEMO, ICON, GObject) |
17 | |
18 | struct _DemoIcon |
19 | { |
20 | GObject parent_instance; |
21 | |
22 | GdkPaintable *icon; |
23 | GdkPaintable *emblem; |
24 | GdkPaintableFlags flags; |
25 | }; |
26 | |
27 | struct _DemoIconClass |
28 | { |
29 | GObjectClass parent_class; |
30 | }; |
31 | |
32 | void |
33 | demo_icon_snapshot (GdkPaintable *paintable, |
34 | GtkSnapshot *snapshot, |
35 | double width, |
36 | double height) |
37 | { |
38 | DemoIcon *self = DEMO_ICON (ptr: paintable); |
39 | |
40 | gdk_paintable_snapshot (paintable: self->icon, snapshot, width, height); |
41 | gtk_snapshot_save (snapshot); |
42 | gtk_snapshot_translate (snapshot, point: &GRAPHENE_POINT_INIT (0.5 * width, 0)); |
43 | gdk_paintable_snapshot (paintable: self->emblem, snapshot, width: 0.5 * width, height: 0.5 * height); |
44 | gtk_snapshot_restore (snapshot); |
45 | } |
46 | |
47 | static GdkPaintableFlags |
48 | demo_icon_get_flags (GdkPaintable *paintable) |
49 | { |
50 | DemoIcon *self = DEMO_ICON (ptr: paintable); |
51 | |
52 | return self->flags; |
53 | } |
54 | |
55 | static void |
56 | demo_icon_paintable_init (GdkPaintableInterface *iface) |
57 | { |
58 | iface->snapshot = demo_icon_snapshot; |
59 | iface->get_flags = demo_icon_get_flags; |
60 | } |
61 | |
62 | G_DEFINE_TYPE_WITH_CODE (DemoIcon, demo_icon, G_TYPE_OBJECT, |
63 | G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, |
64 | demo_icon_paintable_init)) |
65 | |
66 | static void |
67 | demo_icon_dispose (GObject *object) |
68 | { |
69 | DemoIcon *self = DEMO_ICON (ptr: object); |
70 | |
71 | g_signal_handlers_disconnect_by_func (self->emblem, |
72 | gdk_paintable_invalidate_contents, |
73 | self); |
74 | |
75 | g_clear_object (&self->icon); |
76 | g_clear_object (&self->emblem); |
77 | |
78 | G_OBJECT_CLASS (demo_icon_parent_class)->dispose (object); |
79 | } |
80 | |
81 | static void |
82 | demo_icon_class_init (DemoIconClass *klass) |
83 | { |
84 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
85 | |
86 | object_class->dispose = demo_icon_dispose; |
87 | } |
88 | |
89 | static void |
90 | demo_icon_init (DemoIcon *self) |
91 | { |
92 | self->flags = GDK_PAINTABLE_STATIC_SIZE | GDK_PAINTABLE_STATIC_CONTENTS; |
93 | } |
94 | |
95 | GdkPaintable * |
96 | demo_icon_new_with_paintable (const char *icon_name, |
97 | GdkPaintable *emblem) |
98 | { |
99 | GtkIconTheme *theme; |
100 | GtkIconPaintable *icon; |
101 | DemoIcon *self; |
102 | |
103 | theme = gtk_icon_theme_get_for_display (display: gdk_display_get_default ()); |
104 | |
105 | icon = gtk_icon_theme_lookup_icon (self: theme, |
106 | icon_name, NULL, |
107 | size: 128, scale: 1, |
108 | direction: GTK_TEXT_DIR_LTR, flags: 0); |
109 | |
110 | self = g_object_new (DEMO_TYPE_ICON, NULL); |
111 | |
112 | self->icon = GDK_PAINTABLE (ptr: icon); |
113 | self->emblem = emblem; |
114 | |
115 | if ((gdk_paintable_get_flags (paintable: emblem) & GDK_PAINTABLE_STATIC_CONTENTS) == 0) |
116 | { |
117 | self->flags &= ~GDK_PAINTABLE_STATIC_CONTENTS; |
118 | |
119 | g_signal_connect_swapped (emblem, "invalidate-contents" , |
120 | G_CALLBACK (gdk_paintable_invalidate_contents), self); |
121 | } |
122 | |
123 | return GDK_PAINTABLE (ptr: self); |
124 | } |
125 | |
126 | GdkPaintable * |
127 | demo_icon_new (const char *icon_name, |
128 | const char *emblem_name) |
129 | { |
130 | GtkIconTheme *theme; |
131 | GtkIconPaintable *emblem; |
132 | |
133 | theme = gtk_icon_theme_get_for_display (display: gdk_display_get_default ()); |
134 | |
135 | emblem = gtk_icon_theme_lookup_icon (self: theme, |
136 | icon_name: emblem_name, NULL, |
137 | size: 128, scale: 1, |
138 | direction: GTK_TEXT_DIR_LTR, flags: 0); |
139 | |
140 | return GDK_PAINTABLE (ptr: demo_icon_new_with_paintable (icon_name, |
141 | emblem: GDK_PAINTABLE (ptr: emblem))); |
142 | } |
143 | |
144 | GtkWidget * |
145 | do_paintable_emblem (GtkWidget *do_widget) |
146 | { |
147 | GdkPaintable *icon; |
148 | GtkWidget *grid; |
149 | GtkWidget *image; |
150 | |
151 | if (!window) |
152 | { |
153 | window = gtk_window_new (); |
154 | gtk_window_set_display (GTK_WINDOW (window), |
155 | display: gtk_widget_get_display (widget: do_widget)); |
156 | gtk_window_set_title (GTK_WINDOW (window), title: "Paintable — Emblems" ); |
157 | gtk_window_set_default_size (GTK_WINDOW (window), width: 300, height: 200); |
158 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window); |
159 | |
160 | grid = gtk_grid_new (); |
161 | |
162 | icon = demo_icon_new (icon_name: "folder" , emblem_name: "starred" ); |
163 | image = gtk_image_new_from_paintable (paintable: icon); |
164 | gtk_widget_set_hexpand (widget: image, TRUE); |
165 | gtk_widget_set_vexpand (widget: image, TRUE); |
166 | gtk_grid_attach (GTK_GRID (grid), child: image, column: 0, row: 0, width: 1, height: 1); |
167 | |
168 | icon = demo_icon_new_with_paintable (icon_name: "drive-multidisk" , |
169 | emblem: gtk_nuclear_animation_new (FALSE)); |
170 | image = gtk_image_new_from_paintable (paintable: icon); |
171 | gtk_widget_set_hexpand (widget: image, TRUE); |
172 | gtk_widget_set_vexpand (widget: image, TRUE); |
173 | gtk_grid_attach (GTK_GRID (grid), child: image, column: 1, row: 0, width: 1, height: 1); |
174 | |
175 | gtk_window_set_child (GTK_WINDOW (window), child: grid); |
176 | g_object_unref (object: icon); |
177 | } |
178 | |
179 | if (!gtk_widget_get_visible (widget: window)) |
180 | gtk_widget_show (widget: window); |
181 | else |
182 | gtk_window_destroy (GTK_WINDOW (window)); |
183 | |
184 | return window; |
185 | } |
186 | |
187 | |