/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)
  
	Adresse mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.

	Ce logiciel est un programme informatique servant à visualiser des
	structures atomiques dans un rendu pseudo-3D. 

	Ce logiciel est régi par la licence CeCILL soumise au droit français et
	respectant les principes de diffusion des logiciels libres. Vous pouvez
	utiliser, modifier et/ou redistribuer ce programme sous les conditions
	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
	sur le site "http://www.cecill.info".

	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
	pris connaissance de la licence CeCILL, et que vous en avez accepté les
	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
	Copyright CEA, contributors : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)

	E-mail address:
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.

	This software is a computer program whose purpose is to visualize atomic
	configurations in 3D.

	This software is governed by the CeCILL  license under French law and
	abiding by the rules of distribution of free software.  You can  use, 
	modify and/ or redistribute the software under the terms of the CeCILL
	license as circulated by CEA, CNRS and INRIA at the following URL
	"http://www.cecill.info". 

	The fact that you are presently reading this means that you have had
	knowledge of the CeCILL license and that you accept its terms. You can
	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#include <gdk/gdkkeysyms.h>

#include "support.h"
#include "interface.h"
#include "gtk_interactive.h"
#include "gtk_main.h"
#include "visu_gtk.h"

#include "gtk_pick.h"
#include "gtk_move.h"
#include "gtk_renderingWindowWidget.h"
#include "openGLFunctions/interactive.h"
#include "extraGtkFunctions/gtk_numericalEntryWidget.h"
#include "extraGtkFunctions/gtk_orientationChooser.h"

/**
 * SECTION: gtk_interactive
 * @short_description: The interactive dialog.
 *
 * <para>This is the second main interface for V_Sim after the command
 * panel. It provides widgets to interact with the nodes. There is
 * three built-in interactive modes : the observe one (as in normal
 * behaviour), the pick one and the move one.</para>
 * <para>It is possible to add new action thanks to
 * visu_ui_interactive_addAction() function. It is also possible to
 * show a small warning message with visu_ui_interactive_setMessage()
 * that shows a GtkInfoBar.</para>
 */

/* Local types. */
typedef struct ActionInterface_
{
  guint id;

  gchar *label;
  gchar *help;

  GtkWidget *radio;

  VisuUiInteractiveBuild build;
  VisuInteractiveId mode;
  VisuUiInteractiveStartStop onStart, onStop;
} ActionInterface;

/* Local variables. */
static ActionInterface* currentAction;
static guint n_actions = 0;
static GList *actions;
static VisuInteractive *interObserve = NULL;
static GBinding *theta_bind, *phi_bind, *omega_bind;
static GBinding *xs_bind, *ys_bind, *gross_bind, *persp_bind;

/* Callbacks. */
static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event,
			      gpointer data);
static void onDataNotify(GtkButton *button, GParamSpec *pspec, VisuGlNodeScene *scene);
static void observeMethodChanged(GtkToggleButton* button, gpointer data);
static void radioObserveToggled(GtkToggleButton *togglebutton, gpointer user_data);
static void onCloseButtonClicked(GtkButton *button, gpointer user_data);
static void onTabActionChanged(GtkNotebook *book, GtkWidget *child,
			       gint num, gpointer data);
static void onVisuUiOrientationChooser(GtkButton *button, gpointer data);
static gboolean onKillWindowEvent(GtkWidget *widget, GdkEvent *event,
				  gpointer user_data);
static void onRadioToggled(GtkToggleButton *toggle, gpointer data);
static void onObserveStart(VisuUiRenderingWindow *window);
static void onObserveStop(VisuUiRenderingWindow *window);

/* Local methods. */
static void _setGlView(VisuGlView *view);
static void connectSignalsObservePick(VisuUiRenderingWindow *window);
static void setNamesGtkWidgetObservePick(VisuUiMain *main);
static GtkWidget* gtkObserveBuild_interface(VisuUiMain *main, gchar **label,
					    gchar **help, GtkWidget **radio);

/* Widgets */
static GtkWidget *observeWindow, *infoBar;
static GtkWidget *orientationChooser;
static GtkWidget *spinOmega;


/* Help message used in the help area. */
#define GTK_PICKOBSERVE_OBSERVE_INFO \
  _("left-[control]-button\t\t\t: rotations "				\
    "(\316\270, \317\206, [control]\317\211)\n"				\
    "shift-left-button\t\t\t\t: translations (dx, dy)\n"		\
    "middle-[shift]-button or wheel\t: zoom or [shift]perspective\n"	\
    "key 's' / 'r'\t\t\t\t\t: save/restore camera position\n"		\
    "right-button\t\t\t\t\t: switch to current tabbed action")

