/*   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 <gtk/gtk.h>

#include "gtk_colorComboBoxWidget.h"
#include <support.h>
#include <visu_tools.h>

/**
 * SECTION:gtk_colorComboBoxWidget
 * @short_description: Defines a specialised #GtkComboBox to choose
 * stored colours.
 * @see_also: #ToolColor, #VisuUiStippleCombobox, #VisuUiShadeCombobox
 * @include: coreTools/toolColor.h
 *
 * <para>This widget looks like a #GtkComboBox and it displays a list
 * of stored colours. These colours may come from the configuration
 * files or can be selected and stored by the user actions. To do it,
 * the first entry of the combo box is 'new / modify', that opens a GTK
 * colour picker. The new values are used to craete a new colour entry
 * in the combo box. In a complete version, the combo box can have a
 * #GtkVBox associated to modify colours without creating new entries, see
 * visu_ui_color_combobox_newWithRanges() method. Otherwise, only already
 * selected colours are available. The stored colours are shared by
 * all widgets of this class. It is thus a convenient way to have
 * coherent colour picker through V_Sim.</para>
 *
 * <para>When the widget is created with ranges, the additional part
 * can be retrieve with visu_ui_color_combobox_getRangeWidgets() and attached
 * whereever is convenient. When the ranges are modified, the new
 * colour is not added to the combo box. It can be read using
 * visu_ui_color_combobox_getRangeColor() or visu_ui_color_combobox_getRangeMaterial(). The combo
 * box is set thus to an unselected state and
 * visu_ui_color_combobox_getSelection() will return a NULL
 * pointer. Besides the colour ranges, there is an add button to
 * insert the newly defined colour into the combo box.</para>
 *
 * <para>This widget can emit a #VisuUiColorCombobox::color-selected
 * signal that is a wrapper around the #GtkComboBox::changed signal,
 * but it is emitted only when a new colour is selected (either an
 * existing one or a newly created from the picker). This colour
 * is passed to the callback. The two other signals,
 * #VisuUiColorCombobox::color-value-changed and
 * #VisuUiColorCombobox::material-value-changed, are generated when the
 * widget have been created with ranges and that one of these ranges
 * is modified.</para>
 *
 * Since: 3.1
 */

enum {
  COLOR_SELECTED_SIGNAL,
  COLOR_VALUE_CHANGED_SIGNAL,
  MATERIAL_VALUE_CHANGED_SIGNAL,
  LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
enum
  {
    PROP_0,
    COLOR_PROP,
    MATERIAL_PROP,
    N_PROP
  };
static GParamSpec *properties[N_PROP];

/* This enum is used to access the column of the GtkListStore
   that contains the informations of stroed colors. */
enum
  {
    /* This has a pointer to a 16x16 image to represent the color,
       including the alpha channel. */
    COLUMN_COLOR_PIXBUF_ALPHA,
    /* This has a pointer to a 16x16 image to represent the color,
       without the alpha channel. */
    COLUMN_COLOR_PIXBUF,
    /* This is a pointer to a label that describes the color :
       "(n_red;n_green;n_blue;n_alpha)" with n_xxx from 0 to 255. */
    COLUMN_COLOR_LABEL_ALPHA,
    /* This is the same label than above but without the alpha value. */
    COLUMN_COLOR_LABEL,
    /* This a pointer to the #ToolColor as defined in visuTools.h */
    COLUMN_COLOR_POINTER_TO,
    N_COLUMN_COLOR
  };

/* Labels for the ranges part. */
#define RED_ELE_LABEL   _("R:")
#define GREEN_ELE_LABEL _("G:")
#define BLUE_ELE_LABEL  _("B:")
#define ALPHA_ELE_LABEL _("Alph:")
#define AMB_ELE_LABEL   _("amb:")
#define DIF_ELE_LABEL   _("dif:")
#define SHI_ELE_LABEL   _("shi:")
#define SPE_ELE_LABEL   _("spe:")
#define EMI_ELE_LABEL   _("emi:")

static void visu_ui_color_combobox_changed (GtkWidget *widget, VisuUiColorCombobox *colorComboBox);
static void visu_ui_color_combobox_dispose (GObject *obj);
static void visu_ui_color_combobox_finalize(GObject *obj);
static void visu_ui_color_combobox_get_property(GObject* obj, guint property_id,
                                                GValue *value, GParamSpec *pspec);
static void visu_ui_color_combobox_set_property(GObject* obj, guint property_id,
                                                const GValue *value, GParamSpec *pspec);

/**
 * VisuUiColorCombobox
 *
 * Private structure to store informations of a #VisuUiColorCombobox object.
 *
 * Since: 3.1
 */
struct _VisuUiColorCombobox
{
  GtkComboBox comboColor;
  ToolColor* previouslySelectedColor;

  gboolean withRanges;
  GtkWidget *expandRanges;
  GtkWidget *rgbRanges[4];
  GtkWidget *materialRanges[TOOL_MATERIAL_N_VALUES];
  gulong rgbSignals[4];
  gulong materialSignals[TOOL_MATERIAL_N_VALUES];
  gulong comboSignal;
  GtkWidget *addButton;

  gboolean hasAlphaChannel;

  GtkCellRenderer *rendererRGB;

  /* Memory gestion. */
  gboolean dispose_has_run;
};
/**
 * VisuUiColorComboboxClass
 *
 * Private structure to store informations of a #VisuUiColorComboboxClass object.
 *
 * Since: 3.1
 */
struct _VisuUiColorComboboxClass
{
  GtkComboBoxClass parent_class;

  void (*colorComboBox) (VisuUiColorCombobox *colorCombo);

  /* This listStore contains all the colors
     known by widgets of this class. It is used
     as TreeModel for the combobox in the widget. */
  GtkListStore *listStoredColors;

