/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD, Damien
	CALISTE, Olivier D'Astier, laboratoire L_Sim, (2001-2006)
  
	Adresses mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.
	D'ASTIER, dastier AT iie P cnam 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 and Damien
	CALISTE and Olivier D'Astier, laboratoire L_Sim, (2001-2006)

	E-mail addresses :
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.
	D'ASTIER, dastier AT iie P cnam 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 "panelSurfaces.h"
#include "panelSurfacesTools.h"

#include <visu_object.h>
#include <support.h>
#include <gtk_main.h>
#include <opengl.h>
#include <visu_extension.h>
#include <visu_configFile.h>
#include <renderingBackend/visu_windowInterface.h>
#include <gtk_renderingWindowWidget.h>
#include <openGLFunctions/objectList.h>

#include <extraFunctions/surfaces.h>
#include <extraGtkFunctions/gtk_colorComboBoxWidget.h>

int identifier_isosurfaces;

static GtkWidget *isosurfaces_gtk_vbox;

static OpenGLExtension *extension_isosurfaces;

static GtkListStore *isosurfaces_data_list;
static GtkWidget *isosurfaces_tree_model;

enum
  {
    NUMBER_COLUMN,
    SHOW_COLUMN,
    NAME_COLUMN,
    N_COLUMNS
  };

gboolean gtk_tree_model_iter_previous(GtkTreeModel *tree_model, GtkTreeIter *iter);

void isosurfaces_rebuild_gl_list_in_order(VisuData *dataObj, OpenGLView *view, gpointer data);
void isosurfaces_rebuild_gl_list(VisuData *dataObj);
gchar *isosurfaces_get_current_surface_selected();
void isosurfaces_update_data_list();
void isosurfaces_remove_all();
gboolean isosurfaces_show_hide(GtkTreeModel *model, GtkTreePath *path,
			       GtkTreeIter *iter, gpointer data);
void isosurfaces_rebuild_gl_list_and_redraw();
void isosurfaces_rebuild_gl_list_in_order_and_redraw();

static GtkWidget *edit_combo_color;
static GtkWidget *edit_prop_value[9];

static gboolean inhibit_redraw = FALSE;
static gboolean reverse_order = FALSE;

static GtkWidget *auto_reorder;

/* Callback for when the combo color is changed in the edit panel */
void isosurfaces_combo_selection_changed(ColorComboBox *combo, Color *color)
{
  float rgba[4];
  int i;

  inhibit_redraw = TRUE;
  for(i=0; i<4; i++)
    gtk_spin_button_set_value(GTK_SPIN_BUTTON(edit_prop_value[i]), color->rgba[i]);
  inhibit_redraw = FALSE;

  isosurfaces_rebuild_gl_list_and_redraw();
}

/* Callback for when the value of a spin button is changed in the single edit panel. */
void isosurfaces_update_properties(GtkWidget *widget, gpointer data)
{
  int k;
  gchar *current_surface_selected = isosurfaces_get_current_surface_selected();
  int position;
  surf_res *res = isosurfaces_resources_get(current_surface_selected);

  for(k=0; k<9; k++)
    res->material[k] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(edit_prop_value[k]));   

  DBG_fprintf(stderr, "Panel Surfaces : properties of surface '%s' changed to\n"
	      "                 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
	      current_surface_selected, res->material[0], res->material[1], res->material[2], 
	      res->material[3], res->material[4], res->material[5], res->material[6],
	      res->material[7], res->material[8]);
  

  if(inhibit_redraw == FALSE)
    isosurfaces_rebuild_gl_list_and_redraw();
}

/* Callback for when the value of a spin button is changed in the multi edit panel. */
void isosurfaces_multi_update_properties(GtkWidget *widget, gpointer data)
{
  int i,j = GPOINTER_TO_INT(data), n;
  Color* color = NULL;
  float rgba[4];
  int position;
  float surf_prop[9];
  surf_res *res;

  color = colorComboBoxGet_selectedColor(COLOR_COMBOX(edit_combo_color));

  vgl_get_surfaces_number(&n);

  for(i=1; i<=n; i++)
    {
      res = isosurfaces_resources_get(vgl_get_surface_name(i));
      
      res->material[j] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(edit_prop_value[j])); 

      DBG_fprintf(stderr, "Panel Surfaces : properties of surface '%s' changed to\n"
		  "                 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
		  vgl_get_surface_name(i), res->material[0], res->material[1], res->material[2], 
		  res->material[3], res->material[4], res->material[5], res->material[6],
		  res->material[7], res->material[8]);
    }

  if(inhibit_redraw == FALSE)
    isosurfaces_rebuild_gl_list_and_redraw();
}

