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