/**
 * visu_ui_interactive_init: (skip)
 *
 * Initialise the observe/pick window, connect the
 * signals, give names to widgets...
 */
void visu_ui_interactive_init()
{
  orientationChooser = (GtkWidget*)0;
  /* Set the actions tabs. */
  actions = (GList*)0;

  visu_ui_interactive_addAction(gtkObserveBuild_interface,
                                onObserveStart, onObserveStop);
  currentAction = (ActionInterface*)actions->data;

  visu_ui_interactive_addAction(visu_ui_interactive_pick_initBuild,
                                visu_ui_interactive_pick_start, visu_ui_interactive_pick_stop);

  visu_ui_interactive_addAction(visu_ui_interactive_move_initBuild,
                                visu_ui_interactive_move_start, visu_ui_interactive_move_stop);
}

/**
 * visu_ui_interactive_addAction:
 * @build: a routine to build a tab.
 * @start: a routine to run when session is selected.
 * @stop: a routine to run when session is stopped.
 *
 * One can add new interactive mode with specific tab in the
 * interactive dialog.
 *
 * Since: 3.6
 *
 * Returns: an id for this new action.
 */
guint visu_ui_interactive_addAction(VisuUiInteractiveBuild build,
			       VisuUiInteractiveStartStop start,
			       VisuUiInteractiveStartStop stop)
{
  ActionInterface *action;

  g_return_val_if_fail(build && start && stop, 0);

  action = g_malloc(sizeof(ActionInterface));
  action->id      = n_actions;
  action->build   = build;
  action->onStart = start;
  action->onStop  = stop;

  actions       = g_list_append(actions, action);
  n_actions += 1;

  return action->id;
}

static GtkWidget* gtkObserveBuild_interface(VisuUiMain *main _U_, gchar **label,
					    gchar **help, GtkWidget **radio)
{
  *label = g_strdup("Observe");
  *help  = g_strdup(GTK_PICKOBSERVE_OBSERVE_INFO);
  *radio = lookup_widget(observeWindow, "radioObserve");

  return (GtkWidget*)0;
}
/**
 * visu_ui_interactive_initBuild: (skip)
 * @main: the command panel the about dialog is associated to.
 *
 * create the window.
 */
void visu_ui_interactive_initBuild(VisuUiMain *main)
{
  GtkWidget *labelHelp, *wd;
  VisuUiRenderingWindow *window;
  VisuGlNodeScene *scene;
  VisuGlView *view;
  GList *tmpLst;
  ActionInterface *action;
  gchar *msg;
  GSList *lst;
 
  window = visu_ui_main_getRendering(main);
  scene = visu_ui_rendering_window_getGlScene(window);
  view = visu_gl_node_scene_getGlView(scene);

  DBG_fprintf(stderr, "Gtk Interactive: init build.\n");

  interObserve = visu_interactive_new(interactive_observe);
  g_signal_connect_swapped(G_OBJECT(interObserve), "stop",
                           G_CALLBACK(visu_ui_interactive_toggle), (gpointer)0);

  DBG_fprintf(stderr, "Gtk observePick: creating the window.\n");
  main->interactiveDialog = create_observeDialog();
  gtk_window_set_default_size(GTK_WINDOW(main->interactiveDialog), 100, -1);
  g_signal_connect_swapped(G_OBJECT(main->interactiveDialog), "destroy",
                           G_CALLBACK(g_object_unref), interObserve);
  observeWindow = main->interactiveDialog;
  gtk_window_set_type_hint(GTK_WINDOW(main->interactiveDialog),
			   GDK_WINDOW_TYPE_HINT_NORMAL);
  setNamesGtkWidgetObservePick(main);
  g_signal_connect(G_OBJECT(observeWindow), "key-press-event",
		   G_CALLBACK(onHomePressed), (gpointer)observeWindow);

  /* Create the actions parts. */
  DBG_fprintf(stderr, "Gtk Interactive: Create the actions parts.\n");
  lst = (GSList*)0;
  for (tmpLst = actions; tmpLst; tmpLst = g_list_next(tmpLst))
    {
      action = ((ActionInterface*)tmpLst->data);
      g_return_if_fail(action->build);
      wd = action->build(main, &action->label, &msg, &action->radio);
      DBG_fprintf(stderr, " | action '%s'\n", action->label);
      action->help = g_markup_printf_escaped("<span size=\"smaller\">%s</span>", msg);
      g_free(msg);
      if (wd)
	gtk_notebook_append_page
	  (GTK_NOTEBOOK(lookup_widget(observeWindow, "notebookAction")),
	   wd, gtk_label_new(action->label));
      if (action->id > 0)
	gtk_radio_button_set_group(GTK_RADIO_BUTTON(action->radio), lst);
      lst = gtk_radio_button_get_group(GTK_RADIO_BUTTON(action->radio));
      g_signal_connect(G_OBJECT(action->radio), "toggled",
		       G_CALLBACK(onRadioToggled), (gpointer)action);
      DBG_fprintf(stderr, " | action '%s' OK\n", action->label);
    }

  /* Create and Set the help text. */
  action = ((ActionInterface*)actions->data);
  labelHelp = lookup_widget(main->interactiveDialog, "labelInfoObservePick");
  gtk_label_set_markup(GTK_LABEL(labelHelp), action->help);

  /* Add an info bar for warning and so on. */
#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 
  infoBar = gtk_info_bar_new();
  gtk_widget_set_no_show_all(infoBar, TRUE);
  gtk_info_bar_add_button(GTK_INFO_BAR(infoBar),
                          _("_Ok"), GTK_RESPONSE_OK);
  g_signal_connect(infoBar, "response",
                   G_CALLBACK(gtk_widget_hide), NULL);
  wd = gtk_label_new("");
  gtk_label_set_xalign(GTK_LABEL(wd), 0.);
  gtk_container_add(GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar))), wd);
  gtk_widget_show(wd);
