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