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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <gtk/gtk.h>

#include <gtk_main.h>
#include <visu_tools.h>
#include <visu_gtk.h>
#include <support.h>

#include <extraFunctions/dataFile.h>
#include <extraGtkFunctions/gtk_numericalEntryWidget.h>
#include <extraGtkFunctions/gtk_toolPanelWidget.h>
#include <extraGtkFunctions/gtk_shadeComboBoxWidget.h>
#include <extensions/shade.h>

/**
 * SECTION: panelDataFile
 * @short_description: The tab where to configure the action of an
 * external data file on colourisation of nodes.
 *
 * <para>The widgets are organised in three categories. The first is
 * used to normalised the inputs, see visu_colorization_setMin() /
 * visu_colorization_setMax(). The second category is used for
 * colourisation, see visu_colorization_setShade(). Finally the last
 * category is about post-processing.</para>
 */

/* Local variables. */
static GtkWidget *panelDataFile;
static gboolean panelDataFileIsInitiated;
static VisuColorization *attachedDt;

#define RED_DATA_LABEL   _("R")
#define GREEN_DATA_LABEL _("G")
#define BLUE_DATA_LABEL  _("B")
#define HUE_DATA_LABEL   _("H")
#define SAT_DATA_LABEL   _("S")
#define VAL_DATA_LABEL   _("V")

char* labelRGB[3];
char* labelHSV[3];

#define COL_ONE          "1."
#define COL_COORD_X      _("coord. x")
#define COL_COORD_Y      _("coord. y")
#define COL_COORD_Z      _("coord. z")
#define N_COORDS_COLS    3

#define COLOR_PREVIEW_WIDTH  120
#define COLOR_PREVIEW_HEIGHT 15
#define COLOR_PREVIEW_BITS   8

#define COLOR_TRANSFORMATION_WIDTH  60
#define COLOR_TRANSFORMATION_HEIGHT 40

#define MIN_MAX_NO_DATA_FILE _("<span style=\"italic\">No data file loaded</span>")
#define DATA_FILE_NO_FILE_MESSAGE _("No data file")

/* Local methods. */
static void createInteriorDataFile(VisuGlNodeScene *scene);
static void _createDialogFilters(GtkFileChooser *chooser, const gchar *ext);
static void updateStatusBar(const VisuColorization *dt);
static gboolean hideBelow(const VisuNodeMasker *masker,
                          const VisuNodeValuesIter *at, gpointer data);

/* Linkable widgets */
static GtkWidget *vBoxDataFileOption, *vboxNormalize;
static GtkWidget *openDataFileButton;
static GtkWidget *checkbuttonAutoLoad;
static GBinding *bind_auto;
static GtkWidget *statusbarDataFile;
static guint statusDataFileContextId;
static GtkWidget *expanderTransformation;
static GtkWidget *expanderPostProcessing;
static GtkWidget *readMinMaxValues;
static GtkWidget *checkHideMinValues;
static GtkWidget *spinHideMinValues;
static GtkWidget *entryHideMinValues;
static GtkWidget *entryFileExtension;
static GBinding *bind_ext;
static GtkWidget *comboboxRange;

static GBinding *bind_box;

static GtkListStore *colsModel;
static GtkWidget *comboboxDataCh[3];
static GBinding *bind_cols[3];

static GtkWidget *checkRestrict;
static GBinding *bind_restrict;
static GtkWidget *checkbuttonData;
static GBinding *bind_used;
static GtkWidget *entryDataMin, *entryDataMax;
static GBinding *bind_manualMin, *bind_manualMax;
static GtkWidget *radioNormalized, *radioMinMax;
static GBinding *bind_scaleAuto, *bind_scaleManual;
static GtkWidget *comboPreSetColorRange;
static GBinding *bind_preset/* , *bind_presetNot */;
static GtkWidget *radiobuttonDataRGB, *radiobuttonDataHSV;
static GBinding *bind_RGB, *bind_HSV;
static GtkWidget *colorPreview, *labelPreview;
static GdkPixbuf *pixbufColorPreview;
static GBinding *bind_preview, *bind_warn, *bind_pixbuf;
static GtkWidget *checkLegend;
static GBinding *bind_legend;
static GtkWidget *comboboxPresetCol;
static GBinding *bind_presetCol;
static GtkWidget *tableLinearToolShade;
static GBinding *bind_linear;
static GtkWidget *spinbuttonDataChA[3], *spinbuttonDataChB[3];
static GBinding *bind_spinA[3], *bind_spinB[3];
static GtkWidget *comboboxScaling, *checkScaleRadius;
static GBinding *bind_scaling, *bind_radius;

/* Signals that need to be suspended */
static gulong ncols_signal, file_signal, data_signal;

/* Callbacks */
static void onLoadDataFile(GtkFileChooserButton *button, gpointer data);
static void onComboManualChange(GtkComboBox *combo, gpointer data);
static void onSpinHideMinValuesChange(GtkSpinButton *spin, gpointer data);
static void onEntryHideMinValuesChange(VisuUiNumericalEntry *entry,
				       double oldValue, gpointer data);
static void onCheckHideMinValuesChange(GtkToggleButton *toggle, gpointer data);
static void onDataFileEnter(VisuUiPanel *visu_ui_panel, gpointer data);
static void onEntryExtChange(GtkEntry *entry, gpointer data);
static gboolean onEntryExtFocus(GtkEntry *entry, GdkEventFocus *event, gpointer data);

static void onColumns(VisuColorization *dt, GParamSpec *pspec, gpointer data);
static void onFile(VisuColorization *dt, GParamSpec *pspec, gpointer data);
static void onDataMM(VisuColorization *dt, GParamSpec *pspec, gpointer data);

static void _set(VisuColorization *dt);
static gboolean _setAttachedData(VisuColorization *dt);

struct _HideBelowData
{
  guint column;
  float value;
};
static struct _HideBelowData hidingData;

/**
 * visu_ui_panel_colorization_init: (skip)
 * @ui: a #VisuUiMain object.
 *
 * Should be used in the list declared in externalModules.h to be loaded by
 * V_Sim on start-up. This routine will create the #VisuUiPanel where the colouring
 * stuff can be done, such as choosing a colour shade, opening a file,
 * setting boundaries...
 *
 * Returns: a newly created #VisuUiPanel object.
 */
VisuUiPanel* visu_ui_panel_colorization_init(VisuUiMain *ui _U_)
{
  char *cl = _("Colorize with data");
  char *tl = _("Data color");
  GtkTreeIter iter;
  VisuGlNodeScene *scene;

  labelRGB[0] = RED_DATA_LABEL;
  labelRGB[1] = GREEN_DATA_LABEL;
  labelRGB[2] = BLUE_DATA_LABEL;
  labelHSV[0] = HUE_DATA_LABEL;
  labelHSV[1] = SAT_DATA_LABEL;
  labelHSV[2] = VAL_DATA_LABEL;

  panelDataFile = visu_ui_panel_newWithIconFromPath("Panel_colorise", cl, tl,
						"stock-data_20.png");
  if (!panelDataFile)
    return (VisuUiPanel*)0;
  visu_ui_panel_setDockable(VISU_UI_PANEL(panelDataFile), TRUE);
						 
  /* Local variables */
  colsModel = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
  gtk_list_store_append(colsModel, &iter);
  gtk_list_store_set(colsModel, &iter, 0, VISU_COLORIZATION_FROM_X,
                     1, COL_COORD_X, -1);
  gtk_list_store_append(colsModel, &iter);
  gtk_list_store_set(colsModel, &iter, 0, VISU_COLORIZATION_FROM_Y,
                     1, COL_COORD_Y, -1);
  gtk_list_store_append(colsModel, &iter);
  gtk_list_store_set(colsModel, &iter, 0, VISU_COLORIZATION_FROM_Z,
                     1, COL_COORD_Z, -1);
  entryFileExtension = (GtkWidget*)0;
  tableLinearToolShade   = (GtkWidget*)0;
  panelDataFileIsInitiated = FALSE;
  attachedDt = (VisuColorization*)0;
  scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering());

  /* Local callbacks. */
  g_signal_connect(panelDataFile, "page-entered",
		   G_CALLBACK(onDataFileEnter), scene);
  g_signal_connect_swapped(panelDataFile, "destroy",
                           G_CALLBACK(_setAttachedData), (gpointer)0);

  return VISU_UI_PANEL(panelDataFile);
}