#else
  infoBar = gtk_label_new("");
  gtk_misc_set_alignment(GTK_MISC(infoBar), 0., 0.5);
#endif
  gtk_box_pack_end(GTK_BOX(lookup_widget(observeWindow, "vbox20")),
                   infoBar, FALSE, FALSE, 2);

  /* connect the signals to the spins. */
  connectSignalsObservePick(window);
  theta_bind = NULL;
  phi_bind   = NULL;
  omega_bind = NULL;
  xs_bind    = NULL;
  ys_bind    = NULL;
  gross_bind = NULL;
  persp_bind = NULL;

  DBG_fprintf(stderr, "Gtk Interactive: Setup initial values.\n");
  _setGlView(view);

  g_signal_connect_object(scene, "notify::data", G_CALLBACK(onDataNotify),
                          lookup_widget(observeWindow, "buttonBackToCommandPanel"),
                          G_CONNECT_SWAPPED);
}

/**
 * visu_ui_interactive_toggle:
 *
 * The user can switch between a current specific interactive action
 * and the observe mode. This routine is used to do this.*
 *
 * Since: 3.6
 */
void visu_ui_interactive_toggle(void)
{
  GtkWidget *wd;
  guint id;
  ActionInterface *action;

  if (currentAction->id == VISU_UI_ACTION_OBSERVE)
    {
      wd = lookup_widget(observeWindow, "notebookAction");
      id = gtk_notebook_get_current_page(GTK_NOTEBOOK(wd)) + 1;
    }
  else
    id = VISU_UI_ACTION_OBSERVE;
  action = (ActionInterface*)g_list_nth_data(actions, id);

  /* We toggle on the radio of the new action. */
  if (action->radio)
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(action->radio), TRUE);
}
/**
 * visu_ui_interactive_start:
 * @window: the current rendering widget.
 * 
 * Start the observe & pick session.
 */
void visu_ui_interactive_start(VisuUiRenderingWindow *window)
{
  DBG_fprintf(stderr, "Gtk Interactive: initialise session.\n");

  visu_ui_rendering_window_pushMessage(window, "");
  currentAction->onStart(window);
}

/**
 * visu_ui_interactive_stop:
 * @window: a #VisuUiRenderingWindow object.
 *
 * Stop the observe and pick session from @window.
 *
 * Since: 3.8
 **/
void visu_ui_interactive_stop(VisuUiRenderingWindow *window)
{
  DBG_fprintf(stderr, "Gtk Interactive: stop session.\n");

  visu_ui_rendering_window_popMessage(window);
  currentAction->onStop(window);
}
/**
 * visu_ui_interactive_setMessage:
 * @message: a string.
 * @type: the type of message.
 *
 * Show a message in the interactive dialog.
 *
 * Since: 3.6
 */
