]> git.tdb.fi Git - ext/subsurface.git/blobdiff - gtk-gui.c
Change plot routine to take a drawing_area as argument
[ext/subsurface.git] / gtk-gui.c
index e1140cbe089921a3641a42bf641ce7d1200e21ad..a5728e2c8e5149e54d30c79cd95df02e40f6665e 100644 (file)
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -17,7 +17,7 @@
 
 #include "libdivecomputer.h"
 
-GtkWidget *main_window, *divelist_window;
+GtkWidget *main_window;
 GtkWidget *main_vbox;
 GtkWidget *error_info_bar;
 GtkWidget *error_label;
@@ -103,6 +103,8 @@ static void file_open(GtkWidget *w, gpointer data)
        filter = gtk_file_filter_new();
        gtk_file_filter_add_pattern(filter, "*.xml");
        gtk_file_filter_add_pattern(filter, "*.XML");
+       gtk_file_filter_add_pattern(filter, "*.sda");
+       gtk_file_filter_add_pattern(filter, "*.SDA");
        gtk_file_filter_add_mime_type(filter, "text/xml");
        gtk_file_filter_set_name(filter, "XML file");
        gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
@@ -203,6 +205,42 @@ static void quit(GtkWidget *w, gpointer data)
        gtk_main_quit();
 }
 
+GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title,
+                               data_func_t data_func, PangoAlignment align, gboolean visible)
+{
+       GtkCellRenderer *renderer;
+       GtkTreeViewColumn *col;
+       double xalign = 0.0; /* left as default */
+
+       renderer = gtk_cell_renderer_text_new();
+       col = gtk_tree_view_column_new();
+
+       gtk_tree_view_column_set_title(col, title);
+       gtk_tree_view_column_set_sort_column_id(col, index);
+       gtk_tree_view_column_set_resizable(col, TRUE);
+       gtk_tree_view_column_pack_start(col, renderer, TRUE);
+       if (data_func)
+               gtk_tree_view_column_set_cell_data_func(col, renderer, data_func, (void *)(long)index, NULL);
+       else
+               gtk_tree_view_column_add_attribute(col, renderer, "text", index);
+       gtk_object_set(GTK_OBJECT(renderer), "alignment", align, NULL);
+       switch (align) {
+       case PANGO_ALIGN_LEFT:
+               xalign = 0.0;
+               break;
+       case PANGO_ALIGN_CENTER:
+               xalign = 0.5;
+               break;
+       case PANGO_ALIGN_RIGHT:
+               xalign = 1.0;
+               break;
+       }
+       gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), xalign, 0.5);
+       gtk_tree_view_column_set_visible(col, visible);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
+       return col;
+}
+
 static void create_radio(GtkWidget *vbox, const char *name, ...)
 {
        va_list args;
@@ -462,69 +500,83 @@ static void switch_page(GtkNotebook *notebook, gint arg1, gpointer user_data)
 
 static const char notebook_group[] = "123";
 #define GRP_ID ((void *)notebook_group)
+typedef struct {
+       char *name;
+       GtkWidget *widget;
+       GtkWidget *box;
+       gulong delete_handler;
+       gulong destroy_handler;
+} notebook_data_t;
+
+static notebook_data_t nbd[2]; /* we rip at most two notebook pages off */
 
 static GtkNotebook *create_new_notebook_window(GtkNotebook *source,
                GtkWidget *page,
                gint x, gint y, gpointer data)
 {
        GtkWidget *win, *notebook, *vbox;
+       notebook_data_t *nbdp;
 
-       /* We don't detatch twice */
-       if (divelist_window)
+       /* pick the right notebook page data and return if both are detached */
+       if (nbd[0].widget == NULL)
+               nbdp = nbd;
+       else if (nbd[1].widget == NULL)
+               nbdp = nbd + 1;
+       else
                return NULL;
 
-       divelist_window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-       gtk_window_set_title(GTK_WINDOW(win), "Dive List");
+       nbdp->name = strdup(gtk_widget_get_name(page));
+       nbdp->widget = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       gtk_window_set_title(GTK_WINDOW(win), nbdp->name);
        gtk_window_move(GTK_WINDOW(win), x, y);
 
        /* Destroying the dive list will kill the application */
-       g_signal_connect(G_OBJECT(win), "delete-event", G_CALLBACK(on_delete), NULL);
-       g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(on_destroy), NULL);
+       nbdp->delete_handler = g_signal_connect(G_OBJECT(win), "delete-event", G_CALLBACK(on_delete), NULL);
+       nbdp->destroy_handler = g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(on_destroy), NULL);
 
-       vbox = gtk_vbox_new(FALSE, 0);
+       nbdp->box = vbox = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(win), vbox);
 
        notebook = gtk_notebook_new();
        gtk_notebook_set_group(GTK_NOTEBOOK(notebook), GRP_ID);
+       gtk_widget_set_name(notebook, nbdp->name);
+       /* disallow drop events */
+       gtk_drag_dest_set(notebook, 0, NULL, 0, 0);
        gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 6);