/* static gboolean fromSingle(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_) */
/* { */
/*   g_value_set_boolean(to, g_value_get_int(from) != VISU_COLORIZATION_UNSET); */
/*   return TRUE; */
/* } */
static gboolean setChLabels(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data)
{
  if (g_value_get_boolean(from))
    g_value_set_static_string(to, labelRGB[GPOINTER_TO_INT(data)]);
  else
    g_value_set_static_string(to, labelHSV[GPOINTER_TO_INT(data)]);
  return TRUE;
}
static void createInteriorDataFile(VisuGlNodeScene *scene)
{
  GtkWidget *containerDataFilePanel;
  GtkWidget *scrolledwindow1, *wd;
  GtkWidget *viewport1;
  GtkWidget *vbox;
  GtkWidget *vboxLimits, *vboxTransformation, *vboxPostProcessing;
  GtkWidget *hbox3;
  GtkWidget *hbox8;
  GSList *radioNormalized_group = NULL;
  GtkWidget *table2;
  GtkWidget *label7;
  GtkWidget *label8;
  GtkWidget *hbox6;
  GSList *radiobuttonDataRGB_group = NULL;
  GtkWidget *label;
  GtkWidget *label14;
  GtkWidget *label15;
  GtkWidget *label16;
  GtkWidget *label20;
  GtkWidget *label21;
  GtkWidget *hrule;
  GtkWidget *hboxPreSetColorRange;
  GtkCellRenderer *renderer;
  gint i;
  const gchar *dir;
#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12
  GtkTooltips *tooltips;

  tooltips = gtk_tooltips_new ();
#endif

  DBG_fprintf(stderr, "Panel DataFile : creating subpanel.\n");

  containerDataFilePanel = gtk_vbox_new (FALSE, 0);
  gtk_widget_set_margin_start(containerDataFilePanel, 5);
  gtk_widget_set_margin_end(containerDataFilePanel, 5);

  checkbuttonData = gtk_check_button_new_with_mnemonic(_("_Use color scheme"));
  gtk_box_pack_start (GTK_BOX (containerDataFilePanel), checkbuttonData, FALSE, FALSE, 0);

  scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolledwindow1),
                                      GTK_SHADOW_IN);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_box_pack_start (GTK_BOX (containerDataFilePanel), scrolledwindow1, TRUE, TRUE, 0);

  viewport1 = gtk_viewport_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1);

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (viewport1), vbox);
  vBoxDataFileOption = vbox;
  g_object_bind_property(scene, "data",
                         vBoxDataFileOption, "sensitive", G_BINDING_SYNC_CREATE);

  /********************/
  /* The Data subset. */
  /********************/
  hbox3 = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), hbox3, FALSE, FALSE, 0);

  checkbuttonAutoLoad = gtk_check_button_new_with_mnemonic(_("_Auto load data"));
  gtk_box_pack_end(GTK_BOX(hbox3), checkbuttonAutoLoad, FALSE, FALSE, 0);
  gtk_widget_set_tooltip_text(checkbuttonAutoLoad,
			_("Try to load a data file whenever a new V_Sim file is loaded."
			  " For example, if 'example.ascii' has just been opened, V_Sim"
			  " will look for 'example.dat' and will apply it."));

  entryFileExtension = gtk_entry_new();
  gtk_entry_set_width_chars(GTK_ENTRY(entryFileExtension), 4);
  g_signal_connect(G_OBJECT(entryFileExtension), "activate",
                   G_CALLBACK(onEntryExtChange), (gpointer)0);
  g_signal_connect(G_OBJECT(entryFileExtension), "focus-out-event",
                   G_CALLBACK(onEntryExtFocus), (gpointer)0);

#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 12
  openDataFileButton = gtk_file_chooser_button_new(_("Load data file"),
                                                   GTK_FILE_CHOOSER_ACTION_OPEN);
  dir = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel());
  gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(openDataFileButton), dir);
  _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), gtk_entry_get_text(GTK_ENTRY(entryFileExtension)));
  g_signal_connect(G_OBJECT(openDataFileButton), "file-set",
                   G_CALLBACK(onLoadDataFile), (gpointer)0);  
#else
  openDataFileButton = gtk_button_new_from_stock (GTK_STOCK_OPEN);
  g_signal_connect(G_OBJECT(openDataFileButton), "clicked",
		   G_CALLBACK(loadDataFile), (gpointer)0);
#endif
  gtk_widget_set_tooltip_text(openDataFileButton,
		       _("Choose a file to read the colorization data from."));
  gtk_box_pack_start(GTK_BOX(hbox3), openDataFileButton, TRUE, TRUE, 0);
  
  gtk_box_pack_start(GTK_BOX(hbox3), entryFileExtension, FALSE, FALSE, 5);
  gtk_widget_set_tooltip_text(entryFileExtension,
		       _("File extension used for the autoload option, its value is"
			 " saved in the parameter file (see 'dataFile_fileExt')."));

  vboxNormalize = gtk_vbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), vboxNormalize, FALSE, FALSE, 0);

  hbox3 = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vboxNormalize), hbox3, FALSE, FALSE, 0);

  label = gtk_label_new(_("Normalize input: "));
  gtk_widget_set_name(label, "label_head");
  gtk_label_set_xalign(GTK_LABEL(label), 0.);
  gtk_box_pack_start (GTK_BOX (hbox3), label, TRUE, TRUE, 0);

  radioNormalized = gtk_radio_button_new_with_mnemonic (NULL, _("auto"));
  gtk_box_pack_start (GTK_BOX (hbox3), radioNormalized, FALSE, FALSE, 0);
  gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioNormalized), radioNormalized_group);
  radioNormalized_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioNormalized));

  radioMinMax = gtk_radio_button_new_with_mnemonic (NULL, _("manual"));
  gtk_box_pack_start (GTK_BOX (hbox3), radioMinMax, FALSE, FALSE, 0);
  gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioMinMax), radioNormalized_group);
  radioNormalized_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioMinMax));

  wd = gtk_expander_new(_("More information"));
  gtk_box_pack_start(GTK_BOX(vboxNormalize), wd, FALSE, FALSE, 0);
  g_object_bind_property(radioMinMax, "active", wd, "expanded", G_BINDING_SYNC_CREATE);

  vboxLimits = gtk_vbox_new(FALSE, 0);
  gtk_widget_set_margin_start(vboxLimits, 15);
  gtk_container_add(GTK_CONTAINER(wd), vboxLimits);