void visu_ui_interactive_setMessage(const gchar *message, GtkMessageType type)
{
#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17 
  GList *lst;

  gtk_info_bar_set_message_type(GTK_INFO_BAR(infoBar), type);
  lst = gtk_container_get_children(GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar))));
  gtk_label_set_text(GTK_LABEL(lst->data), message);
  g_list_free(lst);
#else
  gtk_label_set_text(GTK_LABEL(infoBar), message);
#endif
  gtk_widget_show(infoBar);
}
/**
 * visu_ui_interactive_unsetMessage:
 *
 * Hide any message from the interactive dialog. See also
 * visu_ui_interactive_setMessage().
 *
 * Since: 3.6
 */
void visu_ui_interactive_unsetMessage()
{
  gtk_widget_hide(infoBar);
}

static gboolean onKillWindowEvent(GtkWidget *widget _U_, GdkEvent *event _U_,
				  gpointer user_data)
{
  DBG_fprintf(stderr, "Gtk interactive: window killed.\n");

  visu_ui_interactive_stop(VISU_UI_RENDERING_WINDOW(user_data));
  return FALSE;
}
static void onCloseButtonClicked(GtkButton *button _U_, gpointer user_data)
{
  DBG_fprintf(stderr, "Gtk interactive: click on close button.\n");

  if (!gtk_widget_get_visible(observeWindow))
    return;
  visu_ui_interactive_stop(VISU_UI_RENDERING_WINDOW(user_data));
}

/****************/
/* Private part */
/****************/

/* Connect the listeners on the signal emitted by the OpenGL server. */
static void connectSignalsObservePick(VisuUiRenderingWindow *window)
{
  GtkWidget *wd;

  g_signal_connect(G_OBJECT(observeWindow), "delete-event",
		   G_CALLBACK(onKillWindowEvent), window);
  g_signal_connect(G_OBJECT(observeWindow), "destroy-event",
		   G_CALLBACK(onKillWindowEvent), window);

  wd = lookup_widget(observeWindow, "buttonBackToCommandPanel");
  g_signal_connect(G_OBJECT(wd), "clicked",
		   G_CALLBACK(onCloseButtonClicked), window);
  wd = lookup_widget(observeWindow, "radioObserve");
  g_signal_connect(G_OBJECT(wd), "toggled",
		   G_CALLBACK(radioObserveToggled), (gpointer)0);

  wd = lookup_widget(observeWindow, "buttonVisuUiOrientationChooser");
  g_signal_connect(G_OBJECT(wd), "clicked",
		   G_CALLBACK(onVisuUiOrientationChooser), (gpointer)0);

  /* The observe widgets. */
  wd = lookup_widget(observeWindow, "radioObserveConstrained");
  g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(observeMethodChanged),
		   GINT_TO_POINTER(interactive_constrained));
  wd = lookup_widget(observeWindow, "radioObserveWalker");
  g_signal_connect(G_OBJECT(wd), "toggled", G_CALLBACK(observeMethodChanged),
		   GINT_TO_POINTER(interactive_walker));

  wd = lookup_widget(observeWindow, "notebookAction");
  g_signal_connect(G_OBJECT(wd), "switch-page",
		   G_CALLBACK(onTabActionChanged), (gpointer)0);
}

static void _setGlView(VisuGlView *view)
{
  if (theta_bind)
    g_object_unref(theta_bind);
  theta_bind = (GBinding*)0;
  if (phi_bind)
    g_object_unref(phi_bind);
  phi_bind = (GBinding*)0;
  if (omega_bind)
    g_object_unref(omega_bind);
  omega_bind = (GBinding*)0;
  if (xs_bind)
    g_object_unref(xs_bind);
  xs_bind = (GBinding*)0;
  if (ys_bind)
    g_object_unref(ys_bind);
  ys_bind = (GBinding*)0;
  if (gross_bind)
    g_object_unref(gross_bind);
  gross_bind = (GBinding*)0;
  if (persp_bind)
    g_object_unref(persp_bind);
  persp_bind = (GBinding*)0;

  if (view)
    {
      theta_bind = g_object_bind_property(view, "theta",
                                          lookup_widget(observeWindow,
                                                        "spinTheta"), "value",
                                          G_BINDING_BIDIRECTIONAL |
                                          G_BINDING_SYNC_CREATE);
      phi_bind   = g_object_bind_property(view, "phi",
                                          lookup_widget(observeWindow,
                                                        "spinPhi"), "value",
                                          G_BINDING_BIDIRECTIONAL |
                                          G_BINDING_SYNC_CREATE);
      omega_bind = g_object_bind_property(view, "omega",
                                          lookup_widget(observeWindow,
                                                        "spinOmega"), "value",
                                          G_BINDING_BIDIRECTIONAL |
                                          G_BINDING_SYNC_CREATE);
      xs_bind    = g_object_bind_property(view, "trans-x",
                                          lookup_widget(observeWindow,
                                                        "spinDx"), "value",
                                          G_BINDING_BIDIRECTIONAL |
                                          G_BINDING_SYNC_CREATE);
      ys_bind    = g_object_bind_property(view, "trans-y",
                                          lookup_widget(observeWindow,
                                                        "spinDy"), "value",
                                          G_BINDING_BIDIRECTIONAL |
                                          G_BINDING_SYNC_CREATE);
      gross_bind = g_object_bind_property(view, "zoom",
                                          lookup_widget(observeWindow,
                                                        "spinGross"), "value",
                                          G_BINDING_BIDIRECTIONAL |
                                          G_BINDING_SYNC_CREATE);
      persp_bind = g_object_bind_property(view, "perspective",
                                          lookup_widget(observeWindow,
                                                        "spinPersp"), "value",
                                          G_BINDING_BIDIRECTIONAL |
                                          G_BINDING_SYNC_CREATE);
    }
}

