/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Damien
	CALISTE, laboratoire L_Sim, (2001-2005)
  
	Adresse 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 : Damien
	CALISTE, laboratoire L_Sim, (2001-2005)

	E-mail address:
	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 <string.h>

#include "gtk_elementComboBox.h"
#include <visu_tools.h>
#include <visu_elements.h>

/**
 * SECTION:gtk_elementComboBox
 * @short_description: Defines a specialised #GtkComboBox to choose #VisuElement.
 *
 * <para>This widget looks like a #GtkComboBox and it displays a list
 * of #VisuElement currently used by the displayed data.</para>
 *
 * Since: 3.6
 */

enum {
  ELEMENT_SELECTED_SIGNAL,
  LAST_SIGNAL
};

/* This enum is used to access the column of the GtkListStore
   that contains the informations of stroed shades. */
enum
  {
    /* This a pointer to the VisuElement */
    COLUMN_ELEMENT_POINTER_TO,
    N_COLUMN_ELEMENT
  };

enum
  {
    PROP_0,
    NODES_PROP,
    ELEMENT_PROP,
    N_PROP
  };
static GParamSpec *_properties[N_PROP];

static void visu_ui_element_combobox_dispose (GObject *obj);
static void visu_ui_element_combobox_finalize(GObject *obj);
static void visu_ui_element_combobox_get_property(GObject* obj, guint property_id,
                                                  GValue *value, GParamSpec *pspec);
static void visu_ui_element_combobox_set_property(GObject* obj, guint property_id,
                                                  const GValue *value, GParamSpec *pspec);

static guint _signals[LAST_SIGNAL] = { 0 };

/**
 * VisuUiElementCombobox:
 *
 * An opaque structure defining a #VisuUiElementCombobox widget.
 *
 * Since: 3.6
 */
struct _VisuUiElementCombobox
{
  GtkComboBox parent;

  GtkTreeModel *filter;

  VisuNodeArray *nodes;
  gulong popDef_signal;

  gulong onChanged;
  gpointer previousSelection;

  gboolean hasAllSelector;
  gboolean hasNoneSelector;
  gboolean showUnPhysical;
  gchar *format;

  /* Memory gestion. */
  gboolean dispose_has_run;
};

/**
 * VisuUiElementComboboxClass:
 *
 * An opaque structure defining the class of a #VisuUiElementCombobox widget.
 *
 * Since: 3.6
 */
struct _VisuUiElementComboboxClass
{
  GtkComboBoxClass parent_class;

  void (*elementComboBox) (VisuUiElementCombobox *shadeCombo);

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

  gulong newElementSignalId;
};

/* Local callbacks. */
static void onChanged(GtkComboBox *widget, gpointer user_data);
static gboolean onElementNewHook(GSignalInvocationHint *ihint, guint nvalues,
                                 const GValue *param_values, gpointer data);

/* Local methods. */
static void addElementToModel(GtkTreeIter *iter, VisuUiElementComboboxClass* klass,
                              gpointer element);