  gulong colorAddedSignalId;
};

/* Local callbacks. */
static void visu_ui_color_combobox_materialChanged(GtkRange *rg, gpointer data);
static void visu_ui_color_combobox_rgbChanged(GtkRange *rg, gpointer data);
static void visu_ui_color_combobox_addButtonClicked(GtkButton *button, gpointer data);

/* Local methods. */
static void addColorToModel(GtkTreeIter *iter, VisuUiColorComboboxClass* klass,
			    ToolColor* color);
static void onNewColorAvailable(ToolPool *pool, ToolColor* newColor, gpointer data);

/**
 * visu_ui_color_combobox_get_type
 *
 * #GType are unique numbers to identify objects.
 *
 * Returns: the #GType associated with #VisuUiColorCombobox objects.
 *
 * Since: 3.1
 */
G_DEFINE_TYPE(VisuUiColorCombobox, visu_ui_color_combobox, GTK_TYPE_COMBO_BOX)

static void visu_ui_color_combobox_class_init(VisuUiColorComboboxClass *klass)
{
  GtkTreeIter iter;
  GList *colorLst;
  
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: creating the class of the widget.\n");
  DBG_fprintf(stderr, "                     - adding new signals ;\n");
  /**
   * VisuUiColorCombobox::color-selected:
   * @combo: the #VisuUiColorCombobox that emits the signal ;
   * @color: the newly selected #ToolColor.
   *
   * This signal is emitted when a new valid colour is selected,
   * either an existing one or newly created one.
   *
   * Since: 3.1
   */
  signals[COLOR_SELECTED_SIGNAL] =
    g_signal_new ("color-selected",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (VisuUiColorComboboxClass, colorComboBox),
		  NULL, 
		  NULL,                
		  g_cclosure_marshal_VOID__POINTER,
		  G_TYPE_NONE, 1, G_TYPE_POINTER);
  /**
   * VisuUiColorCombobox::color-value-changed:
   * @combo: the #VisuUiColorCombobox that emits the signal ;
   * @RGBA: the modified channel.
   *
   * This signal is emitted when the range of a colour is modified.
   *
   * Since: 3.3
   */
  signals[COLOR_VALUE_CHANGED_SIGNAL] =
    g_signal_new ("color-value-changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (VisuUiColorComboboxClass, colorComboBox),
		  NULL, 
		  NULL,                
		  g_cclosure_marshal_VOID__UINT,
		  G_TYPE_NONE, 1, G_TYPE_UINT);
  /**
   * VisuUiColorCombobox::material-value-changed:
   * @combo: the #VisuUiColorCombobox that emits the signal ;
   * @mat: the modified material channel (see #ToolMaterialIds).
   *
   * This signal is emitted when the range of a material is modified.
   *
   * Since: 3.3
   */
  signals[MATERIAL_VALUE_CHANGED_SIGNAL] =
    g_signal_new ("material-value-changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (VisuUiColorComboboxClass, colorComboBox),
		  NULL, 
		  NULL,                
		  g_cclosure_marshal_VOID__UINT,
		  G_TYPE_NONE, 1, G_TYPE_UINT);

  DBG_fprintf(stderr, "                     - initializing the listStore of colors.\n");
  /* Init the listStore of colors. */
  klass->listStoredColors = gtk_list_store_new (N_COLUMN_COLOR,
						GDK_TYPE_PIXBUF,
						GDK_TYPE_PIXBUF,
						G_TYPE_STRING,
						G_TYPE_STRING,
						G_TYPE_POINTER);
  gtk_list_store_append(klass->listStoredColors, &iter);
  gtk_list_store_set(klass->listStoredColors, &iter,
		     COLUMN_COLOR_PIXBUF_ALPHA, NULL,
		     COLUMN_COLOR_PIXBUF      , NULL,
		     COLUMN_COLOR_LABEL_ALPHA , _("New / modify"),
		     COLUMN_COLOR_LABEL       , _("New / modify"),
		     COLUMN_COLOR_POINTER_TO  , NULL,
		     -1);
  klass->colorAddedSignalId = g_signal_connect(tool_color_getStorage(), "new-element",
					       G_CALLBACK(onNewColorAvailable),
					       (gpointer)klass);
  DBG_fprintf(stderr, "                     - add stored colours.\n");
  colorLst = tool_pool_asList(tool_color_getStorage());
  while (colorLst)
    {
      addColorToModel(&iter, klass, (ToolColor*)colorLst->data);
      colorLst = g_list_next(colorLst);
    }

  /* Connect freeing methods. */
  G_OBJECT_CLASS(klass)->dispose = visu_ui_color_combobox_dispose;
  G_OBJECT_CLASS(klass)->finalize = visu_ui_color_combobox_finalize;
  G_OBJECT_CLASS(klass)->set_property = visu_ui_color_combobox_set_property;
  G_OBJECT_CLASS(klass)->get_property = visu_ui_color_combobox_get_property;

  /**
   * VisuUiColorCombobox::color:
   *
   * Store the color of the current selection.
   *
   * Since: 3.8
   */
  properties[COLOR_PROP] = g_param_spec_boxed("color", "Color",
                                              "color of the current selection",
                                              TOOL_TYPE_COLOR, G_PARAM_READWRITE);
  /**
   * VisuUiColorCombobox::material:
   *
   * Store the material of the current selection.
   *
   * Since: 3.8
   */
  properties[MATERIAL_PROP] = g_param_spec_boxed("material", "Material",
                                                 "material of the current selection",
                                                 TOOL_TYPE_MATERIAL, G_PARAM_READWRITE);

  g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties);
}

static void visu_ui_color_combobox_dispose(GObject *obj)
{
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: dispose object %p.\n", (gpointer)obj);

  if (VISU_UI_COLOR_COMBOBOX(obj)->dispose_has_run)
    return;

  VISU_UI_COLOR_COMBOBOX(obj)->dispose_has_run = TRUE;
  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_ui_color_combobox_parent_class)->dispose(obj);
}
static void visu_ui_color_combobox_finalize(GObject *obj)
{
  /* VisuUiColorCombobox *colorComboBox; */

  g_return_if_fail(obj);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: finalize object %p.\n", (gpointer)obj);

  /* colorComboBox = VISU_UI_COLOR_COMBOBOX(obj); */
/*   if (colorComboBox->expandRanges) */
/*     gtk_widget_destroy(colorComboBox->expandRanges); */

  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_ui_color_combobox_parent_class)->finalize(obj);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: freeing ... OK.\n");
}
static void visu_ui_color_combobox_get_property(GObject* obj, guint property_id,
                                                GValue *value, GParamSpec *pspec)
{
  VisuUiColorCombobox *self = VISU_UI_COLOR_COMBOBOX(obj);
  const ToolColor *color;
  ToolColor _color;

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: get property '%s'.\n",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case COLOR_PROP:
      color = visu_ui_color_combobox_getSelection(self);
      if (color)
        g_value_set_static_boxed(value, color);
      else
        {
          _color.rgba[0] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[0]));
          _color.rgba[1] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[1]));
          _color.rgba[2] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[2]));
          _color.rgba[3] = gtk_range_get_value(GTK_RANGE(self->rgbRanges[3]));
          g_value_set_boxed(value, &_color);
        }
      DBG_fprintf(stderr, " | color pointer is %p.\n",
                  (gpointer)g_value_get_boxed(value));
      break;
    case MATERIAL_PROP:
      g_value_take_boxed(value, visu_ui_color_combobox_getRangeMaterial(self));
      DBG_fprintf(stderr, " | material pointer is %p.\n",
                  (gpointer)g_value_get_boxed(value));
      break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}