/*   label = gtk_label_new(_("<b>Read min/max values:</b>")); */
/*   gtk_label_set_use_markup(GTK_LABEL(label), TRUE); */
/*   gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5); */
/*   gtk_box_pack_start(GTK_BOX(vboxLimits), label, FALSE, FALSE, 0); */

  readMinMaxValues = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  gtk_box_pack_start(GTK_BOX(vboxLimits), readMinMaxValues, FALSE, FALSE, 0);  

  label = gtk_label_new(MIN_MAX_NO_DATA_FILE);
  gtk_widget_set_margin_start(label, 10);
  gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
  gtk_box_pack_start(GTK_BOX(readMinMaxValues), label, FALSE, FALSE, 0);

  label = gtk_label_new(_("<b>Input data bounds:</b>"));
  gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
  gtk_label_set_xalign(GTK_LABEL(label), 0.);
  gtk_box_pack_start(GTK_BOX(vboxLimits), label, FALSE, FALSE, 0);

  table2 = gtk_grid_new();
  tool_grid_resize(table2, 1, 6);
  gtk_widget_set_margin_start(table2, 10);
  gtk_box_pack_start(GTK_BOX(vboxLimits), table2, FALSE, FALSE, 0);
  gtk_grid_set_column_spacing(GTK_GRID(table2), 3);

  entryDataMax = visu_ui_numerical_entry_new(1.);
  gtk_entry_set_width_chars(GTK_ENTRY(entryDataMax), 6);
  gtk_grid_attach(GTK_GRID(table2), entryDataMax, 3, 0, 1, 1);
  g_object_bind_property(radioMinMax, "active", entryDataMax, "sensitive",
                         G_BINDING_SYNC_CREATE);

  entryDataMin = visu_ui_numerical_entry_new(-1.);
  gtk_entry_set_width_chars(GTK_ENTRY(entryDataMin), 6);
  gtk_grid_attach(GTK_GRID(table2), entryDataMin, 1, 0, 1, 1);
  g_object_bind_property(radioMinMax, "active", entryDataMin, "sensitive",
                         G_BINDING_SYNC_CREATE);

  renderer = gtk_cell_renderer_text_new();
  comboboxRange = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel));
  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxRange), renderer, TRUE);
  gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxRange), renderer, "text", 1);
  /* gtk_combo_box_set_id_column(GTK_COMBO_BOX(comboboxRange), 1); */
  gtk_combo_box_set_active(GTK_COMBO_BOX(comboboxRange), 0);
  gtk_grid_attach(GTK_GRID(table2), comboboxRange, 5, 0, 1, 1);
  g_object_bind_property(radioMinMax, "active", comboboxRange, "sensitive",
                         G_BINDING_SYNC_CREATE);

  label7 = gtk_label_new (_("Min:"));
  gtk_grid_attach(GTK_GRID(table2), label7, 0, 0, 1, 1);
  gtk_label_set_xalign(GTK_LABEL(label7), 1.);

  label8 = gtk_label_new (_("Max:"));
  gtk_grid_attach(GTK_GRID(table2), label8, 2, 0, 1, 1);
  gtk_label_set_xalign(GTK_LABEL(label8), 1.);

  label8 = gtk_label_new(_("Col.:"));
  gtk_grid_attach(GTK_GRID(table2), label8, 4, 0, 1, 1);
  gtk_label_set_xalign(GTK_LABEL(label8), 1.);

  /* Bar */
  hrule = gtk_hseparator_new();
  gtk_box_pack_start(GTK_BOX(vbox), hrule, FALSE, FALSE, 8);

  /***********************/
  /* Transformation part */
  /***********************/
  label = gtk_label_new(_("Define the color scheme:"));
  gtk_widget_set_name(label, "label_head");
  gtk_label_set_xalign(GTK_LABEL(label), 0.);
  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);

  hboxPreSetColorRange = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), hboxPreSetColorRange, FALSE, FALSE, 0);

  /* label = gtk_label_new(_("Preset:")); */
  /* gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5); */
  /* gtk_box_pack_start(GTK_BOX(hboxPreSetColorRange), label, TRUE, TRUE, 0); */
  
  comboPreSetColorRange = visu_ui_shade_combobox_new(FALSE, TRUE);
  gtk_box_pack_start(GTK_BOX(hboxPreSetColorRange), comboPreSetColorRange, TRUE, TRUE, 0);

  renderer = gtk_cell_renderer_text_new();
  comboboxPresetCol = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel));
  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxPresetCol), renderer, TRUE);
  gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxPresetCol), renderer, "text", 1);
  gtk_box_pack_start(GTK_BOX(hboxPreSetColorRange), comboboxPresetCol, FALSE, FALSE, 0);

  expanderTransformation = gtk_expander_new(_("More options"));
  gtk_expander_set_expanded(GTK_EXPANDER(expanderTransformation), FALSE);
  gtk_box_pack_start(GTK_BOX (vbox), expanderTransformation, FALSE, FALSE, 0);

  vboxTransformation = gtk_vbox_new(FALSE, 0);
  gtk_widget_set_margin_start(vboxTransformation, 15);
  gtk_container_add(GTK_CONTAINER(expanderTransformation), vboxTransformation);

  hbox6 = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (vboxTransformation), hbox6, FALSE, FALSE, 0);

  label = gtk_label_new(_("<b>Color space: </b>"));
  gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
  gtk_label_set_xalign(GTK_LABEL(label), 0.);
  gtk_box_pack_start (GTK_BOX (hbox6), label, TRUE, TRUE, 0);

  radiobuttonDataRGB = gtk_radio_button_new_with_mnemonic (NULL, _("RGB"));
  gtk_box_pack_start (GTK_BOX (hbox6), radiobuttonDataRGB, FALSE, FALSE, 0);
  gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobuttonDataRGB), radiobuttonDataRGB_group);
  radiobuttonDataRGB_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobuttonDataRGB));

  radiobuttonDataHSV = gtk_radio_button_new_with_mnemonic (NULL, _("HSV"));
  gtk_box_pack_start (GTK_BOX (hbox6), radiobuttonDataHSV, FALSE, FALSE, 0);
  gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobuttonDataHSV), radiobuttonDataRGB_group);
  radiobuttonDataRGB_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobuttonDataHSV));

  tableLinearToolShade = gtk_grid_new();
  tool_grid_resize(tableLinearToolShade, 3, 7);
  gtk_box_pack_start (GTK_BOX (vboxTransformation), tableLinearToolShade, FALSE, FALSE, 0);
  gtk_container_set_border_width (GTK_CONTAINER (tableLinearToolShade), 3);
  gtk_grid_set_row_spacing(GTK_GRID(tableLinearToolShade), 3);

  wd= gtk_label_new (labelRGB[0]);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), wd, 0, 0, 1, 1);
  gtk_label_set_xalign(GTK_LABEL(wd), 0.);
  g_object_bind_property_full(radiobuttonDataRGB, "active", wd, "label",
                              G_BINDING_SYNC_CREATE, setChLabels, (GBindingTransformFunc)0,
                              GINT_TO_POINTER(0), (GDestroyNotify)0);

  wd = gtk_label_new (labelRGB[1]);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), wd, 0, 1, 1, 1);
  gtk_label_set_xalign(GTK_LABEL(wd), 0.);
  g_object_bind_property_full(radiobuttonDataRGB, "active", wd, "label",
                              G_BINDING_SYNC_CREATE, setChLabels, (GBindingTransformFunc)0,
                              GINT_TO_POINTER(1), (GDestroyNotify)0);

  wd = gtk_label_new (labelRGB[2]);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), wd, 0, 2, 1, 1);
  gtk_label_set_xalign(GTK_LABEL(wd), 0.);
  g_object_bind_property_full(radiobuttonDataRGB, "active", wd, "label",
                              G_BINDING_SYNC_CREATE, setChLabels, (GBindingTransformFunc)0,
                              GINT_TO_POINTER(2), (GDestroyNotify)0);

  label14 = gtk_label_new ("=");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label14, 1, 0, 1, 1);
  label14 = gtk_label_new ("=");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label14, 1, 1, 1, 1);
  label14 = gtk_label_new ("=");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label14, 1, 2, 1, 1);

  label15 = gtk_label_new ("+");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label15, 3, 0, 1, 1);
  label15 = gtk_label_new ("+");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label15, 3, 1, 1, 1);
  label15 = gtk_label_new ("+");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label15, 3, 2, 1, 1);

  label16 = gtk_label_new ("\303\227");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label16, 5, 0, 1, 1);

  label20 = gtk_label_new ("\303\227");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label20, 5, 1, 1, 1);

  label21 = gtk_label_new ("\303\227");
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), label21, 5, 2, 1, 1);

  spinbuttonDataChA[0] = gtk_spin_button_new_with_range(-99, 99, 0.01);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChA[0]), 1.);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChA[0], 4, 0, 1, 1);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChA[0]), TRUE);

  spinbuttonDataChA[1] = gtk_spin_button_new_with_range(-99, 99, 0.01);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChA[1]), 1.);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChA[1], 4, 1, 1, 1);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChA[1]), TRUE);

  spinbuttonDataChA[2] = gtk_spin_button_new_with_range(-99, 99, 0.01);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChA[2]), 1.);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChA[2], 4, 2, 1, 1);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChA[2]), TRUE);

  spinbuttonDataChB[0] = gtk_spin_button_new_with_range(-99, 99, 0.01);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChB[0]), 0.);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChB[0], 2, 0, 1, 1);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChB[0]), TRUE);

  spinbuttonDataChB[1] = gtk_spin_button_new_with_range(-99, 99, 0.01);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChB[1]), 0.);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChB[1], 2, 1, 1, 1);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChB[1]), TRUE);

  spinbuttonDataChB[2] = gtk_spin_button_new_with_range(-99, 99, 0.01);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbuttonDataChB[2]), 0.);
  gtk_grid_attach(GTK_GRID(tableLinearToolShade), spinbuttonDataChB[2], 2, 2, 1, 1);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbuttonDataChB[2]), TRUE);

  for (i = 0; i < 3; i++)
    {
      renderer = gtk_cell_renderer_text_new();
      comboboxDataCh[i] = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel));
      gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxDataCh[i]), renderer, TRUE);
      gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxDataCh[i]), renderer, "text", 1);
      gtk_grid_attach(GTK_GRID(tableLinearToolShade), comboboxDataCh[i], 6, i, 1, 1);
    }

  hbox8 = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vboxTransformation), hbox8, FALSE, FALSE, 0);

  label = gtk_label_new(_("Color range preview: "));
  gtk_box_pack_start (GTK_BOX (hbox8), label, FALSE, FALSE, 0);

  pixbufColorPreview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE,
				      COLOR_PREVIEW_BITS,
				      COLOR_PREVIEW_WIDTH,
				      COLOR_PREVIEW_HEIGHT);
  colorPreview = create_pixmap ((GtkWidget*)0, NULL);
  gtk_widget_set_size_request (colorPreview, COLOR_PREVIEW_WIDTH,
			       COLOR_PREVIEW_HEIGHT);
  gtk_box_pack_start (GTK_BOX (hbox8), colorPreview, TRUE, TRUE, 0);

  labelPreview = gtk_label_new(_("<span style=\"italic\">No preview available</span>"));
  gtk_label_set_use_markup(GTK_LABEL(labelPreview), TRUE);
  gtk_box_pack_start (GTK_BOX (hbox8), labelPreview, TRUE, TRUE, 0);

  /* Bar */
  hrule = gtk_hseparator_new();
  gtk_box_pack_start(GTK_BOX(vbox), hrule, FALSE, FALSE, 8);

  checkLegend = gtk_check_button_new_with_mnemonic(_("Display the colour range."));
  gtk_box_pack_start(GTK_BOX(vboxTransformation), checkLegend, FALSE, FALSE, 0);
  g_object_bind_property(visu_gl_node_scene_getColorizationLegend(scene),
                         "active", checkLegend, "active",
                         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
  /* g_object_bind_property_full(visu_gl_node_scene_getColorization(scene), */
  /*                             "single-param", checkLegend, "sensitive", */
  /*                             G_BINDING_SYNC_CREATE, fromSingle, NULL, NULL, NULL); */

  /***********************/
  /* Post treatment part */
  /***********************/
  expanderPostProcessing = gtk_expander_new(_("Post processing:"));
  gtk_widget_set_sensitive(expanderPostProcessing, FALSE);
  gtk_widget_set_name(gtk_expander_get_label_widget(GTK_EXPANDER(expanderPostProcessing)),
		      "label_head");
  gtk_expander_set_expanded(GTK_EXPANDER(expanderPostProcessing), TRUE);
  gtk_box_pack_start(GTK_BOX(vbox), expanderPostProcessing, FALSE, FALSE, 0);

  vboxPostProcessing = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(expanderPostProcessing), vboxPostProcessing);

  hbox3 = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0);

  checkHideMinValues = gtk_check_button_new_with_mnemonic(_("_Hide elements"));
  gtk_box_pack_start(GTK_BOX(hbox3), checkHideMinValues, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkHideMinValues), FALSE);
  
  label = gtk_label_new(_(" whose value from"));
  gtk_box_pack_start(GTK_BOX(hbox3), label, FALSE, FALSE, 0);

  hbox3 = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0);

  label = gtk_label_new(_("col. "));
  gtk_label_set_xalign(GTK_LABEL(label), 1.);
  gtk_box_pack_start(GTK_BOX(hbox3), label, TRUE, TRUE, 0);

  /* The 2 here is to avoid a GTK bug in 2.4. */
  spinHideMinValues = gtk_spin_button_new_with_range(1, 2, 1);
  gtk_box_pack_start(GTK_BOX(hbox3), spinHideMinValues, FALSE, FALSE, 0);

  label = gtk_label_new(_(" is lower than "));
  gtk_box_pack_start(GTK_BOX(hbox3), label, FALSE, FALSE, 0);

  entryHideMinValues = visu_ui_numerical_entry_new(1.);
  gtk_entry_set_width_chars(GTK_ENTRY(entryHideMinValues), 10);
  gtk_box_pack_start(GTK_BOX(hbox3), entryHideMinValues, FALSE, FALSE, 0);

  hbox3 = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0);

  checkScaleRadius = gtk_check_button_new_with_mnemonic(_("_Scale shape according to "));
  gtk_box_pack_start(GTK_BOX(hbox3), checkScaleRadius, FALSE, FALSE, 0);
  
  renderer = gtk_cell_renderer_text_new();
  comboboxScaling = gtk_combo_box_new_with_model(GTK_TREE_MODEL(colsModel));
  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboboxScaling), renderer, TRUE);
  gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(comboboxScaling), renderer, "text", 1);
  gtk_box_pack_start(GTK_BOX(hbox3), comboboxScaling, TRUE, TRUE, 0);

  hbox3 = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vboxPostProcessing), hbox3, FALSE, FALSE, 0);

  checkRestrict = gtk_check_button_new_with_mnemonic(_("_Restrict colourisation"
                                                       " to values in range."));
  gtk_box_pack_start(GTK_BOX(hbox3), checkRestrict, FALSE, FALSE, 0);

  /**************/
  /* Status bar */
  /**************/
  statusbarDataFile = gtk_statusbar_new();
  gtk_box_pack_end(GTK_BOX(containerDataFilePanel),
		   statusbarDataFile, FALSE, FALSE, 0);
