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