/* Returns the number of the current surface selected in the tree view.
   If no surface is selected, returns -1. */
gchar * isosurfaces_get_current_surface_selected()
{
  gchar *current_surface_selected;
  GtkTreeIter iter;
  GtkTreeModel *model;
  GtkTreeSelection* tree_selection = 
    gtk_tree_view_get_selection(GTK_TREE_VIEW(isosurfaces_tree_model));
  if (!gtk_tree_selection_get_selected (tree_selection, &model, &iter))
    return NULL;
  gtk_tree_model_get(GTK_TREE_MODEL(isosurfaces_data_list), &iter,
		     NAME_COLUMN, &current_surface_selected, -1);

  return current_surface_selected;
}

/* See header for more info */
void isosurfaces_edit_interface(gpointer flag)
{
  GtkWidget *edit_window;
  GtkWidget *edit_vbox;
  GtkWidget *color_vbox;
  GtkWidget *material_vbox;
  GtkWidget *hbox[9];
  GtkWidget *prop_labels[9];
  GtkWidget *close_button;
  GtkWidget *top_frame;
  GtkWidget *bottom_frame;
  GtkWidget *hbox_color;
  char *prop_name[9] = {"Red :", "Green :", "Blue :", "Alpha :",
			"Ambient :", "Diffuse :", "Shininess :", "Specular :", "Emission :"};
  int i, n=GPOINTER_TO_INT(flag);
  gchar *current_surface_selected = isosurfaces_get_current_surface_selected();
  Color *selected_color;  
  surf_res *res;
  if(current_surface_selected == NULL)
    return;

  res = isosurfaces_resources_get(current_surface_selected);
  edit_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  edit_vbox = gtk_vbox_new(FALSE, 2);
  color_vbox = gtk_vbox_new(FALSE, 2);
  material_vbox = gtk_vbox_new(FALSE, 2);
  close_button = gtk_button_new_with_label(_("Close"));
  top_frame = gtk_frame_new(_("Color properties :"));  
  bottom_frame = gtk_frame_new(_("Material properties :")); 
  hbox_color = gtk_hbox_new(FALSE, 2);
  edit_combo_color = colorComboBox_new(TRUE);

  selected_color = colorAdd_floatRGBA(res->material, NULL);
  colorComboBoxSet_selectionByColor(COLOR_COMBOX(edit_combo_color), selected_color);

  gtk_window_set_title(GTK_WINDOW(edit_window), "Edit surface properties");
  gtk_window_set_modal(GTK_WINDOW(edit_window), TRUE);
  gtk_window_set_transient_for(GTK_WINDOW(edit_window), GTK_WINDOW(mainWindow));

  gtk_container_add(GTK_CONTAINER(edit_window), edit_vbox);


  if(n==1)
    gtk_box_pack_start(GTK_BOX(edit_vbox), 
		       gtk_label_new(current_surface_selected), 
		       FALSE, FALSE, 2);
  gtk_box_pack_start(GTK_BOX(edit_vbox), top_frame, FALSE, FALSE, 2);
  gtk_box_pack_start(GTK_BOX(edit_vbox), bottom_frame, FALSE, FALSE, 2);
  gtk_box_pack_start(GTK_BOX(edit_vbox), close_button, FALSE, FALSE, 2);

  gtk_container_add(GTK_CONTAINER(top_frame), color_vbox);
  gtk_container_add(GTK_CONTAINER(bottom_frame), material_vbox);

  gtk_box_pack_start(GTK_BOX(color_vbox), hbox_color, FALSE, FALSE, 2);
  gtk_box_pack_start(GTK_BOX(hbox_color), edit_combo_color, FALSE, FALSE, 2);

  for(i=0; i<9; i++)
    {
      hbox[i] = gtk_hbox_new(FALSE, 2);
      gtk_box_pack_start(GTK_BOX(i < 4 ? color_vbox : material_vbox), hbox[i], FALSE, FALSE, 2);
      prop_labels[i] = gtk_label_new(prop_name[i]);
      gtk_box_pack_start(GTK_BOX(hbox[i]), prop_labels[i], FALSE, FALSE, 2);
      edit_prop_value[i] = gtk_spin_button_new_with_range(0, 1, 0.01);
      gtk_box_pack_end(GTK_BOX(hbox[i]), edit_prop_value[i], FALSE, FALSE, 2);
      gtk_spin_button_set_value(GTK_SPIN_BUTTON(edit_prop_value[i]), res->material[i]);
      if(n==1)
	g_signal_connect(edit_prop_value[i], "value-changed",
			 G_CALLBACK(isosurfaces_update_properties), NULL);
      else if(n==0)
	g_signal_connect(edit_prop_value[i], "value-changed",
			 G_CALLBACK(isosurfaces_multi_update_properties), GINT_TO_POINTER(i));
    }

  g_signal_connect_swapped(close_button, "clicked",
		   G_CALLBACK(gtk_widget_destroy), edit_window);
  g_signal_connect(G_OBJECT(edit_combo_color), "color-selected",
		   G_CALLBACK(isosurfaces_combo_selection_changed), NULL);
   

  gtk_widget_show_all(edit_window);
}

