goffice r2135 - in trunk: . goffice/graph goffice/gtk



Author: jbrefort
Date: Mon Jul  7 06:41:37 2008
New Revision: 2135
URL: http://svn.gnome.org/viewvc/goffice?rev=2135&view=rev

Log:
2008-07-07  Mariusz Adamski  <mariusz adamski gmail com>

	* goffice/graph/Makefile.am: add new glade file.
	* goffice/graph/gog-3d-box-prefs.glade: new glade file for setting
	the 3d view.
	* goffice/graph/gog-3d-box.c: ditto and make the settings persistant.
	* goffice/gtk/Makefile.am: new 3d related widget
	* goffice/gtk/go-3d-rotation-sel.c: ditto.
	* goffice/gtk/go-3d-rotation-sel.glade: ditto.
	* goffice/gtk/go-3d-rotation-sel.h: ditto.



Added:
   trunk/goffice/graph/gog-3d-box-prefs.glade
   trunk/goffice/gtk/go-3d-rotation-sel.c
   trunk/goffice/gtk/go-3d-rotation-sel.glade
   trunk/goffice/gtk/go-3d-rotation-sel.h
Modified:
   trunk/ChangeLog
   trunk/goffice/graph/Makefile.am
   trunk/goffice/graph/gog-3d-box.c
   trunk/goffice/gtk/Makefile.am

Modified: trunk/goffice/graph/Makefile.am
==============================================================================
--- trunk/goffice/graph/Makefile.am	(original)
+++ trunk/goffice/graph/Makefile.am	Mon Jul  7 06:41:37 2008
@@ -96,7 +96,8 @@
 	gog-error-bar-prefs.glade	\
 	gog-reg-curve-prefs.glade	\
 	gog-reg-eqn-prefs.glade		\
-	gog-series-prefs.glade
+	gog-series-prefs.glade		\
+	gog-3d-box-prefs.glade
 
 include $(top_srcdir)/goffice.mk
 

Added: trunk/goffice/graph/gog-3d-box-prefs.glade
==============================================================================
--- (empty file)
+++ trunk/goffice/graph/gog-3d-box-prefs.glade	Mon Jul  7 06:41:37 2008
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+  <widget class="GtkWindow" id="window1">
+    <property name="visible">True</property>
+    <property name="title" translatable="yes">window2</property>
+    <child>
+      <widget class="GtkHBox" id="gog_3d_box_prefs">
+        <property name="visible">True</property>
+        <property name="border_width">12</property>
+        <property name="spacing">24</property>
+        <child>
+          <widget class="GtkVBox" id="vbox7">
+            <property name="visible">True</property>
+            <property name="spacing">12</property>
+            <child>
+              <widget class="GtkLabel" id="label4">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Euler angles&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkTable" id="table1">
+                <property name="visible">True</property>
+                <property name="n_rows">3</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">12</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <widget class="GtkHScale" id="phi_scale">
+                    <property name="width_request">180</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="adjustment">0 0 370 1 10 10</property>
+                    <property name="digits">0</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Phi:</property>
+                    <property name="use_underline">True</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Theta:</property>
+                    <property name="use_underline">True</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Psi:</property>
+                    <property name="use_underline">True</property>
+                  </widget>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHScale" id="psi_scale">
+                    <property name="width_request">180</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="adjustment">0 0 370 1 10 10</property>
+                    <property name="digits">0</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHScale" id="theta_scale">
+                    <property name="width_request">180</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="adjustment">0 0 370 1 10 10</property>
+                    <property name="digits">0</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Modified: trunk/goffice/graph/gog-3d-box.c
==============================================================================
--- trunk/goffice/graph/gog-3d-box.c	(original)
+++ trunk/goffice/graph/gog-3d-box.c	Mon Jul  7 06:41:37 2008
@@ -23,12 +23,298 @@
 #include <goffice/graph/gog-3d-box.h>
 #include <goffice/math/go-math.h>
 #include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+#include <goffice/graph/gog-chart.h>
+
+#ifdef GOFFICE_WITH_GTK
+#include <goffice/gtk/goffice-gtk.h>
+#include <goffice/gtk/go-3d-rotation-sel.h>
+#endif
 
 typedef GogObjectClass Gog3DBoxClass;
 
