一个非常出色的gtk例子

 

2007-06-10 22:09:41

#include <config.h>

#include <string.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>

#include <gtkimageview/gtkimageview.h>
#include <gtkimageview/gtkimagescrollwin.h>

#include <gio/gfile.h>

#include "katachi-fullscreen.h"
#include "katachi-image-cache.h"
#include "katachi-image-store.h"
#include "thumbnailer.h"
#include "shared.h"

GdkPixbuf *generic_thumb;

static int load_depth; /* Used to know when to restore the cursor */
static GdkCursor *busy_cursor;

static GtkTreeModel *file_store;

static GtkWidget *window;
static GtkWidget *file_list, *preview;


static void
got_pixbuf (GFile *file, GdkPixbuf *pixbuf, gpointer user_data)
{
gtk_image_view_set_pixbuf (GTK_IMAGE_VIEW (preview), pixbuf);

/* The image view takes it's own reference, so unref our copy */
g_object_unref (pixbuf);

if (--load_depth == 0)
gdk_window_set_cursor (window->window, NULL);
}

/*
* GtkIconView selection changed. Cancels an existing loader, and starts a new
* one.
*/
static void
on_selection_changed (GtkIconView *view, gpointer user_data)
{
GtkTreeModel *model;
GList *list;
GtkTreeIter iter;
GFile *file;

model = gtk_icon_view_get_model (view);

list = gtk_icon_view_get_selected_items (view);
if (list == NULL) {
gtk_image_view_set_pixbuf (GTK_IMAGE_VIEW (preview), NULL);
return;
}

if (g_list_length (list) > 1) {
gtk_image_view_set_pixbuf (GTK_IMAGE_VIEW (preview), NULL);
goto done;
}

gtk_tree_model_get_iter (model, &iter, list->data);

gtk_tree_model_get (model, &iter, COL_FILE, &file, -1);
if (!file) {
gtk_image_view_set_pixbuf (GTK_IMAGE_VIEW (preview), NULL);
goto done;
}

gdk_window_set_cursor (window->window, busy_cursor);
load_depth++;

katachi_image_cache_get_pixbuf (preview, file, TRUE, got_pixbuf, NULL);

g_object_unref (file);

done:
g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
g_list_free (list);
}

/*
* Callback from rows being inserted, to generate a thumbnail.
*/
static void
on_row_inserted (GtkTreeModel *model,
GtkTreePath *tree_path, GtkTreeIter *iter,
gpointer user_data)
{
ThumbnailData *data;

data = g_slice_new0 (ThumbnailData);

gtk_tree_model_get (model, iter, COL_FILE, &data->file, -1);
if (data->file == NULL)
return;

data->iter = *iter;

thumbnailer_push (data);
}

/*
* Callback from the UI manager with the GtkMenu widget. Pack and add this to
* the container.
*/
static void
ui_add_widget (GtkUIManager *ui, GtkWidget *widget, GtkContainer *container)
{
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
}

static void
on_open_location_action (GtkAction *action, gpointer user_data)
{
GtkWidget *dialog;

/* TODO: have to use a specific backend because gnome-vfs and gvfs conflict */
dialog = gtk_file_chooser_dialog_new (_("Select Directory"), GTK_WINDOW (window),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);

if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
char *filename;

filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));

katachi_image_store_populate (KATACHI_IMAGE_STORE (file_store),
g_file_get_for_path (filename));

g_free (filename);
}

gtk_widget_destroy (dialog);
}

static void
on_delete_action (GtkAction *action, gpointer user_data)
{
GtkWidget *dialog;
GList *iters, *l;
int count;

iters = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (file_list));

count = g_list_length (iters);
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
0, GTK_MESSAGE_QUESTION,
GTK_BUTTONS_NONE,
ngettext ("Are you sure you want to delete this file?",
"Are you sure you want to delete these %d files?",
count),
count);

gtk_dialog_add_buttons (GTK_DIALOG (dialog),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT,
NULL);

if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
gtk_icon_view_unselect_all (GTK_ICON_VIEW (file_list));

for (l = iters; l; l = l->next) {
GtkTreeIter iter;
GError *error = NULL;
GFile *file = NULL;

gtk_tree_model_get_iter (file_store, &iter, l->data);

gtk_tree_model_get (file_store, &iter, COL_FILE, &file, -1);
if (!file)
continue;

if (g_file_delete (file, NULL, &error)) {
/* TODO: remove from the model now instead of waiting for the notification */
} else {
g_warning ("Cannot delete file: %s", error->message);
g_error_free (error);
error = NULL;
}

g_object_unref (file);
}
}

gtk_widget_destroy (dialog);
g_list_foreach (iters, (GFunc)gtk_tree_path_free, NULL);
g_list_free (iters);
}

static void
on_fullscreen_action (GtkAction *action, gpointer user_data)
{
GtkWidget *fullscreen;
GList *paths;

paths = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (file_list));

if (g_list_length (paths) == 1) {
fullscreen = katachi_fullscreen_new (KATACHI_IMAGE_STORE (file_store));
katachi_fullscreen_set_path (KATACHI_FULLSCREEN (fullscreen), paths->data);
gtk_widget_show (fullscreen);
}