/* See header for more info */
void isosurfaces_open_file_chooser()
{
  char error[256] = "\0";
  char *file_choosed;
  gchar *directory = getLastOpenDirectory();
  GtkFileFilter *filter_surf = gtk_file_filter_new();
  GtkFileFilter *filter_none = gtk_file_filter_new();
  GtkWidget* file_chooser = 
    gtk_file_chooser_dialog_new("Open .surf file",
				GTK_WINDOW(mainWindow),
				GTK_FILE_CHOOSER_ACTION_OPEN,
				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
				NULL);
  GtkTooltips *tooltips = gtk_tooltips_new ();
  GtkWidget *fit_to_box = gtk_check_button_new_with_label (_("Fit surfaces to box"));
  RenderingWindow *window;

  if (directory)
    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), directory);

  gtk_tooltips_set_tip(tooltips, fit_to_box, 
		       _("Makes surfaces fit to the current loaded bounding box"), NULL);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fit_to_box), FALSE);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(file_chooser)->vbox), fit_to_box, FALSE, FALSE, 0);
  gtk_widget_show(fit_to_box);

  gtk_file_filter_add_pattern(filter_surf, "*.surf");
  gtk_file_filter_set_name(filter_surf, "Isosurfaces files (*.surf)");  
  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_surf);

  gtk_file_filter_add_pattern(filter_none, "*");
  gtk_file_filter_set_name(filter_none, "All files");
  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter_none);

  window = RENDERING_WINDOW(visuRenderingWindowGet_current());
  while(1)
    {
      switch(gtk_dialog_run (GTK_DIALOG (file_chooser)))
	{
	case GTK_RESPONSE_ACCEPT:
	  file_choosed = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
	  if(isosurfaces_try_file(file_choosed, 
				  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fit_to_box)),
				  renderingWindowGet_visuData(window)) == 0)
	    {
      directory = (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser));
      setLastOpenDirectory(directory);
      g_free(directory);
	      gtk_widget_destroy(file_chooser);  
	      return;
	    }
	  break;
	default:
      directory = (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER (file_chooser));
      setLastOpenDirectory(directory);
      g_free(directory);
	  gtk_widget_destroy(file_chooser);  
	  return;
	}
    }
}

/* See header for more info */
  int isosurfaces_try_file(const char* file_name, gboolean fit_to_box, VisuData *data)
{
  GString *errors = g_string_new("");

  if(file_name == NULL || strcmp(file_name, "") == 0)
    {
      raiseAlertDialog(_("Can't open unnamed file"));      
      g_string_free(errors, TRUE);
      return 1;
    }

  if(isosurfaces_data_list == NULL)
    {
      fprintf(stderr, "WARNING : isosurfaces list_store uninitialised\n");
      g_string_free(errors, TRUE);
      return 2;
    }

  gtk_list_store_clear(isosurfaces_data_list);

  if(!vgl_load_surfaces(file_name, errors))
    {
      raiseAlertDialog(errors->str);            
      g_string_free(errors, TRUE);
      return 3;
    }

  if (fit_to_box)
    isoSurfacesSet_fitToBox(data);

  isosurfaces_update_data_list();
  g_string_free(errors, TRUE);
  return 0;
}

/* refresh tree view info according to loaded surfaces by surfaces.c 
   refresh gl display */
