The attached patch adds caps for opening a new window that just contains
a graph to Gnumeric.

caveats

1 we sometimes display scrollbars although it isn't aesthetically
pleasing (fit to height/width). This is due to GtkScrolledWindow
allocation issues. Without proper height-by-width management in GTK+, I
don't think it's fixable.

2 if the graph window persists longer than all the other toplevels, the
gnumeric shutdown functions spit warnings about non-freed ressources.
I see two ways of resolving this:
- set destroy_with_parent for the graph window. This requires an API for
getting the window a sheet object is associated with
- add a global list of graph windows, which are all destroyed before the
ressource check runs

3

the % sizes of the graph are relative to the window size, not absolute
to the passed-in graph size. This makes sense if you consider that for
fullscreen presentation, one often wants to zoom in.

4

+                    w->zoom_factor > 1.0 ?
+                    w->height < w->width * w->aspect_ratio :
+                    w->height > w->width * w->aspect_ratio))

is a bit fishy. However, I supposed that if one has an aspect ratio of
1.0, he expects the widget to scale like in the pie-demo. If the aspect
ratio is bigger, and no explicit reference direction is set, I use the
(relative) longer dimension, since using the shorter causes issues where
scrolling takes place with a hoffset/voffset != 0, which looks ugly.

5

the graph size in the window is wrong compared to the sheet object graph
size, it seems like by a constant factor

6

gog_object_get_child_by_name was added just for API completeness. It is
not needed by the rest of the patch.

-- 
Christian Neumair <[EMAIL PROTECTED]>
? 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 <gnumeric-config.h>
+
+#include "gnm-graph-window.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+
+#include <gtk/gtkcombobox.h>
+#include <gtk/gtktoolbar.h>
+#include <gtk/gtktoolbutton.h>
+#include <gtk/gtktoolitem.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkwindow.h>
+
+#include <goffice/gtk/go-graph-widget.h>
+
+#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 <gtk/gtkwidget.h>
+#include <goffice/graph/gog-graph.h>
+
+#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 <goffice/utils/go-glib-extras.h>
 #include <goffice/utils/go-format.h>
 #include <goffice/app/go-cmd-context.h>
+#include <goffice/gtk/go-graph-widget.h>
 
 #include <gsf/gsf-impl-utils.h>
 #include <gsf/gsf-utils.h>
@@ -61,6 +63,7 @@
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtkimagemenuitem.h>
 #include <gtk/gtkstock.h>
+#include <gtk/gtkwindow.h>
 #include <goffice/cut-n-paste/foocanvas/foo-canvas-line.h>
 #include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
 #include <goffice/cut-n-paste/foocanvas/foo-canvas-polygon.h>