+enum {
+	BOX3D_PROP_0,
+	BOX3D_PROP_PSI,
+	BOX3D_PROP_THETA,
+	BOX3D_PROP_PHI,
+	BOX3D_PROP_FOV,
+};
+
+#ifdef GOFFICE_WITH_GTK
+
+static gboolean
+cb_g3d_update (GO3DRotationSel *g3d, GdkEventExpose *event, GObject *gobj)
+{
+	Gog3DBox *box = GOG_3D_BOX (gobj);
+	go_3d_rotation_sel_set_matrix (g3d, &box->mat);
+	return FALSE;
+}
+
+static void
+cb_matrix_changed (GO3DRotationSel *g3d, GObject *gobj)
+{
+	Gog3DBox *box = GOG_3D_BOX (gobj);
+
+	go_3d_rotation_sel_get_matrix (g3d, &box->mat);
+	box->psi = go_3d_rotation_sel_get_psi (g3d);
+	box->theta = go_3d_rotation_sel_get_theta (g3d);
+	box->phi = go_3d_rotation_sel_get_phi (g3d);
+	
+	gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+	                         TRUE);
+}
+
+static void
+cb_fov_changed (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+	Gog3DBox *box = GOG_3D_BOX (gobj);
+
+	box->fov = angle * M_PI / 180;
+	
+	gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+	                         TRUE);
+}
+
+static gboolean
+cb_box_psi_changed (GtkHScale *scale_widget, GdkEventButton *event,
+                    GObject *gobj)
+{
+	Gog3DBox *box = GOG_3D_BOX (gobj);
+
+	box->psi = gtk_range_get_value (GTK_RANGE (scale_widget)) * M_PI / 180;
+	go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+
+	gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+	                         TRUE);
+	return FALSE;
+}
+
+static gboolean
+cb_box_theta_changed (GtkHScale *scale_widget, GdkEventButton *event,
+                      GObject *gobj)
+{
+	Gog3DBox *box = GOG_3D_BOX (gobj);
+
+	box->theta = gtk_range_get_value (GTK_RANGE (scale_widget)) * M_PI / 180;
+	go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+
+	gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+	                         TRUE);
+	return FALSE;
+}
+
+static gboolean
+cb_box_phi_changed (GtkHScale *scale_widget, GdkEventButton *event,
+                    GObject *gobj)
+{
+	Gog3DBox *box = GOG_3D_BOX (gobj);
+
+	box->phi = gtk_range_get_value (GTK_RANGE (scale_widget)) * M_PI / 180;
+	go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+
+	gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+	                         TRUE);
+	return FALSE;
+}
+
+static void
+cb_g3d_change_psi (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+	g_signal_handlers_block_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+		0, 0, 0, G_CALLBACK (cb_box_psi_changed), 0);
+	gtk_range_set_value (GTK_RANGE (gobj), angle);
+	g_signal_handlers_unblock_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+		0, 0, 0, G_CALLBACK (cb_box_psi_changed), 0);
+}
+
+static void
+cb_g3d_change_theta (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+	g_signal_handlers_block_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+		0, 0, 0, G_CALLBACK (cb_box_theta_changed), 0);
+	gtk_range_set_value (GTK_RANGE (gobj), angle);
+	g_signal_handlers_unblock_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+		0, 0, 0, G_CALLBACK (cb_box_theta_changed), 0);
+}
+
+static void
+cb_g3d_change_phi (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+	g_signal_handlers_block_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+		0, 0, 0, G_CALLBACK (cb_box_phi_changed), 0);
+	gtk_range_set_value (GTK_RANGE (gobj), angle);
+	g_signal_handlers_unblock_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+		0, 0, 0, G_CALLBACK (cb_box_phi_changed), 0);
+}
+
+static void
+gog_3d_box_populate_editor (GogObject *gobj, 
+			  GogEditor *editor, 
+			  GogDataAllocator *dalloc, 
+			  GOCmdContext *cc)
+{
+	GtkWidget *w;
+	GtkWidget *g3d;
+	GladeXML *gui;
+	Gog3DBox *box = GOG_3D_BOX(gobj);
+
+	g3d = go_3d_rotation_sel_new ();
+	go_3d_rotation_sel_set_matrix (GO_3D_ROTATION_SEL (g3d), &box->mat);
+	go_3d_rotation_sel_set_fov (GO_3D_ROTATION_SEL (g3d), box->fov);
+	gog_editor_add_page (editor, g3d, _("Rotation"));
+
+	gui = go_libglade_new ("gog-3d-box-prefs.glade", "gog_3d_box_prefs", GETTEXT_PACKAGE, cc);
+	if (gui == NULL)
+		return;
+
+	g_signal_connect (G_OBJECT (g3d),
+	                  "expose-event",
+	                  G_CALLBACK (cb_g3d_update),
+	                  GOG_3D_BOX (gobj));
+	g_signal_connect (G_OBJECT (g3d),
+	                  "matrix-changed",
+	                  G_CALLBACK (cb_matrix_changed),
+	                  GOG_3D_BOX (gobj));
+	g_signal_connect (G_OBJECT (g3d),
+	                  "fov-changed",
+			  G_CALLBACK (cb_fov_changed),
+	                  GOG_3D_BOX (gobj));
+	
+	w = glade_xml_get_widget (gui, "psi_scale");
+	gtk_range_set_value (GTK_RANGE (w), box->psi * 180 / M_PI);
+	g_signal_connect (G_OBJECT (w),
+	                  "button-release-event",
+	                   G_CALLBACK (cb_box_psi_changed),
+	                   GOG_3D_BOX (gobj));
+	g_signal_connect (G_OBJECT (g3d),
+	                  "psi-changed",
+	                  G_CALLBACK (cb_g3d_change_psi),
+	                  GTK_RANGE (w));
+
+	w = glade_xml_get_widget (gui, "theta_scale");
+	gtk_range_set_value (GTK_RANGE (w), box->theta * 180 / M_PI);
+	g_signal_connect (G_OBJECT (w),
+	                  "button-release-event",
+	                  G_CALLBACK (cb_box_theta_changed),
+	                  GOG_3D_BOX (gobj));
+	g_signal_connect (G_OBJECT (g3d),
+	                  "theta-changed",
+	                  G_CALLBACK (cb_g3d_change_theta),
+	                  GTK_RANGE (w));
+
+	w = glade_xml_get_widget (gui, "phi_scale");
+	gtk_range_set_value (GTK_RANGE (w), box->phi * 180 / M_PI);
+	g_signal_connect (G_OBJECT (w),
+	                  "button-release-event",
+	                  G_CALLBACK (cb_box_phi_changed),
+	                  GOG_3D_BOX (gobj));
+	g_signal_connect (G_OBJECT (g3d),
+	                  "phi-changed",
+	                  G_CALLBACK (cb_g3d_change_phi),
+	                  GTK_RANGE (w));
+
+	w = glade_xml_get_widget (gui, "gog_3d_box_prefs");
+	g_object_set_data_full (G_OBJECT (w),
+		"state", gui, (GDestroyNotify)g_object_unref);
+	
+	gog_editor_add_page (editor, w, _("Advanced"));
+}
+
+#endif
+
+static void
+gog_3d_box_set_property (GObject *obj, guint param_id,
+			GValue const *value, GParamSpec *pspec)
+{
+	Gog3DBox *box = GOG_3D_BOX (obj);
+
+	switch (param_id) {
+	case BOX3D_PROP_PSI:
+		box->psi = g_value_get_double (value);
+		break;
+	case BOX3D_PROP_THETA:
+		box->theta = g_value_get_double (value);
+		break;
+	case BOX3D_PROP_PHI:
+		box->phi = g_value_get_double (value);
+		break;
+	case BOX3D_PROP_FOV:
+		box->fov = g_value_get_double (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		return;
+	}
+	go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+}
+
+static void
+gog_3d_box_get_property (GObject *obj, guint param_id,
+			GValue *value, GParamSpec *pspec)
+{
+	Gog3DBox *box = GOG_3D_BOX (obj);
+
+	switch (param_id) {
+	case BOX3D_PROP_PSI:
+		g_value_set_double (value, box->psi);
+		break;
+	case BOX3D_PROP_THETA: 
+		g_value_set_double (value, box->theta);
+		break;
+	case BOX3D_PROP_PHI:
+		g_value_set_double (value, box->phi);
+		break;
+	case BOX3D_PROP_FOV:
+		g_value_set_double (value, box->fov);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		break;
+	}
+}
+
 static void
 gog_3d_box_class_init (Gog3DBoxClass *klass)
 {
+	GObjectClass *gobject_klass = (GObjectClass *) klass;
+	GogObjectClass *gog_klass   = (GogObjectClass *) klass;
+
+	gobject_klass->set_property = gog_3d_box_set_property;
+	gobject_klass->get_property = gog_3d_box_get_property;
+	
+	g_object_class_install_property (gobject_klass, BOX3D_PROP_PSI,
+		g_param_spec_double ("psi", 
+			"Psi",
+			_("Euler angle psi"),
+			0.0, 2 * M_PI, 70. / 180. * M_PI, 
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+			| GOG_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, BOX3D_PROP_THETA,
+		g_param_spec_double ("theta", 
+			"Theta",
+			_("Euler angle theta"),
+			0.0, 2 * M_PI, 10. / 180. * M_PI, 
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+			| GOG_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, BOX3D_PROP_PHI,
+		g_param_spec_double ("phi", 
+			"Phi",
+			_("Euler angle phi"),
+			0.0, 2 * M_PI, 270. / 180. * M_PI, 
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+			| GOG_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, BOX3D_PROP_FOV,
+		g_param_spec_double ("fov", 
+			"FoV",
+			_("Field of view"),
+			0.0, M_PI, 10. / 180. * M_PI, 
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+			| GOG_PARAM_PERSISTENT));
+
+#ifdef GOFFICE_WITH_GTK
+	gog_klass->populate_editor = gog_3d_box_populate_editor;
+#endif
 }
 
 static void
@@ -37,7 +323,7 @@
 	box->fov = 10. / 180. * M_PI;
 	box->psi = 70. / 180. * M_PI;
 	box->theta = 10. / 180. * M_PI;
-	box->phi = -90. / 180. * M_PI;
+	box->phi = 270. / 180. * M_PI;
 	go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
 }
 

Modified: trunk/goffice/gtk/Makefile.am
==============================================================================
--- trunk/goffice/gtk/Makefile.am	(original)
+++ trunk/goffice/gtk/Makefile.am	Mon Jul  7 06:41:37 2008
@@ -8,6 +8,7 @@
 	go-rotation-sel.c	 	\
 	go-charmap-sel.c		\
 	go-locale-sel.c			\
+	go-3d-rotation-sel.c		\
 	\
 	go-optionmenu.c			\
 	go-combo-box.c			\
@@ -44,6 +45,7 @@
 	go-rotation-sel.h	 	\
 	go-charmap-sel.h		\
 	go-locale-sel.h			\
+	go-3d-rotation-sel.h		\
 	\
 	go-optionmenu.h			\
 	go-combo-box.h			\
@@ -76,6 +78,7 @@
 	go-rotation-sel.glade			\
 	go-font-sel.glade 			\
 	go-format-sel.glade 			\
+ 	go-3d-rotation-sel.glade		\
 	go-image-save-dialog-extra.glade	\
 	go-image-sel.glade
 

Added: trunk/goffice/gtk/go-3d-rotation-sel.c
==============================================================================
--- (empty file)
+++ trunk/goffice/gtk/go-3d-rotation-sel.c	Mon Jul  7 06:41:37 2008
@@ -0,0 +1,499 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-3d-rotation-sel.c: A widget to select rotation angles of 3d plot
+ *
+ * This program 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.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA.
+ */
+#include <goffice/goffice-config.h>
+#include "go-3d-rotation-sel.h"
+
+#include <goffice/gtk/goffice-gtk.h>
+#include <goffice/math/go-math.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-util.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-line.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-widget.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-polygon.h>
+#include <gsf/gsf-impl-utils.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkrange.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtklabel.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+
+typedef struct {
+	double x, y, z;
+} g3d_point;
+
+struct _GO3DRotationSel {
+	GtkHBox		 box;
+	GladeXML	*gui;
+	GtkRange	*fovscale;
+	double		 psi;
+	double		 theta;
+	double		 phi;
+	double		 fov;
+	GOMatrix3x3	 mat;
+
+	int		 radius;
+	int		 margin;
+	int		 bank_dial_x;
+	int		 bank_dial_y;
+	int		 bank_dial_r;
+	double		 old_x, old_y;
+	double		 bank;
+	g3d_point	*cube_points;
+	int 	 	*cube_faces;
+	FooCanvas       *rotate_canvas;
+	FooCanvasItem   *dial;
+	FooCanvasItem	*bank_dial;
+	FooCanvasItem	*cube_polygons[6];
+	gulong		 motion_handle;
+};
+
+typedef struct {
+	GtkHBoxClass parent_class;
+	void (* psi_changed) (GO3DRotationSel *g3d, int angle);
+	void (* theta_changed) (GO3DRotationSel *g3d, int angle);
+	void (* phi_changed) (GO3DRotationSel *g3d, int angle);
+	void (* fov_changed) (GO3DRotationSel *g3d, int angle);
+} GO3DRotationSelClass;
+
+enum {
+	MATRIX_CHANGED,
+	PSI_CHANGED,
+	THETA_CHANGED,
+	PHI_CHANGED,
+	FOV_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint g3d_signals[LAST_SIGNAL] = { 0, 0, 0, 0, 0 };
+static GObjectClass *g3d_parent_class;
+
+/* NOTE: This works only for angles [-2*pi,4*pi] */
+static double
+g3d_normalize (double angle)
+{
+	if (angle > 2 * M_PI)
+		return angle - 2 * M_PI;
+	if (angle < 0)
+		return angle + 2 * M_PI;
+	return angle;
+}
+
+static void
+cb_rotation_changed (GO3DRotationSel *g3d)
+{
+	double mgn = g3d->margin - 2;
+	double r = g3d->radius;
+	double d = 2 * r;
+	double dr = g3d->bank_dial_r;
+	double dx = g3d->bank_dial_x = mgn + r * (1 - sin (g3d->bank));
+	double dy = g3d->bank_dial_y = mgn + r * (1 - cos (g3d->bank));
+
+	/*double psi, theta, phi;*/
+	g3d_point cp[] = {
+		{ 50,  50,  50},
+		{ 50, -50,  50},
+		{-50, -50,  50},
+		{-50,  50,  50},
+		{ 50,  50, -50},
+		{ 50, -50, -50},
+		{-50, -50, -50},
+		{-50,  50, -50},
+	};
+	const int cf[] = {
+		0, 1, 2, 3,
+		4, 5, 6, 7,
+		0, 1, 5, 4,
+		1, 2, 6, 5,
+		2, 3, 7, 6,
+		3, 0, 4, 7
+	};
+	int i;
+
+	if (g3d->dial) {
+		foo_canvas_item_set (g3d->dial,
+			"x1", mgn, "y1", mgn,
+			"x2", mgn + d, "y2", mgn + d, NULL);
+	}
+
+	if (g3d->bank_dial) {
+		foo_canvas_item_set (g3d->bank_dial,
+			"x1", dx - dr, "y1", dy - dr,
+			"x2", dx + dr, "y2", dy + dr, NULL);
+	}
+
+	for (i = 0; i < 8; ++i) {
+		double x = cp[i].x;
+		double y = cp[i].y;
+		double z = cp[i].z;
+		go_matrix3x3_transform (&g3d->mat, x, y, z,
+		                        &cp[i].x, &cp[i].y, &cp[i].z);
+	}
+
+	for (i = 0; i < 6; ++i) {
+		FooCanvasPoints *points;
+		double cx = mgn + r;
+		double mean_y;
+		if (g3d->cube_polygons[i] == NULL)
+			continue;
+
+		points = foo_canvas_points_new (5);
+		points->coords[0] = cp[cf[4 * i + 0]].x + cx;
+		points->coords[1] = -cp[cf[4 * i + 0]].z + cx;
+		points->coords[2] = cp[cf[4 * i + 1]].x + cx;
+		points->coords[3] = -cp[cf[4 * i + 1]].z + cx;
+		points->coords[4] = cp[cf[4 * i + 2]].x + cx;
+		points->coords[5] = -cp[cf[4 * i + 2]].z + cx;
+		points->coords[6] = cp[cf[4 * i + 3]].x + cx;
+		points->coords[7] = -cp[cf[4 * i + 3]].z + cx;
+		points->coords[8] = cp[cf[4 * i + 0]].x + cx;
+		points->coords[9] = -cp[cf[4 * i + 0]].z + cx;
+
+		/* NOTE: This back face culling method works only with
+		 * a cube in parallel projection*/
+		mean_y  = cp[cf[4 * i + 0]].y;
+		mean_y += cp[cf[4 * i + 1]].y;
+		mean_y += cp[cf[4 * i + 2]].y;
+		mean_y += cp[cf[4 * i + 3]].y;
+		foo_canvas_item_set (g3d->cube_polygons[i], "points", points,
+		                     "width_units", (mean_y < 0) ? 4. : 0.5, 
+				     "fill-color", (i == 1)? "light blue" : "none",
+				     NULL);
+		foo_canvas_points_free (points);
+	}
+	go_matrix3x3_to_euler (&g3d->mat, &g3d->psi, &g3d->theta, &g3d->phi);
+
+	g3d->psi = g3d_normalize (g3d->psi);
+	g3d->theta = g3d_normalize (g3d->theta);
+	g3d->phi = g3d_normalize (g3d->phi);
+
+	g_signal_emit (G_OBJECT (g3d),
+		g3d_signals[PSI_CHANGED], 0, (int) (g3d->psi * 180 / M_PI));
+	g_signal_emit (G_OBJECT (g3d),
+		g3d_signals[THETA_CHANGED], 0, (int) (g3d->theta * 180 / M_PI));
+	g_signal_emit (G_OBJECT (g3d),
+		g3d_signals[PHI_CHANGED], 0, (int) (g3d->phi * 180 / M_PI));
+}
+
+static gboolean
+cb_fov_changed (GtkRange *range, GdkEventButton *event, GO3DRotationSel *g3d)
+{
+	int angle = gtk_range_get_value (GTK_RANGE (range));
+	g3d->fov = angle * M_PI / 180;
+	g_signal_emit (G_OBJECT (g3d), g3d_signals[FOV_CHANGED], 0, angle);
+	return FALSE;
+}
+
+static void
+cb_rotate_canvas_realize (FooCanvas *canvas, GO3DRotationSel *g3d)
+{
+	FooCanvasGroup  *group = FOO_CANVAS_GROUP (foo_canvas_root (canvas));
+	GtkStyle *style = gtk_style_copy (GTK_WIDGET (canvas)->style);
+	int i;
+	style->bg[GTK_STATE_NORMAL] = style->white;
+	gtk_widget_set_style (GTK_WIDGET (canvas), style);
+	g_object_unref (style);
+
+	foo_canvas_set_scroll_region (canvas, 0, 0, 220, 220);
+	foo_canvas_scroll_to (canvas, 0, 0);
+
+	for (i = 0; i < 6; ++i) {
+		g3d->cube_polygons[i] = foo_canvas_item_new (group,
+			FOO_TYPE_CANVAS_POLYGON, "outline-color", "black",
+			NULL);
+	}
+
+	g3d->dial = foo_canvas_item_new (group,
+        	FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
+		"width_units", 2., NULL);
+
+	g3d->bank_dial = foo_canvas_item_new (group,
+		FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
+		"fill_color", "white", "width_units", 3., NULL);
+
+	cb_rotation_changed(g3d);	
+}
+
+
+static gboolean
+cb_bank_dial_motion_notify_event (FooCanvas *canvas, GdkEventMotion *event,
+			          GO3DRotationSel *g3d)
+{
+	GOMatrix3x3 m1, m2;
+	double x = event->x;
+	double y = event->y;
+	double theta, bank;
+
+	x -= g3d->margin + g3d->radius;
+	y -= g3d->margin + g3d->radius;
+
+	bank = g3d_normalize (-atan2 (x, -y));
+	theta = g3d->bank - bank;
+	g3d->bank = bank;
+	g3d->old_x = event->x;
+	g3d->old_y = event->y;
+	go_matrix3x3_from_euler (&m1, 0, theta, -M_PI * 0.5);
+	go_matrix3x3_from_euler (&m2, 0, 0, M_PI * 0.5);
+	go_matrix3x3_multiply (&m1, &m2, &m1);
+	go_matrix3x3_multiply (&g3d->mat, &m1, &g3d->mat);
+	cb_rotation_changed (g3d);
+	return TRUE;
+}
+
+static gboolean
+cb_rotate_motion_notify_event (FooCanvas *canvas, GdkEventMotion *event,
+			       GO3DRotationSel *g3d)
+{
+	GOMatrix3x3 m1, m2, m3;
+	double theta, phi, dx, dy;
+
+	dx = event->x - g3d->old_x;
+	dy = event->y - g3d->old_y;
+	theta = atan2 (dy, dx);
+	phi = sqrt (dx * dx + dy * dy) * M_PI / 180;
+	g3d->old_x = event->x;
+	g3d->old_y = event->y;
+
+	go_matrix3x3_from_euler (&m1, 0, theta, phi);
+	go_matrix3x3_from_euler_transposed (&m2, 0, theta, 0);
+	go_matrix3x3_from_euler (&m3, 0, 0, M_PI * 0.5);
+	go_matrix3x3_multiply (&m1, &m3, &m1);
+	go_matrix3x3_multiply (&m1, &m1, &m2);
+	go_matrix3x3_from_euler (&m3, 0, 0, -M_PI * 0.5);
+	go_matrix3x3_multiply (&m1, &m1, &m3);
+	go_matrix3x3_multiply (&g3d->mat, &m1, &g3d->mat);
+	cb_rotation_changed (g3d);	
+	return TRUE;
+}
+
+static gboolean
+cb_rotate_canvas_button (FooCanvas *canvas, GdkEventButton *event,
+                         GO3DRotationSel *g3d)
+{
+	double x, y, r;
+	if (event->type == GDK_BUTTON_PRESS) {
+		if (g3d->motion_handle != 0)
+			return TRUE;
+		x = g3d->old_x = event->x;
+		y = g3d->old_y = event->y;
+		x -= g3d->bank_dial_x;
+		y -= g3d->bank_dial_y;
+		r = g3d->bank_dial_r;
+		gdk_pointer_grab (canvas->layout.bin_window, FALSE,
+			GDK_POINTER_MOTION_MASK
+			| GDK_BUTTON_RELEASE_MASK, NULL, NULL,
+			event->time);
+
+		if (x * x + y * y <= r * r) {
+			g3d->motion_handle = g_signal_connect (G_OBJECT (canvas),
+				"motion_notify_event",
+				G_CALLBACK (cb_bank_dial_motion_notify_event),
+				g3d);
+		} else {
+			g3d->motion_handle = g_signal_connect (G_OBJECT (canvas),
+				"motion_notify_event",
+				G_CALLBACK (cb_rotate_motion_notify_event), g3d);
+		}
+	} else if (event->type == GDK_BUTTON_RELEASE) {
+		if (g3d->motion_handle == 0)
+			return TRUE;
+		gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (canvas)),
+			event->time);
+		g_signal_handler_disconnect (canvas, g3d->motion_handle);
+		g3d->motion_handle = 0;
+		g_signal_emit (G_OBJECT (g3d),
+			g3d_signals[MATRIX_CHANGED], 0, &g3d->mat);
+	}
+	return TRUE;
+}
+
+static void
+g3d_init (GO3DRotationSel *g3d)
+{
+	GtkWidget *w;
+
+	g3d->gui = go_libglade_new ("go-3d-rotation-sel.glade", "toplevel",
+		GETTEXT_PACKAGE, NULL);
+	if (g3d->gui == NULL)
+		return;
+
+	g3d->radius = 100;
+	g3d->margin = 10;
+	g3d->bank_dial_x = g3d->margin + g3d->radius;
+	g3d->bank_dial_y = g3d->margin;
+	g3d->bank_dial_r = 7;
+	g3d->dial = NULL;
+	g3d->bank_dial = NULL;
+	memset (g3d->cube_polygons, 0, sizeof (g3d->cube_polygons));
+	g3d->rotate_canvas = FOO_CANVAS (foo_canvas_new ());
+	gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (g3d->gui,
+	                   "rotate_canvas")),
+	                   GTK_WIDGET (g3d->rotate_canvas));
+	gtk_widget_show (GTK_WIDGET (g3d->rotate_canvas));
+	
+	g3d->motion_handle = 0;
+	g_object_connect (G_OBJECT (g3d->rotate_canvas),
+	                  "signal::realize",
+			  G_CALLBACK (cb_rotate_canvas_realize), g3d,
+	                  "signal::button-press-event",
+			  G_CALLBACK (cb_rotate_canvas_button), g3d,
+	                  "signal::button-release-event",
+			  G_CALLBACK (cb_rotate_canvas_button), g3d,
+	                  NULL);
+
+	g3d->fovscale = GTK_RANGE (glade_xml_get_widget (g3d->gui, "fovscale"));
+	g_signal_connect (G_OBJECT (g3d->fovscale), "button-release-event",
+	                  G_CALLBACK (cb_fov_changed), g3d);
+	w = glade_xml_get_widget (g3d->gui, "toplevel");
+	gtk_box_pack_start (GTK_BOX (g3d), w, TRUE, TRUE, 0);
+	gtk_widget_show_all (GTK_WIDGET (g3d));
+}
+
+static void
+g3d_finalize (GObject *obj)
+{
+	GO3DRotationSel *g3d = GO_3D_ROTATION_SEL (obj);
+
+	if (g3d->gui) {
+		g_object_unref (G_OBJECT (g3d->gui));
+		g3d->gui = NULL;
+	}
+
+	g3d_parent_class->finalize (obj);
+}
+
+static void
+g3d_class_init (GObjectClass *klass)
+{
+	GObjectClass *gobj_class = (GObjectClass *) klass;
+	gobj_class->finalize = g3d_finalize;
+
+	g3d_parent_class = g_type_class_peek (gtk_hbox_get_type ());
+	g3d_signals [MATRIX_CHANGED] = g_signal_new ("matrix-changed",
+		G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (GO3DRotationSelClass, psi_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+	g3d_signals [PSI_CHANGED] = g_signal_new ("psi-changed",
+		G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (GO3DRotationSelClass, psi_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__INT,
+		G_TYPE_NONE, 1, G_TYPE_INT);
+	g3d_signals [THETA_CHANGED] = g_signal_new ("theta-changed",
+		G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (GO3DRotationSelClass, theta_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__INT,
+		G_TYPE_NONE, 1, G_TYPE_INT);
+	g3d_signals [PHI_CHANGED] = g_signal_new ("phi-changed",
+		G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (GO3DRotationSelClass, phi_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__INT,
+		G_TYPE_NONE, 1, G_TYPE_INT);
+	g3d_signals [FOV_CHANGED] = g_signal_new ("fov-changed",
+		G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (GO3DRotationSelClass, fov_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__INT,
+		G_TYPE_NONE, 1, G_TYPE_INT);
+}
+
+GSF_CLASS (GO3DRotationSel, go_3d_rotation_sel,
+	   g3d_class_init, g3d_init, GTK_TYPE_HBOX)
+
+GtkWidget *
+go_3d_rotation_sel_new (void)
+{
+	return g_object_new (GO_3D_ROTATION_SEL_TYPE, NULL);
+}
+
+void
+go_3d_rotation_sel_get_matrix (GO3DRotationSel const *g3d, GOMatrix3x3 *mat)
+{
+	mat->a11 = g3d->mat.a11;
+	mat->a12 = g3d->mat.a12;
+	mat->a13 = g3d->mat.a13;
+	mat->a21 = g3d->mat.a21;
+	mat->a22 = g3d->mat.a22;
+	mat->a23 = g3d->mat.a23;
+	mat->a31 = g3d->mat.a31;
+	mat->a32 = g3d->mat.a32;
+	mat->a33 = g3d->mat.a33;
+}
+
+double
+go_3d_rotation_sel_get_psi (GO3DRotationSel const *g3d)
+{
+	g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+	return g3d->psi;
+}
+
+double
+go_3d_rotation_sel_get_theta (GO3DRotationSel const *g3d)
+{
+	g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+	return g3d->theta;
+}
+
+double
+go_3d_rotation_sel_get_phi (GO3DRotationSel const *g3d)
+{
+	g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+	return g3d->phi;
+}
+
+double
+go_3d_rotation_sel_get_fov (GO3DRotationSel const *g3d)
+{
+	g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+	return g3d->fov;
+}
+
+void
+go_3d_rotation_sel_set_matrix (GO3DRotationSel *g3d, GOMatrix3x3 *mat)
+{
+	g3d->mat.a11 = mat->a11; 
+	g3d->mat.a12 = mat->a12; 
+	g3d->mat.a13 = mat->a13; 
+	g3d->mat.a21 = mat->a21; 
+	g3d->mat.a22 = mat->a22; 
+	g3d->mat.a23 = mat->a23; 
+	g3d->mat.a31 = mat->a31; 
+	g3d->mat.a32 = mat->a32; 
+	g3d->mat.a33 = mat->a33; 
+
+	cb_rotation_changed (g3d);
+}
+
+void
+go_3d_rotation_sel_set_fov (GO3DRotationSel *g3d, double fov)
+{
+	g3d->fov = fov;
+	g_signal_handlers_block_matched (GTK_RANGE (g3d->fovscale),
+		G_SIGNAL_MATCH_FUNC, 0, 0, 0, G_CALLBACK (cb_fov_changed), 0);
+	gtk_range_set_value (GTK_RANGE (g3d->fovscale),
+		(int) (fov * 180. / M_PI));
+	g_signal_handlers_unblock_matched (GTK_RANGE (g3d->fovscale),
+		G_SIGNAL_MATCH_FUNC, 0, 0, 0, G_CALLBACK (cb_fov_changed), 0);
+}

Added: trunk/goffice/gtk/go-3d-rotation-sel.glade
==============================================================================
--- (empty file)
+++ trunk/goffice/gtk/go-3d-rotation-sel.glade	Mon Jul  7 06:41:37 2008
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+  <widget class="GtkWindow" id="window1">
+    <property name="visible">True</property>
+    <property name="title" translatable="yes">window2</property>
+    <child>
+      <widget class="GtkHBox" id="toplevel">
+        <property name="visible">True</property>
+        <property name="border_width">12</property>
+        <property name="spacing">24</property>
+        <child>
+          <widget class="GtkVBox" id="vbox7">
+            <property name="visible">True</property>
+            <property name="spacing">12</property>
+            <child>
+              <widget class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Rotation&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkScrolledWindow" id="rotate_canvas">
+                    <property name="width_request">220</property>
+                    <property name="height_request">220</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkVScale" id="fovscale">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="adjustment">0 0 190 1 10 10</property>
+                    <property name="digits">0</property>
+                    <property name="draw_value">False</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/goffice/gtk/go-3d-rotation-sel.h
==============================================================================
--- (empty file)
+++ trunk/goffice/gtk/go-3d-rotation-sel.h	Mon Jul  7 06:41:37 2008
@@ -0,0 +1,48 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-3d-rotation-sel.h - Select a rotation angles
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA.
+ */
+#ifndef _GO_3D_ROTATION_SEL_H_
+#define _GO_3D_ROTATION_SEL_H_
+
+#include <gtk/gtkwindow.h>
+#include <goffice/utils/goffice-utils.h>
+#include <goffice/math/go-matrix3x3.h>
+
+G_BEGIN_DECLS
+
+#define GO_3D_ROTATION_SEL_TYPE	(go_3d_rotation_sel_get_type ())
+#define GO_3D_ROTATION_SEL(obj)	(G_TYPE_CHECK_INSTANCE_CAST((obj), \
+                                 GO_3D_ROTATION_SEL_TYPE, GO3DRotationSel))
+#define IS_GO_3D_ROTATION_SEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+                                    GO_3D_ROTATION_SEL_TYPE))
+
+typedef struct _GO3DRotationSel GO3DRotationSel;
+
+GType      go_3d_rotation_sel_get_type (void);
+GtkWidget *go_3d_rotation_sel_new (void);
+void       go_3d_rotation_sel_set_matrix (GO3DRotationSel *rs, GOMatrix3x3 *mat);
+void       go_3d_rotation_sel_set_fov (GO3DRotationSel *rs, double fov);
+void       go_3d_rotation_sel_get_matrix (GO3DRotationSel const *rs, GOMatrix3x3 *mat);
+double     go_3d_rotation_sel_get_psi (GO3DRotationSel const *rs);
+double     go_3d_rotation_sel_get_theta (GO3DRotationSel const *rs);
+double     go_3d_rotation_sel_get_phi (GO3DRotationSel const *rs);
+double     go_3d_rotation_sel_get_fov (GO3DRotationSel const *rs);
+
+G_END_DECLS
+
+#endif /* _GO_3D_ROTATION_SEL_H_ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]