diff options
Diffstat (limited to 'window.c')
-rw-r--r-- | window.c | 256 |
1 files changed, 234 insertions, 22 deletions
@@ -1,7 +1,9 @@ #include <math.h> #include <gtk/gtk.h> +#include <string.h> #include "siv.h" + #define MIN_ZOOM -80 #define MAX_ZOOM 65 @@ -299,52 +301,71 @@ rebuild (Window *window) } static void +zoom (Window *window, int delta) +{ + GtkWidget *z; + + if (delta == 0) + return; + + if (delta < 0) + z = get_widget (window, "zoom_out"); + else + z = get_widget (window, "zoom_in"); + + if (GTK_WIDGET_SENSITIVE (z)) + { + window->zoom_level += delta; + + rebuild (window); + } +} + +static void on_zoom_in (GtkWidget *widget, Window *window) { - window->zoom_level += 5; - rebuild (window); + zoom (window, 5); }; static void on_zoom_out (GtkWidget *widget, Window *window) { - window->zoom_level -= 5; - rebuild (window); + zoom (window, -5); }; static void on_zoom_normal (GtkWidget *widget, Window *window) { - window->zoom_level = 0; - rebuild (window); + zoom (window, -window->zoom_level); }; -static void -on_various (GtkWidget *widget, Window *window) -{ - rebuild (window); -} - static gboolean on_scroll (GtkWidget *widget, GdkEventScroll *event, Window *window) { if (event->state & GDK_CONTROL_MASK) { if (event->direction == GDK_SCROLL_UP) - window->zoom_level += 1; + { + zoom (window, 1); + return TRUE; + } else if (event->direction == GDK_SCROLL_DOWN) - window->zoom_level -= 1; - else - return FALSE; - - rebuild (window); - return TRUE; + { + zoom (window, -1); + return TRUE; + } } return FALSE; } static void +on_various (GtkWidget *widget, Window *window) +{ + rebuild (window); +} + +static void on_size_allocate (GtkWidget *widget, GtkAllocation *allocation, gpointer data) { Window *window = data; @@ -421,7 +442,106 @@ on_close (GtkWidget *widget, gpointer data) window_free (window); } - + +static void +set_busy (GtkWidget *widget, + gboolean busy) +{ + GdkCursor *cursor; + GdkWindow *window; + + if (busy) + cursor = gdk_cursor_new (GDK_WATCH); + else + cursor = NULL; + + if (GTK_IS_TEXT_VIEW (widget)) + window = gtk_text_view_get_window (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_TEXT); + else + window = widget->window; + + gdk_window_set_cursor (window, cursor); + + if (cursor) + gdk_cursor_unref (cursor); + + gdk_display_flush (gdk_display_get_default ()); +} + +static void +show_could_not_open (Window *window, + const char *filename, + GError *err) +{ + app_show_warning (get_widget (window, "main_window"), + "Could not open %s: %s", + filename, + err->message); +} + +static void +on_open (GtkWidget *widget, gpointer data) +{ + Window *window = data; + gchar *filename = NULL; + GtkWidget *dialog; + + set_busy (get_widget (window, "main_window"), TRUE); + + dialog = gtk_file_chooser_dialog_new ("Open", + get_widget (window, "main_window"), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + set_busy (get_widget (window, "main_window"), FALSE); + +retry: + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + GError *err = NULL; + Window *target; + gboolean success; + + if (window->original) + target = window_new (window->app); + else + target = window; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + + set_busy (dialog, TRUE); + + success = window_load_file (target, filename, &err); + + if (success) + { + if (target != window) + window_show (target, gtk_get_current_event_time()); + } + else + { + show_could_not_open (window, filename, err); + + g_error_free (err); + + if (window != target) + window_free (target); + } + + set_busy (dialog, FALSE); + g_free (filename); + + if (!success) + goto retry; + } + + gtk_widget_destroy (dialog); +} + static void connect_signals (Window *window) { @@ -454,6 +574,7 @@ connect_signals (Window *window) { "drawing_area", "expose_event", G_CALLBACK (on_expose) }, { "drawing_area", "scroll_event", G_CALLBACK (on_scroll) }, { "drawing_area", "size_allocate", G_CALLBACK (on_size_allocate) }, + { "menu_open", "activate", G_CALLBACK (on_open) }, }; for (i = 0; i < G_N_ELEMENTS (connections); ++i) @@ -497,12 +618,99 @@ set_defaults (Window *window) gtk_check_menu_item_set_active (get_widget (window, "menu_no"), TRUE); } +/* Cut and paste from GLib */ +static char * +canonicalize_filename (const char *filename) +{ + char *canon, *start, *p, *q; + char *cwd; + int i; + + if (!g_path_is_absolute (filename)) + { + cwd = g_get_current_dir (); + canon = g_build_filename (cwd, filename, NULL); + g_free (cwd); + } + else + canon = g_strdup (filename); + + start = (char *)g_path_skip_root (canon); + + /* POSIX allows double slashes at the start to + * mean something special (as does windows too). + * So, "//" != "/", but more than two slashes + * is treated as "/". + */ + i = 0; + for (p = start - 1; + (p >= canon) && + G_IS_DIR_SEPARATOR (*p); + p--) + i++; + if (i > 2) + { + i -= 1; + start -= i; + memmove (start, start+i, strlen (start+i)+1); + } + + p = start; + while (*p != 0) + { + if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) + { + memmove (p, p+1, strlen (p+1)+1); + } + else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) + { + q = p + 2; + /* Skip previous separator */ + + p = p - 2; + if (p < start) + p = start; + while (p > start && !G_IS_DIR_SEPARATOR (*p)) + p--; + if (G_IS_DIR_SEPARATOR (*p)) + *p++ = G_DIR_SEPARATOR; + memmove (p, q, strlen (q)+1); + } + else + { + /* Skip until next separator */ + while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) + p++; + + if (*p != 0) + { + /* Canonicalize one separator */ + *p++ = G_DIR_SEPARATOR; + } + } + + /* Remove additional separators */ + q = p; + while (*q && G_IS_DIR_SEPARATOR (*q)) + q++; + + if (p != q) + memmove (p, q, strlen (q)+1); + } + + /* Remove trailing slashes */ + if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) + *(p-1) = 0; + + return canon; +} + gboolean window_load_file (Window *window, const char *filename, GError **err) { GdkPixbuf *pixbuf; - window->filename = g_strdup (filename); + window->filename = canonicalize_filename (filename); pixbuf = gdk_pixbuf_new_from_file (filename, err); @@ -521,6 +729,8 @@ window_load_file (Window *window, const char *filename, GError **err) if (data) { GtkCheckMenuItem *item; + + g_print ("moving to %d %d\n", data->window_x, data->window_y); gtk_window_move (get_widget (window, "main_window"), data->window_x, data->window_y); @@ -616,7 +826,7 @@ window_free (Window *window) } void -window_show (Window *window) +window_show (Window *window, guint32 time) { GtkAdjustment *vadj, *hadj; @@ -631,4 +841,6 @@ window_show (Window *window) gtk_adjustment_set_value (vadj, window->vadj); gtk_adjustment_set_value (hadj, window->hadj); + + gtk_window_present_with_time (get_widget (window, "main_window"), time); } |