"Fossies" - the Fresh Open Source Software Archive 
Member "gfsview-snapshot-121130/view/gfkgl.c" (30 Nov 2012, 133939 Bytes) of package /linux/privat/gfsview-snapshot-121130.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "gfkgl.c" see the
Fossies "Dox" file reference documentation.
1 /* Gerris - The GNU Flow Solver
2 * Copyright (C) 2004-2012 National Institute of Water and Atmospheric
3 * Research
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 */
20
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <glob.h>
28 #include <math.h>
29 #include <gts.h>
30 #include <gtk/gtkgl.h>
31 #include <gdk/x11/gdkglx.h>
32 #include <gdk/x11/gdkglglxext.h>
33 #if defined(__APPLE__)
34 # include <OpenGL/glu.h>
35 #else
36 # include <GL/glu.h>
37 #endif
38
39 #include "gfkgl.h"
40 #include "gl/trackball.h"
41 #include "glade/interface.h"
42 #include "glade/callbacks.h"
43 #include "glade/support.h"
44
45 G_LOCK_DEFINE (gfk_gl_scripting);
46 gboolean gfk_gl_scripting = FALSE;
47
48 gpointer lookup_gl (gpointer widget);
49 gpointer lookup_widget_params (gpointer widget, const gchar * widget_name);
50 void gl2ps_ppm_set_sensitive (GtkWidget * w, gboolean s, gboolean s1);
51
52 static void gl2D_destroy (GtsObject * o);
53
54 typedef GtsFile * (* GfkFunctionSet) (GfkGl *, const gchar *);
55
56 static GtkWidget * gfk_function (GtkWidget * parent,
57 GfkGl * gl,
58 const gchar * name,
59 GfkFunctionSet set);
60
61 /* GfkGlSymmetry: Object */
62
63 static void gl2D_read (GtsObject ** o, GtsFile * fp)
64 {
65 GtkWidget * params = GFK_GL2D (*o)->params;
66 GfsGl2D * gl = GFS_GL2D (GFK_GL (*o)->gl);
67
68 (* GTS_OBJECT_CLASS (gfk_gl2D_class ())->parent_class->read) (o, fp);
69 if (fp->type == GTS_ERROR)
70 return;
71
72 GFK_GL2D (*o)->n = gl->n;
73 gtk_spin_button_set_value (lookup_widget_params (params, "spinbuttonx"), gl->n.x);
74 gtk_spin_button_set_value (lookup_widget_params (params, "spinbuttony"), gl->n.y);
75 gtk_spin_button_set_value (lookup_widget_params (params, "spinbuttonz"), gl->n.z);
76 gtk_spin_button_set_value (lookup_widget_params (params, "spinbuttonpos"), gl->pos);
77 }
78
79 static void pos_bounds (FttCell * root, GfsGl2D * gl, GtkAdjustment * pos)
80 {
81 static FttVector d[8] = {{1.,1.,1.},{1.,1.,-1.},{1.,-1.,1.},{1.,-1.,-1.},
82 {-1.,1.,1.},{-1.,1.,-1.},{-1.,-1.,1.},{-1.,-1.,-1.}};
83 FttVector p, o;
84 gdouble h = ftt_cell_size (root)/2.;
85 guint i;
86
87 pos->lower = G_MAXDOUBLE;
88 pos->upper = -G_MAXDOUBLE;
89 ftt_cell_pos (root, &o);
90 for (i = 0; i < 8; i++) {
91 gdouble e;
92 p.x = o.x + h*d[i].x; p.y = o.y + h*d[i].y; p.z = o.z + h*d[i].z;
93 e = p.x*gl->n.x + p.y*gl->n.y + p.z*gl->n.z;
94 if (e > pos->upper) pos->upper = e;
95 if (e < pos->lower) pos->lower = e;
96 }
97 }
98
99 static void find_bounds (FttCell * root, GfsGl2D * gl, GtkAdjustment * pos)
100 {
101 GtkAdjustment p;
102
103 pos_bounds (root, gl, &p);
104 if (FTT_CELL_IS_LEAF (root)) {
105 if (p.upper > pos->upper) pos->upper = p.upper;
106 if (p.lower < pos->lower) pos->lower = p.lower;
107 }
108 else if (p.upper > pos->upper || p.lower < pos->lower) {
109 FttCellChildren child;
110 guint n;
111
112 ftt_cell_children (root, &child);
113 for (n = 0; n < FTT_CELLS; n++)
114 if (child.c[n])
115 find_bounds (child.c[n], gl, pos);
116 }
117 }
118
119 static void find_box_bounds (GfsBox * box, gpointer * data)
120 {
121 find_bounds (box->root, data[0], data[1]);
122 }
123
124 void gfk_gl2D_update_pos_bounds (GfkGl2D * gl)
125 {
126 GtkSpinButton * spos = lookup_widget_params (gl->params, "spinbuttonpos");
127 GtkAdjustment * pos = gtk_spin_button_get_adjustment (spos);
128
129 if (GFK_IS_GL_PERIODIC (gl)) {
130 pos->lower = -G_MAXDOUBLE;
131 pos->upper = G_MAXDOUBLE;
132 }
133 else {
134 gpointer data[2];
135 data[0] = GFK_GL (gl)->gl;
136 data[1] = pos;
137 pos->lower = G_MAXDOUBLE;
138 pos->upper = -G_MAXDOUBLE;
139 gts_container_foreach (GTS_CONTAINER (GFK_GL (gl)->gl->sim), (GtsFunc) find_box_bounds, data);
140 }
141 gtk_spin_button_set_adjustment (spos, pos);
142 if (pos->value < pos->lower)
143 gtk_spin_button_set_value (spos, pos->lower);
144 else if (pos->value > pos->upper)
145 gtk_spin_button_set_value (spos, pos->upper);
146 }
147
148 static void set_pos_increment (GfkGl * gl)
149 {
150 GtkSpinButton * maxlevel = lookup_widget_params (gl->properties, "maxlevel");
151 GtkAdjustment * amax = gtk_spin_button_get_adjustment (maxlevel);
152 GtkSpinButton * spos = lookup_widget_params (GFK_GL2D (gl)->params, "spinbuttonpos");
153 GtkAdjustment * pos = gtk_spin_button_get_adjustment (spos);
154 pos->step_increment = pos->page_increment = 1./exp (amax->upper*log (2.));
155 gtk_spin_button_set_adjustment (spos, pos);
156 }
157
158 static void gl2D_set_simulation (GfkGl * gl, GfsSimulation * sim)
159 {
160 (* GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl2D_class ())->parent_class)->set_simulation) (gl, sim);
161 gfk_gl2D_update_pos_bounds (GFK_GL2D (gl));
162 set_pos_increment (gl);
163 }
164
165 static void gl2D_post_init (GfkGl * gl)
166 {
167 GfkGl2D * gl2 = GFK_GL2D (gl);
168
169 (* GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl2D_class ())->parent_class)->post_init) (gl);
170
171 FttComponent c;
172 for (c = 0; c < 3; c++) {
173 static gchar * name[] = {"spinbuttonx", "spinbuttony", "spinbuttonz"};
174 GtkSpinButton * spin = lookup_widget_params (gl2->params, name[c]);
175 gdouble v = gtk_spin_button_get_value (spin);
176 if (v != (&gl2->n.x)[c])
177 gtk_spin_button_set_value (spin, (&gl2->n.x)[c]);
178 }
179
180 GFS_GL2D (gl->gl)->n = gl2->n;
181 gfs_gl2D_update_plane (GFS_GL2D (gl->gl));
182
183 if (gl->gl->sim) {
184 gfk_gl2D_update_pos_bounds (gl2);
185 set_pos_increment (gl);
186 }
187 }
188
189 static gchar * gl_symmetry_name (GfkGlClass * klass)
190 {
191 static gchar name[] = "Symmetry";
192 return name;
193 }
194
195 static GtkWidget * gl_symmetry_icon (GfkGlClass * klass)
196 {
197 return create_pixmap (NULL, "symmetry-16x16.png");
198 }
199
200 static void gl_symmetry_class_init (GfkGlClass * klass)
201 {
202 GTS_OBJECT_CLASS (klass)->destroy = gl2D_destroy;
203 GTS_OBJECT_CLASS (klass)->read = gl2D_read;
204 klass->post_init = gl2D_post_init;
205 klass->set_simulation = gl2D_set_simulation;
206
207 klass->gl_class = gfs_gl_symmetry_class ();
208 klass->name = gl_symmetry_name;
209 klass->icon = gl_symmetry_icon;
210 }
211
212 static void gl_symmetry_init (GfkGl2D * object)
213 {
214 object->params = create_gl2D_params ();
215 object->n.x = 1.; object->n.y = 0.; object->n.z = 0.;
216 gfk_gl_prepend_params (GFK_GL (object), object->params, gtk_label_new ("2D Plane"));
217 #if FTT_2D
218 gtk_widget_hide (lookup_widget_params (object->params, "spinbuttonz"));
219 #endif
220 gtk_widget_show (object->params);
221 }
222
223 GfkGlClass * gfk_gl_symmetry_class (void)
224 {
225 static GfkGlClass * klass = NULL;
226
227 if (klass == NULL) {
228 GtsObjectClassInfo gfk_gl_symmetry_info = {
229 "GfkGlSymmetry",
230 sizeof (GfkGl2D),
231 sizeof (GfkGlClass),
232 (GtsObjectClassInitFunc) gl_symmetry_class_init,
233 (GtsObjectInitFunc) gl_symmetry_init,
234 (GtsArgSetFunc) NULL,
235 (GtsArgGetFunc) NULL
236 };
237 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &gfk_gl_symmetry_info);
238 }
239
240 return klass;
241 }
242
243 /* GfkGlPeriodic: Object */
244
245 static gchar * gl_periodic_name (GfkGlClass * klass)
246 {
247 static gchar name[] = "Periodic";
248 return name;
249 }
250
251 static GtkWidget * gl_periodic_icon (GfkGlClass * klass)
252 {
253 return create_pixmap (NULL, "periodic-16x16.png");
254 }
255
256 static void gl_periodic_class_init (GfkGlClass * klass)
257 {
258 klass->gl_class = gfs_gl_periodic_class ();
259 klass->name = gl_periodic_name;
260 klass->icon = gl_periodic_icon;
261 }
262
263 GfkGlClass * gfk_gl_periodic_class (void)
264 {
265 static GfkGlClass * klass = NULL;
266
267 if (klass == NULL) {
268 GtsObjectClassInfo gfk_gl_periodic_info = {
269 "GfkGlPeriodic",
270 sizeof (GfkGl2D),
271 sizeof (GfkGlClass),
272 (GtsObjectClassInitFunc) gl_periodic_class_init,
273 (GtsObjectInitFunc) NULL,
274 (GtsArgSetFunc) NULL,
275 (GtsArgGetFunc) NULL
276 };
277 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_symmetry_class ()),
278 &gfk_gl_periodic_info);
279 }
280
281 return klass;
282 }
283
284 #if FTT_2D
285 # include "gfkgl2D.h"
286 #else /* 3D */
287 # include "gfkgl3D.h"
288 #endif /* 3D */
289
290 /* GfkGl: Object */
291
292 static void gl_read (GtsObject ** o, GtsFile * fp)
293 {
294 GtkWidget * properties = GFK_GL (*o)->properties;
295 GfsGl * gl = GFK_GL (*o)->gl;
296 GtsObject * object = GTS_OBJECT (gl);
297 GtkSpinButton * maxlevel = lookup_widget_params (properties, "maxlevel");
298 GtkSpinButton * linewidth = lookup_widget_params (properties, "linewidth");
299 GtkAdjustment * amax = gtk_spin_button_get_adjustment (maxlevel);
300
301 (* object->klass->read) (&object, fp);
302 if (fp->type == GTS_ERROR)
303 return;
304
305 gfk_gl_set_color (GFK_GL (*o), gl->lc);
306
307 gtk_spin_button_set_value (linewidth, gl->line_width);
308
309 if (gl->maxlevel == -1)
310 gtk_spin_button_set_value (maxlevel, amax->upper);
311 else {
312 gtk_spin_button_set_value (maxlevel, gl->maxlevel);
313 gl->maxlevel = -1;
314 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget_params (properties, "finest")),
315 FALSE);
316 }
317
318 GtkWidget * font = GFK_GL (*o)->font;
319 gtk_spin_button_set_value (lookup_widget_params (font, "font_size"), gl->font_size);
320 if (!gl->use_raster_font) {
321 gl->use_raster_font = TRUE;
322 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget_params (font, "vector_font")),
323 TRUE);
324 }
325 }
326
327 static void gl_write (GtsObject * o, FILE * fp)
328 {
329 GfsGl * gl = GFK_GL (o)->gl;
330
331 (* GTS_OBJECT (gl)->klass->write) (GTS_OBJECT (gl), fp);
332 }
333
334 static void gl_destroy (GtsObject * object)
335 {
336 GfkGl * gl = GFK_GL (object);
337
338 gtk_widget_destroy (gl->params);
339 gtk_widget_destroy (gl->color_selector);
340 gts_object_destroy (GTS_OBJECT (gl->gl));
341 g_free (gl->props);
342 (* GTS_OBJECT_CLASS (gfk_gl_class ())->parent_class->destroy) (object);
343 }
344
345 static gchar * gfk_gl_get_name (GfkGl * gl)
346 {
347 return (* GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->name) (GFK_GL_CLASS (GTS_OBJECT (gl)->klass));
348 }
349
350 static GtkWidget * gfk_gl_get_icon (GfkGl * gl)
351 {
352 return (* GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->icon) (GFK_GL_CLASS (GTS_OBJECT (gl)->klass));
353 }
354
355 static gchar * gfk_gl_get_properties (GfkGl * gl)
356 {
357 if (GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->properties)
358 return (* GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->properties) (gl);
359 return gfk_gl_get_name (gl);
360 }
361
362 static void gl_update_interface (GfkGl * gl)
363 {
364 GtkSpinButton * maxlevel = lookup_widget_params (gl->properties, "maxlevel");
365 GtkAdjustment * amax = gtk_spin_button_get_adjustment (maxlevel);
366
367 amax->upper = gfs_domain_depth (GFS_DOMAIN (gl->gl->sim));
368 gtk_spin_button_set_adjustment (maxlevel, amax);
369 if (gl->gl->maxlevel == -1) {
370 gtk_spin_button_set_value (maxlevel, amax->upper);
371 gl->gl->maxlevel = -1;
372 }
373 else {
374 gtk_spin_button_set_value (maxlevel, gl->gl->maxlevel);
375 GtkToggleButton * finest = GTK_TOGGLE_BUTTON (lookup_widget_params (gl->properties, "finest"));
376 if (gtk_toggle_button_get_active (finest)) {
377 gl->gl->maxlevel = -1;
378 gtk_toggle_button_set_active (finest, FALSE);
379 }
380 }
381 gtk_spin_button_set_value (lookup_widget_params (gl->font, "font_size"), gl->gl->font_size);
382 }
383
384 static void gl_set_simulation (GfkGl * gl, GfsSimulation * sim)
385 {
386 gfs_gl_set_simulation (gl->gl, sim);
387 gl_update_interface (gl);
388 }
389
390 static void gl_post_init (GfkGl * gl)
391 {
392 gtk_window_set_transient_for (GTK_WINDOW (gl->params),
393 GTK_WINDOW (gtk_widget_get_toplevel (gl->glarea)));
394 gtk_window_set_destroy_with_parent (GTK_WINDOW (gl->params), FALSE);
395 gtk_window_set_position (GTK_WINDOW (gl->params), GTK_WIN_POS_CENTER_ON_PARENT);
396 gtk_window_set_title (GTK_WINDOW (gl->params), gfk_gl_get_name (gl));
397
398 gtk_window_set_transient_for (GTK_WINDOW (gl->color_selector),
399 GTK_WINDOW (gtk_widget_get_toplevel (gl->glarea)));
400 gtk_window_set_destroy_with_parent (GTK_WINDOW (gl->color_selector), FALSE);
401 gtk_window_set_position (GTK_WINDOW (gl->color_selector), GTK_WIN_POS_CENTER_ON_PARENT);
402
403 if (gl->gl->sim)
404 gl_update_interface (gl);
405 }
406
407 static void gl_add_gl (GtkWidget * glarea, GtkWidget * list, GfkGl * gl)
408 {
409 GtkListStore * store;
410 GtkTreeSelection * select;
411 GtkTreeIter iter;
412 GtkImage * icon;
413
414 g_return_if_fail (glarea != NULL);
415 g_return_if_fail (list != NULL);
416 g_return_if_fail (gl != NULL);
417
418 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (list)));
419 select = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
420 icon = GTK_IMAGE (gfk_gl_get_icon (gl));
421
422 gtk_list_store_append (store, &iter);
423 gtk_list_store_set (store, &iter,
424 VISIBLE_COLUMN, TRUE,
425 ICON_COLUMN, icon ? gtk_image_get_pixbuf (icon) : NULL,
426 PROPERTIES_COLUMN, gfk_gl_get_properties (gl),
427 GL_COLUMN, gl,
428 SELECTED_COLUMN, TRUE,
429 -1);
430 gtk_tree_selection_select_iter (select, &iter);
431
432 gtk_widget_set_sensitive (lookup_widget (glarea, "save1"), TRUE);
433 gtk_widget_set_sensitive (lookup_widget (glarea, "edit1"), TRUE);
434 gtk_widget_set_sensitive (lookup_widget (glarea, "view1"), TRUE);
435 }
436
437 static void gl_add (GObject * tool)
438 {
439 GtkWidget * glarea = g_object_get_data (tool, "glarea");
440 GtkWidget * list = g_object_get_data (tool, "list");
441 GfkGlClass * klass = g_object_get_data (tool, "klass");
442 GfsSimulation * sim = g_object_get_data (G_OBJECT (glarea), "sim");
443 GfkGl * gl = gfk_gl_new (klass, glarea, list);
444
445 gfk_gl_set_simulation (gl, sim);
446 gl_add_gl (glarea, list, gl);
447 gfk_gl_expose (gl);
448 }
449
450 static GtkWidget * gl_icon (GfkGlClass * klass)
451 {
452 return NULL;
453 }
454
455 static gchar * gl_name (GfkGlClass * klass)
456 {
457 return GTS_OBJECT_CLASS (klass)->info.name;
458 }
459
460 static void gl_class_init (GfkGlClass * klass)
461 {
462 klass->gl_class = gfs_gl_class ();
463 klass->post_init = gl_post_init;
464 klass->set_simulation = gl_set_simulation;
465 klass->icon = gl_icon;
466 klass->name = gl_name;
467 GTS_OBJECT_CLASS (klass)->read = gl_read;
468 GTS_OBJECT_CLASS (klass)->write = gl_write;
469 GTS_OBJECT_CLASS (klass)->destroy = gl_destroy;
470 }
471
472 static gboolean hide_params (GtkWidget * p)
473 {
474 GfkGl * gl = g_object_get_data (G_OBJECT (p), "GfkGl");
475
476 gtk_widget_hide (p);
477 g_object_set_data (G_OBJECT (gl->list), "former", NULL);
478 return TRUE;
479 }
480
481 void gfk_gl_prepend_params (GfkGl * gl, GtkWidget * widget, GtkWidget * label)
482 {
483 gtk_notebook_prepend_page (g_object_get_data (G_OBJECT (gl->params), "book"), widget, label);
484 }
485
486 void gfk_gl_set_color (GfkGl * gl, GtsColor c)
487 {
488 GdkColor gc;
489 GtkWidget * b;
490
491 g_return_if_fail (gl != NULL);
492
493 gl->gl->lc = c;
494 b = lookup_widget_params (gl->properties, "default_color");
495 gc.red = c.r*65535.;
496 gc.green = c.g*65535.;
497 gc.blue = c.b*65535.;
498 gtk_widget_modify_bg (b, GTK_STATE_NORMAL, &gc);
499 gtk_widget_modify_bg (b, GTK_STATE_PRELIGHT, &gc);
500 gtk_widget_modify_bg (b, GTK_STATE_ACTIVE, &gc);
501 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (lookup_widget (gl->color_selector,
502 "colorselection1")),
503 &gc);
504 }
505
506 static void gl_init (GfkGl * gl)
507 {
508 GtkWidget * b = gtk_notebook_new ();
509
510 gtk_widget_show (b);
511 gl->params = gtk_window_new (GTK_WINDOW_TOPLEVEL);
512
513 g_signal_connect (G_OBJECT (gl->params), "delete_event", G_CALLBACK (hide_params), NULL);
514 g_object_set_data (G_OBJECT (gl->params), "GfkGl", gl);
515 g_object_set_data (G_OBJECT (gl->params), "book", b);
516 gtk_container_add (GTK_CONTAINER (gl->params), b);
517
518 gl->properties = create_gl_params ();
519 gfk_gl_prepend_params (gl, gl->properties, gtk_label_new ("Properties"));
520 gtk_widget_show (gl->properties);
521
522 gl->font = create_font_params ();
523 gfk_gl_prepend_params (gl, gl->font, gtk_label_new ("Font"));
524 /* dot not show by default */
525
526 gl->color_selector = create_color_selector ();
527 g_signal_connect (G_OBJECT (gl->color_selector), "delete_event",
528 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
529 g_object_set_data (G_OBJECT (gl->color_selector), "GfkGl", gl);
530
531 gl->gl = gfs_gl_new (GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->gl_class);
532
533 gfk_gl_set_color (gl, gl->gl->lc);
534
535 GtkSpinButton * linewidth = lookup_widget_params (gl->properties, "linewidth");
536 GtkAdjustment * a = gtk_spin_button_get_adjustment (linewidth);
537 GLint range[2];
538 glGetIntegerv (GL_ALIASED_LINE_WIDTH_RANGE, range);
539 a->lower = range[0];
540 a->upper = range[1];
541 gtk_spin_button_set_adjustment (linewidth, a);
542 }
543
544 GfkGlClass * gfk_gl_class (void)
545 {
546 static GfkGlClass * klass = NULL;
547
548 if (klass == NULL) {
549 GtsObjectClassInfo gfk_gl_info = {
550 "GfkGl",
551 sizeof (GfkGl),
552 sizeof (GfkGlClass),
553 (GtsObjectClassInitFunc) gl_class_init,
554 (GtsObjectInitFunc) gl_init,
555 (GtsArgSetFunc) NULL,
556 (GtsArgGetFunc) NULL
557 };
558 klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_object_class ()),
559 &gfk_gl_info);
560 }
561
562 return klass;
563 }
564
565 GfkGl * gfk_gl_new (GfkGlClass * klass,
566 GtkWidget * glarea,
567 GtkWidget * list)
568 {
569 GfkGl * object;
570
571 g_return_val_if_fail (klass != NULL, NULL);
572 g_return_val_if_fail (glarea != NULL, NULL);
573 g_return_val_if_fail (list != NULL, NULL);
574
575 object = GFK_GL (gts_object_new (GTS_OBJECT_CLASS (klass)));
576 object->glarea = glarea;
577 object->gl->p = g_object_get_data (G_OBJECT (glarea), "GfsGlViewParams");
578 object->list = list;
579 (* klass->post_init) (object);
580
581 return object;
582 }
583
584 void gfk_gl_expose (GfkGl * gl)
585 {
586 g_return_if_fail (gl != NULL);
587
588 if (gl->glarea->window)
589 gdk_window_invalidate_rect (gl->glarea->window, &gl->glarea->allocation, FALSE);
590 }
591
592 void gfk_gl_set_sensitive (GfkGl * gl, GtkWidget * page, gboolean sensitive)
593 {
594 GtkNotebook * book;
595
596 g_return_if_fail (gl != NULL);
597 g_return_if_fail (page != NULL);
598
599 book = g_object_get_data (G_OBJECT (gl->params), "book");
600 gtk_widget_set_sensitive (page, sensitive);
601 gtk_widget_set_sensitive (gtk_notebook_get_tab_label (book, page), sensitive);
602 }
603
604 void gfk_gl_set_simulation (GfkGl * gl, GfsSimulation * sim)
605 {
606 g_return_if_fail (gl != NULL);
607 g_return_if_fail (sim != NULL);
608
609 if (GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->set_simulation)
610 (* GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->set_simulation) (gl, sim);
611 }
612
613 void gfk_gl_update_properties (GfkGl * gl)
614 {
615 GtkTreeSelection * select = gtk_tree_view_get_selection (GTK_TREE_VIEW (gl->list));
616 GtkTreeModel * model;
617 GtkTreeIter iter;
618
619 if (gtk_tree_selection_get_selected (select, &model, &iter)) {
620 GfkGl * sgl;
621
622 gtk_tree_model_get (model, &iter, GL_COLUMN, &sgl, -1);
623 if (sgl == gl)
624 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
625 PROPERTIES_COLUMN, gfk_gl_get_properties (gl),
626 -1);
627 }
628 }
629
630 void gfk_gl_update_interface (GfkGl * gl)
631 {
632 g_return_if_fail (gl != NULL);
633
634 if (GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->update_interface)
635 (* GFK_GL_CLASS (GTS_OBJECT (gl)->klass)->update_interface) (gl);
636 }
637
638 static void gfk_gl_menu_append (GfkGlClass * klass,
639 GtkMenu * objects,
640 GtkWidget * list,
641 GtkWidget * glarea)
642 {
643 GtkWidget * menuitem;
644
645 menuitem = gtk_menu_item_new_with_mnemonic ((* klass->name) (klass));
646 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (gl_add), NULL);
647 g_object_set_data (G_OBJECT (menuitem), "klass", klass);
648 g_object_set_data (G_OBJECT (menuitem), "list", list);
649 g_object_set_data (G_OBJECT (menuitem), "glarea", glarea);
650 gtk_widget_show (menuitem);
651 gtk_container_add (GTK_CONTAINER (objects), menuitem);
652 }
653
654 static void gfk_gl_tool_append (GfkGlClass * klass,
655 GtkToolbar * toolbar,
656 GtkMenu * objects,
657 GtkWidget * list,
658 GtkWidget * glarea)
659 {
660 GtkWidget * tool;
661
662 gfk_gl_menu_append (klass, objects, list, glarea);
663 tool = gtk_toolbar_append_element (toolbar,
664 GTK_TOOLBAR_CHILD_BUTTON,
665 NULL,
666 (* klass->name) (klass),
667 NULL, NULL,
668 (* klass->icon) (klass),
669 (GtkSignalFunc) gl_add, NULL);
670 g_object_set_data (G_OBJECT (tool), "klass", klass);
671 g_object_set_data (G_OBJECT (tool), "list", list);
672 g_object_set_data (G_OBJECT (tool), "glarea", glarea);
673 gtk_widget_show (tool);
674 }
675
676 /* GfkGlLabel: Object */
677
678 static void gl_label_read (GtsObject ** o, GtsFile * fp)
679 {
680 (* GTS_OBJECT_CLASS (gfk_gl_label_class ())->parent_class->read) (o, fp);
681 if (fp->type == GTS_ERROR)
682 return;
683
684 GfsGlLabel * gl = GFS_GL_LABEL (GFK_GL (*o)->gl);
685 GtkWidget * label = GFK_GL_LABEL (*o)->label;
686 gtk_entry_set_text (lookup_widget_params (label, "labelentry"), gl->label);
687 gtk_spin_button_set_value (lookup_widget_params (label, "labelx"), gl->p.x);
688 gtk_spin_button_set_value (lookup_widget_params (label, "labely"), gl->p.y);
689 gtk_spin_button_set_value (lookup_widget_params (label, "labelz"), gl->p.z);
690 if (gl->symbol) {
691 gl->symbol = FALSE;
692 gtk_toggle_button_set_active (lookup_widget_params (label, "label_symbol_check"), TRUE);
693 }
694 }
695
696 typedef struct {
697 GfsSimulation * sim;
698 GtkAdjustment * pos[3];
699 } BoundPar;
700
701 static void cell_bounds (FttCell * cell, BoundPar * par)
702 {
703 static FttVector d[8] = {{ 1.,1.,1.},{ 1.,1.,-1.},{ 1.,-1.,1.},{ 1.,-1.,-1.},
704 {-1.,1.,1.},{-1.,1.,-1.},{-1.,-1.,1.},{-1.,-1.,-1.}};
705 FttVector p, o;
706 gdouble h = ftt_cell_size (cell)/2.;
707 guint i;
708
709 ftt_cell_pos (cell, &o);
710 for (i = 0; i < 8; i++) {
711 p.x = o.x + h*d[i].x; p.y = o.y + h*d[i].y; p.z = o.z + h*d[i].z;
712 gfs_simulation_map_inverse (par->sim, &p);
713 FttComponent c;
714 for (c = 0; c < 3; c++) {
715 gdouble e = (&p.x)[c];
716 if (e > par->pos[c]->upper) par->pos[c]->upper = e;
717 if (e < par->pos[c]->lower) par->pos[c]->lower = e;
718 }
719 }
720 }
721
722 static void gfk_gl_label_update_bounds (GfkGlLabel * gl)
723 {
724 GtkSpinButton * label[3];
725 BoundPar p;
726 p.sim = GFK_GL (gl)->gl->sim;
727 FttComponent c;
728 for (c = 0; c < 3; c++) {
729 const char * name[] = { "labelx", "labely", "labelz" };
730 label[c] = lookup_widget_params (gl->label, name[c]);
731 p.pos[c] = gtk_spin_button_get_adjustment (label[c]);
732 p.pos[c]->lower = G_MAXDOUBLE;
733 p.pos[c]->upper = -G_MAXDOUBLE;
734 }
735 gfs_domain_cell_traverse (GFS_DOMAIN (GFK_GL (gl)->gl->sim),
736 FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS | FTT_TRAVERSE_LEVEL, 5,
737 (FttCellTraverseFunc) cell_bounds, &p);
738 for (c = 0; c < 3; c++) {
739 gdouble range = p.pos[c]->upper - p.pos[c]->lower;
740 p.pos[c]->lower -= range/2.;
741 p.pos[c]->upper += range/2.;
742 gtk_spin_button_set_adjustment (label[c], p.pos[c]);
743 if (p.pos[c]->value < p.pos[c]->lower)
744 gtk_spin_button_set_value (label[c], p.pos[c]->lower);
745 else if (p.pos[c]->value > p.pos[c]->upper)
746 gtk_spin_button_set_value (label[c], p.pos[c]->upper);
747 gdouble max = fabs (p.pos[c]->upper);
748 if (fabs (p.pos[c]->lower) > max)
749 max = fabs (p.pos[c]->lower);
750 if (max == 0.)
751 gtk_spin_button_set_digits (label[c], 3);
752 else {
753 gint n = 6. - log10 (max);
754 gtk_spin_button_set_digits (label[c], MAX (n, 0));
755 }
756 }
757 }
758
759 static void gl_label_set_simulation (GfkGl * gl, GfsSimulation * sim)
760 {
761 (* GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_label_class ())->parent_class)->set_simulation)
762 (gl, sim);
763 gfk_gl_label_update_bounds (GFK_GL_LABEL (gl));
764 }
765
766 static gchar * gl_label_name (GfkGlClass * klass)
767 {
768 static gchar name[] = "Label";
769 return name;
770 }
771
772 static GtkWidget * gl_label_icon (GfkGlClass * klass)
773 {
774 return create_pixmap (NULL, "label-16x16.png");
775 }
776
777 #define MAXLENGTH 16
778
779 static gchar * gl_label_properties (GfkGl * gl)
780 {
781 g_free (gl->props);
782 gl->props = g_strndup (GFS_GL_LABEL (gl->gl)->label, MAXLENGTH + 3);
783 if (strlen (gl->props) > MAXLENGTH) {
784 guint i;
785 for (i = 0; i < 3; i++)
786 gl->props[MAXLENGTH + i] = '.';
787 }
788 return gl->props;
789 }
790
791 static void gl_label_class_init (GfkGlClass * klass)
792 {
793 klass->gl_class = gfs_gl_label_class ();
794 klass->name = gl_label_name;
795 klass->icon = gl_label_icon;
796 klass->properties = gl_label_properties;
797 klass->set_simulation = gl_label_set_simulation;
798 GTS_OBJECT_CLASS (klass)->read = gl_label_read;
799 }
800
801 static void gl_label_init (GfkGl * gl)
802 {
803 gtk_widget_show (gl->font);
804
805 GFK_GL_LABEL (gl)->label = create_label_params ();
806 gfk_gl_prepend_params (gl, GFK_GL_LABEL (gl)->label, gtk_label_new ("Label"));
807 gtk_widget_show (GFK_GL_LABEL (gl)->label);
808 }
809
810 GfkGlClass * gfk_gl_label_class (void)
811 {
812 static GfkGlClass * klass = NULL;
813
814 if (klass == NULL) {
815 GtsObjectClassInfo gfk_gl_label_info = {
816 "GfkGlLabel",
817 sizeof (GfkGlLabel),
818 sizeof (GfkGlClass),
819 (GtsObjectClassInitFunc) gl_label_class_init,
820 (GtsObjectInitFunc) gl_label_init,
821 (GtsArgSetFunc) NULL,
822 (GtsArgGetFunc) NULL
823 };
824 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &gfk_gl_label_info);
825 }
826
827 return klass;
828 }
829
830 /* GfkGl2D: Object */
831
832 static void gl2D_destroy (GtsObject * o)
833 {
834 g_free (GFK_GL2D (o)->pickinfo);
835
836 (* GTS_OBJECT_CLASS (gfk_gl2D_class ())->parent_class->destroy) (o);
837 }
838
839 static void gl2D_class_init (GfkGlClass * klass)
840 {
841 GTS_OBJECT_CLASS (klass)->destroy = gl2D_destroy;
842 GTS_OBJECT_CLASS (klass)->read = gl2D_read;
843 klass->post_init = gl2D_post_init;
844 klass->set_simulation = gl2D_set_simulation;
845 klass->pickinfo = gl2D_pickinfo;
846
847 klass->gl_class = gfs_gl_symmetry_class ();
848 klass->name = gl_symmetry_name;
849 klass->icon = gl_symmetry_icon;
850 }
851
852 GfkGlClass * gfk_gl2D_class (void)
853 {
854 static GfkGlClass * klass = NULL;
855
856 if (klass == NULL) {
857 GtsObjectClassInfo gfk_gl2D_info = {
858 "GfkGl2D",
859 sizeof (GfkGl2D),
860 sizeof (GfkGlClass),
861 (GtsObjectClassInitFunc) gl2D_class_init,
862 (GtsObjectInitFunc) gl2D_init,
863 (GtsArgSetFunc) NULL,
864 (GtsArgGetFunc) NULL
865 };
866 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &gfk_gl2D_info);
867 }
868
869 return klass;
870 }
871
872 /* GfkGlCells: Object */
873
874 static gchar * gl_cells_name (GfkGlClass * klass)
875 {
876 static gchar name[] = "Cells";
877 return name;
878 }
879
880 static GtkWidget * gl_cells_icon (GfkGlClass * klass)
881 {
882 return create_pixmap (NULL, "cells-16x16.png");
883 }
884
885 static gboolean coarsenable (FttCell * cell)
886 {
887 return TRUE;
888 }
889
890 static gchar * gl_cells_pickinfo (GfkGl * gl, gboolean motion)
891 {
892 GfkGlCells * glk = GFK_GL_CELLS (gl);
893
894 if (gtk_toggle_button_get_active (lookup_widget_params (glk->cells, "edit"))) {
895 FttCell * cell = GFS_GL2D (gl->gl)->picked;
896 guint level = gtk_spin_button_get_value (lookup_widget_params (glk->cells, "level"));
897 guint l = ftt_cell_level (cell);
898 if (FTT_CELL_IS_LEAF (cell) && l < level) {
899 GfsDomain * domain = GFS_DOMAIN (gl->gl->sim);
900 while (l < level) {
901 ftt_cell_refine_corners (cell, (FttCellInitFunc) gfs_cell_fine_init, domain);
902 ftt_cell_refine_single (cell, (FttCellInitFunc) gfs_cell_fine_init, domain);
903 if (++l < level)
904 cell = ftt_cell_locate (cell, GFS_GL2D (gl->gl)->pickedpos, -1);
905 }
906 gfk_gl_expose (gl);
907 }
908 else if ((FTT_CELL_IS_LEAF (cell) && l > level) ||
909 (!FTT_CELL_IS_LEAF (cell) && l >= level)) {
910 while (l > level) {
911 cell = ftt_cell_parent (cell);
912 l--;
913 }
914 ftt_cell_coarsen (cell, (FttCellCoarsenFunc) coarsenable, NULL,
915 (FttCellCleanupFunc) gfs_cell_cleanup, GFS_DOMAIN (gl->gl->sim));
916 gfk_gl_expose (gl);
917 }
918 }
919 return gl2D_pickinfo (gl, motion);
920 }
921
922 static void gl_cells_class_init (GfkGlClass * klass)
923 {
924 klass->gl_class = gfs_gl_cells_class ();
925 klass->name = gl_cells_name;
926 klass->icon = gl_cells_icon;
927 klass->pickinfo = gl_cells_pickinfo;
928 }
929
930 static void gl_cells_init (GfkGl * gl)
931 {
932 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading_label"), FALSE);
933 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading"), FALSE);
934
935 GFK_GL_CELLS (gl)->cells = create_cells_params ();
936 gfk_gl_prepend_params (gl, GFK_GL_CELLS (gl)->cells, gtk_label_new ("Cells"));
937 gtk_widget_show (GFK_GL_CELLS (gl)->cells);
938 }
939
940 GfkGlClass * gfk_gl_cells_class (void)
941 {
942 static GfkGlClass * klass = NULL;
943
944 if (klass == NULL) {
945 GtsObjectClassInfo gfk_gl_cells_info = {
946 "GfkGlCells",
947 sizeof (GfkGlCells),
948 sizeof (GfkGlClass),
949 (GtsObjectClassInitFunc) gl_cells_class_init,
950 (GtsObjectInitFunc) gl_cells_init,
951 (GtsArgSetFunc) NULL,
952 (GtsArgGetFunc) NULL
953 };
954 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl2D_class ()), &gfk_gl_cells_info);
955 }
956
957 return klass;
958 }
959
960 /* GfkGlFractions: Object */
961
962 static gchar * gl_fractions_name (GfkGlClass * klass)
963 {
964 static gchar name[] = "Fractions";
965 return name;
966 }
967
968 static GtkWidget * gl_fractions_icon (GfkGlClass * klass)
969 {
970 return create_pixmap (NULL, "fractions-16x16.png");
971 }
972
973 static void gl_fractions_class_init (GfkGlClass * klass)
974 {
975 klass->gl_class = gfs_gl_fractions_class ();
976 klass->name = gl_fractions_name;
977 klass->icon = gl_fractions_icon;
978 }
979
980 GfkGlClass * gfk_gl_fractions_class (void)
981 {
982 static GfkGlClass * klass = NULL;
983
984 if (klass == NULL) {
985 GtsObjectClassInfo gfk_gl_fractions_info = {
986 "GfkGlFractions",
987 sizeof (GfkGl),
988 sizeof (GfkGlClass),
989 (GtsObjectClassInitFunc) gl_fractions_class_init,
990 (GtsObjectInitFunc) gl_fractions_init,
991 (GtsArgSetFunc) NULL,
992 (GtsArgGetFunc) NULL
993 };
994 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &gfk_gl_fractions_info);
995 }
996
997 return klass;
998 }
999
1000 /* GfkGlBoundaries: Object */
1001
1002 static gchar * gl_boundaries_name (GfkGlClass * klass)
1003 {
1004 static gchar name[] = "Boundaries";
1005 return name;
1006 }
1007
1008 static GtkWidget * gl_boundaries_icon (GfkGlClass * klass)
1009 {
1010 return create_pixmap (NULL, "boundaries-16x16.png");
1011 }
1012
1013 static void gl_boundaries_class_init (GfkGlClass * klass)
1014 {
1015 klass->gl_class = gfs_gl_boundaries_class ();
1016 klass->name = gl_boundaries_name;
1017 klass->icon = gl_boundaries_icon;
1018 }
1019
1020 static void gl_boundaries_init (GfkGl * gl)
1021 {
1022 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading_label"), FALSE);
1023 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading"), FALSE);
1024 }
1025
1026 GfkGlClass * gfk_gl_boundaries_class (void)
1027 {
1028 static GfkGlClass * klass = NULL;
1029
1030 if (klass == NULL) {
1031 GtsObjectClassInfo gfk_gl_boundaries_info = {
1032 "GfkGlBoundaries",
1033 sizeof (GfkGl),
1034 sizeof (GfkGlClass),
1035 (GtsObjectClassInitFunc) gl_boundaries_class_init,
1036 (GtsObjectInitFunc) gl_boundaries_init,
1037 (GtsArgSetFunc) NULL,
1038 (GtsArgGetFunc) NULL
1039 };
1040 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &gfk_gl_boundaries_info);
1041 }
1042
1043 return klass;
1044 }
1045
1046 /* GfkGlLevels: Object */
1047
1048 static gchar * gl_levels_name (GfkGlClass * klass)
1049 {
1050 static gchar name[] = "Levels";
1051 return name;
1052 }
1053
1054 static GtkWidget * gl_levels_icon (GfkGlClass * klass)
1055 {
1056 return create_pixmap (NULL, "levels-16x16.png");
1057 }
1058
1059 static void gl_levels_class_init (GfkGlClass * klass)
1060 {
1061 klass->gl_class = gfs_gl_levels_class ();
1062 klass->name = gl_levels_name;
1063 klass->icon = gl_levels_icon;
1064 }
1065
1066 static void gl_levels_init (GfkGl * gl)
1067 {
1068 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading_label"), FALSE);
1069 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading"), FALSE);
1070 }
1071
1072 GfkGlClass * gfk_gl_levels_class (void)
1073 {
1074 static GfkGlClass * klass = NULL;
1075
1076 if (klass == NULL) {
1077 GtsObjectClassInfo gfk_gl_levels_info = {
1078 "GfkGlLevels",
1079 sizeof (GfkGlLevels),
1080 sizeof (GfkGlClass),
1081 (GtsObjectClassInitFunc) gl_levels_class_init,
1082 (GtsObjectInitFunc) gl_levels_init,
1083 (GtsArgSetFunc) NULL,
1084 (GtsArgGetFunc) NULL
1085 };
1086 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl2D_class ()),
1087 &gfk_gl_levels_info);
1088 }
1089
1090 return klass;
1091 }
1092
1093 /* GfkFunction */
1094
1095 enum {
1096 COMPLETION_NAME_COLUMN,
1097 COMPLETION_DESCRIPTION_COLUMN,
1098 COMPLETION_POINTER_COLUMN
1099 } CompletionColumns;
1100
1101 #define GLADE_HOOKUP_OBJECT(component,widget,name) \
1102 g_object_set_data_full (G_OBJECT (component), name, \
1103 gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
1104
1105 static void on_function_activate (GtkEntry * entry, GfkFunctionSet set)
1106 {
1107 GfkGl * gl = lookup_gl (entry);
1108 const gchar * needle = gtk_entry_get_text (entry);
1109 GtsFile * fp = (*set) (gl, needle);
1110 GtkEntryCompletion * c = gtk_entry_get_completion (entry);
1111 GtkTreeModel * list = gtk_entry_completion_get_model (c);
1112 GtkTreeIter iter;
1113 gboolean valid, found = FALSE;
1114 gchar * haystack;
1115
1116 valid = gtk_tree_model_get_iter_first (list, &iter);
1117 while (valid && !found) {
1118 gtk_tree_model_get (list, &iter, 0, &haystack, -1);
1119 if (!strcmp (haystack, needle)) {
1120 found = TRUE;
1121 break;
1122 }
1123 valid = gtk_tree_model_iter_next (list, &iter);
1124 }
1125
1126 if (fp) {
1127 GtkWidget * view = lookup_widget (gl->list, "view");
1128 GtkWidget * msg = gtk_message_dialog_new (GTK_WINDOW (view),
1129 GTK_DIALOG_DESTROY_WITH_PARENT,
1130 GTK_MESSAGE_WARNING,
1131 GTK_BUTTONS_CLOSE,
1132 "%s",
1133 fp->error);
1134 gts_file_destroy (fp);
1135 gtk_dialog_run (GTK_DIALOG (msg));
1136 gtk_widget_destroy (msg);
1137 if (found)
1138 gtk_list_store_remove (GTK_LIST_STORE (list), &iter);
1139 }
1140 else {
1141 if (!found) {
1142 gtk_list_store_append (GTK_LIST_STORE (list), &iter);
1143 gtk_list_store_set (GTK_LIST_STORE (list), &iter,
1144 COMPLETION_NAME_COLUMN, needle,
1145 COMPLETION_DESCRIPTION_COLUMN, NULL,
1146 COMPLETION_POINTER_COLUMN, NULL,
1147 -1);
1148 }
1149 gfk_gl_update_interface (gl);
1150 g_object_set_data (G_OBJECT (entry), "edited", NULL);
1151 }
1152 }
1153
1154 static void variable_selected (GtkButton * button, GtkEntry * entry)
1155 {
1156 GtkWidget * tree = lookup_widget (GTK_WIDGET (button), "tree");
1157 GtkTreeSelection * select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1158 GtkTreeModel * model;
1159 GtkTreeIter iter;
1160
1161 if (gtk_tree_selection_get_selected (select, &model, &iter)) {
1162 gchar * name;
1163 gtk_tree_model_get (model, &iter, 0, &name, -1);
1164 gtk_entry_set_text (entry, name);
1165 on_function_activate (entry, g_object_get_data (G_OBJECT (entry), "set"));
1166 }
1167 }
1168
1169 static GtkWidget * variables_view (GtkEntry * entry, GtkTreeModel * model, GtkWindow * parent)
1170 {
1171 GtkWidget * variables = create_variables ();
1172
1173 gtk_window_set_transient_for (GTK_WINDOW (variables), parent);
1174 gtk_window_set_position (GTK_WINDOW (variables), GTK_WIN_POS_CENTER_ON_PARENT);
1175 g_signal_connect (G_OBJECT (variables), "delete_event",
1176 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
1177 g_signal_connect_swapped (G_OBJECT (lookup_widget (variables, "cancel")), "clicked",
1178 G_CALLBACK (gtk_widget_hide), variables);
1179 g_signal_connect_swapped (G_OBJECT (lookup_widget (variables, "OK")), "clicked",
1180 G_CALLBACK (gtk_widget_hide), variables);
1181 g_signal_connect (G_OBJECT (lookup_widget (variables, "OK")), "clicked",
1182 G_CALLBACK (variable_selected), entry);
1183
1184 GtkWidget * tree = lookup_widget (variables, "tree");
1185 gtk_tree_view_set_model (GTK_TREE_VIEW (tree), model);
1186 GtkTreeSelection * select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1187 gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
1188
1189 GtkCellRenderer * renderer = gtk_cell_renderer_text_new ();
1190 GtkTreeViewColumn * column =
1191 gtk_tree_view_column_new_with_attributes ("Name", renderer,
1192 "text", COMPLETION_NAME_COLUMN,
1193 NULL);
1194 gtk_tree_view_column_set_resizable (column, TRUE);
1195 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
1196 gtk_tree_view_column_set_fixed_width (column, 80);
1197 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1198
1199 column = gtk_tree_view_column_new_with_attributes ("Description", renderer,
1200 "text", COMPLETION_DESCRIPTION_COLUMN,
1201 NULL);
1202 gtk_tree_view_column_set_resizable (column, TRUE);
1203 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
1204 gtk_tree_view_column_set_fixed_width (column, 80);
1205 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1206
1207 return variables;
1208 }
1209
1210 static gboolean match_selected (GtkEntryCompletion * widget,
1211 GtkTreeModel * model,
1212 GtkTreeIter * iter)
1213 {
1214 GtkWidget * entry = gtk_entry_completion_get_entry (widget);
1215 gchar * text;
1216 gtk_tree_model_get (model, iter, COMPLETION_NAME_COLUMN, &text, -1);
1217 gtk_entry_set_text (GTK_ENTRY (entry), text);
1218 g_signal_emit_by_name (entry, "activate", entry, NULL);
1219 return TRUE;
1220 }
1221
1222 static GtkWidget * gfk_function (GtkWidget * parent,
1223 GfkGl * gl,
1224 const gchar * name,
1225 GfkFunctionSet set)
1226 {
1227 GtkWidget *gfk_function;
1228 GtkWidget *scalar;
1229 GtkWidget *select;
1230
1231 gfk_function = gtk_hbox_new (FALSE, 0);
1232
1233 scalar = gtk_entry_new ();
1234 gtk_widget_show (scalar);
1235 gtk_box_pack_start (GTK_BOX (gfk_function), scalar, TRUE, TRUE, 0);
1236 gtk_entry_set_invisible_char (GTK_ENTRY (scalar), 9679);
1237 g_object_set_data (G_OBJECT (scalar), "set", set);
1238
1239 GtkEntryCompletion * c = gtk_entry_completion_new ();
1240 GtkTreeModel * completion = g_object_get_data (G_OBJECT (lookup_widget (gl->list, "view")),
1241 "completion");
1242 gtk_entry_completion_set_model (c, completion);
1243 gtk_entry_completion_set_text_column (c, COMPLETION_NAME_COLUMN);
1244 g_signal_connect (G_OBJECT (c), "match-selected", G_CALLBACK (match_selected), NULL);
1245 gtk_entry_set_completion (GTK_ENTRY (scalar), c);
1246
1247 select = gtk_button_new_with_mnemonic ("...");
1248 gtk_widget_show (select);
1249 gtk_box_pack_start (GTK_BOX (gfk_function), select, FALSE, FALSE, 0);
1250
1251 GtkWidget * variables = variables_view (GTK_ENTRY (scalar), completion, GTK_WINDOW (gl->params));
1252 GLADE_HOOKUP_OBJECT (select, variables, "variables");
1253 g_signal_connect_swapped ((gpointer) select, "clicked",
1254 G_CALLBACK (gtk_widget_show), variables);
1255
1256 g_signal_connect ((gpointer) scalar, "changed",
1257 G_CALLBACK (mark_edited),
1258 NULL);
1259 g_signal_connect ((gpointer) scalar, "move_cursor",
1260 G_CALLBACK (mark_edited),
1261 NULL);
1262 g_signal_connect ((gpointer) scalar, "activate",
1263 G_CALLBACK (on_function_activate),
1264 set);
1265
1266 /* Store pointers to all widgets, for use by lookup_widget(). */
1267 GLADE_HOOKUP_OBJECT (parent, gfk_function, "gfk_function");
1268 GLADE_HOOKUP_OBJECT (parent, scalar, name);
1269 GLADE_HOOKUP_OBJECT (parent, select, "select");
1270
1271 return gfk_function;
1272 }
1273
1274 /* GfkGlScalar: Object */
1275
1276 static void gl_scalar_read (GtsObject ** o, GtsFile * fp)
1277 {
1278 GtkWidget * scalar = GFK_GL_SCALAR (*o)->scalar;
1279 GfsGlScalar * gl = GFS_GL_SCALAR (GFK_GL (*o)->gl);
1280 GtkWidget * amin = lookup_widget_params (scalar, "amin");
1281 GtkWidget * amax = lookup_widget_params (scalar, "amax");
1282 GtkSpinButton * spinbuttonmin = lookup_widget_params (scalar, "spinbuttonmin");
1283 GtkSpinButton * spinbuttonmax = lookup_widget_params (scalar, "spinbuttonmax");
1284 gdouble maxv = gtk_spin_button_get_value (spinbuttonmax);
1285
1286 (* GTS_OBJECT_CLASS (gfk_gl_scalar_class ())->parent_class->read) (o, fp);
1287 if (fp->type == GTS_ERROR)
1288 return;
1289
1290 if (!gl->amin) {
1291 gl->amin = TRUE;
1292 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (amin), FALSE);
1293 if (gl->amax && gl->min > maxv)
1294 gtk_spin_button_set_value (spinbuttonmax, gl->min);
1295 gtk_spin_button_set_value (spinbuttonmin, gl->min);
1296 }
1297
1298 if (!gl->amax) {
1299 gl->amax = TRUE;
1300 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (amax), FALSE);
1301 gtk_spin_button_set_value (spinbuttonmax, gl->max);
1302 }
1303
1304 if (gl->show) {
1305 gl->show = FALSE;
1306 gtk_toggle_button_set_active
1307 (GTK_TOGGLE_BUTTON (lookup_widget_params (scalar, "show")), TRUE);
1308 }
1309
1310 GtkOptionMenu * colormap = lookup_widget_params (scalar, "colormap");
1311 if (colormap) {
1312 if (!strcmp (gl->cmap->name, "Jet"))
1313 gtk_option_menu_set_history (colormap, 0);
1314 else if (!strcmp (gl->cmap->name, "Cool"))
1315 gtk_option_menu_set_history (colormap, 1);
1316 else if (!strcmp (gl->cmap->name, "Gray"))
1317 gtk_option_menu_set_history (colormap, 2);
1318 }
1319 }
1320
1321 guint gfk_decimal_digits (double x, guint significant)
1322 {
1323 if (x == 0.)
1324 return significant;
1325 else {
1326 gdouble n = significant - 1. - floor (log10 (fabs (x)));
1327 return n > 0 ? n : 0;
1328 }
1329 }
1330
1331 static void set_value (GtkSpinButton * s, gdouble v)
1332 {
1333 GtkAdjustment * as = gtk_spin_button_get_adjustment (s);
1334 if (as->lower > v)
1335 as->lower = v;
1336 if (as->upper < v)
1337 as->upper = v;
1338 gtk_spin_button_set_adjustment (s, as);
1339 gtk_spin_button_set_value (s, v);
1340 }
1341
1342 static void gl_scalar_update_interface (GfkGl * g)
1343 {
1344 GfkGlScalar * gl = GFK_GL_SCALAR (g);
1345 GfsGlScalar * gls = GFS_GL_SCALAR (GFK_GL (gl)->gl);
1346 GtkSpinButton * min = lookup_widget_params (gl->scalar, "spinbuttonmin");
1347 GtkSpinButton * max = lookup_widget_params (gl->scalar, "spinbuttonmax");
1348 GtkEntry * scalar = lookup_widget_params (gl->scalar, "scalar");
1349
1350 if (!GFK_IS_EDITED (scalar))
1351 gtk_entry_set_text (scalar, gls->expr->str);
1352
1353 if (gls->amin)
1354 set_value (min, gls->aminv);
1355 else if (!GFK_IS_EDITED (min))
1356 set_value (min, gls->min);
1357 if (gls->amax)
1358 set_value (max, gls->amaxv);
1359 else if (!GFK_IS_EDITED (max))
1360 set_value (max, gls->max);
1361
1362 if (gls->max > gls->min) {
1363 gdouble step = (gls->max - gls->min)/1000.;
1364 guint digits = gfk_decimal_digits (step, 2);
1365 GtkAdjustment * amin = gtk_spin_button_get_adjustment (min);
1366 GtkAdjustment * amax = gtk_spin_button_get_adjustment (max);
1367 amin->step_increment = amax->step_increment = step;
1368 amin->page_increment = amax->page_increment = step*10.;
1369 if (!GFK_IS_EDITED (min))
1370 gtk_spin_button_configure (min, amin, 2.*step, digits);
1371 if (!GFK_IS_EDITED (max))
1372 gtk_spin_button_configure (max, amax, 2.*step, digits);
1373 }
1374 gfk_gl_update_properties (GFK_GL (gl));
1375 gfk_gl_expose (GFK_GL (gl));
1376 }
1377
1378 static void gl_scalar_set_simulation (GfkGl * object, GfsSimulation * sim)
1379 {
1380 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_scalar_class ())->parent_class)->set_simulation)
1381 (object, sim);
1382
1383 gl_scalar_update_interface (object);
1384 }
1385
1386 static GtsFile * gl_scalar_set (GfkGl * gl, const gchar * s)
1387 {
1388 GtsFile * fp = gfs_gl_scalar_set (GFS_GL_SCALAR (gl->gl), s);
1389 if (!fp)
1390 gl_scalar_update_interface (gl);
1391 return fp;
1392 }
1393
1394 static void gl_scalar_post_init (GfkGl * object)
1395 {
1396 GfkGlScalar * gls = GFK_GL_SCALAR (object);
1397
1398 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_scalar_class ())->parent_class)->post_init) (object);
1399
1400 GtkWidget * scalar = gfk_function (gls->scalar, object, "scalar", gl_scalar_set);
1401 gtk_widget_show (scalar);
1402 gtk_table_attach (GTK_TABLE (lookup_widget_params (gls->scalar, "table1")),
1403 scalar, 1, 3, 0, 1,
1404 (GtkAttachOptions) (GTK_FILL),
1405 (GtkAttachOptions) (0), 0, 0);
1406
1407 gl_scalar_update_interface (object);
1408 }
1409
1410 static gchar * gl_scalar_properties (GfkGl * gl)
1411 {
1412 g_free (gl->props);
1413 gl->props = g_strndup (GFS_GL_SCALAR (gl->gl)->expr->str, MAXLENGTH + 3);
1414 if (strlen (gl->props) > MAXLENGTH) {
1415 guint i;
1416 for (i = 0; i < 3; i++)
1417 gl->props[MAXLENGTH + i] = '.';
1418 }
1419 return gl->props;
1420 }
1421
1422 static gchar * gl_scalar_pickinfo (GfkGl * gl, gboolean motion)
1423 {
1424 gchar * s =
1425 (* GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_scalar_class ())->parent_class)->pickinfo) (gl, motion);
1426 gdouble val = GFS_VALUE (GFS_GL2D (gl->gl)->picked,
1427 GFS_GL_SCALAR (gl->gl)->v);
1428 gchar * s1 = (val != GFS_NODATA ?
1429 g_strdup_printf ("%s %s %g", s, gl_scalar_properties (gl), val) :
1430 g_strdup_printf ("%s %s NODATA", s, gl_scalar_properties (gl))
1431 );
1432 g_free (GFK_GL2D (gl)->pickinfo);
1433 GFK_GL2D (gl)->pickinfo = s1;
1434 return s1;
1435 }
1436
1437 static void gl_scalar_class_init (GfkGlClass * klass)
1438 {
1439 klass->post_init = gl_scalar_post_init;
1440 klass->set_simulation = gl_scalar_set_simulation;
1441 klass->update_interface = gl_scalar_update_interface;
1442 klass->properties = gl_scalar_properties;
1443 klass->pickinfo = gl_scalar_pickinfo;
1444 GTS_OBJECT_CLASS (klass)->read = gl_scalar_read;
1445 }
1446
1447 static void set_cmap_cool_warm (GtkWidget * cmap, GfkGl * gl)
1448 {
1449 gfs_colormap_destroy (GFS_GL_SCALAR (gl->gl)->cmap);
1450 GFS_GL_SCALAR (gl->gl)->cmap = gfs_colormap_cool_warm ();
1451 gfk_gl_expose (gl);
1452 }
1453
1454 static void set_cmap_gray (GtkWidget * cmap, GfkGl * gl)
1455 {
1456 gfs_colormap_destroy (GFS_GL_SCALAR (gl->gl)->cmap);
1457 GFS_GL_SCALAR (gl->gl)->cmap = gfs_colormap_gray ();
1458 gfk_gl_expose (gl);
1459 }
1460
1461 static void set_cmap_jet (GtkWidget * cmap, GfkGl * gl)
1462 {
1463 gfs_colormap_destroy (GFS_GL_SCALAR (gl->gl)->cmap);
1464 GFS_GL_SCALAR (gl->gl)->cmap = gfs_colormap_jet ();
1465 gfk_gl_expose (gl);
1466 }
1467
1468 static void gl_scalar_init (GfkGlScalar * object)
1469 {
1470 GtkOptionMenu * colormap;
1471
1472 object->scalar = create_scalar_params ();
1473 if ((colormap = lookup_widget_params (object->scalar, "colormap"))) {
1474 GtkWidget * m = gtk_menu_new (), * i;
1475
1476 i = gtk_menu_item_new_with_label ("Jet");
1477 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_cmap_jet), object);
1478 gtk_menu_append (m, i);
1479 gtk_widget_show (i);
1480 gtk_option_menu_set_menu (colormap, m);
1481 gtk_widget_show (m);
1482
1483 i = gtk_menu_item_new_with_label ("Cool");
1484 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_cmap_cool_warm), object);
1485 gtk_menu_append (m, i);
1486 gtk_widget_show (i);
1487 gtk_option_menu_set_menu (colormap, m);
1488 gtk_widget_show (m);
1489
1490 i = gtk_menu_item_new_with_label ("Gray");
1491 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_cmap_gray), object);
1492 gtk_menu_append (m, i);
1493 gtk_widget_show (i);
1494 gtk_option_menu_set_menu (colormap, m);
1495 gtk_widget_show (m);
1496 }
1497 gfk_gl_prepend_params (GFK_GL (object), object->scalar, gtk_label_new ("Scalar"));
1498 gtk_widget_show (object->scalar);
1499 }
1500
1501 GfkGlClass * gfk_gl_scalar_class (void)
1502 {
1503 static GfkGlClass * klass = NULL;
1504
1505 if (klass == NULL) {
1506 GtsObjectClassInfo gfk_gl_scalar_info = {
1507 "GfkGlScalar",
1508 sizeof (GfkGlScalar),
1509 sizeof (GfkGlClass),
1510 (GtsObjectClassInitFunc) gl_scalar_class_init,
1511 (GtsObjectInitFunc) gl_scalar_init,
1512 (GtsArgSetFunc) NULL,
1513 (GtsArgGetFunc) NULL
1514 };
1515 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl2D_class ()),
1516 &gfk_gl_scalar_info);
1517 }
1518
1519 return klass;
1520 }
1521
1522 /* GfkGlSquares: Object */
1523
1524 static gchar * gl_squares_name (GfkGlClass * klass)
1525 {
1526 static gchar name[] = "Squares";
1527 return name;
1528 }
1529
1530 static GtkWidget * gl_squares_icon (GfkGlClass * klass)
1531 {
1532 return create_pixmap (NULL, "squares-16x16.png");
1533 }
1534
1535 static void gl_squares_class_init (GfkGlClass * klass)
1536 {
1537 klass->gl_class = gfs_gl_squares_class ();
1538 klass->name = gl_squares_name;
1539 klass->icon = gl_squares_icon;
1540 }
1541
1542 static void gl_squares_init (GfkGl * gl)
1543 {
1544 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color_label"), FALSE);
1545 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color"), FALSE);
1546 }
1547
1548 GfkGlClass * gfk_gl_squares_class (void)
1549 {
1550 static GfkGlClass * klass = NULL;
1551
1552 if (klass == NULL) {
1553 GtsObjectClassInfo gfk_gl_squares_info = {
1554 "GfkGlSquares",
1555 sizeof (GfkGlSquares),
1556 sizeof (GfkGlClass),
1557 (GtsObjectClassInitFunc) gl_squares_class_init,
1558 (GtsObjectInitFunc) gl_squares_init,
1559 (GtsArgSetFunc) NULL,
1560 (GtsArgGetFunc) NULL
1561 };
1562 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_scalar_class ()),
1563 &gfk_gl_squares_info);
1564 }
1565
1566 return klass;
1567 }
1568
1569 /* GfkGlLinear: Object */
1570
1571 static void update_linear_color (GfkGl * gl)
1572 {
1573 gfk_gl_set_sensitive (GFK_GL (gl), GFK_GL_SCALAR (gl)->scalar, FALSE);
1574 gfk_gl_update_properties (GFK_GL (gl));
1575 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color_label"),
1576 TRUE);
1577 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color"), TRUE);
1578 }
1579
1580 static void gl_linear_read (GtsObject ** o, GtsFile * fp)
1581 {
1582 GtkWidget * scalar = GFK_GL_LINEAR (*o)->scalar;
1583 GfsGlLinear * gl = GFS_GL_LINEAR (GFK_GL (*o)->gl);
1584
1585 (* GTS_OBJECT_CLASS (gfk_gl_linear_class ())->parent_class->read) (o, fp);
1586 if (fp->type == GTS_ERROR)
1587 return;
1588
1589 if (gl->reversed) {
1590 gl->reversed = FALSE;
1591 gtk_toggle_button_set_active (lookup_widget_params (scalar, "reversed"), TRUE);
1592 }
1593
1594 if (!gl->use_scalar) {
1595 gtk_option_menu_set_history (lookup_widget_params (scalar, "color"), 0);
1596 update_linear_color (GFK_GL (*o));
1597 }
1598 }
1599
1600 static gchar * gl_linear_properties (GfkGl * gl)
1601 {
1602 GfsGlLinear * gll = GFS_GL_LINEAR (gl->gl);
1603 gchar * s;
1604 if (gll->vf->f && gfs_function_get_constant_value (gll->vf->f) != 0.)
1605 s = g_strjoin (" ",
1606 gll->expr->str,
1607 gll->use_scalar ?
1608 ((* gfk_gl_scalar_class ()->properties) (gl)) : NULL,
1609 NULL);
1610 else
1611 s = g_strjoin (" ",
1612 gll->use_scalar ?
1613 ((* gfk_gl_scalar_class ()->properties) (gl)) : NULL,
1614 NULL);
1615 g_free (gl->props);
1616 gl->props = s;
1617 return gl->props;
1618 }
1619
1620 static gchar * gl_linear_name (GfkGlClass * klass)
1621 {
1622 static gchar name[] = "Linear";
1623 return name;
1624 }
1625
1626 static GtkWidget * gl_linear_icon (GfkGlClass * klass)
1627 {
1628 return create_pixmap (NULL, "linear-16x16.png");
1629 }
1630
1631 static gchar * gl_linear_pickinfo (GfkGl * gl, gboolean motion)
1632 {
1633 gchar * s =
1634 (* GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_scalar_class ())->parent_class)->pickinfo)
1635 (gl, motion);
1636 gchar * s1 = GFS_VALUE (GFS_GL2D (gl->gl)->picked, GFS_GL_SCALAR (gl->gl)->v) != GFS_NODATA ?
1637 g_strdup_printf ("%s %s %g", s, gl_scalar_properties (gl),
1638 gfs_interpolate (GFS_GL2D (gl->gl)->picked,
1639 GFS_GL2D (gl->gl)->pickedpos,
1640 GFS_GL_SCALAR (gl->gl)->v)) :
1641 g_strdup_printf ("%s %s NODATA", s, gl_scalar_properties (gl));
1642 g_free (GFK_GL2D (gl)->pickinfo);
1643 GFK_GL2D (gl)->pickinfo = s1;
1644 return s1;
1645 }
1646
1647 static void gl_linear_update_interface (GfkGl * g)
1648 {
1649 GfkGlLinear * gl = GFK_GL_LINEAR (g);
1650 GfsGlLinear * gli = GFS_GL_LINEAR (GFK_GL (gl)->gl);
1651 GtkEntry * scalar = lookup_widget_params (gl->scalar, "scalar");
1652
1653 if (!GFK_IS_EDITED (scalar))
1654 gtk_entry_set_text (scalar, gli->expr->str);
1655
1656 gfk_gl_update_properties (GFK_GL (gl));
1657 gfk_gl_expose (GFK_GL (gl));
1658 }
1659
1660 static void gl_linear_set_simulation (GfkGl * object, GfsSimulation * sim)
1661 {
1662 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_linear_class ())->parent_class)->set_simulation)
1663 (object, sim);
1664
1665 gl_linear_update_interface (object);
1666 }
1667
1668 static void set_linear_scalar (GtkWidget * scalar, GfkGl * gl)
1669 {
1670 GFS_GL_LINEAR (gl->gl)->use_scalar = GFS_GL_SCALAR (gl->gl)->v;
1671 gfk_gl_set_sensitive (gl, GFK_GL_SCALAR (gl)->scalar, TRUE);
1672 gfk_gl_update_properties (gl);
1673 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color_label"), FALSE);
1674 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color"), FALSE);
1675 gfk_gl_expose (gl);
1676 }
1677
1678 static void set_linear_color (GtkWidget * color, GfkGlLinear * gl)
1679 {
1680 GFS_GL_LINEAR (GFK_GL (gl)->gl)->use_scalar = NULL;
1681 update_linear_color (GFK_GL (gl));
1682 gfk_gl_expose (GFK_GL (gl));
1683 }
1684
1685 static GtsFile * gl_linear_set (GfkGl * gl, const char * s)
1686 {
1687 return gfs_gl_linear_set (GFS_GL_LINEAR (gl->gl), s);
1688 }
1689
1690 static void gl_linear_post_init (GfkGl * object)
1691 {
1692 GfkGlLinear * gli = GFK_GL_LINEAR (object);
1693
1694 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_linear_class ())->parent_class)->post_init)
1695 (object);
1696
1697 GtkWidget * scalar = gfk_function (gli->scalar, object, "scalar", gl_linear_set);
1698 gtk_widget_show (scalar);
1699 gtk_table_attach (GTK_TABLE (lookup_widget_params (gli->scalar, "table1")),
1700 scalar, 1, 3, 0, 1,
1701 (GtkAttachOptions) (GTK_FILL),
1702 (GtkAttachOptions) (0), 0, 0);
1703
1704 gl_linear_update_interface (object);
1705 }
1706
1707 static void gl_linear_class_init (GfkGlClass * klass)
1708 {
1709 GTS_OBJECT_CLASS (klass)->read = gl_linear_read;
1710 klass->gl_class = gfs_gl_linear_class ();
1711 klass->set_simulation = gl_linear_set_simulation;
1712 klass->update_interface = gl_linear_update_interface;
1713 klass->post_init = gl_linear_post_init;
1714 klass->properties = gl_linear_properties;
1715 klass->name = gl_linear_name;
1716 klass->icon = gl_linear_icon;
1717 klass->pickinfo = gl_linear_pickinfo;
1718 }
1719
1720 static void gl_linear_init (GfkGl * gl)
1721 {
1722 GfkGlLinear * gls = GFK_GL_LINEAR (gl);
1723 gls->scalar = create_linear_params ();
1724
1725 GtkWidget * m = gtk_menu_new ();
1726 GtkWidget * i = gtk_menu_item_new_with_label ("Default");
1727 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_linear_color), gl);
1728 gtk_menu_append (m, i);
1729 gtk_widget_show (i);
1730
1731 i = gtk_menu_item_new_with_label ("Scalar");
1732 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_linear_scalar), gl);
1733 gtk_menu_append (m, i);
1734 gtk_widget_show (i);
1735
1736 gtk_option_menu_set_menu (lookup_widget_params (gls->scalar, "color"), m);
1737 gtk_option_menu_set_history (lookup_widget_params (gls->scalar, "color"), 1);
1738 gtk_widget_show (m);
1739 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color_label"), FALSE);
1740 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color"), FALSE);
1741
1742 gfk_gl_prepend_params (gl, gls->scalar, gtk_label_new ("Linear"));
1743 #if FTT_2D
1744 gtk_widget_show (gls->scalar);
1745 #endif
1746 }
1747
1748 GfkGlClass * gfk_gl_linear_class (void)
1749 {
1750 static GfkGlClass * klass = NULL;
1751
1752 if (klass == NULL) {
1753 GtsObjectClassInfo gfk_gl_linear_info = {
1754 "GfkGlLinear",
1755 sizeof (GfkGlLinear),
1756 sizeof (GfkGlClass),
1757 (GtsObjectClassInitFunc) gl_linear_class_init,
1758 (GtsObjectInitFunc) gl_linear_init,
1759 (GtsArgSetFunc) NULL,
1760 (GtsArgGetFunc) NULL
1761 };
1762 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_scalar_class ()),
1763 &gfk_gl_linear_info);
1764 }
1765
1766 return klass;
1767 }
1768
1769 /* GfkGlIsoline: Object */
1770
1771 static void gl_isoline_read (GtsObject ** o, GtsFile * fp)
1772 {
1773 GtkWidget * scalar = GFK_GL_SCALAR (*o)->scalar;
1774 GfsGlIsoline * gl = GFS_GL_ISOLINE (GFK_GL (*o)->gl);
1775
1776 (* GTS_OBJECT_CLASS (gfk_gl_isoline_class ())->parent_class->read) (o, fp);
1777 if (fp->type == GTS_ERROR)
1778 return;
1779
1780 gtk_spin_button_set_value (lookup_widget_params (scalar, "spinbuttoniso"), gl->n);
1781 if (gl->ls)
1782 gtk_entry_set_text (lookup_widget_params (scalar, "entryiso"), gl->ls);
1783 }
1784
1785 static gchar * gl_isoline_name (GfkGlClass * klass)
1786 {
1787 static gchar name[] = "Isoline";
1788 return name;
1789 }
1790
1791 static GtkWidget * gl_isoline_icon (GfkGlClass * klass)
1792 {
1793 return create_pixmap (NULL, "isoline-16x16.png");
1794 }
1795
1796 static void gl_isoline_class_init (GfkGlClass * klass)
1797 {
1798 GTS_OBJECT_CLASS (klass)->read = gl_isoline_read;
1799 klass->gl_class = gfs_gl_isoline_class ();
1800 klass->name = gl_isoline_name;
1801 klass->icon = gl_isoline_icon;
1802 }
1803
1804 static void gl_isoline_init (GfkGl * gl)
1805 {
1806 GfkGlScalar * gls = GFK_GL_SCALAR (gl);
1807 gtk_widget_destroy (gls->scalar);
1808 gls->scalar = create_isoline_params ();
1809 gfk_gl_prepend_params (gl, gls->scalar, gtk_label_new ("Isoline"));
1810 gtk_widget_show (gls->scalar);
1811 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading_label"), FALSE);
1812 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading"), FALSE);
1813
1814 gtk_option_menu_set_history (lookup_widget_params (GFK_GL_LINEAR (gl)->scalar, "color"), 0);
1815 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL_LINEAR (gl)->scalar, "normals"), FALSE);
1816 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL_LINEAR (gl)->scalar, "reversed"), FALSE);
1817 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color_label"),
1818 TRUE);
1819 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color"), TRUE);
1820 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL_LINEAR (gl)->scalar, "color"), FALSE);
1821 }
1822
1823 GfkGlClass * gfk_gl_isoline_class (void)
1824 {
1825 static GfkGlClass * klass = NULL;
1826
1827 if (klass == NULL) {
1828 GtsObjectClassInfo gfk_gl_isoline_info = {
1829 "GfkGlIsoline",
1830 sizeof (GfkGlIsoline),
1831 sizeof (GfkGlClass),
1832 (GtsObjectClassInitFunc) gl_isoline_class_init,
1833 (GtsObjectInitFunc) gl_isoline_init,
1834 (GtsArgSetFunc) NULL,
1835 (GtsArgGetFunc) NULL
1836 };
1837 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_linear_class ()),
1838 &gfk_gl_isoline_info);
1839 }
1840
1841 return klass;
1842 }
1843
1844 /* GfkGlVOF: Object */
1845
1846 static void update_vof_scalar (GfkGl * gl)
1847 {
1848 gfk_gl_set_sensitive (gl, GFK_GL_SCALAR (gl)->scalar, TRUE);
1849 gfk_gl_update_properties (gl);
1850 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color_label"), FALSE);
1851 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "default_color"), FALSE);
1852 }
1853
1854 static void gl_vof_read (GtsObject ** o, GtsFile * fp)
1855 {
1856 GtkWidget * scalar = GFK_GL_VOF (*o)->scalar;
1857 GfsGlVOF * gl = GFS_GL_VOF (GFK_GL (*o)->gl);
1858
1859 (* GTS_OBJECT_CLASS (gfk_gl_vof_class ())->parent_class->read) (o, fp);
1860 if (fp->type == GTS_ERROR)
1861 return;
1862
1863 if (gl->reversed) {
1864 gl->reversed = FALSE;
1865 gtk_toggle_button_set_active (lookup_widget_params (scalar, "reversed"), TRUE);
1866 }
1867
1868 if (gl->draw_edges) {
1869 gl->draw_edges = FALSE;
1870 gtk_toggle_button_set_active (lookup_widget_params (scalar, "visible"), TRUE);
1871 }
1872
1873 if (gl->use_scalar) {
1874 gtk_option_menu_set_history (lookup_widget_params (scalar, "color"), gl->interpolate ? 2 : 1);
1875 update_vof_scalar (GFK_GL (*o));
1876 }
1877 }
1878
1879 static gchar * gl_vof_name (GfkGlClass * klass)
1880 {
1881 static gchar name[] = "VOF";
1882 return name;
1883 }
1884
1885 static GtkWidget * gl_vof_icon (GfkGlClass * klass)
1886 {
1887 return create_pixmap (NULL, "vof-16x16.png");
1888 }
1889
1890 static void gl_vof_update_interface (GfkGl * g)
1891 {
1892 GfkGlVOF * gl = GFK_GL_VOF (g);
1893 GfsGlVOF * gli = GFS_GL_VOF (GFK_GL (gl)->gl);
1894 GtkEntry * scalar = lookup_widget_params (gl->scalar, "scalar");
1895
1896 if (!GFK_IS_EDITED (scalar))
1897 gtk_entry_set_text (scalar, gli->expr->str);
1898
1899 gfk_gl_update_properties (GFK_GL (gl));
1900 gfk_gl_expose (GFK_GL (gl));
1901 }
1902
1903 static void gl_vof_set_simulation (GfkGl * object, GfsSimulation * sim)
1904 {
1905 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_vof_class ())->parent_class)->set_simulation)
1906 (object, sim);
1907
1908 gl_vof_update_interface (object);
1909 }
1910
1911 static void set_vof_scalar (GtkWidget * scalar, GfkGl * gl)
1912 {
1913 GFS_GL_VOF (gl->gl)->use_scalar = GFS_GL_SCALAR (gl->gl)->v;
1914 GFS_GL_VOF (gl->gl)->interpolate = FALSE;
1915 update_vof_scalar (gl);
1916 gfk_gl_expose (gl);
1917 }
1918
1919 static void set_vof_scalar_interpolated (GtkWidget * scalar, GfkGl * gl)
1920 {
1921 GFS_GL_VOF (gl->gl)->use_scalar = GFS_GL_SCALAR (gl->gl)->v;
1922 GFS_GL_VOF (gl->gl)->interpolate = TRUE;
1923 update_vof_scalar (gl);
1924 gfk_gl_expose (gl);
1925 }
1926
1927 static void set_vof_color (GtkWidget * color, GfkGlVOF * gl)
1928 {
1929 GFS_GL_VOF (GFK_GL (gl)->gl)->use_scalar = NULL;
1930 gfk_gl_set_sensitive (GFK_GL (gl), GFK_GL_SCALAR (gl)->scalar, FALSE);
1931 gfk_gl_update_properties (GFK_GL (gl));
1932 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color_label"),
1933 TRUE);
1934 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color"), TRUE);
1935 gfk_gl_expose (GFK_GL (gl));
1936 }
1937
1938 static GtsFile * gl_vof_set (GfkGl * gl, const gchar * s)
1939 {
1940 return gfs_gl_vof_set (GFS_GL_VOF (gl->gl), s);
1941 }
1942
1943 static void gl_vof_post_init (GfkGl * object)
1944 {
1945 GfkGlVOF * gli = GFK_GL_VOF (object);
1946
1947 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_vof_class ())->parent_class)->post_init)
1948 (object);
1949
1950 GtkWidget * scalar = gfk_function (gli->scalar, object, "scalar", gl_vof_set);
1951 gtk_widget_show (scalar);
1952 gtk_table_attach (GTK_TABLE (lookup_widget_params (gli->scalar, "table1")),
1953 scalar, 1, 3, 0, 1,
1954 (GtkAttachOptions) (GTK_FILL),
1955 (GtkAttachOptions) (0), 0, 0);
1956
1957 gl_vof_update_interface (object);
1958 }
1959
1960 static gchar * gl_vof_properties (GfkGl * gl)
1961 {
1962 gchar * s = g_strjoin (" ",
1963 GFS_GL_VOF (gl->gl)->expr->str,
1964 GFS_GL_VOF (gl->gl)->use_scalar ?
1965 ((* gfk_gl_scalar_class ()->properties) (gl)) : NULL,
1966 NULL);
1967 g_free (gl->props);
1968 gl->props = s;
1969 return gl->props;
1970 }
1971
1972 static void gl_vof_class_init (GfkGlClass * klass)
1973 {
1974 GTS_OBJECT_CLASS (klass)->read = gl_vof_read;
1975 klass->gl_class = gfs_gl_vof_class ();
1976 klass->set_simulation = gl_vof_set_simulation;
1977 klass->update_interface = gl_vof_update_interface;
1978 klass->post_init = gl_vof_post_init;
1979 klass->properties = gl_vof_properties;
1980 klass->name = gl_vof_name;
1981 klass->icon = gl_vof_icon;
1982 }
1983
1984 static void gl_vof_init (GfkGl * gl)
1985 {
1986 GfkGlVOF * gli = GFK_GL_VOF (gl);
1987
1988 gli->scalar = create_vof_params ();
1989
1990 gfk_gl_set_sensitive (gl, GFK_GL_SCALAR (gl)->scalar, FALSE);
1991
1992 GtkWidget * m = gtk_menu_new ();
1993 GtkWidget * i = gtk_menu_item_new_with_label ("Default");
1994 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_vof_color), gl);
1995 gtk_menu_append (m, i);
1996 gtk_widget_show (i);
1997
1998 i = gtk_menu_item_new_with_label ("Scalar");
1999 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_vof_scalar), gl);
2000 gtk_menu_append (m, i);
2001 gtk_widget_show (i);
2002
2003 i = gtk_menu_item_new_with_label ("Scalar (interpolated)");
2004 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_vof_scalar_interpolated), gl);
2005 gtk_menu_append (m, i);
2006 gtk_widget_show (i);
2007
2008 gtk_option_menu_set_menu (lookup_widget_params (gli->scalar, "color"), m);
2009 gtk_widget_show (m);
2010
2011 #if FTT_2D
2012 gtk_widget_hide (lookup_widget_params (gli->scalar, "normals"));
2013 gtk_widget_hide (lookup_widget_params (gli->scalar, "reversed"));
2014 gtk_widget_hide (lookup_widget_params (gli->scalar, "edges"));
2015 gtk_widget_hide (lookup_widget_params (gli->scalar, "visible"));
2016 #else
2017 gtk_widget_hide (GFK_GL2D (gl)->params);
2018 #endif
2019
2020 gfk_gl_prepend_params (gl, gli->scalar, gtk_label_new ("VOF"));
2021 gtk_widget_show (gli->scalar);
2022 }
2023
2024 GfkGlClass * gfk_gl_vof_class (void)
2025 {
2026 static GfkGlClass * klass = NULL;
2027
2028 if (klass == NULL) {
2029 GtsObjectClassInfo gfk_gl_vof_info = {
2030 "GfkGlVOF",
2031 sizeof (GfkGlVOF),
2032 sizeof (GfkGlClass),
2033 (GtsObjectClassInitFunc) gl_vof_class_init,
2034 (GtsObjectInitFunc) gl_vof_init,
2035 (GtsArgSetFunc) NULL,
2036 (GtsArgGetFunc) NULL
2037 };
2038 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_scalar_class ()),
2039 &gfk_gl_vof_info);
2040 }
2041
2042 return klass;
2043 }
2044
2045 /* GfkGlVectors: Object */
2046
2047 static void set_vector_color (GtkWidget * color, GfkGlVectors * gl)
2048 {
2049 GFS_GL_VECTORS (GFK_GL (gl)->gl)->use_scalar = FALSE;
2050 gfk_gl_set_sensitive (GFK_GL (gl), GFK_GL_SCALAR (gl)->scalar, FALSE);
2051 gfk_gl_update_properties (GFK_GL (gl));
2052 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color_label"),
2053 TRUE);
2054 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color"), TRUE);
2055 gfk_gl_expose (GFK_GL (gl));
2056 }
2057
2058 static void update_vector_scalar (GfkGlVectors * gl)
2059 {
2060 gfk_gl_set_sensitive (GFK_GL (gl), GFK_GL_SCALAR (gl)->scalar, TRUE);
2061 gfk_gl_update_properties (GFK_GL (gl));
2062 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color_label"),
2063 FALSE);
2064 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color"),
2065 FALSE);
2066 }
2067
2068 static void set_vector_scalar (GtkWidget * scalar, GfkGlVectors * gl)
2069 {
2070 GFS_GL_VECTORS (GFK_GL (gl)->gl)->use_scalar = TRUE;
2071 update_vector_scalar (gl);
2072 gfk_gl_expose (GFK_GL (gl));
2073 }
2074
2075 static void gl_vectors_read (GtsObject ** o, GtsFile * fp)
2076 {
2077 GtkWidget * vector = GFK_GL_VECTORS (*o)->vector;
2078 GfsGlVectors * gl = GFS_GL_VECTORS (GFK_GL (*o)->gl);
2079
2080 (* GTS_OBJECT_CLASS (gfk_gl_vectors_class ())->parent_class->read) (o, fp);
2081 if (fp->type == GTS_ERROR)
2082 return;
2083
2084 gtk_spin_button_set_value (lookup_widget_params (vector, "scale"), gl->scale);
2085
2086 if (gl->use_scalar) {
2087 gtk_option_menu_set_history (lookup_widget_params (vector, "color"), 1);
2088 update_vector_scalar (GFK_GL_VECTORS (*o));
2089 }
2090 }
2091
2092 static void gl_vectors_update_interface (GfkGlVectors * gl)
2093 {
2094 GfsGlVectors * glv = GFS_GL_VECTORS (GFK_GL (gl)->gl);
2095 GtkSpinButton * scale = lookup_widget_params (gl->vector, "scale");
2096 GtkAdjustment * ascale = gtk_spin_button_get_adjustment (scale);
2097 FttComponent c;
2098
2099 for (c = 0; c < FTT_DIMENSION; c++) {
2100 static gchar * name[] = {"Vx", "Vy", "Vz"};
2101 GtkEntry * entry = lookup_widget_params (gl->vector, name[c]);
2102 if (!GFK_IS_EDITED (entry))
2103 gtk_entry_set_text (entry, glv->expr[c]->str);
2104 }
2105
2106 ascale->upper = glv->max > 0. ? 10000.*glv->h/glv->max : 1.;
2107 ascale->step_increment = glv->max > 0. ? glv->h/glv->max/10. : 0.1;
2108 ascale->page_increment = 10.*ascale->step_increment;
2109 ascale->value = glv->scale;
2110 if (!GFK_IS_EDITED (scale))
2111 gtk_spin_button_configure (scale, ascale, 2.*ascale->step_increment,
2112 gfk_decimal_digits (ascale->step_increment, 2));
2113 gfk_gl_update_properties (GFK_GL (gl));
2114 gfk_gl_expose (GFK_GL (gl));
2115 }
2116
2117 static void gl_vectors_set_simulation (GfkGl * object, GfsSimulation * sim)
2118 {
2119 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_vectors_class ())->parent_class)->set_simulation)
2120 (object, sim);
2121
2122 gl_vectors_update_interface (GFK_GL_VECTORS (object));
2123 }
2124
2125 static GtsFile * set_x (GfkGl * gl, const gchar * func)
2126 {
2127 return gfs_gl_vectors_set (GFS_GL_VECTORS (gl->gl), 0, func);
2128 }
2129
2130 static GtsFile * set_y (GfkGl * gl, const gchar * func)
2131 {
2132 return gfs_gl_vectors_set (GFS_GL_VECTORS (gl->gl), 1, func);
2133 }
2134
2135 static GtsFile * set_z (GfkGl * gl, const gchar * func)
2136 {
2137 return gfs_gl_vectors_set (GFS_GL_VECTORS (gl->gl), 2, func);
2138 }
2139
2140 static void gl_vectors_post_init (GfkGl * object)
2141 {
2142 GfkGlVectors * gls = GFK_GL_VECTORS (object);
2143 FttComponent c;
2144
2145 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_vectors_class ())->parent_class)->post_init) (object);
2146
2147 GtkTable * table = GTK_TABLE (lookup_widget_params (gls->vector, "table2"));
2148 for (c = 0; c < FTT_DIMENSION; c++) {
2149 static gchar * name[] = {"Vx", "Vy", "Vz"};
2150 static GfkFunctionSet func[] = {set_x, set_y, set_z};
2151
2152 GtkWidget * scalar = gfk_function (gls->vector, object, name[c], func[c]);
2153 gtk_widget_show (scalar);
2154 gtk_table_attach (table, scalar, 1, 2, c, c + 1,
2155 (GtkAttachOptions) (GTK_FILL),
2156 (GtkAttachOptions) (0), 0, 0);
2157
2158 GtkWidget * label = gtk_label_new (name[c]);
2159 gtk_widget_show (label);
2160 gtk_table_attach (table, label, 0, 1, c, c + 1,
2161 (GtkAttachOptions) (GTK_FILL),
2162 (GtkAttachOptions) (0), 0, 0);
2163 }
2164
2165 gl_vectors_update_interface (gls);
2166 }
2167
2168 static gchar * gl_vectors_name (GfkGlClass * klass)
2169 {
2170 static gchar name[] = "Vectors";
2171 return name;
2172 }
2173
2174 static GtkWidget * gl_vectors_icon (GfkGlClass * klass)
2175 {
2176 return create_pixmap (NULL, "vectors-16x16.png");
2177 }
2178
2179 static gchar * gl_vectors_properties (GfkGl * gl)
2180 {
2181 gchar * f[3] = { NULL, NULL, NULL };
2182 FttComponent c;
2183
2184 g_free (gl->props);
2185 for (c = 0; c < FTT_DIMENSION; c++)
2186 f[c] = GFS_GL_VECTORS (gl->gl)->expr[c]->str;
2187 gl->props = g_strjoin (",", f[0], f[1], f[2], NULL);
2188 return gl->props;
2189 }
2190
2191 static void gl_vectors_class_init (GfkGlClass * klass)
2192 {
2193 GTS_OBJECT_CLASS (klass)->read = gl_vectors_read;
2194 klass->gl_class = gfs_gl_vectors_class ();
2195 klass->post_init = gl_vectors_post_init;
2196 klass->set_simulation = gl_vectors_set_simulation;
2197 klass->name = gl_vectors_name;
2198 klass->icon = gl_vectors_icon;
2199 klass->properties = gl_vectors_properties;
2200 }
2201
2202 static void gl_vectors_init (GfkGlVectors * object)
2203 {
2204 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (object)->properties, "shading_label"),
2205 FALSE);
2206 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (object)->properties, "shading"), FALSE);
2207 object->vector = create_vector_params ();
2208 gfk_gl_set_sensitive (GFK_GL (object), GFK_GL_SCALAR (object)->scalar, FALSE);
2209
2210 GtkWidget * m = gtk_menu_new ();
2211 GtkWidget * i = gtk_menu_item_new_with_label ("Default");
2212 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_vector_color), object);
2213 gtk_menu_append (m, i);
2214 gtk_widget_show (i);
2215
2216 i = gtk_menu_item_new_with_label ("Scalar");
2217 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_vector_scalar), object);
2218 gtk_menu_append (m, i);
2219 gtk_widget_show (i);
2220
2221 gtk_option_menu_set_menu (lookup_widget_params (object->vector, "color"), m);
2222 gtk_widget_show (m);
2223
2224 gfk_gl_prepend_params (GFK_GL (object), object->vector, gtk_label_new ("Vector"));
2225 gtk_widget_show (object->vector);
2226 }
2227
2228 GfkGlClass * gfk_gl_vectors_class (void)
2229 {
2230 static GfkGlClass * klass = NULL;
2231
2232 if (klass == NULL) {
2233 GtsObjectClassInfo gfk_gl_vectors_info = {
2234 "GfkGlVectors",
2235 sizeof (GfkGlVectors),
2236 sizeof (GfkGlClass),
2237 (GtsObjectClassInitFunc) gl_vectors_class_init,
2238 (GtsObjectInitFunc) gl_vectors_init,
2239 (GtsArgSetFunc) NULL,
2240 (GtsArgGetFunc) NULL
2241 };
2242 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_scalar_class ()),
2243 &gfk_gl_vectors_info);
2244 }
2245
2246 return klass;
2247 }
2248
2249 /* GfkGlStreamlines: Object */
2250
2251 static void gl_streamlines_read (GtsObject ** o, GtsFile * fp)
2252 {
2253 GtkWidget * stream = GFK_GL_STREAMLINES (*o)->stream;
2254 GfsGlStreamlines * gl = GFS_GL_STREAMLINES (GFK_GL (*o)->gl);
2255
2256 (* GTS_OBJECT_CLASS (gfk_gl_streamlines_class ())->parent_class->read) (o, fp);
2257 if (fp->type == GTS_ERROR)
2258 return;
2259
2260 if (!gl->show_cells)
2261 gtk_toggle_button_set_active (lookup_widget_params (stream, "showcells"), FALSE);
2262 gtk_spin_button_set_value (lookup_widget_params (stream, "dmin"), gl->dmin);
2263 if (gl->dmin > 0.)
2264 gtk_widget_set_sensitive (lookup_widget_params (stream, "evenly_spaced"), TRUE);
2265 gtk_spin_button_set_value (lookup_widget_params (stream, "radius"), gl->radius);
2266 }
2267
2268 static gchar * gl_streamlines_name (GfkGlClass * klass)
2269 {
2270 static gchar name[] = "Stream";
2271 return name;
2272 }
2273
2274 static GtkWidget * gl_streamlines_icon (GfkGlClass * klass)
2275 {
2276 return create_pixmap (NULL, "stream-16x16.png");
2277 }
2278
2279 static void snap_to_spacing (GfsGlStreamlines * gls)
2280 {
2281 if (gls->dmin > 0.) {
2282 FttVector * picked = &GFS_GL2D (gls)->pickedpos;
2283 GtsPoint p;
2284
2285 if (gfs_gl_streamlines_closest (gls, picked, &p) < G_MAXDOUBLE) {
2286 GtsVector n;
2287 gts_vector_init (n, &p, picked);
2288 gts_vector_normalize (n);
2289 picked->x = p.x + gls->dmin*n[0];
2290 picked->y = p.y + gls->dmin*n[1];
2291 picked->z = p.z + gls->dmin*n[2];
2292 }
2293 }
2294 }
2295
2296 static gchar * gl_streamlines_pickinfo (GfkGl * gl, gboolean motion)
2297 {
2298 GfkGlStreamlines * glk = GFK_GL_STREAMLINES (gl);
2299 GfsGlStreamlines * gls = GFS_GL_STREAMLINES (gl->gl);
2300 gboolean snapspacing = FALSE;
2301
2302 if (gtk_toggle_button_get_active (lookup_widget_params (glk->stream, "snapcenters"))) {
2303 FttCell * cell = GFS_GL2D (gls)->picked;
2304
2305 while (gl->gl->maxlevel >= 0 && gl->gl->maxlevel < ftt_cell_level (cell))
2306 cell = ftt_cell_parent (cell);
2307 ftt_cell_pos (cell, &GFS_GL2D (gls)->pickedpos);
2308 }
2309 else
2310 snapspacing = gtk_toggle_button_get_active (lookup_widget_params (glk->stream, "snapspacing"));
2311
2312 if (motion) {
2313 if (gls->selected) {
2314 GfsGlStreamline * s = gls->selected->data;
2315
2316 gfs_gl_streamlines_reset_selected (gls);
2317 if (snapspacing)
2318 snap_to_spacing (gls);
2319 s->c = GFS_GL2D (gls)->pickedpos;
2320 gfk_gl_expose (gl);
2321 }
2322 }
2323 else if (!glk->edit) {
2324 if (!gls->selected)
2325 gtk_widget_set_sensitive (lookup_widget_params (glk->stream, "delete"), TRUE);
2326 if (snapspacing)
2327 snap_to_spacing (gls);
2328 if (gfs_gl_streamlines_add (gls, GFS_GL2D (gls)->pickedpos))
2329 gfk_gl_expose (gl);
2330 }
2331 else if (gls->candidate) {
2332 if (gls->candidate != gls->selected) {
2333 if (!gls->selected)
2334 gtk_widget_set_sensitive (lookup_widget_params (glk->stream, "delete"), TRUE);
2335 gls->selected = gls->candidate;
2336 gfk_gl_expose (gl);
2337 }
2338 }
2339 else if (gls->selected) {
2340 gtk_widget_set_sensitive (lookup_widget_params (glk->stream, "delete"), FALSE);
2341 gls->selected = NULL;
2342 gfk_gl_expose (gl);
2343 }
2344 return gl2D_pickinfo (gl, motion);
2345 }
2346
2347 static void streamlines_changed (GtkEntry * entry, GfsGlStreamlines * gl)
2348 {
2349 gfs_gl_streamlines_reset (gl);
2350 }
2351
2352 static void gl_streamlines_post_init (GfkGl * object)
2353 {
2354 FttComponent c;
2355
2356 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_streamlines_class ())->parent_class)->post_init)
2357 (object);
2358
2359 for (c = 0; c < FTT_DIMENSION; c++) {
2360 static gchar * name[] = {"Vx", "Vy", "Vz"};
2361 GtkWidget * entry = lookup_widget_params (GFK_GL_VECTORS (object)->vector, name[c]);
2362
2363 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (streamlines_changed), object->gl);
2364 }
2365 }
2366
2367 static void gl_streamlines_class_init (GfkGlClass * klass)
2368 {
2369 GTS_OBJECT_CLASS (klass)->read = gl_streamlines_read;
2370 klass->gl_class = gfs_gl_streamlines_class ();
2371 klass->name = gl_streamlines_name;
2372 klass->icon = gl_streamlines_icon;
2373 klass->pickinfo = gl_streamlines_pickinfo;
2374 klass->post_init = gl_streamlines_post_init;
2375 }
2376
2377 static void gl_streamlines_init (GfkGlVectors * gl)
2378 {
2379 GfkGlStreamlines * gls = GFK_GL_STREAMLINES (gl);
2380
2381 gtk_widget_set_sensitive (lookup_widget_params (gl->vector, "label11"), FALSE);
2382 gtk_widget_set_sensitive (lookup_widget_params (gl->vector, "scale"), FALSE);
2383
2384 gls->stream = create_streamlines_params ();
2385 gtk_widget_set_sensitive (lookup_widget_params (gls->stream, "delete"), FALSE);
2386 gtk_widget_set_sensitive (lookup_widget_params (gls->stream, "evenly_spaced"), FALSE);
2387 if (FTT_DIMENSION < 3)
2388 gtk_widget_hide (lookup_widget_params (gls->stream, "params_3D"));
2389 gfk_gl_prepend_params (GFK_GL (gl), gls->stream, gtk_label_new ("Streamlines"));
2390 gtk_widget_show (gls->stream);
2391 }
2392
2393 GfkGlClass * gfk_gl_streamlines_class (void)
2394 {
2395 static GfkGlClass * klass = NULL;
2396
2397 if (klass == NULL) {
2398 GtsObjectClassInfo gfk_gl_streamlines_info = {
2399 "GfkGlStreamlines",
2400 sizeof (GfkGlStreamlines),
2401 sizeof (GfkGlClass),
2402 (GtsObjectClassInitFunc) gl_streamlines_class_init,
2403 (GtsObjectInitFunc) gl_streamlines_init,
2404 (GtsArgSetFunc) NULL,
2405 (GtsArgGetFunc) NULL
2406 };
2407 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_vectors_class ()),
2408 &gfk_gl_streamlines_info);
2409 }
2410
2411 return klass;
2412 }
2413
2414 /* GfkGlEllipses: Object */
2415
2416 static void update_ellipse_scalar (GfkGlEllipses * gl)
2417 {
2418 gfk_gl_set_sensitive (GFK_GL (gl), GFK_GL_SCALAR (gl)->scalar, TRUE);
2419 gfk_gl_update_properties (GFK_GL (gl));
2420 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color_label"),
2421 FALSE);
2422 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color"),
2423 FALSE);
2424 }
2425
2426 static void gl_ellipses_read (GtsObject ** o, GtsFile * fp)
2427 {
2428 GtkWidget * ellipse = GFK_GL_ELLIPSES (*o)->ellipse;
2429 GfsGlEllipses * gl = GFS_GL_ELLIPSES (GFK_GL (*o)->gl);
2430
2431 (* GTS_OBJECT_CLASS (gfk_gl_ellipses_class ())->parent_class->read) (o, fp);
2432 if (fp->type == GTS_ERROR)
2433 return;
2434
2435 gtk_spin_button_set_value (lookup_widget_params (ellipse, "scale"), gl->scale);
2436
2437 if (gl->use_scalar) {
2438 gtk_option_menu_set_history (lookup_widget_params (ellipse, "color"), 1);
2439 update_ellipse_scalar (GFK_GL_ELLIPSES (*o));
2440 }
2441 }
2442
2443 static void gl_ellipses_update_interface (GfkGl * g)
2444 {
2445 GfkGlEllipses * gl = GFK_GL_ELLIPSES (g);
2446 GfsGlEllipses * gle = GFS_GL_ELLIPSES (GFK_GL (gl)->gl);
2447 GtkSpinButton * scale = lookup_widget_params (gl->ellipse, "scale");
2448 GtkAdjustment * ascale = gtk_spin_button_get_adjustment (scale);
2449 guint j;
2450
2451 for (j = 0; j < 4; j++) {
2452 static gchar * name[] = {"Ax", "Ay", "Bx", "By"};
2453 GtkEntry * entry = lookup_widget_params (gl->ellipse, name[j]);
2454 if (!GFK_IS_EDITED (entry))
2455 gtk_entry_set_text (entry, gle->expr[j]->str);
2456 }
2457
2458 ascale->upper = gle->max > 0. ? 10000.*gle->h/gle->max : 1.;
2459 ascale->step_increment = gle->max > 0. ? gle->h/gle->max/10. : 0.1;
2460 ascale->page_increment = 10.*ascale->step_increment;
2461 ascale->value = gle->scale;
2462 if (!GFK_IS_EDITED (scale))
2463 gtk_spin_button_configure (scale, ascale, 2.*ascale->step_increment,
2464 gfk_decimal_digits (ascale->step_increment, 2));
2465 gfk_gl_update_properties (GFK_GL (gl));
2466 gfk_gl_expose (GFK_GL (gl));
2467 }
2468
2469 static void set_ellipse_color (GtkWidget * color, GfkGlEllipses * gl)
2470 {
2471 GFS_GL_ELLIPSES (GFK_GL (gl)->gl)->use_scalar = FALSE;
2472 gfk_gl_set_sensitive (GFK_GL (gl), GFK_GL_SCALAR (gl)->scalar, FALSE);
2473 gfk_gl_update_properties (GFK_GL (gl));
2474 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color_label"),
2475 TRUE);
2476 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (gl)->properties, "default_color"), TRUE);
2477 gfk_gl_expose (GFK_GL (gl));
2478 }
2479
2480 static void set_ellipse_scalar (GtkWidget * scalar, GfkGlEllipses * gl)
2481 {
2482 GFS_GL_ELLIPSES (GFK_GL (gl)->gl)->use_scalar = TRUE;
2483 update_ellipse_scalar (gl);
2484 gfk_gl_expose (GFK_GL (gl));
2485 }
2486
2487 static void gl_ellipses_set_simulation (GfkGl * object, GfsSimulation * sim)
2488 {
2489 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_ellipses_class ())->parent_class)->set_simulation)
2490 (object, sim);
2491
2492 gl_ellipses_update_interface (object);
2493 }
2494
2495 static GtsFile * set_ax (GfkGl * gl, const gchar * func)
2496 {
2497 return gfs_gl_ellipses_set (GFS_GL_ELLIPSES (gl->gl), 0, func);
2498 }
2499
2500 static GtsFile * set_ay (GfkGl * gl, const gchar * func)
2501 {
2502 return gfs_gl_ellipses_set (GFS_GL_ELLIPSES (gl->gl), 1, func);
2503 }
2504
2505 static GtsFile * set_bx (GfkGl * gl, const gchar * func)
2506 {
2507 return gfs_gl_ellipses_set (GFS_GL_ELLIPSES (gl->gl), 2, func);
2508 }
2509
2510 static GtsFile * set_by (GfkGl * gl, const gchar * func)
2511 {
2512 return gfs_gl_ellipses_set (GFS_GL_ELLIPSES (gl->gl), 3, func);
2513 }
2514
2515 static void gl_ellipses_post_init (GfkGl * object)
2516 {
2517 GfkGlEllipses * gls = GFK_GL_ELLIPSES (object);
2518 guint i;
2519
2520 if (GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_ellipses_class ())->parent_class)->post_init)
2521 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_ellipses_class ())->parent_class)->post_init)
2522 (object);
2523
2524 GtkTable * table = GTK_TABLE (lookup_widget_params (gls->ellipse, "table12"));
2525 for (i = 0; i < 4; i++) {
2526 static gchar * name[] = {"Ax", "Ay", "Bx", "By"};
2527 static GfkFunctionSet func[] = {set_ax, set_ay, set_bx, set_by};
2528
2529 GtkWidget * scalar = gfk_function (gls->ellipse, object, name[i], func[i]);
2530 gtk_widget_show (scalar);
2531 gtk_table_attach (table, scalar, 1, 2, i, i + 1,
2532 (GtkAttachOptions) (GTK_FILL),
2533 (GtkAttachOptions) (0), 0, 0);
2534 }
2535
2536 gl_ellipses_update_interface (object);
2537 }
2538
2539 static gchar * gl_ellipses_name (GfkGlClass * klass)
2540 {
2541 static gchar name[] = "Ellipses";
2542 return name;
2543 }
2544
2545 static GtkWidget * gl_ellipses_icon (GfkGlClass * klass)
2546 {
2547 return create_pixmap (NULL, "ellipses-16x16.png");
2548 }
2549
2550 static gchar * gl_ellipses_properties (GfkGl * gl)
2551 {
2552 GfsGlEllipses * gle = GFS_GL_ELLIPSES (gl->gl);
2553
2554 g_free (gl->props);
2555 gl->props = g_strjoin (",",
2556 gle->expr[0]->str, gle->expr[1]->str,
2557 gle->expr[2]->str, gle->expr[3]->str, NULL);
2558 return gl->props;
2559 }
2560
2561 static void gl_ellipses_class_init (GfkGlClass * klass)
2562 {
2563 GTS_OBJECT_CLASS (klass)->read = gl_ellipses_read;
2564 klass->gl_class = gfs_gl_ellipses_class ();
2565 klass->post_init = gl_ellipses_post_init;
2566 klass->set_simulation = gl_ellipses_set_simulation;
2567 klass->update_interface = gl_ellipses_update_interface;
2568 klass->name = gl_ellipses_name;
2569 klass->icon = gl_ellipses_icon;
2570 klass->properties = gl_ellipses_properties;
2571 }
2572
2573 static void gl_ellipses_init (GfkGlEllipses * object)
2574 {
2575 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (object)->properties, "shading_label"),
2576 FALSE);
2577 gtk_widget_set_sensitive (lookup_widget_params (GFK_GL (object)->properties, "shading"), FALSE);
2578
2579 object->ellipse = create_ellipse_params ();
2580
2581 gfk_gl_set_sensitive (GFK_GL (object), GFK_GL_SCALAR (object)->scalar, FALSE);
2582 GtkWidget * m = gtk_menu_new ();
2583 GtkWidget * i = gtk_menu_item_new_with_label ("Default");
2584 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_ellipse_color), object);
2585 gtk_menu_append (m, i);
2586 gtk_widget_show (i);
2587
2588 i = gtk_menu_item_new_with_label ("Scalar");
2589 g_signal_connect (G_OBJECT (i), "activate", GTK_SIGNAL_FUNC (set_ellipse_scalar), object);
2590 gtk_menu_append (m, i);
2591 gtk_widget_show (i);
2592
2593 gtk_option_menu_set_menu (lookup_widget_params (object->ellipse, "color"), m);
2594 gtk_widget_show (m);
2595
2596 gfk_gl_prepend_params (GFK_GL (object), object->ellipse, gtk_label_new ("Ellipse"));
2597 gtk_widget_show (object->ellipse);
2598 }
2599
2600 GfkGlClass * gfk_gl_ellipses_class (void)
2601 {
2602 static GfkGlClass * klass = NULL;
2603
2604 if (klass == NULL) {
2605 GtsObjectClassInfo gfk_gl_ellipses_info = {
2606 "GfkGlEllipses",
2607 sizeof (GfkGlEllipses),
2608 sizeof (GfkGlClass),
2609 (GtsObjectClassInitFunc) gl_ellipses_class_init,
2610 (GtsObjectInitFunc) gl_ellipses_init,
2611 (GtsArgSetFunc) NULL,
2612 (GtsArgGetFunc) NULL
2613 };
2614 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_scalar_class ()),
2615 &gfk_gl_ellipses_info);
2616 }
2617
2618 return klass;
2619 }
2620
2621 /* GfkGlLocation: Object */
2622
2623 static void gl_location_read (GtsObject ** o, GtsFile * fp)
2624 {
2625 GtkWidget * location = GFK_GL_LOCATION (*o)->location;
2626 GfsGlLocation * gl = GFS_GL_LOCATION (GFK_GL (*o)->gl);
2627
2628 (* GTS_OBJECT_CLASS (gfk_gl_location_class ())->parent_class->read) (o, fp);
2629 if (fp->type == GTS_ERROR)
2630 return;
2631
2632 gtk_spin_button_set_value (lookup_widget_params (location, "size"), gl->size);
2633 #if HAVE_FTGL
2634 if (gl->label) {
2635 gl->label = FALSE;
2636 gtk_toggle_button_set_active (lookup_widget_params (location, "location_label_check"), TRUE);
2637 }
2638 #endif /* HAVE_FTGL */
2639 }
2640
2641 static void gl_location_init (GfkGl * gl)
2642 {
2643 GtkWidget * location = create_location_params ();
2644
2645 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "maxlevel_label"), FALSE);
2646 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "maxlevel"), FALSE);
2647 #if HAVE_FTGL
2648 gtk_widget_show (gl->font);
2649 #else /* not HAVE_FTGL */
2650 gtk_widget_set_sensitive (lookup_widget_params (location, "location_label"), FALSE);
2651 gtk_widget_set_sensitive (lookup_widget_params (location, "location_label_check"), FALSE);
2652 #endif /* not HAVE_FTGL */
2653 gfk_gl_prepend_params (gl, location, gtk_label_new ("Location"));
2654 gtk_spin_button_set_value (lookup_widget_params (location, "size"),
2655 GFS_GL_LOCATION (gl->gl)->size);
2656 gtk_widget_show (location);
2657 GFK_GL_LOCATION (gl)->location = location;
2658 }
2659
2660 static gchar * gl_location_name (GfkGlClass * klass)
2661 {
2662 static gchar name[] = "Location";
2663 return name;
2664 }
2665
2666 static GtkWidget * gl_location_icon (GfkGlClass * klass)
2667 {
2668 return create_pixmap (NULL, "location-16x16.png");
2669 }
2670
2671 static void gl_location_class_init (GfkGlClass * klass)
2672 {
2673 GTS_OBJECT_CLASS (klass)->read = gl_location_read;
2674 klass->gl_class = gfs_gl_location_class ();
2675 klass->name = gl_location_name;
2676 klass->icon = gl_location_icon;
2677 }
2678
2679 GfkGlClass * gfk_gl_location_class (void)
2680 {
2681 static GfkGlClass * klass = NULL;
2682
2683 if (klass == NULL) {
2684 GtsObjectClassInfo gfk_gl_location_info = {
2685 "GfkGlLocation",
2686 sizeof (GfkGlLocation),
2687 sizeof (GfkGlClass),
2688 (GtsObjectClassInitFunc) gl_location_class_init,
2689 (GtsObjectInitFunc) gl_location_init,
2690 (GtsArgSetFunc) NULL,
2691 (GtsArgGetFunc) NULL
2692 };
2693 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &gfk_gl_location_info);
2694 }
2695
2696 return klass;
2697 }
2698
2699 /* GfkGlHeight: Object */
2700
2701 static gchar * gl_height_name (GfkGlClass * klass)
2702 {
2703 static gchar name[] = "Height";
2704 return name;
2705 }
2706
2707 static GtkWidget * gl_height_icon (GfkGlClass * klass)
2708 {
2709 return create_pixmap (NULL, "height-16x16.png");
2710 }
2711
2712 static void gl_height_class_init (GfkGlClass * klass)
2713 {
2714 klass->gl_class = gfs_gl_height_class ();
2715 klass->name = gl_height_name;
2716 klass->icon = gl_height_icon;
2717 }
2718
2719 GfkGlClass * gfk_gl_height_class (void)
2720 {
2721 static GfkGlClass * klass = NULL;
2722
2723 if (klass == NULL) {
2724 GtsObjectClassInfo info = {
2725 "GfkGlHeight",
2726 sizeof (GfkGlLocation),
2727 sizeof (GfkGlClass),
2728 (GtsObjectClassInitFunc) gl_height_class_init,
2729 (GtsObjectInitFunc) NULL,
2730 (GtsArgSetFunc) NULL,
2731 (GtsArgGetFunc) NULL
2732 };
2733 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_location_class ()), &info);
2734 }
2735
2736 return klass;
2737 }
2738
2739 /* GfkGlLocate: Object */
2740
2741 static void gl_locate_read (GtsObject ** o, GtsFile * fp)
2742 {
2743 GtkWidget * locate = GFK_GL_LOCATE (*o)->locate;
2744 GfsGlLocate * gl = GFS_GL_LOCATE (GFK_GL (*o)->gl);
2745
2746 (* GTS_OBJECT_CLASS (gfk_gl_locate_class ())->parent_class->read) (o, fp);
2747 if (fp->type == GTS_ERROR)
2748 return;
2749
2750 FttComponent c;
2751 for (c = 0; c < 3; c++) {
2752 static gchar * name[] = {"locate_x_entry", "locate_y_entry", "locate_z_entry"};
2753 gchar * s = g_strdup_printf ("%g", (&gl->p.x)[c]);
2754 gtk_entry_set_text (lookup_widget_params (locate, name[c]), s);
2755 g_free (s);
2756 }
2757 }
2758
2759 static gchar * gl_locate_name (GfkGlClass * klass)
2760 {
2761 static gchar name[] = "Locate";
2762 return name;
2763 }
2764
2765 static GtkWidget * gl_locate_icon (GfkGlClass * klass)
2766 {
2767 return create_pixmap (NULL, "locate-16x16.png");
2768 }
2769
2770 static void gl_locate_update_interface (GfkGl * g)
2771 {
2772 GtkWidget * locate = GFK_GL_LOCATE (g)->locate;
2773 GfsGlLocate * gl = GFS_GL_LOCATE (g->gl);
2774
2775 FttComponent c;
2776 for (c = 0; c < 3; c++) {
2777 static gchar * name[] = {"locate_x_entry", "locate_y_entry", "locate_z_entry"};
2778 GtkEntry * entry = lookup_widget_params (locate, name[c]);
2779 gchar * s = g_strdup_printf ("%g", (&gl->p.x)[c]);
2780 gtk_entry_set_text (entry, s);
2781 g_free (s);
2782 }
2783 gfk_gl_update_properties (g);
2784 gfk_gl_expose (g);
2785 }
2786
2787 static void gl_locate_set_simulation (GfkGl * object, GfsSimulation * sim)
2788 {
2789 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_locate_class ())->parent_class)->set_simulation)
2790 (object, sim);
2791
2792 gl_locate_update_interface (object);
2793 }
2794
2795 static void gl_locate_class_init (GfkGlClass * klass)
2796 {
2797 GTS_OBJECT_CLASS (klass)->read = gl_locate_read;
2798 klass->gl_class = gfs_gl_locate_class ();
2799 klass->name = gl_locate_name;
2800 klass->icon = gl_locate_icon;
2801 klass->update_interface = gl_locate_update_interface;
2802 klass->set_simulation = gl_locate_set_simulation;
2803 }
2804
2805 static void gl_locate_init (GfkGl * gl)
2806 {
2807 GtkWidget * locate = create_locate_params ();
2808
2809 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading_label"), FALSE);
2810 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "shading"), FALSE);
2811 gfk_gl_prepend_params (gl, locate, gtk_label_new ("Locate"));
2812 gtk_widget_show (locate);
2813
2814 GFK_GL_LOCATE (gl)->locate = locate;
2815 }
2816
2817 GfkGlClass * gfk_gl_locate_class (void)
2818 {
2819 static GfkGlClass * klass = NULL;
2820
2821 if (klass == NULL) {
2822 GtsObjectClassInfo gfk_gl_locate_info = {
2823 "GfkGlLocate",
2824 sizeof (GfkGl),
2825 sizeof (GfkGlClass),
2826 (GtsObjectClassInitFunc) gl_locate_class_init,
2827 (GtsObjectInitFunc) gl_locate_init,
2828 (GtsArgSetFunc) NULL,
2829 (GtsArgGetFunc) NULL
2830 };
2831 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &gfk_gl_locate_info);
2832 }
2833
2834 return klass;
2835 }
2836
2837 /* GfkGlPipes: Object */
2838
2839 static void gl_pipes_init (GfkGl * gl)
2840 {
2841 gtk_widget_hide (lookup_widget_params (gl->properties, "maxlevel_label"));
2842 gtk_widget_hide (lookup_widget_params (gl->properties, "maxlevel"));
2843 gtk_widget_hide (lookup_widget_params (gl->properties, "finest"));
2844 gtk_widget_hide (lookup_widget_params (gl->properties, "shading_label"));
2845 gtk_widget_hide (lookup_widget_params (gl->properties, "shading"));
2846 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "label117"), FALSE);
2847 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "linewidth"), FALSE);
2848 #if HAVE_FTGL
2849 gtk_widget_show (gl->font);
2850 #endif
2851 }
2852
2853 static gchar * gl_pipes_name (GfkGlClass * klass)
2854 {
2855 static gchar name[] = "Pipes";
2856 return name;
2857 }
2858
2859 static GtkWidget * gl_pipes_icon (GfkGlClass * klass)
2860 {
2861 return create_pixmap (NULL, "pipes-16x16.png");
2862 }
2863
2864 static void gl_pipes_class_init (GfkGlClass * klass)
2865 {
2866 klass->gl_class = gfs_gl_pipes_class ();
2867 klass->name = gl_pipes_name;
2868 klass->icon = gl_pipes_icon;
2869 }
2870
2871 GfkGlClass * gfk_gl_pipes_class (void)
2872 {
2873 static GfkGlClass * klass = NULL;
2874
2875 if (klass == NULL) {
2876 GtsObjectClassInfo info = {
2877 "GfkGlPipes",
2878 sizeof (GfkGl),
2879 sizeof (GfkGlClass),
2880 (GtsObjectClassInitFunc) gl_pipes_class_init,
2881 (GtsObjectInitFunc) gl_pipes_init,
2882 (GtsArgSetFunc) NULL,
2883 (GtsArgGetFunc) NULL
2884 };
2885 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()), &info);
2886 }
2887
2888 return klass;
2889 }
2890
2891 /* GfkGlClipPlane: Object */
2892
2893 static gchar * gl_clip_plane_name (GfkGlClass * klass)
2894 {
2895 static gchar name[] = "Clipping";
2896 return name;
2897 }
2898
2899 static GtkWidget * gl_clip_plane_icon (GfkGlClass * klass)
2900 {
2901 return create_pixmap (NULL, "clipping-16x16.png");
2902 }
2903
2904 static void gl_clip_plane_class_init (GfkGlClass * klass)
2905 {
2906 klass->gl_class = gfs_gl_clip_plane_class ();
2907 klass->name = gl_clip_plane_name;
2908 klass->icon = gl_clip_plane_icon;
2909 klass->pickinfo = NULL;
2910 }
2911
2912 static void gl_clip_plane_init (GfkGl * gl)
2913 {
2914 gtk_widget_show (GFK_GL2D (gl)->params);
2915 gtk_widget_set_sensitive (lookup_widget_params (gl->properties, "gl_params"), FALSE);
2916 }
2917
2918 GfkGlClass * gfk_gl_clip_plane_class (void)
2919 {
2920 static GfkGlClass * klass = NULL;
2921
2922 if (klass == NULL) {
2923 GtsObjectClassInfo gfk_gl_clip_plane_info = {
2924 "GfkGlClipPlane",
2925 sizeof (GfkGl2D),
2926 sizeof (GfkGlClass),
2927 (GtsObjectClassInitFunc) gl_clip_plane_class_init,
2928 (GtsObjectInitFunc) gl_clip_plane_init,
2929 (GtsArgSetFunc) NULL,
2930 (GtsArgGetFunc) NULL
2931 };
2932 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl2D_class ()), &gfk_gl_clip_plane_info);
2933 }
2934
2935 return klass;
2936 }
2937
2938 /* GfkGlInfo: Object */
2939
2940 typedef struct {
2941 guint cells, leaves;
2942 GArray * level;
2943 } CellCount;
2944
2945 static void count_cells (FttCell * cell, CellCount * c)
2946 {
2947 guint i = ftt_cell_level (cell), n = 0;
2948 if (i >= c->level->len)
2949 g_array_append_val (c->level, n);
2950 c->cells++;
2951 if (FTT_CELL_IS_LEAF (cell)) {
2952 c->leaves++;
2953 g_array_index (c->level, guint, i)++;
2954 }
2955 }
2956
2957 static void gl_info_set_simulation (GfkGl * object, GfsSimulation * sim)
2958 {
2959 CellCount count = {0, 0, NULL};
2960
2961 (*GFK_GL_CLASS (GTS_OBJECT_CLASS (gfk_gl_info_class ())->parent_class)->set_simulation)
2962 (object, sim);
2963
2964 count.level = g_array_new (FALSE, FALSE, sizeof (guint));
2965 gfs_domain_cell_traverse (GFS_DOMAIN (sim), FTT_PRE_ORDER, FTT_TRAVERSE_ALL, -1,
2966 (FttCellTraverseFunc) count_cells, &count);
2967 GtkLabel * label = lookup_widget_params (GFK_GL_INFO (object)->info, "number_of_levels");
2968 gchar * s = g_strdup_printf ("%d", count.level->len);
2969 gtk_label_set_text (label, s);
2970 g_free (s);
2971
2972 label = lookup_widget_params (GFK_GL_INFO (object)->info, "number_of_cells");
2973 s = g_strdup_printf ("%d", count.cells);
2974 gtk_label_set_text (label, s);
2975 g_free (s);
2976
2977 label = lookup_widget_params (GFK_GL_INFO (object)->info, "number_of_leaf_cells");
2978 s = g_strdup_printf ("%d", count.leaves);
2979 gtk_label_set_text (label, s);
2980 g_free (s);
2981
2982 GtkWidget * table = lookup_widget_params (GFK_GL_INFO (object)->info, "leaf_cells_per_level");
2983 gtk_container_foreach (GTK_CONTAINER (table), (GtkCallback) gtk_widget_destroy, NULL);
2984
2985 guint i, l = 0;
2986 for (i = 0; i < count.level->len; i++)
2987 if (g_array_index (count.level, guint, i)) {
2988 gchar * s = g_strdup_printf ("Level %d", i);
2989 GtkWidget * label = gtk_label_new (s);
2990 gtk_widget_show (label);
2991 g_free (s);
2992 gtk_table_attach (GTK_TABLE (table), label, 0, 1, l, l + 1,
2993 (GtkAttachOptions) (GTK_FILL),
2994 (GtkAttachOptions) (0), 16, 0);
2995 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
2996
2997 s = g_strdup_printf ("%d", g_array_index (count.level, guint, i));
2998 label = gtk_label_new (s);
2999 gtk_widget_show (label);
3000 g_free (s);
3001 gtk_table_attach (GTK_TABLE (table), label, 1, 2, l, l + 1,
3002 (GtkAttachOptions) (GTK_FILL),
3003 (GtkAttachOptions) (0), 0, 0);
3004 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
3005 gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
3006
3007 l++;
3008 }
3009
3010 g_array_free (count.level, TRUE);
3011 }
3012
3013 static gchar * gl_info_name (GfkGlClass * klass)
3014 {
3015 static gchar name[] = "Info";
3016 return name;
3017 }
3018
3019 static GtkWidget * gl_info_icon (GfkGlClass * klass)
3020 {
3021 return create_pixmap (NULL, "info-16x16.png");
3022 }
3023
3024 static void gl_info_class_init (GfkGlClass * klass)
3025 {
3026 klass->set_simulation = gl_info_set_simulation;
3027 klass->name = gl_info_name;
3028 klass->icon = gl_info_icon;
3029 }
3030
3031 static void gl_info_init (GfkGl * gl)
3032 {
3033 GFK_GL_INFO (gl)->info = create_info_params ();
3034 gfk_gl_set_sensitive (gl, gl->properties, FALSE);
3035 gfk_gl_prepend_params (gl, GFK_GL_INFO (gl)->info, gtk_label_new ("Info"));
3036 gtk_widget_show (GFK_GL_INFO (gl)->info);
3037 }
3038
3039 GfkGlClass * gfk_gl_info_class (void)
3040 {
3041 static GfkGlClass * klass = NULL;
3042
3043 if (klass == NULL) {
3044 GtsObjectClassInfo gfk_gl_info_info = {
3045 "GfkGlInfo",
3046 sizeof (GfkGlInfo),
3047 sizeof (GfkGlClass),
3048 (GtsObjectClassInitFunc) gl_info_class_init,
3049 (GtsObjectInitFunc) gl_info_init,
3050 (GtsArgSetFunc) NULL,
3051 (GtsArgGetFunc) NULL
3052 };
3053 klass = gts_object_class_new (GTS_OBJECT_CLASS (gfk_gl_class ()),
3054 &gfk_gl_info_info);
3055 }
3056
3057 return klass;
3058 }
3059
3060 /* GfkGlView: Object */
3061
3062 static void write_ppm_pixbuf (GdkPixbuf * pixbuf, FILE * fp)
3063 {
3064 guint width, height = gdk_pixbuf_get_height (pixbuf);
3065 guchar * pixels = gdk_pixbuf_get_pixels (pixbuf);
3066 guint j, rowstride = gdk_pixbuf_get_rowstride (pixbuf);
3067
3068 g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
3069 g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
3070 g_assert (!gdk_pixbuf_get_has_alpha (pixbuf));
3071 g_assert (gdk_pixbuf_get_n_channels (pixbuf) == 3);
3072
3073 width = rowstride/3;
3074 if (width % 2)
3075 width -= 1;
3076 if (height % 2)
3077 height -= 1;
3078 fprintf (fp, "P6 %d %d 255\n", width, height);
3079 for (j = 0; j < height; j++, pixels += rowstride)
3080 fwrite (pixels, 3*width, sizeof (guchar), fp);
3081 }
3082
3083 static void write_ppm (guint width, guint height, FILE * fp)
3084 {
3085 gchar * p, * p1;
3086 guint j;
3087
3088 p = g_malloc0 (3*width*height*sizeof (gchar));
3089 glPixelStorei (GL_PACK_ALIGNMENT, 1);
3090 glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, p);
3091 fprintf (fp, "P6 %d %d 255\n", width, height);
3092 p1 = (gchar *)(p + sizeof (gchar)*(3*width*(height - 1)));
3093 for (j = height; j--; p1 = (gchar *)(p1 - sizeof (gchar)*3*width))
3094 fwrite (p1, 3*width, sizeof (gchar), fp);
3095 g_free (p);
3096 }
3097
3098 static GList * get_symmetries (GtkTreeModel * list)
3099 {
3100 GtkTreeIter iter;
3101 gboolean valid = gtk_tree_model_get_iter_first (list, &iter);
3102 GList * symmetry = NULL;
3103
3104 while (valid) {
3105 gboolean visible;
3106 GfkGl * gl;
3107
3108 gtk_tree_model_get (list, &iter, GL_COLUMN, &gl, VISIBLE_COLUMN, &visible, -1);
3109 if (visible && GFK_IS_GL_SYMMETRY (gl))
3110 symmetry = g_list_append (symmetry, gl->gl);
3111 valid = gtk_tree_model_iter_next (list, &iter);
3112 }
3113 return symmetry;
3114 }
3115
3116 void gfs_gl2ps (GfsGl2PSParams * p,
3117 FILE * fp,
3118 const gchar * fname,
3119 GtkWidget * view)
3120 {
3121 GtkWidget * glarea;
3122 GfsGlViewParams * viewp;
3123
3124 g_return_if_fail (p != NULL);
3125 g_return_if_fail (fp != NULL);
3126 g_return_if_fail (fname != NULL);
3127 g_return_if_fail (view != NULL);
3128
3129 glarea = g_object_get_data (G_OBJECT (view), "glarea");
3130 viewp = g_object_get_data (G_OBJECT (glarea), "GfsGlViewParams");
3131
3132 switch (p->format) {
3133 case GFSGL_PPM_OFFSCREEN: {
3134 gboolean written = FALSE;
3135 GdkGLConfig * glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
3136 GDK_GL_MODE_DEPTH |
3137 GDK_GL_MODE_SINGLE);
3138 if (!glconfig)
3139 g_warning ("Cannot get OpenGL config\n");
3140 else {
3141 guint width = p->width ? p->width : glarea->allocation.width;
3142 guint height = p->height ? p->height : glarea->allocation.height;
3143 GdkPixmap * pixmap = gdk_pixmap_new (glarea->window, width, height, -1);
3144 GdkGLDrawable * gldrawable = GDK_GL_DRAWABLE (gdk_pixmap_set_gl_capability (pixmap,
3145 glconfig,
3146 NULL));
3147 GdkGLContext * glcontext = gdk_gl_context_new (gldrawable,
3148 NULL,
3149 FALSE,
3150 GDK_GL_RGBA_TYPE);
3151
3152 if (!glcontext)
3153 g_warning ("Cannot create the OpenGL rendering context\n");
3154 else {
3155 GfsGlViewParams * info = g_object_get_data (G_OBJECT (glarea), "GfsGlViewParams");
3156 GLfloat m[4][4];
3157 GdkPixbuf * pixbuf;
3158 gdouble max;
3159
3160 gdk_gl_drawable_gl_begin (gldrawable, glcontext);
3161
3162 glViewport (0, 0, width, height);
3163 gfs_gl_init_gl ();
3164 glMatrixMode (GL_PROJECTION);
3165 glLoadIdentity ();
3166 GtkTreeModel * list =
3167 gtk_tree_view_get_model (GTK_TREE_VIEW (lookup_widget (view, "gl_list")));
3168 GList * symmetries = get_symmetries (list);
3169 max = gfs_gl_domain_extent (g_object_get_data (G_OBJECT (glarea), "sim"), symmetries);
3170 g_list_free (symmetries);
3171 gluPerspective (info->fov, width/(float)height, 1., 1. + 2.*max);
3172 glMatrixMode (GL_MODELVIEW);
3173
3174 glClearColor (info->bg.r, info->bg.g, info->bg.b, 1);
3175 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3176
3177 glLoadIdentity ();
3178 glTranslatef (info->tx, info->ty, - (1. + max));
3179 gfs_gl_build_rotmatrix (m, info->quat);
3180 glMultMatrixf (&m[0][0]);
3181 glScalef (info->sx, info->sy, info->sz);
3182
3183 gfk_gl_view_draw (view, GFSGL_PPM_OFFSCREEN);
3184
3185 glFlush ();
3186 gdk_gl_drawable_gl_end (gldrawable);
3187
3188 pixbuf = gdk_pixbuf_get_from_drawable (NULL, GDK_DRAWABLE (pixmap), NULL,
3189 0, 0, 0, 0, -1, -1);
3190
3191 if (pixbuf == NULL)
3192 g_warning ("Cannot get pixbuf\n");
3193 else {
3194 write_ppm_pixbuf (pixbuf, fp);
3195 written = TRUE;
3196 g_object_unref (G_OBJECT (pixbuf));
3197 }
3198 gdk_gl_context_destroy (glcontext);
3199 info->do_init = TRUE; /* this is necessary to reinitialise textures for fonts */
3200 }
3201 gdk_pixmap_unset_gl_capability (pixmap);
3202 g_object_unref (G_OBJECT (pixmap));
3203 }
3204 if (written)
3205 break;
3206 }
3207 case GFSGL_PPM_SCREEN:
3208 write_ppm (glarea->allocation.width, glarea->allocation.height, fp);
3209 break;
3210 case GFSGL_GNUPLOT: case GFSGL_OBJ: case GFSGL_KML: {
3211 guint buffsize = 0;
3212 gboolean done = FALSE;
3213 gfloat base_res = viewp->base_res;
3214 viewp->base_res = 0.;
3215 while (!done) {
3216 GfsGlFeedback * f;
3217
3218 buffsize += 2048*2048;
3219 f = gfs_gl_feedback_begin (buffsize);
3220 gfk_gl_view_draw (view, GFSGL_SCREEN);
3221 done = gfs_gl_feedback_end (f, g_object_get_data (G_OBJECT (glarea), "sim"), fp, p->format);
3222 }
3223 viewp->base_res = base_res;
3224 break;
3225 }
3226 default: {
3227 GLint buffsize = 0, state = GL2PS_OVERFLOW;
3228
3229 while (state == GL2PS_OVERFLOW) {
3230 buffsize += 2048*2048;
3231 gl2psBeginPage ("", "GfsView",
3232 NULL,
3233 p->format, p->sort, p->options,
3234 GL_RGBA, 0, NULL,
3235 0, 0, 0,
3236 buffsize, fp, fname);
3237 GtkWidget * glarea = g_object_get_data (G_OBJECT (view), "glarea");
3238 GfsGlViewParams * v = g_object_get_data (G_OBJECT (glarea), "GfsGlViewParams");
3239 v->lw = p->lw;
3240 gfk_gl_view_draw (view, p->format);
3241 state = gl2psEndPage();
3242 }
3243 }
3244 }
3245 }
3246
3247 static void visible_toggled (GtkCellRendererToggle * cellrenderertoggle,
3248 gchar * path_string,
3249 GtkTreeModel * model)
3250 {
3251 GtkTreeIter iter;
3252 gboolean visible;
3253 GfkGl * gl;
3254
3255 g_assert (gtk_tree_model_get_iter_from_string (model, &iter, path_string));
3256 gtk_tree_model_get (model, &iter, GL_COLUMN, &gl, VISIBLE_COLUMN, &visible, -1);
3257 gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISIBLE_COLUMN, !visible, -1);
3258 gfk_gl_expose (gl);
3259 }
3260
3261 static gboolean tree_selection_func (GtkTreeSelection * select,
3262 GtkTreeModel * model,
3263 GtkTreePath * path,
3264 gboolean path_currently_selected,
3265 gpointer data)
3266 {
3267 if (path_currently_selected)
3268 return TRUE;
3269 else {
3270 GtkTreeIter iter;
3271 gboolean visible;
3272
3273 g_assert (gtk_tree_model_get_iter (model, &iter, path));
3274 gtk_tree_model_get (model, &iter, VISIBLE_COLUMN, &visible, -1);
3275 if (visible && gtk_tree_selection_get_selected (select, &model, &iter))
3276 gtk_list_store_set (GTK_LIST_STORE (model), &iter, SELECTED_COLUMN, FALSE, -1);
3277 return visible;
3278 }
3279 }
3280
3281 static void tree_selection_changed_cb (GtkTreeSelection * selection, GObject * list)
3282 {
3283 GtkTreeIter iter;
3284 GtkTreeModel * model;
3285
3286 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
3287 GfkGl * gl, * former = g_object_get_data (list, "former");
3288
3289 gtk_tree_model_get (model, &iter, GL_COLUMN, &gl, -1);
3290 gtk_list_store_set (GTK_LIST_STORE (model), &iter, SELECTED_COLUMN, TRUE, -1);
3291 if (former && former != gl) {
3292 gint x, y;
3293 gtk_window_get_position (GTK_WINDOW (former->params), &x, &y);
3294 gtk_window_move (GTK_WINDOW (gl->params), x, y);
3295 gtk_widget_show (gl->params);
3296 gtk_widget_hide (former->params);
3297 g_object_set_data (list, "former", gl);
3298 }
3299 gtk_widget_set_sensitive (lookup_widget (GTK_WIDGET (list), "properties1"), TRUE);
3300 gtk_widget_set_sensitive (lookup_widget (GTK_WIDGET (list), "delete3"), TRUE);
3301 }
3302 }
3303
3304 static gchar * format_glob (GSList * list)
3305 {
3306 gchar * s = g_strdup ("");
3307
3308 while (list) {
3309 GfsFormat * f = list->data;
3310 gchar * s2 = NULL;
3311
3312 switch (f->t) {
3313 case GFS_NONE_FORMAT:
3314 s2 = g_strconcat (s, f->s, NULL);
3315 break;
3316 case GFS_ITER_FORMAT: case GFS_TIME_FORMAT:
3317 s2 = g_strconcat (s, "*", NULL);
3318 break;
3319 default:
3320 g_assert_not_reached ();
3321 }
3322 g_free (s);
3323 s = s2;
3324 list = list->next;
3325 }
3326
3327 return s;
3328 }
3329
3330 static void free_glob (glob_t * files)
3331 {
3332 guint i;
3333
3334 for (i = 0; i < files->gl_pathc; i++)
3335 g_free (files->gl_pathv[i]);
3336 g_free (files->gl_pathv);
3337 g_free (files);
3338 }
3339
3340 static void read_formats (const gchar * fname,
3341 GtkWidget * view)
3342 {
3343 GtkWindow * parent = GTK_WINDOW (view);
3344 gboolean dynamic = FALSE, parallel = FALSE;
3345 GSList * formats = gfs_format_new (fname, NULL, &dynamic, ¶llel);
3346
3347 if (formats == NULL || parallel) {
3348 GtkWidget * msg = gtk_message_dialog_new (parent,
3349 GTK_DIALOG_DESTROY_WITH_PARENT,
3350 GTK_MESSAGE_WARNING,
3351 GTK_BUTTONS_CLOSE,
3352 "Cannot open file `%s`",
3353 fname);
3354 gtk_dialog_run (GTK_DIALOG (msg));
3355 gtk_widget_destroy (msg);
3356 }
3357 else {
3358 gchar * g = format_glob (formats);
3359 glob_t * files;
3360
3361 files = g_malloc (sizeof (glob_t));
3362 glob (g, GLOB_NOSORT, NULL, files);
3363 if (!files->gl_pathc) {
3364 GtkWidget * msg = gtk_message_dialog_new (parent,
3365 GTK_DIALOG_DESTROY_WITH_PARENT,
3366 GTK_MESSAGE_WARNING,
3367 GTK_BUTTONS_CLOSE,
3368 "Pattern `%s` did not match any files",
3369 fname);
3370 gtk_dialog_run (GTK_DIALOG (msg));
3371 gtk_widget_destroy (msg);
3372 }
3373 else {
3374 GtkWidget * play;
3375 guint i, j;
3376
3377 for (i = 0; i < files->gl_pathc - 1; i++)
3378 for (j = 0; j < files->gl_pathc - 1 - i; j++)
3379 if (gfs_format_time_value (formats, files->gl_pathv[j + 1]) <
3380 gfs_format_time_value (formats, files->gl_pathv[j])) {
3381 gchar * tmp = files->gl_pathv[j];
3382 files->gl_pathv[j] = files->gl_pathv[j + 1];
3383 files->gl_pathv[j + 1] = tmp;
3384 }
3385
3386 i = 0;
3387 while (i < files->gl_pathc &&
3388 gfs_format_time_value (formats, files->gl_pathv[i]) < G_MAXDOUBLE)
3389 i++;
3390 j = i;
3391 while (j < files->gl_pathc) g_free (files->gl_pathv[j++]);
3392 files->gl_pathc = i;
3393 if (files->gl_pathc == 0) {
3394 GtkWidget * msg = gtk_message_dialog_new (parent,
3395 GTK_DIALOG_DESTROY_WITH_PARENT,
3396 GTK_MESSAGE_WARNING,
3397 GTK_BUTTONS_CLOSE,
3398 "Pattern `%s` did not match any files",
3399 fname);
3400 gtk_dialog_run (GTK_DIALOG (msg));
3401 gtk_widget_destroy (msg);
3402 free_glob (files);
3403 gfs_format_destroy (formats);
3404 return;
3405 }
3406
3407 files->gl_offs = 0;
3408
3409 play = create_play ();
3410 g_object_set_data_full (G_OBJECT (play), "glob_t", files, (GDestroyNotify) free_glob);
3411 g_object_set_data (G_OBJECT (play), "parent", parent);
3412 gtk_window_set_transient_for (GTK_WINDOW (play), parent);
3413 gtk_window_set_position (GTK_WINDOW (play), GTK_WIN_POS_CENTER_ON_PARENT);
3414 gtk_widget_show (play);
3415
3416 gfk_gl_simulation_read (files->gl_pathv[0], view, TRUE);
3417 }
3418 g_free (g);
3419 }
3420 gfs_format_destroy (formats);
3421 }
3422
3423 static GfsSimulation * gl_simulation_read (GtsFile * fp,
3424 const gchar * fname,
3425 GtkWindow * parent)
3426 {
3427 GfsSimulation * sim;
3428
3429 if ((sim = gfs_simulation_read (fp)) == NULL) {
3430 gchar * basename = g_path_get_basename (fname);
3431 GtkWidget * msg = gtk_message_dialog_new (parent,
3432 GTK_DIALOG_DESTROY_WITH_PARENT,
3433 GTK_MESSAGE_WARNING,
3434 GTK_BUTTONS_CLOSE,
3435 "File `%s' is not a valid Gerris file\n"
3436 "%s:%d:%d: %s\n",
3437 basename, basename,
3438 fp->line, fp->pos, fp->error);
3439 g_free (basename);
3440 gtk_dialog_run (GTK_DIALOG (msg));
3441 gtk_widget_destroy (msg);
3442 return NULL;
3443 }
3444 else
3445 gfs_simulation_init (sim);
3446 return sim;
3447 }
3448
3449 gboolean gfk_gl_view_read_parameters (GtkWidget * view, GtsFile * fp, gboolean discard)
3450 {
3451 GfkGl * gl = NULL;
3452 GtkWidget * pref, * glarea, * list;
3453 GfsGlViewParams * params;
3454 GfsSimulation * sim;
3455
3456 g_return_val_if_fail (view != NULL, FALSE);
3457 g_return_val_if_fail (fp != NULL, FALSE);
3458
3459 pref = lookup_widget (view, "preferences");
3460 glarea = lookup_widget (view, "glarea");
3461 params = g_object_get_data (G_OBJECT (glarea), "GfsGlViewParams");
3462 list = lookup_widget (view, "gl_list");
3463 sim = g_object_get_data (G_OBJECT (glarea), "sim");
3464
3465 while (fp->type == GTS_STRING) {
3466 if (!strcmp (fp->token->str, "View")) {
3467 GfsGlViewParams p = *params;
3468
3469 gfs_gl_view_params_read (&p, fp);
3470 if (!discard) {
3471 GtkWidget * bgcolor = lookup_widget (pref, "bgcolor");
3472 GtkWidget * colorsel = g_object_get_data (G_OBJECT (bgcolor), "colorsel");
3473 GdkColor c;
3474
3475 *params = p;
3476 c.red = params->bg.r*65535; c.green = params->bg.g*65535; c.blue = params->bg.b*65535;
3477 gtk_widget_modify_bg (bgcolor, GTK_STATE_NORMAL, &c);
3478 gtk_widget_modify_bg (bgcolor, GTK_STATE_PRELIGHT, &c);
3479 gtk_widget_modify_bg (bgcolor, GTK_STATE_ACTIVE, &c);
3480 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (lookup_widget
3481 (colorsel, "colorselection2")),
3482 &c);
3483 gtk_spin_button_set_value (lookup_widget_params (pref, "resolution"), params->base_res);
3484 gtk_spin_button_set_value (lookup_widget_params (pref, "lc"), params->lc);
3485 gtk_spin_button_set_value (lookup_widget_params (pref, "reactivity"), params->reactivity);
3486 gtk_spin_button_set_value (lookup_widget_params (pref, "sx"), params->sx);
3487 gtk_spin_button_set_value (lookup_widget_params (pref, "sy"), params->sy);
3488 gtk_spin_button_set_value (lookup_widget_params (pref, "sz"), params->sz);
3489 }
3490 }
3491 else {
3492 if (discard) {
3493 GfsGl * g;
3494
3495 if ((g = gfs_gl_new_from_file (fp)))
3496 gts_object_destroy (GTS_OBJECT (g));
3497 else
3498 break;
3499 }
3500 else {
3501 GtsObjectClass * klass = gts_object_class_from_name (fp->token->str);
3502 GtsObject * o;
3503
3504 if (klass == NULL) {
3505 gchar * ename = g_strconcat ("GfkGl", fp->token->str, NULL);
3506 klass = gts_object_class_from_name (ename);
3507 g_free (ename);
3508 }
3509 if (klass == NULL || !gts_object_class_is_from_class (klass, gfk_gl_class ()))
3510 break;
3511 gl = gfk_gl_new (GFK_GL_CLASS (klass), glarea, list);
3512 o = GTS_OBJECT (gl);
3513 (* klass->read) (&o, fp);
3514 if (fp->type == GTS_ERROR) {
3515 gts_object_destroy (o);
3516 return FALSE;
3517 }
3518 if (sim)
3519 gfk_gl_set_simulation (gl, sim);
3520 gl_add_gl (glarea, list, gl);
3521 }
3522 }
3523 if (fp->type == GTS_ERROR)
3524 return FALSE;
3525 gts_file_next_token (fp);
3526 }
3527 if (gl != NULL)
3528 gfk_gl_expose (gl);
3529 return TRUE;
3530 }
3531
3532 GfsSimulation * gfk_gl_simulation_read (const gchar * fname,
3533 GtkWidget * view,
3534 gboolean set)
3535 {
3536 GtsFile * fp;
3537 GfsSimulation * sim = NULL;
3538 FILE * fptr;
3539
3540 g_return_val_if_fail (fname != NULL, NULL);
3541 g_return_val_if_fail (view != NULL, NULL);
3542
3543 if (g_file_test (fname, G_FILE_TEST_IS_REGULAR))
3544 fptr = gfs_gl_popen (fname);
3545 else {
3546 read_formats (fname, view);
3547 return NULL;
3548 }
3549 if (fptr == NULL)
3550 return NULL;
3551 fp = gts_file_new (fptr);
3552 while (fp->type == GTS_STRING || fp->type == GTS_INT) {
3553 if (!gfk_gl_view_read_parameters (view, fp, FALSE)) {
3554 gchar * basename = g_path_get_basename (fname);
3555 GtkWidget * msg = gtk_message_dialog_new (GTK_WINDOW (view),
3556 GTK_DIALOG_DESTROY_WITH_PARENT,
3557 GTK_MESSAGE_WARNING,
3558 GTK_BUTTONS_CLOSE,
3559 "File `%s' is not a valid GfsView file\n"
3560 "%s:%d:%d: %s\n",
3561 basename, basename,
3562 fp->line, fp->pos, fp->error);
3563 g_free (basename);
3564 gtk_dialog_run (GTK_DIALOG (msg));
3565 gtk_widget_destroy (msg);
3566 gts_file_destroy (fp);
3567 pclose (fptr);
3568 return sim;
3569 }
3570 if (fp->type == GTS_INT || !strcmp (fp->token->str, "GModule")) {
3571 GfsSimulation * sim1 = gl_simulation_read (fp, fname, GTK_WINDOW (view));
3572 if (sim1) {
3573 if (sim && !set)
3574 gts_object_destroy (GTS_OBJECT (sim));
3575 sim = sim1;
3576 if (set)
3577 gfk_gl_view_set_simulation (view, sim, fname);
3578 }
3579 }
3580 }
3581 gts_file_destroy (fp);
3582 pclose (fptr);
3583 return sim;
3584 }
3585
3586 static gint filew_ok (GtkWidget * widget, GtkWidget * filew)
3587 {
3588 GtkWidget * view = g_object_get_data (G_OBJECT (filew), "view");
3589 const gchar * fname = gtk_file_selection_get_filename (GTK_FILE_SELECTION (filew));
3590
3591 gtk_widget_hide (filew);
3592 gfk_gl_simulation_read (fname, view, TRUE);
3593 return TRUE;
3594 }
3595
3596 static void substract (FttCell * from, FttCell * cell, gpointer * data)
3597 {
3598 GfsDomain * domain = data[0];
3599 GSList * i = data[1], * j = domain->variables;
3600
3601 while (j) {
3602 GfsVariable * v = j->data;
3603 if (v->name) {
3604 gint index = GPOINTER_TO_INT (i->data);
3605 if (index >= 0)
3606 GFS_VALUE (from, v) -= GFS_VALUEI (cell, index);
3607 i = i->next;
3608 }
3609 j = j->next;
3610 }
3611 }
3612
3613 static void outside (FttCell * cell, gpointer * data)
3614 {
3615 GfsDomain * domain = data[0];
3616 GSList * i = data[1], * j = domain->variables;
3617
3618 while (j) {
3619 GfsVariable * v = j->data;
3620 if (v->name) {
3621 gint index = GPOINTER_TO_INT (i->data);
3622 if (index >= 0)
3623 GFS_VALUE (cell, v) = 0.;
3624 i = i->next;
3625 }
3626 j = j->next;
3627 }
3628 }
3629
3630 static gint filews_ok (GtkWidget * widget, GtkWidget * filew)
3631 {
3632 GtkWidget * view = g_object_get_data (G_OBJECT (filew), "view");
3633 const gchar * fname = gtk_file_selection_get_filename (GTK_FILE_SELECTION (filew));
3634 GfsSimulation * sim;
3635 gpointer data[2];
3636
3637 gtk_widget_hide (filew);
3638 if ((sim = gfk_gl_simulation_read (fname, view, FALSE)) != NULL) {
3639 GtkWidget * glarea = lookup_widget (view, "glarea");
3640 GfsDomain * domain = g_object_get_data (G_OBJECT (glarea), "sim");
3641 GSList * i = domain->variables;
3642 gchar * missing = g_strdup (""), * title, * basename, * s;
3643 GSList * indices = NULL;
3644
3645 while (i) {
3646 GfsVariable * v = i->data;
3647 if (v->name) {
3648 GfsVariable * v1 = gfs_variable_from_name (GFS_DOMAIN (sim)->variables, v->name);
3649
3650 if (v1 != NULL)
3651 indices = g_slist_append (indices, GINT_TO_POINTER ((gint) v1->i));
3652 else {
3653 gchar * s = missing;
3654 missing = s[0] == '\0' ? g_strdup (v->name) : g_strjoin (",", missing, v->name, NULL);
3655 g_free (s);
3656 indices = g_slist_append (indices, GINT_TO_POINTER (-1));
3657 }
3658 }
3659 i = i->next;
3660 }
3661
3662 if (missing[0] != '\0') {
3663 GtkWidget * msg = gtk_message_dialog_new (GTK_WINDOW (view),
3664 GTK_DIALOG_DESTROY_WITH_PARENT,
3665 GTK_MESSAGE_WARNING,
3666 GTK_BUTTONS_CLOSE,
3667 "The following variables are absent\n"
3668 "from the simulation file:\n%s",
3669 missing);
3670 gtk_dialog_run (GTK_DIALOG (msg));
3671 gtk_widget_destroy (msg);
3672 }
3673 g_free (missing);
3674
3675 gfs_domain_cell_traverse (GFS_DOMAIN (sim),
3676 FTT_POST_ORDER, FTT_TRAVERSE_NON_LEAFS, -1,
3677 (FttCellTraverseFunc) gfs_cell_coarse_init, sim);
3678 data[0] = domain;
3679 data[1] = indices;
3680 gfs_domain_combine_traverse (domain, GFS_DOMAIN (sim),
3681 (FttCellCombineTraverseFunc) substract, data,
3682 (FttCellTraverseFunc) outside, data);
3683 gfs_domain_cell_traverse (domain,
3684 FTT_POST_ORDER, FTT_TRAVERSE_NON_LEAFS, -1,
3685 (FttCellTraverseFunc) gfs_cell_coarse_init, domain);
3686 i = domain->variables;
3687 while (i) {
3688 gfs_domain_bc (domain, FTT_TRAVERSE_ALL, -1, i->data);
3689 i = i->next;
3690 }
3691
3692 g_slist_free (indices);
3693 gts_object_destroy (GTS_OBJECT (sim));
3694
3695 basename = g_path_get_basename (fname);
3696 title = g_strjoin (" - ", gtk_window_get_title (GTK_WINDOW (view)), basename, NULL);
3697 if ((s = strstr (title, "GfsView: ")))
3698 s += strlen ("GfsView: ");
3699 else
3700 s = title;
3701 gfk_gl_view_set_simulation (view, GFS_SIMULATION (domain), s);
3702 g_free (title);
3703 g_free (basename);
3704 }
3705 return TRUE;
3706 }
3707
3708 G_LOCK_DEFINE (scripting_pending);
3709
3710 gboolean gfk_receive_scripting_message (gpointer data)
3711 {
3712 GfkScriptingMessage * msg = data;
3713 switch (msg->event) {
3714 case GFS_SAVE_EVENT: case GFS_APPEND_EVENT: {
3715 GfsGl2PSParams * p = msg->data;
3716 gfs_gl2ps (p, p->fp, "", msg->view);
3717 if (p->fp == stdout || p->fp == stderr || (msg->event == GFS_APPEND_EVENT))
3718 fflush (p->fp);
3719 else
3720 fclose (p->fp);
3721 break;
3722 }
3723 case GFS_ECHO_EVENT:
3724 puts (msg->data);
3725 fflush (stdout);
3726 break;
3727 }
3728
3729 g_free (msg->data);
3730 g_free (msg);
3731 G_UNLOCK (scripting_pending);
3732 return FALSE;
3733 }
3734
3735 static void on_gl_list_destroy (GtkTreeView * tree)
3736 {
3737 GtkTreeModel * model = gtk_tree_view_get_model (tree);
3738 GtkTreeIter iter;
3739 gboolean valid;
3740
3741 valid = gtk_tree_model_get_iter_first (model, &iter);
3742 while (valid) {
3743 GfkGl * gl;
3744
3745 gtk_tree_model_get (model, &iter, GL_COLUMN, &gl, -1);
3746 gts_object_destroy (GTS_OBJECT (gl));
3747 valid = gtk_tree_model_iter_next (model, &iter);
3748 }
3749 }
3750
3751 void gfk_gl_view_set_scripting (GtkWidget * view, gboolean active)
3752 {
3753 g_return_if_fail (view != NULL);
3754
3755 GtkWidget * pref = lookup_widget (view, "preferences");
3756 if (active) {
3757 gtk_widget_set_sensitive (lookup_widget (pref, "scripting_label"), TRUE);
3758 gtk_widget_set_sensitive (lookup_widget (pref, "scripting_on"), TRUE);
3759 gtk_widget_set_sensitive (lookup_widget (pref, "scripting_off"), TRUE);
3760 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (pref, "scripting_on")), TRUE);
3761 }
3762 else {
3763 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (pref, "scripting_off")), TRUE);
3764 gtk_widget_set_sensitive (lookup_widget (pref, "scripting_label"), FALSE);
3765 gtk_widget_set_sensitive (lookup_widget (pref, "scripting_on"), FALSE);
3766 gtk_widget_set_sensitive (lookup_widget (pref, "scripting_off"), FALSE);
3767 }
3768 G_LOCK (gfk_gl_scripting);
3769 gfk_gl_scripting = active;
3770 G_UNLOCK (gfk_gl_scripting);
3771 }
3772
3773 GtkWidget * gfk_gl_view (GtkWidget * glarea)
3774 {
3775 GtkWidget * view, * tree, * pref, * colorsel, * colorb, * gl2ps, * about, * filew, * size;
3776 GtkListStore * store;
3777 GtkTreeViewColumn * column;
3778 GtkToolbar * toolbar;
3779 GtkTreeSelection * select;
3780 GtkCellRenderer * renderer;
3781 GfsGlViewParams * p;
3782 GfsGl2PSParams * q;
3783 gdouble * ratio;
3784 GdkColor c;
3785
3786 GtkMenu * vector, * scalar, * mesh, * special;
3787
3788 g_return_val_if_fail (glarea != NULL, NULL);
3789
3790 p = gfs_gl_view_params_new ();
3791 g_object_set_data_full (G_OBJECT (glarea), "GfsGlViewParams", p, g_free);
3792
3793 view = create_view ();
3794 gtk_container_add (GTK_CONTAINER (lookup_widget (view, "frame1")), glarea);
3795 g_object_set_data (G_OBJECT (view), "glarea", glarea);
3796
3797 tree = lookup_widget (view, "gl_list");
3798 g_signal_connect (G_OBJECT (tree), "destroy", (GCallback) on_gl_list_destroy, NULL);
3799 store = gtk_list_store_new (N_COLUMNS,
3800 G_TYPE_BOOLEAN,
3801 GDK_TYPE_PIXBUF,
3802 G_TYPE_STRING,
3803 G_TYPE_POINTER,
3804 G_TYPE_BOOLEAN);
3805 g_object_set_data (G_OBJECT (glarea), "list", store);
3806 gtk_tree_view_set_model (GTK_TREE_VIEW (tree), GTK_TREE_MODEL (store));
3807 select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
3808 gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
3809 g_signal_connect (tree, "row-activated", (GCallback) on_properties1_activate, NULL);
3810 gtk_tree_selection_set_select_function (select, tree_selection_func, NULL, NULL);
3811 g_signal_connect (G_OBJECT (select), "changed", G_CALLBACK (tree_selection_changed_cb), tree);
3812
3813 renderer = gtk_cell_renderer_pixbuf_new ();
3814 column = gtk_tree_view_column_new_with_attributes ("Icon", renderer,
3815 "pixbuf", ICON_COLUMN,
3816 NULL);
3817 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
3818
3819 renderer = gtk_cell_renderer_toggle_new ();
3820 g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (visible_toggled), store);
3821 column = gtk_tree_view_column_new_with_attributes ("Visible", renderer,
3822 "active", VISIBLE_COLUMN,
3823 NULL);
3824 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
3825
3826 renderer = gtk_cell_renderer_text_new ();
3827 column = gtk_tree_view_column_new_with_attributes ("Properties", renderer,
3828 "text", PROPERTIES_COLUMN,
3829 NULL);
3830 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
3831
3832 vector = GTK_MENU (gtk_menu_new ());
3833 gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget (view, "vector1")),
3834 GTK_WIDGET (vector));
3835 scalar = GTK_MENU (gtk_menu_new ());
3836 gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget (view, "scalar1")),
3837 GTK_WIDGET (scalar));
3838 mesh = GTK_MENU (gtk_menu_new ());
3839 gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget (view, "mesh1")),
3840 GTK_WIDGET (mesh));
3841 special = GTK_MENU (gtk_menu_new ());
3842 gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget (view, "special1")),
3843 GTK_WIDGET (special));
3844
3845 toolbar = GTK_TOOLBAR (lookup_widget (view, "toolbar"));
3846 gfk_gl_tool_append (gfk_gl_vectors_class (), toolbar, vector, tree, glarea);
3847 gfk_gl_tool_append (gfk_gl_streamlines_class (), toolbar, vector, tree, glarea);
3848 gfk_gl_tool_append (gfk_gl_squares_class (), toolbar, scalar, tree, glarea);
3849 gfk_gl_tool_append (gfk_gl_linear_class (), toolbar, scalar, tree, glarea);
3850 gfk_gl_tool_append (gfk_gl_isoline_class (), toolbar, scalar, tree, glarea);
3851 gfk_gl_tool_append (gfk_gl_cells_class (), toolbar, mesh, tree, glarea);
3852 gfk_gl_tool_append (gfk_gl_solid_class (), toolbar, mesh, tree, glarea);
3853 gfk_gl_tool_append (gfk_gl_vof_class (), toolbar, scalar, tree, glarea);
3854
3855 gfk_gl_menu_append (gfk_gl_boundaries_class (), mesh, tree, glarea);
3856 gfk_gl_menu_append (gfk_gl_levels_class (), mesh, tree, glarea);
3857 gfk_gl_menu_append (gfk_gl_fractions_class (), mesh, tree, glarea);
3858 gfk_gl_menu_append (gfk_gl_symmetry_class (), mesh, tree, glarea);
3859 gfk_gl_menu_append (gfk_gl_periodic_class (), mesh, tree, glarea);
3860 gfk_gl_menu_append (gfk_gl_height_class (), scalar, tree, glarea);
3861 gfk_gl_menu_append (gfk_gl_location_class (), special, tree, glarea);
3862 gfk_gl_menu_append (gfk_gl_ellipses_class (), special, tree, glarea);
3863 gfk_gl_menu_append (gfk_gl_info_class (), special, tree, glarea);
3864 gfk_gl_menu_append (gfk_gl_label_class (), special, tree, glarea);
3865 gfk_gl_menu_append (gfk_gl_locate_class (), special, tree, glarea);
3866 gfk_gl_menu_append (gfk_gl_clip_plane_class (), special, tree, glarea);
3867 gfk_gl_menu_append (gfk_gl_pipes_class (), special, tree, glarea);
3868
3869 #if (!FTT_2D)
3870 gfk_gl_tool_append (gfk_gl_isosurface_class (), toolbar, scalar, tree, glarea);
3871 gfk_gl_menu_append (gfk_gl_cut_plane_class (), special, tree, glarea);
3872 #endif /* 3D */
3873
3874 about = create_about ();
3875 gtk_window_set_transient_for (GTK_WINDOW (about), GTK_WINDOW (view));
3876 gtk_window_set_destroy_with_parent (GTK_WINDOW (about), TRUE);
3877 gtk_window_set_position (GTK_WINDOW (about), GTK_WIN_POS_CENTER_ON_PARENT);
3878 g_signal_connect (G_OBJECT (about), "delete_event",
3879 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
3880 g_object_set_data (G_OBJECT (view), "about", about);
3881
3882 filew = gtk_file_selection_new ("Select a Gerris simulation");
3883 gtk_window_set_transient_for (GTK_WINDOW (filew), GTK_WINDOW (view));
3884 gtk_window_set_destroy_with_parent (GTK_WINDOW (filew), TRUE);
3885 gtk_window_set_position (GTK_WINDOW (filew), GTK_WIN_POS_CENTER_ON_PARENT);
3886 g_signal_connect (G_OBJECT (filew), "delete_event",
3887 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
3888 g_object_set_data (G_OBJECT (filew), "view", view);
3889 g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), "clicked",
3890 G_CALLBACK (filew_ok), filew);
3891 g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button), "clicked",
3892 G_CALLBACK (gtk_widget_hide), filew);
3893 g_object_set_data (G_OBJECT (view), "filew", filew);
3894
3895 filew = gtk_file_selection_new ("Select a Gerris simulation");
3896 gtk_window_set_transient_for (GTK_WINDOW (filew), GTK_WINDOW (view));
3897 gtk_window_set_destroy_with_parent (GTK_WINDOW (filew), TRUE);
3898 gtk_window_set_position (GTK_WINDOW (filew), GTK_WIN_POS_CENTER_ON_PARENT);
3899 g_signal_connect (G_OBJECT (filew), "delete_event",
3900 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
3901 g_object_set_data (G_OBJECT (filew), "view", view);
3902 g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), "clicked",
3903 G_CALLBACK (filews_ok), filew);
3904 g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button), "clicked",
3905 G_CALLBACK (gtk_widget_hide), filew);
3906 g_object_set_data (G_OBJECT (view), "filews", filew);
3907
3908 pref = create_preferences ();
3909 gtk_window_set_transient_for (GTK_WINDOW (pref), GTK_WINDOW (view));
3910 gtk_window_set_destroy_with_parent (GTK_WINDOW (pref), TRUE);
3911 gtk_window_set_position (GTK_WINDOW (pref), GTK_WIN_POS_CENTER_ON_PARENT);
3912 g_signal_connect (G_OBJECT (pref), "delete_event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
3913 g_object_set_data (G_OBJECT (view), "preferences", pref);
3914 g_object_set_data (G_OBJECT (pref), "view", view);
3915 gfk_gl_view_set_scripting (view, FALSE);
3916 #if FTT_2D
3917 gtk_widget_hide (lookup_widget (pref, "sz_label"));
3918 gtk_widget_hide (lookup_widget (pref, "sz"));
3919 #endif /* 2D */
3920
3921 colorsel = create_bg_color_selector ();
3922 gtk_window_set_transient_for (GTK_WINDOW (colorsel), GTK_WINDOW (pref));
3923 gtk_window_set_destroy_with_parent (GTK_WINDOW (colorsel), TRUE);
3924 gtk_window_set_position (GTK_WINDOW (colorsel), GTK_WIN_POS_CENTER_ON_PARENT);
3925 g_signal_connect (G_OBJECT (colorsel), "delete_event",
3926 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
3927 c.red = p->bg.r*65535; c.green = p->bg.g*65535; c.blue = p->bg.b*65535;
3928 gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (lookup_widget (colorsel,
3929 "colorselection2")),
3930 &c);
3931
3932 colorb = lookup_widget_params (pref, "bgcolor");
3933 g_object_set_data (G_OBJECT (colorb), "colorsel", colorsel);
3934 gtk_widget_modify_bg (colorb, GTK_STATE_NORMAL, &c);
3935 gtk_widget_modify_bg (colorb, GTK_STATE_PRELIGHT, &c);
3936 gtk_widget_modify_bg (colorb, GTK_STATE_ACTIVE, &c);
3937 g_object_set_data (G_OBJECT (colorsel), "bgcolor", colorb);
3938
3939 gl2ps = create_gl2ps ();
3940 gtk_window_set_transient_for (GTK_WINDOW (gl2ps), GTK_WINDOW (view));
3941 gtk_window_set_destroy_with_parent (GTK_WINDOW (gl2ps), TRUE);
3942 gtk_window_set_position (GTK_WINDOW (gl2ps), GTK_WIN_POS_CENTER_ON_PARENT);
3943 g_signal_connect (G_OBJECT (gl2ps), "delete_event",
3944 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
3945 g_object_set_data (G_OBJECT (view), "gl2ps", gl2ps);
3946 g_object_set_data (G_OBJECT (gl2ps), "view", view);
3947
3948 size = lookup_widget (gl2ps, "size");
3949 gtk_widget_set_sensitive (size, FALSE);
3950 g_signal_connect (G_OBJECT (glarea), "expose_event", G_CALLBACK (gl2ps_update_ppm_size), size);
3951 ratio = g_malloc (sizeof (gdouble));
3952 g_object_set_data_full (G_OBJECT (size), "ratio", ratio, g_free);
3953
3954 q = g_malloc (sizeof (GfsGl2PSParams));
3955 q->width = q->height = 0;
3956 q->format = GFSGL_PPM;
3957 q->lw = 1.;
3958 gl2ps_ppm_set_sensitive (gl2ps, FALSE, TRUE);
3959 q->sort = GL2PS_SIMPLE_SORT;
3960 gtk_option_menu_set_history (GTK_OPTION_MENU (lookup_widget (gl2ps, "sort")), 1);
3961 q->options = (GL2PS_SIMPLE_LINE_OFFSET |
3962 GL2PS_SILENT |
3963 GL2PS_BEST_ROOT |
3964 GL2PS_OCCLUSION_CULL |
3965 GL2PS_USE_CURRENT_VIEWPORT |
3966 GL2PS_TIGHT_BOUNDING_BOX);
3967 g_object_set_data_full (G_OBJECT (gl2ps), "GfsGl2PSParams", q, g_free);
3968
3969 gtk_widget_set_sensitive (lookup_widget (view, "toolbar"), FALSE);
3970 gtk_widget_set_sensitive (lookup_widget (view, "objects1"), FALSE);
3971 gtk_widget_set_sensitive (lookup_widget (view, "save1"), FALSE);
3972 gtk_widget_set_sensitive (lookup_widget (view, "edit1"), FALSE);
3973 gtk_widget_set_sensitive (lookup_widget (view, "properties1"), FALSE);
3974 gtk_widget_set_sensitive (lookup_widget (view, "delete3"), FALSE);
3975 gtk_widget_set_sensitive (lookup_widget (view, "view1"), FALSE);
3976 gtk_widget_set_sensitive (lookup_widget (view, "tools1"), FALSE);
3977 gtk_widget_set_sensitive (lookup_widget (view, "gl_list"), FALSE);
3978
3979 GtkListStore * completion = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
3980 g_object_set_data_full (G_OBJECT (view), "completion",
3981 g_object_ref (G_OBJECT (completion)), (GDestroyNotify) g_object_unref);
3982
3983 return view;
3984 }
3985
3986 void gfk_gl_view_set_simulation (GtkWidget * view, GfsSimulation * sim, const gchar * fname)
3987 {
3988 GtkWidget * glarea;
3989 GfsSimulation * prev;
3990 gchar * basename, * s;
3991 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
3992 GtkTreeModel * list;
3993 GtkTreeIter iter;
3994 gboolean valid;
3995
3996 g_return_if_fail (view != NULL);
3997 g_return_if_fail (sim != NULL);
3998 g_return_if_fail (fname != NULL);
3999
4000 g_static_mutex_lock (&mutex);
4001
4002 glarea = lookup_widget (view, "glarea");
4003 prev = g_object_get_data (G_OBJECT (glarea), "sim");
4004 g_object_set_data (G_OBJECT (glarea), "sim", sim);
4005 list = gtk_tree_view_get_model (GTK_TREE_VIEW (lookup_widget (view, "gl_list")));
4006 valid = gtk_tree_model_get_iter_first (list, &iter);
4007 while (valid) {
4008 GfkGl * gl;
4009
4010 gtk_tree_model_get (list, &iter, GL_COLUMN, &gl, -1);
4011 gfk_gl_set_simulation (gl, sim);
4012 valid = gtk_tree_model_iter_next (list, &iter);
4013 }
4014
4015 /* Remove obsolete variables from completion */
4016 list = GTK_TREE_MODEL (lookup_widget (view, "completion"));
4017 valid = gtk_tree_model_get_iter_first (list, &iter);
4018 while (valid) {
4019 gchar * name;
4020 gpointer p;
4021 gtk_tree_model_get (list, &iter,
4022 COMPLETION_NAME_COLUMN, &name,
4023 COMPLETION_POINTER_COLUMN, &p,
4024 -1);
4025 if (p) {
4026 p = gfs_variable_from_name (GFS_DOMAIN (sim)->variables, name);
4027 if (p) {
4028 gtk_list_store_set (GTK_LIST_STORE (list), &iter,
4029 COMPLETION_NAME_COLUMN, GFS_VARIABLE (p)->name,
4030 COMPLETION_DESCRIPTION_COLUMN, GFS_VARIABLE (p)->description,
4031 COMPLETION_POINTER_COLUMN, p,
4032 -1);
4033 gfs_object_simulation_set (p, NULL);
4034 valid = gtk_tree_model_iter_next (list, &iter);
4035 }
4036 else if ((p = gfs_derived_variable_from_name (GFS_DOMAIN (sim)->derived_variables, name))) {
4037 gtk_list_store_set (GTK_LIST_STORE (list), &iter,
4038 COMPLETION_NAME_COLUMN, GFS_DERIVED_VARIABLE (p)->name,
4039 COMPLETION_DESCRIPTION_COLUMN, GFS_DERIVED_VARIABLE (p)->description,
4040 COMPLETION_POINTER_COLUMN, p,
4041 -1);
4042 gfs_object_simulation_set (p, NULL);
4043 valid = gtk_tree_model_iter_next (list, &iter);
4044 }
4045 else
4046 valid = gtk_list_store_remove (GTK_LIST_STORE (list), &iter);
4047 }
4048 else
4049 valid = gtk_tree_model_iter_next (list, &iter);
4050 }
4051
4052 /* Add new variables to completion*/
4053 GSList * i = GFS_DOMAIN (sim)->variables;
4054 while (i) {
4055 GfsVariable * v = i->data;
4056 if (v->name) {
4057 if (gfs_object_simulation (v)) {
4058 gtk_list_store_append (GTK_LIST_STORE (list), &iter);
4059 gtk_list_store_set (GTK_LIST_STORE (list), &iter,
4060 COMPLETION_NAME_COLUMN, v->name,
4061 COMPLETION_DESCRIPTION_COLUMN, v->description,
4062 COMPLETION_POINTER_COLUMN, v,
4063 -1);
4064 }
4065 else
4066 gfs_object_simulation_set (v, sim);
4067 }
4068 i = i->next;
4069 }
4070
4071 /* Add new derived variables to completion */
4072 i = GFS_DOMAIN (sim)->derived_variables;
4073 while (i) {
4074 GfsDerivedVariable * v = i->data;
4075 if (v->name) {
4076 if (gfs_object_simulation (v)) {
4077 gtk_list_store_append (GTK_LIST_STORE (list), &iter);
4078 gtk_list_store_set (GTK_LIST_STORE (list), &iter,
4079 COMPLETION_NAME_COLUMN, v->name,
4080 COMPLETION_DESCRIPTION_COLUMN, v->description,
4081 COMPLETION_POINTER_COLUMN, v,
4082 -1);
4083 }
4084 else
4085 gfs_object_simulation_set (v, sim);
4086 }
4087 i = i->next;
4088 }
4089
4090 if (prev == NULL) {
4091 gtk_widget_set_sensitive (lookup_widget (view, "toolbar"), TRUE);
4092 gtk_widget_set_sensitive (lookup_widget (view, "objects1"), TRUE);
4093 gtk_widget_set_sensitive (lookup_widget (view, "tools1"), TRUE);
4094 gtk_widget_set_sensitive (lookup_widget (view, "gl_list"), TRUE);
4095 }
4096 else if (prev != sim)
4097 gts_object_destroy (GTS_OBJECT (prev));
4098
4099 basename = g_path_get_basename (fname);
4100 s = g_strdup_printf ("GfsView: %s: t = %g", basename, sim->time.t);
4101 gtk_window_set_title (GTK_WINDOW (view), s);
4102 g_free (s);
4103 g_free (basename);
4104
4105 g_static_mutex_unlock (&mutex);
4106 }
4107
4108 void gfk_gl_view_draw (GtkWidget * view, guint format)
4109 {
4110 GtkWidget * glarea;
4111 GfsGlViewParams * p;
4112 GtkTreeModel * list;
4113 GtkTreeIter iter;
4114 gboolean valid;
4115 guint size = 0;
4116 GTimer * timer;
4117
4118 g_return_if_fail (view != NULL);
4119
4120 timer = g_timer_new ();
4121 g_timer_start (timer);
4122
4123 glarea = g_object_get_data (G_OBJECT (view), "glarea");
4124 p = g_object_get_data (G_OBJECT (glarea), "GfsGlViewParams");
4125
4126 if (p->motion) {
4127 if (p->timing > p->reactivity) {
4128 if (p->res == 0.) p->res = 1.;
4129 p->res *= exp (ceil (log (p->timing/p->reactivity)/log(4.))*log (2.));
4130 if (p->res > 50.)
4131 p->res = 50.;
4132 }
4133 }
4134 else
4135 p->res = p->base_res;
4136
4137 list = gtk_tree_view_get_model (GTK_TREE_VIEW (lookup_widget (view, "gl_list")));
4138 GList * symmetries = get_symmetries (list);
4139 GfsFrustum frustum;
4140 gfs_gl_get_frustum (p, symmetries, &frustum);
4141 GLuint display_list = glGenLists (1);
4142 GList * gl_list = NULL;
4143 valid = gtk_tree_model_get_iter_first (list, &iter);
4144 while (valid) {
4145 gboolean visible;
4146 GfkGl * gl;
4147
4148 gtk_tree_model_get (list, &iter, GL_COLUMN, &gl, VISIBLE_COLUMN, &visible, -1);
4149 if (GFK_IS_GL_CLIP_PLANE (gl)) {
4150 gfs_gl_clip_plane_disable (GFS_GL_CLIP_PLANE (gl->gl));
4151 GFS_GL_CLIP_PLANE (gl->gl)->disabled = !visible;
4152 }
4153 else if (visible || !GFS_IS_GL_CUT_PLANE (gl->gl))
4154 gl_list = g_list_append (gl_list, gl->gl);
4155 valid = gtk_tree_model_iter_next (list, &iter);
4156 }
4157
4158 glNewList (display_list, GL_COMPILE);
4159 GList * i = gl_list;
4160 while (i) {
4161 GfsGl * gl = i->data;
4162 if (GFS_IS_GL_CUT_PLANE (gl)) {
4163 GFS_GL_CUT_PLANE (gl)->list = gl_list;
4164 gl->format = format;
4165 gfs_gl_draw (gl, &frustum);
4166 if (gl->size > size)
4167 size = gl->size;
4168 GFS_GL_CUT_PLANE (gl)->list = NULL;
4169 }
4170 i = i->next;
4171 }
4172 g_list_free (gl_list);
4173
4174 GSList * clip = NULL;
4175 gboolean firstclip = TRUE;
4176 valid = gtk_tree_model_get_iter_first (list, &iter);
4177 while (valid) {
4178 gboolean visible;
4179 GfkGl * gl;
4180
4181 gtk_tree_model_get (list, &iter, GL_COLUMN, &gl, VISIBLE_COLUMN, &visible, -1);
4182 if (visible) {
4183 gl->gl->format = format;
4184 if (GFK_IS_GL_CLIP_PLANE (gl)) {
4185 if (firstclip) {
4186 g_slist_foreach (clip, (GFunc) gfs_gl_clip_plane_disable, NULL);
4187 g_slist_free (clip); clip = NULL;
4188 firstclip = FALSE;
4189 }
4190 gfs_gl_draw (gl->gl, &frustum);
4191 clip = g_slist_prepend (clip, gl->gl);
4192 }
4193 else {
4194 gfs_gl_draw (gl->gl, &frustum);
4195 if (gl->gl->size > size)
4196 size = gl->gl->size;
4197 firstclip = TRUE;
4198 }
4199 }
4200 else if (!GFK_IS_GL_CLIP_PLANE (gl))
4201 firstclip = TRUE;
4202 valid = gtk_tree_model_iter_next (list, &iter);
4203 }
4204 g_slist_free (clip);
4205 glEndList();
4206
4207 gfs_gl_symmetry_apply (symmetries, display_list);
4208 gfs_gl_frustum_free (&frustum);
4209 g_list_free (symmetries);
4210 glDeleteLists (display_list, 1);
4211
4212 g_timer_stop (timer);
4213 p->timing = g_timer_elapsed (timer, NULL);
4214 g_timer_destroy (timer);
4215
4216 if (size > 0) {
4217 GtkStatusbar * status = GTK_STATUSBAR (lookup_widget (view, "statusbar1"));
4218 guint id = gtk_statusbar_get_context_id (status, "glarea");
4219 gchar * s = g_strdup_printf (" %d items, %g s", size, p->timing);
4220
4221 gtk_statusbar_pop (status, id);
4222 gtk_statusbar_push (status, id, s);
4223 g_free (s);
4224 }
4225 }
4226
4227 void gfk_gl_view_pick (GtkWidget * view, GfsGlRay * ray, gboolean motion)
4228 {
4229 GtkWidget * tree;
4230 GtkTreeModel * list;
4231 GtkTreeSelection * select;
4232 GtkTreeIter iter, picked;
4233 gboolean valid;
4234 GfkGl * glmin = NULL;
4235 gdouble zmin = G_MAXDOUBLE/2.;
4236
4237 GtkStatusbar * status;
4238 guint id;
4239
4240 g_return_if_fail (view != NULL);
4241 g_return_if_fail (ray != NULL);
4242
4243 tree = lookup_widget (view, "gl_list");
4244 list = gtk_tree_view_get_model (GTK_TREE_VIEW (tree));
4245 select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
4246 valid = gtk_tree_model_get_iter_first (list, &iter);
4247 while (valid) {
4248 gboolean visible;
4249 GfkGl * gl;
4250
4251 gtk_tree_model_get (list, &iter, GL_COLUMN, &gl, VISIBLE_COLUMN, &visible, -1);
4252 if (visible && GFS_GL_CLASS (GTS_OBJECT (gl->gl)->klass)->pick) {
4253 gdouble z = (* GFS_GL_CLASS (GTS_OBJECT (gl->gl)->klass)->pick) (gl->gl, ray);
4254
4255 if (z < zmin || (z == zmin && gtk_tree_selection_iter_is_selected (select, &iter))) {
4256 glmin = gl;
4257 zmin = z;
4258 picked = iter;
4259 }
4260 }
4261 valid = gtk_tree_model_iter_next (list, &iter);
4262 }
4263
4264 status = GTK_STATUSBAR (lookup_widget (view, "statusbar1"));
4265 id = gtk_statusbar_get_context_id (status, "pick");
4266 gtk_statusbar_pop (status, id);
4267 if (glmin) {
4268 gtk_tree_selection_select_iter (select, &picked);
4269 g_assert (GFK_GL_CLASS (GTS_OBJECT (glmin)->klass)->pickinfo);
4270 gtk_statusbar_push (status, id,
4271 (* GFK_GL_CLASS (GTS_OBJECT (glmin)->klass)->pickinfo) (glmin, motion));
4272 }
4273 }
4274
4275 void gfk_gl_view_clear (GtkWidget * view)
4276 {
4277 GtkWidget * list, * glarea;
4278 GtkTreeModel * model;
4279
4280 g_return_if_fail (view != NULL);
4281
4282 list = lookup_widget (view, "gl_list");
4283 glarea = lookup_widget (view, "glarea");
4284 model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
4285
4286 on_gl_list_destroy (GTK_TREE_VIEW (list));
4287 gtk_list_store_clear (GTK_LIST_STORE (model));
4288 g_object_set_data (G_OBJECT (list), "former", NULL);
4289
4290 gtk_widget_set_sensitive (lookup_widget (glarea, "save1"), FALSE);
4291 gtk_widget_set_sensitive (lookup_widget (glarea, "edit1"), FALSE);
4292 gtk_widget_set_sensitive (lookup_widget (glarea, "properties1"), FALSE);
4293 gtk_widget_set_sensitive (lookup_widget (glarea, "delete3"), FALSE);
4294 gtk_widget_set_sensitive (lookup_widget (glarea, "view1"), FALSE);
4295
4296 gdk_window_invalidate_rect (glarea->window, &glarea->allocation, FALSE);
4297 }