void isosurfaces_update_data_list()
{
  GtkTreeIter iter, iter2;
  int i, n;
  surf_res *res;
  const gchar *current_surface;

  if(isosurfaces_data_list == NULL)
    {
      fprintf(stderr, "WARNING : isosurfaces list_store uninitialised\n");
      return;
    }
  gtk_list_store_clear(isosurfaces_data_list);

  vgl_get_surfaces_number(&n);
  for(i=1; i<=n; i++)
    {
      current_surface = vgl_get_surface_name(i);
      res = isosurfaces_resources_get(current_surface);
      gtk_list_store_insert(isosurfaces_data_list, &iter, i);
      gtk_list_store_set(isosurfaces_data_list, &iter,
			 NUMBER_COLUMN, i,
			 SHOW_COLUMN, res->rendered,
			 NAME_COLUMN, current_surface, -1);
    }

  isosurfaces_rebuild_gl_list_and_redraw();

  if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(isosurfaces_data_list), &iter2))
    gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(isosurfaces_tree_model)), &iter2);

}

/* See header file for more info */
gboolean isosurfaces_show_next()
{
  GtkTreeIter iter;
  GtkTreeSelection* selected_surf;
  int number, nsurfaces,i;
  surf_res *res;

  selected_surf = gtk_tree_view_get_selection(GTK_TREE_VIEW(isosurfaces_tree_model));

  if(!gtk_tree_selection_get_selected(selected_surf, NULL, &iter))
    return FALSE;

  if(reverse_order == FALSE)
    {
      if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(isosurfaces_data_list), &iter))
	{
	  reverse_order = TRUE;
	  if (!gtk_tree_model_iter_previous(GTK_TREE_MODEL(isosurfaces_data_list), &iter))
	    return FALSE;
	}
    }
  else
    {
      if (!gtk_tree_model_iter_previous(GTK_TREE_MODEL(isosurfaces_data_list), &iter))
	{
	  reverse_order = FALSE;
	  if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(isosurfaces_data_list), &iter))
	    return FALSE;
	}
    }

  gtk_tree_model_get(GTK_TREE_MODEL(isosurfaces_data_list), &iter,
		     NUMBER_COLUMN, &number, -1);

  gtk_tree_selection_select_iter(selected_surf, &iter);

  gtk_tree_model_foreach(GTK_TREE_MODEL(isosurfaces_data_list),
			 isosurfaces_show_hide,
			 GINT_TO_POINTER(0));
  gtk_list_store_set (isosurfaces_data_list, &iter,
		      SHOW_COLUMN, 1, -1);

  vgl_get_surfaces_number(&nsurfaces);
  for(i=0; i<nsurfaces; i++)
    {
      res = isosurfaces_resources_get(vgl_get_surface_name(i+1));
      res->rendered = (i == (number-1) ? TRUE : FALSE);
    }
  
  isosurfaces_rebuild_gl_list_and_redraw();

  return TRUE;
}

/* Callback for the "play" button. Registers the above function to be called at a specified time
   interval. */
void isosurfaces_play(GtkWidget *play_stop, GtkWidget *time_interval)
{
  static int event_id = 0;

  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_stop)) == TRUE)
    {
      event_id = g_timeout_add(gtk_spin_button_get_value(GTK_SPIN_BUTTON(time_interval)),
			       isosurfaces_show_next, NULL);
      gtk_button_set_label(GTK_BUTTON(play_stop), " Stop ");
    }
  else
    {
      g_source_remove(event_id);
      gtk_button_set_label(GTK_BUTTON(play_stop), " Play ");
    }      
}

/* Callback for the "Draw" check box. 
   If the selected surface were drawn, hides it and uncheck the button.
   If it was hidden, shows it and check the button. */
void isosurfaces_tree_show_hide(GtkCellRendererToggle *cell_renderer, 
				gchar *string_path, gpointer user_data)
{
  GtkTreePath* path = gtk_tree_path_new_from_string(string_path);
  GtkTreeIter iter;
  gboolean status;
  int surf_number;
  surf_res *res;

  if(gtk_tree_model_get_iter(GTK_TREE_MODEL(isosurfaces_data_list), &iter, path) == FALSE)
    return;

  status = gtk_cell_renderer_toggle_get_active(cell_renderer) ? FALSE : TRUE;
  gtk_list_store_set(isosurfaces_data_list, &iter,
		     SHOW_COLUMN, 
		     status,
		     -1);
  gtk_tree_model_get(GTK_TREE_MODEL(isosurfaces_data_list),
		     &iter,
		     NUMBER_COLUMN,
		     &surf_number,
		     -1);


  res = isosurfaces_resources_get(vgl_get_surface_name(surf_number));
  res->rendered = status;

  isosurfaces_rebuild_gl_list_and_redraw();
}