static void printLabel(GtkCellLayout *layout, GtkCellRenderer *cell,
                       GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
static gboolean showLabel(GtkTreeModel *model, GtkTreeIter *iter, gpointer data);

/**
 * visu_ui_element_combobox_get_type:
 *
 * Internal routine, retrieves the type of #VisuUiElementCombobox
 * objects. Use VISU_TYPE_UI_ELEMENT_COMBOBOX macro instead.
 *
 * Since: 3.6
 */
G_DEFINE_TYPE(VisuUiElementCombobox, visu_ui_element_combobox, GTK_TYPE_COMBO_BOX)

static void visu_ui_element_combobox_class_init(VisuUiElementComboboxClass *klass)
{
  GtkTreeIter iter;
  GList *elementLst;
  
  DBG_fprintf(stderr, "VisuUi ElementCombobox: creating the class of the widget.\n");
  DBG_fprintf(stderr, "                     - adding new signals ;\n");
  /**
   * VisuUiElementCombobox::element-selected:
   * @combo: the #VisuUiElementCombobox that emits the signal ;
   * @element: the newly selected #VisuElement.
   *
   * This signal is emitted when a new element is selected.
   *
   * Since: 3.6
   */
  _signals[ELEMENT_SELECTED_SIGNAL] =
    g_signal_new ("element-selected",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (VisuUiElementComboboxClass, elementComboBox),
		  NULL, 
		  NULL,                
		  g_cclosure_marshal_VOID__POINTER,
		  G_TYPE_NONE, 1, G_TYPE_POINTER);

  DBG_fprintf(stderr, "                     - initializing the listStore of elements.\n");
  /* Init the listStore of elements. */
  klass->storedElements = gtk_list_store_new(N_COLUMN_ELEMENT,
                                             G_TYPE_POINTER);
  addElementToModel(&iter, klass, (gpointer)0);
  addElementToModel(&iter, klass, GINT_TO_POINTER(1));
  for (elementLst = (GList*)visu_element_getAllElements(); elementLst;
       elementLst = g_list_next(elementLst))
    addElementToModel(&iter, klass, elementLst->data);

  /* Connect freeing methods. */
  G_OBJECT_CLASS(klass)->dispose  = visu_ui_element_combobox_dispose;
  G_OBJECT_CLASS(klass)->finalize = visu_ui_element_combobox_finalize;
  G_OBJECT_CLASS(klass)->set_property = visu_ui_element_combobox_set_property;
  G_OBJECT_CLASS(klass)->get_property = visu_ui_element_combobox_get_property;

  /**
   * VisuUiElementCombobox::nodes:
   *
   * Store the #VisuNodeArray object used to filter the elements.
   *
   * Since: 3.8
   */
  _properties[NODES_PROP] = g_param_spec_object("nodes", "Nodes",
                                                "storing nodes used as filter model",
                                                VISU_TYPE_NODE_ARRAY, G_PARAM_READWRITE);
  /**
   * VisuUiElementCombobox::element:
   *
   * Store the #VisuElement currently selected.
   *
   * Since: 3.8
   */
  _properties[ELEMENT_PROP] = g_param_spec_object("element", "Element",
                                                "currently selected element",
                                                  VISU_TYPE_ELEMENT, G_PARAM_READWRITE);

  g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties);

  g_type_class_ref(VISU_TYPE_ELEMENT);
  g_signal_add_emission_hook(g_signal_lookup("ElementNew", VISU_TYPE_ELEMENT),
                             0, onElementNewHook, (gpointer)klass, (GDestroyNotify)0);
}