static void visu_ui_color_combobox_set_property(GObject* obj, guint property_id,
                                                const GValue *value, GParamSpec *pspec)
{
  GtkTreeIter iter;
  VisuUiColorCombobox *self = VISU_UI_COLOR_COMBOBOX(obj);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: set property '%s'.\n",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case COLOR_PROP:
      if (!visu_ui_color_combobox_setSelection(self, (ToolColor*)g_value_get_boxed(value)))
        {
          addColorToModel(&iter, VISU_UI_COLOR_COMBOBOX_GET_CLASS(obj),
                          (ToolColor*)g_value_get_boxed(value));
          gtk_combo_box_set_active_iter(GTK_COMBO_BOX(obj), &iter);
        }
      break;
    case MATERIAL_PROP:
      visu_ui_color_combobox_setRangeMaterial(self, (float*)g_value_get_boxed(value), FALSE);
      break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}


static void visu_ui_color_combobox_init(VisuUiColorCombobox *colorComboBox)
{
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: initializing new object (%p).\n",
	      (gpointer)colorComboBox);

  colorComboBox->hasAlphaChannel = TRUE;
  colorComboBox->dispose_has_run = FALSE;
  colorComboBox->previouslySelectedColor = tool_pool_getById(tool_color_getStorage(), 0);
}

static void _drawPix(GtkCellLayout *layout _U_, GtkCellRenderer *cell,
                     GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
  GdkPixbuf *pix;

  if (GPOINTER_TO_INT(data))
    gtk_tree_model_get(model, iter, COLUMN_COLOR_PIXBUF_ALPHA, &pix, -1);
  else
    gtk_tree_model_get(model, iter, COLUMN_COLOR_PIXBUF, &pix, -1);

  if (pix)
    {
      g_object_set(G_OBJECT(cell), "pixbuf", pix, NULL);
      g_object_unref(pix);
    }
  else
    g_object_set(G_OBJECT(cell), "icon-name", "list-add", NULL);
}
static void buildWidgets(VisuUiColorCombobox *colorComboBox)
{
  GObjectClass *klass;
  GtkCellRenderer *renderer;
  GtkWidget *vboxExpand, *table, *label, *hbox, *image;
  char *rgb[4];
  char *rgbName[4] = {"scroll_r", "scroll_g", "scroll_b", "scroll_a"};
  char *material[5];
  int i, j;

  klass = G_OBJECT_GET_CLASS(colorComboBox);
  gtk_combo_box_set_model(GTK_COMBO_BOX(colorComboBox),
			  GTK_TREE_MODEL(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors));
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: build widgets.\n");
  renderer = gtk_cell_renderer_pixbuf_new();
  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(colorComboBox), renderer, FALSE);
  gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(colorComboBox), renderer, _drawPix,
                                     GINT_TO_POINTER(colorComboBox->hasAlphaChannel),
                                     (GDestroyNotify)0);
  /* if (colorComboBox->hasAlphaChannel) */
  /*   gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer, */
  /*       			  "pixbuf", COLUMN_COLOR_PIXBUF_ALPHA); */
  /* else */
  /*   gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer, */
  /*       			  "pixbuf", COLUMN_COLOR_PIXBUF); */
  renderer = gtk_cell_renderer_text_new();
  g_object_set(G_OBJECT(renderer), "scale", 0.85, NULL);
  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(colorComboBox), renderer, FALSE);
  if (colorComboBox->hasAlphaChannel)
    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer,
				  "text", COLUMN_COLOR_LABEL_ALPHA);
  else
    gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(colorComboBox), renderer,
				  "text", COLUMN_COLOR_LABEL);
  colorComboBox->rendererRGB = renderer;
  DBG_fprintf(stderr, " | renderers OK\n");

  gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), 1);
  DBG_fprintf(stderr, " | selection OK\n");

  colorComboBox->expandRanges = (GtkWidget*)0;
  if (colorComboBox->withRanges)
    {
      DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: add range widgets.\n");
      rgb[0] = RED_ELE_LABEL;
      rgb[1] = GREEN_ELE_LABEL;
      rgb[2] = BLUE_ELE_LABEL;
      rgb[3] = ALPHA_ELE_LABEL;
      material[0] = AMB_ELE_LABEL;
      material[1] = DIF_ELE_LABEL;
      material[2] = SHI_ELE_LABEL;
      material[3] = SPE_ELE_LABEL;
      material[4] = EMI_ELE_LABEL;

      colorComboBox->expandRanges = gtk_expander_new(_("More options"));
      gtk_expander_set_expanded(GTK_EXPANDER(colorComboBox->expandRanges), FALSE);

      vboxExpand = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(colorComboBox->expandRanges), vboxExpand);

      hbox = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(vboxExpand), hbox, FALSE, FALSE, 5);

      table = gtk_grid_new();
      tool_grid_resize(table, 3, 2);
      gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0);
      gtk_widget_show(table);
      for (i = 0; i < 3; i++)
	{
	  label = gtk_label_new(rgb[i]);
	  gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1);
	  colorComboBox->rgbRanges[i] = gtk_hscale_new_with_range(0., 1., 0.001);
          gtk_widget_set_hexpand(colorComboBox->rgbRanges[i], TRUE);
	  gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->rgbRanges[i]),
				  GTK_POS_RIGHT);
	  gtk_widget_set_name(colorComboBox->rgbRanges[i], rgbName[i]);
	  gtk_grid_attach(GTK_GRID(table), colorComboBox->rgbRanges[i],
                          1, i, 1, 1);
	}
      colorComboBox->addButton = gtk_button_new();
      gtk_box_pack_start(GTK_BOX(hbox), colorComboBox->addButton, FALSE, FALSE, 2);
      image = gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON);
      gtk_container_add(GTK_CONTAINER(colorComboBox->addButton), image);
      DBG_fprintf(stderr, " | color OK\n");

      table = gtk_grid_new();
      tool_grid_resize(table, 3, 4);
      gtk_box_pack_start(GTK_BOX(vboxExpand), table, FALSE, FALSE, 5);
      for (i = 0; i < 2; i++)
	{
	  for (j = 0; j < 2; j++)
	    {
	      label = gtk_label_new(material[i * 2 + j]);
	      gtk_label_set_xalign(GTK_LABEL(label), 1.);
	      gtk_grid_attach(GTK_GRID(table), label, j * 2, i, 1, 1);
	      colorComboBox->materialRanges[i * 2 + j] =
		gtk_hscale_new_with_range(0., 1., 0.01);
              gtk_widget_set_hexpand(colorComboBox->materialRanges[i * 2 + j], TRUE);
	      gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->materialRanges[i * 2 + j]),
				      GTK_POS_RIGHT);
	      gtk_widget_set_name(colorComboBox->materialRanges[i * 2 +j], "scroll_mat");
	      gtk_grid_attach(GTK_GRID(table), colorComboBox->materialRanges[i * 2 + j],
                              2 * j + 1, i, 1, 1);
	    }
	}
      label = gtk_label_new(material[4]);
      gtk_label_set_xalign(GTK_LABEL(label), 1);
      gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1);
      colorComboBox->materialRanges[4] =
	gtk_hscale_new_with_range(0., 1., 0.01);
      gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->materialRanges[4]),
			      GTK_POS_RIGHT);
      gtk_widget_set_name(colorComboBox->materialRanges[4], "scroll_mat");
      gtk_grid_attach(GTK_GRID(table), colorComboBox->materialRanges[4],
                      1, i, 1, 1);
      label = gtk_label_new(rgb[3]);
      gtk_label_set_xalign(GTK_LABEL(label), 1.);
      gtk_grid_attach(GTK_GRID(table), label, 2, i, 1, 1);
      colorComboBox->rgbRanges[3] = gtk_hscale_new_with_range(0., 1., 0.01);
      gtk_scale_set_value_pos(GTK_SCALE(colorComboBox->rgbRanges[3]),
			      GTK_POS_RIGHT);
      gtk_widget_set_name(colorComboBox->rgbRanges[3], rgbName[3]);
      gtk_grid_attach(GTK_GRID(table), colorComboBox->rgbRanges[3], 3, i, 1, 1);
      DBG_fprintf(stderr, " | material OK\n");
      /* Attach the callbacks. */
      for (i = 0; i < 4; i++)
	colorComboBox->rgbSignals[i] = 
	  g_signal_connect(G_OBJECT(colorComboBox->rgbRanges[i]), "value-changed",
			   G_CALLBACK(visu_ui_color_combobox_rgbChanged), (gpointer)colorComboBox);
      for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++)
	colorComboBox->materialSignals[i] =
	  g_signal_connect(G_OBJECT(colorComboBox->materialRanges[i]), "value-changed",
			   G_CALLBACK(visu_ui_color_combobox_materialChanged), (gpointer)colorComboBox);
      g_signal_connect(G_OBJECT(colorComboBox->addButton), "clicked",
		       G_CALLBACK(visu_ui_color_combobox_addButtonClicked), (gpointer)colorComboBox);
      DBG_fprintf(stderr, " | signals OK\n");
    }
  colorComboBox->comboSignal = g_signal_connect(G_OBJECT(colorComboBox), "changed",
						G_CALLBACK(visu_ui_color_combobox_changed),
						(gpointer)colorComboBox);
}

