2 * Miscellaneous GTK helper functions.
11 #if !GTK_CHECK_VERSION(3,0,0)
12 #include <gdk/gdkkeysyms.h>
16 #include "gtkcompat.h"
18 void get_label_text_dimensions(const char *text, int *width, int *height)
21 * Determine the dimensions of a piece of text in the standard
22 * font used in GTK interface elements like labels. We do this by
23 * instantiating an actual GtkLabel, and then querying its size.
25 * But GTK2 and GTK3 require us to query the size completely
26 * differently. I'm sure there ought to be an easier approach than
27 * the way I'm doing this in GTK3, too!
29 GtkWidget *label = gtk_label_new(text);
31 #if GTK_CHECK_VERSION(3,0,0)
32 PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(label));
33 PangoRectangle logrect;
34 pango_layout_get_extents(layout, NULL, &logrect);
36 *width = logrect.width / PANGO_SCALE;
38 *height = logrect.height / PANGO_SCALE;
41 gtk_widget_size_request(label, &req);
48 g_object_ref_sink(G_OBJECT(label));
49 #if GTK_CHECK_VERSION(2,10,0)
50 g_object_unref(label);
54 int string_width(const char *text)
57 get_label_text_dimensions(text, &ret, NULL);
61 void align_label_left(GtkLabel *label)
63 #if GTK_CHECK_VERSION(3,16,0)
64 gtk_label_set_xalign(label, 0.0);
66 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
70 /* ----------------------------------------------------------------------
71 * Functions to arrange controls in a basically dialog-like window.
73 * The best method for doing this has varied wildly with versions of
74 * GTK, hence the set of wrapper functions here.
76 * In GTK 1, a GtkDialog has an 'action_area' at the bottom, which is
77 * a GtkHBox which stretches to cover the full width of the dialog. So
78 * we can either add buttons or other widgets to that box directly, or
79 * alternatively we can fill the hbox with some layout class of our
80 * own such as a Columns widget.
82 * In GTK 2, the action area has become a GtkHButtonBox, and its
83 * layout behaviour seems to be different and not what we want. So
84 * instead we abandon the dialog's action area completely: we
85 * gtk_widget_hide() it in the below code, and we also call
86 * gtk_dialog_set_has_separator() to remove the separator above it. We
87 * then insert our own action area into the end of the dialog's main
88 * vbox, and add our own separator above that.
90 * In GTK 3, we typically don't even want to use GtkDialog at all,
91 * because GTK 3 has become a lot more restrictive about what you can
92 * sensibly use GtkDialog for - it deprecates direct access to the
93 * action area in favour of making you provide nothing but
94 * dialog-ending buttons in the form of (text, response code) pairs,
95 * so you can't put any other kind of control in there, or fiddle with
96 * alignment and positioning, or even have a button that _doesn't_ end
97 * the dialog (e.g. 'View Licence' in our About box). So instead of
98 * GtkDialog, we use a straight-up GtkWindow and have it contain a
99 * vbox as its (unique) child widget; and we implement the action area
100 * by adding a separator and another widget at the bottom of that
104 GtkWidget *our_dialog_new(void)
106 #if GTK_CHECK_VERSION(3,0,0)
108 * See comment in our_dialog_set_action_area(): in GTK 3, we use
109 * GtkWindow in place of GtkDialog for most purposes.
111 GtkWidget *w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
112 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
113 gtk_container_add(GTK_CONTAINER(w), vbox);
114 gtk_widget_show(vbox);
117 return gtk_dialog_new();
121 void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w)
123 #if !GTK_CHECK_VERSION(2,0,0)
125 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),
128 #elif !GTK_CHECK_VERSION(3,0,0)
131 align = gtk_alignment_new(0, 0, 1, 1);
132 gtk_container_add(GTK_CONTAINER(align), w);
134 * The purpose of this GtkAlignment is to provide padding
135 * around the buttons. The padding we use is twice the padding
136 * used in our GtkColumns, because we nest two GtkColumns most
137 * of the time (one separating the tree view from the main
138 * controls, and another for the main controls themselves).
140 #if GTK_CHECK_VERSION(2,4,0)
141 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 8, 8, 8, 8);
143 gtk_widget_show(align);
144 gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
145 align, FALSE, TRUE, 0);
147 w = gtk_hseparator_new();
148 gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
151 gtk_widget_hide(gtk_dialog_get_action_area(GTK_DIALOG(dlg)));
152 g_object_set(G_OBJECT(dlg), "has-separator", TRUE, (const char *)NULL);
156 /* GtkWindow is a GtkBin, hence contains exactly one child, which
157 * here we always expect to be a vbox */
158 GtkBox *vbox = GTK_BOX(gtk_bin_get_child(GTK_BIN(dlg)));
161 g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL);
162 gtk_box_pack_end(vbox, w, FALSE, TRUE, 0);
164 sep = gtk_hseparator_new();
165 gtk_box_pack_end(vbox, sep, FALSE, TRUE, 0);
166 gtk_widget_show(sep);
171 GtkBox *our_dialog_make_action_hbox(GtkWindow *dlg)
173 #if GTK_CHECK_VERSION(3,0,0)
174 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
175 our_dialog_set_action_area(dlg, hbox);
176 gtk_widget_show(hbox);
177 return GTK_BOX(hbox);
178 #else /* not GTK 3 */
179 return GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dlg)));
183 void our_dialog_add_to_content_area(GtkWindow *dlg, GtkWidget *w,
184 gboolean expand, gboolean fill,
187 #if GTK_CHECK_VERSION(3,0,0)
188 /* GtkWindow is a GtkBin, hence contains exactly one child, which
189 * here we always expect to be a vbox */
190 GtkBox *vbox = GTK_BOX(gtk_bin_get_child(GTK_BIN(dlg)));
192 gtk_box_pack_start(vbox, w, expand, fill, padding);
195 (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
196 w, expand, fill, padding);