1 | /* GTK - The GIMP Toolkit |
2 | * Copyright (C) 2011 Alberto Ruiz <aruiz@gnome.org> |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "config.h" |
19 | |
20 | #include <stdlib.h> |
21 | #include <glib/gprintf.h> |
22 | #include <string.h> |
23 | |
24 | #include "gtkfontchooserdialog.h" |
25 | #include "gtkfontchooser.h" |
26 | #include "gtkfontchooserwidget.h" |
27 | #include "gtkfontchooserwidgetprivate.h" |
28 | #include "gtkfontchooserutils.h" |
29 | #include "gtkbox.h" |
30 | #include "gtkintl.h" |
31 | #include "gtkbuildable.h" |
32 | #include "gtkprivate.h" |
33 | #include "gtkwidget.h" |
34 | #include "gtksettings.h" |
35 | #include "gtkdialogprivate.h" |
36 | #include "gtktogglebutton.h" |
37 | #include "gtkheaderbar.h" |
38 | #include "gtkactionable.h" |
39 | #include "gtkeventcontrollerkey.h" |
40 | |
41 | typedef struct _GtkFontChooserDialogClass GtkFontChooserDialogClass; |
42 | |
43 | struct _GtkFontChooserDialog |
44 | { |
45 | GtkDialog parent_instance; |
46 | |
47 | GtkWidget *fontchooser; |
48 | GtkWidget *select_button; |
49 | GtkWidget *cancel_button; |
50 | GtkWidget *tweak_button; |
51 | }; |
52 | |
53 | struct _GtkFontChooserDialogClass |
54 | { |
55 | GtkDialogClass parent_class; |
56 | }; |
57 | |
58 | /** |
59 | * GtkFontChooserDialog: |
60 | * |
61 | * The `GtkFontChooserDialog` widget is a dialog for selecting a font. |
62 | * |
63 | * ![An example GtkFontChooserDialog](fontchooser.png) |
64 | * |
65 | * `GtkFontChooserDialog` implements the [iface@Gtk.FontChooser] interface |
66 | * and does not provide much API of its own. |
67 | * |
68 | * To create a `GtkFontChooserDialog`, use [ctor@Gtk.FontChooserDialog.new]. |
69 | * |
70 | * # GtkFontChooserDialog as GtkBuildable |
71 | * |
72 | * The `GtkFontChooserDialog` implementation of the `GtkBuildable` |
73 | * interface exposes the buttons with the names “select_button” |
74 | * and “cancel_button”. |
75 | */ |
76 | |
77 | static void gtk_font_chooser_dialog_buildable_interface_init (GtkBuildableIface *iface); |
78 | static GObject *gtk_font_chooser_dialog_buildable_get_internal_child (GtkBuildable *buildable, |
79 | GtkBuilder *builder, |
80 | const char *childname); |
81 | |
82 | G_DEFINE_TYPE_WITH_CODE (GtkFontChooserDialog, gtk_font_chooser_dialog, GTK_TYPE_DIALOG, |
83 | G_IMPLEMENT_INTERFACE (GTK_TYPE_FONT_CHOOSER, |
84 | _gtk_font_chooser_delegate_iface_init) |
85 | G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, |
86 | gtk_font_chooser_dialog_buildable_interface_init)) |
87 | |
88 | static GtkBuildableIface *parent_buildable_iface; |
89 | |
90 | static void |
91 | gtk_font_chooser_dialog_set_property (GObject *object, |
92 | guint prop_id, |
93 | const GValue *value, |
94 | GParamSpec *pspec) |
95 | { |
96 | GtkFontChooserDialog *dialog = GTK_FONT_CHOOSER_DIALOG (object); |
97 | |
98 | switch (prop_id) |
99 | { |
100 | default: |
101 | g_object_set_property (G_OBJECT (dialog->fontchooser), property_name: pspec->name, value); |
102 | break; |
103 | } |
104 | } |
105 | |
106 | static void |
107 | gtk_font_chooser_dialog_get_property (GObject *object, |
108 | guint prop_id, |
109 | GValue *value, |
110 | GParamSpec *pspec) |
111 | { |
112 | GtkFontChooserDialog *dialog = GTK_FONT_CHOOSER_DIALOG (object); |
113 | |
114 | switch (prop_id) |
115 | { |
116 | default: |
117 | g_object_get_property (G_OBJECT (dialog->fontchooser), property_name: pspec->name, value); |
118 | break; |
119 | } |
120 | } |
121 | |
122 | static void |
123 | font_activated_cb (GtkFontChooser *fontchooser, |
124 | const char *fontname, |
125 | gpointer user_data) |
126 | { |
127 | GtkDialog *dialog = user_data; |
128 | |
129 | gtk_dialog_response (dialog, response_id: GTK_RESPONSE_OK); |
130 | } |
131 | |
132 | static gboolean |
133 | dialog_forward_key (GtkEventControllerKey *controller, |
134 | guint keyval, |
135 | guint keycode, |
136 | GdkModifierType modifiers, |
137 | GtkWidget *widget) |
138 | { |
139 | GtkFontChooserDialog *dialog = GTK_FONT_CHOOSER_DIALOG (widget); |
140 | |
141 | return gtk_event_controller_key_forward (controller, widget: dialog->fontchooser); |
142 | } |
143 | |
144 | static void |
145 | update_tweak_button (GtkFontChooserDialog *dialog) |
146 | { |
147 | GtkFontChooserLevel level; |
148 | |
149 | if (!dialog->tweak_button) |
150 | return; |
151 | |
152 | g_object_get (object: dialog->fontchooser, first_property_name: "level" , &level, NULL); |
153 | if ((level & (GTK_FONT_CHOOSER_LEVEL_FEATURES | GTK_FONT_CHOOSER_LEVEL_VARIATIONS)) != 0) |
154 | gtk_widget_show (widget: dialog->tweak_button); |
155 | else |
156 | gtk_widget_hide (widget: dialog->tweak_button); |
157 | } |
158 | |
159 | static void |
160 | setup_tweak_button (GtkFontChooserDialog *dialog) |
161 | { |
162 | gboolean ; |
163 | |
164 | if (dialog->tweak_button) |
165 | return; |
166 | |
167 | g_object_get (object: dialog, first_property_name: "use-header-bar" , &use_header, NULL); |
168 | if (use_header) |
169 | { |
170 | GtkWidget *button; |
171 | GtkWidget *; |
172 | GActionGroup *actions; |
173 | |
174 | actions = G_ACTION_GROUP (g_simple_action_group_new ()); |
175 | g_action_map_add_action (G_ACTION_MAP (actions), action: gtk_font_chooser_widget_get_tweak_action (fontchooser: dialog->fontchooser)); |
176 | gtk_widget_insert_action_group (GTK_WIDGET (dialog), name: "font" , group: actions); |
177 | g_object_unref (object: actions); |
178 | |
179 | button = gtk_toggle_button_new (); |
180 | gtk_actionable_set_action_name (GTK_ACTIONABLE (button), action_name: "font.tweak" ); |
181 | gtk_widget_set_focus_on_click (widget: button, FALSE); |
182 | gtk_widget_set_valign (widget: button, align: GTK_ALIGN_CENTER); |
183 | gtk_button_set_icon_name (GTK_BUTTON (button), icon_name: "emblem-system-symbolic" ); |
184 | |
185 | header = gtk_dialog_get_header_bar (GTK_DIALOG (dialog)); |
186 | gtk_header_bar_pack_end (GTK_HEADER_BAR (header), child: button); |
187 | |
188 | dialog->tweak_button = button; |
189 | |
190 | update_tweak_button (dialog); |
191 | } |
192 | } |
193 | |
194 | static void |
195 | gtk_font_chooser_dialog_map (GtkWidget *widget) |
196 | { |
197 | GtkFontChooserDialog *dialog = GTK_FONT_CHOOSER_DIALOG (widget); |
198 | |
199 | setup_tweak_button (dialog); |
200 | |
201 | GTK_WIDGET_CLASS (gtk_font_chooser_dialog_parent_class)->map (widget); |
202 | } |
203 | |
204 | static void |
205 | update_button (GtkFontChooserDialog *dialog) |
206 | { |
207 | PangoFontDescription *desc; |
208 | |
209 | desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog->fontchooser)); |
210 | |
211 | gtk_widget_set_sensitive (widget: dialog->select_button, sensitive: desc != NULL); |
212 | |
213 | if (desc) |
214 | pango_font_description_free (desc); |
215 | } |
216 | |
217 | static void |
218 | gtk_font_chooser_dialog_dispose (GObject *object) |
219 | { |
220 | GtkFontChooserDialog *dialog = GTK_FONT_CHOOSER_DIALOG (object); |
221 | |
222 | if (dialog->fontchooser) |
223 | { |
224 | g_signal_handlers_disconnect_by_func (dialog->fontchooser, |
225 | update_button, |
226 | dialog); |
227 | g_signal_handlers_disconnect_by_func (dialog->fontchooser, |
228 | update_tweak_button, |
229 | dialog); |
230 | } |
231 | |
232 | g_clear_pointer (&dialog->select_button, gtk_widget_unparent); |
233 | g_clear_pointer (&dialog->cancel_button, gtk_widget_unparent); |
234 | g_clear_pointer (&dialog->tweak_button, gtk_widget_unparent); |
235 | g_clear_pointer (&dialog->fontchooser, gtk_widget_unparent); |
236 | |
237 | G_OBJECT_CLASS (gtk_font_chooser_dialog_parent_class)->dispose (object); |
238 | } |
239 | |
240 | static void |
241 | gtk_font_chooser_dialog_class_init (GtkFontChooserDialogClass *klass) |
242 | { |
243 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
244 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
245 | |
246 | gobject_class->dispose = gtk_font_chooser_dialog_dispose; |
247 | gobject_class->get_property = gtk_font_chooser_dialog_get_property; |
248 | gobject_class->set_property = gtk_font_chooser_dialog_set_property; |
249 | |
250 | widget_class->map = gtk_font_chooser_dialog_map; |
251 | |
252 | _gtk_font_chooser_install_properties (klass: gobject_class); |
253 | |
254 | /* Bind class to template |
255 | */ |
256 | gtk_widget_class_set_template_from_resource (widget_class, |
257 | resource_name: "/org/gtk/libgtk/ui/gtkfontchooserdialog.ui" ); |
258 | |
259 | gtk_widget_class_bind_template_child (widget_class, GtkFontChooserDialog, fontchooser); |
260 | gtk_widget_class_bind_template_child (widget_class, GtkFontChooserDialog, select_button); |
261 | gtk_widget_class_bind_template_child (widget_class, GtkFontChooserDialog, cancel_button); |
262 | gtk_widget_class_bind_template_callback (widget_class, font_activated_cb); |
263 | gtk_widget_class_bind_template_callback (widget_class, dialog_forward_key); |
264 | } |
265 | |
266 | static void |
267 | gtk_font_chooser_dialog_init (GtkFontChooserDialog *dialog) |
268 | { |
269 | gtk_widget_init_template (GTK_WIDGET (dialog)); |
270 | gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (dialog)); |
271 | |
272 | _gtk_font_chooser_set_delegate (GTK_FONT_CHOOSER (dialog), |
273 | GTK_FONT_CHOOSER (dialog->fontchooser)); |
274 | |
275 | g_signal_connect_swapped (dialog->fontchooser, "notify::font-desc" , |
276 | G_CALLBACK (update_button), dialog); |
277 | update_button (dialog); |
278 | g_signal_connect_swapped (dialog->fontchooser, "notify::level" , |
279 | G_CALLBACK (update_tweak_button), dialog); |
280 | } |
281 | |
282 | /** |
283 | * gtk_font_chooser_dialog_new: |
284 | * @title: (nullable): Title of the dialog |
285 | * @parent: (nullable): Transient parent of the dialog |
286 | * |
287 | * Creates a new `GtkFontChooserDialog`. |
288 | * |
289 | * Returns: a new `GtkFontChooserDialog` |
290 | */ |
291 | GtkWidget* |
292 | gtk_font_chooser_dialog_new (const char *title, |
293 | GtkWindow *parent) |
294 | { |
295 | GtkFontChooserDialog *dialog; |
296 | |
297 | dialog = g_object_new (GTK_TYPE_FONT_CHOOSER_DIALOG, |
298 | first_property_name: "title" , title, |
299 | "transient-for" , parent, |
300 | NULL); |
301 | |
302 | return GTK_WIDGET (dialog); |
303 | } |
304 | |
305 | static void |
306 | gtk_font_chooser_dialog_buildable_interface_init (GtkBuildableIface *iface) |
307 | { |
308 | parent_buildable_iface = g_type_interface_peek_parent (g_iface: iface); |
309 | iface->get_internal_child = gtk_font_chooser_dialog_buildable_get_internal_child; |
310 | } |
311 | |
312 | static GObject * |
313 | gtk_font_chooser_dialog_buildable_get_internal_child (GtkBuildable *buildable, |
314 | GtkBuilder *builder, |
315 | const char *childname) |
316 | { |
317 | GtkFontChooserDialog *dialog = GTK_FONT_CHOOSER_DIALOG (buildable); |
318 | |
319 | if (g_strcmp0 (str1: childname, str2: "select_button" ) == 0) |
320 | return G_OBJECT (dialog->select_button); |
321 | else if (g_strcmp0 (str1: childname, str2: "cancel_button" ) == 0) |
322 | return G_OBJECT (dialog->cancel_button); |
323 | |
324 | return parent_buildable_iface->get_internal_child (buildable, builder, childname); |
325 | } |
326 | |