1    | /***************************************
2    |   $Header: /cvsroot/petscgraphics/tsview-ng.c,v 1.65 2006/02/05 21:27:20 hazelsct Exp $
3    | 
4    |   This program views the output of a time series saved using
5    |   +latex+{\tt IlluMultiSave()}.
6    |   +html+ <tt>IlluMultiSave()</tt>.
7    |   It basically just switches between timesteps; future versions may be more
8    |   interesting.  The neat part of it is that it loads multiprocessor data and
9    |   displays it on a single CPU.
10   |   ***************************************/
11   | 
12   | static char help[] = "Displays the output of of a timestep series saved using IlluMultiSave().\n\
13   | Usage:\n\
14   | \n\
15   |   tsview <basename> [-no_transparency]\n\
16   | \n\
17   | Then interactively flip through the timesteps (h or ? lists commands).\n";
18   | 
19   | #include "illuminator.h"
20   | #include <glade/glade.h>
21   | #include <gnome.h>
22   | #include <libgnomeui/libgnomeui.h>
23   | #include <sys/dir.h> /* For scandir(), alphasort, struct dirent */
24   | #include <libgen.h>  /* For dirname(), basename() */
25   | #include <string.h>  /* For strdup() */
26   | 
27   | /* Build with -DDEBUG for debugging output */
28   | #undef DPRINTF
29   | #ifdef DEBUG
30   | #define DPRINTF(fmt, args...) PetscPrintf (PETSC_COMM_WORLD, "%s: " fmt, __FUNCT__, args)
31   | #else
32   | #define DPRINTF(fmt, args...)
33   | #endif
34   | 
35   | /*+ Declared in illuminator.c, these give the current number of triangles on
36   |   this node and corner coordinates and color information for each triangle. +*/
37   | 
38   | GladeXML *xml;
39   | ISurface Surf;
40   | IDisplay Disp [1] = { NULL };
41   | 
42   | /* Filename list and time/log info */
43   | int entrynum=0, total_entries=0, current_timestep;
44   | char *the_basename, *basedirname, **stepnames=NULL;
45   | double current_time;
46   | char *log_text=NULL;
47   | 
48   | /* Ternary diffusion path color, and supplementary diffusion path data: there
49   |    are dp_supp_colors colors, each corresponding to a color and a number of
50   |    points in the big A and B arrays. */
51   | PetscScalar ternary_dp_color[4] = { 0.,0.,0.,1. };
52   | int dp_supp_colors=0, *dp_supp_color_points=NULL;
53   | PetscScalar *dp_supp_red=NULL, *dp_supp_green=NULL, *dp_supp_blue=NULL,
54   |   *dp_supp_alpha=NULL;
55   | PetscScalar *dp_supp_AB=NULL;
56   | 
57   | /* Window parameters and drawables */
58   | #define DEFAULT_RENDER_SIZE 300
59   | #define SCALE_WIDTH 200
60   | #define SCALE_HEIGHT 200
61   | #define SCALE_BPP 3
62   | int width=0, height=0, bpp=3, nx, ny, transform, dataview_count=1;
63   | GtkWidget *dataviews [1];
64   | IDisplay scalar_disp, ternary_square_disp, ternary_triangle_disp, ternary_disp,
65   |   vector_disp, shear_disp;
66   | gboolean scalar_auto_set=TRUE, ternary_auto_set=TRUE, ternary_square_set=FALSE,
67   |   vector_auto_set=TRUE, shear_auto_set=TRUE;
68   | gdouble sizemag;
69   | PetscTruth transp;
70   | 
71   | /* PETSc structures etc. */
72   | DA theda;
73   | Vec global;
74   | PetscScalar minmax[6] = { 0.,1., 0.,1., 0.,1. };
75   | PetscScalar scales[15]; /* 2 scalar, 6 tritern, 4 sqtern, 2 vector, 1 tensor */
76   | field_plot_type *fieldtypes;
77   | int dimensions, num_fields, current_field, *field_index, num_variables[1],
78   |   **variable_indices;
79   | 
80   | /* First some primary functions which do stuff, then callbacks, then main(). */
81   | 
82   | #undef __FUNCT__
83   | #define __FUNCT__ "render_dataviews"
84   | 
85   | /* Width and height are reversed if rotated, so use these macros with render */
86   | #define RENDER_WIDTH ((transform & ROTATE_LEFT) ? height : width)
87   | #define RENDER_HEIGHT ((transform & ROTATE_LEFT) ? width : height)
88   | 
89   | int render_dataviews ()
90   | {
91   |   int viewnum, nx,ny,nz, ierr;
92   | 
93   |   DPRINTF ("Rendering dataviews\n",0);
94   |   if (dataview_count != 1)
95   |     {
96   |       printf ("dataview_count != 1 is not yet supported\n");
97   |       exit(0);
98   |     }
99   |   for (viewnum=0; viewnum<dataview_count; viewnum++)
100  |     {
101  |       int nx,ny, xs,ys, xm,ym, i;
102  |       PetscScalar minval, maxval, refmag, *global_array;
103  |       GtkType type;
104  |       char thestatus [100];
105  | 
106  |       /* (Re)allocate buffer */
107  |       if (!Disp[0])
108  | 	{
109  | 	  DPRINTF ("Allocating IDisplay RGB buffer\n",0);
110  | 	  if (IDispCreate (Disp, width, height, width, bpp, 0)) {
111  | 	    printf ("ERROR: can't allocate RGB buffer\n");
112  | 	    exit (1); }
113  | 	}
114  |       else
115  | 	{
116  | 	  DPRINTF ("Reallocating IDisplay RGB buffer\n",0);
117  | 	  if (IDispResize (Disp[0], width, height, width, bpp, 0)) {
118  | 	    printf ("ERROR: can't reallocate RGB buffer\n");
119  | 	    exit (1); }
120  | 	}
121  |       DPRINTF ("Done, (re)sizing drawing area\n",0);
122  | 
123  |       /* Make sure the drawing area is the right size */
124  |       gtk_drawing_area_size (GTK_DRAWING_AREA (dataviews[viewnum]),
125  | 			     width, height);
126  | 
127  |       /* Render into Disp [viewnum] */
128  |       ierr = DAGetInfo (theda, PETSC_NULL, &nx,&ny,PETSC_NULL,
129  | 			PETSC_NULL,PETSC_NULL,PETSC_NULL, PETSC_NULL,
130  | 			PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
131  |       ierr = DAGetCorners (theda, &xs,&ys,PETSC_NULL, &xm,&ym,PETSC_NULL);
132  |       CHKERRQ (ierr);
133  | 
134  |       DPRINTF ("Rendering %dx%d buffer with transform %d\n", RENDER_WIDTH,
135  | 	       RENDER_HEIGHT, transform);
136  |       if (dimensions == 2)
137  | 	{
138  | 	  char maxes [6][20];
139  | 
140  | 	  ierr = VecGetArray (global, &global_array); CHKERRQ (ierr);
141  | 
142  | 	  /* Plot with automatic or manual scaling, as appropriate */
143  | 	  switch (fieldtypes [current_field])
144  | 	    {
145  | 	    case FIELD_SCALAR:
146  | 	      if (scalar_auto_set)
147  | 		{
148  | 		  auto_scale (global_array, xm*ym, num_fields, current_field,
149  | 			      FIELD_SCALAR, 2, scales);
150  | 		  snprintf (maxes[0], 19, "%g", scales[0]);
151  | 		  snprintf (maxes[1], 19, "%g", scales[1]);
152  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
153  | 						 (xml, "scalar_min_entry")),
154  | 				      maxes[0]);
155  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
156  | 						 (xml, "scalar_max_entry")),
157  | 				      maxes[1]);
158  | 		}
159  | 	      ierr = render_rgb_local_2d
160  | 		(Disp[0], global_array, num_fields,current_field, FIELD_SCALAR,
161  | 		 scales, nx,ny, xs,ys, xm,ym, transform, NULL,0,0,0,0);
162  | 	      CHKERRQ (ierr);
163  | 	      break;
164  | 
165  | 	    case FIELD_TERNARY:
166  | 	    case FIELD_TERNARY_SQUARE:
167  | 	      if (!ternary_square_set) /* Ternary triangle */
168  | 		{
169  | 		  GtkWidget *ternary_scale_area = glade_xml_get_widget
170  | 		    (xml, "ternary_scale_area");
171  | 		  int color, point, i;
172  | 
173  | 		  if (ternary_auto_set)
174  | 		    {
175  | 		      auto_scale (global_array, xm*ym, num_fields,
176  | 				  current_field, FIELD_TERNARY, 2, scales+2);
177  | 		      snprintf (maxes[0], 19, "%g", scales[2]);
178  | 		      snprintf (maxes[1], 19, "%g", scales[3]);
179  | 		      snprintf (maxes[2], 19, "%g", scales[4]);
180  | 		      snprintf (maxes[3], 19, "%g", scales[5]);
181  | 		      snprintf (maxes[4], 19, "%g", scales[6]);
182  | 		      snprintf (maxes[5], 19, "%g", scales[7]);
183  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
184  | 						     (xml,"ternary_1A_entry")),
185  | 					  maxes[0]);
186  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
187  | 						     (xml,"ternary_1B_entry")),
188  | 					  maxes[1]);
189  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
190  | 						     (xml,"ternary_2A_entry")),
191  | 					  maxes[2]);
192  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget 
193  | 						     (xml,"ternary_2B_entry")),
194  | 					  maxes[3]);
195  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
196  | 						     (xml,"ternary_3A_entry")),
197  | 					  maxes[4]);
198  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
199  | 						     (xml,"ternary_3B_entry")),
200  | 					  maxes[5]);
201  | 		    }
202  | 
203  | 		  /* Start with blank ternary scale */
204  | 		  render_scale_2d (ternary_triangle_disp, FIELD_TERNARY, 1);
205  | 		  /* Overlay diffusion path supplements on scale */
206  | 		  for (color=0, i=0; color<dp_supp_colors;
207  | 		       i+=dp_supp_color_points[color++])
208  | 		    render_composition_path
209  | 		      (ternary_triangle_disp, dp_supp_AB+i*2,
210  | 		       dp_supp_color_points[color], 2, FIELD_TERNARY, scales+2,
211  | 		       dp_supp_red[color], dp_supp_green[color],
212  | 		       dp_supp_blue[color], dp_supp_alpha[color]);
213  | 		  /* Render diagram, add diffusion path to scale */
214  | 		  ierr = render_rgb_local_2d
215  | 		    (Disp[0], global_array, num_fields, current_field,
216  | 		     FIELD_TERNARY, scales+2, nx,ny, xs,ys, xm,ym, transform,
217  | 		     ternary_triangle_disp,
218  | 		     ternary_dp_color[0],ternary_dp_color[1],
219  | 		     ternary_dp_color[2],ternary_dp_color[3]);
220  | 		  CHKERRQ (ierr);
221  | 		  IDispDrawGdk (ternary_triangle_disp, ternary_scale_area,
222  | 				GDK_RGB_DITHER_MAX);
223  | 		}
224  | 	      else /* Ternary square */
225  | 		{
226  | 		  GtkWidget *ternary_scale_area = glade_xml_get_widget
227  | 		    (xml, "ternary_scale_area");
228  | 
229  | 		  if (ternary_auto_set)
230  | 		    {
231  | 		      auto_scale (global_array, xm*ym, num_fields,
232  | 				  current_field, FIELD_TERNARY_SQUARE, 2,
233  | 				  scales+8);
234  | 		      snprintf (maxes[0], 19, "%g", scales[8]);
235  | 		      snprintf (maxes[1], 19, "%g", scales[9]);
236  | 		      snprintf (maxes[2], 19, "%g", scales[10]);
237  | 		      snprintf (maxes[3], 19, "%g", scales[11]);
238  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
239  | 						     (xml,"ternary_1A_entry")),
240  | 					  maxes[0]);
241  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
242  | 						     (xml,"ternary_1B_entry")),
243  | 					  maxes[1]);
244  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
245  | 						     (xml,"ternary_2A_entry")),
246  | 					  maxes[2]);
247  | 		      gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget 
248  | 						     (xml,"ternary_2B_entry")),
249  | 					  maxes[3]);
250  | 		    }
251  | 
252  | 		  render_scale_2d (ternary_triangle_disp, FIELD_TERNARY, 1);
253  | 		  ierr = render_rgb_local_2d
254  | 		    (Disp[0], global_array, num_fields, current_field,
255  | 		     FIELD_TERNARY_SQUARE, scales+8, nx,ny, xs,ys, xm,ym,
256  | 		     transform, ternary_square_disp,
257  | 		     ternary_dp_color[0], ternary_dp_color[1],
258  | 		     ternary_dp_color[2], ternary_dp_color[3]); CHKERRQ (ierr);
259  | 		  IDispDrawGdk (ternary_square_disp, ternary_scale_area,
260  | 				GDK_RGB_DITHER_MAX);
261  | 		}
262  | 	      break;
263  | 
264  | 	    case FIELD_VECTOR:
265  | 	      if (vector_auto_set)
266  | 		{
267  | 		  auto_scale (global_array, xm*ym, num_fields, current_field,
268  | 			      FIELD_VECTOR, 2, scales+12);
269  | 		  snprintf (maxes[0], 19, "%g", scales[13]);
270  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
271  | 						 (xml, "vector_max_entry")),
272  | 				      maxes[0]);
273  | 		}
274  | 	      ierr = render_rgb_local_2d
275  | 		(Disp[0], global_array, num_fields, current_field,
276  | 		 FIELD_VECTOR, scales+12, nx,ny, xs,ys, xm,ym, transform,
277  | 		 NULL,0,0,0,0); CHKERRQ (ierr);
278  | 	      break;
279  | 
280  | 	    case FIELD_TENSOR_SHEAR:
281  | 	      if (shear_auto_set)
282  | 		{
283  | 		  auto_scale (global_array, xm*ym, num_fields, current_field,
284  | 			      fieldtypes [current_field], 2, scales+14);
285  | 		  snprintf (maxes[0], 19, "%g", scales[14]);
286  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
287  | 						 (xml, "shear_max_entry")),
288  | 				      maxes[0]);
289  | 		}
290  | 	      ierr = render_rgb_local_2d
291  | 		(Disp[0], global_array, num_fields, current_field,
292  | 		 FIELD_TENSOR_SHEAR,scales+14, nx,ny, xs,ys, xm,ym, transform,
293  | 		 NULL,0,0,0,0); CHKERRQ (ierr);
294  | 	      break;
295  | 	    }
296  | 
297  | 	  ierr = VecRestoreArray (global, &global_array); CHKERRQ (ierr);
298  | 	}
299  |       else /* Three dimensions */
300  | 	{
301  | 	  /* Fixed negative z-direction for now */
302  | 	  PetscScalar eye[3], dir[3] = {0, 0, -1.}, right[3] = {.5, 0., 0.};
303  | 	  guchar bgcolor[4] = { 0x50, 0x50, 0x50, 0xFF };
304  | 	  eye[0] = 0.5*(minmax[0]+minmax[1]);
305  | 	  eye[1] = 0.5*(minmax[2]+minmax[3]);
306  | 	  eye[2] = minmax[5] + minmax[1]-minmax[0];
307  | 
308  | 	  if (!Surf)
309  | 	    ierr = SurfCreate (&Surf); CHKERRQ (ierr);
310  | 
311  | 	  ierr = DATriangulate
312  | 	    (Surf, theda, global, current_field, minmax, PETSC_DECIDE,
313  | 	     PETSC_NULL, PETSC_NULL, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE);
314  | 	  CHKERRQ(ierr);
315  | 
316  | 	  IDispFill (Disp[0], bgcolor);
317  | 	  ierr = render_rgb_local_3d (Disp, Surf, eye, dir, right);
318  | 	  ierr = SurfClear (Surf); CHKERRQ (ierr);
319  | 	}
320  | 
321  |       /* Draw IDisplay object onto window */
322  |       DPRINTF ("Painting %dx%d rgb%s buffer onto window\n",
323  | 	       RENDER_WIDTH, RENDER_HEIGHT, (bpp==4) ? "_32" : "");
324  |       if (!dataviews [viewnum])
325  | 	dataviews [viewnum] = glade_xml_get_widget (xml, "plot_area");
326  |       IDispDrawGdk (Disp[0], dataviews [viewnum], GDK_RGB_DITHER_MAX);
327  |     }
328  | }
329  | 
330  | 
331  | #undef __FUNCT__
332  | #define __FUNCT__ "myfilter"
333  | 
334  | /*+ Little variable for myfilter() and refresh_stepnames(). +*/
335  | static char *basefilename;
336  | 
337  | /*++++++++++++++++++++++++++++++++++++++
338  |   This function returns non-zero for "qualifying" file names which start with
339  |   the stored files' basename.time and end with
340  |   +latex+{\tt .cpu0000.meta}.
341  |   +html+ <tt>.cpu0000.meta</tt>.
342  |   It is used as the
343  |   +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}.
344  |   +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>.
345  | 
346  |   int my_time_filter Returns non-zero for qualifying filenames.
347  | 
348  |   const struct dirent *direntry Directory entry with filename to test.
349  |   ++++++++++++++++++++++++++++++++++++++*/
350  | 
351  | int my_time_filter (const struct dirent *direntry)
352  | {
353  |   if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename))) &&
354  |       (!strncmp (direntry->d_name + strlen(basefilename), ".time", 5)))
355  |     return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13,
356  | 		      ".cpu0000.meta", 13));
357  |   return 0;
358  | }
359  | 
360  | 
361  | /*++++++++++++++++++++++++++++++++++++++
362  |   This function returns non-zero for "qualifying" file names which start with
363  |   the stored files' basename and end with
364  |   +latex+{\tt .cpu0000.meta}.
365  |   +html+ <tt>.cpu0000.meta</tt>.
366  |   It is used as the
367  |   +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}.
368  |   +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>.
369  | 
370  |   int my_notime_filter Returns non-zero for qualifying filenames.
371  | 
372  |   const struct dirent *direntry Directory entry with filename to test.
373  |   ++++++++++++++++++++++++++++++++++++++*/
374  | 
375  | int my_notime_filter (const struct dirent *direntry)
376  | {
377  |   if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename))))
378  |     return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13,
379  | 		      ".cpu0000.meta", 13));
380  |   return 0;
381  | }
382  | 
383  | 
384  | /*++++++++++++++++++++++++++++++++++++++
385  |   This loads the names of the files into a long list.
386  |   ++++++++++++++++++++++++++++++++++++++*/
387  | 
388  | int refresh_stepnames ()
389  | {
390  |   struct dirent **namelist;
391  |   char *filec, *dirc, totalsteps[14];
392  |   int i, ierr;
393  | 
394  |   filec = strdup (the_basename);
395  |   dirc = strdup (the_basename);
396  |   basefilename = basename (filec);
397  |   basedirname = dirname (dirc);
398  | 
399  |   /* Default: scan for a timestep sequence */
400  |   total_entries = scandir (basedirname, &namelist, my_time_filter, alphasort);
401  |   if (total_entries < 0)
402  |     {
403  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error scanning directory %s\n",
404  | 			  basedirname); CHKERRQ (ierr);
405  |       return 1;
406  |     }
407  |   if (!total_entries)
408  |     {
409  |       /* Perhaps this is not a timestep sequence */
410  |       total_entries = scandir (basedirname, &namelist, my_notime_filter,
411  | 			       alphasort);
412  |       if (total_entries < 0)
413  | 	{
414  | 	  ierr= PetscPrintf (PETSC_COMM_WORLD, "Error scanning directory %s\n",
415  | 			      basedirname); CHKERRQ (ierr);
416  | 	  return 1;
417  | 	}
418  |       if (!total_entries)
419  | 	{
420  | 	  ierr = PetscPrintf (PETSC_COMM_WORLD, "No such files\n");
421  | 	  CHKERRQ (ierr);
422  | 	  return 1;
423  | 	}
424  |     }
425  |   DPRINTF ("%d eligible files:\n", total_entries);
426  |   snprintf (totalsteps, 14, "/%d", total_entries-1);
427  |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
428  | 				 (xml, "total_label")), totalsteps);
429  | 
430  |   if (!(stepnames = (char **) realloc
431  | 	(stepnames, total_entries*sizeof (char *))))
432  |     {
433  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error allocating memory\n");
434  |       CHKERRQ (ierr);
435  |       return 1;
436  |     }
437  |   for (i=0; i<total_entries; i++)
438  |     {
439  |       int filength = strlen(namelist[i]->d_name);
440  | 
441  |       stepnames [i] = (char *) malloc ((filength-12)*sizeof(char));
442  |       strncpy (stepnames [i], namelist[i]->d_name, filength-13);
443  |       stepnames [i] [filength-13] = '\0';
444  |       free (namelist[i]);
445  |       DPRINTF ("[%d] %s\n", i, stepnames [i]);
446  |       if (ierr)
447  | 	printf ("myfilter() Error: %d\n", ierr);
448  |       /* CHKERRQ (ierr); */
449  |     }
450  | 
451  |   free (namelist);
452  |   return 0;
453  | }
454  | 
455  | void on_plot_area_expose_event
456  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
457  | { IDispDrawGdk (Disp[0], widget, GDK_RGB_DITHER_MAX); }
458  | 
459  | void on_scalar_scale_area_expose_event
460  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
461  | { IDispDrawGdk (scalar_disp, widget, GDK_RGB_DITHER_MAX); }
462  | 
463  | void on_ternary_scale_area_expose_event
464  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
465  | { IDispDrawGdk (ternary_disp, widget, GDK_RGB_DITHER_MAX); }
466  | 
467  | void on_vector_scale_area_expose_event
468  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
469  | { IDispDrawGdk (vector_disp, widget, GDK_RGB_DITHER_MAX); }
470  | 
471  | void on_shear_scale_area_expose_event
472  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
473  | { IDispDrawGdk (shear_disp, widget, GDK_RGB_DITHER_MAX); }
474  | 
475  | void on_scalar_auto_checkbutton_toggled
476  | (GtkWidget *thebutton, gpointer user_data)
477  | {
478  |   scalar_auto_set = gtk_toggle_button_get_active
479  |     (GTK_TOGGLE_BUTTON (thebutton));
480  |   if (scalar_auto_set)
481  |     {
482  |       gtk_widget_set_sensitive
483  | 	(glade_xml_get_widget (xml, "scalar_min_label"), FALSE);
484  |       gtk_widget_set_sensitive
485  | 	(glade_xml_get_widget (xml, "scalar_max_label"), FALSE);
486  |       gtk_widget_set_sensitive
487  | 	(glade_xml_get_widget (xml, "scalar_min_entry"), FALSE);
488  |       gtk_widget_set_sensitive
489  | 	(glade_xml_get_widget (xml, "scalar_max_entry"), FALSE);
490  |     }
491  |   else
492  |     {
493  |       gtk_widget_set_sensitive
494  | 	(glade_xml_get_widget (xml, "scalar_min_label"), TRUE);
495  |       gtk_widget_set_sensitive
496  | 	(glade_xml_get_widget (xml, "scalar_max_label"), TRUE);
497  |       gtk_widget_set_sensitive
498  | 	(glade_xml_get_widget (xml, "scalar_min_entry"), TRUE);
499  |       gtk_widget_set_sensitive
500  | 	(glade_xml_get_widget (xml, "scalar_max_entry"), TRUE);
501  |     }
502  | }
503  | 
504  | void on_ternary_auto_checkbutton_toggled
505  | (GtkWidget *thebutton, gpointer user_data)
506  | {
507  |   ternary_auto_set = gtk_toggle_button_get_active
508  |     (GTK_TOGGLE_BUTTON (thebutton));
509  |   if (ternary_auto_set)
510  |     {
511  |       gtk_widget_set_sensitive
512  | 	(glade_xml_get_widget (xml, "ternary_1A_label"), FALSE);
513  |       gtk_widget_set_sensitive
514  | 	(glade_xml_get_widget (xml, "ternary_1B_label"), FALSE);
515  |       gtk_widget_set_sensitive
516  | 	(glade_xml_get_widget (xml, "ternary_2A_label"), FALSE);
517  |       gtk_widget_set_sensitive
518  | 	(glade_xml_get_widget (xml, "ternary_2B_label"), FALSE);
519  |       gtk_widget_set_sensitive
520  | 	(glade_xml_get_widget (xml, "ternary_3A_label"), FALSE);
521  |       gtk_widget_set_sensitive
522  | 	(glade_xml_get_widget (xml, "ternary_3B_label"), FALSE);
523  |       gtk_widget_set_sensitive
524  | 	(glade_xml_get_widget (xml, "ternary_1A_entry"), FALSE);
525  |       gtk_widget_set_sensitive
526  | 	(glade_xml_get_widget (xml, "ternary_1B_entry"), FALSE);
527  |       gtk_widget_set_sensitive
528  | 	(glade_xml_get_widget (xml, "ternary_2A_entry"), FALSE);
529  |       gtk_widget_set_sensitive
530  | 	(glade_xml_get_widget (xml, "ternary_2B_entry"), FALSE);
531  |       gtk_widget_set_sensitive
532  | 	(glade_xml_get_widget (xml, "ternary_3A_entry"), FALSE);
533  |       gtk_widget_set_sensitive
534  | 	(glade_xml_get_widget (xml, "ternary_3B_entry"), FALSE);
535  |     }
536  |   else
537  |     {
538  |       gtk_widget_set_sensitive
539  | 	(glade_xml_get_widget (xml, "ternary_1A_label"), TRUE);
540  |       gtk_widget_set_sensitive
541  | 	(glade_xml_get_widget (xml, "ternary_1B_label"), TRUE);
542  |       gtk_widget_set_sensitive
543  | 	(glade_xml_get_widget (xml, "ternary_2A_label"), TRUE);
544  |       gtk_widget_set_sensitive
545  | 	(glade_xml_get_widget (xml, "ternary_2B_label"), TRUE);
546  |       gtk_widget_set_sensitive
547  | 	(glade_xml_get_widget (xml, "ternary_3A_label"), TRUE);
548  |       gtk_widget_set_sensitive
549  | 	(glade_xml_get_widget (xml, "ternary_3B_label"), TRUE);
550  |       gtk_widget_set_sensitive
551  | 	(glade_xml_get_widget (xml, "ternary_1A_entry"), TRUE);
552  |       gtk_widget_set_sensitive
553  | 	(glade_xml_get_widget (xml, "ternary_1B_entry"), TRUE);
554  |       gtk_widget_set_sensitive
555  | 	(glade_xml_get_widget (xml, "ternary_2A_entry"), TRUE);
556  |       gtk_widget_set_sensitive
557  | 	(glade_xml_get_widget (xml, "ternary_2B_entry"), TRUE);
558  |       gtk_widget_set_sensitive
559  | 	(glade_xml_get_widget (xml, "ternary_3A_entry"), TRUE);
560  |       gtk_widget_set_sensitive
561  | 	(glade_xml_get_widget (xml, "ternary_3B_entry"), TRUE);
562  |     }
563  | }
564  | 
565  | void on_ternary_square_checkbutton_toggled
566  | (GtkWidget *thebutton, gpointer user_data)
567  | {
568  |   int field;
569  |   char maxes [6][20];
570  | 
571  |   ternary_square_set = gtk_toggle_button_get_active
572  |     (GTK_TOGGLE_BUTTON (thebutton));
573  | 
574  |   for (field=0; field<num_fields; field++)
575  |     if (fieldtypes [field] == FIELD_TERNARY ||
576  | 	fieldtypes [field] == FIELD_TERNARY_SQUARE)
577  |       fieldtypes [field] =
578  | 	ternary_square_set ? FIELD_TERNARY_SQUARE : FIELD_TERNARY;
579  |   render_dataviews ();
580  | 
581  |   if (ternary_square_set)
582  |     {
583  |       gtk_widget_hide (glade_xml_get_widget (xml, "ternary_3A_label"));
584  |       gtk_widget_hide (glade_xml_get_widget (xml, "ternary_3A_entry"));
585  |       gtk_widget_hide (glade_xml_get_widget (xml, "ternary_3B_label"));
586  |       gtk_widget_hide (glade_xml_get_widget (xml, "ternary_3B_entry"));
587  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
588  | 				     (xml, "ternary_1A_label")), "Min A");
589  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
590  | 				     (xml, "ternary_1B_label")), "Max B");
591  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
592  | 				     (xml, "ternary_2A_label")), "Min A");
593  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
594  | 				     (xml, "ternary_2B_label")), "Max B");
595  |       snprintf (maxes[0], 19, "%g", scales[8]);
596  |       snprintf (maxes[1], 19, "%g", scales[9]);
597  |       snprintf (maxes[2], 19, "%g", scales[10]);
598  |       snprintf (maxes[3], 19, "%g", scales[11]);
599  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
600  | 				     (xml, "ternary_1A_entry")), maxes[0]);
601  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
602  | 				     (xml, "ternary_1B_entry")), maxes[1]);
603  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
604  | 				     (xml, "ternary_2A_entry")), maxes[2]);
605  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget 
606  | 				     (xml, "ternary_2B_entry")), maxes[3]);
607  | 
608  |       ternary_disp = ternary_square_disp;
609  |     }
610  |   else
611  |     {
612  |       gtk_widget_show (glade_xml_get_widget (xml, "ternary_3A_label"));
613  |       gtk_widget_show (glade_xml_get_widget (xml, "ternary_3A_entry"));
614  |       gtk_widget_show (glade_xml_get_widget (xml, "ternary_3B_label"));
615  |       gtk_widget_show (glade_xml_get_widget (xml, "ternary_3B_entry"));
616  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
617  | 				     (xml, "ternary_1A_label")), "Red A");
618  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
619  | 				     (xml, "ternary_1B_label")), "Red B");
620  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
621  | 				     (xml, "ternary_2A_label")), "Green A");
622  |       gtk_label_set_text (GTK_LABEL (glade_xml_get_widget
623  | 				     (xml, "ternary_2B_label")), "Green B");
624  |       snprintf (maxes[0], 19, "%g", scales[2]);
625  |       snprintf (maxes[1], 19, "%g", scales[3]);
626  |       snprintf (maxes[2], 19, "%g", scales[4]);
627  |       snprintf (maxes[3], 19, "%g", scales[5]);
628  |       snprintf (maxes[4], 19, "%g", scales[6]);
629  |       snprintf (maxes[5], 19, "%g", scales[7]);
630  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
631  | 				     (xml, "ternary_1A_entry")), maxes[0]);
632  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
633  | 				     (xml, "ternary_1B_entry")), maxes[1]);
634  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
635  | 				     (xml, "ternary_2A_entry")), maxes[2]);
636  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget 
637  | 				     (xml, "ternary_2B_entry")), maxes[3]);
638  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
639  | 				     (xml, "ternary_3A_entry")), maxes[4]);
640  |       gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
641  | 				     (xml, "ternary_3B_entry")), maxes[5]);
642  | 
643  |       ternary_disp = ternary_triangle_disp;
644  |     }
645  |   on_ternary_scale_area_expose_event
646  |     (glade_xml_get_widget (xml, "ternary_scale_area"), NULL, NULL);
647  | }
648  | 
649  | void on_vector_auto_checkbutton_toggled
650  | (GtkWidget *thebutton, gpointer user_data)
651  | {
652  |   vector_auto_set = gtk_toggle_button_get_active
653  |     (GTK_TOGGLE_BUTTON (thebutton));
654  |   if (vector_auto_set)
655  |     {
656  |       gtk_widget_set_sensitive
657  | 	(glade_xml_get_widget (xml, "vector_max_label"), FALSE);
658  |       gtk_widget_set_sensitive
659  | 	(glade_xml_get_widget (xml, "vector_symm_label"), FALSE);
660  |       gtk_widget_set_sensitive
661  | 	(glade_xml_get_widget (xml, "vector_max_entry"), FALSE);
662  |       gtk_widget_set_sensitive
663  | 	(glade_xml_get_widget (xml, "vector_symm_spinbutton"), FALSE);
664  |     }
665  |   else
666  |     {
667  |       gtk_widget_set_sensitive
668  | 	(glade_xml_get_widget (xml, "vector_max_label"), TRUE);
669  |       gtk_widget_set_sensitive
670  | 	(glade_xml_get_widget (xml, "vector_symm_label"), TRUE);
671  |       gtk_widget_set_sensitive
672  | 	(glade_xml_get_widget (xml, "vector_max_entry"), TRUE);
673  |       gtk_widget_set_sensitive
674  | 	(glade_xml_get_widget (xml, "vector_symm_spinbutton"), TRUE);
675  |     }
676  | }
677  | 
678  | void on_shear_auto_checkbutton_toggled
679  | (GtkWidget *thebutton, gpointer user_data)
680  | {
681  |   shear_auto_set = gtk_toggle_button_get_active
682  |     (GTK_TOGGLE_BUTTON (thebutton));
683  |   if (shear_auto_set)
684  |     {
685  |       gtk_widget_set_sensitive
686  | 	(glade_xml_get_widget (xml, "shear_max_label"), FALSE);
687  |       gtk_widget_set_sensitive
688  | 	(glade_xml_get_widget (xml, "shear_max_entry"), FALSE);
689  |     }
690  |   else
691  |     {
692  |       gtk_widget_set_sensitive
693  | 	(glade_xml_get_widget (xml, "shear_max_label"), TRUE);
694  |       gtk_widget_set_sensitive
695  | 	(glade_xml_get_widget (xml, "shear_max_entry"), TRUE);
696  |     }
697  | }
698  | 
699  | void on_scalar_min_entry_changed (GtkWidget *theentry, gpointer user_data)
700  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
701  |   sscanf (entrytext, "%lf", scales); }
702  | 
703  | void on_scalar_max_entry_changed (GtkWidget *theentry, gpointer user_data)
704  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
705  |   sscanf (entrytext, "%lf", scales+1); }
706  | 
707  | void on_ternary_1A_entry_changed (GtkWidget *theentry, gpointer user_data)
708  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
709  |   sscanf (entrytext, "%lf", ternary_square_set ? scales+8 : scales+2); }
710  | 
711  | void on_ternary_1B_entry_changed (GtkWidget *theentry, gpointer user_data)
712  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
713  |   sscanf (entrytext, "%lf", ternary_square_set ? scales+9 : scales+3); }
714  | 
715  | void on_ternary_2A_entry_changed (GtkWidget *theentry, gpointer user_data)
716  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
717  |   sscanf (entrytext, "%lf", ternary_square_set ? scales+10 : scales+4); }
718  | 
719  | void on_ternary_2B_entry_changed (GtkWidget *theentry, gpointer user_data)
720  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
721  |   sscanf (entrytext, "%lf", ternary_square_set ? scales+11 : scales+5); }
722  | 
723  | void on_ternary_3A_entry_changed (GtkWidget *theentry, gpointer user_data)
724  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
725  |   sscanf (entrytext, "%lf", scales+6); }
726  | 
727  | void on_ternary_3B_entry_changed (GtkWidget *theentry, gpointer user_data)
728  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
729  |   sscanf (entrytext, "%lf", scales+7); }
730  | 
731  | void on_ternary_dp_red_entry_changed (GtkWidget *theentry, gpointer user_data)
732  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
733  |   sscanf (entrytext, "%lf", ternary_dp_color); }
734  | 
735  | void on_ternary_dp_green_entry_changed(GtkWidget *theentry, gpointer user_data)
736  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
737  |   sscanf (entrytext, "%lf", ternary_dp_color+1); }
738  | 
739  | void on_ternary_dp_blue_entry_changed (GtkWidget *theentry, gpointer user_data)
740  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
741  |   sscanf (entrytext, "%lf", ternary_dp_color+2); }
742  | 
743  | void on_ternary_dp_alpha_entry_changed(GtkWidget *theentry, gpointer user_data)
744  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
745  |   sscanf (entrytext, "%lf", ternary_dp_color+3); }
746  | 
747  | void on_path_filename_entry_activate (GtkWidget *theentry, gpointer user) {
748  |   G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
749  |   FILE *path_file;
750  |   gchar linebuf[200];
751  |   int color=-1, point=0, point_array_size=0, ierr;
752  |   DPRINTF ("Filename entered: %s\n", entrytext);
753  | 
754  |   if (!(path_file=fopen(entrytext, "r"))) {
755  |     ierr=PetscPrintf (PETSC_COMM_WORLD, "Unable to open: %s\n", entrytext);
756  |     CHKERRQ (ierr);
757  |     return; }
758  | 
759  |   dp_supp_colors=0;
760  |   while (fgets (linebuf, 199, path_file))
761  |     {
762  |       if (linebuf[0] == 'c' || linebuf[0] == 'C')
763  | 	{
764  | 	  /* Expand the color buffers */
765  | 	  dp_supp_colors++;
766  | 	  dp_supp_color_points = realloc
767  | 	    (dp_supp_color_points, dp_supp_colors*sizeof(int));
768  | 	  dp_supp_red = realloc
769  | 	    (dp_supp_red, dp_supp_colors*sizeof(PetscScalar));
770  | 	  dp_supp_green = realloc
771  | 	    (dp_supp_green, dp_supp_colors*sizeof(PetscScalar));
772  | 	  dp_supp_blue = realloc
773  | 	    (dp_supp_blue, dp_supp_colors*sizeof(PetscScalar));
774  | 	  dp_supp_alpha = realloc
775  | 	    (dp_supp_alpha, dp_supp_colors*sizeof(PetscScalar));
776  | 
777  | 	  /* Properties of the new color entry */
778  | 	  color = dp_supp_colors-1;
779  | 	  dp_supp_color_points [color] = 0;
780  | 	  sscanf (linebuf, "%*s %lf %lf %lf %lf", dp_supp_red+color,
781  | 		  dp_supp_green+color,dp_supp_blue+color,dp_supp_alpha+color);
782  | 	}
783  |       if (((linebuf[0] >= '0' && linebuf[0] <= '9') || linebuf[0] == '.') &&
784  | 	  color > -1)
785  | 	{
786  | 	  if (point >= point_array_size)
787  | 	    dp_supp_AB = realloc
788  | 	      (dp_supp_AB,
789  | 	       (point_array_size=(point_array_size?point_array_size*2:100))*
790  | 	       2*sizeof(PetscScalar));
791  | 	  sscanf (linebuf, "%lf %lf", dp_supp_AB+2*point,
792  | 		  dp_supp_AB+2*point+1);
793  | 	  dp_supp_color_points[color]++;
794  | 	  point++;
795  | 	}
796  |     }
797  |   fclose (path_file);
798  | 
799  | #ifdef DEBUG
800  |   ierr=PetscPrintf (PETSC_COMM_WORLD, "Loaded path supplement:\n");
801  |   CHKERRQ (ierr);
802  |   for (color=0, point=0; color<dp_supp_colors; color++)
803  |     {
804  |       ierr=PetscPrintf (PETSC_COMM_WORLD, "%d: %d points, color %g %g %g %g\n",
805  | 			color, dp_supp_color_points[color], dp_supp_red[color],
806  | 			dp_supp_green[color], dp_supp_blue[color],
807  | 			dp_supp_alpha[color]);
808  |       CHKERRQ (ierr);
809  |       for (ierr=0; ierr<dp_supp_color_points[color]; ierr++, point++)
810  | 	PetscPrintf (PETSC_COMM_WORLD, " %g %g\n", dp_supp_AB [point*2],
811  | 		     dp_supp_AB [point*2+1]);
812  |     }
813  | #endif
814  | 
815  |   render_dataviews();
816  | }
817  | 
818  | void on_vector_max_entry_changed (GtkWidget *theentry, gpointer user_data)
819  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
820  |   sscanf (entrytext, "%lf", scales+13); }
821  | 
822  | void on_vector_symm_spinbutton_changed (GtkWidget *theentry,gpointer user_data)
823  | { int symmetry;
824  |   G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
825  |   sscanf (entrytext, "%d", &symmetry);
826  |   /* Because this sometimes sends events with outrageous symmetry numbers */
827  |   if (symmetry <= 10) {
828  |     render_scale_2d (vector_disp, FIELD_VECTOR, symmetry);
829  |     on_vector_scale_area_expose_event
830  |       (glade_xml_get_widget (xml, "vector_scale_area"), NULL, user_data); }}
831  | 
832  | void on_shear_max_entry_changed (GtkWidget *theentry, gpointer user_data)
833  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
834  |   sscanf (entrytext, "%lf", scales+14); }
835  | 
836  | void change_variable (GtkWidget *widget, gpointer user_data)
837  | {
838  |   current_field = GPOINTER_TO_INT (widget);
839  |   DPRINTF ("Switching to variable %d\n", current_field);
840  |   gtk_notebook_set_current_page
841  |     (GTK_NOTEBOOK (glade_xml_get_widget (xml, "scale_notebook")),
842  |      fieldtypes [current_field] >> 4);
843  |   render_dataviews();
844  | }
845  | 
846  | void on_mag_spin_value_changed (GtkWidget *mag_spin, gpointer user_data) {
847  |   G_CONST_RETURN gchar *entrytext;
848  |   entrytext = gtk_entry_get_text (GTK_ENTRY (mag_spin));
849  |   sscanf (entrytext, "%lf", &sizemag);
850  |   width = (int) (minmax [1] * sizemag);
851  |   height = (int) (minmax [3] * sizemag);
852  | 
853  |   if (width == 0)
854  |     width = DEFAULT_RENDER_SIZE;
855  |   if (height == 0)
856  |     height = DEFAULT_RENDER_SIZE;
857  | 
858  |   render_dataviews();
859  | }
860  | 
861  | 
862  | void display_timestep (int usermetacount, char **usermetanames,
863  | 		       char **usermetadata)
864  | {
865  |   int i;
866  |   static char step_buffer [20], time_buffer [20];
867  | 
868  |   for (i=0; i<usermetacount; i++)
869  |     {
870  |       if (!strncmp (usermetanames [i], "timestep", 8))
871  | 	sscanf (usermetadata [i], "%d", &current_timestep);
872  |       else if (!strncmp (usermetanames [i], "time", 4))
873  | 	sscanf (usermetadata [i], "%lf", &current_time);
874  |     }
875  |   snprintf (step_buffer, 19, "Timestep: %d", current_timestep);
876  |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "timestep_label")),
877  | 		      step_buffer);
878  |   snprintf (time_buffer, 19, "Time: %g", current_time);
879  |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "time_label")),
880  | 		      time_buffer);
881  | 
882  |   on_mag_spin_value_changed (glade_xml_get_widget (xml, "mag_spin"), NULL);
883  | }
884  | 
885  | 
886  | void on_save_activate (GtkWidget *widget, gpointer user_data)
887  | {
888  |   int i, ierr;
889  |   char filename [200], number[10];
890  | 
891  |   strncpy (filename, basedirname, 198);
892  |   strcat (filename, "/");
893  |   strncat (filename, stepnames [entrynum], 198 - strlen (filename));
894  |   snprintf (number, 9, "-f%d", current_field);
895  |   strncat (filename, number, 198 - strlen (filename));
896  |   strncat (filename, ".ppm", 198 - strlen (filename));
897  | 
898  |   DPRINTF ("Saving image with filename %s\n", filename);
899  |   IDispWritePPM (Disp[0], filename);
900  | }
901  | 
902  | 
903  | void on_timestep_spin_value_changed (GtkWidget *timestep_spin, gpointer user_data) {
904  |   int usermetacount, ierr;
905  |   G_CONST_RETURN gchar *entrytext;
906  |   char **usermetanames, **usermetadata, filename [200], **field_name;
907  |   GtkWidget *variable_options, *variable_menu, **variable_item;
908  | 
909  |   entrytext = gtk_entry_get_text (GTK_ENTRY (timestep_spin));
910  |   sscanf (entrytext, "%d", &entrynum);
911  | 
912  |   /* Bound the entrynum between 0 and total_entries-1; -11 is the minimum of
913  |      the widget (from jump), 1000001 is the maximum. */
914  |   if ((entrynum < 0 && entrynum != -11) || entrynum == 1000001)
915  |     entrynum = total_entries-1;
916  |   if ((entrynum >= total_entries && entrynum != 1000001) || entrynum == -11)
917  |     entrynum = 0;
918  |   gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin),
919  | 			     (gfloat) entrynum);
920  | 
921  |   strncpy (filename, basedirname, 198);
922  |   strcat (filename, "/");
923  |   strncat (filename, stepnames [entrynum], 198 - strlen (filename));
924  | 
925  |   ierr = IlluMultiRead (PETSC_COMM_WORLD, theda, global, filename,
926  | 			&usermetacount,&usermetanames, &usermetadata);
927  |   CHKERRQ (ierr);
928  | 
929  |   display_timestep (usermetacount, usermetanames, usermetadata);
930  | }
931  | 
932  | 
933  | void on_transform_activate (GtkWidget *widget, gpointer user_data)
934  | {
935  |   GtkWidget *timestep_spin = glade_xml_get_widget (xml, "timestep_spin"),
936  |     *flip_horiz = glade_xml_get_widget (xml, "flip_horiz"),
937  |     *flip_vertical = glade_xml_get_widget (xml, "flip_vertical"),
938  |     *rotate_left = glade_xml_get_widget (xml, "rotate_left");
939  | 
940  |   transform =
941  |     (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (flip_horiz)) ?
942  |      FLIP_HORIZONTAL : 0) |
943  |     (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (flip_vertical)) ?
944  |      FLIP_VERTICAL : 0) |
945  |     (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (rotate_left)) ?
946  |      ROTATE_LEFT : 0);
947  | 
948  |   render_dataviews ();
949  | }
950  | 
951  | 
952  | void on_save_all_activate (GtkWidget *none, gpointer user_data) {
953  |   GtkWidget *timestep_spin = glade_xml_get_widget (xml, "timestep_spin");
954  |   int i, temp = entrynum;
955  | 
956  |   for (i=0; i<total_entries; i++)
957  |     {
958  |       gchar appbar_message [30];
959  |       gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin), (gfloat) i);
960  |       on_timestep_spin_value_changed (timestep_spin, user_data);
961  | 
962  |       sprintf (appbar_message, "Saving image %d/%d", i+1, total_entries);
963  |       gnome_appbar_set_status
964  | 	(GNOME_APPBAR (glade_xml_get_widget (xml, "main_appbar")),
965  | 	 appbar_message);
966  |       gnome_appbar_set_progress_percentage
967  | 	(GNOME_APPBAR (glade_xml_get_widget (xml, "main_appbar")),
968  | 	 (gfloat) (i+1)/total_entries);
969  |       while (gtk_events_pending ())
970  | 	gtk_main_iteration ();
971  | 
972  |       on_save_activate (timestep_spin, user_data);
973  |     }
974  | 
975  |   gnome_appbar_set_progress_percentage
976  |     (GNOME_APPBAR (glade_xml_get_widget (xml, "main_appbar")), 0.);
977  |   gnome_appbar_refresh (GNOME_APPBAR(glade_xml_get_widget(xml,"main_appbar")));
978  |   gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin), (gfloat) temp);
979  |   on_timestep_spin_value_changed (timestep_spin, user_data);
980  | }
981  | 
982  | 
983  | void on_save_all_scale_activate (GtkWidget *none, gpointer user_data) {
984  |   GtkWidget *timestep_spin = glade_xml_get_widget (xml, "timestep_spin");
985  |   int i,j, ierr, temp = entrynum;
986  |   char filename [200], number [10];
987  |   IDisplay scale_image;
988  | 
989  |   if (!(scale_image =
990  | 	(fieldtypes [current_field] == FIELD_SCALAR) ? scalar_disp :
991  | 	((fieldtypes [current_field] == FIELD_VECTOR) ? vector_disp :
992  | 	 ((fieldtypes [current_field] == FIELD_TENSOR_SHEAR) ? shear_disp :
993  | 	  ((fieldtypes [current_field] == FIELD_TERNARY_SQUARE ||
994  | 	    fieldtypes [current_field] == FIELD_TERNARY) ? ternary_disp :
995  | 	   NULL)))))
996  |     return;
997  | 
998  |   for (i=0; i<total_entries; i++)
999  |     {
1000 |       gchar appbar_message [30];
1001 |       gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin), (gfloat) i);
1002 |       on_timestep_spin_value_changed (timestep_spin, user_data);
1003 | 
1004 |       sprintf (appbar_message, "Saving image %d/%d", i+1, total_entries);
1005 |       gnome_appbar_set_status
1006 | 	(GNOME_APPBAR (glade_xml_get_widget (xml, "main_appbar")),
1007 | 	 appbar_message);
1008 |       gnome_appbar_set_progress_percentage
1009 | 	(GNOME_APPBAR (glade_xml_get_widget (xml, "main_appbar")),
1010 | 	 (gfloat) (i+1)/total_entries);
1011 |       while (gtk_events_pending ())
1012 | 	gtk_main_iteration ();
1013 | 
1014 |       strncpy (filename, basedirname, 198);
1015 |       strcat (filename, "/");
1016 |       strncat (filename, stepnames [entrynum], 198 - strlen (filename));
1017 |       snprintf (number, 9, "-s%d", current_field);
1018 |       strncat (filename, number, 198 - strlen (filename));
1019 |       strncat (filename, ".ppm", 198 - strlen (filename));
1020 | 
1021 |       DPRINTF ("Saving image with filename %s\n", filename);
1022 |       IDispWritePPM (scale_image, filename);
1023 |     }
1024 | 
1025 |   gnome_appbar_set_progress_percentage
1026 |     (GNOME_APPBAR (glade_xml_get_widget (xml, "main_appbar")), 0.);
1027 |   gnome_appbar_refresh (GNOME_APPBAR(glade_xml_get_widget(xml,"main_appbar")));
1028 |   gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin), (gfloat) temp);
1029 |   on_timestep_spin_value_changed (timestep_spin, user_data);
1030 | }
1031 | 
1032 | 
1033 | void on_refresh_activate (GtkWidget *none, gpointer user_data) {
1034 |   if (refresh_stepnames ()) exit (1); }
1035 | 
1036 | 
1037 | /*++++++++++++++++++++++++++++++++++++++
1038 |   This reloads the .log file.
1039 | 
1040 |   GtkWidget *none Empty GtkWidget (unusable because it's a menu item).
1041 | 
1042 |   gpointer user_data Empty pointer.
1043 |   ++++++++++++++++++++++++++++++++++++++*/
1044 | 
1045 | void on_log_reload_button_clicked (GtkWidget *none, gpointer user_data)
1046 | {
1047 |   FILE *run_log;
1048 |   unsigned char run_log_filename [300], run_log_buffer [300];
1049 |   int log_size=0, nextchar=0;
1050 | 
1051 |   strcpy ((char *) run_log_buffer, "Loading new log info");
1052 |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "log_text_label")),
1053 | 		      (char *) run_log_buffer);
1054 | 
1055 |   strncpy ((char *) run_log_filename, the_basename, 298-strlen(".log"));
1056 |   strcat ((char *) run_log_filename, ".log");
1057 |   DPRINTF ("Loading log file %s\n", run_log_filename);
1058 |   if (!(run_log = fopen ((char *) run_log_filename, "r")))
1059 |     {
1060 |       printf ("Can't find log file %s\n", run_log_filename);
1061 |       return;
1062 |     }
1063 | 
1064 |   /* There's probably a MUCH better way to slurp a file into a string... */
1065 |   while (nextchar != EOF)
1066 |     {
1067 |       int i,j;
1068 |       for (i=0; i<300 && nextchar != EOF; i++)
1069 | 	run_log_buffer[i] = nextchar = fgetc (run_log);
1070 |       log_text = (char *) realloc
1071 | 	(log_text, (log_size += i) * sizeof (char));
1072 |       for (j=0; j<i; j++)
1073 | 	log_text [log_size-i+j] = run_log_buffer [j];
1074 |     }
1075 |   log_text [log_size-1] = '\0';
1076 |   fclose (run_log);
1077 |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "log_text_label")),
1078 | 		      log_text);
1079 | }
1080 | 
1081 | 
1082 | void on_run_log_activate (GtkWidget *none, gpointer user_data) {
1083 |   if (!log_text)
1084 |     on_log_reload_button_clicked (none, user_data);
1085 |   gtk_widget_show (glade_xml_get_widget (xml, "log_window")); }
1086 | 
1087 | 
1088 | void on_about_activate (GtkWidget *none, gpointer user_data) {
1089 |   gtk_widget_show (glade_xml_get_widget (xml, "about")); }
1090 | 
1091 | 
1092 | #undef __FUNCT__
1093 | #define __FUNCT__ "main"
1094 | 
1095 | /*++++++++++++++++++++++++++++++++++++++
1096 |   This is
1097 |   +latex+{\tt main()}.
1098 |   +html+ <tt>main()</tt>.
1099 | 
1100 |   int main It returns an int to the OS.
1101 | 
1102 |   int argc Argument count.
1103 | 
1104 |   char *argv[] Arguments.
1105 |   ++++++++++++++++++++++++++++++++++++++*/
1106 | 
1107 | int main (int argc, char *argv[])
1108 | {
1109 |   int usermetacount=0, i, ierr;
1110 |   char **usermetanames, **usermetadata, filename [200], **field_name;
1111 |   GtkWidget *variable_options, *variable_menu, **variable_item;
1112 | 
1113 |   /*+ After
1114 |     +latex+{\tt PETSc}
1115 |     +html+ <tt>PETSc</tt>
1116 |     and glade/GNOME initialization, it gets the list of files matching the
1117 |     basename. +*/
1118 |   ierr = PetscInitialize (&argc, &argv, (char *)0, help); CHKERRQ (ierr);
1119 | 
1120 |   if (argc<2)
1121 |     {
1122 |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Usage: tsview basename\n");
1123 |       CHKERRQ (ierr);
1124 |       return 1;
1125 |     }
1126 | 
1127 | #ifdef DEBUG
1128 |   ierr = PetscPrintf (PETSC_COMM_WORLD, "Command line:"); CHKERRQ (ierr);
1129 |   for (i=0; i<argc; i++)
1130 |     {
1131 |       ierr = PetscPrintf (PETSC_COMM_WORLD, " %s", argv[i]); CHKERRQ (ierr);
1132 |     }
1133 |   ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr);
1134 | #endif
1135 | 
1136 |   /* Initial settings */
1137 |   ierr = PetscOptionsHasName (PETSC_NULL, "-no_transparency", &transp);
1138 |   CHKERRQ (ierr);
1139 |   transp = !transp;
1140 |   Surf = NULL;
1141 |   transform = 0;
1142 | 
1143 |   /* Kludge alert!  Setting argc to avoid gnome_program_init errors;
1144 |      fix: use GNOME arguments instead of PETSc. */
1145 |   argc=2;
1146 | 
1147 |   DPRINTF ("Running gnome_program_init with argc=%d\n", argc);
1148 |   gnome_program_init ("TSView", VERSION, LIBGNOMEUI_MODULE, argc, argv, NULL);
1149 | 
1150 |   strncpy (filename, GLADE_DIRECTORY, 187);
1151 |   strcat (filename, "/tsview.glade");
1152 |   DPRINTF ("Loading Glade file %s\n", filename);
1153 |   xml = glade_xml_new (filename, NULL, NULL);
1154 |   glade_xml_signal_autoconnect (xml);
1155 | 
1156 |   if (argc>1)
1157 |     the_basename = argv[1];
1158 |   else
1159 |     {
1160 |       /* Put in filter for .time0000000.cpu0000.meta */
1161 |       gtk_widget_show (glade_xml_get_widget (xml, "open_fileselect"));
1162 |     }
1163 | 
1164 |   DPRINTF ("Loading list of timestep names\n",0);
1165 |   if (refresh_stepnames ())
1166 |     {
1167 |       ierr = PetscFinalize (); CHKERRQ(ierr);
1168 |       exit (1);
1169 |     }
1170 | 
1171 |   DPRINTF ("Loading first timestep, creating distributed array\n",0);
1172 |   strncpy (filename, basedirname, 198);
1173 |   strcat (filename, "/");
1174 |   strncat (filename, stepnames [0], 198 - strlen (stepnames [0]));
1175 |   ierr = IlluMultiLoad
1176 |     (PETSC_COMM_WORLD, filename, &theda, minmax+1,minmax+3,minmax+5,
1177 |      &fieldtypes, &usermetacount, &usermetanames, &usermetadata);
1178 |   CHKERRQ (ierr);
1179 | 
1180 |   /* Usermetadata xwidth, ywidth, zwidth override minmax in case IlluMulti
1181 |      version of saved data is 0.1. */
1182 |   DPRINTF ("Checking usermetadata for width information\n",0);
1183 |   for (i=0; i<usermetacount; i++)
1184 |     {
1185 |       if (!strncmp (usermetanames [i], "xwidth", 6))
1186 | 	sscanf (usermetadata [i], "%lf", minmax+1);
1187 |       else if (!strncmp (usermetanames [i], "ywidth", 6))
1188 | 	sscanf (usermetadata [i], "%lf", minmax+3);
1189 |       else if (!strncmp (usermetanames [i], "zwidth", 6))
1190 | 	sscanf (usermetadata [i], "%lf", minmax+5);
1191 |     }
1192 | 
1193 |   DPRINTF ("Getting distributed array global vector and info\n",0);
1194 |   ierr = DAGetGlobalVector (theda, &global); CHKERRQ (ierr);
1195 |   ierr = DAGetInfo (theda, &dimensions, PETSC_NULL,PETSC_NULL,PETSC_NULL,
1196 | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL, &num_fields,
1197 | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
1198 |   if (dimensions == 1)
1199 |     SETERRQ (PETSC_ERR_ARG_OUTOFRANGE, "tsview-ng only supports 2-D or 3-D distributed arrays.")
1200 |   else if (dimensions == 2)
1201 |     bpp = 3;
1202 |   else
1203 |     {
1204 |       bpp = 4;
1205 |       gtk_widget_hide (glade_xml_get_widget (xml, "flip_horiz"));
1206 |       gtk_widget_hide (glade_xml_get_widget (xml, "flip_vertical"));
1207 |       gtk_widget_hide (glade_xml_get_widget (xml, "rotate_left"));
1208 |     }
1209 | 
1210 |   /* Build menu of field variables */
1211 |   variable_options = glade_xml_get_widget (xml, "variable_menu");
1212 |   gtk_option_menu_remove_menu (GTK_OPTION_MENU (variable_options));
1213 |   variable_menu = gtk_menu_new ();
1214 |   variable_item = (GtkWidget **) malloc (num_fields * sizeof (GtkWidget *));
1215 |   field_name = (char **) malloc (num_fields * sizeof (char *));
1216 |   field_index = (int *) malloc (num_fields * sizeof (int));
1217 |   /* For now, use scalar plots for all types in 3-D */
1218 |   if (dimensions == 2)
1219 |     field_indices (num_fields, dimensions, fieldtypes, field_index);
1220 |   else
1221 |     for (i=0; i<num_fields; i++)
1222 |       field_index[i] = i;
1223 |   DPRINTF ("Field indices:\n",0);
1224 |   for (i=0; i<num_fields && field_index [i] != -1; i++)
1225 |     {
1226 |       ierr = DAGetFieldName (theda, field_index [i], field_name+i);
1227 |       CHKERRQ (ierr);
1228 |       DPRINTF ("%d index %d name %s\n", i, field_index [i], field_name [i]);
1229 |       variable_item [i] = gtk_menu_item_new_with_label (field_name [i]);
1230 |       gtk_menu_append (GTK_MENU (variable_menu), variable_item [i]);
1231 |       gtk_signal_connect_object (GTK_OBJECT (variable_item [i]), "activate",
1232 | 				 GTK_SIGNAL_FUNC (change_variable),
1233 | 				 GINT_TO_POINTER (field_index [i]));
1234 |       gtk_widget_show (variable_item [i]);
1235 |     }
1236 |   gtk_option_menu_set_menu (GTK_OPTION_MENU (variable_options), variable_menu);
1237 |   gtk_widget_show (variable_menu);
1238 |   gtk_widget_show (variable_options);
1239 | 
1240 |   /* Scale images */
1241 |   IDispCreate (&scalar_disp, SCALE_WIDTH,SCALE_HEIGHT,SCALE_WIDTH,SCALE_BPP,0);
1242 |   IDispCreate (&vector_disp, SCALE_WIDTH,SCALE_HEIGHT,SCALE_WIDTH,SCALE_BPP,0);
1243 |   IDispCreate (&shear_disp, SCALE_WIDTH,SCALE_HEIGHT,SCALE_WIDTH,SCALE_BPP,0);
1244 |   IDispCreate (&ternary_triangle_disp, SCALE_WIDTH, SCALE_HEIGHT, SCALE_WIDTH,
1245 | 	       SCALE_BPP, 0);
1246 |   IDispCreate (&ternary_square_disp, SCALE_WIDTH, SCALE_HEIGHT, SCALE_WIDTH,
1247 | 	       SCALE_BPP, 0);
1248 |   ternary_disp = ternary_triangle_disp;
1249 |   render_scale_2d (scalar_disp, FIELD_SCALAR, 1);
1250 |   render_scale_2d (vector_disp, FIELD_VECTOR, 1);
1251 |   render_scale_2d (shear_disp, FIELD_TENSOR_SHEAR, 1);
1252 | 
1253 |   gtk_notebook_set_current_page
1254 |     (GTK_NOTEBOOK (glade_xml_get_widget (xml, "scale_notebook")),
1255 |      fieldtypes [0] >> 4);
1256 | 
1257 |   /* Main window title */
1258 |   {
1259 |     char main_window_title[100] = "TSView: ";
1260 |     GtkWidget *main_window = glade_xml_get_widget (xml, "main_window");
1261 | 
1262 |     strncat (main_window_title, basename (the_basename), 90);
1263 |     gtk_window_set_title (GTK_WINDOW (main_window), main_window_title);
1264 |     gtk_widget_show (main_window);
1265 |   }
1266 | 
1267 |   /* Set initial magnification */
1268 |   sizemag = DEFAULT_RENDER_SIZE/PetscMax(minmax[1],minmax[3]);
1269 |   DPRINTF ("Max dimension is %g, setting magnification to %g\n",
1270 | 	   PetscMax(minmax[1],minmax[3]), sizemag);
1271 |   gtk_spin_button_set_value
1272 |     (GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "mag_spin")), sizemag);
1273 | 
1274 |   DPRINTF ("Displaying first timestep\n",0);
1275 |   display_timestep (usermetacount, usermetanames, usermetadata);
1276 | 
1277 |   DPRINTF ("Running main loop\n",0);
1278 |   gtk_main();
1279 | 
1280 |   DPRINTF ("Finalizing and exiting.\n",0);
1281 |   if (Surf) {
1282 |     ierr = ISurfDestroy (Surf); CHKERRQ (ierr); }
1283 |   if (Disp[0]) {
1284 |     ierr = IDispDestroy (Disp[0]); CHKERRQ (ierr); }
1285 |   ierr = PetscFinalize (); CHKERRQ(ierr);
1286 |   return 0;
1287 | }