chiark / gitweb /
configure.ac, debian/: Set up correct dependencies for GStreamer.
[disorder] / disobedience / misc.c
1 /*
2  * This file is part of DisOrder
3  * Copyright (C) 2006-2008, 2010 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file disobedience/misc.c
19  * @brief Miscellaneous GTK+ interfacing stuff
20  */
21
22 #include "disobedience.h"
23 #include "table.h"
24
25 /** @brief Embedded image */
26 struct image {
27   /** @brief Image name */
28   const char *name;
29   /** @brief Image data in GDK pixbuf inline format */
30   const guint8 *data;
31 };
32
33 #include "../images/images.h"
34
35 /* Miscellaneous GTK+ stuff ------------------------------------------------ */
36
37 /* Functions */
38
39 /** @brief Put scrollbars around a widget
40  * @param child Widget to surround
41  * @return Scroll widget
42  */
43 GtkWidget *scroll_widget(GtkWidget *child) {
44   GtkWidget *scroller = gtk_scrolled_window_new(0, 0);
45   GtkAdjustment *adj;
46
47   gtk_widget_set_style(scroller, tool_style);
48   D(("scroll_widget"));
49   /* Why isn't _AUTOMATIC the default? */
50   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
51                                  GTK_POLICY_AUTOMATIC,
52                                  GTK_POLICY_AUTOMATIC);
53   if(GTK_IS_LAYOUT(child)
54      || GTK_IS_TREE_VIEW(child)) {
55     /* Child widget has native scroll support */
56     gtk_container_add(GTK_CONTAINER(scroller), child);
57     /* Fix up the step increments if they are 0 (seems like an odd default?) */
58     if(GTK_IS_LAYOUT(child)) {
59       adj = gtk_layout_get_hadjustment(GTK_LAYOUT(child));
60       if(!adj->step_increment) adj->step_increment = 16;
61       adj = gtk_layout_get_vadjustment(GTK_LAYOUT(child));
62       if(!adj->step_increment) adj->step_increment = 16;
63     }
64   } else {
65     /* Child widget requires a viewport */
66     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroller),
67                                           child);
68     gtk_widget_set_style(gtk_bin_get_child(GTK_BIN(scroller)), tool_style);
69   }
70   gtk_widget_set_style(GTK_SCROLLED_WINDOW(scroller)->hscrollbar, tool_style);
71   gtk_widget_set_style(GTK_SCROLLED_WINDOW(scroller)->vscrollbar, tool_style);
72   return scroller;
73 }
74
75 /** @brief Put a frame round a widget
76  * @param w Widget
77  * @param label Label or NULL
78  * @return Frame widget
79  */
80 GtkWidget *frame_widget(GtkWidget *w, const char *label) {
81   GtkWidget *const frame = gtk_frame_new(label);
82   GtkWidget *const hbox = gtk_hbox_new(FALSE, 0);
83   GtkWidget *const vbox = gtk_vbox_new(FALSE, 0);
84   /* We want 4 pixels outside the frame boundary... */
85   gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
86   /* ...and 4 pixels inside */
87   gtk_box_pack_start(GTK_BOX(hbox), w, TRUE/*expand*/, TRUE/*fill*/, 4);
88   gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE/*expand*/, TRUE/*fill*/, 4);
89   gtk_container_add(GTK_CONTAINER(frame), vbox);
90   return frame;
91 }
92
93 /** @brief Find an image
94  * @param name Relative path to image
95  * @return pixbuf containing image
96  *
97  * Images are cached so it's perfectly sensible to call this lots of times even
98  * for the same image.
99  *
100  * Images are searched for in @c pkgdatadir/static.
101  */
102 GdkPixbuf *find_image(const char *name) {
103   static const struct cache_type image_cache_type = { INT_MAX };
104
105   GdkPixbuf *pb;
106   char *path;
107   GError *err = 0;
108   int n;
109
110   if(!(pb = (GdkPixbuf *)cache_get(&image_cache_type, name))) {
111     if((n = TABLE_FIND(images, name, name)) >= 0) {
112       /* Use the built-in copy */
113 #pragma GCC diagnostic push
114 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
115       if(!(pb = gdk_pixbuf_new_from_inline(-1, images[n].data, FALSE, &err))) {
116 #pragma GCC diagnostic pop
117         disorder_error(0, "%s", err->message);
118         return 0;
119       }
120     } else {
121       /* See if there's a copy on disk */
122       byte_xasprintf(&path, "%s/static/%s", pkgdatadir, name);
123       if(!(pb = gdk_pixbuf_new_from_file(path, &err))) {
124         disorder_error(0, "%s", err->message);
125         return 0;
126       }
127     }
128     cache_put(&image_cache_type, name,  pb);
129   }
130   return pb;
131 }
132
133 /** @brief Pop up a message */
134 void popup_msg(GtkMessageType mt, const char *msg) {
135   popup_submsg(toplevel, mt, msg);
136 }
137
138 void popup_submsg(GtkWidget *parent, GtkMessageType mt, const char *msg) {
139   GtkWidget *w;
140
141   w = gtk_message_dialog_new(GTK_WINDOW(parent),
142                              GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
143                              mt,
144                              GTK_BUTTONS_CLOSE,
145                              "%s", msg);
146   gtk_widget_set_style(w, tool_style);
147   gtk_dialog_run(GTK_DIALOG(w));
148   gtk_widget_destroy(w);
149 }
150
151 /** @brief Pop up an error message */
152 void fpopup_msg(GtkMessageType mt, const char *fmt, ...) {
153   va_list ap;
154   char *msg;
155
156   va_start(ap, fmt);
157   byte_xvasprintf(&msg, fmt, ap);
158   va_end(ap);
159   popup_msg(mt, msg);
160 }
161
162 /** @brief Create a button with an icon in it
163  * @param path (relative) path to image
164  * @param tip Tooltip or NULL to not set one
165  * @return Button
166  */
167 GtkWidget *iconbutton(const char *path, const char *tip) {
168   GtkWidget *button, *content;
169   GdkPixbuf *pb;
170
171   button = gtk_button_new();
172   if((pb = find_image(path))) {
173     content = gtk_image_new_from_pixbuf(pb);
174   } else {
175     content = gtk_label_new(path);
176   }
177   gtk_widget_set_style(button, tool_style);
178   gtk_widget_set_style(content, tool_style);
179   gtk_container_add(GTK_CONTAINER(button), content);
180   if(tip)
181     gtk_widget_set_tooltip_text(button, tip);
182   return button;
183 }
184
185 /** @brief Create buttons and pack them into a box, which is returned */
186 GtkWidget *create_buttons_box(struct button *buttons,
187                               size_t nbuttons,
188                               GtkWidget *box) {
189   size_t n;
190
191   for(n = 0; n < nbuttons; ++n) {
192     buttons[n].widget = gtk_button_new_from_stock(buttons[n].stock);
193     gtk_widget_set_style(buttons[n].widget, tool_style);
194     g_signal_connect(G_OBJECT(buttons[n].widget), "clicked",
195                      G_CALLBACK(buttons[n].clicked), 0);
196     void (*pack)(GtkBox *box,
197                  GtkWidget *child,
198                  gboolean expand,
199                  gboolean fill,
200                  guint padding);
201     if(!(pack = buttons[n].pack))
202       pack = gtk_box_pack_start;
203     pack(GTK_BOX(box), buttons[n].widget, FALSE, FALSE, 1);
204     gtk_widget_set_tooltip_text(buttons[n].widget, buttons[n].tip);
205   }
206   return box;
207 }
208
209 /** @brief Create buttons and pack them into an hbox */
210 GtkWidget *create_buttons(struct button *buttons,
211                           size_t nbuttons) {
212   return create_buttons_box(buttons, nbuttons,
213                             gtk_hbox_new(FALSE, 1));
214 }
215
216
217
218 /*
219 Local Variables:
220 c-basic-offset:2
221 comment-column:40
222 fill-column:79
223 indent-tabs-mode:nil
224 End:
225 */