/**
 * visu_ui_color_combobox_newWithRanges:
 * @hasAlphaChannel: a boolean.
 *
 * Create a color combo and several ranges.
 *
 * Returns: (transfer full): a newly created #VisuUiColorCombobox widget.
 *
 * Since: 3.3
 */
GtkWidget* visu_ui_color_combobox_newWithRanges(gboolean hasAlphaChannel)
{
  VisuUiColorCombobox *colorComboBox;

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: creating new object with alpha & ranges: %d.\n",
	      hasAlphaChannel);

  colorComboBox = VISU_UI_COLOR_COMBOBOX(g_object_new(visu_ui_color_combobox_get_type (), NULL));
  colorComboBox->hasAlphaChannel = hasAlphaChannel;
  colorComboBox->withRanges = TRUE;

  buildWidgets(colorComboBox);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: object ready.\n");
  return GTK_WIDGET(colorComboBox);
}
/**
 * visu_ui_color_combobox_new:
 * @hasAlphaChannel: a boolean.
 *
 * A #VisuUiColorCombobox widget is like a #GtkComboBox widget, but it is already filled
 * with the colors stores in the structures adhoc in visu_tools.h. Using this widget
 * is a convienient way to share colors between all part of V_Sim and to give a consistent
 * look of all color selection. If the argument @hasAlphaChannel is FALSE, the widget
 * display all colors but without their alpha channel, assuming it to be fully opaque.
 *
 * Returns: (transfer full): a newly created #VisuUiColorCombobox widget.
 *
 * Since: 3.1
 */
GtkWidget* visu_ui_color_combobox_new(gboolean hasAlphaChannel)
{
  VisuUiColorCombobox *colorComboBox;

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: creating new object with alpha: %d.\n",
	      hasAlphaChannel);

  colorComboBox = VISU_UI_COLOR_COMBOBOX(g_object_new(visu_ui_color_combobox_get_type (), NULL));
  colorComboBox->hasAlphaChannel = hasAlphaChannel;
  colorComboBox->withRanges = FALSE;

  buildWidgets(colorComboBox);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: object ready.\n");
  return GTK_WIDGET(colorComboBox);
}
/**
 * visu_ui_color_combobox_setExpanded:
 * @colorComboBox: a #ToolColor object ;
 * @value: a boolean value.
 *
 * Set the expanded state of the ranges. This is usable only if the colorComboBox
 * has been created with ranges.
 *
 * Since: 3.3
 */
