1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Damien
3 	CALISTE, laboratoire L_Sim, (2016)
4 
5 	Adresse mèl :
6 	CALISTE, damien P caliste AT cea P fr.
7 
8 	Ce logiciel est un programme informatique servant à visualiser des
9 	structures atomiques dans un rendu pseudo-3D.
10 
11 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
12 	respectant les principes de diffusion des logiciels libres. Vous pouvez
13 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
14 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
15 	sur le site "http://www.cecill.info".
16 
17 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
18 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
19 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
20 */
21 
22 /*   LICENCE SUM UP
23 	Copyright CEA, contributors : Damien
24 	CALISTE, laboratoire L_Sim, (2016)
25 
26 	E-mail address:
27 	CALISTE, damien P caliste AT cea P fr.
28 
29 	This software is a computer program whose purpose is to visualize atomic
30 	configurations in 3D.
31 
32 	This software is governed by the CeCILL  license under French law and
33 	abiding by the rules of distribution of free software.  You can  use,
34 	modify and/ or redistribute the software under the terms of the CeCILL
35 	license as circulated by CEA, CNRS and INRIA at the following URL
36 	"http://www.cecill.info".
37 
38 	The fact that you are presently reading this means that you have had
39 	knowledge of the CeCILL license and that you accept its terms. You can
40 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
41 */
42 
43 #include "ui_pairtree.h"
44 
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include <support.h>
49 #include <interface.h>
50 
51 #include <visu_gtk.h>
52 #include <pairsModeling/link.h>
53 #include <pairsModeling/iface_wire.h>
54 #include <pairsModeling/iface_cylinder.h>
55 #include <pairsModeling/wire_renderer.h>
56 #include <pairsModeling/cylinder_renderer.h>
57 #include <extraGtkFunctions/gtk_elementComboBox.h>
58 
59 /**
60  * SECTION:ui_pairtree
61  * @short_description: Defines a widget to setup a link.
62  *
63  * <para>A set of widgets to setup the rendring of a link.</para>
64  */
65 
66 /**
67  * VisuUiPairTreeClass:
68  * @parent: the parent class;
69  *
70  * A short way to identify #_VisuUiPairTreeClass structure.
71  *
72  * Since: 3.8
73  */
74 /**
75  * VisuUiPairTree:
76  *
77  * An opaque structure.
78  *
79  * Since: 3.8
80  */
81 /**
82  * VisuUiPairTreePrivate:
83  *
84  * Private fields for #VisuUiPairTree objects.
85  *
86  * Since: 3.8
87  */
88 struct _VisuUiPairTreePrivate
89 {
90   gboolean dispose_has_run;
91 
92   VisuGlExtPairs *ext;
93   gulong renderer_sig;
94   VisuPairSet *model;
95   GBinding *model_bind;
96   gulong pairs_sig;
97 
98   GtkTreeModel *treemodel, *filtermodel, *sortmodel;
99 
100   GtkWidget *toolbar, *filter;
101   GtkToolItem *hideBt;
102 
103   VisuPairLink *selectedLink;
104 };
105 
106 static void visu_ui_pair_tree_finalize(GObject* obj);
107 static void visu_ui_pair_tree_dispose(GObject* obj);
108 static void visu_ui_pair_tree_get_property(GObject* obj, guint property_id,
109                                            GValue *value, GParamSpec *pspec);
110 static void visu_ui_pair_tree_set_property(GObject* obj, guint property_id,
111                                            const GValue *value, GParamSpec *pspec);
112 
113 enum
114   {
115     PROP_0,
116     MODEL_PROP,
117     EXT_PROP,
118     LINK_PROP,
119     N_PROP
120   };
121 static GParamSpec *_properties[N_PROP];
122 
123 enum {
124   SEL_SIGNAL,
125   LAST_SIGNAL
126 };
127 static guint _signals[LAST_SIGNAL] = { 0 };
128 
129 /* This enum is used to access the column
130    of the liststore have the data of pairs. */
131 enum
132   {
133     POINTER_TO_LINK,
134     COL_SIGNALS,
135     N_COLUMNS
136   };
137 
138 typedef struct _RowLink
139 {
140   guint refcount;
141 
142   VisuPairLink *link;
143   gulong notify_sig;
144 
145   VisuPair *pair;
146   gulong links_sig;
147 } RowLink;
148 #define TYPE_ROW_LINK (row_link_get_type())
149 static GType row_link_get_type(void);
150 
151 static void _setRenderer(VisuUiPairTree *tree, VisuGlExtPairs *ext);
152 static void _formatElements(GtkTreeViewColumn *column, GtkCellRenderer *cell,
153                             GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
154 static void _formatDrawn(GtkTreeViewColumn *column, GtkCellRenderer *cell,
155                          GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
156 static void _formatDistance(GtkTreeViewColumn *column, GtkCellRenderer *cell,
157                             GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
158 static void _formatPrintLength(GtkTreeViewColumn *column, GtkCellRenderer *cell,
159                                GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
160 static void _formatColor(GtkTreeViewColumn *column, GtkCellRenderer *cell,
161                          GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
162 static void _formatDescription(GtkTreeViewColumn *column, GtkCellRenderer *cell,
163                                GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
164 static gint _sortLinks(GtkTreeModel *model, GtkTreeIter *a,
165                        GtkTreeIter *b, gpointer data);
166 static gboolean _filter(GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
167 static void _expandLink(VisuUiPairTree *tree, VisuPairLink *link);
168 static void _selectLink(VisuUiPairTree *tree, VisuPairLink *link);
169 static void _selectPair(VisuUiPairTree *tree, VisuPair *pair);
170 
171 /* Local callbacks. */
172 static void onPairsNotified(VisuPairSet *set, GParamSpec *pspec, VisuUiPairTree *tree);
173 static void onRendererChanged(VisuUiPairTree *tree, VisuPairLink *link, VisuGlExtPairs *ext);
174 static void onDrawnToggled(GtkCellRendererToggle *cell_renderer,
175                            gchar *path, VisuUiPairTree *self);
176 static void onDistanceMinEdited(GtkCellRendererText *cellrenderertext,
177                                 gchar *path, gchar *text, VisuUiPairTree *self);
178 static void onDistanceMaxEdited(GtkCellRendererText *cellrenderertext,
179                                 gchar *path, gchar *text, VisuUiPairTree *self);
180 static void onLengthToggled(GtkCellRendererToggle *cell_renderer,
181                             gchar *path, VisuUiPairTree *self);
182 static void onSelectionChanged(VisuUiPairTree *self, GtkTreeSelection *selection);
183 static void onLinkNotified(GtkTreeRowReference *ref, GParamSpec *pspec, VisuPairLink *link);
184 static void onLinksNotified(GtkTreeRowReference *ref, GParamSpec *pspec, VisuPair *pair);
185 static void onAdd(VisuUiPairTree *tree, GtkButton *button);
186 static void onRemove(VisuUiPairTree *tree, GtkButton *button);
187 static void onFilter(VisuUiPairTree *tree, GtkButton *button);
188 static void onFilterChanged(VisuUiPairTree *tree, GList *elements, VisuUiElementCombobox *combobox);
189 
G_DEFINE_TYPE_WITH_CODE(VisuUiPairTree,visu_ui_pair_tree,GTK_TYPE_TREE_VIEW,G_ADD_PRIVATE (VisuUiPairTree))190 G_DEFINE_TYPE_WITH_CODE(VisuUiPairTree, visu_ui_pair_tree, GTK_TYPE_TREE_VIEW,
191                         G_ADD_PRIVATE(VisuUiPairTree))
192 
193 static void visu_ui_pair_tree_class_init(VisuUiPairTreeClass *klass)
194 {
195   DBG_fprintf(stderr, "Ui PairTree: creating the class of the widget.\n");
196   DBG_fprintf(stderr, "                     - adding new signals ;\n");
197 
198   /* Connect freeing methods. */
199   G_OBJECT_CLASS(klass)->dispose = visu_ui_pair_tree_dispose;
200   G_OBJECT_CLASS(klass)->finalize = visu_ui_pair_tree_finalize;
201   G_OBJECT_CLASS(klass)->set_property = visu_ui_pair_tree_set_property;
202   G_OBJECT_CLASS(klass)->get_property = visu_ui_pair_tree_get_property;
203 
204   /**
205    * VisuUiPairTree::model:
206    *
207    * Store the link to display properties of.
208    *
209    * Since: 3.8
210    */
211   _properties[MODEL_PROP] = g_param_spec_object("model", "Model",
212                                                 "link to display properties of",
213                                                 VISU_TYPE_PAIR_LINK, G_PARAM_READWRITE);
214   g_object_class_install_property(G_OBJECT_CLASS(klass), MODEL_PROP,
215 				  _properties[MODEL_PROP]);
216   /**
217    * VisuUiPairTree::renderer:
218    *
219    * Store the renderer used to draw links.
220    *
221    * Since: 3.8
222    */
223   _properties[EXT_PROP] = g_param_spec_object("renderer", "Renderer",
224                                               "renderer object to draw links",
225                                               VISU_TYPE_GL_EXT_PAIRS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
226   g_object_class_install_property(G_OBJECT_CLASS(klass), EXT_PROP,
227 				  _properties[EXT_PROP]);
228   /**
229    * VisuUiPairTree::selected-link:
230    *
231    * Store the currently selected link. In case of multi-selection,
232    * this property stores the first selection in the list.
233    *
234    * Since: 3.8
235    */
236   _properties[LINK_PROP] = g_param_spec_object("selected-link", "Selected link",
237                                                "currently selected link (first one in a list)",
238                                                VISU_TYPE_PAIR_LINK, G_PARAM_READABLE);
239   g_object_class_install_property(G_OBJECT_CLASS(klass), LINK_PROP,
240 				  _properties[LINK_PROP]);
241 
242   /**
243    * VisuUiPairTree::selection-changed:
244    * @tree: the object which emits the signal ;
245    * @links: (type VisuPairLink) (transfer none): a list of
246    * #VisuPairLink objects.
247    *
248    * Gets emitted when the selection change.
249    *
250    * Since: 3.8
251    */
252   _signals[SEL_SIGNAL] =
253     g_signal_new("selection-changed", G_TYPE_FROM_CLASS(klass),
254                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
255                  0 , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
256                  G_TYPE_NONE, 1, G_TYPE_POINTER);
257 }
visu_ui_pair_tree_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)258 static void visu_ui_pair_tree_get_property(GObject* obj, guint property_id,
259                                            GValue *value, GParamSpec *pspec)
260 {
261   VisuUiPairTree *self = VISU_UI_PAIR_TREE(obj);
262 
263   DBG_fprintf(stderr, "Ui PairTree: get property '%s' -> ",
264 	      g_param_spec_get_name(pspec));
265   switch (property_id)
266     {
267     case MODEL_PROP:
268       g_value_set_object(value, self->priv->model);
269       DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->model);
270       break;
271     case EXT_PROP:
272       g_value_set_object(value, self->priv->ext);
273       DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->ext);
274       break;
275     case LINK_PROP:
276       g_value_set_object(value, self->priv->selectedLink);
277       DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->selectedLink);
278       break;
279     default:
280       /* We don't have any other property... */
281       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
282       break;
283     }
284 }
visu_ui_pair_tree_set_property(GObject * obj,guint property_id,const GValue * value,GParamSpec * pspec)285 static void visu_ui_pair_tree_set_property(GObject* obj, guint property_id,
286                                       const GValue *value, GParamSpec *pspec)
287 {
288   VisuUiPairTree *self = VISU_UI_PAIR_TREE(obj);
289 
290   DBG_fprintf(stderr, "Ui PairTree: set property '%s' -> ",
291 	      g_param_spec_get_name(pspec));
292   switch (property_id)
293     {
294     case MODEL_PROP:
295       DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value));
296       visu_ui_pair_tree_bind(self, VISU_PAIR_SET(g_value_get_object(value)));
297       break;
298     case EXT_PROP:
299       DBG_fprintf(stderr, "%p.\n", (gpointer)g_value_get_object(value));
300       _setRenderer(self, VISU_GL_EXT_PAIRS(g_value_get_object(value)));
301       break;
302     default:
303       /* We don't have any other property... */
304       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
305       break;
306     }
307 }
visu_ui_pair_tree_dispose(GObject * obj)308 static void visu_ui_pair_tree_dispose(GObject *obj)
309 {
310   VisuUiPairTree *self = VISU_UI_PAIR_TREE(obj);
311   DBG_fprintf(stderr, "Ui PairTree: dispose object %p.\n", (gpointer)obj);
312 
313   if (self->priv->dispose_has_run)
314     return;
315   self->priv->dispose_has_run = TRUE;
316 
317   visu_ui_pair_tree_bind(self, (VisuPairSet*)0);
318   _setRenderer(self, (VisuGlExtPairs*)0);
319   if (self->priv->selectedLink)
320     g_object_unref(self->priv->selectedLink);
321   if (self->priv->toolbar)
322     g_object_unref(self->priv->toolbar);
323   if (self->priv->filter)
324     g_object_unref(self->priv->filter);
325   gtk_tree_store_clear(GTK_TREE_STORE(VISU_UI_PAIR_TREE(obj)->priv->treemodel));
326 
327   /* Chain up to the parent class */
328   G_OBJECT_CLASS(visu_ui_pair_tree_parent_class)->dispose(obj);
329 }
visu_ui_pair_tree_finalize(GObject * obj)330 static void visu_ui_pair_tree_finalize(GObject *obj)
331 {
332   g_return_if_fail(obj);
333 
334   DBG_fprintf(stderr, "Ui PairTree: finalize object %p.\n", (gpointer)obj);
335   DBG_fprintf(stderr, " | sort has (%d) ref counts.\n", G_OBJECT(VISU_UI_PAIR_TREE(obj)->priv->sortmodel)->ref_count);
336   g_object_unref(VISU_UI_PAIR_TREE(obj)->priv->sortmodel);
337   DBG_fprintf(stderr, " | filter has (%d) ref counts.\n", G_OBJECT(VISU_UI_PAIR_TREE(obj)->priv->filtermodel)->ref_count);
338   g_object_unref(VISU_UI_PAIR_TREE(obj)->priv->filtermodel);
339   DBG_fprintf(stderr, " | model has (%d) ref counts.\n", G_OBJECT(VISU_UI_PAIR_TREE(obj)->priv->treemodel)->ref_count);
340   g_object_unref(VISU_UI_PAIR_TREE(obj)->priv->treemodel);
341 
342   /* Chain up to the parent class */
343   G_OBJECT_CLASS(visu_ui_pair_tree_parent_class)->finalize(obj);
344   DBG_fprintf(stderr, " | freeing ... OK.\n");
345 }
346 
visu_ui_pair_tree_init(VisuUiPairTree * obj)347 static void visu_ui_pair_tree_init(VisuUiPairTree *obj)
348 {
349   GtkCellRenderer *renderer;
350   GtkTreeViewColumn *column;
351 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12
352   GtkTooltips *tooltips;
353   tooltips = gtk_tooltips_new ();
354 #endif
355 
356   DBG_fprintf(stderr, "Extension PairTree: initializing a new object (%p).\n",
357 	      (gpointer)obj);
358 
359   obj->priv = visu_ui_pair_tree_get_instance_private(obj);
360   obj->priv->dispose_has_run = FALSE;
361 
362   obj->priv->model = (VisuPairSet*)0;
363   obj->priv->model_bind = (GBinding*)0;
364   obj->priv->ext   = (VisuGlExtPairs*)0;
365 
366   obj->priv->selectedLink = (VisuPairLink*)0;
367 
368   obj->priv->toolbar = (GtkWidget*)0;
369   obj->priv->hideBt  = (GtkToolItem*)0;
370 
371   g_object_set(G_OBJECT(obj), "rules-hint", TRUE, NULL);
372   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(obj), TRUE);
373 
374   /* Create the listModel for pairs data*/
375   obj->priv->treemodel =
376     GTK_TREE_MODEL(gtk_tree_store_new(N_COLUMNS, VISU_TYPE_PAIR_LINK, TYPE_ROW_LINK));
377 
378   /* Render the associated tree */
379   renderer = gtk_cell_renderer_text_new ();
380   column = gtk_tree_view_column_new();
381   gtk_tree_view_column_set_title(column, _("Pair"));
382   gtk_tree_view_column_set_sort_indicator(column, TRUE);
383   gtk_tree_view_column_set_sort_order(column, GTK_SORT_ASCENDING);
384   gtk_tree_view_column_pack_start(column, renderer, TRUE);
385   gtk_tree_view_column_set_cell_data_func(column, renderer, _formatElements,
386                                           (gpointer)0, (GDestroyNotify)0);
387   gtk_tree_view_column_set_sort_column_id(column, POINTER_TO_LINK);
388   renderer = gtk_cell_renderer_toggle_new ();
389   g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onDrawnToggled), obj);
390   gtk_tree_view_column_pack_end(column, renderer, FALSE);
391   gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDrawn,
392                                           (gpointer)0, (GDestroyNotify)0);
393   gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column);
394 
395   renderer = gtk_cell_renderer_text_new();
396   g_object_set(G_OBJECT(renderer), "editable", TRUE, "foreground", "blue", NULL);
397   g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(onDistanceMinEdited), obj);
398   column = gtk_tree_view_column_new();
399   gtk_tree_view_column_set_title(column, _("From"));
400   gtk_tree_view_column_pack_start(column, renderer, TRUE);
401   gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDistance,
402                                           GINT_TO_POINTER(VISU_DISTANCE_MIN),
403                                           (GDestroyNotify)0);
404   gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column);
405   renderer = gtk_cell_renderer_text_new();
406   g_object_set(G_OBJECT(renderer), "editable", TRUE, "foreground", "blue", NULL);
407   g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(onDistanceMaxEdited), obj);
408   column = gtk_tree_view_column_new();
409   gtk_tree_view_column_set_title(column, _("To"));
410   gtk_tree_view_column_pack_start(column, renderer, TRUE);
411   gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDistance,
412                                           GINT_TO_POINTER(VISU_DISTANCE_MAX),
413                                           (GDestroyNotify)0);
414   gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column);
415 
416   renderer = gtk_cell_renderer_toggle_new ();
417   g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(onLengthToggled), obj);
418   column = gtk_tree_view_column_new();
419   gtk_tree_view_column_set_title(column, _("Lg."));
420   gtk_tree_view_column_pack_start(column, renderer, TRUE);
421   gtk_tree_view_column_set_cell_data_func(column, renderer, _formatPrintLength,
422                                           (gpointer)0, (GDestroyNotify)0);
423   gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column);
424 
425   column = gtk_tree_view_column_new();
426   gtk_tree_view_column_set_title(column, _("Parameters"));
427   renderer = gtk_cell_renderer_pixbuf_new();
428   gtk_tree_view_column_pack_start(column, renderer, FALSE);
429   gtk_tree_view_column_set_cell_data_func(column, renderer, _formatColor,
430                                           (gpointer)0, (GDestroyNotify)0);
431   renderer = gtk_cell_renderer_text_new();
432   gtk_tree_view_column_pack_start(column, renderer, TRUE);
433   gtk_tree_view_column_set_cell_data_func(column, renderer, _formatDescription,
434                                           (gpointer)obj, (GDestroyNotify)0);
435   gtk_tree_view_append_column(GTK_TREE_VIEW(obj), column);
436 
437   gtk_widget_show_all(GTK_WIDGET(obj));
438 
439   DBG_fprintf(stderr, "Ui PairTree: model has %d ref counts.\n", G_OBJECT(obj->priv->treemodel)->ref_count);
440   obj->priv->filtermodel = gtk_tree_model_filter_new(obj->priv->treemodel, NULL);
441   gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(obj->priv->filtermodel),
442 					 _filter, (gpointer)obj, (GDestroyNotify)0);
443   obj->priv->sortmodel = gtk_tree_model_sort_new_with_model(obj->priv->filtermodel);
444   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(obj->priv->sortmodel),
445 				       POINTER_TO_LINK, GTK_SORT_ASCENDING);
446   gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(obj->priv->sortmodel),
447 				  POINTER_TO_LINK, _sortLinks, (gpointer)0, NULL);
448 
449   gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(obj)),
450 			      GTK_SELECTION_MULTIPLE);
451   gtk_tree_view_set_model(GTK_TREE_VIEW(obj), obj->priv->sortmodel);
452   g_signal_connect_swapped(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(obj))), "changed",
453                            G_CALLBACK(onSelectionChanged), obj);
454   DBG_fprintf(stderr, "Ui PairTree: model has %d ref counts.\n", G_OBJECT(obj->priv->treemodel)->ref_count);
455 }
456 
457 
458 /**
459  * visu_ui_pair_tree_new:
460  * @pairs: a #VisuGlExtPairs object.
461  *
462  * Creates a new #VisuUiPairTree to allow to setup link rendering characteristics.
463  *
464  * Since: 3.8
465  *
466  * Returns: a pointer to the newly created widget.
467  */
visu_ui_pair_tree_new(VisuGlExtPairs * pairs)468 GtkWidget* visu_ui_pair_tree_new(VisuGlExtPairs *pairs)
469 {
470   DBG_fprintf(stderr,"Ui PairTree: new object.\n");
471 
472   return GTK_WIDGET(g_object_new(VISU_TYPE_UI_PAIR_TREE, "renderer", pairs, NULL));
473 }
474 /**
475  * visu_ui_pair_tree_bind:
476  * @tree: a #VisuUiPairTree object.
477  * @model: a #VisuPairSet object.
478  *
479  * Binds @model to @tree, so every #VisuPairLink of @model are always
480  * listed into @tree.
481  *
482  * Since: 3.8
483  **/
visu_ui_pair_tree_bind(VisuUiPairTree * tree,VisuPairSet * model)484 void visu_ui_pair_tree_bind(VisuUiPairTree *tree, VisuPairSet *model)
485 {
486   if (tree->priv->model)
487     {
488       if (tree->priv->model_bind && tree->priv->filter)
489         g_object_unref(tree->priv->model_bind);
490       /* g_signal_handler_disconnect(G_OBJECT(tree->priv->ext), tree->priv->renderer_sig); */
491       g_signal_handler_disconnect(tree->priv->model, tree->priv->pairs_sig);
492       g_object_unref(tree->priv->model);
493     }
494   if (model)
495     {
496       g_object_ref(model);
497       /* tree->priv->renderer_sig = g_signal_connect_swapped(G_OBJECT(ext), "renderer-changed", */
498       /*                                                     G_CALLBACK(onRendererChanged), tree); */
499       if (tree->priv->filter)
500         tree->priv->model_bind =
501           g_object_bind_property(model, "data", tree->priv->filter, "nodes",
502                                  G_BINDING_SYNC_CREATE);
503       tree->priv->pairs_sig = g_signal_connect(model, "notify::pairs",
504                                                G_CALLBACK(onPairsNotified), tree);
505       onPairsNotified(model, (GParamSpec*)0, tree);
506     }
507   tree->priv->model = model;
508   g_object_notify_by_pspec(G_OBJECT(tree), _properties[MODEL_PROP]);
509 }
510 
_setRenderer(VisuUiPairTree * tree,VisuGlExtPairs * ext)511 static void _setRenderer(VisuUiPairTree *tree, VisuGlExtPairs *ext)
512 {
513   if (tree->priv->ext)
514     {
515       g_signal_handler_disconnect(G_OBJECT(tree->priv->ext), tree->priv->renderer_sig);
516       g_object_unref(tree->priv->ext);
517     }
518   if (ext)
519     {
520       g_object_ref(ext);
521       tree->priv->renderer_sig = g_signal_connect_swapped(G_OBJECT(ext), "renderer-changed",
522                                                           G_CALLBACK(onRendererChanged), tree);
523     }
524   tree->priv->ext = ext;
525 }
_notifyFor(GtkTreeModel * model,GtkTreeIter * iter,VisuPairLink * link)526 static void _notifyFor(GtkTreeModel *model, GtkTreeIter *iter, VisuPairLink *link)
527 {
528   VisuPairLink *tmp;
529   GtkTreePath *path;
530 
531   gtk_tree_model_get(model, iter, POINTER_TO_LINK, &tmp, -1);
532   if (tmp == link)
533     {
534       path = gtk_tree_model_get_path(model, iter);
535       gtk_tree_model_row_changed(model, path, iter);
536       gtk_tree_path_free(path);
537     }
538   g_object_unref(G_OBJECT(tmp));
539 }
onRendererChanged(VisuUiPairTree * tree,VisuPairLink * link,VisuGlExtPairs * ext _U_)540 static void onRendererChanged(VisuUiPairTree *tree, VisuPairLink *link, VisuGlExtPairs *ext _U_)
541 {
542   GtkTreeIter it, child;
543   gboolean valid, valid2;
544 
545   DBG_fprintf(stderr, "Ui PairTree: (onRendererChanged) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count);
546   for (valid = gtk_tree_model_get_iter_first(tree->priv->treemodel, &it);
547        valid; valid = gtk_tree_model_iter_next(tree->priv->treemodel, &it))
548     {
549       _notifyFor(tree->priv->treemodel, &it, link);
550       for (valid2 = gtk_tree_model_iter_children(tree->priv->treemodel, &child, &it);
551            valid2; valid2 = gtk_tree_model_iter_next(tree->priv->treemodel, &child))
552         _notifyFor(tree->priv->treemodel, &child, link);
553     }
554   DBG_fprintf(stderr, "Ui PairTree: (onRendererChanged) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count);
555 }
_formatElements(GtkTreeViewColumn * column _U_,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data _U_)556 static void _formatElements(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell,
557                             GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_)
558 {
559   gchar lbl[128];
560   VisuElement *ele1, *ele2;
561   VisuPairLink *link;
562   GtkTreeIter parent;
563 
564   if (gtk_tree_model_iter_parent(model, &parent, iter))
565     lbl[0] = '\0';
566   else
567     {
568       gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1);
569       ele1 = visu_pair_link_getFirstElement(link);
570       ele2 = visu_pair_link_getSecondElement(link);
571       if (strcmp(ele1->name, ele2->name) < 0)
572         sprintf(lbl, "%s - %s", ele1->name, ele2->name);
573       else
574         sprintf(lbl, "%s - %s", ele2->name, ele1->name);
575       g_object_unref(G_OBJECT(link));
576       g_object_unref(G_OBJECT(ele1));
577       g_object_unref(G_OBJECT(ele2));
578     }
579   g_object_set(G_OBJECT(cell), "text", lbl, NULL);
580 }
_formatDrawn(GtkTreeViewColumn * column _U_,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data _U_)581 static void _formatDrawn(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell,
582                          GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_)
583 {
584   VisuPairLink *link;
585 
586   gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1);
587   g_object_set(G_OBJECT(cell), "active", visu_pair_link_getDrawn(link), NULL);
588   g_object_unref(G_OBJECT(link));
589 }
_formatDistance(GtkTreeViewColumn * column _U_,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)590 static void _formatDistance(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell,
591                             GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
592 {
593   gchar dist[18];
594   VisuPairLink *link;
595   ToolUnits units;
596 
597   gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1);
598   units = visu_pair_link_getUnits(link);
599   if (units == TOOL_UNITS_UNDEFINED)
600     sprintf(dist, "%6.3f", visu_pair_link_getDistance(link, GPOINTER_TO_INT(data)));
601   else
602     sprintf(dist, "%6.3f %s", visu_pair_link_getDistance(link, GPOINTER_TO_INT(data)),
603             tool_physic_getUnitLabel(units));
604   g_object_set(G_OBJECT(cell), "markup", dist, NULL);
605   g_object_unref(G_OBJECT(link));
606 }
_formatPrintLength(GtkTreeViewColumn * column _U_,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data _U_)607 static void _formatPrintLength(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell,
608                                GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_)
609 {
610   VisuPairLink *link;
611 
612   gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1);
613   g_object_set(G_OBJECT(cell), "active", visu_pair_link_getPrintLength(link), NULL);
614   g_object_unref(G_OBJECT(link));
615 }
_formatColor(GtkTreeViewColumn * column _U_,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data _U_)616 static void _formatColor(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell,
617                          GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_)
618 {
619   VisuPairLink *link;
620   ToolColor *color;
621   GdkPixbuf *pixColor;
622 
623   gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1);
624   color = visu_pair_link_getColor(link);
625   pixColor = tool_color_get_stamp(color, TRUE);
626   g_object_unref(link);
627 
628   g_object_set(G_OBJECT(cell), "pixbuf", pixColor, NULL);
629   g_object_unref(pixColor);
630 }
_formatDescription(GtkTreeViewColumn * column _U_,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)631 static void _formatDescription(GtkTreeViewColumn *column _U_, GtkCellRenderer *cell,
632                                GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
633 {
634   VisuPairLink *link;
635   VisuPairLinkRenderer *renderer;
636   gchar *str;
637   ToolUnits units;
638   static gchar* cylinderTypes[VISU_CYLINDER_N_COLOR] = {
639     "user color",
640     "element color",
641     "node color",
642   };
643 
644   gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1);
645   renderer = visu_gl_ext_pairs_getLinkRenderer(VISU_UI_PAIR_TREE(data)->priv->ext, link);
646 
647   str = (gchar*)0;
648   if (VISU_IS_PAIR_WIRE_RENDERER(renderer))
649     /* px is for pixels and pat. for pattern. */
650     str = g_strdup_printf("%s %2d%s, %s %d", _("wire:"),
651                           visu_pair_wire_getWidth(VISU_PAIR_WIRE(link)),
652                           _("px"), _("pattern:"),
653                           visu_pair_wire_getStipple(VISU_PAIR_WIRE(link)));
654   else if (VISU_IS_PAIR_CYLINDER_RENDERER(renderer))
655     {
656       units = visu_pair_link_getUnits(link);
657       if (units == TOOL_UNITS_UNDEFINED)
658         /* a.u. is for arbitrary units. */
659         str = g_strdup_printf("%s %3.2f %s, %s", _("radius:"),
660                               visu_pair_cylinder_getRadius(VISU_PAIR_CYLINDER(link)), _("a.u."),
661                               _(cylinderTypes[visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(link))]));
662       else
663         str = g_strdup_printf("%s %3.2f %s, %s", _("radius:"),
664                               visu_pair_cylinder_getRadius(VISU_PAIR_CYLINDER(link)), tool_physic_getUnitLabel(units),
665                               _(cylinderTypes[visu_pair_cylinder_getColorType(VISU_PAIR_CYLINDER(link))]));
666     }
667   g_object_unref(link);
668 
669   g_object_set(G_OBJECT(cell), "text", str, NULL);
670   g_free(str);
671 }
_sortLinks(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data _U_)672 static gint _sortLinks(GtkTreeModel *model, GtkTreeIter *a,
673                        GtkTreeIter *b, gpointer data _U_)
674 {
675   VisuPairLink *aLink, *bLink;
676   VisuElement *a_ele1, *a_ele2;
677   VisuElement *b_ele1, *b_ele2;
678   int cmp1, cmp2;
679   gint diff;
680   float a_from, a_to, b_from, b_to;
681 
682   gtk_tree_model_get(model, a, POINTER_TO_LINK, &aLink, -1);
683   gtk_tree_model_get(model, b, POINTER_TO_LINK, &bLink, -1);
684 
685   a_ele1 = visu_pair_link_getFirstElement(aLink);
686   a_ele2 = visu_pair_link_getSecondElement(aLink);
687   b_ele1 = visu_pair_link_getFirstElement(bLink);
688   b_ele2 = visu_pair_link_getSecondElement(bLink);
689 
690   cmp1 = strcmp(a_ele1->name, b_ele1->name);
691   cmp2 = strcmp(a_ele2->name, b_ele2->name);
692   DBG_fprintf(stderr, "Ui Pair Tree: comparing %d - %d.\n", cmp1, cmp2);
693 
694   diff = (cmp1 == 0) ? cmp2 : cmp1;
695   if (diff == 0)
696     {
697       a_from = visu_pair_link_getDistance(aLink, VISU_DISTANCE_MIN);
698       a_to   = visu_pair_link_getDistance(aLink, VISU_DISTANCE_MAX);
699       b_from = visu_pair_link_getDistance(bLink, VISU_DISTANCE_MIN);
700       b_to   = visu_pair_link_getDistance(bLink, VISU_DISTANCE_MAX);
701       DBG_fprintf(stderr, "Ui Pair Tree: compare distances %g / %g.\n",
702                   (a_to + a_from), (b_to + b_from));
703       if ((a_to + a_from) == (b_to + b_from))
704         diff = 0;
705       else
706         diff = ((a_to + a_from) < (b_to + b_from)) ? -1 : +1;
707     }
708 
709   DBG_fprintf(stderr, "Ui Pair Tree: sort '%s - %s' with '%s - %s' -> %d.\n",
710 	      a_ele1->name, a_ele2->name, b_ele1->name, b_ele2->name, diff);
711 
712   g_object_unref(G_OBJECT(a_ele1));
713   g_object_unref(G_OBJECT(a_ele2));
714   g_object_unref(G_OBJECT(b_ele1));
715   g_object_unref(G_OBJECT(b_ele2));
716 
717   g_object_unref(G_OBJECT(aLink));
718   g_object_unref(G_OBJECT(bLink));
719 
720   return diff;
721 }
_filter(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)722 static gboolean _filter(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
723 {
724   VisuUiPairTree *tree = VISU_UI_PAIR_TREE(data);
725   VisuPairLink *link;
726   GList *elements;
727   float start, stop;
728   VisuElement *ele1, *ele2;
729   const gchar *label;
730   gboolean visible;
731 
732   gtk_tree_model_get(model, iter, POINTER_TO_LINK, &link, -1);
733   start = visu_pair_link_getDistance(link, VISU_DISTANCE_MIN);
734   stop  = visu_pair_link_getDistance(link, VISU_DISTANCE_MAX);
735   ele1 = visu_pair_link_getFirstElement(link);
736   ele2 = visu_pair_link_getSecondElement(link);
737   g_object_unref(link);
738 
739   elements = (tree->priv->filter) ? visu_ui_element_combobox_getSelection(VISU_UI_ELEMENT_COMBOBOX(tree->priv->filter)) : (GList*)0;
740   if (elements)
741     {
742       label = visu_element_getName(VISU_ELEMENT(elements->data));
743       visible = !strcmp(label, ele1->name) || !strcmp(label, ele2->name);
744       g_list_free(elements);
745     }
746   else
747     visible = TRUE;
748 
749   g_object_unref(ele1);
750   g_object_unref(ele2);
751 
752   /* Add the visibility tag due to the hide button. */
753   visible = visible &&
754     (!tree->priv->hideBt ||
755      !gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(tree->priv->hideBt)) ||
756      (stop > start));
757 
758   return visible;
759 }
760 
row_link_copy(RowLink * row)761 static RowLink* row_link_copy(RowLink *row)
762 {
763   if (row)
764     {
765       row->refcount += 1;
766       DBG_fprintf(stderr, "Ui Pair Tree: ref row (%d).\n", row->refcount);
767     }
768   return row;
769 }
row_link_free(RowLink * row)770 static void row_link_free(RowLink *row)
771 {
772   if (!row)
773     return;
774 
775   DBG_fprintf(stderr, "Ui Pair Tree: unref row (%d).\n", row->refcount);
776   row->refcount -= 1;
777   if (!row->refcount)
778     {
779       if (row->link)
780         {
781           g_signal_handler_disconnect(row->link, row->notify_sig);
782           g_object_unref(row->link);
783         }
784       if (row->pair)
785         {
786           g_signal_handler_disconnect(row->pair, row->links_sig);
787           g_object_unref(row->pair);
788         }
789       g_free(row);
790     }
791 }
row_link_get_type(void)792 static GType row_link_get_type(void)
793 {
794   static GType g_define_type_id = 0;
795 
796   if (g_define_type_id == 0)
797     g_define_type_id =
798       g_boxed_type_register_static("RowLink", (GBoxedCopyFunc)row_link_copy,
799                                    (GBoxedFreeFunc)row_link_free);
800   return g_define_type_id;
801 }
_freeRow(GtkTreeRowReference * ref,GClosure * closure _U_)802 static void _freeRow(GtkTreeRowReference *ref, GClosure *closure _U_)
803 {
804   gtk_tree_row_reference_free(ref);
805 }
_addLink(GtkTreeStore * store,GtkTreeIter * iter,GtkTreeIter * parent,VisuPair * pair,VisuPairLink * link)806 static void _addLink(GtkTreeStore *store, GtkTreeIter *iter,
807                      GtkTreeIter *parent, VisuPair *pair, VisuPairLink *link)
808 {
809   GtkTreePath *path;
810   GtkTreeRowReference *ref;
811   RowLink *row;
812 
813 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9
814   gtk_tree_store_insert_with_values(store, iter, parent, 0,
815                                     POINTER_TO_LINK, link, -1);
816 #else
817   gtk_tree_store_append(store, iter, parent);
818   gtk_tree_store_set(store, iter, POINTER_TO_LINK, link, -1);
819 #endif
820   path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), iter);
821   ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path);
822   gtk_tree_path_free(path);
823   row = g_malloc0(sizeof(RowLink));
824   row->link = g_object_ref(link);
825   row->notify_sig = g_signal_connect_data(G_OBJECT(link), "notify",
826                                           G_CALLBACK(onLinkNotified), ref,
827                                           (GClosureNotify)_freeRow,
828                                           G_CONNECT_SWAPPED);
829   row->pair = pair;
830   if (pair)
831     {
832       g_object_ref(pair);
833       row->links_sig = g_signal_connect_swapped(G_OBJECT(pair), "notify::links",
834                                                 G_CALLBACK(onLinksNotified), ref);
835     }
836   gtk_tree_store_set(store, iter, COL_SIGNALS, row, -1);
837 }
onPairsNotified(VisuPairSet * set,GParamSpec * pspec _U_,VisuUiPairTree * tree)838 static void onPairsNotified(VisuPairSet *set, GParamSpec *pspec _U_,
839                             VisuUiPairTree *tree)
840 {
841   guint i, j;
842   GtkTreeIter iter, child;
843   VisuPair *pair;
844   VisuPairLink *link;
845 
846   DBG_fprintf(stderr, "Ui PairTree: (onPairsNotified) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count);
847   gtk_tree_store_clear(GTK_TREE_STORE(tree->priv->treemodel));
848   i = 0;
849   while ((pair = visu_pair_set_getNthPair(set, i++)))
850     {
851       j = 0;
852       link = visu_pair_getNthLink(pair, j++);
853       _addLink(GTK_TREE_STORE(tree->priv->treemodel), &iter, (GtkTreeIter*)0, pair, link);
854       while ((link = visu_pair_getNthLink(pair, j++)))
855         _addLink(GTK_TREE_STORE(tree->priv->treemodel), &child, &iter, (VisuPair*)0, link);
856     };
857   DBG_fprintf(stderr, "Ui PairTree: (onPairsNotified) model has %d ref counts.\n", G_OBJECT(tree->priv->treemodel)->ref_count);
858 }
onDrawnToggled(GtkCellRendererToggle * cell_renderer,gchar * path,VisuUiPairTree * self)859 static void onDrawnToggled(GtkCellRendererToggle *cell_renderer,
860                            gchar *path, VisuUiPairTree *self)
861 {
862   GtkTreeIter iter;
863   VisuPairLink *link;
864 
865   gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path);
866   gtk_tree_model_get(self->priv->sortmodel, &iter, POINTER_TO_LINK, &link, -1);
867   visu_pair_link_setDrawn(link, !gtk_cell_renderer_toggle_get_active(cell_renderer));
868   g_object_unref(G_OBJECT(link));
869 }
_changeDistance(VisuUiPairTree * self,const gchar * text,GtkTreeIter * iter,VisuPairLinkDistances at)870 static void _changeDistance(VisuUiPairTree *self, const gchar *text, GtkTreeIter *iter,
871                             VisuPairLinkDistances at)
872 {
873   float value;
874   char *error;
875   GtkTreePath *_path;
876   VisuPairLink *link;
877 
878   value = (float)strtod(text, &error);
879   if ((value == 0.f && error == text) || value < 0.f)
880     {
881       _path = gtk_tree_model_get_path(self->priv->sortmodel, iter);
882       gtk_tree_model_row_changed(self->priv->sortmodel, _path, iter);
883       gtk_tree_path_free(_path);
884     }
885   else
886     {
887       gtk_tree_model_get(self->priv->sortmodel, iter, POINTER_TO_LINK, &link, -1);
888       visu_pair_link_setDistance(link, value, at);
889       g_object_unref(G_OBJECT(link));
890     }
891 }
onDistanceMinEdited(GtkCellRendererText * cellrenderertext _U_,gchar * path,gchar * text,VisuUiPairTree * self)892 static void onDistanceMinEdited(GtkCellRendererText *cellrenderertext _U_,
893                                 gchar *path, gchar *text, VisuUiPairTree *self)
894 {
895   GtkTreeIter iter;
896 
897   gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path);
898   _changeDistance(self, text, &iter, VISU_DISTANCE_MIN);
899 }
onDistanceMaxEdited(GtkCellRendererText * cellrenderertext _U_,gchar * path,gchar * text,VisuUiPairTree * self)900 static void onDistanceMaxEdited(GtkCellRendererText *cellrenderertext _U_,
901                                 gchar *path, gchar *text, VisuUiPairTree *self)
902 {
903   GtkTreeIter iter;
904 
905   gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path);
906   _changeDistance(self, text, &iter, VISU_DISTANCE_MAX);
907 }
onLengthToggled(GtkCellRendererToggle * cell_renderer,gchar * path,VisuUiPairTree * self)908 static void onLengthToggled(GtkCellRendererToggle *cell_renderer,
909                             gchar *path, VisuUiPairTree *self)
910 {
911   GtkTreeIter iter;
912   VisuPairLink *link;
913 
914   gtk_tree_model_get_iter_from_string(self->priv->sortmodel, &iter, path);
915   gtk_tree_model_get(self->priv->sortmodel, &iter, POINTER_TO_LINK, &link, -1);
916   visu_pair_link_setPrintLength(link, !gtk_cell_renderer_toggle_get_active(cell_renderer));
917   g_object_unref(G_OBJECT(link));
918 }
onSelectionChanged(VisuUiPairTree * self,GtkTreeSelection * selection)919 static void onSelectionChanged(VisuUiPairTree *self, GtkTreeSelection *selection)
920 {
921   GList *rows;
922   GtkTreeModel *model;
923   GtkTreeIter iter;
924   GList *it, *links;
925   VisuPairLink *link;
926 
927   if (self->priv->selectedLink)
928     g_object_unref(self->priv->selectedLink);
929 
930   rows = it = gtk_tree_selection_get_selected_rows(selection, &model);
931 
932   self->priv->selectedLink = (VisuPairLink*)0;
933   if (rows && gtk_tree_model_get_iter(model, &iter, (GtkTreePath*)rows->data))
934     gtk_tree_model_get(model, &iter, POINTER_TO_LINK, &self->priv->selectedLink, -1);
935 
936   g_object_notify_by_pspec(G_OBJECT(self), _properties[LINK_PROP]);
937 
938   links = (GList*)0;
939   while (it && gtk_tree_model_get_iter(model, &iter, (GtkTreePath*)it->data))
940     {
941       gtk_tree_model_get(model, &iter, POINTER_TO_LINK, &link, -1);
942       links = g_list_prepend(links, link);
943       it = g_list_next(it);
944     }
945   g_signal_emit(G_OBJECT(self), _signals[SEL_SIGNAL], 0, links);
946   g_list_free_full(links, (GDestroyNotify)g_object_unref);
947 
948   g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free);
949 }
onLinkNotified(GtkTreeRowReference * ref,GParamSpec * pspec _U_,VisuPairLink * link _U_)950 static void onLinkNotified(GtkTreeRowReference *ref, GParamSpec *pspec _U_, VisuPairLink *link _U_)
951 {
952   GtkTreeModel *model;
953   GtkTreePath *path;
954   GtkTreeIter iter;
955 
956   model = gtk_tree_row_reference_get_model(ref);
957   path = gtk_tree_row_reference_get_path(ref);
958 
959   g_return_if_fail(gtk_tree_model_get_iter(model, &iter, path));
960 
961   gtk_tree_model_row_changed(model, path, &iter);
962 
963   gtk_tree_path_free(path);
964 }
onLinksNotified(GtkTreeRowReference * ref,GParamSpec * pspec _U_,VisuPair * pair)965 static void onLinksNotified(GtkTreeRowReference *ref, GParamSpec *pspec _U_, VisuPair *pair)
966 {
967   GtkTreeStore *model;
968   GtkTreePath *path;
969   GtkTreeIter iter, child;
970   guint j;
971   VisuPairLink *link;
972 
973   model = GTK_TREE_STORE(gtk_tree_row_reference_get_model(ref));
974   path = gtk_tree_row_reference_get_path(ref);
975 
976   g_return_if_fail(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path));
977 
978   gtk_tree_store_remove(model, &iter);
979 
980   gtk_tree_path_free(path);
981 
982   j = 0;
983   link = visu_pair_getNthLink(pair, j++);
984   _addLink(model, &iter, (GtkTreeIter*)0, pair, link);
985   while ((link = visu_pair_getNthLink(pair, j++)))
986     _addLink(model, &child, &iter, (VisuPair*)0, link);
987 }
988 
989 /**
990  * visu_ui_pair_tree_getToolbar:
991  * @tree: a #VisuUiPairTree object.
992  *
993  * Creates a #GtkToolbar with the action button used to add or remove
994  * #VisuPairLink in a @tree.
995  *
996  * Since: 3.8
997  *
998  * Returns: (transfer none): a #GtkToolbar object.
999  **/
visu_ui_pair_tree_getToolbar(VisuUiPairTree * tree)1000 GtkWidget* visu_ui_pair_tree_getToolbar(VisuUiPairTree *tree)
1001 {
1002   GtkToolItem *item;
1003   GtkWidget *wd;
1004 
1005   g_return_val_if_fail(VISU_IS_UI_PAIR_TREE(tree), (GtkWidget*)0);
1006 
1007   if (tree->priv->toolbar)
1008     return tree->priv->toolbar;
1009 
1010   tree->priv->toolbar = gtk_vbox_new(FALSE, 0);
1011 
1012 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5
1013   wd = gtk_label_new(_("Manage links: "));
1014   gtk_label_set_angle(GTK_LABEL(wd), 90.);
1015   gtk_box_pack_end(GTK_BOX(tree->priv->toolbar), wd, FALSE, FALSE, 0);
1016 #endif
1017 
1018   wd = gtk_toolbar_new();
1019   gtk_box_pack_start(GTK_BOX(tree->priv->toolbar), wd, TRUE, TRUE, 0);
1020   gtk_orientable_set_orientation(GTK_ORIENTABLE(wd),
1021                                  GTK_ORIENTATION_VERTICAL);
1022   gtk_toolbar_set_style(GTK_TOOLBAR(wd), GTK_TOOLBAR_ICONS);
1023   gtk_toolbar_set_icon_size(GTK_TOOLBAR(wd), GTK_ICON_SIZE_SMALL_TOOLBAR);
1024 
1025   item = gtk_toggle_tool_button_new();
1026   gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "edit-find");
1027   g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(onFilter), (gpointer)tree);
1028   gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1);
1029   gtk_tool_item_set_tooltip_text(item, _("Show/hide the undrawn pairs."));
1030   tree->priv->hideBt = item;
1031 
1032   item = gtk_tool_button_new(NULL, NULL);
1033   g_object_bind_property(tree, "selected-link", item, "sensitive", G_BINDING_SYNC_CREATE);
1034   gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-add");
1035   g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(onAdd), (gpointer)tree);
1036   gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1);
1037   item = gtk_tool_button_new(NULL, NULL);
1038   g_object_bind_property(tree, "selected-link", item, "sensitive", G_BINDING_SYNC_CREATE);
1039   gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "list-remove");
1040   g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(onRemove), (gpointer)tree);
1041   gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1);
1042 
1043   gtk_widget_show_all(tree->priv->toolbar);
1044 
1045   return g_object_ref(tree->priv->toolbar);
1046 }
onAdd(VisuUiPairTree * tree,GtkButton * button _U_)1047 static void onAdd(VisuUiPairTree *tree, GtkButton *button _U_)
1048 {
1049   VisuPair *pair;
1050   gfloat zeros[2] = {0.f, 0.f};
1051   VisuPairLink *link;
1052 
1053   pair = visu_pair_set_getFromLink(tree->priv->model, tree->priv->selectedLink);
1054   link = visu_pair_addLink(pair, zeros);
1055   _expandLink(tree, link);
1056   _selectLink(tree, link);
1057 }
onRemove(VisuUiPairTree * tree,GtkButton * button _U_)1058 static void onRemove(VisuUiPairTree *tree, GtkButton *button _U_)
1059 {
1060   VisuPair *pair;
1061 
1062   pair = visu_pair_set_getFromLink(tree->priv->model, tree->priv->selectedLink);
1063   visu_pair_removeLink(pair, tree->priv->selectedLink);
1064   _selectPair(tree, pair);
1065 }
onFilter(VisuUiPairTree * tree,GtkButton * button _U_)1066 static void onFilter(VisuUiPairTree *tree, GtkButton *button _U_)
1067 {
1068   gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(tree->priv->filtermodel));
1069 }
1070 
1071 /**
1072  * visu_ui_pair_tree_getFilter:
1073  * @tree: a #VisuUiPairTree object.
1074  *
1075  * Creates a #VisuElement combo widget to be used to filter the list
1076  * of pairs.
1077  *
1078  * Since: 3.8
1079  *
1080  * Returns: (transfer none): a #VisuUiElementCombobox object.
1081  **/
visu_ui_pair_tree_getFilter(VisuUiPairTree * tree)1082 GtkWidget* visu_ui_pair_tree_getFilter(VisuUiPairTree *tree)
1083 {
1084 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11
1085   GList *lst;
1086 #endif
1087 
1088   g_return_val_if_fail(VISU_IS_UI_PAIR_TREE(tree), (GtkWidget*)0);
1089 
1090   if (tree->priv->filter)
1091     return tree->priv->filter;
1092 
1093   tree->priv->filter = visu_ui_element_combobox_new(FALSE, TRUE, (const gchar*)0);
1094   g_signal_connect(tree->priv->filter, "destroy",
1095                    G_CALLBACK(gtk_widget_destroyed), &tree->priv->filter);
1096 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11
1097   lst = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(tree->priv->filter));
1098   if (lst)
1099     {
1100       g_object_set(G_OBJECT(lst->data), "scale", 0.75, NULL);
1101       g_list_free(lst);
1102     }
1103 #endif
1104   if (tree->priv->model)
1105     tree->priv->model_bind =
1106       g_object_bind_property(tree->priv->model, "data", tree->priv->filter, "nodes",
1107                              G_BINDING_SYNC_CREATE);
1108   g_signal_connect_swapped(G_OBJECT(tree->priv->filter), "element-selected",
1109                            G_CALLBACK(onFilterChanged), (gpointer)tree);
1110 
1111   return g_object_ref(tree->priv->filter);
1112 }
onFilterChanged(VisuUiPairTree * tree,GList * elements _U_,VisuUiElementCombobox * combobox _U_)1113 static void onFilterChanged(VisuUiPairTree *tree, GList *elements _U_,
1114                             VisuUiElementCombobox *combobox _U_)
1115 {
1116   gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(tree->priv->filtermodel));
1117 }
1118 
_expandLink(VisuUiPairTree * tree,VisuPairLink * link)1119 static void _expandLink(VisuUiPairTree *tree, VisuPairLink *link)
1120 {
1121   gboolean valid;
1122   GtkTreeIter iter;
1123   RowLink *row;
1124   GtkTreePath *path;
1125 
1126   for (valid = gtk_tree_model_get_iter_first(tree->priv->sortmodel, &iter);
1127        valid; valid = gtk_tree_model_iter_next(tree->priv->sortmodel, &iter))
1128     {
1129       gtk_tree_model_get(tree->priv->sortmodel, &iter, COL_SIGNALS, &row, -1);
1130       if (visu_pair_contains(row->pair, link))
1131         {
1132           g_boxed_free(TYPE_ROW_LINK, row);
1133           path = gtk_tree_model_get_path(tree->priv->sortmodel, &iter);
1134           gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, TRUE);
1135           gtk_tree_path_free(path);
1136           return;
1137         }
1138       g_boxed_free(TYPE_ROW_LINK, row);
1139     }
1140 }
_selectLinkAt(VisuUiPairTree * tree,VisuPairLink * link,GtkTreeIter * at)1141 static gboolean _selectLinkAt(VisuUiPairTree *tree, VisuPairLink *link, GtkTreeIter *at)
1142 {
1143   RowLink *row;
1144 
1145   gtk_tree_model_get(tree->priv->sortmodel, at, COL_SIGNALS, &row, -1);
1146   if (row->link == link)
1147     {
1148       g_boxed_free(TYPE_ROW_LINK, row);
1149       gtk_tree_selection_select_iter
1150         (gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), at);
1151       return TRUE;
1152     }
1153   g_boxed_free(TYPE_ROW_LINK, row);
1154   return FALSE;
1155 }
_selectLink(VisuUiPairTree * tree,VisuPairLink * link)1156 static void _selectLink(VisuUiPairTree *tree, VisuPairLink *link)
1157 {
1158   gboolean valid, valid2;
1159   GtkTreeIter iter, child;
1160 
1161   gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)));
1162   for (valid = gtk_tree_model_get_iter_first(tree->priv->sortmodel, &iter);
1163        valid; valid = gtk_tree_model_iter_next(tree->priv->sortmodel, &iter))
1164     {
1165       if (_selectLinkAt(tree, link, &iter))
1166         return;
1167       for (valid2 = gtk_tree_model_iter_children(tree->priv->sortmodel, &child, &iter);
1168            valid2; valid2 = gtk_tree_model_iter_next(tree->priv->sortmodel, &child))
1169         if (_selectLinkAt(tree, link, &child))
1170           return;
1171     }
1172 }
_selectPair(VisuUiPairTree * tree,VisuPair * pair)1173 static void _selectPair(VisuUiPairTree *tree, VisuPair *pair)
1174 {
1175   gboolean valid;
1176   GtkTreeIter iter;
1177   RowLink *row;
1178 
1179   gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)));
1180   for (valid = gtk_tree_model_get_iter_first(tree->priv->sortmodel, &iter);
1181        valid; valid = gtk_tree_model_iter_next(tree->priv->sortmodel, &iter))
1182     {
1183       gtk_tree_model_get(tree->priv->sortmodel, &iter, COL_SIGNALS, &row, -1);
1184       if (row->pair == pair)
1185         {
1186           g_boxed_free(TYPE_ROW_LINK, row);
1187           gtk_tree_selection_select_iter
1188             (gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), &iter);
1189           return;
1190         }
1191       g_boxed_free(TYPE_ROW_LINK, row);
1192     }
1193 }
1194