/* Used in combination with isosurfaces_show_hide_all().
   Shows/hides given surface. */
gboolean isosurfaces_show_hide(GtkTreeModel *model, GtkTreePath *path,
			       GtkTreeIter *iter, gpointer data)
{
  int show = GPOINTER_TO_INT(data);

  gtk_list_store_set (isosurfaces_data_list, iter,
		      SHOW_COLUMN, 
		      show,
		      -1);
  return FALSE;
}

/* See header file for more info */
void isosurfaces_show_hide_all(gpointer useless, gpointer visibility)
{
  int show = GPOINTER_TO_INT(visibility);
  int nb, i;
  surf_res *res;

  vgl_get_surfaces_number(&nb);
  if(nb <= 0)
    return;

  gtk_tree_model_foreach(GTK_TREE_MODEL(isosurfaces_data_list),
			 isosurfaces_show_hide,
			 visibility);

  for(i=0; i<nb; i++)
    {
      res = isosurfaces_resources_get(vgl_get_surface_name(i+1));
      res->rendered = show;
    }

  isosurfaces_rebuild_gl_list_and_redraw();
}

/* Sets up the model/view architecture used to store the surfaces info. */
void isosurfaces_make_tree_view()
{
  GtkCellRenderer *cell_show = gtk_cell_renderer_toggle_new();
  GtkTreeViewColumn *column = NULL;

  isosurfaces_data_list =
    gtk_list_store_new (N_COLUMNS, G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_STRING);
  isosurfaces_tree_model = 
    gtk_tree_view_new_with_model (GTK_TREE_MODEL (isosurfaces_data_list));

  g_signal_connect(cell_show, "toggled", G_CALLBACK(isosurfaces_tree_show_hide), NULL);

  column = gtk_tree_view_column_new_with_attributes(_("Show"), cell_show,
						    "active", SHOW_COLUMN, NULL);
  gtk_tree_view_column_set_expand(column, FALSE);
  gtk_tree_view_column_set_alignment(column, 0.5);
  gtk_tree_view_append_column (GTK_TREE_VIEW (isosurfaces_tree_model), column);

  column = gtk_tree_view_column_new_with_attributes(_("Surface name"), gtk_cell_renderer_text_new(),
						       "text", NAME_COLUMN, NULL);
  gtk_tree_view_column_set_expand(column, TRUE);
  gtk_tree_view_column_set_alignment(column, 0);
  gtk_tree_view_append_column (GTK_TREE_VIEW (isosurfaces_tree_model), column);

  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (isosurfaces_tree_model), TRUE);  

  g_signal_connect_swapped(G_OBJECT(isosurfaces_tree_model), "row_activated", 
			   G_CALLBACK(isosurfaces_edit_interface), GINT_TO_POINTER(1));
}

/* Callback for time interval value spin button.
   Changes the frequency used to play the surfaces. */
void isosurfaces_change_time_interval(GtkWidget *spin_button, GtkWidget *play_stop)
{
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_stop), FALSE);
}

/* Callback for the check button "use isosurfaces".
   Enables/disables the drawing of isosurfaces by V_Sim's core. */
void isosurfaces_switch_use(GtkToggleButton *togglebutton, gpointer user_data)
{
  gboolean used = gtk_toggle_button_get_active(togglebutton);

  if(used == extension_isosurfaces->used)
      return;

  extension_isosurfaces->used = used;

  if(extension_isosurfaces->used == FALSE)
      g_signal_emit(visu, VISU_GET_CLASS (visu)->OpenGLAskForReDraw_signal_id, 0, NULL);

  isosurfaces_rebuild_gl_list_and_redraw();
}

void isosurfaces_auto_reorder_polys(GtkWidget *button, GtkWidget *reorder_button)
{
  gtk_widget_set_sensitive(reorder_button, !GTK_WIDGET_IS_SENSITIVE(reorder_button));
}

