1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Luc BILLARD et Damien
3 	CALISTE, laboratoire L_Sim, (2001-2005)
4 
5 	Adresse mèl :
6 	BILLARD, non joignable par mèl ;
7 	CALISTE, damien P caliste AT cea P fr.
8 
9 	Ce logiciel est un programme informatique servant à visualiser des
10 	structures atomiques dans un rendu pseudo-3D.
11 
12 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
13 	respectant les principes de diffusion des logiciels libres. Vous pouvez
14 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
15 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16 	sur le site "http://www.cecill.info".
17 
18 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22 
23 /*   LICENCE SUM UP
24 	Copyright CEA, contributors : Luc BILLARD et Damien
25 	CALISTE, laboratoire L_Sim, (2001-2005)
26 
27 	E-mail address:
28 	BILLARD, not reachable any more ;
29 	CALISTE, damien P caliste AT cea P fr.
30 
31 	This software is a computer program whose purpose is to visualize atomic
32 	configurations in 3D.
33 
34 	This software is governed by the CeCILL  license under French law and
35 	abiding by the rules of distribution of free software.  You can  use,
36 	modify and/ or redistribute the software under the terms of the CeCILL
37 	license as circulated by CEA, CNRS and INRIA at the following URL
38 	"http://www.cecill.info".
39 
40 	The fact that you are presently reading this means that you have had
41 	knowledge of the CeCILL license and that you accept its terms. You can
42 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 
45 #include <gdk/gdkkeysyms.h>
46 #include <gtk/gtk.h>
47 #include <math.h>
48 #include <string.h>
49 
50 #include "support.h"
51 #include "gtk_interactive.h"
52 #include "visu_gtk.h"
53 #include "gtk_main.h"
54 #include "gtk_pick.h"
55 #include "visu_basic.h"
56 #include "gtk_renderingWindowWidget.h"
57 #include "extensions/infos.h"
58 #include "extensions/marks.h"
59 #include "extraFunctions/idProp.h"
60 #include "openGLFunctions/interactive.h"
61 #include "extraGtkFunctions/gtk_valueIOWidget.h"
62 #include "uiElements/ui_properties.h"
63 
64 /**
65  * SECTION: gtk_pick
66  * @short_description: The pick and measurement tab in the interactive
67  * dialog.
68  *
69  * <para>This action tab provides widgets to display information about
70  * selected atoms, like distances or angles. In addition, measured
71  * distances and angles are kept in a list when new files are
72  * loaded.</para>
73  * <para>With the list of selected nodes, one can modify properties
74  * associated to nodes like their coordinates, the value of
75  * colourisation if any, the forces on them, if any... One can also
76  * decide to display information directly on nodes.</para>
77  */
78 
79 #define GTK_PICK_INFO				\
80   _("left-button\t\t\t: standard pick\n"			\
81     "control-left-button\t\t: toggle highlihgt node\n"		\
82     "middle-button\t\t: measure node neighbouring\n"		\
83     "shift-middle-button\t: pick 1st reference\n"		\
84     "ctrl-middle-button\t\t: pick 2nd reference\n"		\
85     "drag-left-button\t\t: make a rectangular selection\n"	\
86     "right-button\t\t\t: switch to observe")
87 
88 /* Treeview used to print data of nodes. */
89 static VisuUiSelection *listPickedNodes;
90 static GtkWidget *treeviewPickedNodes, *labelSelection;
91 #define GTK_PICK_EDITABLE_NODE   "blue"
92 #define GTK_PICK_UNEDITABLE_NODE "black"
93 
94 /* Draw data widgets. */
95 static GtkWidget *tglMarks;
96 static VisuInteractive *interPick = NULL;
97 
98 /* The pick viewport. */
99 static GtkWidget *labelPickOut, *labelPickHistory = (GtkWidget*)0, *labelPickError;
100 struct _PickHistory
101 {
102   VisuData *dataObj;
103   gchar *str;
104 };
105 static GList *pickHistory = (GList*)0;
106 
107 /* Signals that need to be suspended */
108 static VisuData *currentData;
109 static gulong propAdd_signal, propRemoved_signal;
110 
111 /* Local callbacks. */
112 static void onEditedValue(GtkCellRendererText *cellrenderertext,
113                           gchar *path, gchar *text, gpointer user_data);
114 static void onDrawDistanceChecked(GtkToggleButton* button, gpointer data);
115 static void onEraseDistanceClicked(GtkButton *button, gpointer user_data);
116 static gboolean onTreeviewInfosKey(GtkWidget *widget, GdkEventKey *event,
117 				   gpointer user_data);
118 static void onHighlightHideToggled(GtkToggleButton *button, gpointer user_data);
119 static void onHighlightHideStatus(GtkButton *button, gpointer user_data);
120 static void onNodeSelection(VisuInteractive *inter, VisuInteractivePick pick,
121 			    VisuData *dataObj, VisuNode *node0, VisuNode *node1,
122                             VisuNode *node2, gpointer data);
123 static void onSelectionError(VisuInteractive *inter, VisuInteractivePickError error,
124 			     gpointer data);
125 static void onMeasurementList(VisuGlExtMarks *marks, VisuData *dataObj, gpointer data);
126 static void onNodeValueChanged(VisuNodeValues *values, VisuNode *node);
127 static void onDataNotify(VisuGlNodeScene *scene);
128 
129 /* Local routines. */
130 static void _setData(VisuData *dataObj);
131 static gboolean onLoadXML(const gchar *filename, GError **error);
132 static gboolean onSaveXML(const gchar *filename, GError **error);
133 static void _addColumn(GtkTreeView *view, VisuNodeValues *prop);
134 static void _removeColumn(GtkTreeView *view, VisuNodeValues *prop);
135 static void _togglePath(VisuUiSelection *selection, gchar *path);
136 
137 /********************/
138 /* Public routines. */
139 /********************/
140 /**
141  * visu_ui_interactive_pick_init: (skip)
142  *
143  * Internal routine to setup the pick action of the interactive dialog.
144  *
145  * Since: 3.6
146  */
visu_ui_interactive_pick_init()147 void visu_ui_interactive_pick_init()
148 {
149   listPickedNodes = visu_ui_selection_new();
150   labelSelection = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
151   currentData = (VisuData*)0;
152 }
_haveNodes(GBinding * bind _U_,const GValue * from,GValue * to,gpointer data _U_)153 static gboolean _haveNodes(GBinding *bind _U_, const GValue *from,
154                            GValue *to, gpointer data _U_)
155 {
156   GArray *ids;
157 
158   ids = (GArray*)g_value_get_boxed(from);
159   g_value_set_boolean(to, ids && ids->len > 0);
160   return TRUE;
161 }
_toLblMarks(GBinding * bind _U_,const GValue * from,GValue * to,gpointer data _U_)162 static gboolean _toLblMarks(GBinding *bind _U_, const GValue *from,
163                             GValue *to, gpointer data _U_)
164 {
165   GArray *ids;
166 
167   ids = (GArray*)g_value_get_boxed(from);
168   if (ids && ids->len)
169     g_value_take_string(to, g_strdup_printf(_("Highlights <span size=\"small\">(%d)</span>:"), ids->len));
170   else
171     g_value_set_string(to, _("Highlights <span size=\"small\">(none)</span>:"));
172   return TRUE;
173 }
_toLblList(GBinding * bind,const GValue * from _U_,GValue * to,gpointer data _U_)174 static gboolean _toLblList(GBinding *bind, const GValue *from _U_,
175                            GValue *to, gpointer data _U_)
176 {
177   gint n;
178 
179   n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(g_binding_get_source(bind)), NULL);
180   if (n > 0)
181     g_value_take_string(to, g_strdup_printf(_("<b>List of %d node(s):</b>"), n));
182   else
183     g_value_set_string(to, _("<b>List of nodes <span size="
184                              "\"small\">(none)</span>:</b>"));
185   return TRUE;
186 }
_toDrawSelected(GBinding * bind,const GValue * from,GValue * to,gpointer data _U_)187 static gboolean _toDrawSelected(GBinding *bind, const GValue *from,
188                                 GValue *to, gpointer data _U_)
189 {
190   GArray *nodes = g_value_get_boxed(from);
191   g_value_set_boolean(to, (nodes && nodes->len) && visu_gl_ext_getActive(VISU_GL_EXT(g_binding_get_source(bind))));
192   return g_value_get_boolean(to);
193 }
_fromDrawSelected(GBinding * bind _U_,const GValue * from,GValue * to,gpointer data)194 static gboolean _fromDrawSelected(GBinding *bind _U_, const GValue *from,
195                                   GValue *to, gpointer data)
196 {
197   if (g_value_get_boolean(from))
198     g_value_take_boxed(to, visu_ui_selection_get(VISU_UI_SELECTION(data)));
199   return g_value_get_boolean(from);
200 }
_toDrawAlways(GBinding * bind,const GValue * from,GValue * to,gpointer data _U_)201 static gboolean _toDrawAlways(GBinding *bind, const GValue *from,
202                               GValue *to, gpointer data _U_)
203 {
204   GArray *nodes = g_value_get_boxed(from);
205   g_value_set_boolean(to, (!nodes || !nodes->len) && visu_gl_ext_getActive(VISU_GL_EXT(g_binding_get_source(bind))));
206   return g_value_get_boolean(to);
207 }
_fromDrawAlways(GBinding * bind _U_,const GValue * from,GValue * to,gpointer data _U_)208 static gboolean _fromDrawAlways(GBinding *bind _U_, const GValue *from,
209                                 GValue *to, gpointer data _U_)
210 {
211   if (g_value_get_boolean(from))
212     g_value_take_boxed(to, (gpointer)0);
213   return g_value_get_boolean(from);
214 }
_toSelection(GBinding * bind _U_,const GValue * from,GValue * to,gpointer data)215 static gboolean _toSelection(GBinding *bind _U_, const GValue *from,
216                              GValue *to, gpointer data)
217 {
218   if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data)))
219     return FALSE;
220   g_value_set_boxed(to, g_value_get_boxed(from));
221   return TRUE;
222 }
223 
224 /**
225  * visu_ui_interactive_pick_initBuild: (skip)
226  * @main: the main interface.
227  * @label: a location to store the name of the pick tab ;
228  * @help: a location to store the help message to be shown at the
229  * bottom of the window ;
230  * @radio: a location on the radio button that will be toggled when
231  * the pick action is used.
232  *
233  * This routine should be called in conjonction to the
234  * visu_ui_interactive_move_initBuild() one. It completes the creation of widgets
235  * (and also initialisation of values) for the pick tab.
236  */
visu_ui_interactive_pick_initBuild(VisuUiMain * main,gchar ** label,gchar ** help,GtkWidget ** radio)237 GtkWidget* visu_ui_interactive_pick_initBuild(VisuUiMain *main, gchar **label,
238                                               gchar **help, GtkWidget **radio)
239 {
240   GtkTreeViewColumn *column;
241   GtkCellRenderer *renderer;
242   GtkWidget *lbl, *wd, *wd2, *hbox, *vbox, *image;
243   GtkWidget *valueIO, *hboxMarks, *comboDraw;
244   GtkWidget *radioDrawNever, *radioDrawSelected, *radioDrawAlways;
245   GSList *radioDrawNever_group = NULL;
246   GtkToolItem *item;
247   VisuUiRenderingWindow *window;
248   VisuGlExtMarks *marks;
249   VisuGlExtInfos *infos;
250   VisuGlNodeScene *scene;
251 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12
252   GtkTooltips *tooltips;
253   tooltips = gtk_tooltips_new ();
254 #endif
255 
256   DBG_fprintf(stderr, "Gtk Pick: setup new action tab.\n");
257   window = visu_ui_main_class_getDefaultRendering();
258   interPick = visu_interactive_new(interactive_measure);
259 
260   scene = visu_ui_rendering_window_getGlScene(window);
261   g_signal_connect(G_OBJECT(interPick), "node-selection",
262 		   G_CALLBACK(onNodeSelection), (gpointer)0);
263   g_signal_connect(G_OBJECT(interPick), "selection-error",
264 		   G_CALLBACK(onSelectionError), (gpointer)0);
265   g_signal_connect_swapped(G_OBJECT(interPick), "region-selection",
266                            G_CALLBACK(visu_ui_selection_append), listPickedNodes);
267   g_signal_connect(G_OBJECT(interPick), "stop",
268 		   G_CALLBACK(visu_ui_interactive_toggle), (gpointer)0);
269   marks = visu_gl_node_scene_getMarks(scene);
270   infos = visu_gl_node_scene_getInfos(scene);
271   g_signal_connect(G_OBJECT(marks), "measurementChanged",
272                    G_CALLBACK(onMeasurementList), (gpointer)0);
273 
274   *label = g_strdup("Pick");
275   *help  = g_strdup(GTK_PICK_INFO);
276   *radio = lookup_widget(main->interactiveDialog, "radioPick");
277 
278   vbox = lookup_widget(main->interactiveDialog, "vbox25");
279 
280   hbox = gtk_hbox_new(FALSE, 0);
281   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
282 
283   lbl = gtk_label_new("");
284   gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
285   gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE);
286   g_object_bind_property_full(listPickedNodes, "selection", lbl, "label",
287                               G_BINDING_SYNC_CREATE, _toLblList, NULL,
288                               (gpointer)0, (GDestroyNotify)0);
289 
290   gtk_box_pack_start(GTK_BOX(hbox), labelSelection, TRUE, TRUE, 0);
291 
292   lbl = gtk_label_new(_("<span size=\"smaller\">Values in <span color=\"blue\">blue</span> are editable</span>"));
293   gtk_box_pack_end(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
294   gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE);
295 
296   image = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU);
297   gtk_box_pack_end(GTK_BOX(hbox), image, FALSE, FALSE, 0);
298   gtk_widget_set_margin_end(image, 3);
299 
300   /* Create the treeview and related buttons. */
301   DBG_fprintf(stderr, "Gtk Pick: Create the treeview and related buttons.\n");
302   hbox = gtk_hbox_new(FALSE, 0);
303   gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
304 
305   g_signal_connect_swapped(hbox, "destroy", G_CALLBACK(g_object_unref), interPick);
306 
307   wd = gtk_scrolled_window_new(NULL, NULL);
308   gtk_widget_set_size_request(wd, -1, 120);
309   gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 0);
310   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(wd),
311 				 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
312   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(wd), GTK_SHADOW_IN);
313 
314   treeviewPickedNodes = gtk_tree_view_new ();
315   gtk_container_add(GTK_CONTAINER(wd), treeviewPickedNodes);
316   gtk_tree_view_set_model(GTK_TREE_VIEW(treeviewPickedNodes),
317 			  GTK_TREE_MODEL(listPickedNodes));
318   g_object_unref(listPickedNodes);
319   g_signal_connect(G_OBJECT(treeviewPickedNodes), "key-press-event",
320 		   G_CALLBACK(onTreeviewInfosKey), (gpointer)0);
321   gtk_tree_selection_set_mode
322     (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeviewPickedNodes)),
323      GTK_SELECTION_MULTIPLE);
324 
325   wd = gtk_toolbar_new();
326   gtk_orientable_set_orientation(GTK_ORIENTABLE(wd), GTK_ORIENTATION_VERTICAL);
327   gtk_toolbar_set_style(GTK_TOOLBAR(wd), GTK_TOOLBAR_ICONS);
328   gtk_toolbar_set_icon_size(GTK_TOOLBAR(wd), GTK_ICON_SIZE_SMALL_TOOLBAR);
329   gtk_box_pack_end(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
330 
331   item = gtk_toggle_tool_button_new();
332   gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Set / unset highlight status following selection."));
333   gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1);
334   gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item),
335                                   create_pixmap((GtkWidget*)0, "stock-select-all_20.png"));
336   g_object_bind_property(listPickedNodes, "highlight", item, "active",
337                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
338 
339   item = gtk_tool_button_new(NULL, NULL);
340   gtk_widget_set_tooltip_text(GTK_WIDGET(item), _("Empty the selection list."));
341   gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "edit-clear");
342   g_signal_connect_swapped(G_OBJECT(item), "clicked",
343                            G_CALLBACK(visu_ui_selection_clear), listPickedNodes);
344   gtk_toolbar_insert(GTK_TOOLBAR(wd), item, -1);
345 
346   lbl = gtk_label_new(_("<b>Draw data on nodes</b>"));
347   gtk_box_pack_start(GTK_BOX(vbox), lbl, FALSE, FALSE, 0);
348   gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE);
349   gtk_label_set_xalign(GTK_LABEL(lbl), 0);
350 
351   hbox = gtk_hbox_new(FALSE, 0);
352   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
353 
354   radioDrawNever = gtk_radio_button_new_with_mnemonic(NULL, _("none"));
355   g_object_bind_property(infos, "active", radioDrawNever, "active",
356                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL | G_BINDING_INVERT_BOOLEAN);
357   gtk_widget_set_name(radioDrawNever, "message_radio");
358   gtk_box_pack_start(GTK_BOX(hbox), radioDrawNever, FALSE, FALSE, 0);
359   gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioDrawNever), radioDrawNever_group);
360   radioDrawNever_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioDrawNever));
361 
362   radioDrawSelected = gtk_radio_button_new_with_mnemonic(NULL, _("listed"));
363   gtk_widget_set_name(radioDrawSelected, "message_radio");
364   g_object_bind_property_full(infos, "selection", radioDrawSelected, "active",
365                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
366                               _toDrawSelected, _fromDrawSelected,
367                               listPickedNodes, (GDestroyNotify)0);
368   g_object_bind_property_full(listPickedNodes, "selection",
369                               radioDrawSelected, "sensitive",
370                               G_BINDING_SYNC_CREATE,
371                               _haveNodes, NULL, (gpointer)0, (GDestroyNotify)0);
372   gtk_box_pack_start(GTK_BOX(hbox), radioDrawSelected, FALSE, FALSE, 0);
373   gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioDrawSelected), radioDrawNever_group);
374   radioDrawNever_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioDrawSelected));
375 
376   radioDrawAlways = gtk_radio_button_new_with_mnemonic (NULL, _("all"));
377   gtk_widget_set_name(radioDrawAlways, "message_radio");
378   g_object_bind_property_full(infos, "selection", radioDrawAlways, "active",
379                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
380                               _toDrawAlways, _fromDrawAlways,
381                               (gpointer)0, (GDestroyNotify)0);
382   gtk_box_pack_start(GTK_BOX(hbox), radioDrawAlways, TRUE, TRUE, 0);
383   gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioDrawAlways), radioDrawNever_group);
384   radioDrawNever_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioDrawAlways));
385 
386   comboDraw = visu_ui_combo_values_new();
387   gtk_widget_show(comboDraw);
388   gtk_box_pack_start(GTK_BOX(hbox), comboDraw, TRUE, TRUE, 0);
389   g_object_bind_property(scene, "data", comboDraw, "model",
390                          G_BINDING_SYNC_CREATE);
391   g_object_bind_property(infos, "values", comboDraw, "active-values",
392                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
393 
394   gtk_widget_show_all(vbox);
395 
396   /* Building headers. */
397   DBG_fprintf(stderr, "Gtk Pick: Build the tree view.\n");
398   /* Highlight colum. */
399   renderer = gtk_cell_renderer_toggle_new();
400   g_signal_connect_swapped(G_OBJECT(renderer), "toggled",
401                            G_CALLBACK(_togglePath), listPickedNodes);
402   g_object_set(G_OBJECT(renderer), "indicator-size", 10, NULL);
403   column = gtk_tree_view_column_new_with_attributes("", renderer,
404 						    "active", VISU_UI_SELECTION_HIGHLIGHT,
405 						    NULL);
406   gtk_tree_view_column_set_sort_column_id(column, VISU_UI_SELECTION_HIGHLIGHT);
407   gtk_tree_view_append_column (GTK_TREE_VIEW(treeviewPickedNodes), column);
408 
409   /* Set the load/save widget. */
410   DBG_fprintf(stderr, "Gtk Pick: Add some widgets.\n");
411   valueIO = visu_ui_value_io_new(GTK_WINDOW(main->interactiveDialog),
412                                  _("Import picked nodes from an existing XML file."),
413                                  _("Export listed picked nodes to the current XML file."),
414                                  _("Export listed picked nodes to a new XML file."));
415   visu_ui_value_io_setSensitiveOpen(VISU_UI_VALUE_IO(valueIO), TRUE);
416   visu_ui_value_io_connectOnOpen(VISU_UI_VALUE_IO(valueIO), onLoadXML);
417   visu_ui_value_io_connectOnSave(VISU_UI_VALUE_IO(valueIO), onSaveXML);
418   g_object_bind_property_full(listPickedNodes, "selection", valueIO, "sensitive-save",
419                               G_BINDING_SYNC_CREATE, _haveNodes, NULL,
420                               (gpointer)0, (GDestroyNotify)0);
421   gtk_widget_show_all(valueIO);
422   wd = lookup_widget(main->interactiveDialog, "hboxPick");
423   gtk_box_pack_end(GTK_BOX(wd), valueIO, TRUE, TRUE, 10);
424 
425   /* Set the names and load the widgets. */
426   labelPickOut = lookup_widget(main->interactiveDialog, "pickInfo");
427   labelPickHistory = gtk_label_new("");
428   gtk_widget_show(labelPickHistory);
429   gtk_box_pack_start(GTK_BOX(lookup_widget(main->interactiveDialog, "vbox24")),
430                      labelPickHistory, FALSE, FALSE, 0);
431   gtk_label_set_use_markup(GTK_LABEL(labelPickHistory), TRUE);
432   gtk_label_set_selectable(GTK_LABEL(labelPickHistory), TRUE);
433   gtk_widget_set_margin_start(labelPickHistory, 15);
434   labelPickError = lookup_widget(main->interactiveDialog, "pickComment");
435   gtk_widget_set_name(labelPickError, "label_error");
436   wd = lookup_widget(main->interactiveDialog, "viewportPick");
437   gtk_widget_set_name(wd, "message_viewport");
438   wd = lookup_widget(main->interactiveDialog, "checkDrawDistance");
439   gtk_widget_set_name(wd, "message_radio");
440   g_signal_connect(G_OBJECT(wd), "toggled",
441 		   G_CALLBACK(onDrawDistanceChecked), (gpointer)marks);
442   wd = lookup_widget(main->interactiveDialog, "buttonEraseDistances");
443   g_signal_connect(G_OBJECT(wd), "clicked",
444 		   G_CALLBACK(onEraseDistanceClicked), (gpointer)marks);
445   hboxMarks = lookup_widget(main->interactiveDialog, "hboxMarks");
446   g_object_bind_property_full(marks, "highlight", hboxMarks, "sensitive",
447                               G_BINDING_SYNC_CREATE, _haveNodes, NULL,
448                               (gpointer)0, (GDestroyNotify)0);
449   wd = lookup_widget(main->interactiveDialog, "buttonEraseMarks");
450   g_signal_connect_swapped(G_OBJECT(wd), "clicked",
451                            G_CALLBACK(visu_gl_ext_marks_unHighlight), (gpointer)marks);
452   wd = lookup_widget(main->interactiveDialog, "buttonSetMarks");
453   g_signal_connect_swapped(G_OBJECT(wd), "clicked",
454                            G_CALLBACK(visu_ui_selection_appendHighlightedNodes), listPickedNodes);
455   tglMarks = gtk_toggle_button_new();
456   gtk_widget_set_tooltip_text(tglMarks, _("Hide nodes depending on highlight status."));
457   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tglMarks),
458                                visu_gl_ext_marks_getHidingMode(marks) != HIDE_NONE);
459   image = create_pixmap((GtkWidget*)0, "stock-masking.png");
460   gtk_container_add(GTK_CONTAINER(tglMarks), image);
461   gtk_box_pack_start(GTK_BOX(hboxMarks), tglMarks, FALSE, FALSE, 0);
462   g_signal_connect(G_OBJECT(tglMarks), "toggled",
463 		   G_CALLBACK(onHighlightHideToggled), marks);
464   gtk_box_pack_start(GTK_BOX(hboxMarks), gtk_label_new("("), FALSE, FALSE, 0);
465   wd = gtk_radio_button_new_with_mnemonic((GSList*)0, _("_h."));
466   g_object_set_data(G_OBJECT(wd), "hiding-mode", GINT_TO_POINTER(HIDE_HIGHLIGHT));
467   if (visu_gl_ext_marks_getHidingMode(marks) == HIDE_HIGHLIGHT)
468     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE);
469   gtk_widget_set_tooltip_text(wd, _("Hide button will hide highlighted nodes."));
470   gtk_widget_set_name(wd, "message_radio");
471   gtk_box_pack_start(GTK_BOX(hboxMarks), wd, FALSE, FALSE, 0);
472   g_signal_connect(G_OBJECT(wd), "toggled",
473 		   G_CALLBACK(onHighlightHideStatus), marks);
474   wd2 = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(wd), _("_non-h."));
475   g_object_set_data(G_OBJECT(wd2), "hiding-mode", GINT_TO_POINTER(HIDE_NON_HIGHLIGHT));
476   if (visu_gl_ext_marks_getHidingMode(marks) == HIDE_NON_HIGHLIGHT)
477     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd2), TRUE);
478   gtk_widget_set_tooltip_text(wd2, _("Hide button will hide non-highlighted nodes."));
479   gtk_widget_set_name(wd2, "message_radio");
480   gtk_box_pack_start(GTK_BOX(hboxMarks), wd2, FALSE, FALSE, 0);
481   g_signal_connect(G_OBJECT(wd2), "toggled",
482 		   G_CALLBACK(onHighlightHideStatus), marks);
483   g_object_set_data(G_OBJECT(tglMarks), "hiding-mode", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wd)) ? GINT_TO_POINTER(HIDE_HIGHLIGHT) : GINT_TO_POINTER(HIDE_NON_HIGHLIGHT));
484   gtk_box_pack_start(GTK_BOX(hboxMarks), gtk_label_new(")"), FALSE, FALSE, 0);
485   lbl = lookup_widget(main->interactiveDialog, "labelMarks");
486   gtk_label_set_use_markup(GTK_LABEL(lbl), TRUE);
487   g_object_bind_property_full(marks, "highlight", lbl, "label",
488                               G_BINDING_SYNC_CREATE, _toLblMarks, NULL,
489                               (gpointer)0, (GDestroyNotify)0);
490   gtk_widget_show_all(hboxMarks);
491 
492   g_object_bind_property(scene, "data", listPickedNodes, "model",
493                          G_BINDING_SYNC_CREATE);
494   visu_ui_selection_setHighlightModel(listPickedNodes, marks);
495   g_object_bind_property_full(listPickedNodes, "selection", infos, "selection",
496                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
497                               _toSelection, _toSelection,
498                               g_object_ref(radioDrawSelected), (GDestroyNotify)g_object_unref);
499 
500   /* Get the current VisuData object. */
501   g_signal_connect_object(scene, "notify::data",
502                           G_CALLBACK(onDataNotify), treeviewPickedNodes, 0);
503   g_signal_connect_swapped(treeviewPickedNodes, "destroy",
504                            G_CALLBACK(_setData), (gpointer)0);
505   onDataNotify(scene);
506 
507   return (GtkWidget*)0;
508 }
509 /**
510  * visu_ui_interactive_pick_start:
511  * @window: a #VisuUiRenderingWindow object.
512  *
513  * Initialise a pick session.
514  */
visu_ui_interactive_pick_start(VisuUiRenderingWindow * window)515 void visu_ui_interactive_pick_start(VisuUiRenderingWindow *window)
516 {
517   VisuInteractive *inter;
518 
519   g_object_get(window, "interactive", &inter, NULL);
520   visu_ui_rendering_window_pushInteractive(window, interPick);
521   visu_interactive_setReferences(interPick, inter);
522   g_object_unref(inter);
523 }
524 /**
525  * visu_ui_interactive_pick_stop:
526  * @window: a #VisuUiRenderingWindow object.
527  *
528  * Finalise a pick session.
529  */
visu_ui_interactive_pick_stop(VisuUiRenderingWindow * window)530 void visu_ui_interactive_pick_stop(VisuUiRenderingWindow *window)
531 {
532   VisuInteractive *inter;
533 
534   visu_ui_rendering_window_popInteractive(window, interPick);
535   g_object_get(window, "interactive", &inter, NULL);
536   visu_interactive_setReferences(inter, interPick);
537   g_object_unref(inter);
538 }
onNodeSelection(VisuInteractive * inter _U_,VisuInteractivePick pick,VisuData * dataObj,VisuNode * node0,VisuNode * node1,VisuNode * node2,gpointer data _U_)539 static void onNodeSelection(VisuInteractive *inter _U_, VisuInteractivePick pick,
540 			    VisuData *dataObj, VisuNode *node0, VisuNode *node1,
541                             VisuNode *node2, gpointer data _U_)
542 {
543   gchar *errors;
544   GString *infos;
545   float posRef1[3], posRef2[3], posSelect[3];
546   double dx, dy, dz, dr, dx1, dy1, dz1, dr1,  dx2, dy2, dz2, dr2;
547   double ang;
548 
549   DBG_fprintf(stderr, "Gtk Pick: one measurement done (%d).\n", pick);
550 
551   gtk_tree_selection_unselect_all(gtk_tree_view_get_selection
552 				  (GTK_TREE_VIEW(treeviewPickedNodes)));
553 
554   /* Update the texts. */
555   infos  = g_string_new("");
556   errors = (gchar*)0;
557   if (pick == PICK_DISTANCE || pick == PICK_ANGLE ||
558       pick == PICK_REFERENCE_1 || pick == PICK_REFERENCE_2)
559     g_string_append_printf(infos,
560 			   _("Reference node\t"
561 			     " <span font_desc=\"monospace\"><b>#%d</b></span>\n"
562 			     "<span font_desc=\"monospace\" size=\"small\">"
563 			     "  ( x  = %7.3f ;  y  = %7.3f ;  z  = %7.3f)\n"
564 			     "</span>"),
565 			   node1->number + 1, node1->xyz[0],
566 			   node1->xyz[1],     node1->xyz[2]);
567   if (pick == PICK_ANGLE || pick == PICK_REFERENCE_2)
568     {
569       visu_data_getNodePosition(dataObj, node1, posRef1);
570       visu_data_getNodePosition(dataObj, node2, posRef2);
571       dx = posRef2[0] - posRef1[0];
572       dy = posRef2[1] - posRef1[1];
573       dz = posRef2[2] - posRef1[2];
574       dr = sqrt(dx*dx + dy*dy + dz*dz);
575       g_string_append_printf(infos,
576 			     _("2nd Reference node\t"
577 			       " <span font_desc=\"monospace\"><b>#%d</b>\t"
578 			       " (<i>i.e.</i> dr = %7.3f)</span>\n"
579 			       "<span font_desc=\"monospace\" size=\"small\">"
580 			       "  ( x  = %7.3f ;  y  = %7.3f ;  z  = %7.3f)\n"
581 			       "  (\316\264x  = %7.3f ; \316\264y  = %7.3f ; \316\264z  = %7.3f)\n"
582 			       "</span>"),
583 			     node2->number + 1, dr, node2->xyz[0],
584 			     node2->xyz[1], node2->xyz[2], dx, dy, dz);
585     }
586   if (pick == PICK_SELECTED)
587     g_string_append_printf(infos,
588 			   _("Newly picked node\t"
589 			     " <span font_desc=\"monospace\"><b>#%d</b></span>\n"
590 			     "<span font_desc=\"monospace\" size=\"small\">"
591 			     "  ( x  = %7.3f ;  y  = %7.3f ;  z  = %7.3f)\n"
592 			     "</span>"),
593 			   node0->number + 1, node0->xyz[0],
594 			   node0->xyz[1], node0->xyz[2]);
595   else if (pick == PICK_DISTANCE)
596     {
597       visu_data_getNodePosition(dataObj, node0, posSelect);
598       visu_data_getNodePosition(dataObj, node1, posRef1);
599       dx = posSelect[0] - posRef1[0];
600       dy = posSelect[1] - posRef1[1];
601       dz = posSelect[2] - posRef1[2];
602       dr = sqrt(dx*dx + dy*dy + dz*dz);
603       g_string_append_printf(infos,
604 			     _("Newly picked node\t"
605 			       " <span font_desc=\"monospace\"><b>#%d</b>\t"
606 			       " (<i>i.e.</i> dr = %7.3f)</span>\n"
607 			       "<span font_desc=\"monospace\" size=\"small\">"
608 			       "  ( x  = %7.3f ;  y  = %7.3f ;  z  = %7.3f)\n"
609 			       "  (\316\264x  = %7.3f ; \316\264y  = %7.3f ; \316\264z  = %7.3f)\n"
610 			       "</span>"),
611 			     node0->number + 1, dr, node0->xyz[0],
612 			     node0->xyz[1], node0->xyz[2], dx, dy, dz);
613     }
614   else if (pick == PICK_ANGLE)
615     {
616       visu_data_getNodePosition(dataObj, node0, posSelect);
617       visu_data_getNodePosition(dataObj, node1, posRef1);
618       visu_data_getNodePosition(dataObj, node2, posRef2);
619       dx1 = posSelect[0] - posRef1[0];
620       dy1 = posSelect[1] - posRef1[1];
621       dz1 = posSelect[2] - posRef1[2];
622       dx2 = posRef2[0] - posRef1[0];
623       dy2 = posRef2[1] - posRef1[1];
624       dz2 = posRef2[2] - posRef1[2];
625       dr1 = sqrt(dx1*dx1 + dy1*dy1 + dz1*dz1);
626       g_string_append_printf(infos,
627 			     _("Newly picked node\t"
628 			       " <span font_desc=\"monospace\"><b>#%d</b>\t"
629 			       " (<i>i.e.</i> dr = %7.3f)</span>\n"
630 			       "<span font_desc=\"monospace\" size=\"small\">"
631 			       "  ( x  = %7.3f ;  y  = %7.3f ;  z  = %7.3f)\n"
632 			       "  (\316\264x1 = %7.3f ; \316\264y1 = %7.3f ; \316\264z1 = %7.3f)\n"
633 			       "  (\316\264x2 = %7.3f ; \316\264y2 = %7.3f ; \316\264z2 = %7.3f)\n"),
634 			     node0->number + 1, dr1, node0->xyz[0],
635 			     node0->xyz[1], node0->xyz[2],
636 			     dx1, dy1, dz1, dx2, dy2, dz2);
637       dr2 = sqrt(dx2*dx2 + dy2*dy2 + dz2*dz2);
638       ang = acos((dx2*dx1+dy2*dy1+dz2*dz1)/(dr2*dr1))/TOOL_PI180;
639       g_string_append_printf(infos,
640 			     _("  angle (Ref-Ref2, Ref-New) = %5.2f degrees"
641 			       "</span>"), ang);
642     }
643   if (pick == PICK_UNREFERENCE_1 || pick == PICK_UNREFERENCE_2)
644     errors = g_strdup_printf(_("Unset reference %d."),
645 			     (pick == PICK_UNREFERENCE_1)?1:2);
646 
647   /* Update the remaining of the interface. */
648   switch (pick)
649     {
650     case PICK_SELECTED:
651     case PICK_DISTANCE:
652     case PICK_ANGLE:
653     case PICK_HIGHLIGHT:
654       /* Add clicked node to list. */
655       visu_ui_selection_add(listPickedNodes, node0->number);
656       /* Falls through. */
657     case PICK_UNREFERENCE_1:
658     case PICK_UNREFERENCE_2:
659     case PICK_REFERENCE_1:
660     case PICK_REFERENCE_2:
661       if (infos)
662 	{
663 	  gtk_label_set_markup(GTK_LABEL(labelPickOut), infos->str);
664 	  g_string_free(infos, TRUE);
665 	}
666       gtk_label_set_text(GTK_LABEL(labelPickError), errors);
667       if (errors)
668 	g_free(errors);
669       return;
670     case PICK_INFORMATION:
671       break;
672     default:
673       g_warning("Not a pick event!");
674     }
675   return;
676 }
onSelectionError(VisuInteractive * inter _U_,VisuInteractivePickError error,gpointer data _U_)677 static void onSelectionError(VisuInteractive *inter _U_,
678 			     VisuInteractivePickError error, gpointer data _U_)
679 {
680   switch (error)
681     {
682     case PICK_ERROR_NO_SELECTION:
683       gtk_label_set_text(GTK_LABEL(labelPickError), _("No node has been selected."));
684       return;
685     case PICK_ERROR_SAME_REF:
686       gtk_label_set_text(GTK_LABEL(labelPickError), _("Picked reference and second"
687 						      " reference are the same."));
688       return;
689     case PICK_ERROR_REF1:
690       gtk_label_set_text(GTK_LABEL(labelPickError), _("Can't pick a second reference"
691 						      " without any existing first one."));
692       return;
693     case PICK_ERROR_REF2:
694       gtk_label_set_text(GTK_LABEL(labelPickError), _("Can't remove first reference"
695 						      " before removing the second one."));
696       return;
697     default:
698       return;
699     }
700 }
701 /**
702  * visu_ui_interactive_pick_getSelection:
703  *
704  * Retrieves the #VisuUiSelection of this panel.
705  *
706  * Since: 3.8
707  *
708  * Returns: (transfer none): a #VisuUiSelection object.
709  **/
visu_ui_interactive_pick_getSelection(void)710 VisuUiSelection* visu_ui_interactive_pick_getSelection(void)
711 {
712   return listPickedNodes;
713 }
714 /**
715  * visu_ui_interactive_pick_getSelectionLabel:
716  *
717  * Retrieves the #GtkWidget used as label for the selection.
718  *
719  * Since: 3.8
720  *
721  * Returns: (transfer none): a #GtkWidget object.
722  **/
visu_ui_interactive_pick_getSelectionLabel(void)723 GtkWidget* visu_ui_interactive_pick_getSelectionLabel(void)
724 {
725   return labelSelection;
726 }
727 
728 /*********************/
729 /* Private routines. */
730 /*********************/
displayProp(GtkTreeViewColumn * column _U_,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)731 static void displayProp(GtkTreeViewColumn *column _U_, GtkCellRenderer *renderer,
732                         GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
733 {
734   VisuNodeValues *values = VISU_NODE_VALUES(data);
735   gint number;
736   gchar *text, *none;
737   gboolean editable;
738 
739   gtk_tree_model_get(model, iter, VISU_UI_SELECTION_NUMBER, &number, -1);
740   text = visu_node_values_toStringFromId(values, (guint)(number - 1));
741   if (!text || text[0] == '\0')
742     {
743       none = g_strdup_printf("<i>%s</i>", _("None"));
744       g_object_set(renderer, "markup", none, NULL);
745       g_free(none);
746     }
747   else
748     g_object_set(renderer, "markup", text, NULL);
749   editable = visu_node_values_getEditable(values);
750   g_object_set(renderer, "editable", editable, NULL);
751   if (editable)
752     g_object_set(renderer, "foreground", GTK_PICK_EDITABLE_NODE, NULL);
753   g_free(text);
754 }
755 
756 /*************/
757 /* Callbacks */
758 /*************/
onNodeValueChanged(VisuNodeValues * values _U_,VisuNode * node)759 static void onNodeValueChanged(VisuNodeValues *values _U_, VisuNode *node)
760 {
761   GtkTreeIter iter;
762   GtkTreePath *path;
763   gboolean valid;
764   guint number;
765 
766   for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listPickedNodes), &iter);
767        valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(listPickedNodes), &iter))
768     {
769       gtk_tree_model_get(GTK_TREE_MODEL(listPickedNodes), &iter,
770                          VISU_UI_SELECTION_NUMBER, &number, -1);
771       if (!node || number == node->number + 1)
772         {
773           path = gtk_tree_model_get_path(GTK_TREE_MODEL(listPickedNodes), &iter);
774           gtk_tree_model_row_changed(GTK_TREE_MODEL(listPickedNodes), path, &iter);
775           gtk_tree_path_free(path);
776           if (node)
777             return;
778         }
779     }
780 }
onEditedValue(GtkCellRendererText * cellrenderertext _U_,gchar * path,gchar * text,gpointer user_data)781 static void onEditedValue(GtkCellRendererText *cellrenderertext _U_,
782                           gchar *path, gchar *text, gpointer user_data)
783 {
784   GtkTreeIter iter;
785   guint number;
786   VisuNodeValues *values = VISU_NODE_VALUES(user_data);
787   gboolean valid;
788 
789   if (text && !strcmp(text, _("None")))
790     return;
791 
792   valid = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(listPickedNodes),
793                                               &iter, path);
794   g_return_if_fail(valid);
795 
796   gtk_tree_model_get(GTK_TREE_MODEL(listPickedNodes), &iter,
797 		     VISU_UI_SELECTION_NUMBER, &number, -1);
798 
799   valid = visu_node_values_setFromStringForId(values, number - 1, text);
800   if (!valid)
801     visu_ui_raiseWarning(_("Reading values"),
802 			 _("Wrong format. Impossible to parse the data associated"
803 			   " to the selected node."), (GtkWindow*)0);
804 }
onMeasurementList(VisuGlExtMarks * marks,VisuData * dataObj,gpointer data _U_)805 static void onMeasurementList(VisuGlExtMarks *marks, VisuData *dataObj, gpointer data _U_)
806 {
807   gchar *lbl;
808   struct _PickHistory *hist;
809   GString *str;
810   GList *lst, *rev;
811 
812   if (!dataObj)
813     return;
814   lbl = visu_gl_ext_marks_getMeasurementStrings(marks);
815   if (!lbl)
816     return;
817 
818   if (!pickHistory || ((struct _PickHistory*)pickHistory->data)->dataObj != dataObj)
819     {
820       hist = g_malloc(sizeof(struct _PickHistory));
821       hist->dataObj = dataObj;
822       pickHistory = g_list_prepend(pickHistory, (gpointer)hist);
823     }
824   else
825     {
826       hist = (struct _PickHistory*)pickHistory->data;
827       g_free(hist->str);
828     }
829   hist->str = lbl;
830 
831   if (labelPickHistory)
832     {
833       lbl = visu_gl_ext_marks_getMeasurementLabels(marks);
834       str = g_string_new(lbl);
835       g_free(lbl);
836       rev = g_list_reverse(pickHistory);
837       for (lst = rev; lst; lst = g_list_next(lst))
838         g_string_append(str, ((struct _PickHistory*)lst->data)->str);
839       pickHistory = g_list_reverse(rev);
840       lbl = g_markup_printf_escaped
841         ("Measurement history, first 6 values (<b>%d entry(ies)</b>):\n"
842          "<span font_desc=\"monospace\" size=\"small\">%s</span>",
843          g_list_length(pickHistory), str->str);
844       g_string_free(str, TRUE);
845       gtk_label_set_markup(GTK_LABEL(labelPickHistory), lbl);
846       g_free(lbl);
847     }
848 }
_togglePath(VisuUiSelection * selection,gchar * path)849 static void _togglePath(VisuUiSelection *selection, gchar *path)
850 {
851   gboolean valid;
852   GtkTreeIter iter;
853 
854   valid = gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(selection),
855 					      &iter, path);
856   g_return_if_fail(valid);
857 
858   visu_ui_selection_highlight(selection, &iter, MARKS_STATUS_TOGGLE);
859 }
onHighlightHideToggled(GtkToggleButton * button,gpointer user_data)860 static void onHighlightHideToggled(GtkToggleButton *button, gpointer user_data)
861 {
862   VisuGlExtMarksHidingModes mode;
863 
864   if (gtk_toggle_button_get_active(button))
865     {
866       mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "hiding-mode"));
867       visu_gl_ext_marks_setHidingMode(VISU_GL_EXT_MARKS(user_data), mode);
868     }
869   else
870     visu_gl_ext_marks_setHidingMode(VISU_GL_EXT_MARKS(user_data), HIDE_NONE);
871 }
onHighlightHideStatus(GtkButton * button,gpointer user_data)872 static void onHighlightHideStatus(GtkButton *button, gpointer user_data)
873 {
874   VisuGlExtMarksHidingModes mode;
875 
876   if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
877     return;
878 
879   mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "hiding-mode"));
880   g_object_set_data(G_OBJECT(tglMarks), "hiding-mode", GINT_TO_POINTER(mode));
881   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tglMarks)))
882     visu_gl_ext_marks_setHidingMode(VISU_GL_EXT_MARKS(user_data), mode);
883 }
onDrawDistanceChecked(GtkToggleButton * button,gpointer data)884 static void onDrawDistanceChecked(GtkToggleButton* button, gpointer data)
885 {
886   visu_gl_ext_marks_setDrawValues(VISU_GL_EXT_MARKS(data),
887                                   gtk_toggle_button_get_active(button));
888 }
onEraseDistanceClicked(GtkButton * button _U_,gpointer user_data)889 static void onEraseDistanceClicked(GtkButton *button _U_, gpointer user_data)
890 {
891   DBG_fprintf(stderr, "Gtk Pick: clicked on 'erase all measures' button.\n");
892   visu_gl_ext_marks_removeMeasures(VISU_GL_EXT_MARKS(user_data), -1);
893 }
onDataNotify(VisuGlNodeScene * scene)894 static void onDataNotify(VisuGlNodeScene *scene)
895 {
896   _setData(visu_gl_node_scene_getData(scene));
897 }
_setData(VisuData * dataObj)898 static void _setData(VisuData *dataObj)
899 {
900   GList *lst, *tmpLst;
901 
902   DBG_fprintf(stderr, "Gtk Pick: set data model to %p.\n", (gpointer)dataObj);
903 
904   if (currentData == dataObj)
905     return;
906 
907   lst = gtk_tree_view_get_columns(GTK_TREE_VIEW(treeviewPickedNodes));
908   for (tmpLst = g_list_next(lst); tmpLst; tmpLst = g_list_next(tmpLst))
909     gtk_tree_view_remove_column(GTK_TREE_VIEW(treeviewPickedNodes),
910                                 GTK_TREE_VIEW_COLUMN(tmpLst->data));
911   if (lst) g_list_free(lst);
912 
913   if (currentData)
914     {
915       g_signal_handler_disconnect(G_OBJECT(currentData), propAdd_signal);
916       g_signal_handler_disconnect(G_OBJECT(currentData), propRemoved_signal);
917       g_object_unref(currentData);
918     }
919   currentData = dataObj;
920   if (dataObj)
921     {
922       g_object_ref(dataObj);
923       DBG_fprintf(stderr, " | dataObj has %d ref counts.\n",
924                   G_OBJECT(dataObj)->ref_count);
925       propAdd_signal = g_signal_connect_swapped
926         (G_OBJECT(dataObj), "node-properties-added",
927          G_CALLBACK(_addColumn), treeviewPickedNodes);
928       propRemoved_signal = g_signal_connect_swapped
929         (G_OBJECT(dataObj), "node-properties-removed",
930          G_CALLBACK(_removeColumn), treeviewPickedNodes);
931 
932       lst = visu_data_getAllNodeProperties(dataObj);
933       for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst))
934         _addColumn(GTK_TREE_VIEW(treeviewPickedNodes), VISU_NODE_VALUES(tmpLst->data));
935       g_list_free(lst);
936       DBG_fprintf(stderr, " | dataObj has %d ref counts.\n",
937                   G_OBJECT(dataObj)->ref_count);
938     }
939 }
_addColumn(GtkTreeView * view,VisuNodeValues * prop)940 static void _addColumn(GtkTreeView *view, VisuNodeValues *prop)
941 {
942   GtkCellRenderer *renderer;
943   GtkTreeViewColumn *column;
944   GtkWidget *lbl;
945   const gchar *title;
946   gchar *markup;
947 
948   renderer = gtk_cell_renderer_text_new();
949   g_signal_connect(G_OBJECT(renderer), "edited",
950                    G_CALLBACK(onEditedValue), prop);
951   g_object_set(G_OBJECT(renderer), "scale", 0.8, NULL);
952   title = visu_node_values_getLabel(prop);
953   DBG_fprintf(stderr, " | add column '%s'.\n", title);
954   lbl = gtk_label_new("");
955   markup = g_markup_printf_escaped("<span size=\"smaller\">%s</span>", title);
956   gtk_label_set_markup(GTK_LABEL(lbl), markup);
957   g_free(markup);
958   gtk_widget_show(lbl);
959 
960   column = gtk_tree_view_column_new();
961   g_object_set_data(G_OBJECT(column), "NodeProperties", prop);
962   gtk_tree_view_column_set_widget(column, lbl);
963   gtk_tree_view_column_pack_start(column, renderer, TRUE);
964   gtk_tree_view_column_set_cell_data_func(column, renderer,
965                                           displayProp, prop, (GDestroyNotify)0);
966   gtk_tree_view_column_set_visible(column, TRUE);
967   if (VISU_IS_NODE_VALUES_ID(prop))
968     gtk_tree_view_column_set_sort_column_id(column, VISU_UI_SELECTION_NUMBER);
969   gtk_tree_view_append_column(view, column);
970   g_signal_connect_object(G_OBJECT(prop), "changed",
971                           G_CALLBACK(onNodeValueChanged), renderer, 0);
972 }
_removeColumn(GtkTreeView * view,VisuNodeValues * prop)973 static void _removeColumn(GtkTreeView *view, VisuNodeValues *prop)
974 {
975   GList *lst, *tmpLst;
976   gpointer myprop;
977 
978   lst = gtk_tree_view_get_columns(view);
979   for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst))
980     {
981       myprop = g_object_get_data(G_OBJECT(tmpLst->data), "NodeProperties");
982       if (myprop == (gpointer)prop)
983         {
984           gtk_tree_view_remove_column(view, GTK_TREE_VIEW_COLUMN(tmpLst->data));
985           break;
986         }
987     }
988   g_list_free(lst);
989 }
onTreeviewInfosKey(GtkWidget * widget,GdkEventKey * event,gpointer user_data _U_)990 static gboolean onTreeviewInfosKey(GtkWidget *widget, GdkEventKey *event,
991 				   gpointer user_data _U_)
992 {
993   GList *selectedPaths;
994   GtkTreeModel *model;
995 
996   DBG_fprintf(stderr, "Gtk Pick: key pressed on treeview '%d'.\n", event->keyval);
997 
998   if (event->keyval != GDK_KEY_Delete && event->keyval != GDK_KEY_BackSpace)
999     return FALSE;
1000 
1001   selectedPaths = gtk_tree_selection_get_selected_rows
1002     (gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), &model);
1003   visu_ui_selection_removePaths(VISU_UI_SELECTION(model), selectedPaths);
1004   g_list_free_full(selectedPaths, (GDestroyNotify)gtk_tree_path_free);
1005   return TRUE;
1006 }
1007 
onLoadXML(const gchar * filename,GError ** error)1008 static gboolean onLoadXML(const gchar *filename, GError **error)
1009 {
1010   return visu_gl_node_scene_setMarksFromFile(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), filename, error);
1011 }
onSaveXML(const gchar * filename,GError ** error)1012 static gboolean onSaveXML(const gchar *filename, GError **error)
1013 {
1014   return visu_gl_node_scene_marksToFile(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), filename, error);
1015 }
1016