@@ -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
Index: goffice/graph/gog-object.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-object.c,v
retrieving revision 1.50
diff -u -p -r1.50 gog-object.c
--- goffice/graph/gog-object.c	17 Oct 2005 12:59:21 -0000	1.50
+++ goffice/graph/gog-object.c	2 Nov 2005 14:30:40 -0000
@@ -1023,6 +1023,22 @@ gog_object_get_child_by_role (GogObject 
 }
 
 /**
+ *
+ * gog_object_get_child_by_name :
+ * @obj : a #GogObject
+ * @role : a #char to use as a filter
+ *
+ * A convenience routine to handle a unique child
+ * Returns NULL and spews an error if there is more than one.
+ **/
+GogObject *
+gog_object_get_child_by_name (GogObject const *obj, const char *name)
+{
+	return gog_object_get_child_by_role (obj,
+		gog_object_find_role_by_name (obj, name));
+}
+
+/**
  * gog_object_is_deletable :
  * @obj : a #GogObject
  *
Index: goffice/graph/gog-object.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-object.h,v
retrieving revision 1.28
diff -u -p -r1.28 gog-object.h
--- goffice/graph/gog-object.h	25 Aug 2005 09:31:36 -0000	1.28
+++ goffice/graph/gog-object.h	2 Nov 2005 14:30:41 -0000
@@ -146,6 +146,7 @@ char const  *gog_object_get_name	 (GogOb
 void	     gog_object_set_name	 (GogObject *obj, char *name, GError **err);
 GSList      *gog_object_get_children	 (GogObject const *obj, GogObjectRole const *filter);
 GogObject   *gog_object_get_child_by_role(GogObject const *obj, GogObjectRole const *role);
+GogObject   *gog_object_get_child_by_name(GogObject const *obj, const char *name);
 gpointer     gog_object_get_editor	 (GogObject *obj,
 					  GogDataAllocator *dalloc, GOCmdContext *cc);
 GogView	  *gog_object_new_view	 	 (GogObject const *obj, GogView *view);
Index: goffice/gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/goffice/goffice/gtk/Makefile.am,v
retrieving revision 1.30
diff -u -p -r1.30 Makefile.am
--- goffice/gtk/Makefile.am	5 Sep 2005 21:02:55 -0000	1.30
+++ goffice/gtk/Makefile.am	2 Nov 2005 14:30:41 -0000
@@ -22,7 +22,9 @@ libgoffice_gtk_la_SOURCES =		\
 	go-action-combo-stack.c 	\
 	go-action-combo-text.c	\
 	\
-	go-graph-widget.c
+	go-graph-widget.c \
+	\
+	go-marshal.list
 
 
 libgoffice_gtk_ladir = $(goffice_include_dir)/gtk
@@ -68,6 +70,24 @@ UNUSED = \
 	go-dock-item-grip.h \
 	go-dock-layout.c \
 	go-dock-layout.h
+
+GENMARSHAL_COMMAND = $(GLIB_GENMARSHAL) --prefix=goffice_gtk_marshal
+SUFFIXES = .list
+
+.list.h:
+	$(GENMARSHAL_COMMAND) --header $< >$@
+
+.list.c:
+	(echo '/* This file has been automatically generated.  Do not edit. */' && \
+	echo '#include <goffice/goffice-config.h>' && \
+	echo '#include "$*.h"' && \
+	$(GENMARSHAL_COMMAND) --body $< ) >$@
+
+BUILT_SOURCES = go-marshal.h
+
+non-intermediate: go-marshal.c
+
+CLEANFILES = go-marshal.h go-marshal.c
 
 EXTRA_DIST = $(UNUSED)
 
Index: goffice/gtk/go-graph-widget.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/gtk/go-graph-widget.c,v
retrieving revision 1.3
diff -u -p -r1.3 go-graph-widget.c
--- goffice/gtk/go-graph-widget.c	8 Aug 2005 08:57:00 -0000	1.3
+++ goffice/gtk/go-graph-widget.c	2 Nov 2005 14:30:41 -0000
@@ -20,7 +20,9 @@
 
 #include <goffice-config.h>
 #include "go-graph-widget.h"
-#include <gtk/gtkdrawingarea.h>
+#include "go-marshal.h"
+#include <gtk/gtklayout.h>
+#include <goffice/graph/gog-graph.h>
 #include <goffice/graph/gog-object.h>
 #include <goffice/graph/gog-renderer-pixbuf.h>
 #include <goffice/utils/go-math.h>
@@ -30,42 +32,83 @@
 enum {
 	GRAPH_WIDGET_PROP_0,
 	GRAPH_WIDGET_PROP_ASPECT_RATIO,
+	GRAPH_WIDGET_PROP_REFERENCE_DIRECTION,
+	GRAPH_WIDGET_PROP_ZOOM_FACTOR,
+	GRAPH_WIDGET_PROP_GRAPH
 };
 