void visu_ui_color_combobox_setExpanded(VisuUiColorCombobox *colorComboBox, gboolean value)
{
  g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox));
  g_return_if_fail(colorComboBox->withRanges);

  gtk_expander_set_expanded(GTK_EXPANDER(colorComboBox->expandRanges), value);
}
/**
 * visu_ui_color_combobox_setPrintValues:
 * @colorComboBox: a #ToolColor object ;
 * @value: a boolean.
 *
 * Print or not the RGB values.
 *
 * Since: 3.4
 */
void visu_ui_color_combobox_setPrintValues(VisuUiColorCombobox *colorComboBox, gboolean value)
{
  g_object_set(G_OBJECT(colorComboBox->rendererRGB),
	       "visible", value, NULL);
}
/**
 * visu_ui_color_combobox_getRangeWidgets:
 * @colorComboBox: a #ToolColor object.
 *
 * Retrieve the wiodget using to represent the ranges, or NULL if the object
 * has no ranges.
 *
 * Returns: (transfer none): a widget owned by @color.
 *
 * Since: 3.3
 */
GtkWidget* visu_ui_color_combobox_getRangeWidgets(VisuUiColorCombobox *colorComboBox)
{
  g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (GtkWidget*)0);

  return colorComboBox->expandRanges;
}

static void visu_ui_color_combobox_changed(GtkWidget *widget _U_, VisuUiColorCombobox *colorComboBox)
{
  int selected, i;
  GdkRGBA gdkcolor;
  GtkWidget *selection;
  gint code;
  float rgba[4];
  GtkTreeIter iter;
  GObjectClass *klass;
  ToolColor *color;

  selected = gtk_combo_box_get_active(GTK_COMBO_BOX(colorComboBox));
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: internal combobox changed signal -> %d.\n", selected);
  if (selected < 0)
    {
      if (colorComboBox->withRanges)
	gtk_widget_set_sensitive(colorComboBox->addButton, TRUE);
      colorComboBox->previouslySelectedColor = (ToolColor*)0;
      return;
    }

  if (colorComboBox->withRanges)
    gtk_widget_set_sensitive(colorComboBox->addButton, FALSE);

  if (selected != 0)
    {
      gtk_combo_box_get_active_iter(GTK_COMBO_BOX(colorComboBox), &iter);
      klass = G_OBJECT_GET_CLASS(colorComboBox);
      gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors), &iter,
			   COLUMN_COLOR_POINTER_TO, &color,
			   -1);
      if (color != colorComboBox->previouslySelectedColor)
	{
	  colorComboBox->previouslySelectedColor = color;
	  /* Set the ranges. */
	  if (colorComboBox->withRanges)
	    for (i = 0; i <4; i++)
	      {
		g_signal_handler_block(G_OBJECT(colorComboBox->rgbRanges[i]),
				       colorComboBox->rgbSignals[i]);
		gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]),
				    (gdouble)color->rgba[i]);
		g_signal_handler_unblock(G_OBJECT(colorComboBox->rgbRanges[i]),
					 colorComboBox->rgbSignals[i]);
	      }
	  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: emitting 'color-selected' signal.\n");
          g_object_notify_by_pspec(G_OBJECT(colorComboBox), properties[COLOR_PROP]);
	  g_signal_emit(G_OBJECT(colorComboBox),
			signals[COLOR_SELECTED_SIGNAL], 0, (gpointer)color, NULL);
	}
      else
	DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: aborting 'color-selected' signal.\n");
      return;
    }
  if (colorComboBox->previouslySelectedColor)
    {
      gdkcolor.red = colorComboBox->previouslySelectedColor->rgba[0];
      gdkcolor.green = colorComboBox->previouslySelectedColor->rgba[1];
      gdkcolor.blue = colorComboBox->previouslySelectedColor->rgba[2];
      gdkcolor.alpha = colorComboBox->previouslySelectedColor->rgba[3];
    }
  else
    {
      gdkcolor.red = 0.;
      gdkcolor.green = 0.;
      gdkcolor.blue = 0.;
      gdkcolor.alpha = 1.;
    }

  /* Create the selection. */
  selection = gtk_color_chooser_dialog_new(_("Select a color"), NULL);
  gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(selection),
                                  colorComboBox->hasAlphaChannel);
/*   createColorSelectionCustomList(GTK_COLOR_SELECTION_DIALOG(selection)); */

  /* Initialise its values. */
  gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(selection), &gdkcolor);

  /* Run the dialog window. */
  code = gtk_dialog_run(GTK_DIALOG(selection));
  if (code == GTK_RESPONSE_OK || code == GTK_RESPONSE_ACCEPT)
    {
      gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(selection), &gdkcolor);
      rgba[0] = (float)gdkcolor.red;
      rgba[1] = (float)gdkcolor.green;
      rgba[2] = (float)gdkcolor.blue;
      rgba[3] = (float)gdkcolor.alpha;

      klass = G_OBJECT_GET_CLASS(colorComboBox);
      g_signal_handler_block(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId);
      color = tool_color_addFloatRGBA(rgba, &selected);
      g_signal_handler_unblock(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId);
      addColorToModel(&iter, VISU_UI_COLOR_COMBOBOX_CLASS(klass), color);
      gtk_combo_box_set_active_iter(GTK_COMBO_BOX(colorComboBox), &iter);
    }
  else
    {
      /* Return the combobox to the previously selected color. */
      if (colorComboBox->previouslySelectedColor)
	visu_ui_color_combobox_setSelection(colorComboBox,
                                            colorComboBox->previouslySelectedColor);
      else
	gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), -1);
    }
  gtk_widget_destroy(selection);
}