/* Creates the main panel. */
void isosurfaces_create_gtk_interface()
{
  GtkTooltips *tooltips = gtk_tooltips_new ();
  GtkWidget *open_file = gtk_button_new_from_stock (GTK_STOCK_OPEN);
  GtkWidget *convert_button = gtk_button_new_with_label(_("Convert"));
  GtkWidget *top_hbox = gtk_hbox_new (FALSE, 0);
  GtkWidget *h_box3 = gtk_hbox_new (FALSE, 0);
  GtkWidget *use_isosurfaces =  
    gtk_check_button_new();
  GtkWidget *edit_one = gtk_button_new();
  GtkWidget *edit_all = gtk_button_new();
  GtkWidget *show_all = gtk_button_new();
  GtkWidget *show_none = gtk_button_new();
  GtkWidget *play_stop =
    gtk_toggle_button_new_with_label(_("Play"));
  GtkWidget *time_interval = 
    gtk_spin_button_new_with_range  (50, 2000, 10);
  GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  GtkWidget *reorder_button = gtk_button_new_with_label("Re-order");
  GtkWidget *image_surfs = create_pixmap(mainWindow, "stock-isosurfaces.png");
  GtkWidget *image_color_i = create_pixmap(mainWindow, "stock_effects-object-colorize_20_.png");
  GtkWidget *image_color = create_pixmap(mainWindow, "stock_effects-object-colorize_20.png");
  GtkWidget *image_show = create_pixmap(mainWindow, "stock-select-all_20.png");
  GtkWidget *image_hide = create_pixmap(mainWindow, "stock-unselect-all_20.png");
  GtkWidget *label_title = gtk_label_new(_("Use isosurfaces"));
  GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
  GtkWidget *tree_vbox = gtk_vbox_new(FALSE, 0);
  GtkWidget *tree_hbox = gtk_hbox_new(FALSE, 0);
  
  gtk_container_add(GTK_CONTAINER(edit_one), image_color);
  gtk_container_add(GTK_CONTAINER(edit_all), image_color_i);
  gtk_container_add(GTK_CONTAINER(show_all), image_show);
  gtk_container_add(GTK_CONTAINER(show_none), image_hide);

  isosurfaces_make_tree_view ();

  isosurfaces_gtk_vbox = gtk_vbox_new(FALSE, 0);

  auto_reorder = gtk_check_button_new_with_label("Auto");
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_reorder), TRUE);

  gtk_widget_set_name(label_title, "label_head");
  gtk_box_pack_start(GTK_BOX(hbox), image_surfs, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), label_title, FALSE, FALSE, 0);
  gtk_container_add(GTK_CONTAINER(use_isosurfaces), hbox);

  gtk_widget_set_sensitive(reorder_button, FALSE);

  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_stop), FALSE);

  g_signal_connect(G_OBJECT(auto_reorder), "clicked",
		   G_CALLBACK(isosurfaces_auto_reorder_polys), reorder_button);
  g_signal_connect(G_OBJECT(reorder_button), "clicked",
		   G_CALLBACK(isosurfaces_rebuild_gl_list_in_order_and_redraw), NULL);
  g_signal_connect(G_OBJECT(open_file), "clicked",
		   G_CALLBACK(isosurfaces_open_file_chooser), NULL);
  g_signal_connect(G_OBJECT(convert_button), "clicked",
		   G_CALLBACK(isosurfaces_convert_interface), NULL);
  g_signal_connect_swapped(G_OBJECT(edit_one), "clicked",
		   G_CALLBACK(isosurfaces_edit_interface), GINT_TO_POINTER(1));
  g_signal_connect_swapped(G_OBJECT(edit_all), "clicked",
		   G_CALLBACK(isosurfaces_edit_interface), GINT_TO_POINTER(0));
  g_signal_connect(G_OBJECT(show_all), "clicked",
		   G_CALLBACK(isosurfaces_show_hide_all), GINT_TO_POINTER(1));
  g_signal_connect(G_OBJECT(show_none), "clicked",
		   G_CALLBACK(isosurfaces_show_hide_all), GINT_TO_POINTER(0));
  g_signal_connect(G_OBJECT(play_stop), "toggled",
		   G_CALLBACK(isosurfaces_play), time_interval);
  g_signal_connect(G_OBJECT(time_interval), "value_changed",
		   G_CALLBACK(isosurfaces_change_time_interval), play_stop);
  g_signal_connect(G_OBJECT(use_isosurfaces), "toggled",
		   G_CALLBACK(isosurfaces_switch_use), NULL);

  gtk_box_pack_start(GTK_BOX(isosurfaces_gtk_vbox), top_hbox, FALSE, FALSE, 0);

  gtk_box_pack_start(GTK_BOX(top_hbox), use_isosurfaces, FALSE, FALSE, 0);
  gtk_tooltips_set_tip (tooltips, open_file, _("Load a .surf file containing isosurfaces data.."), NULL);
  gtk_box_pack_end(GTK_BOX(top_hbox), open_file, FALSE, FALSE, 2);
  gtk_tooltips_set_tip (tooltips, convert_button, _("Several built-in tools to create .surf files."), NULL);
  gtk_box_pack_end(GTK_BOX(top_hbox), convert_button, FALSE, FALSE, 2);

  
  gtk_box_pack_start(GTK_BOX(isosurfaces_gtk_vbox), tree_hbox, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(tree_hbox), scrolled_window, TRUE, TRUE, 0);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 
				 GTK_POLICY_AUTOMATIC, 
				 GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
  gtk_container_add (GTK_CONTAINER (scrolled_window), isosurfaces_tree_model);
  gtk_box_pack_start(GTK_BOX(tree_hbox), tree_vbox, FALSE, FALSE, 0);
  gtk_tooltips_set_tip (tooltips, edit_one, _("Change selected surface's color and material properties"), NULL);
  gtk_box_pack_start(GTK_BOX(tree_vbox), edit_one, FALSE, FALSE, 2);
  gtk_tooltips_set_tip (tooltips, edit_all, _("Change ALL surfaces' color and material properties"), NULL);
  gtk_box_pack_start(GTK_BOX(tree_vbox), edit_all, FALSE, FALSE, 2);
  gtk_tooltips_set_tip (tooltips, show_all, _("Shows all surfaces"), NULL);
  gtk_box_pack_end(GTK_BOX(tree_vbox), show_all, FALSE, FALSE, 2);
  gtk_tooltips_set_tip (tooltips, show_none, _("Hides all surfaces"), NULL);
  gtk_box_pack_end(GTK_BOX(tree_vbox), show_none, FALSE, FALSE, 2);
 
  gtk_box_pack_start(GTK_BOX(isosurfaces_gtk_vbox), h_box3, FALSE, FALSE, 0);
  gtk_tooltips_set_tip (tooltips, play_stop, _("Starts/stops showing isosurfaces at specified rate"), NULL);
  gtk_box_pack_start(GTK_BOX(h_box3), play_stop, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(h_box3), gtk_label_new(_("@")), FALSE, FALSE, 0);
  gtk_tooltips_set_tip (tooltips, time_interval, _("Selects rate to show isosurfaces"), NULL);
  gtk_box_pack_start(GTK_BOX(h_box3), time_interval, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(h_box3), gtk_label_new(_("ms")), FALSE, FALSE, 0);
  gtk_tooltips_set_tip (tooltips, auto_reorder, _("Automatically re-orders surfaces in back to front order whenever camera is modified (can be slow but get rid of transparency problems)"), NULL);
  gtk_box_pack_end(GTK_BOX(h_box3), auto_reorder, FALSE, FALSE, 0);
  gtk_tooltips_set_tip (tooltips, reorder_button, _("Re-orders surfaces in back to front order (deals with transparency problems for current point of view)"), NULL);
  gtk_box_pack_end(GTK_BOX(h_box3), reorder_button, FALSE, FALSE, 0);

  gtk_widget_show_all(isosurfaces_gtk_vbox);
}