-       gtk_widget_set_size_request(notebook, 350, 250);
+       gtk_widget_set_size_request(notebook, 450, 350);
 
        gtk_widget_show_all(win);
        return GTK_NOTEBOOK(notebook);
 }
 
 static void drag_cb(GtkWidget *widget, GdkDragContext *context,
-       gint x, gint y,
-       GtkSelectionData *selection_data,
-       guint info, guint time,
+       gint x, gint y, guint time,
        gpointer user_data)
 {
-       GtkWidget *source, *target;
-       GtkWidget *tab;
-
-       /*
-        * We don't actually really *use* this yet, but Dirk wants to
-        * do all the tabs as detatched tabs, and we'd need to use
-        * this all to figure out which window we're talking about.
-        */
+       GtkWidget *source;
+       notebook_data_t *nbdp;
+
        source = gtk_drag_get_source_widget(context);
-       target = (GtkWidget *) user_data;
-       tab = *(GtkWidget **)selection_data->data;
+       if (nbd[0].name && ! strcmp(nbd[0].name,gtk_widget_get_name(source)))
+               nbdp = nbd;
+       else if (nbd[1].name && ! strcmp(nbd[1].name,gtk_widget_get_name(source)))
+               nbdp = nbd + 1;
+       else
+               /* HU? */
+               return;
 
        gtk_drag_finish(context, TRUE, TRUE, time);
 
-       /*
-        * Horrible, horrible hack. We hide the old divelist window, and
-        * set it to NULL. So if we drag the thing back out, we'll create
-        * a new window. Ugh.
-        *
-        * Actually destroying the divelist window triggers the whole
-        * destroy callback, which we don't want.
-        */
-       if (source != target) {
-               gtk_widget_hide(divelist_window);
-               divelist_window = NULL;
-       }
+       /* we no longer need the widget - but getting rid of this is hard;
+        * remove the signal handler, remove the notebook from the box
+        * then destroy the widget (and clear out our data structure) */
+       g_signal_handler_disconnect(nbdp->widget,nbdp->delete_handler);
+       g_signal_handler_disconnect(nbdp->widget,nbdp->destroy_handler);
+       gtk_container_remove(GTK_CONTAINER(nbdp->box), source);
+       gtk_widget_destroy(nbdp->widget);
+       nbdp->widget = NULL;
+       free(nbdp->name);
+       nbdp->name = NULL;
 }
 
 void init_ui(int argc, char **argv)
@@ -580,20 +632,24 @@ void init_ui(int argc, char **argv)
        notebook = gtk_notebook_new();
        gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 6);
        gtk_notebook_set_group(GTK_NOTEBOOK(notebook), GRP_ID);
-       gtk_notebook_set_window_creation_hook(create_new_notebook_window, NULL, NULL);
+       g_signal_connect(notebook, "create-window", G_CALLBACK(create_new_notebook_window), NULL);
        gtk_drag_dest_set(notebook, GTK_DEST_DEFAULT_ALL, &notebook_target, 1, GDK_ACTION_MOVE);
-       g_signal_connect(notebook, "drag-data-received", G_CALLBACK(drag_cb), notebook);
+       g_signal_connect(notebook, "drag-drop", G_CALLBACK(drag_cb), notebook);
        g_signal_connect(notebook, "switch-page", G_CALLBACK(switch_page), NULL);
 
        /* Create the actual divelist */
        dive_list = dive_list_create();
+       gtk_widget_set_name(dive_list, "Dive List");
        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dive_list, gtk_label_new("Dive List"));
        gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(notebook), dive_list, 1);
        gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(notebook), dive_list, 1);
 
        /* Frame for dive profile */
        dive_profile = dive_profile_widget();
+       gtk_widget_set_name(dive_profile, "Dive Profile");
        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dive_profile, gtk_label_new("Dive Profile"));
+       gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(notebook), dive_profile, 1);
+       gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(notebook), dive_profile, 1);
 
        /* Frame for extended dive info */
        dive_info = extended_dive_info_widget();
@@ -614,62 +670,25 @@ void run_ui(void)
        gtk_main();
 }
 
-/* get the filenames the user selects and call the parsing function
- * on them
- * return 0 if the user cancelled the dialog
- */
-int open_import_file_dialog(char *filterpattern, char *filtertext, 
-                       void(* parse_function)(char *))
-{
-       int ret=0;
-
-       GtkWidget *dialog;
-       GtkFileFilter *filter = gtk_file_filter_new ();
-       gtk_file_filter_add_pattern (filter, filterpattern);
-       gtk_file_filter_set_name(filter, filtertext);
-       dialog = gtk_file_chooser_dialog_new("Open File",
-                                       GTK_WINDOW(main_window),
-                                       GTK_FILE_CHOOSER_ACTION_OPEN,
-                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-                                       NULL);
-       gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
-       gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),filter);
-
-       if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
-               GSList *filenames;
-               char *filename;
-               filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
-               while(filenames != NULL) {
-                       filename = (char *)filenames->data;
-                       parse_function(filename);
-                       g_free(filename);
-                       filenames = g_slist_next(filenames);
-               }
-               g_slist_free(filenames);
-               ret = 1;
-       }
-       gtk_widget_destroy(dialog);
-
-       return ret;
-}
-
 static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
 {
        struct dive *dive = current_dive;
        struct graphics_context gc = { .printer = 0 };
-       int w,h;
+       static cairo_rectangle_int_t drawing_area;
 
-       w = widget->allocation.width;
-       h = widget->allocation.height;
+       /* the drawing area gives TOTAL width * height - x,y is used as the topx/topy offset
+        * so effective drawing area is width-2x * height-2y */
+       drawing_area.width = widget->allocation.width;
+       drawing_area.height = widget->allocation.height;
+       drawing_area.x = drawing_area.width / 20.0;
+       drawing_area.y = drawing_area.height / 20.0;
 
        gc.cr = gdk_cairo_create(widget->window);
        set_source_rgb(&gc, 0, 0, 0);
        cairo_paint(gc.cr);
 
        if (dive)
-               plot(&gc, w, h, dive);
-
+               plot(&gc, &drawing_area, dive);
        cairo_destroy(gc.cr);
 
        return FALSE;