#if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 24
  gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbarDataFile), FALSE);
#endif
  statusDataFileContextId =
    gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbarDataFile),
				 _("Description of loaded data file."));
  gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile), statusDataFileContextId,
		     DATA_FILE_NO_FILE_MESSAGE);

  gtk_widget_show_all(containerDataFilePanel);
  gtk_widget_hide(colorPreview);

  /* All objects have been created. */
  panelDataFileIsInitiated = TRUE;

  /********************/
  /* Create callbacks */
  /********************/
  g_signal_connect(G_OBJECT(comboboxRange), "changed",
                   G_CALLBACK(onComboManualChange), (gpointer)0);

  g_signal_connect(G_OBJECT(checkHideMinValues), "toggled",
		   G_CALLBACK(onCheckHideMinValuesChange), (gpointer)0);
  g_signal_connect(G_OBJECT(entryHideMinValues), "value-changed",
		   G_CALLBACK(onEntryHideMinValuesChange), (gpointer)0);
  g_signal_connect(G_OBJECT(spinHideMinValues), "value-changed",
		   G_CALLBACK(onSpinHideMinValuesChange), (gpointer)0);

  DBG_fprintf(stderr, " | Creation OK.\n");

  gtk_container_add(GTK_CONTAINER(panelDataFile), containerDataFilePanel);
}