/* Reorders the polygons according to camera position and redraw isosurfaces. 
   this is because we're using alpha and for alpha to work properly, it is needed to
   draw polygons from back to front. */
void isosurfaces_rebuild_gl_list_in_order(VisuData *dataObj, OpenGLView *view, gpointer data)
{
  int n;

  if (!dataObj)
    return;

  vgl_get_surfaces_number(&n);
  if(n <= 0)
    return;

  if(extension_isosurfaces->used == TRUE)
    {
      if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_reorder)) == TRUE)
	{
	  vgl_order_polygons();
	  draw_surfaces(view);
	}
    }
}

void isosurfaces_rebuild_gl_list_in_order_and_redraw()
{
  int n;
  RenderingWindow *window;
  VisuData *dataObj;

  vgl_get_surfaces_number(&n);
  if(n <= 0)
    return;

  if(extension_isosurfaces->used == TRUE)
    {
      window = RENDERING_WINDOW(visuRenderingWindowGet_current());
      g_return_if_fail(window);
      dataObj = renderingWindowGet_visuData(window);
      g_return_if_fail(dataObj);
      vgl_order_polygons();
      draw_surfaces(visuDataGet_openGLView(dataObj));
      g_signal_emit(visu, VISU_GET_CLASS (visu)->OpenGLAskForReDraw_signal_id, 0, NULL);
    }
}