static void visu_ui_element_combobox_dispose(GObject *obj)
{
  DBG_fprintf(stderr, "VisuUi ElementCombobox: dispose object %p.\n", (gpointer)obj);

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

  VISU_UI_ELEMENT_COMBOBOX(obj)->dispose_has_run = TRUE;
  visu_ui_element_combobox_setModel(VISU_UI_ELEMENT_COMBOBOX(obj), (VisuNodeArray*)0);

  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_ui_element_combobox_parent_class)->dispose(obj);
}
static void visu_ui_element_combobox_finalize(GObject *obj)
{
  g_return_if_fail(obj);

  DBG_fprintf(stderr, "VisuUi ElementCombobox: finalize object %p.\n", (gpointer)obj);
  g_free(VISU_UI_ELEMENT_COMBOBOX(obj)->format);

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

  DBG_fprintf(stderr, " | freeing ... OK.\n");
}
static void visu_ui_element_combobox_get_property(GObject* obj, guint property_id,
                                                  GValue *value, GParamSpec *pspec)
{
  VisuUiElementCombobox *self = VISU_UI_ELEMENT_COMBOBOX(obj);
  GtkTreeIter iter;
  gpointer data;

  DBG_fprintf(stderr, "VisuUi ElementCombobox: get property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case NODES_PROP:
      g_value_set_object(value, self->nodes);
      DBG_fprintf(stderr, "%p.\n", g_value_get_object(value));
      break;
    case ELEMENT_PROP:
      if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(obj), &iter))
        {
          gtk_tree_model_get(self->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &data, -1);
          g_value_set_object(value, (GPOINTER_TO_INT(data) == 1) ? NULL : data);
        }
      else
        g_value_set_object(value, (GObject*)0);
      DBG_fprintf(stderr, "%p.\n", g_value_get_object(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_element_combobox_set_property(GObject* obj, guint property_id,
                                         const GValue *value, GParamSpec *pspec)
{
  VisuUiElementCombobox *self = VISU_UI_ELEMENT_COMBOBOX(obj);

  DBG_fprintf(stderr, "VisuUi ElementCombobox: set property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case NODES_PROP:
      DBG_fprintf(stderr, "%p\n", g_value_get_object(value));
      visu_ui_element_combobox_setModel(self, VISU_NODE_ARRAY(g_value_get_object(value)));
      break;
    case ELEMENT_PROP:
      DBG_fprintf(stderr, "%p\n", g_value_get_object(value));
      visu_ui_element_combobox_setElement(self, VISU_ELEMENT(g_value_get_object(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_element_combobox_init(VisuUiElementCombobox *elementComboBox)
{
  DBG_fprintf(stderr, "VisuUi ElementCombobox: initializing new object (%p).\n",
	      (gpointer)elementComboBox);

  elementComboBox->hasAllSelector    = FALSE;
  elementComboBox->hasNoneSelector   = FALSE;
  elementComboBox->showUnPhysical    = FALSE;
  elementComboBox->format            = g_strdup("%s");
  elementComboBox->dispose_has_run   = FALSE;
  elementComboBox->previousSelection = (gpointer)0;
  elementComboBox->nodes             = (VisuNodeArray*)0;
}

/**
 * visu_ui_element_combobox_new:
 * @hasAllSelector: a boolean.
 * @hasNoneSelector: a boolean.
 * @format: (allow-none): a string (can be NULL).
 *
 * Creates a #GtkComboBox with a list of available #VisuElement. This
 * list can contain in addition a "all" value if @hasAllSelector is
 * TRUE, or a "None" value if @hasNoneSelector is TRUE. The @format
 * parameter is used to specify the text for each row of the
 * #GtkComboBox. If @formt is NULL, just the name of the element is printed.
 * 
 * Since: 3.6
 *
 * Returns: (transfer full): a newly created widget.
 */
GtkWidget* visu_ui_element_combobox_new(gboolean hasAllSelector, gboolean hasNoneSelector,
                                        const gchar *format)
{
  VisuUiElementCombobox *wd;
  GObjectClass *klass;
  GtkCellRenderer *renderer;

  DBG_fprintf(stderr, "VisuUi ElementCombobox: creating new object with format: '%s'.\n",
	      format);
  wd = VISU_UI_ELEMENT_COMBOBOX(g_object_new(VISU_TYPE_UI_ELEMENT_COMBOBOX, NULL));
  wd->hasAllSelector  = hasAllSelector;
  wd->hasNoneSelector = hasNoneSelector;
  if (format)
    {
      g_free(wd->format);
      wd->format = g_strdup(format);
    }

  DBG_fprintf(stderr, "VisuUi ElementCombobox: build widgets.\n");
  klass = G_OBJECT_GET_CLASS(wd);
  wd->filter = gtk_tree_model_filter_new
    (GTK_TREE_MODEL(VISU_UI_ELEMENT_COMBOBOX_CLASS(klass)->storedElements), (GtkTreePath*)0);
  gtk_combo_box_set_model(GTK_COMBO_BOX(wd), wd->filter);
  g_object_unref(wd->filter);
  gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(wd->filter),
                                         showLabel, wd, (GDestroyNotify)0);
  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(wd->filter));
  DBG_fprintf(stderr, "VisuUi ElementCombobox: use filter %p.\n", (gpointer)wd->filter);

  renderer = gtk_cell_renderer_text_new();
  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(wd), renderer, TRUE);
  gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(wd),
                                     renderer, printLabel,
                                     (gpointer)wd, (GDestroyNotify)0);

  wd->onChanged = g_signal_connect(G_OBJECT(wd), "changed",
                                   G_CALLBACK(onChanged), (gpointer)wd);
  gtk_combo_box_set_active(GTK_COMBO_BOX(wd), (hasAllSelector)?1:0);

  return GTK_WIDGET(wd);
}

/**
 * visu_ui_element_combobox_setModel:
 * @combo: a #VisuUiElementCombobox object.
 * @nodes: a #VisuNodeArray object.
 *
 * Binds @nodes to @combo, so the list is always displaying the
 * #VisuElement used by @nodes.
 *
 * Since: 3.8
 *
 * Returns: TRUE if model is actually changed.
 **/
gboolean visu_ui_element_combobox_setModel(VisuUiElementCombobox *combo,
                                           VisuNodeArray *nodes)
{
  g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(combo), FALSE);

  if (combo->nodes == nodes)
    return FALSE;

  if (combo->nodes)
    {
      g_signal_handler_disconnect(combo->nodes, combo->popDef_signal);
      g_object_unref(combo->nodes);
    }
  combo->nodes = nodes;
  if (nodes)
    {
      g_object_ref(nodes);
      combo->popDef_signal =
        g_signal_connect_swapped(nodes, "notify::elements",
                                 G_CALLBACK(gtk_tree_model_filter_refilter),
                                 combo->filter);
    }
  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(combo->filter));
  if (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) < 0)
    gtk_combo_box_set_active(GTK_COMBO_BOX(combo),
                             MIN((combo->hasAllSelector)?1:0,
                                 gtk_tree_model_iter_n_children(combo->filter,
                                                                (GtkTreeIter*)0) - 1));
  return TRUE;
}