static void _createDialogFilters(GtkFileChooser *chooser, const gchar *ext)
{
  GString *label;
  GSList *lst, *tmp;
  GtkFileFilter *filter;
  
  lst = gtk_file_chooser_list_filters(chooser);

  DBG_fprintf(stderr, "Panel Colorization: creating file filter '%s'.\n", ext);
  if (ext && ext[0])
    {
      filter = gtk_file_filter_new();
      label = g_string_new(_("Data files"));
      g_string_append_printf(label, " (*%s)", ext);
      gtk_file_filter_set_name(filter, label->str);
      g_string_printf(label, "*%s", ext);
      gtk_file_filter_add_pattern(filter, label->str);
      g_string_free(label, TRUE);
      gtk_file_chooser_add_filter(chooser, filter);
      gtk_file_chooser_set_filter(chooser, filter);
    }
  filter = gtk_file_filter_new();
  gtk_file_filter_set_name(filter, _("All files"));
  gtk_file_filter_add_pattern(filter, "*");
  gtk_file_chooser_add_filter(chooser, filter);

  for (tmp = lst; tmp; tmp = g_slist_next(tmp))
    gtk_file_chooser_remove_filter(chooser, GTK_FILE_FILTER(tmp->data));
  g_slist_free(lst);
}

static void onLoadDataFile(GtkFileChooserButton *button, gpointer data _U_)
{
  gchar *filename, *directory;
  VisuData *dataFile;
  VisuNodeValuesFarray *values;
  GError *error;

  g_return_if_fail(attachedDt);

  directory = (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(button));
  if (directory)
    visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(),
                                      directory, VISU_UI_DIR_DATAFILE);
  g_free(directory);
  
  filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(button));

  dataFile = visu_ui_panel_getData(VISU_UI_PANEL(panelDataFile));

  error = (GError*)0;
  values = visu_node_values_farray_new_fromFile
    (VISU_NODE_ARRAY(dataFile), VISU_COLORIZATION_LABEL, filename, &error);
  if (!error)
    {
      visu_colorization_setNodeModel(attachedDt, values);
      visu_data_removeNodeProperties
        (dataFile, visu_node_values_getLabel(VISU_NODE_VALUES(values)));
      visu_data_addNodeProperties(dataFile, VISU_NODE_VALUES(values));
    }
  else
    {
      gchar *errMess;

      errMess = g_strdup_printf(_("Reading data file '%s' reports:\n\t%s"),
                                filename, error->message);
      visu_ui_raiseWarning(_("Loading a data file"), errMess, (GtkWindow*)0);
      g_free(errMess);
      g_error_free(error);
      if (values)
        g_object_unref(values);
    }
  g_free(filename);
}