static void onDataNotify(GtkButton *button, GParamSpec *pspec _U_, VisuGlNodeScene *scene)
{
  if (!visu_gl_node_scene_getData(scene))
    gtk_button_clicked(button);
}

static void onObserveStart(VisuUiRenderingWindow *window)
{
  visu_ui_rendering_window_pushInteractive(window, interObserve);
}
static void onObserveStop(VisuUiRenderingWindow *window)
{
  visu_ui_rendering_window_popInteractive(window, interObserve);
}

static void observeMethodChanged(GtkToggleButton* button, gpointer data)
{
  VisuInteractiveMethod method;

  if (!gtk_toggle_button_get_active(button))
    return;

  method = (VisuInteractiveMethod)GPOINTER_TO_INT(data);
  visu_interactive_class_setPreferedObserveMethod(method);
  if (method == interactive_constrained)
    {
      gtk_widget_set_sensitive(spinOmega, FALSE);
      g_object_set(visu_gl_node_scene_getGlView(visu_ui_rendering_window_getGlScene
                                                (visu_ui_main_class_getDefaultRendering())),
                   "omega", 0., NULL);
    }
  else
    gtk_widget_set_sensitive(spinOmega, TRUE);
}


/* Give a name to the widgets present in this window
   to be able to affect them with a theme. */
static void setNamesGtkWidgetObservePick(VisuUiMain *main)
{
  GtkWidget *wd;
  int method;

  gtk_widget_set_name(main->interactiveDialog, "message");
/*   wd = lookup_widget(main->interactiveDialog, "titreObserve"); */
/*   gtk_widget_set_name(wd, "message_title"); */
  wd = lookup_widget(main->interactiveDialog, "labelInfoObservePick");
  gtk_widget_set_name(wd, "label_info");

  wd = lookup_widget(main->interactiveDialog, "labelTranslation");
  gtk_widget_set_name(wd, "label_head_2");
  wd = lookup_widget(main->interactiveDialog, "labelZoom");
  gtk_widget_set_name(wd, "label_head_2");

  wd = lookup_widget(main->interactiveDialog, "radioObserve");
  gtk_widget_set_name(wd, "message_radio");
  wd = lookup_widget(main->interactiveDialog, "radioPick");
  gtk_widget_set_name(wd, "message_radio");
  wd = lookup_widget(main->interactiveDialog, "radioMove");
  gtk_widget_set_name(wd, "message_radio");

  spinOmega = lookup_widget(main->interactiveDialog, "spinOmega");

  method = visu_interactive_class_getPreferedObserveMethod();
  if (method == interactive_constrained)
    gtk_widget_set_sensitive(spinOmega, FALSE);

  wd = lookup_widget(main->interactiveDialog, "notebookAction");
  gtk_widget_set_name(wd, "message_notebook");

  wd = lookup_widget(main->interactiveDialog, "radioObserveConstrained");
  gtk_widget_set_name(wd, "message_radio");
  if (method == interactive_constrained)
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE);
  wd = lookup_widget(main->interactiveDialog, "radioObserveWalker");
  gtk_widget_set_name(wd, "message_radio");
  if (method == interactive_walker)
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE);
}
static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event,
			      gpointer data _U_)
{
  GtkWindow *window;

  DBG_fprintf(stderr, "Gtk Interactive: get key pressed.\n");
  if(event->keyval == GDK_KEY_Home)
    {
      window = visu_ui_getRenderWindow();
      g_return_val_if_fail(window, FALSE);
      /* We raised the rendering window, if required. */
      gtk_window_present(window);
      return TRUE;
    }
  return FALSE;
}