-struct  _GOGraphWidget{
-	GtkDrawingArea	base;
+struct _GOGraphWidget{
+	GtkLayout base;
 
 	GogRendererPixbuf *renderer;
 	GogGraph *graph;
 	GogChart *chart; /* first chart created on init */
-	double aspect_ratio, width, height, xoffset, yoffset;
+
+	double aspect_ratio, zoom_factor;
+	int width, height, xoffset, yoffset;
+	GOGraphWidgetReferenceDirection reference_direction;
 
 	/* Idle handler ID */
 	guint idle_id;
 };
 
-typedef GtkDrawingAreaClass GOGraphWidgetClass;
+struct _GOGraphWidgetClass {
+	GtkLayoutClass parent_class;
+};
 
 static GtkWidgetClass *graph_parent_klass;
 
+static void go_graph_widget_request_update (GOGraphWidget *w);
+
+GType
+go_graph_widget_reference_direction_get_type (void)
+{
+	static GType type = 0;
+
+	if (!type) {
+		static const GEnumValue values [] = {
+			{ GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE, "GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE", "horizontal" },
+			{ GO_GRAPH_WIDGET_REFERENCE_DIRECTION_HORIZONTAL, "GO_GRAPH_WIDGET_REFERENCE_DIRECTION_HORIZONTAL", "horizontal" },
+			{ GO_GRAPH_WIDGET_REFERENCE_DIRECTION_VERTICAL, "GO_GRAPH_WIDGET_REFERENCE_DIRECTION_VERTICAL", "vertical" },
+			{ 0, NULL, NULL }
+		};
+
+		type = g_enum_register_static ("GOGraphWidgetReferenceDirection", values);
+	}
+
+	return type;
+}
+
 /* Size allocation handler for the widget */
 static void
 go_graph_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
 {
 	GOGraphWidget *w = GO_GRAPH_WIDGET (widget);
+
 	w->width = allocation->width;
 	w->height = allocation->height;
+
 	if (w->aspect_ratio > 0.) {
-		if (w->height > w->width * w->aspect_ratio) {
-			w->yoffset = (w->height - w->width * w->aspect_ratio) / 2.;
+		if (w->reference_direction == GO_GRAPH_WIDGET_REFERENCE_DIRECTION_HORIZONTAL ||
+		    (w->reference_direction == GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE &&
+		     w->zoom_factor > 1.0 ?
+		     w->height < w->width * w->aspect_ratio :
+		     w->height > w->width * w->aspect_ratio)) {
+			w->yoffset = MAX (0, w->height - w->width * w->aspect_ratio) / 2.;
 			w->height = w->width * w->aspect_ratio;
 			w->xoffset = 0;
 		} else {
-			w->xoffset = (w->width - w->height / w->aspect_ratio) / 2.;
+			w->xoffset = MAX (0, w->width - w->height / w->aspect_ratio) / 2.;
 			w->width = w->height / w->aspect_ratio;
 			w->yoffset = 0;
 		}
 	}
+
+	w->height *= w->zoom_factor;
+	w->width *= w->zoom_factor;
+
+	gtk_layout_set_size (GTK_LAYOUT (w), w->width - w->xoffset, w->height - w->yoffset);
+
 	gog_renderer_pixbuf_update (w->renderer, w->width, w->height, 1.0);
 	graph_parent_klass->size_allocate (widget, allocation);
 }
@@ -89,7 +132,7 @@ go_graph_widget_expose_event (GtkWidget 
 	gdk_region_intersect (draw_region, event->region);
 	if (!gdk_region_empty (draw_region)) {
 		gdk_region_get_clipbox (draw_region, &draw_rect);
-		gdk_draw_pixbuf (widget->window, NULL, pixbuf,
+		gdk_draw_pixbuf (GTK_LAYOUT (widget)->bin_window, NULL, pixbuf,
 			/* pixbuf 0, 0 is at pix_rect.x, pix_rect.y */
 			     draw_rect.x - display_rect.x,
 			     draw_rect.y - display_rect.y,
@@ -123,6 +166,21 @@ go_graph_widget_set_property (GObject *o
 		w->aspect_ratio = g_value_get_double (value);
 		w->xoffset = w->yoffset = 0.;
 		break;
+	case GRAPH_WIDGET_PROP_REFERENCE_DIRECTION :
+		w->reference_direction = g_value_get_enum (value);
+		w->xoffset = w->yoffset = 0.;
+		break;
+	case GRAPH_WIDGET_PROP_ZOOM_FACTOR :
+		w->zoom_factor = g_value_get_double (value);
+		break;
+	case GRAPH_WIDGET_PROP_GRAPH :
+		w->graph = (GogGraph *) g_value_get_object (value);
+		w->renderer = g_object_new (GOG_RENDERER_PIXBUF_TYPE,
+					    "model", g_object_ref (w->graph),
+					    NULL);
+		g_signal_connect_swapped (w->renderer, "request_update",
+			G_CALLBACK (go_graph_widget_request_update), w);
+		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
 		 return; /* NOTE : RETURN */
@@ -140,6 +198,15 @@ go_graph_widget_get_property (GObject *o
 	case GRAPH_WIDGET_PROP_ASPECT_RATIO :
 		g_value_set_double (value, w->aspect_ratio);
 		break;
+	case GRAPH_WIDGET_PROP_REFERENCE_DIRECTION :
+		g_value_set_enum (value, w->reference_direction);
+		break;
+	case GRAPH_WIDGET_PROP_ZOOM_FACTOR :
+		g_value_set_double (value, w->zoom_factor);
+		break;
+	case GRAPH_WIDGET_PROP_GRAPH :
+		g_value_set_object (value, w->graph);
+		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
 		 break;
@@ -163,7 +230,26 @@ go_graph_widget_class_init (GOGraphWidge
 		GRAPH_WIDGET_PROP_ASPECT_RATIO,
 		g_param_spec_double ("aspect-ratio", "aspect-ratio",
 			"Aspect ratio for rendering the graph, used only if greater than 0.",
-			-G_MAXDOUBLE, G_MAXDOUBLE, -1., G_PARAM_READWRITE));
+			-G_MAXDOUBLE, G_MAXDOUBLE, -1., G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+	g_object_class_install_property (object_class,
+		GRAPH_WIDGET_PROP_REFERENCE_DIRECTION,
+		g_param_spec_enum ("reference-direction", "reference-direction",
+			"The direction that should be used as base direction for the aspect ratio. "
+			"The choice of this direction influences the size allocation behavior of the widget.",
+			go_graph_widget_reference_direction_get_type (),
+			GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE,
+			G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+	g_object_class_install_property (object_class,
+		GRAPH_WIDGET_PROP_ZOOM_FACTOR,
+		g_param_spec_double ("zoom-factor", "zoom-factor",
+			"This factor determines how big the widget will actually be compared to its allocation size.",
+			0.0, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+	g_object_class_install_property (object_class,
+		GRAPH_WIDGET_PROP_GRAPH,
+		g_param_spec_object ("graph", "graph",
+			"The graph to render.",
+			gog_graph_get_type (), 
+			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 static gint
@@ -193,34 +279,25 @@ go_graph_widget_request_update (GOGraphW
 static void
 go_graph_widget_init (GOGraphWidget *w)
 {
-	w->graph = (GogGraph *) g_object_new (GOG_GRAPH_TYPE, NULL);
-	w->renderer = g_object_new (GOG_RENDERER_PIXBUF_TYPE,
-					  "model", w->graph,
-					  NULL);
-	g_signal_connect_swapped (w->renderer, "request_update",
-		G_CALLBACK (go_graph_widget_request_update), w);
-	/* by default, create one chart and add it to the graph */
-	w->chart = (GogChart *) 
-			gog_object_add_by_name (GOG_OBJECT (w->graph), "Chart", NULL);
 	w->idle_id = 0;
 }
 
 /**
  * go_graph_widget_new :
  * 
- * Creates a new #GOGraphWidget with an embedded #GogGraph. Also add a #GogChart inside
- * graph.
+ * Creates a new #GOGraphWidget, which embeds the specified #GogGraph.
  * Returns the newly created #GOGraphWidget.
  **/
 GtkWidget *
-go_graph_widget_new (void)
+go_graph_widget_new (GogGraph *graph)
 {
-	return GTK_WIDGET (g_object_new (GO_GRAPH_WIDGET_TYPE, NULL));
+	g_return_val_if_fail (IS_GOG_GRAPH (graph), NULL);
+	return GTK_WIDGET (g_object_new (GO_GRAPH_WIDGET_TYPE, "graph", graph, NULL));
 }
 
 GSF_CLASS (GOGraphWidget, go_graph_widget,
 	   go_graph_widget_class_init, go_graph_widget_init,
-	   gtk_drawing_area_get_type ())
+	   gtk_layout_get_type ())
 
 /**
  * go_graph_widget_get_graph :
@@ -233,17 +310,4 @@ go_graph_widget_get_graph (GOGraphWidget
 {
 	g_return_val_if_fail (IS_GO_GRAPH_WIDGET (widget), NULL);
 	return widget->graph;
-}
-
-/**
- * go_graph_widget_get_chart :
- * @widget : #GOGraphWidget
- * 
- * Returns the #GogChart created by go_graph_widget_new().
- **/
-GogChart *
-go_graph_widget_get_chart (GOGraphWidget *widget)
-{
-	g_return_val_if_fail (IS_GO_GRAPH_WIDGET (widget), NULL);
-	return widget->chart;
 }
Index: goffice/gtk/go-graph-widget.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/gtk/go-graph-widget.h,v
retrieving revision 1.2
diff -u -p -r1.2 go-graph-widget.h
--- goffice/gtk/go-graph-widget.h	8 Aug 2005 08:57:00 -0000	1.2
+++ goffice/gtk/go-graph-widget.h	2 Nov 2005 14:30:41 -0000
@@ -32,10 +32,19 @@ G_BEGIN_DECLS
 #define GO_GRAPH_WIDGET(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GO_GRAPH_WIDGET_TYPE, GOGraphWidget))
 #define IS_GO_GRAPH_WIDGET(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GO_GRAPH_WIDGET_TYPE))
 
-typedef struct _GOGraphWidget GOGraphWidget;
+typedef struct _GOGraphWidget      GOGraphWidget;
+typedef struct _GOGraphWidgetClass GOGraphWidgetClass;
+
+typedef enum {
+	GO_GRAPH_WIDGET_REFERENCE_DIRECTION_NONE,
+	GO_GRAPH_WIDGET_REFERENCE_DIRECTION_HORIZONTAL,
+	GO_GRAPH_WIDGET_REFERENCE_DIRECTION_VERTICAL
+} GOGraphWidgetReferenceDirection;
+
+GType go_graph_widget_reference_direction_get_type (void);
 
 GType go_graph_widget_get_type (void);
-GtkWidget *go_graph_widget_new (void);
+GtkWidget *go_graph_widget_new (GogGraph *graph);
 
 GogGraph *go_graph_widget_get_graph (GOGraphWidget *widget);
 GogChart *go_graph_widget_get_chart (GOGraphWidget *widget);
Index: goffice/gtk/go-marshal.list
===================================================================
RCS file: goffice/gtk/go-marshal.list
diff -N goffice/gtk/go-marshal.list
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ goffice/gtk/go-marshal.list	2 Nov 2005 14:30:41 -0000
@@ -0,0 +1 @@
+VOID:OBJECT,OBJECT
Index: tests/pie-demo.c
===================================================================
RCS file: /cvs/gnome/goffice/tests/pie-demo.c,v
retrieving revision 1.7
diff -u -p -r1.7 pie-demo.c
--- tests/pie-demo.c	8 Aug 2005 08:57:07 -0000	1.7
+++ tests/pie-demo.c	2 Nov 2005 14:30:41 -0000
@@ -74,11 +74,15 @@ main (int argc, char *argv[])
 	w = gtk_hseparator_new ();
 	gtk_box_pack_end (GTK_BOX (box), w, FALSE, FALSE, 2);
 
+	/* create a graph and an associated chart */
+	graph = (GogGraph *) g_object_new (GOG_GRAPH_TYPE, NULL);
+	chart = (GogChart *) gog_object_add_by_name (GOG_OBJECT (graph), "Chart", NULL);
 	/* Create a graph widget and add it to the GtkVBox */
-	w = go_graph_widget_new ();
+	w = go_graph_widget_new (graph);
+	g_object_set (G_OBJECT (w), "aspect-ratio", 1.0, NULL);
+	g_assert (graph == go_graph_widget_get_graph (GO_GRAPH_WIDGET (w)));
+	g_object_unref (graph);
 	gtk_box_pack_end (GTK_BOX (box), w, TRUE, TRUE, 0);
-	/* Get the embedded graph */
-	graph = go_graph_widget_get_graph (GO_GRAPH_WIDGET (w));
 	/* Add a title */
 	label = (GogLabel *) g_object_new (GOG_LABEL_TYPE, NULL);
 	data = go_data_scalar_str_new (title, FALSE);
@@ -88,8 +92,6 @@ main (int argc, char *argv[])
 	style = gog_styled_object_get_style (GOG_STYLED_OBJECT (label));
 	desc = pango_font_description_from_string ("Sans bold 16");
 	gog_style_set_font_desc (style, desc);
-	/* Get the chart created by the widget initialization */
-	chart = go_graph_widget_get_chart (GO_GRAPH_WIDGET (w));
 	/* Create a pie plot and add it to the chart */
 	pie = (GogPlot *) gog_plot_new_by_name ("GogPiePlot");
 	gog_object_add_by_name (GOG_OBJECT (chart), "Plot", GOG_OBJECT (pie));

Attachment: signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil

_______________________________________________
gnumeric-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gnumeric-list

Reply via email to