X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/fcc8b9f7b5575b251110171941db742d620edc9f..HEAD:/disobedience/misc.c diff --git a/disobedience/misc.c b/disobedience/misc.c index 3221e18..6a12fb6 100644 --- a/disobedience/misc.c +++ b/disobedience/misc.c @@ -1,50 +1,57 @@ /* * This file is part of DisOrder - * Copyright (C) 2006 Richard Kettlewell + * Copyright (C) 2006-2008, 2010 Richard Kettlewell * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. If not, see . */ /** @file disobedience/misc.c * @brief Miscellaneous GTK+ interfacing stuff */ #include "disobedience.h" +#include "table.h" -/* Miscellaneous GTK+ stuff ------------------------------------------------ */ +/** @brief Embedded image */ +struct image { + /** @brief Image name */ + const char *name; + /** @brief Image data in GDK pixbuf inline format */ + const guint8 *data; +}; + +#include "../images/images.h" -WT(cached_image); +/* Miscellaneous GTK+ stuff ------------------------------------------------ */ /* Functions */ /** @brief Put scrollbars around a widget * @param child Widget to surround - * @param widgetname Name for (both) widgets * @return Scroll widget */ -GtkWidget *scroll_widget(GtkWidget *child, - const char *widgetname) { +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), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - if(GTK_IS_LAYOUT(child)) { + if(GTK_IS_LAYOUT(child) + || GTK_IS_TREE_VIEW(child)) { /* Child widget has native scroll support */ gtk_container_add(GTK_CONTAINER(scroller), child); /* Fix up the step increments if they are 0 (seems like an odd default?) */ @@ -58,13 +65,31 @@ 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 Put a frame round a widget + * @param w Widget + * @param label Label or NULL + * @return Frame widget + */ +GtkWidget *frame_widget(GtkWidget *w, const char *label) { + GtkWidget *const frame = gtk_frame_new(label); + GtkWidget *const hbox = gtk_hbox_new(FALSE, 0); + GtkWidget *const vbox = gtk_vbox_new(FALSE, 0); + /* We want 4 pixels outside the frame boundary... */ + gtk_container_set_border_width(GTK_CONTAINER(frame), 4); + /* ...and 4 pixels inside */ + gtk_box_pack_start(GTK_BOX(hbox), w, TRUE/*expand*/, TRUE/*fill*/, 4); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE/*expand*/, TRUE/*fill*/, 4); + gtk_container_add(GTK_CONTAINER(frame), vbox); + return frame; +} + /** @brief Find an image * @param name Relative path to image * @return pixbuf containing image @@ -80,56 +105,116 @@ GdkPixbuf *find_image(const char *name) { 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, name, name)) >= 0) { + /* Use the built-in copy */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + if(!(pb = gdk_pixbuf_new_from_inline(-1, images[n].data, FALSE, &err))) { +#pragma GCC diagnostic pop + disorder_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))) { + disorder_error(0, "%s", err->message); + return 0; + } } - NW(cached_image); cache_put(&image_cache_type, name, pb); } return pb; } -/** @brief Pop up an error message */ -void popup_error(const char *msg) { +/** @brief Pop up a message */ +void popup_msg(GtkMessageType mt, const char *msg) { + popup_submsg(toplevel, mt, msg); +} + +void popup_submsg(GtkWidget *parent, GtkMessageType mt, const char *msg) { GtkWidget *w; - w = gtk_message_dialog_new(GTK_WINDOW(toplevel), + w = gtk_message_dialog_new(GTK_WINDOW(parent), 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 tooltip Tooltip or NULL to not set one + * @param tip Tooltip or NULL to not set one * @return Button */ GtkWidget *iconbutton(const char *path, const char *tip) { - GtkWidget *button, *content;; + 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, ""); + gtk_widget_set_tooltip_text(button, tip); return button; } +/** @brief Create buttons and pack them into a box, which is returned */ +GtkWidget *create_buttons_box(struct button *buttons, + size_t nbuttons, + GtkWidget *box) { + size_t n; + + for(n = 0; n < nbuttons; ++n) { + buttons[n].widget = gtk_button_new_from_stock(buttons[n].stock); + gtk_widget_set_style(buttons[n].widget, tool_style); + g_signal_connect(G_OBJECT(buttons[n].widget), "clicked", + G_CALLBACK(buttons[n].clicked), 0); + void (*pack)(GtkBox *box, + GtkWidget *child, + gboolean expand, + gboolean fill, + guint padding); + if(!(pack = buttons[n].pack)) + pack = gtk_box_pack_start; + pack(GTK_BOX(box), buttons[n].widget, FALSE, FALSE, 1); + gtk_widget_set_tooltip_text(buttons[n].widget, buttons[n].tip); + } + return box; +} + +/** @brief Create buttons and pack them into an hbox */ +GtkWidget *create_buttons(struct button *buttons, + size_t nbuttons) { + return create_buttons_box(buttons, nbuttons, + gtk_hbox_new(FALSE, 1)); +} + + + /* Local Variables: c-basic-offset:2