static void updateStatusBar(const VisuColorization *dt)
{
  gchar *fileUTF8, *basename;
  gchar *message;
  const gchar *currentDataFile;
  gint nbColumns;

  nbColumns = visu_colorization_getNColumns(dt);
  currentDataFile = visu_colorization_getFile(dt);

  /* Create the text of the status bar or empty it. */
  gtk_statusbar_pop(GTK_STATUSBAR(statusbarDataFile),
		    statusDataFileContextId);
  /* Create the text of the status bar or empty it. */
  if (currentDataFile)
    {
      basename = g_path_get_basename(currentDataFile);
      fileUTF8 = g_filename_to_utf8(basename, -1, NULL, NULL, NULL);
      g_free(basename);
      g_return_if_fail(fileUTF8);

      if (nbColumns > 0)
	message = g_strdup_printf(_("%s: %d column(s)"),
                                  fileUTF8, nbColumns);
      else
	message = g_strdup_printf(_("%s: file error"),
                                  fileUTF8);
      g_free(fileUTF8);
      gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile),
			 statusDataFileContextId,
			 message);
      g_free(message);
    }
  else if (nbColumns > 0)
    {
      message = g_strdup_printf(_("%d column(s)"), nbColumns);
      gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile),
			 statusDataFileContextId,
			 message);
      g_free(message);
    }
  else
    gtk_statusbar_push(GTK_STATUSBAR(statusbarDataFile),
                       statusDataFileContextId,
                       DATA_FILE_NO_FILE_MESSAGE);
}
static gboolean getManual(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data)
{
  gint col;
  float *minmax;

  col = gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxRange));
  g_return_val_if_fail(col >= 0, FALSE);

  minmax = &g_array_index((GArray*)g_value_get_boxed(from), float, 2 * col);
  g_value_set_double(to, (double)minmax[GPOINTER_TO_INT(data)]);
  return TRUE;
}
static gboolean setManual(GBinding *bind, const GValue *from, GValue *to, gpointer data)
{
  gint col;
  float *minmax;
  GArray *arr;

  col = gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxRange));
  g_return_val_if_fail(col >= 0, FALSE);

  g_object_get(g_binding_get_source(bind), "range-min-max", &arr, NULL);
  minmax = &g_array_index(arr, float, 2 * col);
  minmax[GPOINTER_TO_INT(data)] = (float)g_value_get_double(from);
  g_value_set_boxed(to, arr);
  return TRUE;
}
static gboolean getExt(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_string(to, g_value_get_string(from));
  _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), g_value_get_string(from));
  return TRUE;
}
static gboolean setExt(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_string(to, g_value_get_string(from));
  return TRUE;
}
/* static gboolean getPresetNot(GBinding *bind, const GValue *from, GValue *to, gpointer data _U_) */
/* { */
/*   if (g_value_get_int(from) == VISU_COLORIZATION_UNSET) */
/*     g_value_set_boxed(to, (gpointer)0); */
/*   else */
/*     g_value_set_boxed(to, visu_colorization_getShade(VISU_COLORIZATION(g_binding_get_source(bind)))); */
/*   return TRUE; */
/* } */
static gboolean getScaling(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data)
{
  gboolean active;

  active = ((int)g_value_get_uint(from) == GPOINTER_TO_INT(data));
  g_value_set_boolean(to, active);
  return active;
}
static gboolean setScaling(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data)
{
  if (g_value_get_boolean(from))
    g_value_set_uint(to, GPOINTER_TO_INT(data));
  return g_value_get_boolean(from);
}
static gboolean getColor(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data)
{
  gboolean active;

  active = ((int)tool_shade_getColorMode((ToolShade*)g_value_get_boxed(from)) ==
            GPOINTER_TO_INT(data));
  g_value_set_boolean(to, active);
  return active;
}
static gboolean setColor(GBinding *bind, const GValue *from, GValue *to, gpointer data)
{
  ToolShade *shade;

  shade = tool_shade_copy(visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(g_binding_get_source(bind))));
  if (g_value_get_boolean(from))
    tool_shade_setColorMode(shade, GPOINTER_TO_INT(data));
  g_value_set_boxed(to, shade);
  return g_value_get_boolean(from);
}
static gboolean getPixbuf(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  int i;
  int rowstride, x, y;
  guchar *pixels, *p;
  float rgbValues[COLOR_PREVIEW_WIDTH][4];
  ToolShade *shade;

  rowstride = gdk_pixbuf_get_rowstride(pixbufColorPreview);
  pixels = gdk_pixbuf_get_pixels(pixbufColorPreview);
  shade = (ToolShade*)g_value_get_boxed(from);

  for (i = 0; i < COLOR_PREVIEW_WIDTH; i++)
    tool_shade_valueToRGB(shade, rgbValues[i],
                          (float)i / (float)(COLOR_PREVIEW_WIDTH - 1));

  for (y = 0; y < COLOR_PREVIEW_HEIGHT; y++)
    for (x = 0; x < COLOR_PREVIEW_WIDTH; x++)
      {
        p = pixels + y * rowstride + x * 3;
        p[0] = (guchar)(rgbValues[x][0] * 255);
        p[1] = (guchar)(rgbValues[x][1] * 255);
        p[2] = (guchar)(rgbValues[x][2] * 255);
      }
  g_value_set_object(to, pixbufColorPreview);
  return TRUE;
}
static gboolean getSingle(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_boolean(to, g_value_get_int(from) != VISU_COLORIZATION_UNSET);
  return TRUE;
}
static gboolean getCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_int(to, g_value_get_int(from) + N_COORDS_COLS);
  return TRUE;
}
static gboolean setCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_int(to, g_value_get_int(from) - N_COORDS_COLS);
  return TRUE;
}
static gboolean getTransform(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_boolean(to, (tool_shade_getMode((ToolShade*)g_value_get_boxed(from)) ==
                           TOOL_SHADE_MODE_LINEAR));
  return TRUE;
}
static gboolean getSpinA(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data)
{
  const float *vectA, *vectB;

  if (tool_shade_getMode((ToolShade*)g_value_get_boxed(from)) != TOOL_SHADE_MODE_LINEAR)
    return FALSE;
  tool_shade_getLinearCoeff((ToolShade*)g_value_get_boxed(from), &vectA, &vectB);
  g_return_val_if_fail(vectA, FALSE);
  g_value_set_double(to, vectA[GPOINTER_TO_INT(data)]);
  return TRUE;
}
static gboolean setSpinA(GBinding *bind, const GValue *from, GValue *to, gpointer data)
{
  ToolShade *shade;
  gboolean res;

  shade = tool_shade_copy(visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(g_binding_get_source(bind))));
  res = tool_shade_setLinearCoeff(shade, g_value_get_double(from), GPOINTER_TO_INT(data), 1);
  g_value_set_boxed(to, shade);
  return res;
}
static gboolean getSpinB(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data)
{
  const float *vectA, *vectB;

  if (tool_shade_getMode((ToolShade*)g_value_get_boxed(from)) != TOOL_SHADE_MODE_LINEAR)
    return FALSE;
  tool_shade_getLinearCoeff((ToolShade*)g_value_get_boxed(from), &vectA, &vectB);
  g_return_val_if_fail(vectB, FALSE);
  g_value_set_double(to, vectB[GPOINTER_TO_INT(data)]);
  return TRUE;
}
static gboolean setSpinB(GBinding *bind, const GValue *from, GValue *to, gpointer data)
{
  ToolShade *shade;
  gboolean res;

  shade = tool_shade_copy(visu_data_colorizer_shaded_getShade(VISU_DATA_COLORIZER_SHADED(g_binding_get_source(bind))));
  res = tool_shade_setLinearCoeff(shade, g_value_get_double(from), GPOINTER_TO_INT(data), 0);
  g_value_set_boxed(to, shade);
  return res;
}
static gboolean getScalCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  int id;

  id = g_value_get_int(from);
  if (id == VISU_COLORIZATION_UNSET)
    return FALSE;
  g_value_set_int(to, id + N_COORDS_COLS);
  return TRUE;
}
static gboolean setScalCol(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleRadius)))
    return FALSE;

  g_value_set_int(to, g_value_get_int(from) - N_COORDS_COLS);
  return TRUE;
}
static gboolean getScalRad(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_boolean(to, g_value_get_int(from) != VISU_COLORIZATION_UNSET);
  return TRUE;
}
static gboolean setScalRad(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  if (g_value_get_boolean(from))
    g_value_set_int(to, gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxScaling)) - N_COORDS_COLS);
  else
    g_value_set_int(to, VISU_COLORIZATION_UNSET);
  return TRUE;
}
static gboolean getPolicy(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_boolean(to, g_value_get_uint(from) == COLORIZATION_POLICY_FROM_FILE);
  return TRUE;
}
static gboolean setPolicy(GBinding *bind _U_, const GValue *from, GValue *to, gpointer data _U_)
{
  g_value_set_uint(to, g_value_get_boolean(from) ? COLORIZATION_POLICY_FROM_FILE : COLORIZATION_POLICY_FROM_PREVIOUS);
  return TRUE;
}
static gboolean _setAttachedData(VisuColorization *dt)
{
  if (attachedDt == dt)
    return FALSE;

  if (attachedDt)
    {
      g_signal_handler_disconnect(G_OBJECT(attachedDt), ncols_signal);
      g_signal_handler_disconnect(G_OBJECT(attachedDt), data_signal);
      g_signal_handler_disconnect(G_OBJECT(attachedDt), file_signal);
      g_object_unref(attachedDt);
    }
  if (dt)
    {
      g_object_ref(dt);
      ncols_signal = g_signal_connect(G_OBJECT(dt), "notify::n-columns",
                                       G_CALLBACK(onColumns), (gpointer)0);
      file_signal = g_signal_connect(G_OBJECT(dt), "notify::source-file",
                                     G_CALLBACK(onFile), (gpointer)0);
      data_signal = g_signal_connect(G_OBJECT(dt), "notify::data-min-max",
                                     G_CALLBACK(onDataMM), (gpointer)0);
    }
  attachedDt = dt;
  return TRUE;
}
static void _set(VisuColorization *dt)
{
  VisuGlNodeScene *scene;
  VisuColorization *old;

  old = attachedDt;
  if (old)
    g_object_ref(old);

  if (!_setAttachedData(dt))
    {
      if (old)
        g_object_unref(old);
      return;
    }

  if (old)
    {
      g_object_unref(bind_auto);
      g_object_unref(bind_ext);
      g_object_unref(bind_box);
      g_object_unref(bind_used);
      g_object_unref(bind_restrict);
      g_object_unref(bind_manualMin);
      g_object_unref(bind_manualMax);
      g_object_unref(bind_scaleAuto);
      g_object_unref(bind_scaleManual);
      g_object_unref(bind_preset);
      /* g_object_unref(bind_presetNot); */
      g_object_unref(bind_RGB);
      g_object_unref(bind_HSV);
      g_object_unref(bind_preview);
      g_object_unref(bind_warn);
      g_object_unref(bind_pixbuf);
      g_object_unref(bind_legend);
      g_object_unref(bind_presetCol);
      g_object_unref(bind_cols[0]);
      g_object_unref(bind_cols[1]);
      g_object_unref(bind_cols[2]);
      g_object_unref(bind_linear);
      g_object_unref(bind_spinA[0]);
      g_object_unref(bind_spinA[1]);
      g_object_unref(bind_spinA[2]);
      g_object_unref(bind_spinB[0]);
      g_object_unref(bind_spinB[1]);
      g_object_unref(bind_spinB[2]);
      g_object_unref(bind_scaling);
      g_object_unref(bind_radius);
      g_object_unref(old);
    }

  if (dt)
    {
      scene = visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering());
      if (!panelDataFileIsInitiated)
        createInteriorDataFile(scene);

      bind_auto = g_object_bind_property_full
        (scene, "colorization-policy", checkbuttonAutoLoad, "active",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getPolicy, setPolicy, (gpointer)0, (GDestroyNotify)0);
      bind_ext = g_object_bind_property_full
        (scene, "colorization-file-extension", entryFileExtension, "text",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getExt, setExt, (gpointer)0, (GDestroyNotify)0);
      bind_box = g_object_bind_property(scene, "box", dt, "box", G_BINDING_SYNC_CREATE);
      onColumns(dt, (GParamSpec*)0, (gpointer)0);
      onFile(dt, (GParamSpec*)0, (gpointer)0);
      onDataMM(dt, (GParamSpec*)0, (gpointer)0);
      bind_used = g_object_bind_property(dt, "active", checkbuttonData, "active",
                                         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
      bind_restrict = g_object_bind_property(dt, "apply-all", checkRestrict, "active",
                                             G_BINDING_BIDIRECTIONAL |
                                             G_BINDING_SYNC_CREATE |
                                             G_BINDING_INVERT_BOOLEAN);
      bind_manualMin = g_object_bind_property_full
        (dt, "range-min-max", entryDataMin, "value",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getManual, setManual, GINT_TO_POINTER(0), (GDestroyNotify)0);
      bind_manualMax = g_object_bind_property_full
        (dt, "range-min-max", entryDataMax, "value",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getManual, setManual, GINT_TO_POINTER(1), (GDestroyNotify)0);
      bind_scaleAuto = g_object_bind_property_full
        (dt, "normalisation", radioNormalized, "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getScaling, setScaling, GINT_TO_POINTER(VISU_COLORIZATION_NORMALIZE),
         (GDestroyNotify)0);
      bind_scaleManual = g_object_bind_property_full
        (dt, "normalisation", radioMinMax, "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getScaling, setScaling, GINT_TO_POINTER(VISU_COLORIZATION_MINMAX),
         (GDestroyNotify)0);
      bind_preset = g_object_bind_property(dt, "shade", comboPreSetColorRange, "shade",
                                           G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
      /* bind_presetNot = g_object_bind_property_full */
      /*   (dt, "single-param", comboPreSetColorRange, "shade", G_BINDING_SYNC_CREATE, */
      /*    getPresetNot, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0); */
      bind_RGB = g_object_bind_property_full
        (dt, "shade", radiobuttonDataRGB, "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getColor, setColor, GINT_TO_POINTER(TOOL_SHADE_COLOR_MODE_RGB), (GDestroyNotify)0);
      bind_HSV = g_object_bind_property_full
        (dt, "shade", radiobuttonDataHSV, "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getColor, setColor, GINT_TO_POINTER(TOOL_SHADE_COLOR_MODE_HSV), (GDestroyNotify)0);
      bind_preview = g_object_bind_property_full
        (dt, "single-param", colorPreview, "visible", G_BINDING_SYNC_CREATE,
         getSingle, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0);
      bind_warn = g_object_bind_property
        (colorPreview, "visible", labelPreview, "visible",
         G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
      bind_pixbuf = g_object_bind_property_full
        (dt, "shade", colorPreview, "pixbuf", G_BINDING_SYNC_CREATE,
         getPixbuf, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0);
      bind_legend = g_object_bind_property
        (colorPreview, "visible", checkLegend, "sensitive", G_BINDING_SYNC_CREATE);
      bind_presetCol = g_object_bind_property_full
        (dt, "single-param", comboboxPresetCol, "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getCol, setCol, (gpointer)0, (GDestroyNotify)0);
      bind_cols[0] = g_object_bind_property_full
        (dt, "column-red", comboboxDataCh[0], "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getCol, setCol, (gpointer)0, (GDestroyNotify)0);
      bind_cols[1] = g_object_bind_property_full
        (dt, "column-green", comboboxDataCh[1], "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getCol, setCol, (gpointer)0, (GDestroyNotify)0);
      bind_cols[2] = g_object_bind_property_full
        (dt, "column-blue", comboboxDataCh[2], "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getCol, setCol, (gpointer)0, (GDestroyNotify)0);
      bind_linear = g_object_bind_property_full
        (dt, "shade", tableLinearToolShade, "sensitive", G_BINDING_SYNC_CREATE,
         getTransform, (GBindingTransformFunc)0, (gpointer)0, (GDestroyNotify)0);
      bind_spinA[0] = g_object_bind_property_full
        (dt, "shade", spinbuttonDataChA[0], "value",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getSpinA, setSpinA, GINT_TO_POINTER(0), (GDestroyNotify)0);
      bind_spinA[1] = g_object_bind_property_full
        (dt, "shade", spinbuttonDataChA[1], "value",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getSpinA, setSpinA, GINT_TO_POINTER(1), (GDestroyNotify)0);
      bind_spinA[2] = g_object_bind_property_full
        (dt, "shade", spinbuttonDataChA[2], "value",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getSpinA, setSpinA, GINT_TO_POINTER(2), (GDestroyNotify)0);
      bind_spinB[0] = g_object_bind_property_full
        (dt, "shade", spinbuttonDataChB[0], "value",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getSpinB, setSpinB, GINT_TO_POINTER(0), (GDestroyNotify)0);
      bind_spinB[1] = g_object_bind_property_full
        (dt, "shade", spinbuttonDataChB[1], "value",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getSpinB, setSpinB, GINT_TO_POINTER(1), (GDestroyNotify)0);
      bind_spinB[2] = g_object_bind_property_full
        (dt, "shade", spinbuttonDataChB[2], "value",
         G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
         getSpinB, setSpinB, GINT_TO_POINTER(2), (GDestroyNotify)0);
      bind_scaling = g_object_bind_property_full
        (dt, "column-size", comboboxScaling, "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getScalCol, setScalCol, (gpointer)0, (GDestroyNotify)0);
      bind_radius = g_object_bind_property_full
        (dt, "column-size", checkScaleRadius, "active",
         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
         getScalRad, setScalRad, (gpointer)0, (GDestroyNotify)0);

      visu_gl_node_scene_setColorization(scene, dt);
    }
}
/**
 * visu_ui_panel_colorization_get:
 *
 * Retrieve the #VisuColorization object that the panel display the
 * status of.
 *
 * Since: 3.8
 *
 * Returns: (transfer none): a private object attached to the panel.
 **/
VisuColorization* visu_ui_panel_colorization_get()
{
  if (!panelDataFileIsInitiated)
    createInteriorDataFile(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()));
  return attachedDt;
}

/*************/
/* Callbacks */
/*************/
static void onFile(VisuColorization *dt, GParamSpec *pspec _U_, gpointer data _U_)
{
  const gchar *file;

  /* Update the widgets of this panel if necessary. */
  file = visu_colorization_getFile(dt);
  if (file)
    gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(openDataFileButton), file);

  /* Update status bar. */
  updateStatusBar(dt);
}
static void onColumns(VisuColorization *dt, GParamSpec *pspec _U_, gpointer data _U_)
{
  guint nbColumns, i;
  GString *labelStr;
  GtkTreeIter iter;
  gboolean valid;
  GtkAdjustment *adj;

  nbColumns = visu_colorization_getNColumns(dt);

  /* Rebuild the column comboboxes. */
  for (i = 0, valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(colsModel), &iter);
       valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(colsModel), &iter), i++)
    if (i > N_COORDS_COLS + nbColumns - 1)
      gtk_list_store_remove(colsModel, &iter);
  labelStr = g_string_new("");
  for (i -= N_COORDS_COLS; i < nbColumns; i++)
    {
      g_string_printf(labelStr, _("Col. %d"), i + 1);
      gtk_list_store_append(colsModel, &iter);
      gtk_list_store_set(colsModel, &iter, 0, i, 1, labelStr->str, -1);
    }
  g_string_free(labelStr, TRUE);

  /* Update post-processing widgets. */
  gtk_widget_set_sensitive(expanderPostProcessing, (nbColumns > 0));
  adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(spinHideMinValues));
  gtk_adjustment_set_upper(adj, nbColumns);

  /* Update status bar. */
  updateStatusBar(dt);
}
static void _destroyWidget(GtkWidget *widget, gpointer data _U_)
{
  gtk_widget_destroy(widget);
}
static void onDataMM(VisuColorization *dt, GParamSpec *pspec _U_, gpointer data _U_)
{
  guint nbColumns, i;
  GtkWidget *table, *label;
  float minMax[2];
  GString *labelStr;
  VisuNodeValuesFarray *values;

  /* empty the child of the alignment */
  gtk_container_foreach(GTK_CONTAINER(readMinMaxValues),
                        (GtkCallback)_destroyWidget, (gpointer)0);

  nbColumns = visu_colorization_getNColumns(dt);
  if (nbColumns > 0)
    {
      table = gtk_grid_new();
      tool_grid_resize(table, nbColumns + 1, 3);
      /*   label = gtk_label_new(_("Column number")); */
      /*   gtk_widget_set_name(label, "label_head"); */
      /*   gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_SHRINK, GTK_SHRINK, 2, 0); */
      label = gtk_label_new(_("Min value"));
      gtk_widget_set_name(label, "label_head");
      gtk_widget_set_hexpand(label, TRUE);
      gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1);
      label = gtk_label_new(_("Max value"));
      gtk_widget_set_name(label, "label_head");
      gtk_widget_set_hexpand(label, TRUE);
      gtk_grid_attach(GTK_GRID(table), label, 2, 0, 1, 1);

      g_object_get(dt, "model", &values, NULL);
      labelStr = g_string_new("");
      for (i = 0; i < nbColumns; i++)
        {
          g_string_printf(labelStr, _("Column %d"), i + 1);
          label = gtk_label_new(labelStr->str);
          gtk_grid_attach(GTK_GRID(table), label, 0, i + 1, 1, 1);

          if (visu_node_values_farray_getColumnMinMax(values, minMax, i))
            {
              g_string_printf(labelStr, "%g", minMax[0]);
              label = gtk_label_new(labelStr->str);
              gtk_label_set_selectable(GTK_LABEL(label), TRUE);
              gtk_grid_attach(GTK_GRID(table), label, 1, i + 1, 1, 1);

              g_string_printf(labelStr, "%g", minMax[1]);
              label = gtk_label_new(labelStr->str);
              gtk_label_set_selectable(GTK_LABEL(label), TRUE);
              gtk_grid_attach(GTK_GRID(table), label, 2, i + 1, 1, 1);
            }
          else
            g_warning("Can't retrieve min/max values for column %d.\n", i);
        }
      g_object_unref(values);

      gtk_widget_show_all(table);
      g_string_free(labelStr, TRUE);
      gtk_container_add(GTK_CONTAINER(readMinMaxValues), table);
    }
  else
    {
      label = gtk_label_new(MIN_MAX_NO_DATA_FILE);
      gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
      gtk_widget_show(label);
      gtk_container_add(GTK_CONTAINER(readMinMaxValues), label);
    }
}
#if GTK_MAJOR_VERSION < 3 && GTK_MINOR_VERSION < 5
static void loadDataFile(GtkButton *button _U_, gpointer data _U_)
{
  GtkWidget *file_selector;
  VisuData *dataObj;

  dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelDataFile));
  if (!dataObj)
    {
      g_warning("Can't click here since no visuData is available.\n");
      return;
    }

  file_selector = _createLoadDataDialog();
  gtk_dialog_run (GTK_DIALOG (file_selector));
  gtk_widget_destroy(file_selector);
}
#endif
static void onDataFileEnter(VisuUiPanel *visu_ui_panel _U_, gpointer data)
{
  VisuGlNodeScene *scene = VISU_GL_NODE_SCENE(data);
  
  DBG_fprintf(stderr, "Panel dataFile: check values on enter.\n");

  if (!panelDataFileIsInitiated)
    createInteriorDataFile(scene);
  if (!attachedDt)
    {
      VisuColorization *dt = visu_gl_node_scene_getColorization(scene);
      if (dt)
        _set(dt);
      else
        {
          dt = visu_colorization_new();
          _set(dt);
          g_object_unref(dt);
        }
    }
}
static void onComboManualChange(GtkComboBox *combo, gpointer data _U_)
{
  int iCol;
  VisuData *dataObj;

  dataObj = visu_ui_panel_getData(VISU_UI_PANEL(panelDataFile));
  g_return_if_fail(dataObj);

  iCol = gtk_combo_box_get_active(combo);
  if (!attachedDt || iCol < 0)
    return;
  iCol -= N_COORDS_COLS;

  visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryDataMin),
                          (double)visu_colorization_getMin(attachedDt, iCol));
  visu_ui_numerical_entry_setValue(VISU_UI_NUMERICAL_ENTRY(entryDataMax),
                          (double)visu_colorization_getMax(attachedDt, iCol));
}
static gboolean hideBelow(const VisuNodeMasker *masker _U_,
                          const VisuNodeValuesIter *at, gpointer data)
{
  struct _HideBelowData *st = (struct _HideBelowData*)data;

  return (visu_node_values_farray_getFloatAtIter(VISU_NODE_VALUES_FARRAY(at->vals),
                                                 at, st->column) < st->value);
}
static void onCheckHideMinValuesChange(GtkToggleButton *toggle,
				       gpointer data _U_)
{
  if (!attachedDt)
    return;

  /* Set or unset the hiding mode for the current colorization. */
  if (gtk_toggle_button_get_active(toggle))
    visu_node_masker_setMaskFunc(VISU_NODE_MASKER(attachedDt),
                                 hideBelow, &hidingData, (GDestroyNotify)0);
  else
    visu_node_masker_setMaskFunc(VISU_NODE_MASKER(attachedDt),
                                 (VisuNodeMaskerFunc)0, (gpointer)0, (GDestroyNotify)0);
}
static void onEntryHideMinValuesChange(VisuUiNumericalEntry *entry,
				       double oldValue _U_, gpointer data _U_)
{
  DBG_fprintf(stderr, "Panel DataFile : change value on hide"
	      " min values entry : %f\n", visu_ui_numerical_entry_getValue(entry));
  hidingData.value  = visu_ui_numerical_entry_getValue(entry);

  if (!visu_data_colorizer_getActive(VISU_DATA_COLORIZER(attachedDt)) ||
      !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkHideMinValues)))
    return;

  visu_node_masker_emitDirty(VISU_NODE_MASKER(attachedDt));
}
static void onSpinHideMinValuesChange(GtkSpinButton *spinbutton,
				      gpointer user_data _U_)
{
  DBG_fprintf(stderr, "Panel DataFile : change value of spin column"
	      " for hide function : %f\n", gtk_spin_button_get_value(spinbutton));
  hidingData.column = (guint)gtk_spin_button_get_value_as_int(spinbutton) - 1;

  if (!visu_data_colorizer_getActive(VISU_DATA_COLORIZER(attachedDt)) ||
      !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkHideMinValues)))
    return;

  visu_node_masker_emitDirty(VISU_NODE_MASKER(attachedDt));
}
static void onEntryExtChange(GtkEntry *entry, gpointer data _U_)
{
  _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), gtk_entry_get_text(entry));
}
static gboolean onEntryExtFocus(GtkEntry *entry, GdkEventFocus *event _U_, gpointer data _U_)
{
  _createDialogFilters(GTK_FILE_CHOOSER(openDataFileButton), gtk_entry_get_text(entry));
  return FALSE;
}