static void onRadioToggled(GtkToggleButton *toggle, gpointer data)
{
  GtkWidget *labelHelp;
  VisuUiRenderingWindow *window;

  if (!gtk_toggle_button_get_active(toggle))
    return;

  window = visu_ui_main_class_getDefaultRendering();
  
  /* Before setting up the current action, we pop
     the previous one. */
  if (currentAction)
    currentAction->onStop(window);

  /* Get the new action. */
  currentAction = (ActionInterface*)data;
  DBG_fprintf(stderr, "Gtk Interactive: set the action %d current.\n",
	      currentAction->id);

  labelHelp = lookup_widget(observeWindow, "labelInfoObservePick");
  gtk_label_set_markup(GTK_LABEL(labelHelp), currentAction->help);

  currentAction->onStart(window);
}

static void radioObserveToggled(GtkToggleButton *togglebutton, gpointer user_data _U_)
{
  gboolean value;
  GtkWidget *wd;

  value = gtk_toggle_button_get_active(togglebutton);

  wd = lookup_widget(observeWindow, "hboxObserve");
  gtk_widget_set_sensitive(wd, value);
  wd = lookup_widget(observeWindow, "tableObserve");
  gtk_widget_set_sensitive(wd, value);
  if (visu_interactive_class_getPreferedObserveMethod() == interactive_constrained)
    gtk_widget_set_sensitive(spinOmega, FALSE);
  else
    gtk_widget_set_sensitive(spinOmega, value);
}

static void onTabActionChanged(GtkNotebook *book _U_, GtkWidget *child _U_,
			       gint num, gpointer data _U_)
{
  ActionInterface *action;

  DBG_fprintf(stderr, "Gtk Interactive: change the action tab to %d.\n", num);

  action = (ActionInterface*)g_list_nth_data(actions, num + 1);
  if (action->radio)
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(action->radio), TRUE);
}
static void onOrientationChanged(VisuUiOrientationChooser *orientationChooser,
				 gpointer data _U_)
{
  float values[2];

  DBG_fprintf(stderr, "Gtk Observe: orientation changed.\n");
  visu_ui_orientation_chooser_getAnglesValues(orientationChooser, values);

  g_object_set(visu_gl_node_scene_getGlView(visu_ui_rendering_window_getGlScene
                                            (visu_ui_main_class_getDefaultRendering())),
               "theta", values[0], "phi", values[1], NULL);
}
static void onVisuUiOrientationChooser(GtkButton *button _U_, gpointer data _U_)
{
  float values[2];
  VisuUiRenderingWindow *window;
  VisuGlView *view;

  window = visu_ui_main_class_getDefaultRendering();
  view = visu_gl_node_scene_getGlView(visu_ui_rendering_window_getGlScene(window));
  if (!orientationChooser)
    {
      orientationChooser = visu_ui_orientation_chooser_new
	(VISU_UI_ORIENTATION_DIRECTION, TRUE, VISU_BOXED(view), GTK_WINDOW(observeWindow));
/*       gtk_window_set_modal(GTK_WINDOW(orientationChooser), TRUE); */
      values[0] = (float)view->camera.theta;
      values[1] = (float)view->camera.phi;
      visu_ui_orientation_chooser_setAnglesValues(VISU_UI_ORIENTATION_CHOOSER(orientationChooser),
					 values);
      g_signal_connect(G_OBJECT(orientationChooser), "values-changed",
		       G_CALLBACK(onOrientationChanged), (gpointer)0);
      gtk_widget_show(orientationChooser);
    }
  else
    gtk_window_present(GTK_WINDOW(orientationChooser));
  
  switch (gtk_dialog_run(GTK_DIALOG(orientationChooser)))
    {
    case GTK_RESPONSE_ACCEPT:
      DBG_fprintf(stderr, "Gtk Observe: accept changings on orientation.\n");
      break;
    default:
      DBG_fprintf(stderr, "Gtk Observe: reset values on orientation.\n");
      g_object_set(view, "theta", values[0], "phi", values[1], NULL);
    }
  DBG_fprintf(stderr, "Gtk Observe: orientation object destroy.\n");
  gtk_widget_destroy(orientationChooser);
  orientationChooser = (GtkWidget*)0;
}