static void visu_ui_color_combobox_materialChanged(GtkRange *rg, gpointer data)
{
  int i;
  VisuUiColorCombobox *colorComboBox;

  g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(data));

  g_object_notify_by_pspec(G_OBJECT(data), properties[MATERIAL_PROP]);

  colorComboBox = VISU_UI_COLOR_COMBOBOX(data);
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: internal material range changed signal.\n");

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: emitting 'material-value-changed' signal.\n");
  for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++)
    if (GTK_WIDGET(rg) == colorComboBox->materialRanges[i])
      {
	g_signal_emit(G_OBJECT(colorComboBox),
		      signals[MATERIAL_VALUE_CHANGED_SIGNAL], 0,
		      (ToolMaterialIds)i, NULL);
	return;
      }
  g_warning("Internal error, unrecognized range.");
}
static void visu_ui_color_combobox_rgbChanged(GtkRange *rg, gpointer data)
{
  int i;
  VisuUiColorCombobox *colorComboBox;
  float *rgba;

  g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(data));

  colorComboBox = VISU_UI_COLOR_COMBOBOX(data);
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: internal color range changed signal.\n");
  rgba = visu_ui_color_combobox_getRangeColor(colorComboBox);
  tool_color_getByValues(&i, rgba[0], rgba[1], rgba[2], rgba[3]);
  if (i < 0)
    {
      gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), -1);
      g_object_notify_by_pspec(G_OBJECT(data), properties[COLOR_PROP]);
    }
  else
    gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), i + 1);
  g_free(rgba);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: emitting 'color-value-changed' signal.\n");
  for (i = 0; i < 4; i++)
    if (GTK_WIDGET(rg) == colorComboBox->rgbRanges[i])
      {
	g_signal_emit(G_OBJECT(colorComboBox),
		      signals[COLOR_VALUE_CHANGED_SIGNAL], 0,
		      (ToolMaterialIds)i, NULL);
	return;
      }
  g_warning("Internal error, unrecognized range.");
}
static void visu_ui_color_combobox_addButtonClicked(GtkButton *button _U_, gpointer data)
{
  GtkTreeIter iter;
  GObjectClass *klass;
  ToolColor *color;
  VisuUiColorCombobox *colorComboBox;
  float *rgba;
  int selected;

  g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(data));
  colorComboBox = VISU_UI_COLOR_COMBOBOX(data);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: adding a new color from ranges.\n");

  rgba = visu_ui_color_combobox_getRangeColor(colorComboBox);
  klass = G_OBJECT_GET_CLASS(colorComboBox);
  g_signal_handler_block(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId);
  color = tool_color_addFloatRGBA(rgba, &selected);
  g_signal_handler_unblock(tool_color_getStorage(), VISU_UI_COLOR_COMBOBOX_CLASS(klass)->colorAddedSignalId);
  addColorToModel(&iter, VISU_UI_COLOR_COMBOBOX_CLASS(klass), color);
  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(colorComboBox), &iter);
  g_free(rgba);
}

static void addColorToModel(GtkTreeIter *iter, VisuUiColorComboboxClass* klass,
			    ToolColor* color)
{
  char str[20], strAlpha[20];
  GdkPixbuf *pixbufColorBox;
  GdkPixbuf *pixbufColorAlphaBox;

  if (!color || !klass)
    return;
  sprintf(strAlpha, "(#%02x%02x%02x%02x)", (int)(color->rgba[0] * 255.),
	  (int)(color->rgba[1] * 255.),
	  (int)(color->rgba[2] * 255.),
	  (int)(color->rgba[3] * 255.));
  sprintf(str, "(#%02x%02x%02x)", (int)(color->rgba[0] * 255.),
	  (int)(color->rgba[1] * 255.),
	  (int)(color->rgba[2] * 255.));
  pixbufColorAlphaBox = tool_color_get_stamp(color, TRUE);
  pixbufColorBox = tool_color_get_stamp(color, FALSE);
  gtk_list_store_append(klass->listStoredColors, iter);
  gtk_list_store_set(klass->listStoredColors, iter,
		     COLUMN_COLOR_PIXBUF_ALPHA, pixbufColorAlphaBox,
		     COLUMN_COLOR_PIXBUF      , pixbufColorBox,
		     COLUMN_COLOR_LABEL_ALPHA , strAlpha,
		     COLUMN_COLOR_LABEL       , str,
		     COLUMN_COLOR_POINTER_TO  , (gpointer)color,
		     -1);
  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: appending a new color '%s'.\n",
              strAlpha);
  g_object_unref(pixbufColorAlphaBox);
  g_object_unref(pixbufColorBox);
}
/**
 * visu_ui_color_combobox_setSelection:
 * @colorComboBox: a #VisuUiColorCombobox widget ;
 * @color: a #ToolColor object.
 *
 * Use this method to set the ComboBox on the given color. This emits a 'color-channel'
 * signal if the color is changed, which means, a previous color has been modified,
 * or a new color is selected.
 *
 * Returns: TRUE if the @color already exists in the model.
 *
 * Since: 3.1
 */
gboolean visu_ui_color_combobox_setSelection(VisuUiColorCombobox* colorComboBox, ToolColor *color)
{
  GtkTreeIter iter;
  gboolean validIter;
  GObjectClass *klass;
  GtkListStore *model;
  ToolColor *tmpColor;

  g_return_val_if_fail(color && VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), FALSE);

  DBG_fprintf(stderr, "Gtk VisuUiColorCombobox: select a new color %p.\n", (gpointer)color);
  klass = G_OBJECT_GET_CLASS(colorComboBox);
  model = GTK_LIST_STORE(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors);
  validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
  while (validIter)
    {
      gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
			 COLUMN_COLOR_POINTER_TO, &tmpColor,
			 -1);
      if (tmpColor && tool_color_equal(tmpColor, color))
	{
	  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(colorComboBox), &iter);
	  return TRUE;
	}
      validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
    }
  return FALSE;
}
/**
 * visu_ui_color_combobox_setRangeColor:
 * @colorComboBox: a #VisuUiColorCombobox widget ;
 * @rgba: 4 floating point values ;
 * @raiseSignal: if TRUE a material-value-changed can be raised.
 *
 * Change the values for the ranges that control the color. If the color exists
 * in the list, it is also selected.
 * This is possible only if the @colorComboBox has been created with
 * visu_ui_color_combobox_newWithRanges().
 *
 * Since: 3.3
 */