static gboolean onElementNewHook(GSignalInvocationHint *ihint _U_, guint nvalues _U_,
                                 const GValue *param_values, gpointer data)
{
  GtkTreeIter iter;
  VisuElement *ele;

  DBG_fprintf(stderr, "VisuUi ElementCombobox: found a new element.\n");
  ele = VISU_ELEMENT(g_value_get_object(param_values));
  addElementToModel(&iter, VISU_UI_ELEMENT_COMBOBOX_CLASS(data), (gpointer)ele);
  return TRUE;
}

static void onChanged(GtkComboBox *widget, gpointer user_data _U_)
{
  GtkTreeIter iter;
  gpointer *data;
  GList *lst;

  if (!gtk_combo_box_get_active_iter(widget, &iter))
    return;

  DBG_fprintf(stderr, "VisuUi ElementCombobox: internal combobox changed signal.\n");
  gtk_tree_model_get(VISU_UI_ELEMENT_COMBOBOX(widget)->filter, &iter,
                     COLUMN_ELEMENT_POINTER_TO, &data, -1);

  if (data != VISU_UI_ELEMENT_COMBOBOX(widget)->previousSelection)
    {
      VISU_UI_ELEMENT_COMBOBOX(widget)->previousSelection = data;

      lst = visu_ui_element_combobox_getSelection(VISU_UI_ELEMENT_COMBOBOX(widget));
      DBG_fprintf(stderr, "VisuUi ElementCombobox: emitting 'element-selected'"
                  " signal with list %p.\n", (gpointer)lst);
      g_signal_emit(widget, _signals[ELEMENT_SELECTED_SIGNAL], 0, (gpointer)lst);
      DBG_fprintf(stderr, " | free list\n");
      if (lst)
        g_list_free(lst);
      DBG_fprintf(stderr, " | OK\n");
      g_object_notify_by_pspec(G_OBJECT(widget), _properties[ELEMENT_PROP]);
    }
  else
    DBG_fprintf(stderr, "VisuUi ElementCombobox: aborting 'element-selected' signal.\n");
}

static void addElementToModel(GtkTreeIter *iter, VisuUiElementComboboxClass* klass,
                              gpointer element)
{
  g_return_if_fail(iter && klass);

  DBG_fprintf(stderr, "VisuUi ElementCombobox: appending a new element '%p'.\n",
	      element);
  gtk_list_store_append(klass->storedElements, iter);
  gtk_list_store_set(klass->storedElements, iter,
		     COLUMN_ELEMENT_POINTER_TO , element,
		     -1);
}

static void printLabel(GtkCellLayout *layout _U_, GtkCellRenderer *cell,
                       GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
  gpointer pt;
  gchar *str;

  gtk_tree_model_get(model, iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1);
  if (!pt)
    g_object_set(G_OBJECT(cell), "text", _("None"), NULL);
  else if (GPOINTER_TO_INT(pt) == 1)
    g_object_set(G_OBJECT(cell), "text", _("All elements"), NULL);
  else
    {
      str = g_strdup_printf(VISU_UI_ELEMENT_COMBOBOX(data)->format, ((VisuElement*)pt)->name);
      g_object_set(G_OBJECT(cell), "text", str, NULL);
      g_free(str);
    }
}

static gboolean showLabel(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
  gpointer pt;
  VisuUiElementCombobox *combo;

  combo = VISU_UI_ELEMENT_COMBOBOX(data);
  if (!combo->nodes)
    return FALSE;

  gtk_tree_model_get(model, iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1);
  return (!pt && combo->hasNoneSelector) ||
    (pt && GPOINTER_TO_INT(pt) == 1 && combo->hasAllSelector) ||
    (pt && GPOINTER_TO_INT(pt) != 1 &&
     visu_node_array_containsElement(combo->nodes, VISU_ELEMENT(pt)) &&
     (combo->showUnPhysical || visu_element_getPhysical(VISU_ELEMENT(pt))));
}

