X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/460b9539a7c15580e41a71bbc0f47ae776238915..f15929695c1154fc9959e66ecb1d4aad1558fe0a:/disobedience/misc.c diff --git a/disobedience/misc.c b/disobedience/misc.c index 26222a9..b1558d3 100644 --- a/disobedience/misc.c +++ b/disobedience/misc.c @@ -17,18 +17,35 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ +/** @file disobedience/misc.c + * @brief Miscellaneous GTK+ interfacing stuff + */ #include "disobedience.h" +#include "table.h" + +struct image { + const char *name; + const guint8 *data; +}; + +#include "images.h" /* Miscellaneous GTK+ stuff ------------------------------------------------ */ +WT(cached_image); + /* Functions */ -GtkWidget *scroll_widget(GtkWidget *child, - const char *widgetname) { +/** @brief Put scrollbars around a widget + * @param child Widget to surround + * @return Scroll widget + */ +GtkWidget *scroll_widget(GtkWidget *child) { GtkWidget *scroller = gtk_scrolled_window_new(0, 0); GtkAdjustment *adj; + gtk_widget_set_style(scroller, tool_style); D(("scroll_widget")); /* Why isn't _AUTOMATIC the default? */ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller), @@ -48,43 +65,119 @@ GtkWidget *scroll_widget(GtkWidget *child, /* Child widget requires a viewport */ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroller), child); + gtk_widget_set_style(gtk_bin_get_child(GTK_BIN(scroller)), tool_style); } - /* Apply a name to the widget so it can be recolored */ - gtk_widget_set_name(GTK_BIN(scroller)->child, widgetname); - gtk_widget_set_name(scroller, widgetname); + gtk_widget_set_style(GTK_SCROLLED_WINDOW(scroller)->hscrollbar, tool_style); + gtk_widget_set_style(GTK_SCROLLED_WINDOW(scroller)->vscrollbar, tool_style); return scroller; } +/** @brief Find an image + * @param name Relative path to image + * @return pixbuf containing image + * + * Images are cached so it's perfectly sensible to call this lots of times even + * for the same image. + * + * Images are searched for in @c pkgdatadir/static. + */ GdkPixbuf *find_image(const char *name) { static const struct cache_type image_cache_type = { INT_MAX }; GdkPixbuf *pb; char *path; GError *err = 0; + int n; if(!(pb = (GdkPixbuf *)cache_get(&image_cache_type, name))) { - byte_xasprintf(&path, "%s/static/%s", pkgdatadir, name); - if(!(pb = gdk_pixbuf_new_from_file(path, &err))) { - error(0, "%s", err->message); - return 0; + if((n = TABLE_FIND(images, struct image, name, name)) >= 0) { + /* Use the built-in copy */ + if(!(pb = gdk_pixbuf_new_from_inline(-1, images[n].data, FALSE, &err))) { + error(0, "%s", err->message); + return 0; + } + } else { + /* See if there's a copy on disk */ + byte_xasprintf(&path, "%s/static/%s", pkgdatadir, name); + if(!(pb = gdk_pixbuf_new_from_file(path, &err))) { + error(0, "%s", err->message); + return 0; + } } + NW(cached_image); cache_put(&image_cache_type, name, pb); } return pb; } -void popup_error(const char *msg) { +/** @brief Pop up a message */ +void popup_msg(GtkMessageType mt, const char *msg) { GtkWidget *w; w = gtk_message_dialog_new(GTK_WINDOW(toplevel), GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, + mt, GTK_BUTTONS_CLOSE, "%s", msg); + gtk_widget_set_style(w, tool_style); gtk_dialog_run(GTK_DIALOG(w)); gtk_widget_destroy(w); } +/** @brief Pop up an error message */ +void fpopup_msg(GtkMessageType mt, const char *fmt, ...) { + va_list ap; + char *msg; + + va_start(ap, fmt); + byte_xvasprintf(&msg, fmt, ap); + va_end(ap); + popup_msg(mt, msg); +} + +/** @brief Create a button with an icon in it + * @param path (relative) path to image + * @param tip Tooltip or NULL to not set one + * @return Button + */ +GtkWidget *iconbutton(const char *path, const char *tip) { + GtkWidget *button, *content; + GdkPixbuf *pb; + + NW(button); + button = gtk_button_new(); + if((pb = find_image(path))) { + NW(image); + content = gtk_image_new_from_pixbuf(pb); + } else { + NW(label); + content = gtk_label_new(path); + } + gtk_widget_set_style(button, tool_style); + gtk_widget_set_style(content, tool_style); + gtk_container_add(GTK_CONTAINER(button), content); + if(tip) + gtk_tooltips_set_tip(tips, button, tip, ""); + return button; +} + +/** @brief Create buttons and pack them into an hbox */ +GtkWidget *create_buttons(const struct button *buttons, + size_t nbuttons) { + size_t n; + GtkWidget *const hbox = gtk_hbox_new(FALSE, 1); + + for(n = 0; n < nbuttons; ++n) { + GtkWidget *const button = gtk_button_new_from_stock(buttons[n].stock); + gtk_widget_set_style(button, tool_style); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(buttons[n].clicked), 0); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1); + gtk_tooltips_set_tip(tips, button, buttons[n].tip, ""); + } + return hbox; +} + /* Local Variables: c-basic-offset:2 @@ -93,5 +186,3 @@ fill-column:79 indent-tabs-mode:nil End: */ - -/* arch-tag:tV2wkVwV3p2A66vyViQJSw */