1 // $Id: CrystalView.cxx 1103 2011-01-15 16:14:13Z martin $
2 //
3 // CrystalView.cxx - main routine for DRAWxtl V5.5 - the GUI version
4 //
5 // Coded using the FLTK 1.1.6 widget set
6 //
7 //     Larry W. Finger, Martin Kroeker and Brian Toby
8 //
9 // This module includes many of the support routines for the GUI
10 //
11 // routines contained within this file:
12 //
13 //  main - the entry point
14 //  AngleInRange - places angle in range -180 to 180
15 //  Clear_Last_Omit_cb - callback routine to remove last entry in 'omit' item list
16 //  CrystalView::CrystalView constructor
17 //  CrystalView::draw - draw routine for CrystalView class
18 //  Destroy_Open_Windows - call the destructor for all open windows
19 //  Error_Box - display error box
20 //  Exit_cb - the callback routine from the "Exit" menu button pressed or when main window is closed
21 //  ImportDataFile_cb - Callback from Import External Format menu item
22 //  Include_Cutouts_cb - callback routine when 'Include Cutouts' check box is changed
23 //  Load_Bond_Data - get bond data from out file into array
24 //  LoadConfig - load configuration file
25 //  Max_Min_cb - callback routine to readout Max- and Min- sliders
26 //  Offset_cb - callback routine when Origin values are changed
27 //  pick_box - routine to pick the corners of the slab box overlay
28 //  process_hits - routine to process the omit list
29 //  Process_Inp - read the DRAWxtl input file
30 //  Restore_Working_Copy - restores working copy of str file from saved version
31 //  Rotation_cb - callback routine to readout rotation widgets
32 //  Save_Current_cb - Callback from Save Current menu button
33 //  Save_Working_Copy - Copies the working version of the str file into a "save" file
34 //  SelectDataFile_cb - Callback from Select Data File menu item
35 //  show_slab_ovl - overlay draw routine for the temporary slab outline
36 //  start_picking - routine to pick objects to be omitted from drawing
37 //  update_box - routine to process the GL hits from pick_box
38 //  Update_Str - routine to update the 'str' file from widget contents
39 //  WriteConfig - write updated configuration file
40 //  XYZ_Rot_to_Q - X, Y, Z rotations to quaternion
41 //  moveto_atom - routine to pick an atom and move the crosshair to it (UNUSED)
42 //  pick_label - routine to pick a labeltext and return its number
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <ctype.h>
47 #include <math.h>
48 #include <FL/x.H>
49 #include <FL/Fl_Tooltip.H>
50 #include "drawxtl.h"
51 #include "DRAWxtlViewUI.h"
52 #include "EditView.h"
53 #include "Ellipsoids.h"
54 #include "draw_gbl.h"
55 
56 extern int Block_CIF;
57 
58 extern int volatile w_width;
59 
60 extern volatile int w_height;
61 
62 extern int w_st_x;
63 
64 extern int w_st_y;
65 
66 #ifdef WIN32
67 #include <io.h>
68 #include <direct.h>
69 #define AMBLEV 0.2f
70 #define snprintf _snprintf
71 #else
72 #include <unistd.h>
73 #define _chdir chdir
74 #if !defined(__APPLE__)
75 #include <X11/xpm.h>
76 # endif
77 #define AMBLEV 0.2f
78 #endif
79 
80 // function prototypes
81 
82 #include "DRAWxtl_proto.h"
83 
84 #ifdef WIN32
85 const char *flu_file_chooser (const char *, const char *, const char *);
86 char Configure_file[] = { ".drawxtlrc" };
87 
88 char foldersymbol = '\\';
89 #else
90 char Configure_file[] = { "~/.drawxtlrc" };
91 
92 char foldersymbol = '/';
93 #endif
94 
95 #ifdef FREEGLUT24
96 struct freeglut_compat
97 {				// ugly hack to access internal data structures of freeglut 2.4
98     int n0;
99     int n1;
100     GLboolean n2;
101     int n3;
102     int n4;
103     GLboolean n5;
104     unsigned int n6;
105     GLboolean Initialised;
106 };
107 
108 extern freeglut_compat fgState;
109 #endif
110 
111 int
main(int argc,char ** argv)112 main (int argc, char **argv)
113 {
114     int i = 0;
115 
116 #if !defined (WIN32) && !defined (__APPLE__)
117 #include "DRAWxtl.xpm"
118 #endif
119 
120     LoadConfig (0);		/* quick read to get saved size only */
121     drvui = new DRAWxtlViewUI;
122     drvui->destroy = 0;
123     drvui->max_frame = 0;
124     drvui->origin1_flag = 0;
125     drvui->Stereo = 0;
126     drvui->cross_eyed = 1;
127     drvui->stereo_base = 0.05f;
128     drvui->atom_no = NULL;
129     drvui->atom_so = NULL;
130     drvui->orig_atom_no = NULL;
131     drvui->table = NULL;
132     drvui->msgbuffer = (char*) zalloc(sizeof(char));
133     drvui->vert_occ = NULL;
134     drvui->label_scale = 1.0f;
135     drvui->triple[0] = 0;
136     drvui->labels_inited = 0;
137     drvui->auto_ellipse = 0;
138     drvui->nmag_alloc = 0;
139     drvui->nsurf = 0;
140     drvui->crystalDL = 0;
141     drvui->voidmap = NULL;
142     drvui->voidflag = 0;
143     drvui->voiddata1 = NULL;
144     drvui->voiddata2 = NULL;
145     drvui->Cursor_posW = NULL;
146     drvui->cur_reset = -1;
147     init_dynamic_storage ();
148     memset (drvui->saved_x_label, 0, 24 * sizeof (float));
149     memset (drvui->slab_con, 0, sizeof (drvui->slab_con));
150     offset[0] = offset[1] = offset[2] = 0.0f;
151     drvui->glback[0] = drvui->glback[1] = drvui->glback[2] = 1.0f;
152     vzero (drvui->Trans);
153     Fl_Tooltip::font (FL_COURIER_BOLD);
154     Fl_Tooltip::size (12);
155     Fl_Tooltip::color (23);
156     strcpy (drvui->Cur_File, "");
157     strcpy (drvui->Cur_Root, "");
158     drvui->Str_File_Changed = 0;
159     strcpy (drvui->ProgramPath, argv[0]);
160     Omit = new OmitParam;
161     drvui->b_mat[0][0] = drvui->b_mat[1][1] = drvui->b_mat[2][2] = 1.;
162     drvui->b_mat[0][1] = drvui->b_mat[1][0] = 0.;
163     drvui->b_mat[0][2] = drvui->b_mat[2][0] = 0.;
164     drvui->b_mat[1][2] = drvui->b_mat[2][1] = 0.;
165 
166 #ifdef WIN32
167     drvui->mainWindow->icon ((char *) LoadIcon (fl_display, MAKEINTRESOURCE (IDI_ICON1)));
168 #else
169     fl_open_display ();
170 #if !defined(__APPLE__)
171     XpmCreatePixmapFromData (fl_display, DefaultRootWindow (fl_display), drawxtl_xpm,
172 			     &drvui->icon, &shapemask, NULL);
173     drvui->mainWindow->icon ((char *) drvui->icon);
174 #endif
175 #endif
176     Fl::args (argc, argv, i);
177 
178 #ifdef FREEGLUT24
179     fgState.Initialised = 1;	// convince freeglut 2.4 that we did call glutInit()
180 #endif
181 
182     LoadConfig (1);
183     if (i < argc) {
184 	if (strcmp (argv[i], "-h") && strcmp (argv[i], "-?")) {
185 	    strcpy (drvui->Cur_File, argv[i]);	// input file specified on start line
186 	    if (!strchr (drvui->Cur_File, foldersymbol)) {
187 		getcwd (drvui->Cur_Dir, 1023);
188 	    } else {
189 		strcpy (drvui->Cur_Dir, drvui->Cur_File);
190 		char *end = strrchr (drvui->Cur_Dir, foldersymbol);
191 
192 		end++;
193 		*end = '\0';
194 
195 // path may be relative to the cwd, go there to obtain the absolute path
196 		chdir (drvui->Cur_Dir);
197 		getcwd (drvui->Cur_Dir, 1023);
198 
199 // remove path component from filename
200 		char *start = strrchr (drvui->Cur_File, foldersymbol);
201 
202 		start++;
203 		memmove (drvui->Cur_File, start, strlen (start) + 1);
204 	    }
205 
206 	    if (strstr (drvui->Cur_File, ".cif")
207 		&& strlen (strstr (drvui->Cur_File, ".cif")) == 4) {	// filename ends in .cif
208 		char tmp_file[256], string[256], newfile[256];
209 
210 		FILE *newstr, *inp;
211 
212 		static int one = 1;
213 
214 		strcpy (newfile, drvui->Cur_File);
215 		strcpy (tmp_file, drvui->Cur_File);	// copy original cif filename
216 		strcat (tmp_file, ".str");	// and add extension
217 
218 		newstr = fopen (tmp_file, "r");
219 		if (!(inp = fopen (newfile, "r"))) {
220 		    sprintf (string, "The file you selected ('%s') cannot be read\n"
221 			     "Do you wish to continue?", newfile);
222 		    if (fl_choice (string, "No", "Yes", NULL)) {
223 			inp = fopen (tmp_file, "w");
224 			fclose (inp);
225 			Edit_STR_cb (NULL, &one);
226 		    }
227 		} else {
228 		    strcpy (drvui->Cur_File, tmp_file);
229 		    WriteConfig ();	// update configuration file
230 		    drvui->CurFile->value (drvui->Cur_File);	// update main screen widgets
231 		    drvui->CurDir->value (drvui->Cur_Dir);
232 		    newstr = fopen (drvui->Cur_File, "w");
233 		    fprintf (newstr, "titl imported\n");
234 		    Block_CIF = 0;
235 		    fprintf (newstr, "import cif %s\n", newfile);
236 		    drvui->auto_ellipse = 1;
237 		    fprintf (newstr, "box 0.02 Black\n");
238 		    fprintf (newstr, "background White\n");
239 		    fprintf (newstr, "view 0. 0. 0.\n");
240 		    fprintf (newstr, "pack  -0.05 1.05 -0.05 1.05 -0.05 1.05\n");
241 		    fprintf (newstr, "end\n");
242 		    fclose (newstr);
243 		    fclose (inp);
244 		}
245 	    }
246 	    strcpy (drvui->Cur_Root, drvui->Cur_File);
247 	    trim_string (drvui->Cur_Root, 256);
248 	    int j;
249 
250 	    for (j = strlen (drvui->Cur_Root); j > 0; --j) {
251 		if (drvui->Cur_Root[j] == '.') {
252 		    drvui->Cur_Root[j] = 0;
253 		    break;
254 		}
255 	    }
256 	}
257     }
258     WriteConfig ();
259     drvui->mainWindow->show (argc, argv);
260     return Fl::run ();
261 }
262 
~CrystalView()263 CrystalView::~CrystalView ()
264 {
265 }
266 
267 double
AngleInRange(double angle)268 AngleInRange (double angle)
269 {
270 // routine to return an angle in the range -180 to 180
271     if (angle > 180.0)
272 	angle -= 180.0;
273     if (angle < -180.0)
274 	angle += 180.0;
275     if (angle < 0.0) {
276 	angle = int (100.0 * angle - 0.5) / 100.0;
277     } else {
278 	angle = int (100.0 * angle + 0.5) / 100.0;
279     }
280     return angle;
281 }
282 
283 void
Clean_Up_Files(void)284 Clean_Up_Files (void)
285 {
286 // delete the "frm", "save", "tmp" and "cns" files
287     int r;
288 
289     char string[512], tmp[50];
290 
291     if (!strlen (drvui->Cur_Root))
292 	return;
293 
294     for (r = 1; r <= drvui->max_frame; r++) {	// delete the frm* files
295 	strcpy (string, drvui->Cur_Root);
296 	sprintf (tmp, ".frm%d", r);
297 	strcat (string, tmp);
298 	unlink (string);
299     }
300     strcpy (string, drvui->Cur_Root);
301     strcat (string, ".save");
302     unlink (string);		// delete the "save" file
303     unlink (drvui->Cur_Temp);	// delete the tmp file
304     unlink (drvui->Cur_Console);	// delete the cns file
305 }
306 
307 void
Clear_Last_Omit_cb(Fl_Button *,void *)308 Clear_Last_Omit_cb (Fl_Button *, void *)
309 {
310     if (Omit->nomits > 0) {
311 	drvui->Str_File_Changed = 1;
312 	--Omit->nomits;
313 	if (!Omit->nomits) {
314 	    edtprm->ClearLastOmit->deactivate ();
315 	    edtprm->ClearOmit->deactivate ();
316 	}
317     }
318     Update_Str (0);		// update the 'str' file
319     Generate_Drawing (1);	// regenerate the drawing
320     Fl::redraw ();		// update the screen
321 }
322 
CrystalView(int x,int y,int w,int h,const char * l)323 CrystalView::CrystalView (int x, int y, int w, int h, const char *l)
324     :
325 Tb_Window (x, y, w, h, l)
326 {
327 // CrystalView constructor - subclass of Tb_Window - use default constructor
328 }
329 
330 void
Destroy_Open_Windows(void)331 Destroy_Open_Windows (void)
332 {
333 // call the destructor for all open windows and delete the database
334     if (arrows) {
335 	arrows->ArrowWindow->~Fl_Window ();
336 	delete (arrows->ArrowWindow);
337 	delete (arrows->ArrowBuffer);
338 	delete (arrows);
339 	arrows = NULL;
340     }
341     if (Bonds) {
342 //        delete(Bonds->Bond_Output_Buffer);
343 //        delete(Bonds->BondBuffer);
344 	Bonds->Bond_Edit_Window->~Fl_Window ();
345 	delete (Bonds);
346 	Bonds = NULL;
347     }
348     if (Configure) {
349 	Configure->ConfigWindow->~Fl_Window ();
350 	delete (Configure->ConfigWindow);
351 	delete (Configure);
352 	Configure = NULL;
353     }
354     if (MiscConfigure) {
355 	MiscConfigure->MiscConfigWindow->~Fl_Window ();
356 	delete (MiscConfigure->MiscConfigWindow);
357 	delete (MiscConfigure);
358 	MiscConfigure = NULL;
359     }
360     if (MSMSConfigure) {
361 	MSMSConfigure->MSMSConfigWindow->~Fl_Window ();
362 	delete (MSMSConfigure->MSMSConfigWindow);
363 	delete (MSMSConfigure);
364 	MSMSConfigure = NULL;
365     }
366     if (edtprm) {
367 	edtprm->editWindow->~Fl_Window ();
368 	delete (edtprm->editWindow);
369 	delete (edtprm);
370 	edtprm = NULL;
371     }
372     if (ellipsoids) {
373 	ellipsoids->Ellips_Window->~Fl_Window ();
374 	delete (ellipsoids->Ellips_Window);
375 	delete (ellipsoids->ColorInputBuf);
376 	delete (ellipsoids);
377 	ellipsoids = NULL;
378     }
379     if (LonePairs) {
380 	LonePairs->LonePair_Edit_Window->~Fl_Window ();
381 	delete (LonePairs->LonePair_Edit_Window);
382 	delete (LonePairs->LonePairBuffer);
383 	delete (LonePairs);
384 	LonePairs = NULL;
385     }
386     if (Maps) {
387 	Maps->Maps_Edit_Window->~Fl_Window ();
388 	delete (Maps->Maps_Edit_Window);
389 	delete (Maps->MapsBuffer);
390 	delete (Maps);
391 	Maps = NULL;
392     }
393     if (Modparms) {
394 // we cannot simply call the destructor here as this menu contains spinners
395 	Fl::delete_widget (Modparms->Mods_Edit_Window);
396 	delete (Modparms);
397 	Modparms = NULL;
398     }
399     if (MiscConfigure) {
400 	MiscConfigure->MiscConfigWindow->~Fl_Window ();
401 	delete (MiscConfigure->MiscConfigWindow);
402 	delete (MiscConfigure);
403 	MiscConfigure = NULL;
404     }
405     if (Polyhedra) {
406 	Polyhedra->Polyhedra_Edit_Window->~Fl_Window ();
407 	delete (Polyhedra->Polyhedra_Edit_Window);
408 	delete (Polyhedra->PolyhedraBuffer);
409 	delete (Polyhedra->Polyhedra_Output_Buffer);
410 	delete (Polyhedra);
411 	Polyhedra = NULL;
412     }
413     if (Slabs) {
414 	Slabs->SlabWindow->~Fl_Window ();
415 	delete (Slabs->SlabWindow);
416 	delete (Slabs);
417 	Slabs = NULL;
418     }
419     if (Spheres) {
420 	Spheres->Sphere_Edit_Window->~Fl_Window ();
421 	delete (Spheres->Sphere_Edit_Window);
422 	if (Spheres->SphereBuffer) {
423 	    delete (Spheres->SphereBuffer);
424 	    Spheres->SphereBuffer = NULL;
425 	}
426 	delete (Spheres);
427 	Spheres = NULL;
428     }
429     if (listwindow1) {
430 	listwindow1->~Fl_Window ();
431 	if (textbuf1) {
432 	    delete (textbuf1);
433 	    textbuf1 = NULL;
434 	}
435 	delete (listwindow1);
436 	listwindow1 = NULL;
437     }
438     if (listwindow2) {
439 	listwindow2->~Fl_Window ();
440 	if (textbuf2) {
441 	    delete (textbuf2);
442 	    textbuf2 = NULL;
443 	}
444 	delete (listwindow2);
445 	listwindow2 = NULL;
446     }
447     if (listwindow3) {
448 	listwindow3->~Fl_Window ();
449 	if (textbuf3) {
450 	    delete (textbuf3);
451 	    textbuf3 = NULL;
452 	}
453 	delete (listwindow3);
454 	listwindow3 = NULL;
455     }
456     if (helpwindow) {
457 	helpwindow->~Fl_Window ();
458 	if (helpbuf) {
459 	    delete (helpbuf);
460 	    helpbuf = NULL;
461 	}
462 	delete (helpwindow);
463 	helpwindow = NULL;
464     }
465     if (helpwindow1) {
466 	helpwindow1->~Fl_Window ();
467 	if (helpbuf1) {
468 	    delete (helpbuf1);
469 	    helpbuf1 = NULL;
470 	}
471 	delete (helpwindow1);
472 	helpwindow1 = NULL;
473     }
474     if (helpwindow2) {
475 	helpwindow2->~Fl_Window ();
476 	delete (helpwindow2);
477 	helpwindow2 = NULL;
478     }
479     if (helpwindow3) {
480 	helpwindow3->~Fl_Window ();
481 	delete (helpwindow3);
482 	helpwindow3 = NULL;
483     }
484     if (helpwindow4) {
485 	helpwindow4->~Fl_Window ();
486 	delete (helpwindow4);
487 	helpwindow4 = NULL;
488     }
489     if (helpwindow5) {
490 	helpwindow5->~Fl_Window ();
491 	delete (helpwindow5);
492 	helpwindow5 = NULL;
493     }
494     if (helpwindow6) {
495 	Fl::delete_widget (helpwindow6);
496 //        helpwindow6->~Fl_Window();
497 //        delete(helpwindow6);
498 	helpwindow6 = NULL;
499     }
500     if (textwindow) {
501 	textwindow->~Fl_Window ();
502 	if (textbuf) {
503 	    delete (textbuf);
504 	    textbuf = NULL;
505 	}
506 	delete (textwindow);
507 	textwindow = NULL;
508     }
509     drvui->destroy = 0;
510 }
511 
512 void
draw(void)513 CrystalView::draw (void)
514 {
515 // routine to draw crystal object to GL Window
516     static int first_time = 1;
517 
518     float cpx, cpy, cpz;
519 
520     float m[16];
521     GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
522     GLfloat light_ambient[] = { AMBLEV, AMBLEV, AMBLEV, 1.0f };
523     GLfloat light_specular[] = { 0.1f, 0.1f, 0.1f, 1.0f };
524     GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
525     GLfloat mat_shininess[] = { 0.8f };
526     GLfloat light_position[] = { 0.0f, 1.0f, 1.0f, 0.0f };
527     GLfloat light_direction[] = { 0.0f, -1.0f, 0.0f };
528     float ratio = (float) w () / (float) h ();
529 
530     if (!valid ()) {
531 	glLoadIdentity ();
532 	glViewport (0, 0, w (), h ());
533 	glEnable (GL_DEPTH_TEST);
534     }
535     if (first_time) {
536 	first_time = 0;
537 	drvui->crystalDL = glGenLists (1);
538 	drvui->frame_no = 1;
539 	if (strncmp (drvui->LoadOnStartup, "yes", 3) == 0 || strlen (drvui->Cur_Root)) {
540 	    Process_Inp (2);
541 	    Generate_Drawing (0);
542 	    Rotq = XYZ_Rot_to_Q (Xrot, Yrot, Zrot);
543 	    if (drvui->max_frame > 1) {
544 		Add_Frame_Main ();
545 		Main_Frame_Combo_cb (NULL, NULL);
546 	    } else {
547 		drvui->Frame_No->hide ();
548 	    }
549 	}
550     }
551     glMatrixMode (GL_PROJECTION);
552 
553     glLoadIdentity ();
554     if (M_cameras == 0) {
555 	if (ratio <= 1.)
556 	    glOrtho (-gl_size, gl_size, -gl_size / ratio, gl_size / ratio, -10000.,
557 		     10000.);
558 	else
559 	    glOrtho (-gl_size * ratio, gl_size * ratio, -gl_size, gl_size, -10000.,
560 		     10000.);
561     } else {
562 	gluPerspective (17, ratio, 0.01, 1000.);	// view angle, aspect,near/far clip
563     }
564     glMatrixMode (GL_MODELVIEW);
565     glLoadIdentity ();
566     cpx = (POV_Max[0] + POV_Min[0]) / 2.0f;
567     cpy = (POV_Max[1] + POV_Min[1]) / 2.0f;
568     cpz = (POV_Max[2] + POV_Min[2]) / 2.0f;
569 //    glShadeModel (GL_SMOOTH);
570     glMaterialfv (GL_FRONT, GL_SPECULAR, mat_specular);
571     glMaterialfv (GL_FRONT, GL_SHININESS, mat_shininess);
572     glLightfv (GL_LIGHT0, GL_SPECULAR, light_specular);
573     glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse);
574     glLightfv (GL_LIGHT0, GL_AMBIENT, light_ambient);
575     glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
576     glEnable (GL_LIGHTING);
577     glEnable (GL_LIGHT0);
578     glEnable (GL_COLOR_MATERIAL);
579     glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
580     glEnable (GL_DEPTH_TEST);
581     glClearColor (drvui->glback[0], drvui->glback[1], drvui->glback[2], 0.0f);
582     glClear ((GLbitfield) (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
583     gluLookAt (cpx, cpy, Scale * .50,	// camera position
584 	       cpx, cpy, -1.0,	// camera lookat point
585 	       0.0f, 1.0f, 0.0f);	// camera "up" vector
586     glColor3f (0.0f, 0.0f, 0.0f);
587     glLightfv (GL_LIGHT0, GL_POSITION, light_position);
588     glLightfv (GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
589     glPushMatrix ();
590     //   glTranslatef (gl_pos_x, gl_pos_y, gl_pos_z);
591     Tb_Window::calculate (m);	// convert quaternion to matrix
592 
593     Yrot = -asin (m[2]) * RAD;	// convert to equivalent rotations
594     double cosy = cos (Yrot / RAD);
595 
596     if (fabs (cosy) > 1.0e-3) {
597 	Xrot = atan2 (m[6] / cosy, m[10] / cosy) * RAD;
598 	Zrot = atan2 (m[1] / cosy, m[0] / cosy) * RAD;
599     } else {
600 	Zrot = 0.0;
601 	Xrot = atan2 (-m[9], m[5]) * RAD;
602     }
603     char string[20];
604 
605     sprintf (string, "%6.2f", Zrot);	// load widgets on main screen
606     drvui->Z_Rot->value (string);
607     sprintf (string, "%6.2f", Yrot);
608     drvui->Y_Rot->value (string);
609     sprintf (string, "%6.2f", Xrot);
610     drvui->X_Rot->value (string);
611 
612 //    glRotatef ((float)Xrot, (float) 1., (float) 0., (float) 0.);
613 //    glRotatef ((float)Yrot, (float) 0., (float) 1., (float) 0.);
614 //    glRotatef ((float)Zrot, (float) 0., (float) 0., (float) 1.);
615     glMultMatrixf (m);		// this line equivalent to 3 above
616 //    glTranslatef (-cpx,-cpy,-cpz); //this can mess up initial positioning w.r.t POV
617     draw_cursor ();
618     glCallList (drvui->crystalDL);
619     int saved_frame_no = drvui->frame_no;
620 
621     for (drvui->frame_no = 1; drvui->frame_no <= drvui->max_frame; drvui->frame_no++)
622 	generate_gl_texts ();
623     if (ShowMapLegend)
624 	MapLegend();
625     drvui->frame_no = saved_frame_no;
626     glGetIntegerv (GL_VIEWPORT, viewport);	// save matrices for later
627     glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
628     glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
629     glPopMatrix ();
630     if (drvui->destroy) {	// close windows that are no longer needed
631 	if (drvui->destroy & LIST1) {
632 	    listwindow1->~Fl_Window ();
633 	    listwindow1 = NULL;
634 	    drvui->destroy &= !LIST1;
635 	}
636 	if (drvui->destroy & LIST2) {
637 	    listwindow2->~Fl_Window ();
638 	    listwindow2 = NULL;
639 	    if (textbuf2) {
640 		delete (textbuf2);
641 		textbuf2 = NULL;
642 	    }
643 	    drvui->destroy &= !LIST2;
644 	}
645 	if (drvui->destroy & LIST3) {
646 	    listwindow3->~Fl_Window ();
647 	    listwindow3 = NULL;
648 	    if (textbuf3) {
649 		delete (textbuf3);
650 		textbuf3 = NULL;
651 	    }
652 	    drvui->destroy &= !LIST3;
653 	}
654 	if (drvui->destroy & SPHERE) {
655 	    Spheres->Sphere_Edit_Window->~Fl_Window ();
656 	    Spheres->Sphere_Edit_Window = NULL;
657 	    if (Spheres->SphereBuffer) {
658 		delete (Spheres->SphereBuffer);
659 		Spheres->SphereBuffer = NULL;
660 	    }
661 	    if (Spheres->Sphere_Output_Buffer) {
662 		delete (Spheres->Sphere_Output_Buffer);
663 		Spheres->Sphere_Output_Buffer = NULL;
664 	    }
665 	    delete (Spheres);
666 	    Spheres = NULL;
667 	    drvui->destroy &= !SPHERE;
668 	}
669 	if (drvui->destroy & ELLIPSOID) {
670 	    ellipsoids->Ellips_Window->~Fl_Window ();
671 	    ellipsoids->Ellips_Window = NULL;
672 	    delete (ellipsoids->ColorInputBuf);
673 	    delete (ellipsoids);
674 	    ellipsoids = NULL;
675 	    drvui->destroy &= !ELLIPSOID;
676 	}
677 	if (drvui->destroy & LONEPAIR) {
678 	    LonePairs->LonePair_Edit_Window->~Fl_Window ();
679 	    delete (LonePairs->LonePairBuffer);
680 	    delete (LonePairs);
681 	    LonePairs = NULL;
682 	    drvui->destroy &= !LONEPAIR;
683 	}
684 	if (drvui->destroy & TEXT1) {
685 	    textwindow->~Fl_Window ();
686 	    textwindow = NULL;
687 	    delete (textbuf);
688 	    textbuf = NULL;
689 	    drvui->destroy &= !TEXT1;
690 	}
691     }
692     if (drvui->origin1_flag)
693 	drvui->Origin1_Msg->show ();
694     else
695 	drvui->Origin1_Msg->hide ();
696 }
697 
698 void
draw_overlay(void)699 CrystalView::draw_overlay (void)
700 {
701     static float cpx, cpy, cpz;
702 
703     float m[16];
704 
705 
706     if (slabmode < 2)
707 	return;
708 
709     float ratio = 1.0f * (float) w () / (float) h ();
710 
711     glPushMatrix ();
712     glMatrixMode (GL_PROJECTION);
713     glLoadIdentity ();
714     if (M_cameras == 0) {
715 	if (ratio <= 1.)
716 	    glOrtho (-gl_size, gl_size, -gl_size / ratio, gl_size / ratio, -10000.,
717 		     10000.);
718 	else
719 	    glOrtho (-gl_size * ratio, gl_size * ratio, -gl_size, gl_size, -10000.,
720 		     10000.);
721     } else {
722 	gluPerspective (17, ratio, 0.01, 1000.);
723     }
724 
725     glMatrixMode (GL_MODELVIEW);
726     Tb_Window::calculate (m);
727 
728     glMultMatrixf (m);
729     cpx = (POV_Max[0] + POV_Min[0]) / 2.0f;
730     cpy = (POV_Max[1] + POV_Min[1]) / 2.0f;
731     cpz = (POV_Max[2] + POV_Min[2]) / 2.0f;
732     glTranslatef (-cpx, -cpy, -cpz);
733 
734     show_slab_ovl ();
735     glPopMatrix ();
736 }
737 
738 void
Error_Box(const char * message)739 Error_Box (const char *message)
740 {
741     int yy = 100;
742 
743 // routine for Error message windows
744 
745     if (errorbox) {
746 	errorbox->~Fl_Window ();
747 //    Fl::delete_widget(errorbox);
748 	errorbox = NULL;
749     }
750 
751     drvui->msgbuffer= (char*) realloc(drvui->msgbuffer,(strlen(drvui->msgbuffer)+strlen(message)+2)*sizeof(char));
752     strcat(drvui->msgbuffer,message);
753     if (strstr (message, "\n"))
754 	yy = 140;
755     errorbox = new Fl_Window (200, 180, 500, yy, "Error");
756     errorbox->begin ();
757     errorbox->callback ((Fl_Callback *) Error_Box_cb);
758 
759     int y = 20;
760 
761     Fl_Multiline_Output *box = new Fl_Multiline_Output (0, 10, 500, yy - 50, "");
762 
763     box->box (FL_NO_BOX);
764     box->labelsize (14);
765     box->labelcolor ((Fl_Color) 1);
766     box->color (FL_GRAY);
767     box->cursor_color (FL_BACKGROUND_COLOR);
768     box->value (drvui->msgbuffer);
769     y += 15 + yy - 80;
770     Fl_Button *o = new Fl_Button (210, y, 80, 30, "Close");
771 
772     o->callback ((Fl_Callback *) Error_Box_cb);
773 #if !defined (WIN32) && !defined (__APPLE__)
774     errorbox->icon ((char *) drvui->icon);
775 #endif
776     errorbox->end ();
777     errorbox->show ();
778     strcat(drvui->msgbuffer,"\n");
779 //    errorbox->set_modal();
780 }
781 
782 void
Error_Box_cb(Fl_Widget * w,void *)783 Error_Box_cb (Fl_Widget * w, void *)
784 {
785 // callback to hide error message window
786     w->window ()->hide ();
787     free (drvui->msgbuffer);
788     drvui->msgbuffer = (char*) zalloc (sizeof (char));
789 }
790 
791 void
Exit_cb(void)792 Exit_cb (void)
793 {
794 // callback routine when exit menuitem is clicked or when main window is closed
795     int r;
796 
797     if (strlen (drvui->Cur_File) && drvui->Str_File_Changed) {
798 	r = fl_choice ("The current str file has not been saved.\n"
799 		       "What action should be taken?", "Cancel", "Save", "Discard");
800 	if (!r)
801 	    return;
802 	if (r == 1)
803 	    Update_Str (1);
804     }
805     WriteConfig ();
806     Clean_Up_Files ();		// delete all the temporary files
807     Destroy_Open_Windows ();
808     if (FourierPt)
809 	free (FourierPt);
810     free (crystal);
811     delete (Omit);
812     if (s_vert)
813 	free (s_vert);
814     if (o_vert)
815 	free (o_vert);
816     if (o_vert_nm)
817 	free (o_vert_nm);
818     if (drvui->vert_occ)
819 	free (drvui->vert_occ);
820     if (xypos)
821 	free (xypos);
822     if (xypos_nm)
823 	free (xypos_nm);
824     if (vert_sym_no)
825 	free (vert_sym_no);
826     if (vert_sym_nos)
827 	free (vert_sym_nos);
828     if (vertex_list)
829 	free (vertex_list);
830     if (poly_list)
831 	free (poly_list);
832     if (drvui->atom_no)
833 	free (drvui->atom_no);
834     if (drvui->atom_so)
835 	free (drvui->atom_so);
836     if (drvui->orig_atom_no)
837 	free (drvui->orig_atom_no);
838     if (drvui->modulate_x)
839 	free (drvui->modulate_x);
840     if (drvui->modulate_3x)
841 	free (drvui->modulate_3x);
842     if (drvui->modulate_3t)
843 	free (drvui->modulate_3t);
844     if (drvui->atoms)
845 	free (drvui->atoms);
846     if (drvui->ellips)
847 	free (drvui->ellips);
848     if (drvui->fourier)
849 	free (drvui->fourier);
850     if (drvui->labels)
851 	free (drvui->labels);
852     if (drvui->bplanes)
853 	free (drvui->bplanes);
854     if (drvui->planes)
855 	free (drvui->planes);
856     if (drvui->polyhedra)
857 	free (drvui->polyhedra);
858     if (drvui->polyedges)
859 	free (drvui->polyedges);
860     if (drvui->spheres)
861 	free (drvui->spheres);
862     if (drvui->atprops)
863 	free (drvui->atprops);
864     if (drvui->modulate_gbl)
865 	free (drvui->modulate_gbl);
866     if (drvui->frames)
867 	free (drvui->frames);
868     if (drvui->nsurf > 1) {
869 	for (r = 1; r < drvui->nsurf; r++) {
870 	    free (drvui->surfx[r]);
871 	    free (drvui->surfy[r]);
872 	    free (drvui->surfz[r]);
873 	}
874     }
875     if (drvui->voidmap) {
876 	for (int j = 0; j < drvui->voidgrid[0]; j++) {
877 	    for (int k = 0; k < drvui->voidgrid[1]; k++)
878 		free (drvui->voidmap[j][k]);
879 	    free (drvui->voidmap[j]);
880 	}
881 	free (drvui->voidmap);
882     }
883     if (!strncmp (drvui->LoadOnStartup, "maybe", 5)) {
884 	strcpy (drvui->LoadOnStartup, "yes");
885 	WriteConfig ();
886     }
887     Fl::delete_widget (drvui->mainWindow);
888     free (drvui->table);
889     free (drvui->arrows);
890     free (drvui->cones);
891     free (drvui->bonds);
892     free (drvui->msgbuffer);
893     delete (drvui);
894     exit (0);
895 }
896 
897 int
Get_Unique_Atoms(char atoms[100][5],int Frame_No)898 Get_Unique_Atoms (char atoms[100][5], int Frame_No)
899 {
900 // routine to return the unique atom names in current frame
901     int j;
902 
903     int mlist = 0;
904 
905     char atom1[5];
906 
907     FILE *aout;
908 
909     char string[256];
910 
911     strcpy (string, drvui->Cur_Root);
912     strcat (string, ".frm");
913     sprintf (atom1, "%d", Frame_No);
914     strcat (string, atom1);
915     if (!(aout = fopen (string, "r"))) {
916 	Error_Box ("Unable to open frm file.");
917 	return 0;
918     }
919     strcpy (string, "");
920     while (!feof (aout)) {
921 	fgets (string, 100, aout);
922 	memset (atom1, 0, 5);
923 	if (strlen (string) < 4)
924 	    break;
925 	(void) sscanf (string, "%s", atom1);
926 	atom1[4] = 0;
927 	for (j = 3; j >= 0; --j) {
928 	    if (atom1[j] == ' ')
929 		atom1[j] = 0;
930 	}
931 	strncpy (atoms[mlist++], atom1, 5);	// add new one to end of list
932 
933 	for (j = 0; j < mlist - 1; j++) {	// if not unique, truncate list
934 	    if (!strncmp (atoms[j], atom1, 4))
935 		--mlist;
936 	}
937     }
938     for (j = 0; j < mlist - 1; j++) {
939 	int k;
940 
941 	for (k = j + 1; k < mlist; k++) {	// sort atom names
942 	    if (strncmp (atoms[k], atoms[j], 4) < 0) {
943 		strncpy (atom1, atoms[j], 4);
944 		strncpy (atoms[j], atoms[k], 4);
945 		strncpy (atoms[k], atom1, 4);
946 	    }
947 	}
948     }
949     fclose (aout);
950     return mlist;
951 }
952 
953 void
ImportDataFile_cb(Fl_Widget *,void * arg)954 ImportDataFile_cb (Fl_Widget *, void *arg)
955 {
956 // Callback routine to import a structure file
957     int r;
958 
959     int i;
960 
961     FILE *inp;
962 
963     FILE *newstr;
964 
965     static int one = 1;
966 
967     const char *phase;
968 
969     char string[2048];
970 
971     char tmp_dir[1024];
972 
973     char tmp_file[1024];
974 
975     char newfile2[1024];
976 
977     char Input_string[256];
978     char string0[] = { "Select CIF Data File" };
979     char string1[] = { "Select FDAT Data File" };
980     char string2[] = { "Select GSAS Data File" };
981     char string3[] = { "Select SCHAKAL Data File" };
982     char string4[] = { "Select SHELX Data File" };
983     char string5[] = { "Select WIEN2k Data File" };
984     char string6[] = { "Select DISCUS Data File" };
985     char string7[] = { "Select FULLPROF Data File" };
986     char string8[] = { "Select EXCITING Data File" };
987 
988     switch ((long) arg) {
989     case 0:
990 	strcpy (Input_string, string0);
991 	break;
992     case 1:
993 	strcpy (Input_string, string1);
994 	break;
995     case 2:
996 	strcpy (Input_string, string2);
997 	break;
998     case 3:
999 	strcpy (Input_string, string3);
1000 	break;
1001     case 4:
1002 	strcpy (Input_string, string4);
1003 	break;
1004     case 5:
1005 	strcpy (Input_string, string5);
1006 	break;
1007     case 6:
1008 	strcpy (Input_string, string6);
1009 	break;
1010     case 7:
1011 	strcpy (Input_string, string7);
1012 	break;
1013     case 8:
1014 	strcpy (Input_string, string8);
1015 	break;
1016     }
1017     if (strlen (drvui->Cur_File) && drvui->Str_File_Changed) {
1018 	r = fl_choice ("The current str file has not been saved.\n"
1019 		       "What action should be taken?", "Cancel", "Save", "Discard");
1020 	if (!r)
1021 	    return;
1022 	if (r == 1)
1023 	    Update_Str (1);
1024     }
1025 #if defined(WIN32)
1026     char drive[_MAX_DRIVE];
1027 
1028     char dir[_MAX_DIR];
1029 
1030     char fname[_MAX_FNAME];
1031 
1032     char ext[_MAX_EXT];
1033 
1034     const char *newfile = flu_file_chooser (Input_string, "*", drvui->Cur_File);
1035 
1036     if (newfile) {
1037 	_splitpath (newfile, drive, dir, fname, ext);	//Windows code
1038 	strcpy (tmp_dir, drive);	// Drive letter
1039 	strcat (tmp_dir, dir);	//   and directory
1040 	strcpy (tmp_file, fname);	// copy file name
1041 	strcat (tmp_file, ".str");	// and add extension
1042 #else
1043     int k = 0;
1044 
1045     const char *newfile = fl_file_chooser (Input_string, "*", drvui->Cur_File);
1046 
1047     if (newfile) {
1048 	strcpy (tmp_file, newfile);
1049 	strcpy (tmp_dir, newfile);
1050 	for (i = strlen (tmp_dir); i > 0; --i) {	// Find final / in file name
1051 	    if (tmp_dir[i - 1] == '/') {
1052 		tmp_dir[i] = 0;
1053 		break;
1054 	    }
1055 	}
1056 	for (i = strlen (tmp_dir); newfile[i] != 0; i++) {
1057 	    tmp_file[k++] = newfile[i];	// copy file name to tmp_file
1058 	}
1059 	tmp_file[k] = 0;
1060 	strcat (tmp_file, ".str");
1061 #endif
1062 	chdir (tmp_dir);	// switch to that directory
1063 	newstr = fopen (tmp_file, "r");
1064 	if (newstr) {
1065 	    snprintf (string, 2048,
1066 		      "The implied output file ('%s') will be overwritten.\n"
1067 		      "Do you wish to continue?", tmp_file);
1068 	    fclose (newstr);
1069 	    if (!fl_choice (string, "No", "Yes", NULL)) {
1070 		chdir (drvui->Cur_Dir);	// restore the original directory
1071 		return;
1072 	    }
1073 	}
1074 	if (!(inp = fopen (newfile, "r"))) {
1075 	    snprintf (string, 2048, "The file you selected ('%s') cannot be read\n"
1076 		      "Do you wish to continue?", newfile);
1077 	    if (fl_choice (string, "No", "Yes", NULL)) {
1078 		inp = fopen (tmp_file, "w");
1079 		fclose (inp);
1080 		Edit_STR_cb (NULL, &one);
1081 	    }
1082 	} else {
1083 	    drvui->Str_File_Changed = 0;
1084 	    Clean_Up_Files ();	// delete the temporary files,
1085 	    Destroy_Open_Windows ();	// input dialogs and maps
1086 	    if (FourierPt) {	// associated with the previous
1087 		free (FourierPt);	// structure
1088 		FourierPt = NULL;
1089 	    }
1090 	    if (drvui->nsurf > 1) {
1091 		for (i = 1; i < drvui->nsurf; i++) {
1092 		    free (drvui->surfx[i]);
1093 		    free (drvui->surfy[i]);
1094 		    free (drvui->surfz[i]);
1095 		    drvui->surfx[i] = NULL;
1096 		    drvui->surfy[i] = NULL;
1097 		    drvui->surfz[i] = NULL;
1098 		}
1099 	    }
1100 	    strcpy (drvui->Cur_File, tmp_file);
1101 	    strcpy (drvui->Cur_Dir, tmp_dir);
1102 	    WriteConfig ();	// update configuration file
1103 	    drvui->CurFile->value (drvui->Cur_File);	// update main screen widgets
1104 	    drvui->CurDir->value (drvui->Cur_Dir);
1105 	    newstr = fopen (drvui->Cur_File, "w");
1106 	    if (!newstr) {
1107 		snprintf (string, 256,
1108 			  "The implied output file ('%s') could not be created.",
1109 			  drvui->Cur_File);
1110 		Error_Box (string);
1111 		char *newfile =
1112 		    fl_file_chooser ("Please choose a new location in a writable directory", "*.str",
1113 				     drvui->Cur_File);
1114 		if (!newfile || !(newstr=fopen(newfile,"w"))) {
1115 		    fclose (inp);
1116 		    return;
1117 		} else {
1118 		    strcpy(drvui->Cur_File,newfile);
1119 		    strcpy(drvui->Cur_Dir,newfile);
1120 		    for (i = strlen (drvui->Cur_Dir); i > 0; --i) {	// Find final / in file name
1121 	    		if (drvui->Cur_Dir[i - 1] == '/') {
1122 			    drvui->Cur_Dir[i] = 0;
1123 			    break;
1124 			}
1125 		    }
1126 		    WriteConfig ();	// update configuration file
1127 		    drvui->CurFile->value (drvui->Cur_File);	// update main screen widgets
1128 		    drvui->CurDir->value (drvui->Cur_Dir);
1129 		}
1130 	    }
1131 	    fprintf (newstr, "titl imported\n");
1132 
1133 	    if (strlen (newfile) > 80) {
1134 // remove path component from filename if the full name plus import instruction
1135 // would exceed our maximum input line length of 100 bytes
1136 		const char *start = strrchr (newfile, '/');
1137 
1138 		if (!start) {
1139 		    start = strrchr (newfile, '\\');	// look for the other Windows folder marker
1140 		    if (!start) {
1141 			Error_Box
1142 			    ("Unable to find folder/directory markers in file string\n"
1143 			     "Is your input file name really longer than 80 characters?\n"
1144 			     "If so, please rename it.");
1145 			fclose (inp);
1146 			fclose (newstr);
1147 			return;
1148 		    }
1149 		}
1150 		start++;
1151 		memmove (newfile2, start, strlen (start) + 1);
1152 		if (strlen (newfile2) > 80) {
1153 		    Error_Box
1154 			("Your file name is longer than 80 characters. Please rename it.");
1155 		    fclose (inp);
1156 		    fclose (newstr);
1157 		    return;
1158 		}
1159 	    } else {
1160 		strcpy (newfile2, newfile);
1161 	    }
1162 
1163 	    switch ((long) arg) {
1164 	    case 0:		// CIF file
1165 		Block_CIF = 0;
1166 //		fprintf (newstr, "import cif %s\n", newfile2);
1167 		fprintf (newstr, "inline cif\n");
1168 		while (!feof (inp)) {
1169 		    fgets (string, 133, inp);
1170 		    fprintf (newstr, "%s", string);
1171 		}
1172 		fprintf (newstr, "# End of data for %s\n", newfile2);
1173 		drvui->auto_ellipse =
1174 		    fl_choice ("Should ellipsoids be displayed automatically?", "No",
1175 			       "Yes", NULL);
1176 		break;
1177 	    case 1:		// FDAT file
1178 		fprintf (newstr, "import fdat %s\n", newfile2);
1179 		break;
1180 	    case 2:		// GSAS file
1181 		phase = fl_input ("Enter GSAS phase number:", "1");
1182 		if (!phase)
1183 		    fprintf (newstr, "import gsas %s 1\n", newfile2);
1184 		else
1185 		    fprintf (newstr, "import gsas %s %s\n", newfile2, phase);
1186 		break;
1187 	    case 3:		// SCHAKAL file
1188 		fprintf (newstr, "import schakal %s\n", newfile2);
1189 		break;
1190 	    case 4:		// process SHELX file
1191 		drvui->auto_ellipse =
1192 		    fl_choice ("Should ellipsoids be displayed automatically?", "No",
1193 			       "Yes", NULL);
1194 		fprintf (newstr, "inline shelx\n");
1195 		while (!feof (inp)) {
1196 		    fgets (string, 133, inp);
1197 		    fprintf (newstr, "%s", string);
1198 		    if (!strncmp (string, "HKLF", 4) || !strncmp (string, "hklf", 4)
1199 			|| !strncmp (string, "END", 3) || !strncmp (string, "end", 3))
1200 			break;
1201 		}
1202 		if (drvui->autolabel == 1)
1203 		    drvui->autolabel = 2;
1204 		break;
1205 	    case 5:		// WIEN file
1206 		fprintf (newstr, "import wien2k %s\n", newfile2);
1207 		break;
1208 	    case 6:		// DISCUS file
1209 		fprintf (newstr, "import discus %s\n", newfile2);
1210 		break;
1211 	    case 7:		// FULLPROF file
1212 		phase = fl_input ("Enter FULLPROF phase number:", "1");
1213 		if (!phase)
1214 		    fprintf (newstr, "import pcr %s 1\n", newfile2);
1215 		else
1216 		    fprintf (newstr, "import pcr %s %s\n", newfile2, phase);
1217 		break;
1218 	    case 8:		// Exciting file
1219 		fprintf (newstr, "import exciting %s\n", newfile2);
1220 		break;
1221 	    }
1222 	    fprintf (newstr, "box 0.02 Black\n");
1223 	    fprintf (newstr, "background White\n");
1224 	    fprintf (newstr, "view 0. 0. 0.\n");
1225 	    fprintf (newstr, "pack  -0.05 1.05 -0.05 1.05 -0.05 1.05\n");
1226 	    fprintf (newstr, "end\n");
1227 	    fclose (newstr);
1228 	    fclose (inp);
1229 	}
1230 	Process_Inp (2);
1231 	Rotq = XYZ_Rot_to_Q (Xrot, Yrot, Zrot);
1232 	Add_Frame_Main ();
1233 	Generate_Drawing (0);	// generate this structure
1234 	Fl::redraw ();		//  and draw it
1235     }
1236 }
1237 
1238 void
1239 Include_Cutouts_cb (void)
1240 {
1241 // callback routine when Use_Cutouts checkbox is changed
1242     char string[128];
1243 
1244     drvui->Str_File_Changed = 1;
1245     if (ellipsoids->Use_Cutouts->value ()) {
1246 	ellipsoids->Cutout_Color->activate ();
1247 	drvui->El_Cutout = 1;
1248 	strcpy (string, ellipsoids->Cutout_Color->value ());
1249 	if (!strlen (string))
1250 	    strcpy (string, (char *) "Gray20");
1251 	ellipsoids->Cutout_Color->value (string);
1252     } else {
1253 	drvui->El_Cutout = 0;
1254 	ellipsoids->Cutout_Color->deactivate ();
1255     }
1256 }
1257 
1258 void
1259 Load_Bond_Data (const char *atom, char table[20480])
1260 {
1261 // get sorted bond data for 'atom' from out file into character array table
1262     FILE *flin;
1263 
1264     int i;
1265 
1266     float f1, f2, f3, d;
1267 
1268     char filename[256];
1269 
1270     char string[100];
1271 
1272     char string1[20], string2[40], string3[20];
1273 
1274     char atom1[5];
1275 
1276     int nfound = 0;
1277 
1278     char atoms[1000][5];
1279 
1280     float d_list[1000];
1281 
1282     memset (string1, 0, 20);
1283     memset (string2, 0, 20);
1284     memset (string3, 0, 20);
1285     strcpy (filename, drvui->Cur_Root);	// generate name of '.out' file
1286     strcat (filename, ".out");
1287     if (!(flin = fopen (filename, "r"))) {
1288 	strcpy (table, "Generated Bond Table\n  not available!");
1289 	return;
1290     }
1291 
1292     table[0] = 0;
1293     strcpy (string, "    ");
1294     while (strncmp (string, " Bond Distance", 14)) {	// find bond-distance table
1295 	if (!fgets (string, 100, flin)) {
1296 	    strcpy (table, "Generated Bond Table\n  not available!");
1297 	    fclose (flin);
1298 	    return;
1299 	}
1300     }
1301     while (strncmp (string, "End of File.", 12) && strncmp (string, " doing frame", 12)) {	// bond-distances over when end of file is reached
1302 	int j;
1303 
1304 	if (!fgets (string, 100, flin)) {
1305 	    strcpy (table, "Generated Bond Table\n  not available!");
1306 	    fclose (flin);
1307 	    return;
1308 	}
1309 	sscanf (string, "%s %s %s", string1, string2, string3);
1310 	if ((!strncmp (string1, "Distances", 9))
1311 	    && (!strncmp (string3, atom, strlen (string3)))) {
1312 	    if (!fgets (string, 100, flin)) {
1313 		if (!strlen (table)) {
1314 		    strcpy (table, "Generated Bond Table\n  not available!");
1315 		}
1316 		fclose (flin);
1317 		return;
1318 	    }
1319 	    if (!fgets (string, 100, flin)) {
1320 		if (!strlen (table)) {
1321 		    strcpy (table, "Generated Bond Table\n  not available!");
1322 		}
1323 		fclose (flin);
1324 		return;
1325 	    }
1326 	    while (strlen (string) > 10 && nfound < 1000) {
1327 		sscanf (string, "%s %d %s %f %f %f %f", string1, &j, string2, &f1, &f2,
1328 			&f3, &d);
1329 		strncpy (atoms[nfound], string1, 4);
1330 		atoms[nfound][4] = 0;
1331 		d_list[nfound++] = d;
1332 		if (!fgets (string, 100, flin)) {
1333 		    if (!strlen (table)) {
1334 			strcpy (table, "Generated Bond Table\n  not available!");
1335 		    }
1336 		    fclose (flin);
1337 		    return;
1338 		}
1339 	    }
1340 	}
1341     }
1342     for (i = 0; i < nfound - 1; i++) {
1343 	int k;
1344 
1345 	float tmp;
1346 
1347 	for (k = i + 1; k < nfound; k++) {	// sort distances
1348 	    if (d_list[k] < d_list[i]) {
1349 		tmp = d_list[i];
1350 		d_list[i] = d_list[k];
1351 		d_list[k] = tmp;
1352 		strncpy (atom1, atoms[i], 4);
1353 		strncpy (atoms[i], atoms[k], 4);
1354 		strncpy (atoms[k], atom1, 4);
1355 	    }
1356 	}
1357     }
1358     for (i = 0; i < nfound; i++) {
1359 	sprintf (string, "%4s  %8.3f\n", atoms[i], d_list[i]);
1360 	strcat (table, string);
1361     }
1362 
1363     if (!strlen (table)) {
1364 	strcpy (table, "Generated Bond Table\n  not available!");
1365     }
1366     fclose (flin);
1367 }
1368 
1369 void
1370 LoadConfig (bool full_check)
1371 {
1372 // load configuration file. If full_check is true, load all data, else just saved screen size
1373     FILE *fname;
1374 
1375     char filename[256];
1376 
1377     char temp[256];
1378 
1379     char stereo[256];
1380 
1381     char autolabel[256];
1382 
1383 #ifdef WIN32
1384     char profile[100];
1385 
1386     OSVERSIONINFOEX osvi;
1387 
1388     memset (&osvi, 0, sizeof (OSVERSIONINFOEX));
1389     osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
1390     GetVersionEx ((OSVERSIONINFO *) & osvi);
1391     if (osvi.dwMajorVersion == 4)
1392 	strcpy (profile, "c:");
1393     else
1394 	strcpy (profile, getenv ("USERPROFILE"));
1395     strcpy (filename, profile);
1396     strcat (filename, "\\");
1397     strcat (filename, Configure_file);
1398 #else
1399     fl_filename_expand (filename, Configure_file);
1400 #endif
1401     fname = fopen (filename, "r");
1402     if (!full_check) {
1403 	if (fname) {
1404 	    int i;
1405 
1406 	    for (i = 0; i < 15; i++)
1407 		fgets (temp, 256, fname);
1408 	    if (strlen (temp) > 10) {
1409 		int xpos, ypos, width, height;
1410 
1411 		if (sscanf (temp, "%d %d %d %d", &xpos, &ypos, &width, &height) == 4) {
1412 		    w_st_x = xpos;
1413 		    w_st_y = ypos;
1414 		    w_width = width;
1415 		    w_height = height;
1416 		}
1417 	    }
1418 	    fclose (fname);
1419 	}
1420 	return;
1421     }
1422     if (!fname) {
1423 	strcpy (drvui->Cur_Dir,
1424 		"Unable to open Configuration - Please use 'Configure' menu items.");
1425 	strcpy (drvui->Cur_File, "");
1426 	strcpy (drvui->DefaultFinish, "finish 0.70 0.30 0.08 0.01");
1427 #ifdef WIN32			// Allow for different windows defaults
1428 	strcpy (drvui->POV_Options, "+W600 +H600 +D +FC +A0.3 +P");
1429 //      strcpy(drvui->POV_Include,"c:\\colors.inc");   // Is there a good default for windows?
1430 //      strcpy(drvui->POV_Path,"povray.exe");
1431 #else
1432 	strcpy (drvui->POV_Options, "+W600 +H600 +D +FC +A0.3 +P");
1433 #ifdef __APPLE__
1434 	strcpy (drvui->POV_Include, "/sw/share/povray-3.5/include/colors.inc");
1435 	strcpy (drvui->POV_Path, "/sw/bin/povray");
1436 #else
1437 	strcpy (drvui->POV_Include, "/usr/local/share/povray-3.5/include/colors.inc");
1438 	strcpy (drvui->POV_Path, "/usr/local/bin/povray");
1439 #endif
1440 #endif
1441     } else {
1442 	fgets (drvui->DRAWxtl_Path, 256, fname);
1443 	trim_string (drvui->DRAWxtl_Path, 256);
1444 	fgets (drvui->POV_Path, 256, fname);
1445 	trim_string (drvui->POV_Path, 256);
1446 	fgets (drvui->VRML_Path, 256, fname);
1447 	trim_string (drvui->VRML_Path, 256);
1448 	fgets (drvui->EditName, 256, fname);
1449 	trim_string (drvui->EditName, 256);
1450 	fgets (drvui->FileViewName, 256, fname);
1451 	trim_string (drvui->FileViewName, 256);
1452 	fgets (drvui->POV_Options, 256, fname);
1453 	trim_string (drvui->POV_Options, 256);
1454 	fgets (drvui->Cur_File, 256, fname);
1455 	trim_string (drvui->Cur_File, 256);
1456 	fgets (drvui->Cur_Dir, 256, fname);
1457 	trim_string (drvui->Cur_Dir, 256);
1458 	fgets (drvui->POV_Include, 256, fname);
1459 	trim_string (drvui->POV_Include, 256);
1460 	fgets (drvui->LoadOnStartup, 10, fname);
1461 	trim_string (drvui->LoadOnStartup, 10);
1462 	fgets (drvui->DefaultFinish, 256, fname);
1463 	trim_string (drvui->DefaultFinish, 256);
1464 	fgets (temp, 256, fname);	// skip over executable path
1465 	fgets (autolabel, 256, fname);
1466 	fgets (stereo, 256, fname);
1467 	trim_string (stereo, 256);
1468 	fgets (temp, 256, fname);	// skip over window dimensions
1469 	temp[0] = '\0';
1470 	fgets (temp, 256, fname);
1471 	trim_string (temp, 256);
1472 	strcpy (drvui->MSMS_Path, "");
1473 	fgets (drvui->MSMS_Path, 256, fname);
1474 	trim_string (drvui->MSMS_Path, 256);
1475 	strcpy (drvui->Mencoder_Path, "");
1476 	fgets (drvui->Mencoder_Path, 256, fname);
1477 	trim_string (drvui->Mencoder_Path, 256);
1478 	strcpy (drvui->FFmpeg_Path, "");
1479 	fgets (drvui->FFmpeg_Path, 256, fname);
1480 	trim_string (drvui->FFmpeg_Path, 256);
1481 	fclose (fname);
1482     }
1483     if (!strncmp (drvui->LoadOnStartup, "maybe", 5)) {
1484 	Error_Box ("Previous attempt to load a structure on startup failed.\n"
1485 		   "LoadOnStartup cleared - Use Configure menu to reinstate.");
1486 	strcpy (drvui->LoadOnStartup, "");
1487     } else if (!strlen (drvui->LoadOnStartup)) {
1488 	strcpy (drvui->LoadOnStartup, "maybe");
1489     }
1490 
1491     sscanf (drvui->DefaultFinish, "%*s %f %f %f %f",
1492 	    &drvui->ambient, &drvui->diffuse, &drvui->specular, &drvui->roughness);
1493 
1494     if (!strncmp (autolabel, "autolabel", 9))
1495 	drvui->autolabel = 1;
1496     else
1497 	drvui->autolabel = 0;
1498     if (strlen (stereo) > 1) {
1499 	sscanf (stereo, "%d %d %f", &drvui->Stereo, &drvui->cross_eyed,
1500 		&drvui->stereo_base);
1501     }
1502     if (strlen (temp) > 10) {
1503 	sscanf (temp, "povray %d vrml %d asy %d", &doPOV, &doVrml, &doAsy);
1504     } else {
1505 	doPOV = doVrml = doAsy = 1;
1506     }
1507     WriteConfig ();
1508 }
1509 
1510 void
1511 Max_Min_cb (void)
1512 {
1513 // callback routine to readout Max - Min spinners
1514     static int in_progress;
1515 
1516     if (in_progress) {
1517 #ifndef WIN32
1518 	fprintf (stderr, "calculation already in progress\n");
1519 #endif
1520 	return;
1521     }
1522     in_progress = 1;
1523     int frame = atoi (drvui->Frame_No->value ());
1524 
1525     if (!frame)
1526 	frame = 1;
1527     Omit->nomits = 0;
1528     xmin = drvui->X_Min->value ();
1529     drvui->frames[frame].cryst_lim[0] = (float) xmin;
1530     xmax = drvui->X_Max->value ();
1531     drvui->frames[frame].cryst_lim[3] = (float) xmax;
1532     ymin = drvui->Y_Min->value ();
1533     drvui->frames[frame].cryst_lim[1] = (float) ymin;
1534     ymax = drvui->Y_Max->value ();
1535     drvui->frames[frame].cryst_lim[4] = (float) ymax;
1536     zmin = drvui->Z_Min->value ();
1537     drvui->frames[frame].cryst_lim[2] = (float) zmin;
1538     zmax = drvui->Z_Max->value ();
1539     drvui->frames[frame].cryst_lim[5] = (float) zmax;
1540     if (drvui->Use_Clipping->value () != 0) {	// test check button
1541 	clipflag = 1;		// check button set
1542 	// save spinner widget values
1543 	drvui->frames[frame].clip_lim[0] =
1544 	    (float) max (drvui->X_Min_clip->value (), drvui->X_Min->value ());
1545 	// MUST be within the min-max range
1546 	drvui->frames[frame].clip_lim[0] =
1547 	    (float) min (drvui->frames[frame].clip_lim[0], drvui->X_Max->value ());
1548 	drvui->frames[frame].clip_lim[1] =
1549 	    (float) max (drvui->Y_Min_clip->value (), drvui->Y_Min->value ());
1550 	drvui->frames[frame].clip_lim[1] =
1551 	    (float) min (drvui->frames[frame].clip_lim[1], drvui->Y_Max->value ());
1552 	drvui->frames[frame].clip_lim[2] =
1553 	    (float) max (drvui->Z_Min_clip->value (), drvui->Z_Min->value ());
1554 	drvui->frames[frame].clip_lim[2] =
1555 	    (float) min (drvui->frames[frame].clip_lim[2], drvui->Z_Max->value ());
1556 	drvui->frames[frame].clip_lim[3] =
1557 	    (float) min (drvui->X_Max_clip->value (), drvui->X_Max->value ());
1558 	drvui->frames[frame].clip_lim[3] =
1559 	    (float) max (drvui->frames[frame].clip_lim[3], drvui->X_Min->value ());
1560 	drvui->frames[frame].clip_lim[4] =
1561 	    (float) min (drvui->Y_Max_clip->value (), drvui->Y_Max->value ());
1562 	drvui->frames[frame].clip_lim[4] =
1563 	    (float) max (drvui->frames[frame].clip_lim[4], drvui->Y_Min->value ());
1564 	drvui->frames[frame].clip_lim[5] =
1565 	    (float) min (drvui->Z_Max_clip->value (), drvui->Z_Max->value ());
1566 	drvui->frames[frame].clip_lim[5] =
1567 	    (float) max (drvui->frames[frame].clip_lim[5], drvui->Z_Min->value ());
1568 	drvui->X_Min_clip->value (drvui->frames[frame].clip_lim[0]);	// reload widgets with tested value
1569 	drvui->Y_Min_clip->value (drvui->frames[frame].clip_lim[1]);
1570 	drvui->Z_Min_clip->value (drvui->frames[frame].clip_lim[2]);
1571 	drvui->X_Max_clip->value (drvui->frames[frame].clip_lim[3]);
1572 	drvui->Y_Max_clip->value (drvui->frames[frame].clip_lim[4]);
1573 	drvui->Z_Max_clip->value (drvui->frames[frame].clip_lim[5]);
1574 
1575 	drvui->X_Min_clip->activate ();	// make widgets active
1576 	drvui->X_Max_clip->activate ();
1577 	drvui->Y_Min_clip->activate ();
1578 	drvui->Y_Max_clip->activate ();
1579 	drvui->Z_Min_clip->activate ();
1580 	drvui->Z_Max_clip->activate ();
1581     } else {
1582 	clipflag = 0;		// check button off - clipping disabled
1583 	drvui->X_Min_clip->deactivate ();	// deactivate widgets
1584 	drvui->X_Max_clip->deactivate ();
1585 	drvui->Y_Min_clip->deactivate ();
1586 	drvui->Y_Max_clip->deactivate ();
1587 	drvui->Z_Min_clip->deactivate ();
1588 	drvui->Z_Max_clip->deactivate ();
1589 #if 0
1590 	drvui->X_Min_clip->value (drvui->X_Min->value ());	//load widgets with min or max value
1591 	drvui->X_Max_clip->value (drvui->X_Max->value ());
1592 	drvui->Y_Min_clip->value (drvui->Y_Min->value ());
1593 	drvui->Y_Max_clip->value (drvui->Y_Max->value ());
1594 	drvui->Z_Min_clip->value (drvui->Z_Min->value ());
1595 	drvui->Z_Max_clip->value (drvui->Z_Max->value ());
1596 #endif
1597     }
1598     drvui->Str_File_Changed = 1;
1599     Update_Str (0);
1600     Generate_Drawing (0);
1601     Fl::redraw ();
1602     in_progress = 0;
1603 }
1604 
1605 void
1606 Offset_cb (void)
1607 {
1608 // callback routine when Origin values are changed
1609     const char *string;
1610 
1611     Omit->nomits = 0;
1612     drvui->Str_File_Changed = 1;
1613     string = drvui->Origin_X->value ();
1614     origin[0] = (float) atof (string);
1615     string = drvui->Origin_Y->value ();
1616     origin[1] = (float) atof (string);
1617     string = drvui->Origin_Z->value ();
1618     origin[2] = (float) atof (string);
1619     Update_Str (0);
1620     Generate_Drawing (0);
1621     Fl::redraw ();
1622 }
1623 
1624 int
1625 pick_box (int x, int y, int w, int h)
1626 {
1627     GLint viewport[4];
1628 
1629     int hits;
1630 
1631     float cpx, cpy, cpz;
1632 
1633     float m[16];
1634 
1635     extern void show_slab (void);
1636 
1637     float ratio = 1.0f * (float) w / (float) h;
1638 
1639     memset (selectBuf, 0, BUFSIZE);
1640     glSelectBuffer (BUFSIZE, selectBuf);
1641     glRenderMode (GL_SELECT);
1642 
1643     glMatrixMode (GL_PROJECTION);
1644     glPushMatrix ();
1645     glLoadIdentity ();
1646     glGetIntegerv (GL_VIEWPORT, viewport);
1647 
1648     gluPickMatrix (x, viewport[3] - y, 1, 1, viewport);
1649 
1650     if (M_cameras == 0) {
1651 	if (ratio <= 1.)
1652 	    glOrtho (-gl_size, gl_size, -gl_size / ratio, gl_size / ratio, -10000.,
1653 		     10000.);
1654 	else
1655 	    glOrtho (-gl_size * ratio, gl_size * ratio, -gl_size, gl_size, -10000.,
1656 		     10000.);
1657     } else {
1658 	gluPerspective (17, ratio, 0.01, 1000.);
1659     }
1660 
1661     glMatrixMode (GL_MODELVIEW);
1662 
1663     glTranslatef (drvui->Trans[0], drvui->Trans[1], drvui->Trans[2]);
1664 
1665     quaternion_to_rotmatrix (&Rotq, m);
1666 
1667     glMultMatrixf (m);
1668 
1669     cpx = (POV_Max[0] + POV_Min[0]) / 2.0f;
1670     cpy = (POV_Max[1] + POV_Min[1]) / 2.0f;
1671     cpz = (POV_Max[2] + POV_Min[2]) / 2.0f;
1672 
1673     glTranslatef (-cpx, -cpy, -cpz);
1674 
1675     glInitNames ();
1676     glPushName (~0);
1677 
1678     show_slab_ovl ();
1679 
1680     glMatrixMode (GL_PROJECTION);
1681     glMatrixMode (GL_MODELVIEW);
1682     glFlush ();
1683     glPopMatrix ();
1684     glFlush ();
1685     hits = glRenderMode (GL_RENDER);
1686     if (!hits)
1687 	return (0);
1688     else
1689 	hits = update_box (hits, selectBuf);
1690 
1691     return (hits);
1692 }
1693 
1694 void
1695 process_hits (int hits, GLuint buffer[])
1696 {
1697     int i;
1698 
1699     GLuint names, *ptr, minZ, *ptrNames = 0, numberOfNames;
1700 
1701     numberOfNames = 0;
1702 
1703     ptr = (GLuint *) buffer;
1704     minZ = 0xffffffff;
1705     for (i = 0; i < hits; i++) {
1706 	names = *ptr;
1707 	ptr++;
1708 	if (*ptr < minZ && *(ptr + 2) != (GLuint) - 1) {
1709 	    numberOfNames = names;
1710 	    minZ = *ptr;
1711 	    ptrNames = ptr + 2;
1712 	}
1713 	ptr += names + 2;
1714     }
1715     if (numberOfNames == 0)
1716 	return;
1717 
1718     ptr = ptrNames;
1719 
1720     Omit->omit1[Omit->nomits] = *ptr;
1721     ptr++;
1722     Omit->omit2[Omit->nomits++] = *ptr;
1723 
1724     if (Omit->nomits == 1 && edtprm) {
1725 	edtprm->ClearLastOmit->activate ();
1726 	edtprm->ClearOmit->activate ();
1727     }
1728     Generate_Drawing (1);	/* regenerate drawing */
1729 }
1730 
1731 void
1732 Process_Inp (int i)
1733 {
1734 // routine to process the DRAWxtl input file
1735     char string[60];
1736 
1737     Init_DRAWxtl ();		// initialize variables
1738     drvui->CurDir->value (drvui->Cur_Dir);
1739     if (strlen (drvui->Cur_File) < 2) {
1740 	drvui->X_Min->value (-0.1);
1741 	drvui->X_Max->value (1.1);
1742 	drvui->Y_Min->value (-0.1);
1743 	drvui->Y_Max->value (1.1);
1744 	drvui->Z_Min->value (-0.1);
1745 	drvui->Z_Max->value (1.1);
1746 	xmin = -.1;
1747 	xmax = 1.1;
1748 	ymin = -.1;
1749 	ymax = 1.1;
1750 	zmin = -.1;
1751 	zmax = 1.1;
1752 	drvui->X_Origin = 0.5;
1753 	drvui->Y_Origin = 0.5;
1754 	drvui->Z_Origin = 0.5;
1755 	drvui->X_Boxlim = 10.;
1756 	drvui->Y_Boxlim = 10.;
1757 	drvui->Z_Boxlim = 10.;
1758 	drvui->Origin_X->value ("0.5");
1759 	drvui->Origin_Y->value ("0.5");
1760 	drvui->Origin_Z->value ("0.5");
1761 	return;
1762     }
1763     memset (string, 0, 60);
1764     strcpy (string, drvui->Cur_File);
1765     if (string[strlen (string) - 1] == '_')
1766 	string[strlen (string) - 1] = 0;
1767     drvui->CurFile->value (string);
1768 
1769     _chdir (drvui->Cur_Dir);
1770 
1771     drvui->fpin = fopen (drvui->Cur_File, "r");	// open 'str' file
1772     if (!drvui->fpin) {
1773 	Error_Box ("Cannot open structure file !");
1774 	strcpy (drvui->Cur_Temp, "");
1775 	drvui->X_Min->value (-0.1);
1776 	drvui->X_Max->value (1.1);
1777 	drvui->Y_Min->value (-0.1);
1778 	drvui->Y_Max->value (1.1);
1779 	drvui->Z_Min->value (-0.1);
1780 	drvui->Z_Max->value (1.1);
1781 	xmin = -.1;
1782 	xmax = 1.1;
1783 	ymin = -.1;
1784 	ymax = 1.1;
1785 	zmin = -.1;
1786 	zmax = 1.1;
1787 	drvui->X_Origin = 0.5;
1788 	drvui->Y_Origin = 0.5;
1789 	drvui->Z_Origin = 0.5;
1790 	drvui->X_Boxlim = 10.;
1791 	drvui->Y_Boxlim = 10.;
1792 	drvui->Z_Boxlim = 10.;
1793 	drvui->Origin_X->value ("0.5");
1794 	drvui->Origin_Y->value ("0.5");
1795 	drvui->Origin_Z->value ("0.5");
1796 
1797 	return;
1798     } else {
1799 	drvui->frame_no = 1;
1800 	while (1) {
1801 	    read_inp (i);	// read the 'str' file
1802 	    make_bmat (drvui->sys, drvui->lat_con, drvui->b_mat, drvui->ginv, drvui->rec_lat_con);	/* create the lattice metric */
1803 	    rewind (drvui->fpin);
1804 	    drvui->frame_no++;
1805 	    if (drvui->frame_no > drvui->max_frame)
1806 		break;
1807 	}
1808 	drvui->frame_no = drvui->max_frame;
1809 	fclose (drvui->fpin);	// close str file
1810 	strcpy (drvui->Cur_Listing, drvui->Cur_File);
1811 	trim_string (drvui->Cur_Listing, 256);
1812 	int j;
1813 
1814 	for (j = strlen (drvui->Cur_Listing); j > 0; --j) {
1815 	    if (drvui->Cur_Listing[j] == '.') {
1816 		drvui->Cur_Listing[j] = 0;
1817 		break;
1818 	    }
1819 	}
1820 	strcpy (drvui->Cur_Root, drvui->Cur_Listing);
1821 	strcpy (drvui->Cur_Console, drvui->Cur_Listing);
1822 	strcpy (drvui->Cur_Temp, drvui->Cur_Listing);
1823 	strcat (drvui->Cur_Listing, ".out");
1824 	strcat (drvui->Cur_Console, ".cns");
1825 	strcat (drvui->Cur_Temp, ".tmp");
1826 	Fl_Text_Buffer *atextbuf = new Fl_Text_Buffer;
1827 
1828 	atextbuf->loadfile (drvui->Cur_File);	// get text of str file
1829 	if ( atextbuf->savefile (drvui->Cur_Temp)) {	// output it to temp file
1830 	    Error_Box("Unable to create temporary str file - disk full or directory not writable");
1831 
1832             char *newfile =
1833 		fl_file_chooser ("Please save this file in a writable directory", "*.str",
1834 				drvui->Cur_File);
1835 	    if (newfile) {
1836 		atextbuf->savefile(newfile);
1837 
1838 #if defined(WIN32)
1839 		char drive[_MAX_DRIVE];
1840 
1841 		char dir[_MAX_DIR];
1842 
1843 		char fname[_MAX_FNAME];
1844 
1845 		char ext[_MAX_EXT];
1846 
1847 		_splitpath (newfile, drive, dir, fname, ext);       //Windows code
1848 		strcpy (drvui->Cur_Dir, drive);     // Drive letter
1849 		strcat (drvui->Cur_Dir, dir);       //   and directory
1850 		strcpy (drvui->Cur_File, fname);    // copy file name
1851 		strcat (drvui->Cur_File, ext);      // and add extension
1852 #else
1853 		strcpy(drvui->Cur_File,newfile);
1854 		strcpy (drvui->Cur_Dir,drvui->Cur_Listing);
1855 		for (j = strlen (drvui->Cur_Dir); j > 0; --j) {
1856 		    if (drvui->Cur_Dir[j] == '/') {
1857 			drvui->Cur_Dir[j] = 0;
1858 			break;
1859 		    }
1860 		}
1861 #endif
1862 
1863 		strcpy (drvui->Cur_Listing, drvui->Cur_File);
1864 		trim_string (drvui->Cur_Listing, 256);
1865 		int j;
1866 
1867 		for (j = strlen (drvui->Cur_Listing); j > 0; --j) {
1868 		    if (drvui->Cur_Listing[j] == '.') {
1869 			drvui->Cur_Listing[j] = 0;
1870 			break;
1871 		    }
1872 		}
1873 		strcpy (drvui->Cur_Root, drvui->Cur_Listing);
1874 		strcpy (drvui->Cur_Console, drvui->Cur_Listing);
1875 		strcpy (drvui->Cur_Temp, drvui->Cur_Listing);
1876 		strcat (drvui->Cur_Listing, ".out");
1877 		strcat (drvui->Cur_Console, ".cns");
1878 		strcat (drvui->Cur_Temp, ".tmp");
1879 		atextbuf->savefile(drvui->Cur_Temp);
1880 		drvui->CurFile->value (drvui->Cur_File);
1881 		drvui->CurDir->value (drvui->Cur_Dir);
1882 	    }
1883 	}
1884 	delete (atextbuf);	// free the buffer
1885     }
1886     int frame = atoi (drvui->Frame_No->value ());
1887 
1888     if (frame == 0)
1889 	frame = 1;
1890 /* set limits of search regions */
1891     if (packflag == 0 && boxflag == 0) {	/* neither given */
1892 	drvui->frames[frame].cryst_lim[0] = origin[0] - 0.5f;
1893 	drvui->frames[frame].cryst_lim[1] = origin[1] - 0.5f;
1894 	drvui->frames[frame].cryst_lim[2] = origin[2] - 0.5f;	/* set to generate one cell */
1895 	drvui->frames[frame].cryst_lim[3] = origin[0] + 0.5f;
1896 	drvui->frames[frame].cryst_lim[4] = origin[1] + 0.5f;
1897 	drvui->frames[frame].cryst_lim[5] = origin[2] + 0.5f;
1898 	packflag = 1;
1899     }
1900     xmin = drvui->frames[frame].cryst_lim[0];	// transfer DRAWxtl variables to widgets
1901     drvui->X_Min->value (xmin);
1902     xmax = drvui->frames[frame].cryst_lim[3];
1903     drvui->X_Max->value (xmax);
1904     ymin = drvui->frames[frame].cryst_lim[1];
1905     drvui->Y_Min->value (ymin);
1906     ymax = drvui->frames[frame].cryst_lim[4];
1907     drvui->Y_Max->value (ymax);
1908     zmin = drvui->frames[frame].cryst_lim[2];
1909     drvui->Z_Min->value (zmin);
1910     zmax = drvui->frames[frame].cryst_lim[5];
1911     drvui->Z_Max->value (zmax);
1912     if (clipflag == 1) {	// clip active - load clip widgets
1913 	drvui->Use_Clipping->value (1);
1914 	drvui->X_Min_clip->value (drvui->frames[frame].clip_lim[0]);
1915 	drvui->Y_Min_clip->value (drvui->frames[frame].clip_lim[1]);
1916 	drvui->Z_Min_clip->value (drvui->frames[frame].clip_lim[2]);
1917 	drvui->X_Max_clip->value (drvui->frames[frame].clip_lim[3]);
1918 	drvui->Y_Max_clip->value (drvui->frames[frame].clip_lim[4]);
1919 	drvui->Z_Max_clip->value (drvui->frames[frame].clip_lim[5]);
1920 
1921 	drvui->X_Min_clip->activate ();	// activate them
1922 	drvui->X_Max_clip->activate ();
1923 	drvui->Y_Min_clip->activate ();
1924 	drvui->Y_Max_clip->activate ();
1925 	drvui->Z_Min_clip->activate ();
1926 	drvui->Z_Max_clip->activate ();
1927     } else {			// no clipping - load widgets with min and max values
1928 	drvui->Use_Clipping->value (0);	//  and deactivate them
1929 	drvui->X_Min_clip->deactivate ();
1930 	drvui->X_Max_clip->deactivate ();
1931 	drvui->Y_Min_clip->deactivate ();
1932 	drvui->Y_Max_clip->deactivate ();
1933 	drvui->Z_Min_clip->deactivate ();
1934 	drvui->Z_Max_clip->deactivate ();
1935 	drvui->X_Min_clip->value (drvui->X_Min->value ());
1936 	drvui->X_Max_clip->value (drvui->X_Max->value ());
1937 	drvui->Y_Min_clip->value (drvui->Y_Min->value ());
1938 	drvui->Y_Max_clip->value (drvui->Y_Max->value ());
1939 	drvui->Z_Min_clip->value (drvui->Z_Min->value ());
1940 	drvui->Z_Max_clip->value (drvui->Z_Max->value ());
1941     }
1942     Xrot = xrot;
1943     sprintf (string, "%6.2f", Xrot);
1944     drvui->X_Rot->value (string);
1945     sprintf (string, "%6.2f", Yrot);
1946     Yrot = yrot;
1947     drvui->Y_Rot->value (string);
1948     Zrot = zrot;
1949     sprintf (string, "%6.2f", Zrot);
1950     drvui->Z_Rot->value (string);
1951     sprintf (string, "%6.2f", origin[0]);
1952     drvui->Origin_X->value (string);
1953     sprintf (string, "%6.2f", origin[1]);
1954     drvui->Origin_Y->value (string);
1955     sprintf (string, "%6.2f", origin[2]);
1956     drvui->Origin_Z->value (string);
1957     if (!Vrml2)
1958 	drvui->Generate_VRML1->set ();	// VRML1 checkbox is set
1959     else
1960 	drvui->Generate_VRML1->clear ();
1961     if (!doVrml)
1962 	drvui->Generate_VRML1->deactivate ();
1963     if (!doPOV)
1964 	DRAWxtlViewUI::drawxtl_menu[39].deactivate ();
1965     if (!M_cameras)
1966 	drvui->Orthographic_View->set ();	// orthographic view checkbox set
1967     else
1968 	drvui->Orthographic_View->clear ();
1969     if (Display_axes)
1970 	drvui->Show_Vector_Triple->set ();	// Show vector triple checkbox set
1971     else
1972 	drvui->Show_Vector_Triple->clear ();
1973 
1974     Update_Str (0);
1975 }
1976 
1977 void
1978 Progress_Window (int type, const char *label, float max)
1979 {
1980 
1981 // Routine to handle a progress bar. The first argument defines the type of call
1982 //      type == -1, open a window. The second argument gives the label, 3rd the maximum.
1983 //      type == -2, close the window. 2nd and 3rd arguments ignored.
1984 //      type == 0, 3rd argument contains progress argument. 2nd ignored.
1985 
1986     static Fl_Window *prog_window;
1987 
1988     static Fl_Progress *prog_bar;
1989 
1990     switch (type) {
1991 
1992     case -1:
1993 	prog_window = new Fl_Window (400, 300, 250, 50, "Please Wait");
1994 	prog_window->begin ();
1995 	prog_bar = new Fl_Progress (20, 10, 200, 30, label);
1996 	prog_bar->minimum (0.0f);
1997 	prog_bar->maximum (max);
1998 #if !defined (WIN32) && !defined (__APPLE__)
1999 	prog_window->icon ((char *) drvui->icon);
2000 #endif
2001 	prog_window->end ();
2002 	prog_window->show ();
2003 	break;
2004     case -2:
2005 	prog_window->~Fl_Window ();
2006 	delete(prog_window);
2007 	break;
2008     default:
2009 	prog_bar->value (max);
2010     }
2011     Fl::check ();
2012 }
2013 
2014 void
2015 Restore_Working_Copy (void)
2016 {
2017 // restore working str file from saved version
2018     Fl_Text_Buffer *text = new Fl_Text_Buffer;
2019 
2020     char savefile[256];
2021 
2022     strcpy (savefile, drvui->Cur_Root);
2023     strcat (savefile, ".save");
2024     text->loadfile (savefile);
2025     text->savefile (drvui->Cur_Temp);
2026     delete (text);
2027 }
2028 
2029 void
2030 Rotation_cb (void)
2031 {
2032 // callback routine to readout Rotation widgets
2033     Xrot = atof (drvui->X_Rot->value ());
2034     Xrot = AngleInRange (Xrot);
2035     xrot = (float) Xrot;
2036     Yrot = atof (drvui->Y_Rot->value ());
2037     Yrot = AngleInRange (Yrot);
2038     yrot = (float) Yrot;
2039     Zrot = atof (drvui->Z_Rot->value ());
2040     Zrot = AngleInRange (Zrot);
2041     zrot = (float) Zrot;
2042     Update_Str (0);
2043     Rotq = XYZ_Rot_to_Q (Xrot, Yrot, Zrot);
2044     Fl::redraw ();
2045 }
2046 
2047 void
2048 Save_Current_cb (void)
2049 {
2050 // callback routine to save the current .str and .pov under a new name
2051     char oldpovfile[1024], newpovfile[1024];
2052 
2053     char old_dir[1024], old_file[1024], new_file[1024];
2054 
2055     int old_state;
2056 
2057 #if defined(WIN32)
2058     char drive[_MAX_DRIVE];
2059 
2060     char dir[_MAX_DIR];
2061 
2062     char fname[_MAX_FNAME];
2063 
2064     char ext[_MAX_EXT];
2065 
2066     const char *newfile;
2067 #else
2068     int i;
2069 
2070     char *newfile;
2071 #endif
2072 
2073     if (!strlen (drvui->CurDir->value ())) {	// Make sure rendering enabled
2074 	Error_Box ("A Structure File must be selected first.");
2075 	return;
2076     }
2077     strcpy (old_dir, drvui->Cur_Dir);
2078     strcpy (old_file, drvui->Cur_File);
2079     strcpy (oldpovfile, drvui->Cur_Root);
2080     strcat (oldpovfile, ".pov");
2081 
2082 #if defined(WIN32)
2083     newfile = flu_file_chooser ("Select New Name for Current .STR/.POV Files",
2084 				"*", drvui->Cur_Dir);
2085     if (newfile) {
2086 	_splitpath (newfile, drive, dir, fname, ext);	//Windows code
2087 	strcpy (drvui->Cur_Dir, drive);	// Drive letter
2088 	strcat (drvui->Cur_Dir, dir);	//   and directory
2089 	strcpy (drvui->Cur_File, fname);	// copy file name
2090     } else
2091 	return;
2092 #else
2093     newfile =
2094 	fl_file_chooser ("Select New Name for Current .STR/.POV Files", "*",
2095 			 drvui->Cur_Dir);
2096     if (newfile) {
2097 	strcpy (drvui->Cur_File, newfile);
2098 	strcpy (drvui->Cur_Dir, newfile);
2099 	for (i = strlen (drvui->Cur_Dir); i > 0; --i) {	// Find final / in file name
2100 	    if (drvui->Cur_Dir[i - 1] == '/') {
2101 		drvui->Cur_Dir[i] = 0;
2102 		break;
2103 	    }
2104 	}
2105 	for (i = strlen (drvui->Cur_File); i > 0; --i) {	// find final . in file name
2106 	    if (drvui->Cur_File[i - 1] == '.') {
2107 		drvui->Cur_File[i - 1] = 0;
2108 		break;
2109 	    }
2110 	}
2111     } else
2112 	return;
2113 #endif
2114 
2115     strcpy (newpovfile, drvui->Cur_File);
2116     strcat (newpovfile, ".pov");
2117     rename (oldpovfile, newpovfile);
2118 
2119     strcpy (new_file, drvui->Cur_File);
2120     strcat (new_file, ".str");
2121     strcpy (drvui->Cur_File, new_file);
2122     old_state = drvui->Str_File_Changed;
2123     Update_Str (1);
2124     drvui->Str_File_Changed = old_state;
2125     strcpy (drvui->Cur_File, old_file);
2126     strcpy (drvui->Cur_Dir, old_dir);
2127 }
2128 
2129 void
2130 Save_Working_Copy (void)
2131 {
2132 // copy working version of str file into a "save" file
2133     Fl_Text_Buffer *text = new Fl_Text_Buffer;
2134 
2135     char savefile[256];
2136 
2137     strcpy (savefile, drvui->Cur_Root);
2138     strcat (savefile, ".save");
2139     text->loadfile (drvui->Cur_Temp);
2140     text->savefile (savefile);
2141     delete (text);
2142 }
2143 
2144 void
2145 SelectDataFile_cb (void)
2146 {
2147 // Callback routine to select the data file
2148     int r, i;
2149 
2150     FILE *inp;
2151 
2152     static int one = 1;
2153 
2154     if (strlen (drvui->Cur_File) && drvui->Str_File_Changed) {
2155 	r = fl_choice ("The current str file has not been saved.\n"
2156 		       "What action should be taken?", "Cancel", "Save", "Discard");
2157 	if (!r)
2158 	    return;
2159 	if (r == 1)
2160 	    Update_Str (1);
2161     }
2162 
2163     drvui->Str_File_Changed = 0;
2164 
2165 #if defined(WIN32)
2166     char drive[_MAX_DRIVE];
2167 
2168     char dir[_MAX_DIR];
2169 
2170     char fname[_MAX_FNAME];
2171 
2172     char ext[_MAX_EXT];
2173 
2174     const char *newfile = flu_file_chooser ("Select Data/Experiment File",
2175 					    "*.str", drvui->Cur_File);
2176 
2177     if (newfile) {
2178 	_splitpath (newfile, drive, dir, fname, ext);	//Windows code
2179 	strcpy (drvui->Cur_Dir, drive);	// Drive letter
2180 	strcat (drvui->Cur_Dir, dir);	//   and directory
2181 	strcpy (drvui->Cur_File, fname);	// copy file name
2182 	strcat (drvui->Cur_File, ext);	// and add extension
2183 #else
2184     int k = 0;
2185 
2186     char *newfile =
2187 	fl_file_chooser ("Select Data/Experiment File", "*.str", drvui->Cur_File);
2188     if (newfile) {
2189 	strcpy (drvui->Cur_File, newfile);
2190 	strcpy (drvui->Cur_Dir, newfile);
2191 	for (i = strlen (drvui->Cur_Dir); i > 0; --i) {	// Find final / in file name
2192 	    if (drvui->Cur_Dir[i - 1] == '/') {
2193 		drvui->Cur_Dir[i] = 0;
2194 		break;
2195 	    }
2196 	}
2197 	for (i = strlen (drvui->Cur_Dir); newfile[i] != 0; i++) {
2198 	    drvui->Cur_File[k++] = newfile[i];	// copy file name to Cur_File
2199 	}
2200 	drvui->Cur_File[k] = 0;
2201 #endif
2202 
2203 	Clean_Up_Files ();	// get rid of the temporary files
2204 	Destroy_Open_Windows ();
2205 
2206 	if (FourierPt) {
2207 	    free (FourierPt);
2208 	    FourierPt = NULL;
2209 	}
2210 	for (i = 0; i < 4; i++) {
2211 	    cur_atom[i] = 0;
2212 	    strcpy (cur_name[i], "");
2213 	}
2214 	cur_show = 0;
2215 	ReadFourMap = 0;
2216 	strcpy (FourierFileName, "");
2217 	drvui->Cursor_pos->value ("");
2218 	drvui->labels_inited = 0;	// make sure the labels get reinited
2219 
2220 	chdir (drvui->Cur_Dir);	// switch to that directory
2221 	WriteConfig ();		// update configuration file
2222 	drvui->CurFile->value (drvui->Cur_File);	// update main screen widgets
2223 	drvui->CurDir->value (drvui->Cur_Dir);
2224 	if (!(inp = fopen (drvui->Cur_File, "r"))) {
2225 	    char string[256];
2226 
2227 	    sprintf (string, "The file you selected ('%s') cannot be read\n"
2228 		     "Do you wish to continue?", drvui->Cur_File);
2229 	    if (fl_choice (string, "No", "Yes", NULL)) {
2230 		inp = fopen (drvui->Cur_File, "w");
2231 		fclose (inp);
2232 		Edit_STR_cb (NULL, &one);
2233 	    }
2234 	} else {
2235 	    fclose (inp);
2236 	}
2237 	vzero (drvui->Trans);
2238 	drvui->origin1_flag = 0;
2239 	gl_size = 0.0f;
2240 	Process_Inp (2);
2241 	Rotq = XYZ_Rot_to_Q (Xrot, Yrot, Zrot);
2242 	Add_Frame_Main ();
2243 	Fl::flush ();
2244 	Generate_Drawing (0);	// generate this structure
2245 	Fl::redraw ();		//  and draw it
2246     }
2247 }
2248 
2249 void
2250 show_slab_ovl (void)
2251 {
2252     glPushMatrix ();
2253 
2254     glDisable (GL_LIGHTING);
2255     glLineWidth (3);
2256     glColor3f (0., 1., 0.);
2257     glBegin (GL_LINES);
2258 
2259     glVertex3f (slabx1, slaby1, slabz1);
2260     glVertex3f (slabx2, slaby2, slabz2);
2261 
2262     glVertex3f (slabx3, slaby3, slabz3);
2263     glVertex3f (slabx1, slaby1, slabz1);
2264 
2265     glVertex3f (slabx3, slaby3, slabz3);
2266     glVertex3f (slabx2 + (slabx3 - slabx1), slaby2 + (slaby3 - slaby1),
2267 		slabz2 + (slabz3 - slabz1));
2268 
2269     glVertex3f (slabx2, slaby2, slabz2);
2270     glVertex3f (slabx2 + (slabx3 - slabx1), slaby2 + (slaby3 - slaby1),
2271 		slabz2 + (slabz3 - slabz1));
2272 
2273     glVertex3f (slabx1, slaby1, slabz1);
2274     glVertex3f (slabx4, slaby4, slabz4);
2275 
2276 
2277     glVertex3f (slabx3, slaby3, slabz3);
2278     glVertex3f (slabx3 + (slabx4 - slabx1), slaby3 + (slaby4 - slaby1),
2279 		slabz3 + (slabz4 - slabz1));
2280 
2281     glVertex3f (slabx4, slaby4, slabz4);
2282     glVertex3f (slabx3 + (slabx4 - slabx1), slaby3 + (slaby4 - slaby1),
2283 		slabz3 + (slabz4 - slabz1));
2284 
2285     glVertex3f (slabx2, slaby2, slabz2);
2286     glVertex3f (slabx2 + (slabx4 - slabx1), slaby2 + (slaby4 - slaby1),
2287 		slabz2 + (slabz4 - slabz1));
2288 
2289 
2290     glVertex3f (slabx2 + (slabx4 - slabx1), slaby2 + (slaby4 - slaby1),
2291 		slabz2 + (slabz4 - slabz1));
2292     glVertex3f (slabx4, slaby4, slabz4);
2293 
2294     glVertex3f (slabx2 + (slabx4 - slabx1), slaby2 + (slaby4 - slaby1),
2295 		slabz2 + (slabz4 - slabz1));
2296     glVertex3f (slabx2 + (slabx4 - slabx1) + slabx3 - slabx1,
2297 		slaby2 + (slaby4 - slaby1) + slaby3 - slaby1,
2298 		slabz2 + (slabz4 - slabz1) + slabz3 - slabz1);
2299 
2300 
2301     glVertex3f (slabx3 + (slabx4 - slabx1), slaby3 + (slaby4 - slaby1),
2302 		slabz3 + (slabz4 - slabz1));
2303     glVertex3f (slabx2 + (slabx4 - slabx1) + slabx3 - slabx1,
2304 		slaby2 + (slaby4 - slaby1) + slaby3 - slaby1,
2305 		slabz2 + (slabz4 - slabz1) + slabz3 - slabz1);
2306 
2307     glVertex3f (slabx2 + (slabx3 - slabx1), slaby2 + (slaby3 - slaby1),
2308 		slabz2 + (slabz3 - slabz1));
2309     glVertex3f (slabx2 + (slabx4 - slabx1) + slabx3 - slabx1,
2310 		slaby2 + (slaby4 - slaby1) + slaby3 - slaby1,
2311 		slabz2 + (slabz4 - slabz1) + slabz3 - slabz1);
2312     glEnd ();
2313     glPushMatrix ();
2314     glLoadName (1);
2315     glTranslatef (slabx1, slaby1, slabz1);
2316     glutSolidCube (0.004 * Scale);
2317     glPopMatrix ();
2318     glPushMatrix ();
2319     glLoadName (2);
2320     glTranslatef (slabx2, slaby2, slabz2);
2321     glutSolidCube (0.004 * Scale);
2322     glPopMatrix ();
2323     glPushMatrix ();
2324     glLoadName (3);
2325     glTranslatef (slabx3, slaby3, slabz3);
2326     glutSolidCube (0.004 * Scale);
2327     glPopMatrix ();
2328     glPushMatrix ();
2329     glLoadName (4);
2330     glTranslatef (slabx4, slaby4, slabz4);
2331     glutSolidCube (0.004 * Scale);
2332     glPopMatrix ();
2333 
2334     glEnable (GL_LIGHTING);
2335     glPopMatrix ();
2336     glLineWidth (1);
2337 }
2338 
2339 void
2340 start_picking (int x, int y, int w, int h)
2341 {
2342     GLint viewport[4];
2343 
2344     int hits;
2345 
2346     float cpx, cpy, cpz;
2347 
2348     float m[16];
2349 
2350     int n, i;
2351 
2352     float ratio = 1.0f * (float) w / (float) h;
2353 
2354     memset (selectBuf, 0, BUFSIZE);
2355     glGetIntegerv (GL_VIEWPORT, viewport);
2356 
2357     glPushMatrix ();
2358     glSelectBuffer (BUFSIZE, selectBuf);
2359     glRenderMode (GL_SELECT);
2360     glMatrixMode (GL_PROJECTION);
2361     glLoadIdentity ();
2362 
2363     gluPickMatrix (x, viewport[3] - y, viewport[2] / 100, viewport[3] / 100, viewport);
2364 
2365     if (M_cameras == 0) {
2366 	if (w <= h)
2367 	    glOrtho (-gl_size, gl_size, -gl_size / ratio, gl_size / ratio, -10000.,
2368 		     10000.);
2369 	else
2370 	    glOrtho (-gl_size * ratio, gl_size * ratio, -gl_size, gl_size, -10000.,
2371 		     10000.);
2372     } else {
2373 	gluPerspective (17, ratio, 0.01, 1000.);	// view angle, aspect,near/far clip
2374     }
2375     glMatrixMode (GL_MODELVIEW);
2376     glLoadIdentity ();
2377 
2378     glInitNames ();
2379     glPushName (~0);
2380 
2381     cpx = (POV_Max[0] + POV_Min[0]) / 2.0f;
2382     cpy = (POV_Max[1] + POV_Min[1]) / 2.0f;
2383     cpz = (POV_Max[2] + POV_Min[2]) / 2.0f;
2384 
2385     gluLookAt (cpx, cpy, Scale * .50,   // camera position
2386                cpx, cpy, -1.0,          // camera lookat point
2387                0.0f, 1.0f, 0.0f);       // camera "up" vector
2388 
2389     glTranslatef (drvui->Trans[0], drvui->Trans[1], drvui->Trans[2]);
2390 
2391     quaternion_to_rotmatrix (&Rotq, m);
2392 
2393     glMultMatrixf (m);
2394 
2395     glCallList (drvui->crystalDL);
2396 
2397     glPopMatrix ();
2398 
2399     hits = glRenderMode (GL_RENDER);
2400     glFlush ();
2401 
2402     if (hits > 0) {
2403 	process_hits (hits, selectBuf);
2404     } else {
2405 	hits = pick_label (x, y, Fl::w (), Fl::h ());
2406 	if (hits > 0 && hits <= drvui->nlabel) {
2407 	    if (hits != drvui->triple[0] && hits != drvui->triple[1]
2408 		&& hits != drvui->triple[2] && hits != drvui->triple[3]) {
2409 		for (n = hits; n < drvui->nlabel; n++) {	// remove label, but not a, b, c, or origin
2410 		    drvui->labels[n].label_fn = drvui->labels[n + 1].label_fn;
2411 		    strcpy (drvui->labels[n].label_label,
2412 			    drvui->labels[n + 1].label_label);
2413 		    for (i = 0; i < 3; i++)
2414 			drvui->labels[n].label_x[i] = drvui->labels[n + 1].label_x[i];
2415 		    for (i = 0; i < 4; i++)
2416 			if (drvui->triple[i] == n + 1)
2417 			    drvui->triple[i] = n;
2418 		}
2419 		drvui->nlabel--;
2420 	    }
2421 	    Update_Str (0);
2422 	}
2423     }
2424 
2425     Fl::redraw ();
2426 
2427 }
2428 
2429 int
2430 update_box (int hits, GLuint buffer[])
2431 {
2432     int i, j;
2433 
2434     GLuint names, *ptr, minZ, *ptrNames = 0, numberOfNames;
2435 
2436     numberOfNames = 0;
2437     j = 0;
2438 
2439     ptr = (GLuint *) buffer;
2440     minZ = 0xffffffff;
2441     for (i = 0; i < hits; i++) {
2442 	names = *ptr;
2443 	ptr++;
2444 	if (*ptr < minZ && *(ptr + 2) != (GLuint) - 1) {
2445 	    numberOfNames = names;
2446 	    minZ = *ptr;
2447 	    ptrNames = ptr + 2;
2448 	}
2449 	ptr += names + 2;
2450     }
2451 
2452     if (numberOfNames == 0)
2453 	return 0;
2454 
2455     ptr = ptrNames;
2456     j = *ptr;
2457 
2458     return (j);
2459 }
2460 
2461 void
2462 Update_Objects (int Frame_No, FILE * out)
2463 {
2464 // Update the objects that belong to this frame
2465     int i;
2466 
2467     unsigned int j;
2468 
2469     char string[256];
2470 
2471 // add bond lines
2472     if (drvui->nbond > 1) {
2473 	for (i = 1; i < drvui->nbond; i++) {
2474 	    char atom1[5], atom2[5];
2475 
2476 	    if (drvui->bonds[i].bond_fn == Frame_No) {
2477 		strncpy (string, drvui->bonds[i].col_bond, 39);
2478 		string[39] = 0;
2479 		for (j = 0; j < strlen (string); j++)
2480 		    if (string[j] < ' ')
2481 			string[j] = 0;
2482 		strncpy (atom1, drvui->bonds[i].bond_l1, 4);
2483 		strncpy (atom2, drvui->bonds[i].bond_l2, 4);
2484 		atom1[4] = 0;
2485 		atom2[4] = 0;
2486 		if (drvui->bonds[i].bond_style == 0)
2487 		    fprintf (out, "bond %s %s %6.3f %6.3f %6.3f %s\n", atom1,
2488 			     atom2, drvui->bonds[i].bond_size, drvui->bonds[i].bond_min,
2489 			     drvui->bonds[i].bond_max, string);
2490 		else {
2491 		    if (drvui->bonds[i].bond_style != 5)
2492 			fprintf (out, "dash %d %s %s %6.3f %6.3f %6.3f %s\n",
2493 				 drvui->bonds[i].bond_style, atom1,
2494 				 atom2, drvui->bonds[i].bond_size,
2495 				 drvui->bonds[i].bond_min, drvui->bonds[i].bond_max,
2496 				 string);
2497 		    else
2498 			fprintf (out, "dash %s %s %6.3f %6.3f %6.3f %s\n", atom1,
2499 				 atom2, drvui->bonds[i].bond_size,
2500 				 drvui->bonds[i].bond_min, drvui->bonds[i].bond_max,
2501 				 string);
2502 		}
2503 	    }
2504 	}
2505     }
2506 // add sphere lines
2507     if (drvui->nsphere > 1) {
2508 	for (i = 1; i < drvui->nsphere; i++) {
2509 	    if (drvui->spheres[i].sphere_fn == Frame_No) {
2510 		if (drvui->spheres[i].sphere_n == -1) {
2511 		    fprintf (out, "sphere %s %6.3f %s\n", drvui->spheres[i].sphere_l,
2512 			     drvui->spheres[i].sphere_size, drvui->spheres[i].sphere_col);
2513 		} else {
2514 		    fprintf (out, "sphere %s %d %6.3f %s\n", drvui->spheres[i].sphere_l,
2515 			     drvui->spheres[i].sphere_n, drvui->spheres[i].sphere_size,
2516 			     drvui->spheres[i].sphere_col);
2517 		}
2518 	    }
2519 	}
2520     }
2521 // add magnetic arrow commands
2522     if (drvui->nmag > 0) {
2523 	for (i = 0; i < drvui->nmag; i++) {
2524 	    if (drvui->arrows[i].arrow_fn == Frame_No) {
2525 		fprintf (out,
2526 			 "arrow %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %s\n",
2527 			 drvui->arrows[i].mag_xp[0], drvui->arrows[i].mag_xp[1],
2528 			 drvui->arrows[i].mag_xp[2], drvui->arrows[i].mag_xc[0],
2529 			 drvui->arrows[i].mag_xc[1], drvui->arrows[i].mag_xc[2],
2530 			 drvui->arrows[i].arrow_length, drvui->arrows[i].arrow_diam,
2531 			 drvui->arrows[i].col_arrow);
2532 	    }
2533 	}
2534 // add magnetic transformation command
2535 	fprintf (out, "mag_trans %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
2536 		 drvui->mag_matrix[0][0], drvui->mag_matrix[0][1],
2537 		 drvui->mag_matrix[0][2], drvui->mag_matrix[1][0],
2538 		 drvui->mag_matrix[1][1], drvui->mag_matrix[1][2],
2539 		 drvui->mag_matrix[2][0], drvui->mag_matrix[2][1],
2540 		 drvui->mag_matrix[2][2]);
2541     }
2542 // add various types of polyhedra commands
2543     if (drvui->npoly > 1) {
2544 	for (i = 1; i < drvui->npoly; i++) {
2545 	    if (drvui->polyhedra[i].poly_fn == Frame_No) {
2546 		char atom1[5], atom2[5];
2547 
2548 		strncpy (string, drvui->polyhedra[i].poly_col, 39);
2549 		string[39] = 0;
2550 		for (j = 0; j < strlen (string); j++)
2551 		    if (string[j] < ' ')
2552 			string[j] = 0;
2553 		strncpy (atom2, drvui->polyhedra[i].poly_t, 4);
2554 		strncpy (atom1, drvui->polyhedra[i].poly_l, 4);
2555 		atom1[4] = 0;
2556 		atom2[4] = 0;
2557 		for (j = 0; j < strlen (atom1); j++)
2558 		    if (atom1[j] <= ' ')
2559 			atom1[j] = 0;
2560 		for (j = 0; j < strlen (atom2); j++)
2561 		    if (atom2[j] <= ' ')
2562 			atom2[j] = 0;
2563 		if (strlen (atom2)) {	// polyvert command if 'to' atom
2564 		    fprintf (out, "polyvert %s %s %6.3f %s\n", atom1,
2565 			     atom2, drvui->polyhedra[i].poly_size, string);
2566 		} else if (drvui->polyhedra[i].poly_min > 0.005) {	// shell command if minimum distance specified
2567 		    fprintf (out, "shell %s %6.3f %6.3f %s\n", atom1,
2568 			     drvui->polyhedra[i].poly_min, drvui->polyhedra[i].poly_size,
2569 			     string);
2570 		} else {	// polysz command
2571 		    fprintf (out, "polysz %s %6.3f %s\n", atom1,
2572 			     drvui->polyhedra[i].poly_size, string);
2573 		}
2574 	    }
2575 	}
2576 // add polyedge commands
2577 	for (i = 1; i < drvui->npoly; i++) {
2578 	    if (drvui->polyhedra[i].poly_fn == Frame_No) {
2579 		if (drvui->polyhedra[i].poly_rad_edge > 0.0f) {
2580 		    char atom1[5];
2581 
2582 		    strncpy (atom1, drvui->polyhedra[i].poly_l, 4);
2583 		    atom1[4] = 0;
2584 		    for (j = 0; j < strlen (atom1); j++)
2585 			if (atom1[j] <= ' ')
2586 			    atom1[j] = 0;
2587 		    fprintf (out, "polyedge %s %6.3f %s\n", atom1,
2588 			     drvui->polyhedra[i].poly_rad_edge,
2589 			     drvui->polyhedra[i].poly_col_edge);
2590 		}
2591 	    }
2592 	}
2593     }
2594 // add plane commands
2595     if (drvui->nplane > 1) {
2596 	for (i = 1; i < drvui->nplane; i++) {
2597 	    if (drvui->planes[i].plane_fn == Frame_No) {
2598 		char atom1[5];
2599 
2600 		strncpy (string, drvui->planes[i].plane_col, 39);
2601 		string[39] = 0;
2602 		for (j = 0; j < strlen (string); j++)
2603 		    if (string[j] < ' ')
2604 			string[j] = 0;
2605 		strncpy (atom1, drvui->planes[i].plane_l, 4);
2606 		atom1[4] = 0;
2607 		for (j = 0; j < strlen (atom1); j++)
2608 		    if (atom1[j] <= ' ')
2609 			atom1[j] = 0;
2610 		fprintf (out, "plane %s %6.3f %s\n", atom1, drvui->planes[i].plane_size,
2611 			 string);
2612 	    }
2613 	}
2614     }
2615 // add lonepair command(s)
2616     if (drvui->ncone > 1) {
2617 	for (i = 1; i < drvui->ncone; i++) {
2618 	    char atom[5];
2619 
2620 	    if (drvui->cones[i].cone_fn == Frame_No) {
2621 		strncpy (string, drvui->cones[i].col_cone, 39);
2622 		string[39] = 0;
2623 		for (j = 0; j < strlen (string); j++)
2624 		    if (string[j] < ' ')
2625 			string[j] = 0;
2626 		strncpy (atom, drvui->cones[i].cone_l1, 4);
2627 		atom[4] = 0;
2628 		for (j = 0; j < strlen (atom); j++)
2629 		    if (atom[j] <= ' ')
2630 			atom[j] = 0;
2631 		fprintf (out, "lonepair %s %d %6.3f %6.3f %6.3f %s\n", atom,
2632 			 drvui->cones[i].numlonepairs, drvui->cones[i].cone_height,
2633 			 drvui->cones[i].cone_min, drvui->cones[i].cone_max, string);
2634 	    }
2635 	}
2636     }
2637 // add labeltext command(s)
2638     if (drvui->nlabel > 1) {
2639 	for (i = 1; i < drvui->nlabel; i++) {
2640 	    if (drvui->labels[i].label_fn == Frame_No) {
2641 		if (!strcmp (drvui->labels[i].label_label, "triple_vect")) {
2642 		    fprintf (out, "vectors %.3f %.3f %.3f\n", offset[0], offset[1],
2643 			     offset[2]);
2644 		} else {
2645 		    fprintf (out, "labeltext %6.3f %6.3f %6.3f %s\n",
2646 			     drvui->labels[i].label_x[0], drvui->labels[i].label_x[1],
2647 			     drvui->labels[i].label_x[2], drvui->labels[i].label_label);
2648 		}
2649 	    }
2650 	}
2651     }
2652 // add pack commands for this frame
2653     if (packflag) {
2654 	fprintf (out, "pack %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",
2655 		 drvui->frames[Frame_No].cryst_lim[0],
2656 		 drvui->frames[Frame_No].cryst_lim[3],
2657 		 drvui->frames[Frame_No].cryst_lim[1],
2658 		 drvui->frames[Frame_No].cryst_lim[4],
2659 		 drvui->frames[Frame_No].cryst_lim[2],
2660 		 drvui->frames[Frame_No].cryst_lim[5]);
2661     }
2662 // add clip commands for this frame
2663     if (clipflag) {
2664 	fprintf (out, "clip %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",
2665 		 drvui->frames[Frame_No].clip_lim[0], drvui->frames[Frame_No].clip_lim[3],
2666 		 drvui->frames[Frame_No].clip_lim[1], drvui->frames[Frame_No].clip_lim[4],
2667 		 drvui->frames[Frame_No].clip_lim[2],
2668 		 drvui->frames[Frame_No].clip_lim[5]);
2669     }
2670     if (Map_Info.info_valid) {
2671 	if (drvui->modulated != 0)
2672 	    fprintf (out, "mapregion %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n",
2673 		     drvui->frames[Frame_No].map_lim[0], drvui->frames[Frame_No].map_lim[3],
2674 		     drvui->frames[Frame_No].map_lim[1], drvui->frames[Frame_No].map_lim[4],
2675 		     drvui->frames[Frame_No].map_lim[2], drvui->frames[Frame_No].map_lim[5],
2676 		     drvui->frames[Frame_No].map_lim[6], drvui->frames[Frame_No].map_lim[7],
2677 		     drvui->frames[Frame_No].map_lim[8]);
2678 	else
2679 	    fprintf (out, "mapregion %.4f %.4f %.4f %.4f %.4f %.4f\n",
2680 		     drvui->frames[Frame_No].map_lim[0], drvui->frames[Frame_No].map_lim[3],
2681 		     drvui->frames[Frame_No].map_lim[1], drvui->frames[Frame_No].map_lim[4],
2682 		     drvui->frames[Frame_No].map_lim[2], drvui->frames[Frame_No].map_lim[5]);
2683     	if (drvui->frames[Frame_No].slice >0)
2684 	    fprintf (out, "mapslice %.3f %.3f %.3f  %.3f %.3f %.3f  %d\n",
2685 		     drvui->frames[Frame_No].mapslice[0], drvui->frames[Frame_No].mapslice[1],
2686 		     drvui->frames[Frame_No].mapslice[2], drvui->frames[Frame_No].mapnorm[0],
2687 		     drvui->frames[Frame_No].mapnorm[1], drvui->frames[Frame_No].mapnorm[2],
2688 		     drvui->frames[Frame_No].slice);
2689     }
2690 
2691 // add atomic property value lines
2692     if (drvui->natprop > 1) {
2693 	for (i = 1; i < drvui->natprop; i++) {
2694 	    if (drvui->atprops[i].atprop_fn == Frame_No) {
2695 		if (drvui->atprops[i].atprop_n == -1) {
2696 		    fprintf (out, "values %s * %6.3f\n", drvui->atprops[i].atprop_l,
2697 			     drvui->atprops[i].radius);
2698 		} else {
2699 		    fprintf (out, "values %s %d %6.3f\n", drvui->atprops[i].atprop_l,
2700 			     drvui->atprops[i].atprop_n, drvui->atprops[i].radius);
2701 		}
2702 	    }
2703 	}
2704     }
2705 }
2706 
2707 void
2708 Update_Str (int overwrite)
2709 {
2710 // routine to update the tmp file with the new values from the widgets
2711 // if 'overwrite' is true, delete the str file and move (rename) the tmp file to str
2712     FILE *inp;
2713 
2714     FILE *out;
2715 
2716     char string[256];
2717 
2718     char temp_out[256];
2719 
2720     static const char *surftypes[3] = { "mesh", "solid", "dots"};
2721 
2722     int i;
2723 
2724     int Upd_magnification = 1;
2725 
2726     int Upd_depthcue = 1;
2727 
2728     int Upd_molcomp = 1;
2729 
2730     int Upd_ellipsoids = 1;
2731 
2732     int Upd_cutout = 1;
2733 
2734     int Upd_list = 1;
2735 
2736     int Upd_vrml = 1;
2737 
2738     int Upd_orthographic = 1;
2739 
2740     int Upd_axislines = 1;
2741 
2742     int Upd_box = 1;
2743 
2744     int Upd_edges = 1;
2745 
2746     int Upd_polytolerance = 1;
2747 
2748     int Upd_background = 1;
2749 
2750     int Frame_No;
2751 
2752     int Upd_finish = 1;
2753 
2754     int Upd_xyzoff = 1;
2755 
2756     int copy_end = 0;
2757 
2758     Frame_No = 1;
2759     inp = fopen (drvui->Cur_Temp, "r");	// open the existing file
2760     if (!inp)
2761 	return;
2762 
2763     strcpy (temp_out, drvui->Cur_Temp);
2764     strcat (temp_out, "a");
2765     if (!(out = fopen (temp_out, "w"))) {	// open a temp file
2766 	fclose (inp);
2767 	Error_Box ("Unable to open temporary file.");
2768 	return;
2769     }
2770     while (1) {
2771 	fgets (string, 256, inp);
2772 	trim_string (string, 256);
2773 	if (feof (inp) != 0)
2774 	    break;
2775 
2776 	/* see if we need to preserve the terminal END of an inlined dataset */
2777 	if (strstr (string, "inline") || strstr (string, "INLINE")) {
2778 	    if (strstr (string, "shelx")
2779 		|| strstr (string, "shakal")
2780 		|| strstr (string, "schakal"))
2781 		copy_end = 1;
2782 	    if (strstr (string, "SHELX")
2783 		|| strstr (string, "SHAKAL")
2784 		|| strstr (string, "SCHAKAL"))
2785 		copy_end = 1;
2786 	}
2787 	if (copy_end == 1) {	// for shelx data, hklf is as good as end
2788 	    if (strstr (string, "HKLF") || strstr (string, "hklf"))
2789 		copy_end = 0;
2790 	}
2791 	if (!strncmp (string, "end", 3) || !strncmp (string, "END", 3)) {
2792 	    if (copy_end == 0)
2793 		strcpy (string, "");
2794 	    else
2795 		copy_end = 0;
2796 	}
2797 	if (strncmp (string, "frame", 5) == 0) {
2798 	    Update_Objects (Frame_No, out);	// update stuff for this frame
2799 	    Frame_No++;
2800 	}
2801 //
2802 // update lines containing information contained in widgets
2803 //      magnification, depthcue, molcomp, ellipsoids, cutout, list, pack
2804 //      view, vrml, orthographic, vectors, axislines, box, edges
2805 //      phong, origin, polytolerance, background, clip, bond, special
2806 //      polysz, plane, polyvert, shell, sphere, lonepair, slab, noshadow
2807 //      arrow, mag_trans, ellipcolor, dash, phong, mapcontour, mapcontour2d,
2808 //      labeltext, mapread, mapregion, xyzoff, labelscale, import cif,
2809 //      lookat -> view
2810 
2811 	if (strncmp (string, "magnification", 13) == 0) {
2812 	    if (fabs (Magnification - 1.0) > 0.001) {
2813 		sprintf (string, "magnification %6.2f", Magnification);
2814 		Upd_magnification = 0;
2815 	    } else {
2816 		strcpy (string, "");
2817 	    }
2818 	}
2819 	if (strncmp (string, "depthcue", 8) == 0) {
2820 	    if (DepthCue > 0.001) {
2821 		sprintf (string, "depthcue %6.3f", DepthCue);
2822 		Upd_depthcue = 0;
2823 	    } else {
2824 		strcpy (string, "");
2825 	    }
2826 	}
2827 	if (strncmp (string, "molcomp", 7) == 0) {
2828 	    if (drvui->mol_d > 0.0f) {
2829 		sprintf (string, "molcomp %6.2f", drvui->mol_d);
2830 		Upd_molcomp = 0;
2831 	    } else
2832 		strcpy (string, "");
2833 	}
2834 	if (strncmp (string, "ellipsoids", 10) == 0) {
2835 	    if (drvui->do_ellipsoids)
2836 		sprintf (string, "ellipsoids %6.2f", drvui->Ellipsoid_Prob);
2837 	    else
2838 		strcpy (string, "");
2839 	    Upd_ellipsoids = 0;
2840 	}
2841 	if (strncmp (string, "cutout", 6) == 0) {
2842 	    if (strlen (drvui->Cutout_color) != 0) {
2843 		sprintf (string, "cutout %s", drvui->Cutout_color);
2844 		Upd_cutout = 0;
2845 	    } else
2846 		strcpy (string, "");
2847 	}
2848 	if (strncmp (string, "list", 4) == 0) {
2849 	    if (fabs (printdist - 3.5) > 0.001) {
2850 		sprintf (string, "list %6.2f", printdist);
2851 		Upd_list = 0;
2852 	    } else
2853 		strcpy (string, "");
2854 	}
2855 	if (strncmp (string, "pack", 4) == 0) {
2856 	    strcpy (string, "");
2857 	}
2858 	if (strncmp (string, "slab", 4) == 0) {
2859 	    strcpy (string, "");
2860 	}
2861 	if (strncmp (string, "view", 4) == 0) {
2862 	    strcpy (string, "");
2863 	}
2864 	if (strncmp (string, "vrml", 4) == 0) {
2865 	    Upd_vrml = 0;
2866 	    if (Vrml2 == 0)
2867 		sprintf (string, "vrml1");
2868 	    else
2869 		sprintf (string, "vrml97");
2870 	}
2871 	if (strncmp (string, "orthographic", 12) == 0) {
2872 	    if (M_cameras == 0) {
2873 		sprintf (string, "orthographic");
2874 		Upd_orthographic = 0;
2875 	    } else
2876 		strcpy (string, "");
2877 	}
2878 	if (strncmp (string, "vectors", 7) == 0) {
2879 	    strcpy (string, "");
2880 	}
2881 	if (strncmp (string, "polyedge", 8) == 0) {
2882 	    strcpy (string, "");
2883 	}
2884 	if (strncmp (string, "axislines", 9) == 0) {
2885 	    sprintf (string, "axislines %6.2f %s", drvui->Ellipaxis_width,
2886 		     drvui->Ellipaxis_color);
2887 	    Upd_axislines = 0;
2888 	}
2889 	if (strncmp (string, "box", 3) == 0) {
2890 	    sprintf (string, "box %6.3f %s", rad_cell, drvui->col_cell);
2891 	    Upd_box = 0;
2892 	}
2893 	if (strncmp (string, "edges", 5) == 0) {
2894 	    if (edges) {
2895 		sprintf (string, "edges %6.2f %s", drvui->rad_edge, drvui->col_edge);
2896 		Upd_edges = 0;
2897 	    } else
2898 		strcpy (string, "");
2899 	}
2900 	if (strncmp (string, "origin", 6) == 0)
2901 	    strcpy (string, "");
2902 	if (strncmp (string, "polytolerance", 13) == 0) {
2903 	    if (drvui->polylimit > 0.105) {
2904 		sprintf (string, "polytolerance %6.2f", drvui->polylimit);
2905 		Upd_polytolerance = 0;
2906 	    } else
2907 		strcpy (string, "");
2908 	}
2909 	if (strncmp (string, "background", 10) == 0) {
2910 	    sprintf (string, "background %s", drvui->col_bg);
2911 	    Upd_background = 0;
2912 	}
2913 	if (strncmp (string, "finish", 6) == 0) {
2914 	    sprintf (string, "finish %6.2f %6.2f %6.2f %6.2f", drvui->ambient,
2915 		     drvui->diffuse, drvui->specular, drvui->roughness);
2916 	    Upd_finish = 0;
2917 	}
2918 	if (strncmp (string, "clip", 4) == 0)
2919 	    strcpy (string, "");
2920 	if (strncmp (string, "bond", 4) == 0)
2921 	    strcpy (string, "");
2922 	if (strncmp (string, "dash", 4) == 0)
2923 	    strcpy (string, "");
2924 	if (strncmp (string, "special", 7) == 0)
2925 	    strcpy (string, "");
2926 	if (strncmp (string, "polysz", 6) == 0)
2927 	    strcpy (string, "");
2928 	if (strncmp (string, "plane", 5) == 0)
2929 	    strcpy (string, "");
2930 	if (strncmp (string, "polyvert", 8) == 0)
2931 	    strcpy (string, "");
2932 	if (strncmp (string, "shell", 5) == 0)
2933 	    strcpy (string, "");
2934 	if (strncmp (string, "sphere", 6) == 0)
2935 	    strcpy (string, "");
2936 	if (strncmp (string, "lonepair", 8) == 0)
2937 	    strcpy (string, "");
2938 	if (strncmp (string, "noshadow", 8) == 0)
2939 	    strcpy (string, "");
2940 	if (strncmp (string, "arrow", 5) == 0)
2941 	    strcpy (string, "");
2942 	if (strncmp (string, "mag_trans", 9) == 0)
2943 	    strcpy (string, "");
2944 	if (strncmp (string, "ellipcolor", 10) == 0)
2945 	    strcpy (string, "");
2946 	if (strncmp (string, "phong", 5) == 0)
2947 	    strcpy (string, "");
2948 	if (strncmp (string, "mapcontour", 10) == 0)
2949 	    strcpy (string, "");
2950 	if (strncmp (string, "labeltext", 9) == 0)
2951 	    strcpy (string, "");
2952 	if (strncmp (string, "mapread", 7) == 0)
2953 	    strcpy (string, "");
2954 	if (strncmp (string, "mapregion", 9) == 0)
2955 	    strcpy (string, "");
2956 	if (strncmp (string, "mapslice", 8) == 0)
2957 	    strcpy (string, "");
2958 	if (strncmp (string, "xyzoff", 6) == 0) {
2959 	    Upd_xyzoff = 0;
2960 	    drvui->origin1_flag = 0;
2961 	}
2962 	if (strncmp (string, "labelscale", 10) == 0) {
2963 	    strcpy (string, "");
2964 	}
2965 	if (strncmp (string, "lookat", 6) == 0) {
2966 	    strcpy (string, "");
2967 	}
2968 	if (strncmp (string, "nolabels", 8) == 0) {
2969 	    strcpy (string, "");
2970 	}
2971 	if (strncmp (string, "average", 7) == 0) {
2972 	    strcpy (string, "");
2973 	}
2974 	if (strncmp (string, "phaseshift", 10) == 0) {
2975 	    strcpy (string, "");
2976 	}
2977 	if (strncmp (string, "occupancy", 9) == 0) {
2978 	    strcpy (string, "");
2979 	}
2980 	if (strncmp (string, "aimsurf", 7) == 0) {
2981 	    strcpy (string, "");
2982 	}
2983 	if (strncmp (string, "voids", 5) == 0) {
2984 	    strcpy (string, "");
2985 	}
2986 	if (strncmp (string, "values", 6) == 0) {
2987 	    strcpy (string, "");
2988 	}
2989 	if (strncmp (string, "import", 6) == 0 && strstr (string, "cif")) {
2990 	    char string2[5];
2991 
2992 	    i = strlen (string) - 1;
2993 	    if (isdigit (string[i])) {	// if number at end
2994 		for (int j = i; j > i - 6; j--) {
2995 		    if (isspace (string[j])) {	// strip off number
2996 			string[j] = '\0';
2997 			break;
2998 		    }
2999 		    if (isalpha (string[j]))
3000 			break;	// unless it is attached to filename
3001 		}
3002 	    }
3003 	    sprintf (string2, " %d", Block_CIF);
3004 	    strcat (string, string2);	// add block number for CIF
3005 	}
3006 	if (strncmp (string, "rem xyzoff", 10) == 0)
3007 	    strcpy (string, "");
3008 	if (strncmp (string, "rem - following lines indicate", 30) == 0)
3009 	    strcpy (string, "");
3010 	if ((i = strlen (string)) > 0)
3011 	    if (string[i - 1] <= 13)
3012 		string[i - 1] = 0;
3013 	if ((i = strlen (string)) > 0) {
3014 	    if (string[i - 1] <= 13)
3015 		string[i - 1] = 0;
3016 	    fprintf (out, "%s\n", string);
3017 	}
3018     }
3019     fclose (inp);
3020     Update_Objects (Frame_No, out);	// update last frame stuff
3021 //
3022 // Add parameters that are or may be generated by widgets but NOT in input file
3023 //
3024     if (drvui->noshadow)
3025 	fprintf (out, "noshadow\n");
3026     if (Labels == 0)
3027 	fprintf (out, "nolabels\n");
3028     if (fabs (Magnification - 1.0) > 0.001 && Upd_magnification)
3029 	fprintf (out, "magnification %6.2f\n", Magnification);
3030     if (DepthCue > 0.001 && Upd_depthcue)
3031 	fprintf (out, "depthcue %6.3f\n", DepthCue);
3032     if (drvui->mol_d > 0.0f && Upd_molcomp)
3033 	fprintf (out, "molcomp %6.2f\n", drvui->mol_d);
3034     if (drvui->do_ellipsoids && Upd_ellipsoids)
3035 	fprintf (out, "ellipsoids %6.2f\n", drvui->Ellipsoid_Prob);
3036     if (strlen (drvui->Cutout_color) != 0 && Upd_cutout)
3037 	fprintf (out, "cutout %s\n", drvui->Cutout_color);
3038     if (fabs (printdist - 3.5) > 0.001 && Upd_list)
3039 	fprintf (out, "list %6.2f\n", printdist);
3040     if (fabs (drvui->label_scale - 1.0) > 0.001)
3041 	fprintf (out, "labelscale %.3f\n", drvui->label_scale);
3042     if (drvui->slab_con[0] > 0.)
3043 	fprintf (out, "slab %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f "
3044 		 "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %d\n",
3045 		 drvui->slab_con[0], drvui->slab_con[1], drvui->slab_con[2],
3046 		 drvui->slab_con[3], drvui->slab_con[4], drvui->slab_con[5],
3047 		 drvui->slab_off[0], drvui->slab_off[1], drvui->slab_off[2],
3048 		 drvui->slab_rot[0], drvui->slab_rot[1], drvui->slab_rot[2], slabmode);
3049     fprintf (out, "view %6.1f %6.1f %6.1f\n", Xrot, Yrot, Zrot);
3050     if (Vrml2 == 0 && Upd_vrml == 1)
3051 	fprintf (out, "vrml1\n");
3052     if (M_cameras == 0 && Upd_orthographic)
3053 	fprintf (out, "orthographic\n");
3054     if ((drvui->Phong_Size != 1.0f) || (drvui->Phong_Value != 0.2f))
3055 	fprintf (out, "phong %6.2f %6.2f\n", drvui->Phong_Value, drvui->Phong_Size);
3056     if (Upd_axislines)
3057 	fprintf (out, "axislines %6.2f %s\n", drvui->Ellipaxis_width,
3058 		 drvui->Ellipaxis_color);
3059     if (Upd_box)
3060 	fprintf (out, "box %6.3f %s\n", rad_cell, drvui->col_cell);
3061     if (edges && Upd_edges)
3062 	fprintf (out, "edges %6.2f %s\n", drvui->rad_edge, drvui->col_edge);
3063     if ((fabs (origin[0] - 0.5) > 0.0001) || (fabs (origin[1] - 0.5) > 0.0001) ||
3064 	(fabs (origin[2] - 0.5) > 0.0001))
3065 	fprintf (out, "origin %6.2f %6.2f %6.2f\n", origin[0], origin[1], origin[2]);
3066     if (drvui->polylimit > 0.105 && Upd_polytolerance)
3067 	fprintf (out, "polytolerance %6.2f\n", drvui->polylimit);
3068     if (Upd_background)
3069 	fprintf (out, "background %s\n", drvui->col_bg);
3070     if (Upd_finish)
3071 	fprintf (out, "finish %6.2f %6.2f %6.2f %6.2f\n", drvui->ambient,
3072 		 drvui->diffuse, drvui->specular, drvui->roughness);
3073     if (drvui->do_ellipsoids) {
3074 	for (i = 1; i < drvui->n_ellips; i++) {
3075 	    if (drvui->ellips[i].ell_type > 1000) {
3076 		if (drvui->ellips[i].save_el_number != -1)
3077 		    fprintf (out, "ellipcolor %s %d %s\n", drvui->ellips[i].ellips_l,
3078 			     drvui->ellips[i].ellips_n, drvui->ellips[i].ellips_col);
3079 		else {
3080 		    int j, haveit;
3081 
3082 		    haveit = 0;
3083 		    for (j = 1; j < i; j++)
3084 			if (check_atom_name
3085 			    (drvui->ellips[i].ellips_l, drvui->ellips[j].ellips_l))
3086 			    haveit = 1;
3087 		    if (haveit == 0)
3088 			fprintf (out, "ellipcolor %s * %s\n", drvui->ellips[i].ellips_l,
3089 				 drvui->ellips[i].ellips_col);
3090 		}
3091 	    }
3092 	}
3093     }
3094 // add mapcontour and mapcontour2d commands
3095     if (drvui->numOfFourierContours) {
3096 	for (i = 1; i <= drvui->numOfFourierContours; i++) {
3097 	    char type[6];
3098 
3099 	    if (drvui->Fourier2d) {
3100 		fprintf (out, "mapcontour2d %.3f %.3f %.3f %s",
3101 			 drvui->fourier[i].FourierContourLevel,
3102 			 drvui->fourier[i].FourierContourStep,
3103 			 drvui->fourier[i].FourierContourTop,
3104 			 drvui->fourier[i].FourierContourColor);
3105 		if (strlen(drvui->fourier[i].FourierBackColor))
3106 		    fprintf(out," %s\n",drvui->fourier[i].FourierBackColor);
3107 		else
3108 		    fprintf(out, "\n");
3109 	    } else {
3110 		if (drvui->fourier[i].FourierContourSolid)
3111 		    strcpy (type, "solid");
3112 		else
3113 		    strcpy (type, "mesh");
3114 		fprintf (out, "mapcontour  %.3f %s %s\n",
3115 			 drvui->fourier[i].FourierContourLevel, type,
3116 			 drvui->fourier[i].FourierContourColor);
3117 	    }
3118 	}
3119     }
3120 // add mapread command if needed
3121     switch (FourierMapType) {
3122     case 1:
3123 	strcpy (string, "mapread grd ");
3124 	break;
3125     case 2:
3126 	strcpy (string, "mapread stf ");
3127 	break;
3128     case 3:
3129 	strcpy (string, "mapread w2k ");
3130 	break;
3131     case 4:
3132 	strcpy (string, "mapread vsp ");
3133 	break;
3134     case 5:
3135 	strcpy (string, "mapread flp ");
3136 	break;
3137     case 6:
3138 	strcpy (string, "mapread fcf ");
3139 	break;
3140     case 7:
3141 	strcpy (string, "mapread dn6 ");
3142 	break;
3143     case 8:
3144 	strcpy (string, "mapread m80 ");
3145 	break;
3146     case 9:
3147 	strcpy (string, "mapread exc ");
3148 	break;
3149     case 10:
3150 	strcpy (string, "mapread m81 ");
3151 	break;
3152     case 11:
3153 	strcpy (string, "mapread xsf ");
3154 	break;
3155     default:
3156 	strcpy (string, "");
3157 	break;
3158     }
3159     if (strlen (string) > 0) {
3160 	char res[20];
3161 	strcat (string, FourierFileName);
3162 	if (FourierMapType == 6 || FourierMapType == 8) {	// add calc type
3163 	    if (Map_Info.map_type == 1)
3164 		strcat (string, " Fc");
3165 	    else if (Map_Info.map_type == 2)
3166 		strcat (string, " Fo-Fc");
3167 	    else if (Map_Info.map_type == 3)
3168 		strcat (string, " 2Fo-Fc");
3169 	    else if (Map_Info.map_type == 4)
3170 		strcat (string, " Fo2");
3171 	    else
3172 		strcat (string, " Fo");
3173 	}
3174 	sprintf(res, " %i", Map_Info.res);
3175 	strcat(string, res);
3176 	fprintf (out, "%s\n", string);
3177     }
3178 // add options and parameters related to modulation
3179     if (drvui->modulated != 0) {
3180 	if (drvui->modulated < 0)
3181 	    fprintf (out, "average\n");
3182 	if (drvui->phaseshift[0] + drvui->phaseshift[1] + drvui->phaseshift[2] > 0.0)
3183 	    fprintf (out, "phaseshift %.4f %.4f %.4f\n",
3184 		     drvui->phaseshift[0], drvui->phaseshift[1], drvui->phaseshift[2]);
3185 	for (i = 0; i < natom; i++)
3186 	    if (drvui->atoms[i].min_occ > 0.)
3187 		fprintf (out, "occupancy %s %d %.2f %.2f\n", drvui->atoms[i].atom_l,
3188 			 drvui->atoms[i].sv_atom_n, drvui->atoms[i].occupancy,
3189 			 drvui->atoms[i].min_occ);
3190     }
3191 // add surface-related options and parameters
3192     if (drvui->nsurf >1 ) {
3193 	for (i = 1; i < drvui->nsurf; i++)
3194 	    fprintf(out,"aimsurf %s %d %s %s %s\n", drvui->surfatom[i], drvui->surfnum[i],
3195 		    drvui->surffile[i], surftypes[drvui->surftype[i]], drvui->surfcolor[i]);
3196     }
3197     if (drvui->voidflag != 0) {
3198 	fprintf (out,"voids %d %.4f %d %d %d %s\n", drvui->voidflag, drvui->probesize,
3199 		 drvui->voidgrid[0], drvui->voidgrid[1], drvui->voidgrid[2], drvui->voidcolor);
3200     }
3201 // add special command (if needed)
3202     if (Omit->nomits > 0) {
3203 	for (i = 0; i < Omit->nomits; i++) {
3204 	    fprintf (out, "special %d %d\n", Omit->omit1[i], Omit->omit2[i]);
3205 	}
3206     }
3207     if (Upd_xyzoff && drvui->origin1_flag)
3208 	fprintf (out, "rem xyzoff %.3f %.3f %.3f\n", -drvui->origin_offset[0],
3209 		 -drvui->origin_offset[1], -drvui->origin_offset[2]);
3210     if (fabs (drvui->Old_Xrot - Xrot) > 0.1)
3211 	drvui->Str_File_Changed = 1;
3212     if (fabs (drvui->Old_Yrot - Yrot) > 0.1)
3213 	drvui->Str_File_Changed = 1;
3214     if (fabs (drvui->Old_Zrot - Zrot) > 0.1)
3215 	drvui->Str_File_Changed = 1;
3216     fprintf (out, "end\n");
3217 
3218     if (fclose (out) != 0) {
3219 	Error_Box ("Unable to update the working file!");
3220 	return;
3221     }
3222 
3223     if (!overwrite) {
3224 	unlink (drvui->Cur_Temp);	// delete the input file
3225 	if (rename (temp_out, drvui->Cur_Temp)) {	// rename temporary to working
3226 	    Error_Box ("Unable to update working file!");
3227 	    return;
3228 	}
3229     } else {
3230 	unlink (drvui->Cur_File);	// delete the str file
3231 	if (rename (temp_out, drvui->Cur_File)) {	// rename tmp to str
3232 	    Error_Box ("Unable to create revised str file!");
3233 	    return;
3234 	}
3235 	drvui->Str_File_Changed = 0;
3236     }
3237 }
3238 
3239 void
3240 WriteConfig (void)
3241 {
3242 // write updated configuration file
3243     FILE *fname;
3244 
3245     char filename[256];
3246 
3247 #ifdef WIN32
3248     char profile[100];
3249 
3250     OSVERSIONINFOEX osvi;
3251 
3252     memset (&osvi, 0, sizeof (OSVERSIONINFOEX));
3253     osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
3254     GetVersionEx ((OSVERSIONINFO *) & osvi);
3255     if (osvi.dwMajorVersion == 4)
3256 	strcpy (profile, "c:");
3257     else
3258 	strcpy (profile, getenv ("USERPROFILE"));
3259     strcpy (filename, profile);
3260     strcat (filename, "\\");
3261     strcat (filename, Configure_file);
3262 #else
3263     fl_filename_expand (filename, Configure_file);
3264 #endif
3265     fname = fopen (filename, "w");
3266     if (!fname) {
3267 	return;
3268     }
3269     fprintf (fname, "%s\n%s\n", drvui->DRAWxtl_Path, drvui->POV_Path);
3270     fprintf (fname, "%s\n%s\n", drvui->VRML_Path, drvui->EditName);
3271     fprintf (fname, "%s\n%s\n", drvui->FileViewName, drvui->POV_Options);
3272     fprintf (fname, "%s\n%s\n", drvui->Cur_File, drvui->Cur_Dir);
3273     fprintf (fname, "%s\n", drvui->POV_Include);
3274     fprintf (fname, "%s\n", drvui->LoadOnStartup);
3275     fprintf (fname, "%s\n", drvui->DefaultFinish);
3276     fprintf (fname, "%s\n", drvui->ProgramPath);
3277     if (drvui->autolabel == 0)
3278 	fprintf (fname, "noautolabel\n");
3279     else
3280 	fprintf (fname, "autolabel\n");
3281     fprintf (fname, "%d %d %.3f\n", drvui->Stereo, drvui->cross_eyed, drvui->stereo_base);
3282     fprintf (fname, "%d %d %d %d\n", drvui->mainWindow->x (), drvui->mainWindow->y (),
3283 	     drvui->mainWindow->w (), drvui->mainWindow->h ());
3284     fprintf (fname, "povray %d vrml %d asy %d\n", doPOV, doVrml, doAsy);
3285     fprintf (fname, "%s\n", drvui->MSMS_Path);
3286     fprintf (fname, "%s\n", drvui->Mencoder_Path);
3287     fprintf (fname, "%s\n", drvui->FFmpeg_Path);
3288     fclose (fname);
3289 }
3290 
3291 QUAT
3292 XYZ_Rot_to_Q (double Xrot, double Yrot, double Zrot)
3293 {
3294 // routine to convert the X,Y,Z rotations into a quaternion
3295     float *axis;
3296 
3297     QUAT q1, q2, q3, qtemp, Rotq;
3298 
3299     axis = (float *) zalloc (3 * sizeof (float));
3300     axis[0] = 1.0f;
3301     axis_to_quaternion (axis, (float) (Xrot / RAD), &q1);
3302     axis[0] = axis[2] = 0.0;
3303     axis[1] = 1.0f;
3304     axis_to_quaternion (axis, (float) (Yrot / RAD), &q2);
3305     axis[2] = 1.0f;
3306     axis[1] = axis[0] = 0.0;
3307     axis_to_quaternion (axis, (float) (Zrot / RAD), &q3);
3308     qmult (&q3, &q2, &qtemp);
3309     qmult (&qtemp, &q1, &Rotq);
3310     free (axis);
3311     return Rotq;
3312 }
3313 
3314 #if 0
3315 void
3316 moveto_atom (int x, int y, int w, int h)
3317 {
3318 // picks the sphere at the current cursor position, moves the crosshair to it
3319 // and updates distance and angle from previous atom(s)
3320 
3321     int i, j;
3322 
3323     GLint viewport[4];
3324 
3325     GLuint names, *ptr, minZ;
3326 
3327     GLuint *ptrNames = 0, numberOfNames = 0;
3328 
3329     int hits;
3330 
3331     int sphere, num;
3332 
3333     float cpx, cpy, cpz;
3334 
3335     float m[16];
3336 
3337     float dot;
3338 
3339     char atnum[5];
3340 
3341     int ellips;
3342 
3343     char cur_name_t[10];
3344 
3345     float ratio = 1.0f * (float) w / (float) h;
3346 
3347     memset (selectBuf, 0, BUFSIZE);
3348     glGetIntegerv (GL_VIEWPORT, viewport);
3349     glPushMatrix ();
3350 
3351     glSelectBuffer (BUFSIZE, selectBuf);
3352     glRenderMode (GL_SELECT);
3353     glMatrixMode (GL_PROJECTION);
3354     glLoadIdentity ();
3355 
3356     gluPickMatrix (x, viewport[3] - y, viewport[2] / 100, viewport[3] / 100, viewport);
3357 
3358     if (M_cameras == 0) {
3359 	if (w <= h)
3360 	    glOrtho (-gl_size, gl_size, -gl_size / ratio, gl_size / ratio, -10000.,
3361 		     10000.);
3362 	else
3363 	    glOrtho (-gl_size * ratio, gl_size * ratio, -gl_size, gl_size, -10000.,
3364 		     10000.);
3365     } else {
3366 	gluPerspective (17, ratio, 0.01, 1000.);	// view angle, aspect,near/far clip
3367     }
3368     glMatrixMode (GL_MODELVIEW);
3369 
3370     glInitNames ();
3371     glPushName (~0);
3372 
3373     glTranslatef (drvui->Trans[0], drvui->Trans[1], drvui->Trans[2]);
3374 
3375     quaternion_to_rotmatrix (&Rotq, m);
3376 
3377     glMultMatrixf (m);
3378     cpx = (POV_Max[0] + POV_Min[0]) / 2.0f;
3379     cpy = (POV_Max[1] + POV_Min[1]) / 2.0f;
3380     cpz = (POV_Max[2] + POV_Min[2]) / 2.0f;
3381 
3382 
3383     glCallList (drvui->crystalDL);
3384 
3385     glPopMatrix ();
3386 
3387     hits = glRenderMode (GL_RENDER);
3388     glFlush ();
3389 
3390     if (hits == 0)
3391 	return;
3392 
3393     ptr = (GLuint *) selectBuf;
3394     minZ = 0xffffffff;
3395     for (i = 0; i < hits; i++) {
3396 	names = *ptr;
3397 	ptr++;
3398 	if (*ptr < minZ && *(ptr + 2) != (GLuint) - 1) {
3399 	    numberOfNames = names;
3400 	    minZ = *ptr;
3401 	    ptrNames = ptr + 2;
3402 	}
3403 	ptr += names + 2;
3404     }
3405     if (numberOfNames == 0)
3406 	return;
3407 
3408     ptr = ptrNames;
3409 
3410     sphere = *ptr;
3411     ptr++;
3412     num = *ptr;
3413 
3414     ellips = 0;
3415 
3416     if (sphere > 90000 && sphere / 100000 < drvui->n_ellips) {
3417 	ellips = 1;
3418 	sphere /= 100000;
3419     } else if (sphere >= drvui->nsphere)
3420 	return;			// not a sphere
3421 
3422 
3423     nvert = 0;			// clear the vertex list
3424     for (j = 0; j < natom; ++j) {	// loop through atoms
3425 	if (drvui->atoms[j].atom_fn != drvui->frame_no)
3426 	    continue;
3427 	if ((drvui->atoms[j].atom_n & 255) == sphere
3428 	    || ((drvui->atoms[j].atom_n >> 24) & 255) == sphere)
3429 	    find_all_in_box (j);
3430     }
3431 
3432     if (nvert == 0)
3433 	return;
3434 
3435     cur_cen[0] = o_vert[3 * num];
3436     cur_cen[1] = o_vert[3 * num + 1];
3437     cur_cen[2] = o_vert[3 * num + 2];
3438     if (cur_atom[3] > 0) {
3439 	cur_atom[0] = cur_atom[1];
3440 	cur_atom[1] = cur_atom[2];
3441 	cur_atom[2] = cur_atom[3];
3442 	strcpy (cur_name[0], cur_name[1]);
3443 	strcpy (cur_name[1], cur_name[2]);
3444 	strcpy (cur_name[2], cur_name[3]);
3445     }
3446     i = 0;
3447     if (ellips == 0) {
3448 	for (j = 0; j < 4; j++) {
3449 	    if (drvui->spheres[sphere].sphere_l[j] != ' ')
3450 		cur_name_t[i++] = drvui->spheres[sphere].sphere_l[j];
3451 	}
3452     } else {
3453 	for (j = 0; j < 4; j++) {
3454 	    if (drvui->ellips[sphere].ellips_l[j] != ' ')
3455 		cur_name_t[i++] = drvui->ellips[sphere].ellips_l[j];
3456 	}
3457     }
3458     cur_name_t[i] = '\0';
3459     sprintf (atnum, "%d", drvui->atoms[drvui->orig_atom_no[num]].sv_atom_n);
3460     strcat (cur_name_t, atnum);
3461 
3462     if (cur_atom[0] <= 0) {
3463 	cur_atom[0] = i;
3464 	strcpy (cur_name[0], cur_name_t);
3465     } else if (cur_atom[1] <= 0) {
3466 	cur_atom[1] = i;
3467 	dist12 = dist (cur_atom[0], cur_atom[1]);
3468 	strcpy (cur_name[1], cur_name_t);
3469     } else if (cur_atom[2] <= 0) {
3470 	cur_atom[2] = i;
3471 	strcpy (cur_name[2], cur_name_t);
3472 	dist12 = dist (cur_atom[0], cur_atom[1]);
3473 	dist23 = dist (cur_atom[1], cur_atom[2]);
3474 	if (dist12 == 0.0f || dist23 == 0.0f || cur_atom[2] == cur_atom[0]) {
3475 	    ang123 = 0.0f;
3476 	} else {
3477 	    dot =
3478 		dot0_3d (s_vert[3 * cur_atom[1]], s_vert[3 * cur_atom[1] + 1],
3479 			 s_vert[3 * cur_atom[1] + 2], s_vert[3 * cur_atom[0]],
3480 			 s_vert[3 * cur_atom[0] + 1], s_vert[3 * cur_atom[0] + 2],
3481 			 s_vert[3 * cur_atom[2]], s_vert[3 * cur_atom[2] + 1],
3482 			 s_vert[3 * cur_atom[2] + 2]);
3483 	    float temp = dot / (dist12 * dist23);
3484 
3485 	    if (temp > 1.0f)
3486 		temp = 1.0f;
3487 	    if (temp < -1.0f)
3488 		temp = -1.0f;
3489 	    ang123 = (float) (acos (temp) * RAD);
3490 	}
3491     } else {
3492 	float v1[3], v2[3], v0[3], p1[3], p2[3];
3493 
3494 	int j;
3495 
3496 	cur_atom[3] = i;
3497 	strcpy (cur_name[3], cur_name_t);
3498 	dist23 = dist (cur_atom[1], cur_atom[2]);
3499 	dist34 = dist (cur_atom[2], i);
3500 	for (j = 0; j < 3; j++) {
3501 	    v0[j] = s_vert[3 * cur_atom[0] + j] - s_vert[3 * cur_atom[1] + j];
3502 	    v1[j] = s_vert[3 * cur_atom[1] + j] - s_vert[3 * cur_atom[2] + j];
3503 	    v2[j] = s_vert[3 * cur_atom[2] + j] - s_vert[3 * cur_atom[3] + j];
3504 	}
3505 	if (dist23 == 0.0f || dist34 == 0.0f)
3506 	    ang234 = 0.0f;
3507 	else {
3508 	    dot = vdot (v1, v2);
3509 	    float temp = -dot / (dist23 * dist34);
3510 
3511 	    if (temp > 1.0f)
3512 		temp = 1.0f;
3513 	    if (temp < -1.0f)
3514 		temp = -1.0f;
3515 	    ang234 = (float) (acos (temp) * RAD);
3516 	}
3517 	vcross (v0, v1, p1);
3518 	vcross (v2, v1, p2);
3519 	if (vlength (p1) < 0.1f || vlength (p2) < 0.1f) {
3520 	    torsion_ang = 0.0f;
3521 	    return;
3522 	}
3523 	torsion_ang = -vdot (p1, p2) / (vlength (p1) * vlength (p2));
3524 	if (torsion_ang < -1.0f)
3525 	    torsion_ang = -1.0f;
3526 	if (torsion_ang > 1.0f)
3527 	    torsion_ang = 1.0f;
3528 	torsion_ang = (float) (acos (torsion_ang) * RAD);
3529 	if (vdot (p1, v2) > 0.0f)	// set the sign
3530 	    torsion_ang *= -1.0f;
3531     }
3532 
3533     Fl::redraw ();
3534 }
3535 #endif
3536 
3537 int
3538 pick_label (int x, int y, int w, int h)
3539 {
3540 // picks the label at the current cursor position
3541 
3542     int i;
3543 
3544     GLint viewport[4];
3545 
3546     GLuint names, *ptr, minZ;
3547 
3548     GLuint *ptrNames = 0, numberOfNames = 0;
3549 
3550     int hits;
3551 
3552     int label;
3553 
3554     float m[16];
3555 
3556     int offset;
3557 
3558     float ratio = 1.0f * (float) w / (float) h;
3559 
3560     memset (selectBuf, 0, BUFSIZE);
3561     glGetIntegerv (GL_VIEWPORT, viewport);
3562     glPushMatrix ();
3563 
3564     glSelectBuffer (BUFSIZE, selectBuf);
3565     glRenderMode (GL_SELECT);
3566     glMatrixMode (GL_PROJECTION);
3567     glLoadIdentity ();
3568 
3569     offset = (int) (100.0f / gl_size);
3570     gluPickMatrix (x + offset, viewport[3] - y + offset, 25, 25, viewport);
3571 
3572     if (M_cameras == 0) {
3573 	if (w <= h)
3574 	    glOrtho (-gl_size, gl_size, -gl_size / ratio, gl_size / ratio, -10000.,
3575 		     10000.);
3576 	else
3577 	    glOrtho (-gl_size * ratio, gl_size * ratio, -gl_size, gl_size, -10000.,
3578 		     10000.);
3579     } else {
3580 	gluPerspective (17, ratio, 0.01, 1000.);	// view angle, aspect,near/far clip
3581     }
3582     glMatrixMode (GL_MODELVIEW);
3583 
3584     glInitNames ();
3585     glPushName (~0);
3586 
3587     glTranslatef (drvui->Trans[0], drvui->Trans[1], drvui->Trans[2]);
3588 
3589     quaternion_to_rotmatrix (&Rotq, m);
3590 
3591     glMultMatrixf (m);
3592 
3593     for (drvui->frame_no = 1; drvui->frame_no <= drvui->max_frame; drvui->frame_no++)
3594 	generate_gl_texts ();
3595     drvui->frame_no = drvui->max_frame;
3596 
3597     glPopMatrix ();
3598 
3599     hits = glRenderMode (GL_RENDER);
3600     glFlush ();
3601 
3602     if (hits == 0)
3603 	return (0);
3604 
3605     ptr = (GLuint *) selectBuf;
3606     minZ = 0xffffffff;
3607     for (i = 0; i < hits; i++) {
3608 	names = *ptr;
3609 	ptr++;
3610 	if (*ptr < minZ && *(ptr + 2) != (GLuint) - 1) {
3611 	    numberOfNames = names;
3612 	    minZ = *ptr;
3613 	    ptrNames = ptr + 2;
3614 	}
3615 	ptr += names + 2;
3616     }
3617     if (numberOfNames == 0)
3618 	return (0);
3619 
3620     ptr = ptrNames;
3621 
3622     label = *ptr;
3623 
3624     //fprintf(stderr,"picked label no %d\n",label);
3625 
3626     if (label >= drvui->nlabel)
3627 	return (0);		// not a label ?
3628 
3629 
3630     //cur_cen[0]= drvui->label_x[label][0];
3631     //cur_cen[1]= drvui->label_x[label][1];
3632     //cur_cen[2]= drvui->label_x[label][2];
3633 
3634     //Fl::redraw();
3635 
3636     return (label);
3637 }
3638