/**
 * visu_ui_element_combobox_setSelection:
 * @wd: a #VisuUiElementCombobox widget.
 * @name: a string.
 *
 * Select a #VisuElement by providing its name.
 *
 * Since: 3.6
 *
 * Returns: TRUE if the given element exists.
 */
gboolean visu_ui_element_combobox_setSelection(VisuUiElementCombobox* wd, const gchar *name)
{
  GtkTreeIter iter;
  gboolean valid;
  gpointer *pt;

  g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd) && name, FALSE);

  DBG_fprintf(stderr, "VisuUi ElementCombobox: select a new element '%s'.\n",
              name);

  for (valid = gtk_tree_model_get_iter_first(wd->filter, &iter);
       valid; valid = gtk_tree_model_iter_next(wd->filter, &iter))
    {
      gtk_tree_model_get(wd->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1);
      if (pt && GPOINTER_TO_INT(pt) != 1 &&
          !strcmp(visu_element_getName(VISU_ELEMENT(pt)), name))
	{
	  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(wd), &iter);
	  return TRUE;
	}
    }
  return FALSE;
}
/**
 * visu_ui_element_combobox_setElement:
 * @wd: a #VisuUiElementCombobox widget.
 * @element: a #VisuElement object.
 *
 * Select a #VisuElement.
 *
 * Since: 3.8
 *
 * Returns: TRUE if the given element exists.
 */
gboolean visu_ui_element_combobox_setElement(VisuUiElementCombobox* wd,
                                             const VisuElement *element)
{
  GtkTreeIter iter;
  gboolean valid;
  gpointer pt;

  g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd), FALSE);

  for (valid = gtk_tree_model_get_iter_first(wd->filter, &iter);
       valid; valid = gtk_tree_model_iter_next(wd->filter, &iter))
    {
      gtk_tree_model_get(wd->filter, &iter, COLUMN_ELEMENT_POINTER_TO, &pt, -1);
      if (pt == element)
	{
	  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(wd), &iter);
	  return TRUE;
	}
    }
  gtk_combo_box_set_active(GTK_COMBO_BOX(wd), -1);
  return FALSE;
}
/**
 * visu_ui_element_combobox_getSelection:
 * @wd: a #VisuUiElementCombobox widget.
 *
 * Provide a list of selected elements.
 *
 * Since: 3.6
 *
 * Returns: (transfer container) (element-type VisuElement*): a newly
 * created list of #VisuElement. It should be freed later with
 * g_list_free().
 */
GList* visu_ui_element_combobox_getSelection(VisuUiElementCombobox *wd)
{
  GtkTreeIter iter;
  gpointer *data;
  GList *lst;
  gboolean valid;

  g_return_val_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd), (GList*)0);

  if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(wd), &iter))
    return (GList*)0;

  gtk_tree_model_get(wd->filter, &iter,
                     COLUMN_ELEMENT_POINTER_TO, &data, -1);

  lst = (GList*)0;
  if (GPOINTER_TO_INT(data) == 1)
    for (valid = gtk_tree_model_get_iter_first(wd->filter, &iter); valid;
         valid = gtk_tree_model_iter_next(wd->filter, &iter))
      {
        gtk_tree_model_get(wd->filter, &iter,
                           COLUMN_ELEMENT_POINTER_TO, &data, -1);
        if (data && GPOINTER_TO_INT(data) != 1 &&
            visu_element_getPhysical(VISU_ELEMENT(data)))
          lst = g_list_prepend(lst, data);
      }
  else if (data)
    lst = g_list_prepend(lst, data);

  DBG_fprintf(stderr, "VisuUi ElementCombobox: return a list of %d elements.\n",
              g_list_length(lst));

  return lst;
}

/**
 * visu_ui_element_combobox_setUnphysicalStatus:
 * @wd: a #VisuUiElementCombobox object ;
 * @status: a boolean
 *
 * If @status is TRUE, the combobox will also show elements that are
 * tagged unphysical, see visu_element_getPhysical().
 *
 * Since: 3.7
 */
void visu_ui_element_combobox_setUnphysicalStatus(VisuUiElementCombobox* wd,
                                                  gboolean status)
{
  g_return_if_fail(VISU_IS_UI_ELEMENT_COMBOBOX(wd));

  wd->showUnPhysical = status;
}
