chiark / gitweb /
Disobedience choose 'select all' now only selects tracks (and
[disorder] / disobedience / misc.c
CommitLineData
460b9539 1/*
2 * This file is part of DisOrder
ba937f01 3 * Copyright (C) 2006-2008 Richard Kettlewell
460b9539 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 2 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, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 */
2c348789
RK
20/** @file disobedience/misc.c
21 * @brief Miscellaneous GTK+ interfacing stuff
22 */
460b9539 23
24#include "disobedience.h"
54abef2b
RK
25#include "table.h"
26
27struct image {
28 const char *name;
29 const guint8 *data;
30};
31
32#include "images.h"
460b9539 33
34/* Miscellaneous GTK+ stuff ------------------------------------------------ */
35
36/* Functions */
37
2c348789
RK
38/** @brief Put scrollbars around a widget
39 * @param child Widget to surround
2c348789
RK
40 * @return Scroll widget
41 */
d4ef4132 42GtkWidget *scroll_widget(GtkWidget *child) {
460b9539 43 GtkWidget *scroller = gtk_scrolled_window_new(0, 0);
44 GtkAdjustment *adj;
45
33288048 46 gtk_widget_set_style(scroller, tool_style);
460b9539 47 D(("scroll_widget"));
48 /* Why isn't _AUTOMATIC the default? */
49 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
50 GTK_POLICY_AUTOMATIC,
51 GTK_POLICY_AUTOMATIC);
ed464350
RK
52 if(GTK_IS_LAYOUT(child)
53 || GTK_IS_TREE_VIEW(child)) {
460b9539 54 /* Child widget has native scroll support */
55 gtk_container_add(GTK_CONTAINER(scroller), child);
56 /* Fix up the step increments if they are 0 (seems like an odd default?) */
57 if(GTK_IS_LAYOUT(child)) {
58 adj = gtk_layout_get_hadjustment(GTK_LAYOUT(child));
59 if(!adj->step_increment) adj->step_increment = 16;
60 adj = gtk_layout_get_vadjustment(GTK_LAYOUT(child));
61 if(!adj->step_increment) adj->step_increment = 16;
62 }
63 } else {
64 /* Child widget requires a viewport */
65 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroller),
66 child);
33288048 67 gtk_widget_set_style(gtk_bin_get_child(GTK_BIN(scroller)), tool_style);
460b9539 68 }
33288048
RK
69 gtk_widget_set_style(GTK_SCROLLED_WINDOW(scroller)->hscrollbar, tool_style);
70 gtk_widget_set_style(GTK_SCROLLED_WINDOW(scroller)->vscrollbar, tool_style);
460b9539 71 return scroller;
72}
73
e18c4734
RK
74/** @brief Put a frame round a widget
75 * @param w Widget
76 * @param label Label or NULL
77 * @return Frame widget
78 */
79GtkWidget *frame_widget(GtkWidget *w, const char *label) {
80 GtkWidget *const frame = gtk_frame_new(label);
81 GtkWidget *const hbox = gtk_hbox_new(FALSE, 0);
82 GtkWidget *const vbox = gtk_vbox_new(FALSE, 0);
83 /* We want 4 pixels outside the frame boundary... */
84 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
85 /* ...and 4 pixels inside */
86 gtk_box_pack_start(GTK_BOX(hbox), w, TRUE/*expand*/, TRUE/*fill*/, 4);
87 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE/*expand*/, TRUE/*fill*/, 4);
88 gtk_container_add(GTK_CONTAINER(frame), vbox);
89 return frame;
90}
91
2c348789
RK
92/** @brief Find an image
93 * @param name Relative path to image
94 * @return pixbuf containing image
95 *
96 * Images are cached so it's perfectly sensible to call this lots of times even
97 * for the same image.
98 *
99 * Images are searched for in @c pkgdatadir/static.
100 */
460b9539 101GdkPixbuf *find_image(const char *name) {
102 static const struct cache_type image_cache_type = { INT_MAX };
103
104 GdkPixbuf *pb;
105 char *path;
106 GError *err = 0;
54abef2b 107 int n;
460b9539 108
109 if(!(pb = (GdkPixbuf *)cache_get(&image_cache_type, name))) {
ba937f01 110 if((n = TABLE_FIND(images, name, name)) >= 0) {
54abef2b
RK
111 /* Use the built-in copy */
112 if(!(pb = gdk_pixbuf_new_from_inline(-1, images[n].data, FALSE, &err))) {
113 error(0, "%s", err->message);
114 return 0;
115 }
116 } else {
117 /* See if there's a copy on disk */
118 byte_xasprintf(&path, "%s/static/%s", pkgdatadir, name);
119 if(!(pb = gdk_pixbuf_new_from_file(path, &err))) {
120 error(0, "%s", err->message);
121 return 0;
122 }
460b9539 123 }
124 cache_put(&image_cache_type, name, pb);
125 }
126 return pb;
127}
128
043d60b1
RK
129/** @brief Pop up a message */
130void popup_msg(GtkMessageType mt, const char *msg) {
34239ce4
RK
131 popup_submsg(toplevel, mt, msg);
132}
133
134void popup_submsg(GtkWidget *parent, GtkMessageType mt, const char *msg) {
460b9539 135 GtkWidget *w;
136
34239ce4 137 w = gtk_message_dialog_new(GTK_WINDOW(parent),
460b9539 138 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
043d60b1 139 mt,
460b9539 140 GTK_BUTTONS_CLOSE,
141 "%s", msg);
33288048 142 gtk_widget_set_style(w, tool_style);
460b9539 143 gtk_dialog_run(GTK_DIALOG(w));
144 gtk_widget_destroy(w);
145}
146
73f1b9f3 147/** @brief Pop up an error message */
043d60b1 148void fpopup_msg(GtkMessageType mt, const char *fmt, ...) {
73f1b9f3
RK
149 va_list ap;
150 char *msg;
151
152 va_start(ap, fmt);
153 byte_xvasprintf(&msg, fmt, ap);
154 va_end(ap);
043d60b1 155 popup_msg(mt, msg);
73f1b9f3
RK
156}
157
fcc8b9f7
RK
158/** @brief Create a button with an icon in it
159 * @param path (relative) path to image
3149c1e2 160 * @param tip Tooltip or NULL to not set one
fcc8b9f7
RK
161 * @return Button
162 */
163GtkWidget *iconbutton(const char *path, const char *tip) {
33288048 164 GtkWidget *button, *content;
fcc8b9f7
RK
165 GdkPixbuf *pb;
166
fcc8b9f7
RK
167 button = gtk_button_new();
168 if((pb = find_image(path))) {
fcc8b9f7
RK
169 content = gtk_image_new_from_pixbuf(pb);
170 } else {
fcc8b9f7
RK
171 content = gtk_label_new(path);
172 }
33288048
RK
173 gtk_widget_set_style(button, tool_style);
174 gtk_widget_set_style(content, tool_style);
fcc8b9f7
RK
175 gtk_container_add(GTK_CONTAINER(button), content);
176 if(tip)
177 gtk_tooltips_set_tip(tips, button, tip, "");
178 return button;
179}
180
ffc4dbaf 181/** @brief Create buttons and pack them into a box, which is returned */
f44417cf 182GtkWidget *create_buttons_box(struct button *buttons,
ffc4dbaf
RK
183 size_t nbuttons,
184 GtkWidget *box) {
73f1b9f3 185 size_t n;
73f1b9f3
RK
186
187 for(n = 0; n < nbuttons; ++n) {
f44417cf
RK
188 buttons[n].widget = gtk_button_new_from_stock(buttons[n].stock);
189 gtk_widget_set_style(buttons[n].widget, tool_style);
190 g_signal_connect(G_OBJECT(buttons[n].widget), "clicked",
73f1b9f3 191 G_CALLBACK(buttons[n].clicked), 0);
f44417cf
RK
192 gtk_box_pack_start(GTK_BOX(box), buttons[n].widget, FALSE, FALSE, 1);
193 gtk_tooltips_set_tip(tips, buttons[n].widget, buttons[n].tip, "");
73f1b9f3 194 }
ffc4dbaf
RK
195 return box;
196}
197
198/** @brief Create buttons and pack them into an hbox */
f44417cf 199GtkWidget *create_buttons(struct button *buttons,
ffc4dbaf
RK
200 size_t nbuttons) {
201 return create_buttons_box(buttons, nbuttons,
202 gtk_hbox_new(FALSE, 1));
73f1b9f3
RK
203}
204
ffc4dbaf
RK
205
206
460b9539 207/*
208Local Variables:
209c-basic-offset:2
210comment-column:40
211fill-column:79
212indent-tabs-mode:nil
213End:
214*/