? src/.gnm-graph-window.c.swp Index: src/Makefile.am =================================================================== RCS file: /cvs/gnome/gnumeric/src/Makefile.am,v retrieving revision 1.387 diff -u -p -r1.387 Makefile.am --- src/Makefile.am 4 Oct 2005 12:09:15 -0000 1.387 +++ src/Makefile.am 2 Nov 2005 13:54:45 -0000 @@ -212,6 +212,8 @@ GNUMERIC_BASE = \ sheet-object-widget.h \ sheet-style.c \ sheet-style.h \ + gnm-graph-window.c \ + gnm-graph-window.h \ gnm-plugin.c \ gnm-plugin.h \ solver.h \ Index: src/gnm-graph-window.c =================================================================== RCS file: src/gnm-graph-window.c diff -N src/gnm-graph-window.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/gnm-graph-window.c 2 Nov 2005 13:54:45 -0000 @@ -0,0 +1,283 @@ +#include + +#include "gnm-graph-window.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ZOOM_IN(x) *x = CLAMP(*x+1, ZOOM_LEVEL_25, ZOOM_LEVEL_200) +#define ZOOM_OUT(x) *x = CLAMP(*x-1, ZOOM_LEVEL_25, ZOOM_LEVEL_200) +#define ZOOM_100(x) *x = ZOOM_LEVEL_100 +#define ZOOM_FIT(x) *x = ZOOM_LEVEL_FIT + +struct _GnmGraphWindow { + GtkWindow parent; + + GtkWidget *vbox; + + GtkWidget *toolbar; + GtkWidget *size_combo; + + GtkWidget *scrolled_window; + + GtkWidget *graph; + double graph_height; + double graph_width; + + gboolean is_fullscreen; +}; + +struct _GnmGraphWindowClass { + GtkWindowClass parent_class; +}; + +/* keep in sync with gnm_graph_window_init */ +typedef enum { + CHART_SIZE_FIT = 0, + CHART_SIZE_FIT_WIDTH, + CHART_SIZE_FIT_HEIGHT, + /* separator */ + CHART_SIZE_100 = 4, + CHART_SIZE_125, + CHART_SIZE_150, + CHART_SIZE_200, + CHART_SIZE_300, + CHART_SIZE_500, +} ChartSize; + +G_DEFINE_TYPE (GnmGraphWindow, gnm_graph_window, GTK_TYPE_WINDOW); +#define parent_class gnm_graph_window_parent_class + +static void +fullscreen_button_clicked (GtkToolButton *button, + GnmGraphWindow *window) +{ + if (!window->is_fullscreen) { + gtk_window_fullscreen (GTK_WINDOW (window)); + gtk_tool_button_set_stock_id (button, GTK_STOCK_LEAVE_FULLSCREEN); + } else { + gtk_window_unfullscreen (GTK_WINDOW (window)); + gtk_tool_button_set_stock_id (button, GTK_STOCK_FULLSCREEN); + } + + window->is_fullscreen = !window->is_fullscreen; +} + + +static void +size_combo_changed (GtkComboBox *size_combo, + GnmGraphWindow *window) +{ + gboolean lock_ratio; + gdouble zoom_factor; + GOGraphWidgetReferenceDirection reference_direction; + + g_assert (IS_GO_GRAPH_WIDGET (window->graph)); + + zoom_factor = 1.0; + + switch (gtk_combo_box_get_active (size_combo)) { + case CHART_SIZE_FIT: + lock_ratio = FALSE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE; + break; + case CHART_SIZE_FIT_WIDTH: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_HORIZONTAL; + break; + case CHART_SIZE_FIT_HEIGHT: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_VERTICAL; + break; + case CHART_SIZE_100: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE; + break; + case CHART_SIZE_125: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE; + zoom_factor = 1.25; + break; + case CHART_SIZE_150: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE; + zoom_factor = 1.50; + break; + case CHART_SIZE_200: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE; + zoom_factor = 2.00; + break; + case CHART_SIZE_300: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE; + zoom_factor = 3.00; + break; + case CHART_SIZE_500: + lock_ratio = TRUE; + reference_direction = GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE; + zoom_factor = 5.00; + break; + default: + g_assert_not_reached (); + } + + g_object_set (window->graph, + "aspect-ratio", lock_ratio ? window->graph_height / window->graph_width : 0.0, + "reference-direction", reference_direction, + "zoom-factor", zoom_factor, + NULL); + + /* FIXME use GTK_POLICY_AUTOMATIC here. + * Unfortunately, scrolled windows cause endless allocations recursions + * under some circumstances with height-by-width management */ + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->scrolled_window), + (reference_direction == GO_GRAPH_WIDGET_REFERENCE_DIRECTION_VERTICAL || zoom_factor > 1.0) + ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER, + (reference_direction == GO_GRAPH_WIDGET_REFERENCE_DIRECTION_HORIZONTAL || zoom_factor > 1.0) + ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER); +} + +static gboolean +size_combo_is_row_separator (GtkTreeModel *model, + GtkTreeIter *iter, + G_GNUC_UNUSED gpointer data) +{ + gboolean is_sep; + char *str; + + gtk_tree_model_get (model, iter, 0, &str, -1); + is_sep = (strcmp (str, "SEPARATOR") == 0); + + g_free (str); + + return is_sep; +} + +static void +gnm_graph_window_init (GnmGraphWindow *window) +{ + GtkToolItem *item; + unsigned int i; + + /* these indexes match the ChartSize enum */ + static char const * chart_sizes[] = { + N_("Fit"), + N_("Fit Width"), + N_("Fit Height"), + "SEPARATOR", + N_("100%"), + N_("125%"), + N_("150%"), + N_("200%"), + N_("300%"), + N_("500%") + }; + + window->vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (GTK_WIDGET (window->vbox)); + gtk_container_add (GTK_CONTAINER (window), window->vbox); + + window->toolbar = gtk_toolbar_new (); + gtk_widget_show (GTK_WIDGET (window->toolbar)); + gtk_box_pack_start (GTK_BOX (window->vbox), window->toolbar, FALSE, FALSE, 0); + + window->scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (GTK_WIDGET (window->scrolled_window)); + gtk_container_add (GTK_CONTAINER (window->vbox), window->scrolled_window); + + item = gtk_tool_item_new (); + gtk_widget_show (GTK_WIDGET (item)); + gtk_toolbar_insert (GTK_TOOLBAR (window->toolbar), item, -1); + + window->size_combo = gtk_combo_box_new_text (); + for (i = 0; i < G_N_ELEMENTS (chart_sizes); i++) + gtk_combo_box_append_text (GTK_COMBO_BOX (window->size_combo), _(chart_sizes[i])); + gtk_widget_set_sensitive (window->size_combo, FALSE); + gtk_widget_show (window->size_combo); + gtk_combo_box_set_active (GTK_COMBO_BOX (window->size_combo), CHART_SIZE_FIT); + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (window->size_combo), + size_combo_is_row_separator, NULL, NULL); + gtk_container_add (GTK_CONTAINER (item), window->size_combo); + g_signal_connect (window->size_combo, "changed", + G_CALLBACK (size_combo_changed), window); + + item = gtk_tool_button_new_from_stock (GTK_STOCK_FULLSCREEN); + gtk_widget_show (GTK_WIDGET (item)); + gtk_toolbar_insert (GTK_TOOLBAR (window->toolbar), item, -1); + g_signal_connect (item, "clicked", + G_CALLBACK (fullscreen_button_clicked), window); + + gtk_window_set_title (GTK_WINDOW (window), "Chart Viewer"); +} + +static void +gnm_graph_window_class_init (GnmGraphWindowClass *class) +{ +} + + +static void +gnm_graph_window_set_graph (GnmGraphWindow *window, + GogGraph *graph, + gdouble graph_width, + gdouble graph_height) +{ + GtkRequisition toolbar_requisition; + GogGraph *old_graph = + window->graph != NULL ? + go_graph_widget_get_graph (GO_GRAPH_WIDGET (window->graph)) : + NULL; + + if (graph == old_graph) + return; + + if (old_graph != NULL) { + gtk_container_remove (GTK_CONTAINER (window->scrolled_window), window->graph); + g_object_unref (window->graph); + window->graph = NULL; + } + + if (graph != NULL) { + window->graph = go_graph_widget_new (graph); + gtk_widget_show (window->graph); + gtk_container_add (GTK_CONTAINER (window->scrolled_window), window->graph); + + gtk_widget_size_request (window->toolbar, &toolbar_requisition); + gtk_window_set_default_size (GTK_WINDOW (window), + (int) graph_width, + (int) graph_height + toolbar_requisition.height); + + window->graph_width = graph_width; + window->graph_height = graph_height; + + /* ensure that the aspect ratio is updated */ + gtk_widget_set_sensitive (window->size_combo, TRUE); + g_signal_emit_by_name (window->size_combo, "changed"); + } +} + +GtkWidget * +gnm_graph_window_new (GogGraph *graph, + gdouble graph_width, + gdouble graph_height) +{ + GtkWidget *ret; + + ret = g_object_new (gnm_graph_window_get_type (), NULL); + gnm_graph_window_set_graph (GNM_GRAPH_WINDOW (ret), graph, graph_width, graph_height); + + return ret; +} Index: src/gnm-graph-window.h =================================================================== RCS file: src/gnm-graph-window.h diff -N src/gnm-graph-window.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/gnm-graph-window.h 2 Nov 2005 13:54:45 -0000 @@ -0,0 +1,23 @@ +#ifndef GNM_GRAPH_WINDOW_H +#define GNM_GRAPH_WINDOW_H + +#include +#include + +#define GNM_TYPE_GRAPH_WINDOW (gnm_graph_window_get_type ()) +#define GNM_GRAPH_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNM_TYPE_GRAPH_WINDOW, GnmGraphWindow)) +#define GNM_GRAPH_WINDOW_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), GNM_TYPE_GRAPH_WINDOW, GnmGraphWindowClass)) +#define IS_GNM_GRAPH_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNM_TYPE_GRAPH_WINDOW)) +#define IS_GNM_GRAPH_WINDOW_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GNM_TYPE_GRAPH_WINDOW)) +#define GNM_GRAPH_WINDOW_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GNM_TYPE_GRAPH_WINDOW, GnmGraphWindowClass)) + +typedef struct _GnmGraphWindow GnmGraphWindow; +typedef struct _GnmGraphWindowClass GnmGraphWindowClass; + +GType gnm_graph_window_get_type (void); + +GtkWidget *gnm_graph_window_new (GogGraph *graph, + double graph_width, + double graph_height); + +#endif /* GNM_GRAPH_WINDOW_H */ Index: src/sheet-object-graph.c =================================================================== RCS file: /cvs/gnome/gnumeric/src/sheet-object-graph.c,v retrieving revision 1.71 diff -u -p -r1.71 sheet-object-graph.c --- src/sheet-object-graph.c 5 Sep 2005 03:29:49 -0000 1.71 +++ src/sheet-object-graph.c 2 Nov 2005 13:54:45 -0000 @@ -30,6 +30,7 @@ #include "str.h" #include "gui-util.h" #include "gui-file.h" +#include "gnm-graph-window.h" #include "style-color.h" #include "sheet-object-impl.h" #include "workbook-edit.h" @@ -53,6 +54,7 @@ #include #include #include +#include #include #include @@ -61,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -358,12 +361,38 @@ out: } static void +sog_cb_open_in_new_window (SheetObject *so, SheetControl *sc) +{ + SheetObjectGraph *sog = SHEET_OBJECT_GRAPH (so); + GtkWidget *window; + double coords[4]; + double w, h; + + g_return_if_fail (so->sheet != NULL); + + sheet_object_position_pts_get (SHEET_OBJECT (sog), coords); + w = fabs (coords[2] - coords[0]) + 1.; + h = fabs (coords[3] - coords[1]) + 1.; + + window = gnm_graph_window_new (sog->graph, w, h); + gtk_window_present (GTK_WINDOW (window)); +} + +static void sheet_object_graph_populate_menu (SheetObject *so, GPtrArray *actions) { - static SheetObjectAction const sog_action = - { GTK_STOCK_SAVE_AS, N_("_Save as image"), NULL, 0, sog_cb_save_as }; + static SheetObjectAction const sog_actions[] = { + { GTK_STOCK_SAVE_AS, N_("_Save as Image"), NULL, 0, sog_cb_save_as }, + { NULL, N_("Open in _New Window"), NULL, 0, sog_cb_open_in_new_window } + }; + + unsigned int i; + SHEET_OBJECT_CLASS (parent_klass)->populate_menu (so, actions); - go_ptr_array_insert (actions, (gpointer) &sog_action, 1); + + for (i = 0; i < G_N_ELEMENTS (sog_actions); i++) + go_ptr_array_insert (actions, (gpointer) (sog_actions + i), 1 + i); + } static gboolean