g_list_foreach (paths, (GFunc)gtk_tree_path_free, NULL);
g_list_free (paths);
}

/*
* Callback from the About action.
*/
static void
on_about_action (GtkAction *action, gpointer user_data)
{
const char* authors[] = {
"Ross Burton <ross@openedhand.com>", NULL,
};
const char *license = {
N_(
"Tasks 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 "
"(at your option) any later version.\n\n"
"Tasks 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.\n\n"
"You should have received a copy of the GNU General Public License "
"along with Tasks; if not, write to the Free Software Foundation, Inc., "
"51 Franklin St, Fifth Floor, Boston, MA 0110-1301, USA"
)
};

gtk_show_about_dialog (GTK_WINDOW (window),
"name", _("Katachi Image Viewer"),
"version", VERSION,
"logo-icon-name", "katachi",
"copyright", "Copyright \302\251 2007 Ross Burton",
"authors", authors,
"license", license,
"wrap-license", TRUE,
"website", "http://burtonini.com/",
NULL);
}

static const GtkActionEntry actions[] =
{
/* Action name, stock ID, label, accelerator, tooltip, callback */
{ "FileMenu", NULL, N_("_File") },
{ "OpenLocation", NULL, N_("Open _Location..."), NULL, NULL, G_CALLBACK (on_open_location_action) },
{ "Quit", GTK_STOCK_QUIT, NULL, NULL, NULL, G_CALLBACK (gtk_main_quit) },
{ "EditMenu", NULL, N_("_Edit") },
{ "Delete", GTK_STOCK_DELETE, NULL, "<Shift>Delete", NULL, G_CALLBACK (on_delete_action) },
{ "ViewMenu", NULL, N_("_View") },
/* TODO: disable Fullscreen if more than one selected items */
{ "Fullscreen", GTK_STOCK_FULLSCREEN, NULL, "F11", NULL, G_CALLBACK (on_fullscreen_action) },
{ "HelpMenu", NULL, N_("_Help") },
{ "About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (on_about_action) },
};

int
main (int argc, char **argv)
{
GError *error = NULL;
GtkWidget *top_box, *box, *scrolled, *image_scroll;
GtkActionGroup *action_group;
GtkUIManager *ui_manager;

g_thread_init (NULL);
g_set_application_name (_("Katachi"));
gtk_init (&argc, &argv);

load_depth = 0;

busy_cursor = gdk_cursor_new_from_name (gdk_display_get_default (),
"left_ptr_watch");

generic_thumb = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
"image-x-generic", 64, 0, NULL);

katachi_image_cache_init ();
file_store = katachi_image_store_new ();

thumbnailer_init (KATACHI_IMAGE_STORE (file_store));
g_signal_connect_after (file_store, "row-inserted", G_CALLBACK (on_row_inserted), NULL);

/* This starts an async operation, and will unref the path when done */
if (argc > 1) {
katachi_image_store_populate (KATACHI_IMAGE_STORE (file_store),
g_file_get_for_commandline_arg (argv[1]));
} else {
katachi_image_store_populate (KATACHI_IMAGE_STORE (file_store),
g_file_get_for_path ("/home/ross/Pictures/Photos/Incoming/"));
}

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);

top_box = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), top_box);

action_group = gtk_action_group_new ("Actions");
gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
gtk_action_group_add_actions (action_group, actions, G_N_ELEMENTS (actions), NULL);

ui_manager = gtk_ui_manager_new ();
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);

gtk_ui_manager_add_ui_from_file (ui_manager, PKGDATADIR "/katachi-ui.xml", &error);
if (error) {
g_warning ("Cannot load UI: %s", error->message);
g_error_free (error);
error = NULL;
}

/* Bind the accelerators */
gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (ui_manager));
g_signal_connect (ui_manager, "add-widget", G_CALLBACK (ui_add_widget), top_box);

/* Do this so that the menu is packed now instead of in the idle loop */
gtk_ui_manager_ensure_update (ui_manager);

box = gtk_hbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (top_box), box);

scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
gtk_box_pack_start (GTK_BOX (box), scrolled, FALSE, TRUE, 0);

/* TODO: make a widget out of this */
file_list = gtk_icon_view_new_with_model (file_store);
/* TODO: add my own renderers so that I can use icon names and magically
handle theme changes? */
g_object_set (file_list,
"selection-mode", GTK_SELECTION_MULTIPLE,
"columns", 1,
"pixbuf-column", COL_THUMB,
NULL);
/* TODO: get these numbers from the widget */
gtk_widget_set_size_request (file_list, 128 + 6 + 6, -1);
g_signal_connect (file_list, "selection-changed", G_CALLBACK (on_selection_changed), NULL);
gtk_container_add (GTK_CONTAINER (scrolled), file_list);

preview = gtk_image_view_new ();
image_scroll = gtk_image_scroll_win_new (GTK_IMAGE_VIEW (preview));
gtk_box_pack_start (GTK_BOX (box), image_scroll, TRUE, TRUE, 0);

gtk_widget_show_all (window);
gtk_main ();

return 0;

}


from http://burtonini.com/bzr/

posted on 2007-06-18 09:24  cy163  阅读(8774)  评论(0编辑  收藏  举报

导航