void visu_ui_color_combobox_setRangeColor(VisuUiColorCombobox *colorComboBox,
                                          const float rgba[4],
                                          gboolean raiseSignal)
{
  int pos, i;
  ToolColor *color;

  color = tool_color_getByValues(&pos, rgba[0], rgba[1], rgba[2], rgba[3]);
  if (!color)
    {
      gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), -1);
      if (raiseSignal)
	for (i = 0; i < 4; i++)
	  gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]),
			      (gdouble)rgba[i]);
      else
	for (i = 0; i < 4; i++)
	  {
	    g_signal_handler_block(G_OBJECT(colorComboBox->rgbRanges[i]),
				   colorComboBox->rgbSignals[i]);
	    gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]),
				(gdouble)rgba[i]);
	    g_signal_handler_unblock(G_OBJECT(colorComboBox->rgbRanges[i]),
				     colorComboBox->rgbSignals[i]);
	  }
    }
  else
    {
      if (raiseSignal)
	gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), pos + 1);
      else
	{
	  colorComboBox->previouslySelectedColor = color;
	  g_signal_handler_block(G_OBJECT(colorComboBox),
				 colorComboBox->comboSignal);
	  gtk_combo_box_set_active(GTK_COMBO_BOX(colorComboBox), pos + 1);
	  g_signal_handler_unblock(G_OBJECT(colorComboBox),
				   colorComboBox->comboSignal);
	  for (i = 0; i < 4; i++)
	    {
	      g_signal_handler_block(G_OBJECT(colorComboBox->rgbRanges[i]),
				     colorComboBox->rgbSignals[i]);
	      gtk_range_set_value(GTK_RANGE(colorComboBox->rgbRanges[i]),
				  (gdouble)rgba[i]);
	      g_signal_handler_unblock(G_OBJECT(colorComboBox->rgbRanges[i]),
				       colorComboBox->rgbSignals[i]);
	    }
	}
    }
}


static void onNewColorAvailable(ToolPool *pool _U_, ToolColor* newColor, gpointer data)
{
  VisuUiColorComboboxClass *klass;
  GtkTreeIter iter;

  g_return_if_fail(data);

  DBG_fprintf(stderr, "Gtk VisuUiColorComboboxClass: catch the 'new-element' signal.\n");
  klass = VISU_UI_COLOR_COMBOBOX_CLASS(data);
  addColorToModel(&iter, klass, newColor);
}
/**
 * visu_ui_color_combobox_getSelection:
 * @colorComboBox: a #VisuUiColorCombobox widget.
 *
 * The user can access to the selected #ToolColor object using this method.
 *
 * Returns: (transfer none): a pointer to the selected #ToolColor
 * object (or NULL). This object is read-only.
 *
 * Since: 3.1
 */
const ToolColor* visu_ui_color_combobox_getSelection(VisuUiColorCombobox *colorComboBox)
{
  gboolean validIter;
  GtkTreeIter iter;
  ToolColor *color;
  GObjectClass *klass;

  g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (ToolColor*)0);

  validIter = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(colorComboBox), &iter);
  if (!validIter)
    return (const ToolColor*)0;

  color = (ToolColor*)0;
  klass = G_OBJECT_GET_CLASS(colorComboBox);
  gtk_tree_model_get(GTK_TREE_MODEL(VISU_UI_COLOR_COMBOBOX_CLASS(klass)->listStoredColors), &iter,
		     COLUMN_COLOR_POINTER_TO, &color,
		     -1);
  return color;
}
/**
 * visu_ui_color_combobox_getPixbufFromColor:
 * @colorComboBox: a #VisuUiColorCombobox widget ;
 * @color: a #ToolColor object.
 *
 * The @colorComboBox has little pixbufs to represent the color. User methods can
 * use these pixbufs but should considered them read-only.
 *
 * Returns: (transfer full): a pixbuf pointer corresponding to the
 * little image shown on the @colorComboBox.
 *
 * Since: 3.1
 */
GdkPixbuf* visu_ui_color_combobox_getPixbufFromColor(VisuUiColorCombobox *colorComboBox, ToolColor *color)
{
  GtkTreeIter iter;
  gboolean validIter;
  GdkPixbuf *pixbuf;
  ToolColor *cl;
  GtkListStore *model;

  g_return_val_if_fail(colorComboBox && color, (GdkPixbuf*)0);

  model = VISU_UI_COLOR_COMBOBOX_CLASS(G_OBJECT_GET_CLASS(colorComboBox))->listStoredColors;
  validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
  while (validIter)
    {
      pixbuf = (GdkPixbuf*)0;
      cl = (ToolColor*)0;
      if (colorComboBox->hasAlphaChannel)
	gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
			   COLUMN_COLOR_PIXBUF_ALPHA, &pixbuf,
			   COLUMN_COLOR_POINTER_TO, &cl,
			   -1);
      else
	gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
			   COLUMN_COLOR_PIXBUF, &pixbuf,
			   COLUMN_COLOR_POINTER_TO, &cl,
			   -1);
      if (cl && tool_color_equal(color, cl))
	return pixbuf;
      if (pixbuf)
        g_object_unref(pixbuf);
      validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
    }
  return (GdkPixbuf*)0;
}
/**
 * visu_ui_color_combobox_setRangeMaterial:
 * @colorComboBox: a #VisuUiColorCombobox widget ;
 * @material: TOOL_MATERIAL_N_VALUES (see #ToolMaterialIds) floating point values ;
 * @raiseSignal: if TRUE a material-value-changed can be raised.
 *
 * Change the values for the ranges that control the light (emission, diffuse...).
 * This is possible only if the @colorComboBox has been created with
 * visu_ui_color_combobox_newWithRanges().
 *
 * Since: 3.3
 */
void visu_ui_color_combobox_setRangeMaterial(VisuUiColorCombobox *colorComboBox,
                                             const float material[TOOL_MATERIAL_N_VALUES],
                                             gboolean raiseSignal)
{
  int i;

  g_return_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox));
  g_return_if_fail(colorComboBox->withRanges);

  if (raiseSignal)
    for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++)
      gtk_range_set_value(GTK_RANGE(colorComboBox->materialRanges[i]),
			  (gdouble)material[i]);
  else
    for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++)
      {
	g_signal_handler_block(G_OBJECT(colorComboBox->materialRanges[i]),
			       colorComboBox->materialSignals[i]);
	gtk_range_set_value(GTK_RANGE(colorComboBox->materialRanges[i]),
			    (gdouble)material[i]);
	g_signal_handler_unblock(G_OBJECT(colorComboBox->materialRanges[i]),
				 colorComboBox->materialSignals[i]);
      }
}
/**
 * visu_ui_color_combobox_getRangeMaterial:
 * @colorComboBox: a #VisuUiColorCombobox widget.
 *
 * If the @colorComboBox uses ranges (see visu_ui_color_combobox_newWithRanges()), this method
 * is used to get the values from the material ranges.
 *
 * Returns: (array fixed-size=5) (transfer full): a newly created array of size
 * TOOL_MATERIAL_N_VALUES (see #ToolMaterialIds). Use g_free() to delete it.
 *
 * Since: 3.3
 */