/* Rebuilds the gl list associated to isosurfaces */
void isosurfaces_rebuild_gl_list(VisuData *dataObj)
{  
  int n;
  vgl_get_surfaces_number(&n);
  if(n <= 0)
    return;

  if(extension_isosurfaces->used == TRUE)
    {
      draw_surfaces(visuDataGet_openGLView(dataObj));
    }
}

/* Same as isosurfaces_rebuild_gl_list() but also asks the core for a redraw. */
void isosurfaces_rebuild_gl_list_and_redraw(OpenGLView *view)
{  
  int n;
  RenderingWindow *window;
  VisuData *dataObj;

  vgl_get_surfaces_number(&n);
  if(n <= 0)
    return;

  if(extension_isosurfaces->used == TRUE)
    {
      window = RENDERING_WINDOW(visuRenderingWindowGet_current());
      g_return_if_fail(window);
      dataObj = renderingWindowGet_visuData(window);
      g_return_if_fail(dataObj);
      draw_surfaces(visuDataGet_openGLView(dataObj));
      g_signal_emit(visu, VISU_GET_CLASS (visu)->OpenGLAskForReDraw_signal_id, 0, NULL);
    }
}

/* Callback to set the interface insensitive whenever a file hasn't been loaded. */
void isosurfaces_set_interface_sensitive(gpointer *useless,
					 VisuData *dataObj, gpointer data)
{
  DBG_fprintf(stderr, "Panel Surfaces : caught 'dataReadyForRendering' signal,"
	      " setting sensitivity.\n");
  if (dataObj)
    {
      gtk_widget_set_sensitive(isosurfaces_gtk_vbox, TRUE);
      g_signal_connect(G_OBJECT(dataObj), "OpenGLThetaPhiOmega",
		       G_CALLBACK(isosurfaces_rebuild_gl_list_in_order), NULL);
    }
  else
    gtk_widget_set_sensitive(isosurfaces_gtk_vbox, FALSE);
}
  

subPanel* initPanelSurfaces()
{
  /* Long description */
  char *cl = _("Drawing iso-surfaces");
  /* Short description */
  char *tl = _("Isosurfaces");
  subPanel *panel = NULL;

  isosurfaces_create_gtk_interface();

  gtk_widget_set_sensitive(isosurfaces_gtk_vbox, FALSE);

  panel = createSubPanelWithIconFromPath(cl, tl, "stock-isosurfaces.png",
					 isosurfaces_gtk_vbox, 0, 0);
  addSubPanel(panel);
  
  visuConfigFileAdd_entry(VISU_CONFIGFILE_RESOURCE,
			  "isosurface_property",
			  "Properties of a given isosurface",
			  1, isosurfaces_read_resources);
  visuConfigFileAdd_exportFunction(VISU_CONFIGFILE_RESOURCE, isosurfaces_export_resources);

  /* Register the extension as an opengl one */
  identifier_isosurfaces = openGLObjectList_new(1);
  extension_isosurfaces = 
    OpenGLExtension_new(tl, cl, identifier_isosurfaces, 
			isosurfaces_rebuild_gl_list);
  extension_isosurfaces->used = 0;
/*   OpenGLExtensionSet_priority(extension_isosurfaces, OPENGL_EXTENSION_PRIORITY_NORMAL);  */
  OpenGLExtensionSet_sensitiveToRenderingMode(extension_isosurfaces, TRUE);
  OpenGLExtensionSet_saveOpenGLState(extension_isosurfaces, TRUE);
  OpenGLExtensionRegister(extension_isosurfaces);

  /* Add the signal for the vBoxPlanes. */
  g_signal_connect(G_OBJECT(visu), "dataReadyForRendering",
		   G_CALLBACK(isosurfaces_set_interface_sensitive), (gpointer)0);

  if(!panel)
    return NULL;

  return panel;
}
 