float* visu_ui_color_combobox_getRangeMaterial(VisuUiColorCombobox *colorComboBox)
{
  int i;
  float *values;

  g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (float*)0);
  g_return_val_if_fail(colorComboBox->withRanges, (float*)0);

  values = g_malloc(sizeof(float) * TOOL_MATERIAL_N_VALUES);
  for (i = 0; i < TOOL_MATERIAL_N_VALUES; i++)
    values[i] = (float)gtk_range_get_value(GTK_RANGE(colorComboBox->materialRanges[i]));

  return values;
}
/**
 * visu_ui_color_combobox_getRangeColor:
 * @colorComboBox: a #VisuUiColorCombobox widget.
 *
 * If the @colorComboBox uses ranges (see visu_ui_color_combobox_newWithRanges()), this method
 * is used to get the values from the color ranges.
 *
 * Returns: (array fixed-size=4) (transfer full): a newly created
 * array of size 4. Use g_free() to delete it.
 *
 * Since: 3.2
 */
float* visu_ui_color_combobox_getRangeColor(VisuUiColorCombobox *colorComboBox)
{
  int i;
  float *values;

  g_return_val_if_fail(VISU_IS_UI_COLOR_COMBOBOX(colorComboBox), (float*)0);
  g_return_val_if_fail(colorComboBox->withRanges, (float*)0);

  values = g_malloc(sizeof(float) * 4);
  for (i = 0; i < 4; i++)
    values[i] = (float)gtk_range_get_value(GTK_RANGE(colorComboBox->rgbRanges[i]));

  return values;
}


/* Under developpement method, not used at the present time. */
/* void createColorSelectionCustomList(GtkColorSelectionDialog *selection) */
/* { */
/*   GtkWidget *hbox; */
/*   GtkWidget *buttonF, *buttonB, *button; */
/*   GtkWidget *image; */
/*   GtkWidget *table; */
/*   GtkWidget *label; */
/*   GtkWidget *align; */
/*   gboolean validIter; */
/*   GdkPixbuf *pixbuf; */
/*   int i; */
/*   gboolean usedPrevNext; */
/*   #define N_SHOW_COLOR 15 */
/*   GtkTreeIter iter; */
/*   GtkWidget *imageGroup; */
/*   GtkTreeIter *iterStored; */
  
/*   hbox = gtk_hbox_new(FALSE, 0); */
/*   gtk_widget_show(hbox); */
/*   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(selection)->vbox), hbox, FALSE, FALSE, 2); */

/*   label = gtk_label_new(_("Stored colors:")); */
/*   gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5); */
/*   gtk_widget_show(label); */
/*   gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 2); */
  
/*   button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); */
/*   gtk_widget_show(button); */
/*   gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 2); */

/*   usedPrevNext = (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(listStoredColors), NULL) >= N_SHOW_COLOR); */

/*   hbox = gtk_hbox_new(FALSE, 0); */
/*   gtk_widget_show(hbox); */
/*   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(selection)->vbox), hbox, FALSE, FALSE, 2); */

/*   if (usedPrevNext) */
/*     { */
/*       buttonB = gtk_button_new (); */
/*       gtk_widget_show(buttonB); */
/*       gtk_box_pack_start(GTK_BOX(hbox), buttonB, FALSE, FALSE, 2); */
/*       image = gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON); */
/*       gtk_widget_show (image); */
/*       gtk_container_add(GTK_CONTAINER(buttonB), image); */
/*     } */

/*   align= gtk_alignment_new(0.5, 0.5, 0., 0.); */
/*   gtk_widget_show(align); */
/*   gtk_box_pack_start(GTK_BOX(hbox), align, FALSE, FALSE, 2); */
/*   table = gtk_table_new(1, 10, FALSE); */
/*   gtk_widget_show(table); */
/*   gtk_container_add(GTK_CONTAINER(align), table); */

/*   if (usedPrevNext) */
/*     { */
/*       buttonF = gtk_button_new (); */
/*       gtk_widget_show(buttonF); */
/*       gtk_box_pack_start(GTK_BOX(hbox), buttonF, FALSE, FALSE, 2); */
/*       image = gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON); */
/*       gtk_widget_show (image); */
/*       gtk_container_add(GTK_CONTAINER(buttonF), image); */
/*     } */

  /* Put all the colors. */
/*   imageGroup = (GtkWidget*)0; */
/*   i = 0; */
/*   validIter = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoredColors), &iter); */
/*   while (validIter && i < N_SHOW_COLOR) */
/*     { */
/*       pixbuf = (GdkPixbuf*)0; */
/*       gtk_tree_model_get(GTK_TREE_MODEL(listStoredColors), */
/* 			 &iter, COLUMN_COLOR_PIXBUF_ALPHA, */
/* 			 &pixbuf, -1); */
/*       if (pixbuf) */
/* 	{ */
/* 	  if (!imageGroup) */
/* 	    { */
/* 	      imageGroup = gtk_radio_button_new(NULL); */
/* 	      button = imageGroup; */
/* 	    } */
/* 	  else */
/* 	    button = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(imageGroup)); */
/* 	  gtk_widget_show(button); */
/* 	  gtk_table_attach(GTK_TABLE(table), button, i, i + 1, 0, 1, GTK_FILL, GTK_FILL, 2, 2); */
/* 	  image = gtk_image_new_from_pixbuf(pixbuf); */
/* 	  gtk_widget_show(image); */
/* 	  gtk_container_add(GTK_CONTAINER(button), image); */

/* 	  iterStored = gtk_tree_iter_copy(&iter); */
/* 	  i += 1; */
/* 	} */
/*       validIter = gtk_tree_model_iter_next(GTK_TREE_MODEL(listStoredColors), &iter); */
/*     } */
/* } */
