1 /*
2  * (c) 2005-2006 Iowa State University
3  *     see the LICENSE file in the top level directory
4  */
5 
6 /***************************************
7  * MolDisplayWin.cpp
8  ***************************************/
9 
10 #include "Globals.h"
11 #include "GlobalExceptions.h"
12 #include "MolDisplayWin.h"
13 #include "Prefs.h"
14 #include "main.h"
15 #include "Frame.h"
16 #include "BasisSet.h"
17 #include "InputData.h"
18 #include "Math3D.h"
19 #include "myFiles.h"
20 #include "setscreenplane.h"
21 #include "bondsdlg.h"
22 #include "coordinateswindow.h"
23 #include "energyplotdialog.h"
24 #include "VirtualSphere.h"
25 #include "Internals.h"
26 #include "llmdialog.h"
27 #include "setbondlength.h"
28 #include "appendframesoptions.h"
29 #include "exportoptionsdialog.h"
30 #include "frequenciesdialog.h"
31 #include "inputbuilder.h"
32 #include "surfaceswindow.h"
33 #include "choosevecgroup.h"
34 #include "coordinateoffset.h"
35 #include "frameenergy.h"
36 #include "build_palette.h"
37 #include "printoptions.h"
38 #include "windowparameters.h"
39 #include "zmatrixcalculator.h"
40 #include "symmetrypointgroupdlg.h"
41 #include "setPreference.h"
42 #include "selectfiletype.h"
43 #include "MyTypes.h"
44 #include <wx/clipbrd.h>
45 #include <wx/dataobj.h>
46 #include <wx/filename.h>
47 #include <wx/image.h>
48 #include <wx/printdlg.h>
49 #include <wx/mstream.h>
50 #include <wx/display.h>
51 #include <wx/stdpaths.h>
52 #include <wx/toolbar.h>
53 #if wxCHECK_VERSION(2,9,0)
54 #include <wx/quantize.h>
55 #endif
56 
57 #ifdef __WXMSW__
58 #include <stdio.h>
59 #endif
60 
61 extern WinPrefs * gPreferences;
62 extern BuilderInterface * BuilderTool;
63 extern WindowData	gWindowDefault;
64 
65 using namespace std;
66 
67 //Local use class to hold data during the animation of normal modes
68 class ModeAnimation {
69 public:
70 	std::vector<CPoint3D>   SavedCoordinates;
71 	std::vector<CPoint3D>   ModeOffset;
72 	float                   offsetFactor;
73 	int                     iPoint;
74 	int                     inc;
75 	int                     NumPoints;
76 	wxTimer                 m_timer;
77 	bool                    SavedDrawMode;
78 };
79 
80 //derive a status bar class so we can add the scrollbar
81 class MolStatusBar : public wxStatusBar {
82 public:
83 	MolStatusBar(MolDisplayWin * parent);
84 
85 	void OnScrollBarChange(wxScrollEvent & event);
86 	void SetScrollBar(int pos, int range);
87 	void SetScrollBarValue(int pos);
88 	void OnSize(wxSizeEvent & event);
89 
90 private:
91 	MolDisplayWin *	myParent;
92 	wxScrollBar *	myScroll;
93 
94 	DECLARE_EVENT_TABLE()
95 };
96 
97 BEGIN_EVENT_TABLE(MolStatusBar, wxStatusBar)
98 	EVT_SIZE(MolStatusBar::OnSize)
99 	EVT_COMMAND_SCROLL(MMP_FRAMESCROLLBAR, MolStatusBar::OnScrollBarChange )
100 END_EVENT_TABLE()
101 
102 //Class to hold CML data on the clipboard
103 //This is really intended for internal use for copying data from one file to another.
104 class wxCMLDataObject : public wxDataObjectSimple {
105 public:
wxCMLDataObject(char * cmlText=NULL)106 	wxCMLDataObject(char * cmlText=NULL) : wxDataObjectSimple(_("CML")) {
107 		CML = cmlText;};
~wxCMLDataObject(void)108 	virtual ~wxCMLDataObject(void) {if (CML) delete [] CML; CML=NULL;};
GetCML(void) const109 	char * GetCML(void) const {return CML;};
GetDataSize(void) const110 	virtual size_t GetDataSize(void) const {return (CML?strlen(CML):0);};
GetDataHere(void * buf) const111 	virtual bool GetDataHere(void * buf) const {if (CML) {strcpy((char *)buf, CML); return true;} return false;};
SetData(size_t len,const void * buf)112 	virtual bool SetData(size_t len, const void * buf) {
113 		if (CML) {delete [] CML; CML = NULL;}
114 		if (len>0) {
115 			CML = new char[len+1];
116 			CML[len] = '\0';
117 			if (buf) strncpy(CML, (const char *)buf, len);
118 			return true;
119 		}
120 		return false;
121 	};
122 
123 private:
124 	char * CML;
125 	DECLARE_NO_COPY_CLASS(wxCMLDataObject)
126 };
127 
128 #include <iostream>
MolDisplayWin(const wxString & title,const wxPoint & position,const wxSize & size,long style,const wxString & name)129 MolDisplayWin::MolDisplayWin(const wxString &title,
130 						 const wxPoint  &position,
131 						 const wxSize   &size,
132 						 long            style,
133 						 const wxString &name)
134 	: wxFrame(NULL, wxID_ANY, title, position, size, style, name) {
135 
136 	MainData = new MoleculeData(this);
137 	Prefs = new WinPrefs;
138 	*Prefs = *gPreferences;
139 	Dirty = false;
140 	OperationInProgress = false;
141 	ProgressInd = NULL;
142 	ModeAnimationData = NULL;
143 	bondsWindow = NULL;
144 	coordsWindow = NULL;
145 	energyPlotWindow = NULL;
146 	frequenciesWindow = NULL;
147 	surfacesWindow = NULL;
148 	inputBuilderWindow = NULL;
149 	prefsDlg = NULL;
150 	zMatCalcDlg = NULL;
151 
152 	winData = gWindowDefault;
153 
154 	pageSetupData = NULL;
155 	printData = NULL;
156 	myStatus = NULL;
157 
158 	show_fullscreen = false;
159 	mHighliteState = false;
160 	window_just_focused = false;
161 	mAltModifyingToolBar = false;
162 	edit_symmetrically = false;
163 	do_rotate_annotation = false;
164 	GLUpdateInProgress = false;
165 
166 	toolbar = NULL;
167 	lasso_has_area = false;
168 	show_bond_sites = true;
169 
170 	status_timer.SetOwner(this, MMP_STATUS_TIMER);
171 	rotate_timer.SetOwner(this, MMP_ROTATE_TIMER);
172 
173 #ifdef _MSC_VER
174 	//Visual studio is a total pile.
175 	//The %n format specifier is disabled by default and
176 	//putting this in the app init function didn't work.
177 	_set_printf_count_output(1);
178 #endif
179 
180 	transpTriList = NULL;
181 	transpSortVertex = NULL;
182 	transpIndex = NULL;
183 	triangleCount = 0;
184 	sphere_list = 0;
185 	shader_program = 0;
186 	depth_fbo = 0;
187 	depth_tex_id = 0;
188 	MainListActive = false;
189 	SurfaceListActive = false;
190 	haveTransparentSurfaces = false;
191 
192 	light_pos[0] = 6.0f;
193 	light_pos[1] = 6.0f;
194 	light_pos[2] = 12.0f;
195 	light_pos[3] = 0.0f;
196 
197 	myStatus = new MolStatusBar(this);
198 	SetStatusBar(myStatus);
199 
200 	int attribs[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16,
201 	                 0, 0};
202 	bool do_stereo = false;
203 #if wxCHECK_VERSION(2,9,0)
204 	if (Prefs->UseStereo()) {
205 		attribs[4] = WX_GL_STEREO;
206 		if (wxGLCanvas::IsDisplaySupported(attribs)) {
207 			do_stereo = true;
208 		} else {
209 			attribs[4] = 0;
210 		}
211 	}
212 #endif
213 	glCanvas = new MpGLCanvas(this, wxID_ANY, wxPoint(0,0), wxDefaultSize,
214 	                          attribs, do_stereo);
215 	glCanvas->SetPrefs(Prefs);
216 
217 	createMenuBar();
218 	SetMenuBar(menuBar);
219 	/* SizeChanged(); */
220 	glCanvas->SetFocus();
221 
222 		//init the inertia for the autorotation to something reasonable
223 	inertia.x = 1;
224 	inertia.y = 1;
225 
226 	/* Show(true); */
227 	AdjustMenus();
228 
229 	// If this is a new/empty window default to edit mode (title should be
230 	// "Untitled")
231 	if (!title.Cmp(wxT("Untitled"))) {
232 		Prefs->SetToolbarShown(true);
233 		ShowToolbar();
234 		menuBuild->Check(MMP_SHOW_TOOLBAR, Prefs->ToolbarShown());
235 
236 		wxCommandEvent foo;
237 		foo.SetId(MMP_TOOL_HAND);
238 		OnToggleTool(foo);
239 	}
240 
241 //	SetClientSize(wxSize(400, 400));
242 	SetSize(winData.GetMolWinRect());
243 
244 	Show();
245 }
246 
~MolDisplayWin()247 MolDisplayWin::~MolDisplayWin() {
248 	//As long as all related windows indicate this window as their
249 	//parent when they are created, they will be automatically destroyed
250 	//when this window is destroyed.
251 	if (printData) delete printData;
252 	if (pageSetupData) delete pageSetupData;
253 	glCanvas->SetPrefs(NULL);
254 	if (ModeAnimationData) {
255 		delete ModeAnimationData;
256 		ModeAnimationData = NULL;
257 	}
258 
259 	if (ProgressInd != NULL) {
260 		delete ProgressInd;
261 		ProgressInd = NULL;
262 	}
263 
264 	if (MainData != NULL) {
265 		delete MainData;
266 		MainData = NULL;
267 	}
268 
269 	if (Prefs != NULL) {
270 		delete Prefs;
271 		Prefs = NULL;
272 	}
273 
274 	delete[] transpTriList;
275 	transpTriList = NULL;
276 	delete[] transpSortVertex;
277 	transpSortVertex = NULL;
278 	delete[] transpIndex;
279 	transpIndex = NULL;
280 
281 	// Since the periodic table dialog no longer has a parent, the application
282 	// will stay open if the dialog is open but no MolDisplayWins are.  So,
283 	// if this is the last MolDisplayWin that's open, we close the periodic
284 	// dialog in order for the whole application to close.
285 #ifndef __WXMAC__
286 	MpApp *app = (MpApp *) wxTheApp;
287 	if (app->WindowCount() == 0) {
288 		BuilderTool->ClosePalette();
289 	}
290 #endif
291 }
292 
getCanvasSize(long * width,long * height)293 void MolDisplayWin::getCanvasSize(long *width, long *height) {
294 	int w, h;
295 	glCanvas->GetClientSize(&w, &h);
296 	*width = w;
297 	*height = h;
298 }
299 
eventSize(wxSizeEvent & event)300 void MolDisplayWin::eventSize(wxSizeEvent &event) {
301 	event.Skip();
302 }
303 
OnMenuOpen(wxMenuEvent & event)304 void MolDisplayWin::OnMenuOpen(wxMenuEvent & event) {
305 //	StopAnimations();
306 	event.Skip();
307 }
308 
OnKillFocus(wxFocusEvent & event)309 void MolDisplayWin::OnKillFocus(wxFocusEvent & event) {
310 	StopAnimations();
311 	event.Skip();
312 }
313 
OnActivate(wxActivateEvent & event)314 void MolDisplayWin::OnActivate(wxActivateEvent & event) {
315 	if (event.GetActive()) {
316 		window_just_focused = true;
317 		glCanvas->eventWindowActivated(event);
318 	} else {
319 //		StopAnimations();
320 	}
321 	event.Skip();
322 }
323 
JustFocused(void)324 bool MolDisplayWin::JustFocused(void) {
325 	return window_just_focused;
326 }
327 
StopAnimations(void)328 void MolDisplayWin::StopAnimations(void) {
329 	bool resetNeeded = false;
330 
331 	if (m_timer.IsRunning()) {
332 		m_timer.Stop();
333 		timerRunning = false;
334 		resetNeeded = true;
335 	}
336 	if (ModeAnimationData) { //if data already exists toggle off the animation
337 		ModeAnimationData->m_timer.Stop();
338 		MainData->SetDrawMode(ModeAnimationData->SavedDrawMode);
339 		for (int iatm=0; iatm<(MainData->cFrame->NumAtoms); iatm++) {
340 			MainData->cFrame->Atoms[iatm].Position = ModeAnimationData->SavedCoordinates[iatm];
341 		}
342 		delete ModeAnimationData;
343 		ModeAnimationData = NULL;
344 		resetNeeded = true;
345 	}
346 	if (resetNeeded) ResetModel(false);
347 
348 	// It's kind of nice to leave the auto-rotation running.  Otherwise, if we
349 	// leave the window, we've got to start it going again.  If you don't like
350 	// this, uncomment the next lines.
351 	// if (rotate_timer.IsRunning()) {
352 		// rotate_timer.Stop();
353 	// }
354 }
355 
OnFrameAnimationTimer(wxTimerEvent &)356 void MolDisplayWin::OnFrameAnimationTimer(wxTimerEvent & /*event*/) {
357 	if (MainData->CurrentFrame>=MainData->NumFrames)
358 		ChangeFrames(1);
359 	else
360 		ChangeFrames(MainData->CurrentFrame+1);
361 }
362 
createMenuBar(void)363 void MolDisplayWin::createMenuBar(void) {
364 	menuBar = new wxMenuBar;
365 
366 	menuFile = new wxMenu;
367 	menuEdit = new wxMenu;
368 	menuView = new wxMenu;
369 	menuBuild = new wxMenu;
370 	menuMolecule = new wxMenu;
371 	menuWindow = new wxMenu;
372 	menuHelp = new wxMenu;
373 
374 	menuFile->Append(wxID_NEW, wxT("&New\tCtrl+N"), _("Open a new empty window"));
375 	menuFile->Append(MMP_NEWFRAME, wxT("Append New Frame"), wxT("Add a new, empty frame"));
376 	menuFile->Append(wxID_OPEN, wxT("&Open ...\tCtrl+O"), wxT("Open a file into a new window"));
377 	menuFile->Append(MMP_ADDFRAMES, wxT("Add Frames from File..."), wxT("Add additional geometries to this window from a file"));
378 	menuFile->Append(wxID_SAVE, wxT("&Save\tCtrl+S"));
379 	menuFile->Append(wxID_SAVEAS, wxT("Save &as ...\tCtrl+Shift+S"));
380 	menuFile->Append(wxID_CLOSE, wxT("&Close\tCtrl+W"));
381 	menuFile->AppendSeparator();
382 	menuFile->Append(MMP_DELETEFRAME, wxT("Delete Frame"), wxT("Delete the visible geometry point"));
383 	menuFile->AppendSeparator();
384 	menuFile->Append(MMP_IMPORTMENU, wxT("Import..."), wxT("Import a $VEC group from a GAMESS dat file"));
385 	menuFile->Append(MMP_EXPORT, wxT("Export..."), wxT("Export this window to one of a variety of formats"));
386 	menuFile->AppendSeparator();
387 	menuFile->Append(wxID_PRINT_SETUP, wxT("Page Set&up ..."));
388 	menuFile->Append(MMP_PRINTOPTIONS, wxT("Print Options ..."));
389 	menuFile->Append(wxID_PREVIEW, wxT("Print Pre&view\tCtrl+Shift+P"));
390 	menuFile->Append(wxID_PRINT, wxT("&Print ...\tCtrl+P"));
391 	menuFile->AppendSeparator();
392 	menuFile->Append(wxID_EXIT, wxT("&Quit\tCtrl+Q"));
393 
394 	menuEdit->Append(wxID_UNDO, wxT("&Undo\tCtrl+Z"));
395 	menuEdit->Append(wxID_REDO, wxT("&Redo\tCtrl+Shift+Z"));
396 	menuEdit->AppendSeparator();
397 	menuEdit->Append(wxID_CUT, wxT("Cu&t\tCtrl+X"));
398 	menuEdit->Append(wxID_COPY, wxT("&Copy\tCtrl+C"), wxT("Copy the display as an image"));
399 	menuEdit->Append(MMP_COPYCOORDS, wxT("Copy Coordinates"), wxT("Copy the current set of coordinates as plain text in GAMESS style"));
400 	menuEdit->Append(MMP_COPYNWCOORDS, wxT("Copy NWChem Coordinates"), wxT("Copy the current set of coordinates as plain text in NWChem style"));
401 	menuEdit->Append(wxID_PASTE, wxT("&Paste\tCtrl+V"));
402 	menuEdit->Append(wxID_CLEAR, wxT("&Delete\tDel"));
403 	menuEdit->AppendSeparator();
404 	menuEdit->Append(MMP_SELECT_ALL, wxT("&Select All\tCtrl+A"));
405 	menuEdit->Append(MMP_SELECT_NONE, wxT("Select &None\tShift+Ctrl+A"));
406 	menuEdit->AppendSeparator();
407 	menuEdit->Append(wxID_PREFERENCES, wxT("Global Pr&eferences"), wxT("Edit the default preferences for new windows"));
408 
409 	menuView->AppendCheckItem(MMP_SHOWMODE, wxT("Show &Normal Mode\tCtrl+D"), wxT("Display the vibrational motion as mass-weighted vectors"));
410 	menuView->Append(MMP_ANIMATEMODE, wxT("&Animate Mode\tShift+Ctrl+M"), wxT("Animate the vibration, click outside the window to stop"));
411 	menuView->Append(MMP_OFFSETMODE, wxT("&Offset along mode..."), wxT("Generate a new set of coordinates by moving along the current mode"));
412 	menuView->Append(MMP_PREVMODE, wxT("&Previous Normal Mode\tCtrl+["));
413 	menuView->Append(MMP_NEXTMODE, wxT("Ne&xt Normal &Mode\tCtrl+]"));
414 	menuView->AppendCheckItem(MMP_SHOWGRADIENT, wxT("Show Energy Gradient\tCtrl+G"));
415 	menuView->AppendSeparator();
416 	menuView->AppendCheckItem(MMP_SHOWAXIS, wxT("Show Ax&is"), wxT("Display the cartesian axis"));
417 	menuView->AppendCheckItem(MMP_SHOWSYMMETRYOPERATOR, _("Show S&ymmetry Operators"), _("Overlays the symmetry operators for the current point group. Not all point groups are supported."));
418 
419 	menuViewLabels = new wxMenu;
420 	menuView->Append(MMP_ATOMLABELSSUBMENU, wxT("Atom &Labels"), menuViewLabels);
421 	menuViewLabels->AppendRadioItem(MMP_NO_ATOMLABEL, wxT("&None"));
422 	menuViewLabels->AppendRadioItem(MMP_SHOWATOMLABELS, wxT("Atomic &Symbol"));
423 	menuViewLabels->AppendRadioItem(MMP_SHOWATOMNUMBER, wxT("Atom &Number"));
424 	menuViewLabels->AppendRadioItem(MMP_BOTHATOMLABELS, wxT("S&ymbols and Numbers"));
425 
426 	menuViewStyle = new wxMenu;
427 	menuView->Append(MMP_DISPLAYMODESUBMENU, _("&Display Style"), menuViewStyle);
428 	menuViewStyle->AppendRadioItem(MMP_WIREFRAMEMODE, _("Wire Frame"), _("Display as bonds only"));
429 	menuViewStyle->AppendRadioItem(MMP_BALLANDSTICKMODE, _("Ball and Stick"), _("Tradiational display mode, sphere size can be adjusted in the preferences"));
430 	menuViewStyle->AppendSeparator();
431 	menuViewStyle->AppendCheckItem(MMP_EFP_WIREFRAME, _("Show Effective Fragments as Wire Frame"), _("Overide the display mode for EFP solvent molecules"));
432 	menuViewStyle->AppendSeparator();
433 	menuViewStyle->AppendCheckItem(MMP_SHOWPATTERN, _("Show Atom Patterns"), _("Overlay a 2D pattern on the atom spheres (Ball and Stick mode only)"));
434 
435 	wxMenu * menuViewToggleVis = new wxMenu;
436 	menuView->Append(MMP_DISPLAYMODESUBMENU, _("&Toggle visibility of"), menuViewToggleVis);
437 	menuViewToggleVis->Append(MMP_TOGGLEABINITIO, _("&ab initio atoms\tAlt-a"), _("Show/Hide ab initio atoms"));
438 	menuViewToggleVis->Append(MMP_TOGGLEMMATOMS, _("&MM atoms\tAlt-s"), _("Show/Hide Molecular Mechanics atoms"));
439 	menuViewToggleVis->Append(MMP_TOGGLEEFPATOMS, _("&Effective Fragment atoms\tAlt-e"), _("Show/Hide EFP atoms"));
440 
441 	menuViewAnnotations = new wxMenu;
442 	menuViewAnnotations->Append(MMP_ADDMARKANNOTATION, _("&Mark Selected"), _("Mark the selected atom(s), right-click to remove"));
443 	menuViewAnnotations->Append(MMP_ADDLENGTHANNOTATION, _("Display &Length"), _("Select 2 atoms then right-click on one of them"));
444 	menuViewAnnotations->Append(MMP_ADDANGLEANNOTATION, _("Display &Angle"), _("Select 3 atoms then right-click on one of them"));
445 	menuViewAnnotations->Append(MMP_ADDDIHEDRALANNOTATION, _("Display Di&hedral"), _("Select 4 atoms then right-click on one of them"));
446 	menuViewAnnotations->Append(MMP_DELETEALLANNOTATIONS, _("&Delete all annotations"), _("Remove all annotations or right-click on the annotation"));
447 	menuView->Append(MMP_ANNOTATIONSSUBMENU, _("&Annotations"), menuViewAnnotations, _("Annotate the molecule display"));
448 
449 	menuView->Append(MMP_ANIMATEFRAMES, wxT("Animate &Frames\tCtrl+F"), wxT("Run through the geometries producing an animation"));
450 	menuView->Append(MMP_SHRINK10, wxT("&Shrink 10%\tCtrl-down"), _T("Reduce size by 10%"));
451 	menuView->Append(MMP_ENLARGE10, wxT("&Enlarge 10%\tCtrl-up"), _T("Enlarge size by 10%"));
452 	menuView->Append(MMP_CENTER, wxT("&Center View"), _T("Center the molecule in the window"));
453 	menuView->Append(MMP_AUTOROTATE, wxT("Start AutoRotation"), _T("Start/Stop the molecule autorotation"));
454 
455 	menuViewRotate = new wxMenu;
456 	menuView->Append(MMP_ROTATESUBMENU, wxT("&Rotate ..."), menuViewRotate);
457 	menuView->Append(MMP_WINDOWPARAMETERS, wxT("Set &Window Parameters..."));
458 
459 	menuView->AppendSeparator();
460 	menuView->AppendCheckItem(MMP_SHOW_FULLSCREEN, _("Show Fullscreen"), _("Display in full screen mode"));
461 
462 	menuViewRotate->Append(MMP_ROTATETOXAXIS, wxT("to &X-axis"));
463 	menuViewRotate->Append(MMP_ROTATETOYAXIS, wxT("to &Y-axis"));
464 	menuViewRotate->Append(MMP_ROTATETOZAXIS, wxT("to &Z-axis"));
465 	menuViewRotate->Append(MMP_ROTATE180HOR, wxT("180 degrees &Horizontal"));
466 	menuViewRotate->Append(MMP_ROTATE180VER, wxT("180 degrees &Vertical"));
467 	menuViewRotate->Append(MMP_ROTATEPRINC, wxT("to &Principal Orientation"));
468 	menuViewRotate->Append(MMP_ROTATEOTHER, wxT("&Other..."));
469 
470 #ifdef ENABLE_INTERACTIVE_MODE
471 	menuBuild->AppendCheckItem(MMP_SHOW_TOOLBAR, _("Show Toolbar\tCtrl+I"), _("Show tools for viewing and editing atoms"));
472 #endif
473 	menuBuild->AppendCheckItem(MMP_SHOWBUILDTOOLS, _("Show Build &Tools\tCtrl+T"), _("Display build tools palette"));
474 #ifdef ENABLE_INTERACTIVE_MODE
475 	menuBuild->AppendSeparator();
476 	menuBuild->Append(MMP_ADDHYDROGENS, wxT("Add &Hydrogens"), _T("Complete moleclues by adding hydrogens to incomplete bonds"));
477 	menuBuild->Append(MMP_DELETEHYDROGENS, wxT("&Delete Hydrogens"), _T("Remove terminal hydrogens (Does not apply to effective fragments or SIMOMM atoms)"));
478 	menuBuild->AppendCheckItem(MMP_SHOWBONDSITES, wxT("&Show Bonding Sites"), _T("Click on a site to add an atom"));
479 	menuBuild->AppendCheckItem(MMP_SYMMETRY_EDIT, wxT("Edit with Symmetry"), _T(""));
480 	/* menuBuild->Append(MMP_SYMMETRY_REGEN, wxT("Regenerate Symmetry"), _T("")); */
481 	menuBuild->AppendSeparator();
482 	menuBuild->Append(MMP_SAVESTRUCTURE, wxT("Prototype Selection"), _T("Save structure as a prototype in builder"));
483 #endif
484 
485 	menuMolecule->Append(MMP_SETBONDLENGTH, wxT("Set Bonds..."), _("Apply the automated bond determination with several options"));
486 	menuMolecule->Append(MMP_ENERGYEDIT, wxT("Set &Frame Energy..."));
487 	menuMolecule->Append(MMP_CREATELLMPATH, wxT("Create &LLM Path..."), _("Create a Linear Least Motion path between this geometry and the next one"));
488 	menuMolecule->Append(MMP_MINFRAMEMOVEMENTS, wxT("&Minimize Frame Movements"), _("Reorient each frame so as to minimize the movement of each atom"));
489 	menuMolecule->AppendSeparator();
490 	menuSetPG = new wxMenu;
491 	menuSetPG->Append(MMP_CURPOINTGROUP, _("cur pg"), _("Currently selected point group"));
492 	menuPointGroup = new wxMenu;
493 	menuPointGroup->AppendRadioItem(MMP_PGC1, _("C1"));
494 	menuPointGroup->AppendRadioItem(MMP_PGCS, _("Cs"));
495 	menuPointGroup->AppendRadioItem(MMP_PGCI, _("Ci"));
496 	menuPointGroup->AppendRadioItem(MMP_PGCNH, _("Cnh"));
497 	menuPointGroup->AppendRadioItem(MMP_PGCNV, _("Cnv"));
498 	menuPointGroup->AppendRadioItem(MMP_PGCN, _("Cn"));
499 	menuPointGroup->AppendRadioItem(MMP_PGS2N, _("S2n"));
500 	menuPointGroup->AppendRadioItem(MMP_PGDND, _("Dnd"));
501 	menuPointGroup->AppendRadioItem(MMP_PGDNH, _("Dnh"));
502 	menuPointGroup->AppendRadioItem(MMP_PGDN, _("Dn"));
503 	menuPointGroup->AppendRadioItem(MMP_PGTD, _("Td"));
504 	menuPointGroup->AppendRadioItem(MMP_PGTH, _("Th"));
505 	menuPointGroup->AppendRadioItem(MMP_PGT, _("T"));
506 	menuPointGroup->AppendRadioItem(MMP_PGOH, _("Oh"));
507 	menuPointGroup->AppendRadioItem(MMP_PGO, _("O"));
508 	menuPGOrder = new wxMenu;
509 	menuPGOrder->AppendRadioItem(MMP_PGORDER2, _("2"));
510 	menuPGOrder->AppendRadioItem(MMP_PGORDER3, _("3"));
511 	menuPGOrder->AppendRadioItem(MMP_PGORDER4, _("4"));
512 	menuPGOrder->AppendRadioItem(MMP_PGORDER5, _("5"));
513 	menuPGOrder->AppendRadioItem(MMP_PGORDER6, _("6"));
514 	menuPGOrder->AppendRadioItem(MMP_PGORDER7, _("7"));
515 	menuPGOrder->AppendRadioItem(MMP_PGORDER8, _("8"));
516 
517 	menuSetPG->Append(wxID_ANY, _("&Point Group"), menuPointGroup, _("Select the Point Group"));
518 	menuSetPG->Append(MMP_POINTGROUPORDER, _("&Order of Principal Axis"), menuPGOrder, _("Set the order of the principle rotation axis, if any"));
519 	menuMolecule->Append(wxID_ANY, _("Set &Point Group"), menuSetPG, _("Manually set the point group"));
520 	menuMolecule->Append(MMP_DETERMINEPG, _("Determine Point Group"), _("Compute the point group for the current coordinates"));
521 	menuMolecule->Append(MMP_SYMADAPTCOORDS, _("Set &Coordinates to Principal Orientation"), _("Transform coordinates to the symmetry adapted principle orientation"));
522 	menuMolecule->AppendSeparator();
523 	menuMolecule->Append(MMP_CONVERTTOBOHR, wxT("Convert to &Bohr"));
524 	menuMolecule->Append(MMP_CONVERTTOANGSTROMS, wxT("Convert to &Angstroms"));
525 	menuMolecule->Append(MMP_INVERTNORMALMODE, wxT("&Invert Normal Mode"), _T("Multiply the normal mode by -1 to invert the direction of the vectors"));
526 // TODO:  Create menu items for remaining menus
527 
528 	menuWindow->Append(MMP_BONDSWINDOW, wxT("&Bonds"), _("View/edit the bonding within the molecule"));
529 	menuWindow->Append(MMP_COORDSWINDOW, wxT("&Coordinates"), _("View/edit cartesian or internal coordinates"));
530 	menuWindow->Append(MMP_ENERGYPLOTWINDOW, wxT("&Energy Plot"), _("A plot of the energy for each geometry"));
531 	menuWindow->Append(MMP_FREQUENCIESWINDOW, wxT("&Frequencies"), _("Plot the vibrational frequencies"));
532 	menuWindow->Append(MMP_INPUTBUILDERWINDOW, wxT("&Input Builder"), _T("Generate a GAMESS input file"));
533 	/* menuWindow->Append(MMP_INPUT_WIZARD, wxT("&Input Builder Wizard"), _T("Easily generate a GAMESS input file")); */
534 	menuWindow->Append(MMP_SURFACESWINDOW, wxT("&Surfaces"), _T("Add/Edit/Remove various surface types"));
535 	menuWindow->Append(MMP_ZMATRIXCALC, wxT("&Z-Matrix Calculator"), _("Compute bond lengths/angles or dihedrals between any set of atoms"));
536 	menuWindow->Append(MMP_LOCAL_PREFERENCES, wxT("Pr&eferences"), _T("Edit the preferences for this window"));
537 
538 	menuBar->Append(menuFile, wxT("&File"));
539 	menuBar->Append(menuEdit, wxT("&Edit"));
540 	menuBar->Append(menuView, wxT("&View"));
541 	menuBar->Append(menuBuild, wxT("&Builder"));
542 	menuBar->Append(menuMolecule, wxT("&Molecule"));
543 	menuBar->Append(menuWindow, wxT("&Subwindow"));
544 
545 	menuHelp->Append(wxID_ABOUT, wxT("&About MacMolPlt..."), _T("Learn about MacMolPlt"));
546 	menuHelp->Append(wxID_HELP, wxT("&MacMolPlt Manual..."), _T("Brief documentation"));
547 	menuBar->Append(menuHelp, wxT("&Help"));
548 }
549 
ClearMenus(void)550 void MolDisplayWin::ClearMenus(void) {
551 	menuFile->Enable(MMP_NEWFRAME, false);
552 	menuFile->Enable(wxID_SAVE, false);
553 	menuFile->Enable(MMP_DELETEFRAME, false);
554 	menuFile->Enable(MMP_EXPORT, false);
555 
556 	menuEdit->Enable(wxID_CUT, false);
557 	/* menuEdit->Enable(wxID_COPY, false); */
558 	menuEdit->Enable(MMP_COPYCOORDS, false);
559 	menuEdit->Enable(MMP_COPYNWCOORDS, false);
560 	/* menuEdit->Enable(wxID_CLEAR, false); */
561 
562 	menuView->Enable(MMP_SHOWMODE, false);
563 	menuView->Enable(MMP_ANIMATEMODE, false);
564 	menuView->Enable(MMP_PREVMODE, false);
565 	menuView->Enable(MMP_NEXTMODE, false);
566 	menuView->Enable(MMP_OFFSETMODE, false);
567 	menuView->Enable(MMP_ANIMATEFRAMES, false);
568 
569 	menuMolecule->Enable(MMP_SETBONDLENGTH, false);
570 	menuMolecule->Enable(MMP_ENERGYEDIT, false);
571 	menuMolecule->Enable(MMP_MINFRAMEMOVEMENTS, false);
572 	menuMolecule->Enable(MMP_DETERMINEPG, false);
573 	menuMolecule->Enable(MMP_SYMADAPTCOORDS, false);
574 	menuMolecule->Enable(MMP_INVERTNORMALMODE, false);
575 }
576 
AdjustMenus(void)577 void MolDisplayWin::AdjustMenus(void) {
578 	ClearMenus();
579 	/* menuFile->Enable(wxID_SAVE, Dirty); */
580 	if (Prefs->ShowAtomicSymbolLabels() && Prefs->ShowAtomNumberLabels())
581 		menuViewLabels->Check(MMP_BOTHATOMLABELS, true);
582 	else if (Prefs->ShowAtomicSymbolLabels())
583 		menuViewLabels->Check(MMP_SHOWATOMLABELS, true);
584 	else if (Prefs->ShowAtomNumberLabels())
585 		menuViewLabels->Check(MMP_SHOWATOMNUMBER, true);
586 	else
587 		menuViewLabels->Check(MMP_NO_ATOMLABEL, true);
588 
589 	if (Prefs->DrawWireFrame())
590 		menuViewStyle->Check(MMP_WIREFRAMEMODE, true);
591 	else
592 		menuViewStyle->Check(MMP_BALLANDSTICKMODE, true);
593 
594 	if (MainData->NumFrames > 1 ) {
595 		menuFile->Enable(MMP_DELETEFRAME, true);
596 		menuView->Enable(MMP_ANIMATEFRAMES, true);
597 		menuMolecule->Enable(MMP_MINFRAMEMOVEMENTS, true);
598 	}
599 	if (MainData->cFrame->Vibs) {
600 		menuView->Enable(MMP_SHOWMODE, true);
601 		menuView->Enable(MMP_ANIMATEMODE, true);
602 		menuView->Check(MMP_SHOWMODE, MainData->GetDrawMode());
603 		if (MainData->cFrame->Vibs->CurrentMode>0) menuView->Enable(MMP_PREVMODE, true);
604 		if (MainData->cFrame->Vibs->CurrentMode<(MainData->cFrame->Vibs->NumModes-1))
605 			menuView->Enable(MMP_NEXTMODE, true);
606 		menuView->Enable(MMP_OFFSETMODE, true);
607 		menuMolecule->Enable(MMP_INVERTNORMALMODE, true);
608 	}
609 }
610 
OnSaveUpdate(wxUpdateUIEvent & event)611 void MolDisplayWin::OnSaveUpdate(wxUpdateUIEvent& event) {
612 	event.Enable(Dirty);
613 }
614 
OnShowToolbarUpdate(wxUpdateUIEvent & event)615 void MolDisplayWin::OnShowToolbarUpdate(wxUpdateUIEvent& event) {
616 	event.Check(Prefs->ToolbarShown());
617 }
618 
OnShowBuildToolsUpdate(wxUpdateUIEvent & event)619 void MolDisplayWin::OnShowBuildToolsUpdate(wxUpdateUIEvent& event) {
620 	event.Check(BuilderTool->IsPaletteVisible());
621 }
622 
OnUndoUpdate(wxUpdateUIEvent & event)623 void MolDisplayWin::OnUndoUpdate( wxUpdateUIEvent& event ) {
624 	event.Enable(mUndoBuffer.undoPossible());
625 }
626 
OnRedoUpdate(wxUpdateUIEvent & event)627 void MolDisplayWin::OnRedoUpdate( wxUpdateUIEvent& event ) {
628 	event.Enable(mUndoBuffer.redoPossible());
629 }
630 
OnAddHydrogensUpdate(wxUpdateUIEvent & event)631 void MolDisplayWin::OnAddHydrogensUpdate( wxUpdateUIEvent& event ) {
632 	event.Enable((MainData->cFrame->GetNumAtoms() > 0) && InEditMode());
633 	menuBuild->Enable(MMP_DELETEHYDROGENS, (MainData->cFrame->GetNumAtoms() > 0) &&
634 	                  InEditMode());
635 }
636 
OnShowBondSitesUpdate(wxUpdateUIEvent & event)637 void MolDisplayWin::OnShowBondSitesUpdate(wxUpdateUIEvent& event) {
638 	event.Check(show_bond_sites);
639 	event.Enable(InEditMode());
640 }
641 
OnShowSymmetryEdit(wxUpdateUIEvent & event)642 void MolDisplayWin::OnShowSymmetryEdit(wxUpdateUIEvent& event) {
643 	event.Check(edit_symmetrically);
644 	event.Enable(InEditMode());
645 }
646 
647 /**
648  * This function updates a variety of controls that should be enabled when
649  * at least one atom is in the current frame and disabled otherwise.  To
650  * register a control with this update function, insert its window ID into
651  * the range of IDs this function handles.
652  * @param event The update event.
653  */
UpdateAtomsOptions(wxUpdateUIEvent & event)654 void MolDisplayWin::UpdateAtomsOptions(wxUpdateUIEvent& event) {
655 	event.Enable(MainData->cFrame->GetNumAtoms() > 0);
656 }
657 
658 /*!
659 * wxEVT_UPDATE_UI event handler for wxID_PASTE
660  */
661 
OnPasteUpdate(wxUpdateUIEvent & event)662 void MolDisplayWin::OnPasteUpdate(wxUpdateUIEvent& event) {
663 
664 	// This function gets triggered on a paste event (actually, a call to
665 	// CreateFrameSnapShot, which triggers UI updates).  The clipboard is
666 	// already open there, and it's a mistake to open it twice.
667 	if (wxTheClipboard->IsOpened()) return;
668 
669 	event.Enable(false);
670 	//paste is allowed for empty frames or while in edit mode
671 	if ((MainData->cFrame->NumAtoms == 0)||InEditMode()) {
672 		if (wxTheClipboard->Open()) {
673 			if (wxTheClipboard->IsSupported(wxDF_TEXT) ||
674 			    wxTheClipboard->IsSupported(_("CML"))) {
675 				event.Enable(true);
676 			}
677 			wxTheClipboard->Close();
678 		}
679 	}
680 }
681 /*!
682 * wxEVT_UPDATE_UI event handler for Edit menu items
683  */
684 
OnSelectNoneUpdate(wxUpdateUIEvent & event)685 void MolDisplayWin::OnSelectNoneUpdate(wxUpdateUIEvent& event) {
686 	/* menuEdit->Enable(wxID_CLEAR, mHighliteState && InEditMode()); */
687 	event.Enable(MainData->cFrame->GetNumAtomsSelected() > 0);
688 }
689 
OnSelectAllUpdate(wxUpdateUIEvent & event)690 void MolDisplayWin::OnSelectAllUpdate(wxUpdateUIEvent& event) {
691 	/* menuEdit->Enable(wxID_CLEAR, mHighliteState && InEditMode()); */
692 	event.Enable(MainData->cFrame->GetNumAtoms() > 0);
693 }
694 
695 /**
696  * Handles enable/disabling of the Edit -> Delete menu item.  The menu item is
697  * enabled when highlighting is in effect and we're in edit mode.
698  * @param event The update event.
699  **/
OnDeleteUpdate(wxUpdateUIEvent & event)700 void MolDisplayWin::OnDeleteUpdate(wxUpdateUIEvent& event) {
701 	event.Enable(mHighliteState && InEditMode());
702 }
703 
OnAnnotationMarkUpdate(wxUpdateUIEvent & event)704 void MolDisplayWin::OnAnnotationMarkUpdate( wxUpdateUIEvent& event ) {
705 	event.Enable(glCanvas->NumberSelectedAtoms()>0);
706 }
OnAnnotationLengthUpdate(wxUpdateUIEvent & event)707 void MolDisplayWin::OnAnnotationLengthUpdate( wxUpdateUIEvent& event ) {
708 	event.Enable(glCanvas->NumberSelectedAtoms()==2);
709 }
OnAnnotationAngleUpdate(wxUpdateUIEvent & event)710 void MolDisplayWin::OnAnnotationAngleUpdate( wxUpdateUIEvent& event ) {
711 	event.Enable(glCanvas->NumberSelectedAtoms()==3);
712 }
OnAnnotationDihedralUpdate(wxUpdateUIEvent & event)713 void MolDisplayWin::OnAnnotationDihedralUpdate( wxUpdateUIEvent& event ) {
714 	event.Enable(glCanvas->NumberSelectedAtoms()==4);
715 }
OnShowSymOpsUpdate(wxUpdateUIEvent & event)716 void MolDisplayWin::OnShowSymOpsUpdate( wxUpdateUIEvent& event ) {
717 	bool state = false;
718 	if (MainData->InputOptions) {
719 		if (MainData->InputOptions->Data) {
720 			GAMESSPointGroup pg = MainData->InputOptions->Data->GetPointGroup();
721 			if ((pg > GAMESS_C1)&&(pg!=GAMESS_S2N)&&(pg <GAMESS_TD)) {
722 				state = true;
723 			}
724 		}
725 	}
726 	event.Enable(state);
727 	event.Check(state && Prefs->ShowSymmetryOperators());
728 }
OnDeleteAnnotationsUpdate(wxUpdateUIEvent & event)729 void MolDisplayWin::OnDeleteAnnotationsUpdate( wxUpdateUIEvent& event ) {
730 	event.Enable(MainData->GetAnnotationCount() > 0);
731 }
OnShowPatternUpdate(wxUpdateUIEvent & event)732 void MolDisplayWin::OnShowPatternUpdate( wxUpdateUIEvent& event ) {
733 	event.Enable(!Prefs->DrawWireFrame());
734 	event.Check(Prefs->Show2DPattern());
735 }
OnEFPWireFrameUpdate(wxUpdateUIEvent & event)736 void MolDisplayWin::OnEFPWireFrameUpdate( wxUpdateUIEvent& event ) {
737 	event.Enable(MainData->FragmentNames.size()>0);
738 	event.Check(Prefs->ShowEFPWireFrame());
739 }
OnAutoRotationUpdate(wxUpdateUIEvent & event)740 void MolDisplayWin::OnAutoRotationUpdate( wxUpdateUIEvent& event ) {
741 	if (rotate_timer.IsRunning()) {
742 		event.SetText(wxT("Stop AutoRotation"));
743 	} else {
744 		event.SetText(wxT("Start AutoRotation"));
745 	}
746 }
OnShowPointGroupUpdate(wxUpdateUIEvent & event)747 void MolDisplayWin::OnShowPointGroupUpdate( wxUpdateUIEvent& event ) {
748 	event.Enable(false);
749 	GAMESSPointGroup pg = GAMESS_C1;
750 	int pgOrder = 1;
751 	if (MainData->InputOptions) {
752 		pg = MainData->InputOptions->Data->GetPointGroup();
753 		pgOrder = MainData->InputOptions->Data->GetPointGroupOrder();
754 	}
755 	if ((pg<GAMESS_C1)||(pg>NumberGAMESSPointGroups)) pg = GAMESS_C1;
756 	wxString pgString;
757 	const char * pgt = DataGroup::GetGAMESSPointGroupText(pg);
758 	if ((pg >=GAMESS_CNH)&&(pg<=GAMESS_DN)) {
759 		if (pgOrder<2) pgOrder = 2;
760 		menuSetPG->Enable(MMP_POINTGROUPORDER, true);
761 		menuPGOrder->Check((MMP_PGORDER2+pgOrder-2), true);
762 		int i=0;
763 		while (pgt[i]) {
764 			if (pgt[i] == 'N') {
765 				wxString temp;
766 				temp.Printf(wxT("%d"), pgOrder);
767 				pgString.Append(temp);
768 			} else {
769 				pgString.Append((char)(pgt[i]), 1);
770 			}
771 			i++;
772 		}
773 	} else {
774 		menuSetPG->Enable(MMP_POINTGROUPORDER, false);
775 		pgString = wxString(pgt, wxConvUTF8);
776 	}
777 	menuPointGroup->Check((MMP_PGC1+pg-GAMESS_C1), true);
778 	event.SetText(pgString);
779 }
OnMoleculeCreateLLMPathUpdate(wxUpdateUIEvent & event)780 void MolDisplayWin::OnMoleculeCreateLLMPathUpdate( wxUpdateUIEvent& event ) {
781 	event.Enable(false);
782 	if (MainData->NumFrames > 1 ) {
783 		if (MainData->CurrentFrame < MainData->NumFrames) {
784 			Frame * lFrame = MainData->GetCurrentFramePtr();
785 			Frame * lnFrame = lFrame->GetNextFrame();
786 			if (lFrame->NumAtoms == lnFrame->NumAtoms) {
787 				bool good = true;
788 				for (long i=0; i<lFrame->NumAtoms; i++) {
789 					if (lFrame->Atoms[i].Type != lnFrame->Atoms[i].Type) {
790 						good = false;
791 						break;
792 					}
793 				}
794 				event.Enable(good);
795 			}
796 		}
797 	}
798 }
799 /* Event handler functions */
800 
801 /* File menu */
menuFileAppendNewFrame(wxCommandEvent &)802 void MolDisplayWin::menuFileAppendNewFrame(wxCommandEvent &/*event*/) {
803 	StopAnimations();
804 	MainData->AddFrame(10,0);
805 	ResetAllWindows();
806 }
menuFileDeleteFrame(wxCommandEvent &)807 void MolDisplayWin::menuFileDeleteFrame(wxCommandEvent &/*event*/) {
808 	StopAnimations();
809 	MainData->DeleteFrame();
810 	ResetAllWindows();
811 }
menuFileImport(wxCommandEvent &)812 void MolDisplayWin::menuFileImport(wxCommandEvent &/*event*/) {
813 	StopAnimations();
814 	//First need to use an open file dialog
815 	wxString filename = wxFileSelector(wxT("Choose a GAMESS .DAT file to import a $VEC group"));
816 	//We are looking for $ VEC groups. Scan to see how many are there. If more than 1 the user will
817 	//have to choose.
818 	if (!filename.empty()) {
819 		FILE * myfile = fopen(filename.mb_str(wxConvUTF8), "rb");
820 		if (myfile == NULL) {
821 			MessageAlert("Unable to open the selected file!");
822 		} else {
823 			BufferFile * Buffer = NULL;
824 			try {
825 				Buffer = new BufferFile(myfile, false);
826 				int vecCount=0;
827 				while (Buffer->LocateKeyWord("$VEC", 4)) {
828 					vecCount++;
829 					Buffer->SkipnLines(1);
830 				}
831 				Buffer->SetFilePos(0);
832 				if (vecCount <= 0) {
833 					MessageAlert("No $VEC group found in the selected file.");
834 				} else {
835 					int targetVec = -1;
836 					if (vecCount == 1) {
837 						targetVec = 1;
838 					} else { //The user must choose the desired one
839 						ChooseVECgroup * chooser = new ChooseVECgroup(this);
840 						chooser->SetBuffer(Buffer);
841 						int rcode = chooser->ShowModal();
842 						if (rcode == wxID_OK) {
843 							targetVec = chooser->GetTarget() + 1;
844 						}
845 						chooser->Destroy();
846 					}
847 					if (targetVec >= 1) {
848 						Buffer->SetFilePos(0);
849 						for (int i=0; i<targetVec; i++) {
850 							if (i>0) Buffer->SkipnLines(1);
851 							Buffer->LocateKeyWord("$VEC", 4);
852 						}
853 						if (Buffer->LocateKeyWord("$VEC", 4)) {
854 							//Buffer should now have the correct position
855 							BasisSet * lBasis = MainData->GetBasisSet();
856 							Frame * lFrame = MainData->GetCurrentFramePtr();
857 							InputData * lInputData = MainData->GetInputData();
858 							if (lBasis) {
859 								long NumFuncs = lBasis->GetNumBasisFuncs(false);
860 								long SCFType = lInputData->Control->GetSCFType();
861 								long NumBetaOrbs = 0;
862 								if (SCFType == UHF) NumBetaOrbs = NumFuncs;
863 								else SCFType = 0;
864 								OrbitalRec * OrbSet = NULL;
865 								try {
866 									OrbSet = new OrbitalRec(NumFuncs, NumBetaOrbs, NumFuncs);
867 									if (OrbSet) {
868 										OrbSet->ReadVecGroup(Buffer, NumFuncs, (TypeOfWavefunction) SCFType);
869 									}
870 								}
871 								catch (DataError) {
872 									MessageAlert("Invalid data encountered while reading $Vec group. Import aborted!");
873 									if (OrbSet) {
874 										delete OrbSet;
875 										OrbSet = NULL;
876 									}
877 								}
878 								catch (MemoryError) {
879 									MessageAlert("Insufficient memory to import $Vec. Aborted!");
880 									if (OrbSet) {
881 										delete OrbSet;
882 										OrbSet = NULL;
883 									}
884 								}
885 								catch (std::bad_alloc) {
886 									MessageAlert("Insufficient memory to import $Vec. Aborted!");
887 									if (OrbSet) {
888 										delete OrbSet;
889 										OrbSet = NULL;
890 									}
891 								}
892 								catch (FileError) {
893 									MessageAlert("Unexpected end of file encountered.");
894 									if (OrbSet) {
895 										delete OrbSet;
896 										OrbSet = NULL;
897 									}
898 								}
899 								if (OrbSet != NULL) lFrame->Orbs.push_back(OrbSet);
900 							}
901 						}
902 					}
903 				}
904 			}
905 			catch (...) {
906 				MessageAlert("An error occurred importing the $VEC group.");
907 			}
908 			if (Buffer) delete Buffer;      //Done reading so free up the buffer
909 			fclose(myfile);
910 		}
911 	}
912 }
913 enum {
914 	mmp_bmp=0,
915 	mmp_png,
916 	mmp_jpg,
917 #if wxCHECK_VERSION(2,9,0)
918 	mmp_gif,
919 	mmp_tiff,
920 #endif
921 	mmp_data,
922 	mmp_mdl,
923 	mmp_xmol,
924 	mmp_eneg,
925 	mmp_vrml,
926 	mmp_pov,
927 	mmp_freq,
928 	mmp_qt,
929 	mmp_ming
930 };
menuFileExport(wxCommandEvent &)931 void MolDisplayWin::menuFileExport(wxCommandEvent &/*event*/) {
932 	wxFileDialog        *fileDlg = NULL;
933 	ExportOptionsDialog *exportOptionsDlg = NULL;
934 	wxString   filepath;
935 	wxMemoryDC memDC;
936 	wxImage    exportImage;
937 	wxBitmap  *bmp;
938 	int animGIFIndex = -1;
939 	wxString   wildcards(wxT("Windows Bitmap (*.bmp)|*.bmp")
940 						 wxT("|Portable Network Graphics (*.png)|*.png")
941 						 wxT("|JPEG (*.jpeg;*.jpg)|*.jpeg;*.jpg")
942 #if wxCHECK_VERSION(2,9,0)
943 						 wxT("|GIF (*.gif)|*.gif")
944 						 wxT("|TIFF (*.tiff)|*.tiff")
945 #endif
946 						 wxT("|GAMESS $DATA group (*.inp)|*.inp")
947 						 wxT("|MDL MolFile|*.mol")
948 						 wxT("|XMOL (*.xyz)|*.xyz")
949 						 wxT("|Tab delimited Energies (*.txt)|*.txt")
950 						 wxT("|VRML (*.wrl)|*.wrl")
951 						 wxT("|POV-Ray (*.pov)|*.pov"));
952 	bool vibs = false;
953 	int itemCount = 9;
954 		//Many of the exports are specific to a single frame so need to make sure a frame animation or a mode animation is stopped.
955 	StopAnimations();
956 #if wxCHECK_VERSION(2,9,0)
957 	itemCount = 11;
958 #endif
959 	if (MainData->cFrame->GetNumberNormalModes() > 0) {
960 		vibs = true;
961 		wildcards.Append(wxT("|Frequencies (*.txt)|*.txt"));
962 		itemCount++;
963 	}
964 #if wxCHECK_VERSION(2,9,0)
965 	if ((MainData->GetNumFrames() > 1)||vibs) {
966 		wildcards.Append(wxT("|Animated GIF (*.gif)|*.gif"));
967 		animGIFIndex = itemCount;
968 		itemCount++;
969 	}
970 #endif
971 #ifdef __MAC_USE_QUICKTIME__
972 	int QTindex = -1;
973 	if ((MainData->GetNumFrames() > 1)||vibs) {
974 		wildcards.Append(wxT("|QuickTime Movie (*.mov)|*.mov"));
975 		QTindex = itemCount;
976 		itemCount++;
977 	}
978 #endif
979 #ifdef HAVE_LIBMING
980 	int FlashIndex = -1;
981     if ((MainData->GetNumFrames() > 1)||vibs) {
982         wildcards.Append(wxT("|Flash Movie (*.swf)|*.swf"));
983 		FlashIndex = itemCount;
984 		itemCount++;
985     }
986 #endif
987 	int        index = 0;
988 	int        type  = 0;
989 
990 	fileDlg = new wxFileDialog(this,
991 	                           wxT("Export"),
992 							   wxT(""),
993 							   wxT(""),
994 							   wildcards,
995 #if wxCHECK_VERSION(2,9,0)
996 							   wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
997 #else
998 							   wxSAVE | wxOVERWRITE_PROMPT);
999 #endif
1000 
1001 	if(fileDlg->ShowModal() == wxID_OK) {
1002 		Prefs->CylindersForLines(true);
1003 		filepath = fileDlg->GetPath();
1004 		index    = fileDlg->GetFilterIndex();
1005 		if ((index < mmp_data) || (index == animGIFIndex)) {
1006 			switch(index) {
1007 				case mmp_bmp:
1008 					type = wxBITMAP_TYPE_BMP;
1009 					if(!filepath.Lower().Matches(wxT("*.bmp"))) {
1010 						filepath.Append(wxT(".bmp"));
1011 					}
1012 					break;
1013 				case mmp_png:
1014 					type = wxBITMAP_TYPE_PNG;
1015 					if(!filepath.Lower().Matches(wxT("*.png"))) {
1016 						filepath.Append(wxT(".png"));
1017 					}
1018 					break;
1019 				case mmp_jpg:
1020 					type = wxBITMAP_TYPE_JPEG;
1021 					if(!filepath.Lower().Matches(wxT("*.jpg")) &&
1022 					   !filepath.Lower().Matches(wxT("*.jpeg"))) {
1023 
1024 						filepath.Append(wxT(".jpg"));
1025 					}
1026 					break;
1027 #if wxCHECK_VERSION(2,9,0)
1028 				case mmp_gif:
1029 					type = wxBITMAP_TYPE_GIF;
1030 					if(!filepath.Lower().Matches(wxT("*.gif"))) {
1031 
1032 						filepath.Append(wxT(".gif"));
1033 					}
1034 					break;
1035 				case mmp_tiff:
1036 					type = wxBITMAP_TYPE_TIFF;
1037 					if(!filepath.Lower().Matches(wxT("*.tiff"))) {
1038 
1039 						filepath.Append(wxT(".tiff"));
1040 					}
1041 					break;
1042 #endif
1043 			}
1044 			exportOptionsDlg = new ExportOptionsDialog(this);
1045 			exportOptionsDlg->setFileType(type);
1046 #if wxCHECK_VERSION(2,9,0)
1047 			if (index == animGIFIndex) {
1048 				exportOptionsDlg->EnableModeMovie((MainData->cFrame->GetNumberNormalModes() > 0));
1049 				if (MainData->GetNumFrames() > 1) {
1050 					exportOptionsDlg->EnableFrameMovie(true);
1051 					exportOptionsDlg->SetMovieChoice(0);
1052 				} else {
1053 					exportOptionsDlg->EnableFrameMovie(false);
1054 					exportOptionsDlg->SetMovieChoice(1);
1055 				}
1056 			}
1057 #endif
1058 			if(exportOptionsDlg->ShowModal() == wxID_OK) {
1059 #if wxCHECK_VERSION(2,9,0)
1060 				if (index == animGIFIndex) {
1061 					WriteGIFMovie(filepath, exportOptionsDlg);
1062 				} else
1063 #endif
1064 				{
1065 					bmp = new wxBitmap(exportOptionsDlg->getWidth(),
1066 																   exportOptionsDlg->getHeight());
1067 					memDC.SelectObject(*bmp);
1068 					Prefs->SetLineWidth(exportOptionsDlg->getImageRatio());
1069 					glCanvas->GenerateHiResImageForExport(&memDC);
1070 					Prefs->SetLineWidth(1);
1071 					exportImage = bmp->ConvertToImage();
1072 					if(exportOptionsDlg->getTransparency()) {
1073 						// This gets really hairy, since there isn't a good way to
1074 						// determine what the actual value of the background color
1075 						// ends up being after it's pumped through both GL and WX.
1076 						//
1077 						// In the end we just compare our "ideal" value with the
1078 						// upper left corner of the image.  If the two are
1079 						// reasonably close, we use the value from the corner.
1080 
1081 						RGBColor *bgColor = Prefs->GetBackgroundColorLoc();
1082 						unsigned char red, green, blue;
1083 						short dRed, dGreen, dBlue;
1084 
1085 						red = exportImage.GetRed(0, 0);
1086 						green = exportImage.GetGreen(0, 0);
1087 						blue = exportImage.GetBlue(0, 0);
1088 
1089 						dRed = (short) abs((short)((bgColor->red) >> 8) - red);
1090 						dGreen = (short) abs((short)((bgColor->green) >> 8) - green);
1091 						dBlue = (short) abs((short)((bgColor->blue) >> 8) - blue);
1092 
1093 						if(dRed < 3 && dGreen < 3 && dBlue < 3) {
1094 							exportImage.SetMaskColour(red, green, blue);
1095 						}
1096 					}
1097 #if wxCHECK_VERSION(2,9,0)
1098 					if (type == wxBITMAP_TYPE_GIF) {
1099 						wxQuantize::Quantize(exportImage, exportImage);
1100 						if (exportImage.HasAlpha()) {
1101 							exportImage.ConvertAlphaToMask();
1102 						}
1103 					}
1104 #endif
1105 					exportImage.SaveFile(filepath, (wxBitmapType) type);
1106 					memDC.SelectObject(wxNullBitmap); // bmp has now been
1107 				}									  // destroyed.
1108 			}
1109 			exportOptionsDlg->Destroy();
1110 		}
1111 #ifdef __MAC_USE_QUICKTIME__
1112 		else if (index == QTindex)
1113 			//quicktime movie export
1114 			WriteQTMovie(filepath);
1115 #endif
1116 #ifdef HAVE_LIBMING
1117 		else if (index == FlashIndex)
1118 			//flash movie export
1119             WriteFlashMovie(filepath);
1120 #endif
1121 		else {
1122 			FILE *currFile = NULL;
1123 
1124 			if((currFile = fopen(filepath.mb_str(wxConvUTF8), "wb")) != NULL) {
1125 				BufferFile *buffer = NULL;
1126 				try {
1127 					buffer = new BufferFile(currFile, true);
1128 
1129 					bool AllFrames = false;
1130 					switch (index) {
1131 						case mmp_data:
1132 							if (MainData->GetNumFrames()>1) {
1133 								AllFrames = (wxMessageBox(wxT("Should all geometries (frames) be included\?"),
1134 														  wxT(""), wxYES_NO | wxICON_QUESTION) == wxYES);
1135 							}
1136 							ExportGAMESS(buffer, AllFrames);
1137 							break;
1138 						case mmp_mdl:
1139 							WriteMDLMolFile(buffer);
1140 							break;
1141 						case mmp_xmol:
1142 						{
1143 							if (MainData->GetNumFrames()>1) {
1144 								AllFrames = (wxMessageBox(wxT("Should all geometries (frames) be included\?"),
1145 														  wxT(""), wxYES_NO | wxICON_QUESTION) == wxYES);
1146 							}
1147 							bool AllModes = false;
1148 							bool AnimateMode = false;
1149 							if (!AllFrames && MainData->cFrame->Vibs) {
1150 								if (MainData->cFrame->Vibs->GetNumModes() > 1) {
1151 									AllModes = (wxMessageBox(wxT("Should all normal modes be included\?"),
1152 															  wxT(""), wxYES_NO | wxICON_QUESTION) == wxYES);
1153 								}
1154 								if (!AllModes && (MainData->cFrame->Vibs->GetNumModes() > 0)) {
1155 									AnimateMode = (wxMessageBox(wxT("Would you like to include data to animate the current normal mode\?"),
1156 															 wxT(""), wxYES_NO | wxICON_QUESTION) == wxYES);
1157 								}
1158 							}
1159 							WriteXYZFile(buffer, AllFrames, AllModes, AnimateMode);
1160 						}
1161 							break;
1162 						case mmp_eneg:
1163 							if (MainData->GetNumFrames()>1) {
1164 								AllFrames = (wxMessageBox(wxT("Should all geometries (frames) be included\?"),
1165 														  wxT(""), wxYES_NO | wxICON_QUESTION) == wxYES);
1166 							}
1167 							WriteTabbedEnergies(buffer, AllFrames);
1168 							break;
1169 						case mmp_vrml:
1170 							WriteVRMLFile(buffer);
1171 							break;
1172 						case mmp_pov:
1173 							WritePOVFile(buffer);
1174 							break;
1175 						case mmp_freq:
1176 							WriteFrequencies(buffer);
1177 							break;
1178 					}
1179 				}
1180 				catch (MemoryError) {
1181 					MessageAlert("Not enough memory to open the file for writing.");
1182 				}
1183 				if(buffer) {
1184 					delete buffer;
1185 				}
1186 				fclose(currFile);
1187 			} else {
1188 				MessageAlert("Unable to open the file for output.");
1189 			}
1190 		}
1191 		Prefs->CylindersForLines(false);
1192 	}
1193 
1194 	fileDlg->Destroy();
1195 }
1196 
menuFileOpen(wxCommandEvent & event)1197 void MolDisplayWin::menuFileOpen(wxCommandEvent &event) {
1198 	//Its possible we could handle this here if the current data is empty?
1199 	//On the Mac Open always opens a new window
1200 #ifndef __WXMAC__
1201 	if (!Dirty && (MainData->NumFrames == 1) && (MainData->MaxAtoms == 0)) {
1202 		//First need to use an open file dialog
1203 		wxString filename = wxFileSelector(wxT("Choose a file to open"),
1204 										   wxT(""), wxT(""), wxT(""),
1205 										   wxT("*.*"),
1206 #if wxCHECK_VERSION(2,9,0)
1207 										   wxFD_OPEN,
1208 #else
1209 										   wxOPEN,
1210 #endif
1211 										   this);
1212 		//If the user chooses a file, create a window and have it process it.
1213 		if (!filename.IsEmpty()) {
1214 			//An empty window defaults to edit mode with the toolbar active
1215 			//but once we open a file we should default to non-edit mode and hide the toolbar
1216 			if (Prefs->ToolbarShown()) {
1217 				ShowToolbar(false);
1218 			}
1219 			//Ok we have a problem. Abort open can't close the last window!
1220 			long r = OpenFile(filename);
1221 			if (r>0) {
1222 				SetTitle(filename);
1223 			}
1224 	//      if (r>0) temp->Show(true);
1225 		}
1226 	} else
1227 #endif
1228 		//otherwise just skip the event to pass it up the chain to the app handler
1229 		event.Skip();
1230 }
menuFileAddFramesFromFile(wxCommandEvent &)1231 void MolDisplayWin::menuFileAddFramesFromFile(wxCommandEvent &/*event*/) {
1232 	/* Add the data from one or more files to the existing file. */
1233 	wxFileDialog fileDlg(this,
1234 						_T("Choose a file(s) containing points to be appended to the currently open file."),
1235 						wxT(""), wxT(""), _T("*.*"),
1236 #if wxCHECK_VERSION(2,9,0)
1237 							   wxFD_OPEN | wxFD_MULTIPLE);
1238 #else
1239 								wxOPEN | wxMULTIPLE);
1240 #endif
1241 
1242 	if(fileDlg.ShowModal() == wxID_OK) {
1243 		wxArrayString paths;
1244 		fileDlg.GetPaths(paths);
1245 		AppendFramesOptions * optDlg = new AppendFramesOptions(this);
1246 		optDlg->SetSkip(Prefs->GetDRCSkip());
1247 		optDlg->SetupItems();
1248 		if (optDlg->ShowModal() == wxID_OK) {
1249 			Prefs->SetDRCSkip(optDlg->GetSkip());
1250 			//Loop over the filenames in the path list.
1251 			for (size_t i=0; i<paths.GetCount(); i++) {
1252 				OpenFile(paths.Item(i), optDlg->GetOffset(), optDlg->GetFlip(), true);
1253 			}
1254 		}
1255 		optDlg->Destroy();
1256 	}
1257 }
1258 
menuFileSave(wxCommandEvent & event)1259 void MolDisplayWin::menuFileSave(wxCommandEvent &event) {
1260 	if(!currFilePath.IsEmpty()) {
1261 		FILE *currFile = NULL;
1262 		BufferFile *buffer = NULL;
1263 
1264 		if((currFile = fopen(currFilePath.mb_str(wxConvUTF8), "wb")) == NULL) {
1265 			MessageAlert("Unable to access the file.");
1266 			return;
1267 		}
1268 		try {
1269 			buffer = new BufferFile(currFile, true);
1270 		}
1271 		//catch (std::bad_alloc) {//Out of memory error
1272 			//if (!append)
1273 				//AbortOpen("Not enough memory to open the file. Aborted!");
1274 		//}
1275 		catch (MemoryError) {
1276 			MessageAlert("Not enough memory to open the file for writing.");
1277 		}
1278 		//catch (UserCancel) {
1279 			//if (!append)
1280 				//AbortOpen("File open canceled by user");
1281 		//}
1282 	//  catch (DataError Error) {//Error parsing the file data
1283 	//      if (!Error.ErrorSet())  Window->AbortOpen(21);
1284 	//      else {
1285 	//          Error.WriteError();
1286 	//          delete Window; Window = NULL;
1287 	//      }
1288 	//  }
1289 		//Some kind of File system related error
1290 		//catch (FileError Error) { Error.WriteError();
1291 			//if (!append) AbortOpen(NULL);}
1292 		//catch (...) {
1293 			//if (!append)
1294 				//AbortOpen("Unknown error reading the selected file. File open aborted.");
1295 		//}
1296 
1297 		if(buffer) {
1298 			UpdateWindowData();
1299 			MainData->WriteCMLFile(buffer, Prefs, &winData, true, true);
1300 			Dirtify(false);
1301 			delete buffer;
1302 		}
1303 #ifdef __WXOSX_CARBON__
1304 		if (Prefs->CreateCustomIcon()) CreateCustomFileIcon(currFilePath);
1305 #endif
1306 		fclose(currFile);
1307 	}
1308 	else {
1309 		menuFileSave_as(event);
1310 	}
1311 }
1312 
menuFileSave_as(wxCommandEvent &)1313 void MolDisplayWin::menuFileSave_as(wxCommandEvent &/*event*/) {
1314 	FILE *currFile = NULL;
1315 	BufferFile *buffer = NULL;
1316 	wxString filePath;
1317 
1318 	filePath = wxFileSelector(wxT("Save As"), wxT(""), wxT(""), wxT(""),
1319 							  wxT("CML Files (*.cml)|*.cml"),
1320 #if wxCHECK_VERSION(2,9,0)
1321 							  wxFD_SAVE | wxFD_OVERWRITE_PROMPT,
1322 #else
1323 							  wxSAVE | wxOVERWRITE_PROMPT,
1324 #endif
1325 							  this);
1326 
1327 	if(!filePath.IsEmpty()) {
1328 		if((currFile = fopen(filePath.mb_str(wxConvUTF8), "wb")) == NULL) {
1329 			MessageAlert("Unable to access the file.");
1330 			return;
1331 		}
1332 		try {
1333 			UpdateWindowData();
1334 			buffer = new BufferFile(currFile, true);
1335 			MainData->WriteCMLFile(buffer, Prefs, &winData, true, true);
1336 			Dirtify(false);
1337 		}
1338 		//catch (std::bad_alloc) {//Out of memory error
1339 			//if (!append)
1340 				//AbortOpen("Not enough memory to open the file. Aborted!");
1341 		//}
1342 		catch (MemoryError) {
1343 			MessageAlert("Not enough memory to open the file for writing.");
1344 		}
1345 		//catch (UserCancel) {
1346 			//if (!append)
1347 				//AbortOpen("File open canceled by user");
1348 		//}
1349 	//  catch (DataError Error) {//Error parsing the file data
1350 	//      if (!Error.ErrorSet())  Window->AbortOpen(21);
1351 	//      else {
1352 	//          Error.WriteError();
1353 	//          delete Window; Window = NULL;
1354 	//      }
1355 	//  }
1356 		//Some kind of File system related error
1357 		//catch (FileError Error) { Error.WriteError();
1358 		//if (!append) AbortOpen(NULL);}
1359 		//catch (...) {
1360 			//if (!append)
1361 				//AbortOpen("Unknown error reading the selected file. File open aborted.");
1362 		//}
1363 		if(buffer) {
1364 			delete buffer;
1365 		}
1366 #ifdef __WXOSX_CARBON__
1367 		if (Prefs->CreateCustomIcon()) CreateCustomFileIcon(filePath);
1368 #endif
1369 		currFilePath = filePath;
1370 		wxFileName fn(filePath);
1371 		SetTitle(fn.GetFullName());
1372 		fclose(currFile);
1373 		//update the window titles for any open subwindows
1374 		if (bondsWindow) {
1375 			bondsWindow->UpdateWindowTitle();
1376 		}
1377 		if (coordsWindow) {
1378 			coordsWindow->UpdateWindowTitle();
1379 		}
1380 		if (energyPlotWindow) {
1381 			energyPlotWindow->UpdateWindowTitle();
1382 		}
1383 		if (frequenciesWindow) {
1384 			frequenciesWindow->UpdateWindowTitle();
1385 		}
1386 		if (inputBuilderWindow) {
1387 			inputBuilderWindow->UpdateWindowTitle();
1388 		}
1389 		if (surfacesWindow) {
1390 			surfacesWindow->UpdateWindowTitle();
1391 		}
1392 		if (zMatCalcDlg) {
1393 			zMatCalcDlg->UpdateWindowTitle();
1394 		}
1395 		if (prefsDlg) {
1396 			prefsDlg->UpdateWindowTitle();
1397 		}
1398 	}
1399 }
1400 
1401 #ifdef __WXOSX_CARBON__
1402 OSErr	SendFinderAppleEvent( AliasHandle aliasH, AEEventID appleEventID );
1403 OSErr	SaveCustomIcon( const wxString & filename, IconFamilyHandle icnsH );
1404 //	This routine will set the custom icon in the file with
1405 //  an image based on the current molecule display.
1406 //	It does this by creating a PicHandle, then creating an icon from the Picture,
1407 //	and finally saving the custom icon to disk.
1408 //  I am utilizing a private interface to internal data for the wxBitmap class so
1409 //  be warned that this could break in the future!
1410 
1411 #if wxCHECK_VERSION(2, 9, 0)
1412 #include <wx/osx/private.h>
1413 //This is a gross hack to get access to the picHandle in the wxBitmapRefData class
1414 //that is no longer provided in the wx headers
1415 class wxBitmapRefData {
1416 public:
1417 	PicHandle     GetPictHandle();
1418 };
1419 #else
1420 #include <wx/mac/carbon/private.h>
1421 #endif
CreateCustomFileIcon(const wxString & filePath)1422 bool MolDisplayWin::CreateCustomFileIcon( const wxString & filePath ) {
1423 	bool result = false;
1424 
1425 	//	create a pict of the current molecule display
1426 	wxImage mImage = glCanvas->getImage(0,0);
1427 	wxBitmap * mBitmap = new wxBitmap(mImage);
1428 	//The following utilizes a Mac specific internal pair of calls
1429 	//to get a PicHandle from a wxBitmap.
1430 	wxBitmapRefData * mBitmapData = mBitmap->GetBitmapData();
1431 	PicHandle pictH = mBitmapData->GetPictHandle();
1432 	if ( pictH != NULL ) {
1433 		//	IconFamilyResource.resourceType + IconFamilyResource.resourceSize
1434 		IconFamilyHandle icnsH	= (IconFamilyHandle) NewHandle( 8 );
1435 		if ( icnsH == NULL ) return( memFullErr );
1436 		(**icnsH).resourceType			= kIconFamilyType;
1437 		(**icnsH).resourceSize			= 8;
1438 
1439 		//	Create the icon from the Picture
1440 		OSErr err	= SetIconFamilyData( icnsH, 'PICT', (Handle)pictH );
1441 		if (err == noErr) {
1442 			//	Save the custom icon to disk
1443 			SaveCustomIcon( filePath, icnsH );
1444 		}
1445 		if ( icnsH != NULL ) DisposeHandle( (Handle) icnsH );
1446 	}
1447 	return result;
1448 }
1449 //	Saves the custom icon to disk - Mostly copied from Apple sample code
1450 //	A file with a custom icon must contain a resource ( 'icns', -16455 ) and have its kHasCustomIcon bit set.
1451 //	A folder with a custom icon must contain a file named "\pIcon\r" within it with a resource ( 'icns', -16455 ) and have the folders kHasCustomIcon bit set.
SaveCustomIcon(const wxString & filename,IconFamilyHandle icnsH)1452 OSErr	SaveCustomIcon( const wxString & filename, IconFamilyHandle icnsH )
1453 {
1454 	OSErr				err=fnfErr;
1455 
1456 	FSRef mFSRef;
1457 	FSSpec targetSpec;
1458 	const char * t = filename.mb_str(wxConvUTF8);
1459 	OSStatus s = FSPathMakeRef((const UInt8 *) t, &mFSRef, false);
1460 	FSCatalogInfoBitmap fields = kFSCatInfoFinderInfo;
1461 	FSCatalogInfo info;
1462 	if (s == noErr) {
1463 	  err = FSGetCatalogInfo(&mFSRef, fields, &info, NULL, &targetSpec, NULL);
1464 	}
1465 	if (err != noErr) return err;
1466 
1467 	HCreateResFile( targetSpec.vRefNum, targetSpec.parID, targetSpec.name );			//	Create the resource forked file "\pIcon\r"
1468 	short refNum = FSpOpenResFile( &targetSpec, fsCurPerm );									//	Open it with write permissions
1469 
1470 	if ( refNum == -1 )	return err;
1471 
1472 	UseResFile( refNum );
1473 	Handle h	= Get1Resource( 'icns', kCustomIconResource );
1474 	if ( h != NULL )																		//	If it already has a custom icon
1475 	{
1476 		RemoveResource( h );																//	Remove the existing custom icon
1477 		DisposeHandle( h );
1478 	}
1479 	AddResource( (Handle) icnsH, 'icns', kCustomIconResource, nil );						//	Create a new resource ( 'icns', -16455 )
1480 																							//	err	= ResError(); if ( err != noErr ) DebugStr("\p AddResource Failed" );
1481 	WriteResource( (Handle) icnsH );														//	Save the 'icns' resource
1482 																							//	err	= ResError(); if ( err != noErr ) DebugStr("\p WriteResource Failed" );
1483 	DetachResource( (Handle) icnsH );
1484 	//	err	= ResError(); if ( err != noErr ) DebugStr("\p DetachResource Failed" );
1485 
1486 	CloseResFile( refNum );																	//	Close the resource fork
1487 		//now modify the finder bit to indicate the file has a custom icon
1488 	FileInfo * mfinfo = (FileInfo *) (&(info.finderInfo));
1489 	if (!(mfinfo->finderFlags & kHasCustomIcon)) {
1490 		mfinfo->finderFlags = mfinfo->finderFlags | kHasCustomIcon;
1491 		FSSetCatalogInfo(&mFSRef, fields, &info);
1492 	}
1493 
1494 	AliasHandle			aliasH;
1495 	err = FSNewAliasMinimal(&mFSRef, &aliasH);
1496 	if (err == noErr) {
1497 		err	= SendFinderAppleEvent( aliasH, kAESync );											//	Send the Finder a kAESync AppleEvent to force it to update the icon immediately
1498 		DisposeHandle( (Handle) aliasH );
1499 	}
1500 	return( err );
1501 }
1502 //	Utility routine to send the Finder an event within its kAEFinderSuite.  We use it to send a kAESync AppleEvent which forces the Finder
1503 //	to immediately display the new icon.
SendFinderAppleEvent(AliasHandle aliasH,AEEventID appleEventID)1504 OSErr	SendFinderAppleEvent( AliasHandle aliasH, AEEventID appleEventID )
1505 {
1506 	ProcessInfoRec			processInfo;
1507 	OSErr					err;
1508 	AppleEvent				appleEvent		= { typeNull, NULL };
1509 	AEDesc					aeDesc			= { typeNull, NULL };
1510 	ProcessSerialNumber		psn				= { kNoProcess, kNoProcess };
1511 	AppleEvent				aeReply			= { typeNull, NULL };
1512 
1513 	BlockZero( (Ptr)&processInfo, sizeof(processInfo) );
1514 	processInfo.processInfoLength	= sizeof( processInfo );
1515 
1516 	for ( err = GetNextProcess( &psn ) ; err == noErr ; err = GetNextProcess( &psn ) )
1517 	{
1518 		err	= GetProcessInformation( &psn, &processInfo );
1519 		if ( (processInfo.processSignature == 'MACS') && (processInfo.processType == 'FNDR') )			//	Find the Finders PSN by searching all running processes
1520 			break;
1521 	}
1522 	if (err != noErr) return err;
1523 
1524 	err	= AECreateDesc( typeProcessSerialNumber, &psn, sizeof( psn ), &aeDesc );
1525 	if (err == noErr) {
1526 		err	= AECreateAppleEvent( kAEFinderSuite, appleEventID, &aeDesc, kAutoGenerateReturnID, kAnyTransactionID, &appleEvent );	//	Create AppleEvent (kAEFinderSuite, appleEventID)
1527 		(void) AEDisposeDesc( &aeDesc );
1528 		if (err == noErr) {
1529 			err	= AECreateDesc( typeAlias, *aliasH, GetHandleSize( (Handle)aliasH ), &aeDesc );
1530 			if (err == noErr) {
1531 				err	= AEPutParamDesc( &appleEvent, keyDirectObject, &aeDesc );
1532 				(void) AEDisposeDesc( &aeDesc );
1533 
1534 				if (err == noErr) {
1535 					err = AESend( &appleEvent, &aeReply, kAENoReply, kAENormalPriority, kNoTimeOut, NULL, NULL );		//	Send the AppleEvent to the Finder
1536 					(void) AEDisposeDesc( &aeReply );
1537 
1538 					if (err == noErr)
1539 						(void) AEDisposeDesc( &appleEvent );
1540 				}
1541 			}
1542 		}
1543 	}
1544 	return( err );
1545 }
1546 #endif
1547 
menuFileClose(wxCommandEvent &)1548 void MolDisplayWin::menuFileClose(wxCommandEvent &/*event*/) {
1549 	Close();
1550 }
1551 
FileClose(wxCloseEvent & event)1552 void MolDisplayWin::FileClose(wxCloseEvent &event) {
1553 	bool canVeto = event.CanVeto();
1554 	//First we should check to see if a save is needed which could abort the close
1555 	if (Dirty && Prefs->GetPrompt4Save()) {
1556 		//prompt the user to see if they want the file saved
1557 		//Note the message should be slightly different if we can't abort the close
1558 		int style = wxYES_NO | wxICON_QUESTION;
1559 		if (canVeto) style = style | wxCANCEL;
1560 		wxString fileText = wxT("The file ");
1561 		fileText += GetTitle();
1562 		fileText += wxT(" has unsaved changes.");
1563 		int r = wxMessageBox(wxT("Do you wish to save the current data and customizations before closing?"),
1564 							 fileText, style, this);
1565 		if (r == wxCANCEL) {
1566 			event.Veto(true);
1567 			return;
1568 		} else if (r == wxYES) {
1569 			//process the save
1570 			wxCommandEvent temp;
1571 			menuFileSave(temp);
1572 			if (Dirty) {//Dirty should be false if the save was successful
1573 				event.Veto(true);
1574 				return;
1575 			}
1576 		}
1577 	}
1578 	//Close all of the subwindows before the main window
1579 	if (bondsWindow) {
1580 		CloseBondsWindow();
1581 	}
1582 	if (coordsWindow) {
1583 		CloseCoordsWindow();
1584 	}
1585 	if (energyPlotWindow) {
1586 		CloseEnergy_plotWindow();
1587 	}
1588 	if (frequenciesWindow) {
1589 		CloseFrequenciesWindow();
1590 	}
1591 	if (inputBuilderWindow) {
1592 		CloseInputBuilderWindow();
1593 	}
1594 	if (surfacesWindow) {
1595 		CloseSurfacesWindow();
1596 	}
1597 	if (zMatCalcDlg) {
1598 		CloseZMatrixCalc();
1599 	}
1600 	if (prefsDlg) {
1601 		ClosePrefsWindow();
1602 	}
1603 	MpApp & app = wxGetApp();
1604 	//Once we decide to close the window it may be system dependant whether we
1605 	//leave an empty window up. On the Mac the window is always destroyed.
1606 #ifndef __WXMAC__
1607 /*  if ((app.WindowCount() <= 1) && canVeto) {
1608 		//This is the last window! Clear it out, but leave it open
1609 		delete MainData;
1610 		MainData = new MoleculeData(this);
1611 		delete Prefs;
1612 		Prefs = new WinPrefs;
1613 		*Prefs = *gPreferences;
1614 		Dirty = false;
1615 		SetTitle(wxT("Untitled"));
1616 		SetName(wxT("Untitled"));
1617 		event.Veto(true);
1618 		return;
1619 	}*/
1620 #endif
1621 	app.destroyMainFrame(this);
1622 	//Freeze();
1623 	Destroy();
1624 }
1625 
menuFilePage_setup(wxCommandEvent &)1626 void MolDisplayWin::menuFilePage_setup(wxCommandEvent &/*event*/) {
1627 	wxPrintData     *tempPrintData     = new wxPrintData;
1628 	wxPageSetupData *tempPageSetupData = new wxPageSetupData;
1629 
1630 	(*tempPageSetupData) = *tempPrintData;
1631 
1632 	wxPageSetupDialog pageSetupDialog(this, tempPageSetupData);
1633 
1634 	if(pageSetupDialog.ShowModal() == wxID_OK) {
1635 		(*tempPageSetupData) = pageSetupDialog.GetPageSetupData();
1636 		if(pageSetupData != NULL) delete pageSetupData;
1637 		pageSetupData = tempPageSetupData;
1638 
1639 		(*tempPrintData) = pageSetupData->GetPrintData();
1640 		if(printData != NULL) delete printData;
1641 		printData = tempPrintData;
1642 	}
1643 	else {
1644 		delete tempPageSetupData;
1645 		delete tempPrintData;
1646 	}
1647 }
1648 
menuFilePrintOptions(wxCommandEvent &)1649 void MolDisplayWin::menuFilePrintOptions(wxCommandEvent &/*event*/) {
1650 	//throw up a mini dialog to handle some app specific printing options
1651 	PrintOptions * po = new PrintOptions(this);
1652 	po->ShowModal();
1653 	po->Destroy();
1654 	Dirtify();
1655 }
1656 
menuFilePrint_preview(wxCommandEvent & event)1657 void MolDisplayWin::menuFilePrint_preview(wxCommandEvent &event) {
1658 	if (printData == NULL || pageSetupData == NULL) menuFilePage_setup(event);
1659 	if (printData == NULL || pageSetupData == NULL) return;
1660 
1661 	StopAnimations();
1662 	wxPrintDialogData printDialogData(*printData);
1663 	wxString title(_T("MacMolPlt printout"));
1664 	wxPrintPreview * preview = new wxPrintPreview(new MolPrintOut(this, title),
1665 												  new MolPrintOut(this, title),
1666 												  &printDialogData);
1667 	if (!preview->Ok()) {//failure to create the print preview
1668 		delete preview;
1669 		wxLogMessage(_("Unable to create the print preview dialog. Aborted!"));
1670 		return;
1671 	}
1672 	wxPreviewFrame * frame = new wxPreviewFrame(preview, this, _T("wxMacMolPlt print preview"),
1673 												wxPoint(100,100), wxSize(600,650));
1674 	frame->Centre(wxBOTH);
1675 	frame->Initialize();
1676 	frame->Show();
1677 }
1678 
menuFilePrint(wxCommandEvent & event)1679 void MolDisplayWin::menuFilePrint(wxCommandEvent &event) {
1680 	if (printData == NULL || pageSetupData == NULL) menuFilePage_setup(event);
1681 	if (printData == NULL || pageSetupData == NULL) return;
1682 
1683 	StopAnimations();
1684 	wxPrintDialogData printDialogData(*printData);
1685 	wxPrinter printer(&printDialogData);
1686 	wxString title(_T("MacMolPlt printout"));
1687 	MolPrintOut printout(this, title);
1688 	if (!printer.Print(this, &printout, true)) {
1689 		if (wxPrinter::GetLastError() == wxPRINTER_ERROR) {
1690 			MessageAlert("The printing attempt failed...");
1691 		}
1692 		//otherwise the user canceled printing...
1693 	} else {
1694 		//save off the print data from a successful job
1695 		(*printData) = printer.GetPrintDialogData().GetPrintData();
1696 	}
1697 	glCanvas->Draw();
1698 
1699 }
1700 
MolPrintOut(MolDisplayWin * parent,wxString & title)1701 MolPrintOut::MolPrintOut(MolDisplayWin * parent, wxString & title) :
1702 	wxPrintout(title) {
1703 	Parent = parent;
1704 }
1705 
GetPageInfo(int * minPage,int * maxPage,int * selPageFrom,int * selPageTo)1706 void MolPrintOut::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) {
1707 	*minPage = 1;
1708 	*maxPage = 1;
1709 	*selPageFrom = 1;
1710 	*selPageTo = 1;
1711 }
1712 
HasPage(int pageNum)1713 bool MolPrintOut::HasPage(int pageNum) {
1714 	return (pageNum == 1);
1715 }
1716 
OnBeginDocument(int startPage,int endPage)1717 bool MolPrintOut::OnBeginDocument(int startPage, int endPage) {
1718 	if (!wxPrintout::OnBeginDocument(startPage, endPage))
1719 		return false;
1720 	return true;
1721 }
1722 
OnPrintPage(int page)1723 bool MolPrintOut::OnPrintPage(int page) {
1724 	if (page != 1) return false;
1725 	wxDC * dc = GetDC();
1726     if (dc) {
1727 
1728 #ifdef __WXMAC__
1729 		// Preview has a different scale, which I don't quite get.
1730 		if (!IsPreview()) {
1731 			MapScreenSizeToDevice();
1732 		}
1733 		/* dc->SetBrush(*wxLIGHT_GREY_BRUSH); */
1734 #endif
1735 
1736 		wxSize dcp = dc->GetPPI();
1737 		int sh, sw;
1738 		GetPPIScreen(&sw, &sh);
1739 		float scale = (float)dcp.GetWidth()/ (float)sw;
1740 		Parent->PrintGL(dc, scale);
1741 		return true;
1742 	}
1743 	return false;
1744 }
1745 
PrintGL(wxDC * dc,const float & sFactor)1746 void MolDisplayWin::PrintGL(wxDC * dc, const float & sFactor) {
1747 	float scaleFactor = sFactor;
1748 	BeginOperation();
1749 	ProgressInd->ChangeText("Generating Hi-res image");
1750 	Prefs->CylindersForLines(true);
1751 	if (Prefs->GetFitToPage()) {
1752 		int screenWidth, screenHeight;
1753 		glCanvas->GetSize(&screenWidth, &screenHeight);
1754 		float wRatio = ((float) screenWidth)/((float) screenHeight);
1755 		int pageWidth, pageHeight;
1756 		dc->GetSize(&pageWidth, &pageHeight);
1757 		float pRatio = ((float) pageWidth)/((float) pageHeight);
1758 		if (wRatio >= pRatio) { //base scaleup on page width
1759 			scaleFactor = ((float) pageWidth)/((float) screenWidth);
1760 		} else {    //base scaleup on page height
1761 			scaleFactor = ((float) pageHeight)/((float) screenHeight);
1762 		}
1763 	}
1764 	int scale = scaleFactor;
1765 	if (scale < 1) scale = 1;
1766 	Prefs->SetLineWidth(scale);
1767 	glCanvas->GenerateHiResImage(dc, scaleFactor, ProgressInd, Prefs->GetCenterOnPage(),
1768 								 Prefs->GetFramePage());
1769 	Prefs->SetLineWidth(1);
1770 	Prefs->CylindersForLines(false);
1771 	FinishOperation();
1772 }
1773 /* Edit menu */
1774 
menuEditUndo(wxCommandEvent &)1775 void MolDisplayWin::menuEditUndo(wxCommandEvent &/*event*/) {
1776 	if (mUndoBuffer.GetPosition() == mUndoBuffer.GetOperationCount()) {
1777 		CreateFrameSnapShot();
1778 		mUndoBuffer.SetPosition(mUndoBuffer.GetOperationCount()-1);
1779 	}
1780 	mUndoBuffer.UndoOperation();
1781 	mHighliteState = false;
1782 	for (long i=0; i<MainData->cFrame->NumAtoms; i++) {
1783 		if (MainData->cFrame->Atoms[i].GetSelectState()) {
1784 			mHighliteState = true;
1785 			break;
1786 		}
1787 	}
1788 	ResetModel(false);
1789 	AtomsChanged(true, false);
1790 
1791 	menuEdit->UpdateUI(); // force accelerators to reenable
1792 }
1793 
menuEditRedo(wxCommandEvent &)1794 void MolDisplayWin::menuEditRedo(wxCommandEvent &/*event*/) {
1795 	mUndoBuffer.RedoOperation();
1796 	mHighliteState = false;
1797 	for (long i=0; i<MainData->cFrame->NumAtoms; i++) {
1798 		if (MainData->cFrame->Atoms[i].GetSelectState()) {
1799 			mHighliteState = true;
1800 			break;
1801 		}
1802 	}
1803 	ResetModel(false);
1804 	AtomsChanged(true, false);
1805 
1806 	menuEdit->UpdateUI(); // force accelerators to reenable
1807 }
1808 
menuEditCut(wxCommandEvent &)1809 void MolDisplayWin::menuEditCut(wxCommandEvent &/*event*/) {
1810 }
1811 
menuEditCopy(wxCommandEvent &)1812 void MolDisplayWin::menuEditCopy(wxCommandEvent &/*event*/) {
1813 	StopAnimations();
1814 	//Put the image onto the clipboard
1815 	if (wxTheClipboard->Open()) {
1816 		wxDataObjectComposite * comp = new wxDataObjectComposite();
1817 		comp->Add(new wxBitmapDataObject(glCanvas->getImage(0,0)), true);
1818 
1819 		//Next add a CML version for internal pasting
1820 		BufferFile *Buffer=NULL;
1821 		char *	CML=NULL;
1822 		try {	//First get the size needed for the buffer
1823 			Buffer = new BufferFile(CML, 0);
1824 			Buffer->SetOutput(false);	//no actual writing, just keep track of the total size
1825 			long datalength = MainData->WriteCMLFile(Buffer, Prefs, NULL, false, true);
1826 			delete Buffer;
1827 			CML = new char[datalength+1];
1828 			CML[datalength]='\0';
1829 			Buffer = new BufferFile(CML, datalength);
1830 			MainData->WriteCMLFile(Buffer, Prefs, NULL, false, true);
1831 
1832 			comp->Add(new wxCMLDataObject(CML), false);
1833 		}
1834 		catch (MemoryError) {
1835 			if (Buffer) delete Buffer;
1836 			if (CML) delete [] CML;
1837 		}
1838 		catch (FileError) {		//This shouldn't happen
1839 			if (Buffer) delete Buffer;
1840 			if (CML) delete [] CML;
1841 		}
1842 		wxTheClipboard->SetData(comp);
1843 		wxTheClipboard->Close();
1844 	}
1845 }
1846 
menuEditCopyCoordinates(wxCommandEvent &)1847 void MolDisplayWin::menuEditCopyCoordinates(wxCommandEvent &/*event*/) {
1848 	StopAnimations();
1849 	CopyCoordinates(0);
1850 }
menuEditCopyNWChemCoordinates(wxCommandEvent &)1851 void MolDisplayWin::menuEditCopyNWChemCoordinates(wxCommandEvent &/*event*/) {
1852 	StopAnimations();
1853 	CopyCoordinates(2);
1854 }
CopyCoordinates(short ctype) const1855 void MolDisplayWin::CopyCoordinates(short ctype) const {
1856 	//Now copy the coords
1857 	Frame *     lFrame = MainData->cFrame;
1858 	wxString textBuffer;
1859 
1860 	try {
1861 		if (ctype == 0) {	// GAMESS style atomic_symbol  atomic_number  x  y  z
1862 			wxString    Label;
1863 			for (long iatm=0; iatm<lFrame->NumAtoms; iatm++) {
1864 				if (mHighliteState && !lFrame->Atoms[iatm].GetSelectState()) continue;
1865 				Prefs->GetAtomLabel(lFrame->Atoms[iatm].GetType()-1, Label);
1866 				textBuffer.Append(Label);
1867 				Label.Printf(wxT("   %5.1f  %13.8f  %13.8f  %13.8f\r"),
1868 								 (float) (lFrame->Atoms[iatm].GetType()),
1869 								 lFrame->Atoms[iatm].Position.x, lFrame->Atoms[iatm].Position.y,
1870 								 lFrame->Atoms[iatm].Position.z);
1871 				textBuffer.Append(Label);
1872 			}
1873 		} else if (ctype == 1) {	// GAMESS style z-matrix
1874 			//Make a guess for the Handle size based on the # of atoms and the line format
1875 			long datalength = lFrame->NumAtoms*70*sizeof(char);
1876 			char * lText = new char[datalength+1];
1877 			//Create a bufferFile object to protect the text buffer from overrun
1878 			BufferFile *Buffer = new BufferFile(lText, datalength);
1879 
1880 			Internals * IntCoords = MainData->GetInternalCoordinates();
1881 			if (IntCoords) IntCoords->WriteCoordinatesToFile(Buffer, MainData, Prefs);
1882 
1883 			lText[Buffer->GetFilePos()] = '\0';
1884 			textBuffer = wxString(lText, wxConvUTF8);
1885 			delete Buffer;
1886 			delete [] lText;
1887 		} else if (ctype == 2) {
1888 			wxString    Label;
1889 			for (long iatm=0; iatm<lFrame->NumAtoms; iatm++) {
1890 				if (mHighliteState && !lFrame->Atoms[iatm].GetSelectState()) continue;
1891 				Prefs->GetAtomLabel(lFrame->Atoms[iatm].GetType()-1, Label);
1892 				textBuffer.Append(Label);
1893 				Label.Printf(wxT("   %13.8f  %13.8f  %13.8f\r"),
1894 							 lFrame->Atoms[iatm].Position.x, lFrame->Atoms[iatm].Position.y,
1895 							 lFrame->Atoms[iatm].Position.z);
1896 				textBuffer.Append(Label);
1897 			}
1898 		}
1899 	}
1900 	catch (...) {   //The buffer length was probably exceeded, since this shouldn't happen
1901 		return;
1902 	}
1903 	//Put the text onto the clipboard
1904 	if (wxTheClipboard->Open()) {
1905 		wxTheClipboard->SetData(new wxTextDataObject(textBuffer));
1906 		wxTheClipboard->Close();
1907 	}
1908 }
1909 
menuEditPaste(wxCommandEvent &)1910 void MolDisplayWin::menuEditPaste(wxCommandEvent &/*event*/) {
1911 	StopAnimations();
1912 	if (wxTheClipboard->Open()) {
1913 		if (wxTheClipboard->IsSupported(_("CML"))) {
1914 			wxCMLDataObject cmlObject;
1915 			if (wxTheClipboard->GetData(cmlObject)) {
1916 				char * CML = cmlObject.GetCML();
1917 				if (CML) {
1918 					BeginOperation();
1919 					try {
1920 						if ((MainData->NumFrames > 1)||InEditMode()) {
1921 							MoleculeData *	tdatap = new MoleculeData(this);
1922 							if (!tdatap) return;
1923 							BufferFile *Buffer = new BufferFile(CML, strlen(CML));
1924 							if (tdatap->OpenCMLFile(Buffer, Prefs, NULL, ProgressInd, false, false)) {
1925 								if (InEditMode()) {
1926 									CreateFrameSnapShot();
1927 									//In builder mode copy the selected atoms over
1928 									bool CopyAllAtoms = true;
1929 									for (long i=0; i<tdatap->cFrame->NumAtoms; i++) {
1930 										if (tdatap->cFrame->Atoms[i].GetSelectState()) {
1931 											CopyAllAtoms = false;
1932 											break;
1933 										}
1934 									}
1935 									long initialAtomCount = MainData->cFrame->NumAtoms;
1936 									for (long i=0; i<tdatap->cFrame->NumAtoms; i++) {
1937 										if (CopyAllAtoms || tdatap->cFrame->Atoms[i].GetSelectState()) {
1938 											MainData->NewAtom(tdatap->cFrame->Atoms[i], false);
1939 										}
1940 									}
1941 									for (long i=0; i<initialAtomCount; i++) {
1942 										MainData->cFrame->SetAtomSelection(i, false);
1943 									}
1944 									for (long i=initialAtomCount; i<MainData->cFrame->NumAtoms; i++) {
1945 										MainData->cFrame->SetAtomSelection(i, true);
1946 									}
1947 									MainData->AtomAdded();//update global structures after all atoms are added
1948 									if (Prefs->GetAutoBond())
1949 										MainData->cFrame->SetBonds(Prefs, false, ProgressInd);
1950 									mHighliteState = true;
1951 								} else {
1952 									tdatap->cFrame->PreviousFrame = MainData->cFrame->PreviousFrame;
1953 									tdatap->cFrame->NextFrame = MainData->cFrame->NextFrame;
1954 									if (MainData->cFrame->PreviousFrame)
1955 										MainData->cFrame->PreviousFrame->NextFrame = tdatap->cFrame;
1956 									if (MainData->cFrame->NextFrame)
1957 										MainData->cFrame->NextFrame->PreviousFrame = tdatap->cFrame;
1958 									MainData->cFrame->PreviousFrame = MainData->cFrame->NextFrame = NULL;
1959 									if (MainData->cFrame == MainData->Frames) MainData->Frames = tdatap->cFrame;
1960 									delete MainData->cFrame;
1961 									MainData->cFrame = tdatap->cFrame;
1962 									if (tdatap->MaxAtoms > MainData->MaxAtoms) {
1963 										MainData->MaxAtoms = tdatap->MaxAtoms;
1964 										if (MainData->RotCoords) delete [] MainData->RotCoords;
1965 										MainData->RotCoords = tdatap->RotCoords;
1966 										tdatap->RotCoords = NULL;
1967 									}
1968 									if (tdatap->Basis && !MainData->Basis) {
1969 										MainData->Basis = tdatap->Basis;
1970 										tdatap->Basis = NULL;
1971 									}
1972 									tdatap->cFrame = tdatap->Frames = NULL; //this frame is now in use in MainData
1973 								}
1974 							}
1975 							if (Buffer) delete Buffer;
1976 							delete tdatap;
1977 						} else {
1978 							BufferFile *Buffer = new BufferFile(CML, strlen(CML));
1979 							if (MainData->OpenCMLFile(Buffer, Prefs, NULL, ProgressInd, true, true)) {
1980 							//if (MainData->OpenCMLFile(Buffer, Prefs, &tempData, true)) {
1981 				//				FileSave = 1;
1982 							}
1983 							if (Buffer) delete Buffer;
1984 						}
1985 					}
1986 					catch (MemoryError) {
1987 						MessageAlert("Insufficient memory to complete the paste!");
1988 						Close();
1989 						return;
1990 					}
1991 					catch (DataError) {
1992 						MessageAlert("Invalid data encountered!");
1993 						Close();
1994 						return;
1995 					}
1996 					FinishOperation();
1997 					MainData->ResetRotation();
1998 					FrameChanged();
1999 				}
2000 			}
2001 			wxTheClipboard->Close();
2002 		} else if (wxTheClipboard->IsSupported(wxDF_TEXT)) {
2003 			wxTheClipboard->Close();
2004 			PasteText();
2005 		} else
2006 			wxTheClipboard->Close();
2007 	}
2008 }
PasteText(void)2009 void MolDisplayWin::PasteText(void) {
2010 	StopAnimations();
2011 	//relax this restriction later (while in build mode)
2012 	if ((MainData->cFrame->NumAtoms != 0)&&!InEditMode()) return;    //Do not allow pasting if there are already atoms in this frame
2013 	if (wxTheClipboard->Open()) {
2014 		if (wxTheClipboard->IsSupported(wxDF_TEXT)) {
2015 			if (InEditMode()) CreateFrameSnapShot();
2016 			long        iline, test, Type;
2017 			CPoint3D    Position, offset;
2018 			long initialAtomCount = MainData->cFrame->NumAtoms;
2019 
2020 			wxTextDataObject data;
2021 			wxTheClipboard->GetData(data);
2022 			wxString text = data.GetText();
2023 			char * tbuf = new char[text.Length()+1];
2024 			strncpy(tbuf, text.ToAscii(), text.Length()+1);
2025 			//Clean up the unicode to 7 bit ASCII conversion. WX replaces anything non
2026 			//7-bit with an '_' so convert those into spaces as the only possible guess.
2027 			for (int i=0; i<=text.Length(); i++) if (tbuf[i]=='_') tbuf[i] = ' ';
2028 			BufferFile * TextBuffer=NULL;
2029 			try {
2030 				TextBuffer = new BufferFile(tbuf, text.Length());
2031 				if ((MainData->NumFrames == 1)&&(MainData->cFrame->NumAtoms==0)) {
2032 					//If this is the only frame, make sure it is init'ed
2033 					InitRotationMatrix(MainData->TotalRotation);
2034 				}
2035 				long NumLines = TextBuffer->GetNumLines(-1);
2036 				// There may be up to NumLines atoms so dimension memory accordingly
2037 				if (!MainData->SetupFrameMemory(NumLines+initialAtomCount, 0)) {
2038 					delete TextBuffer;
2039 					delete [] tbuf;
2040 					wxTheClipboard->Close();
2041 					return;
2042 				}
2043 
2044 				/*Now interpret each of the lines*/
2045 				for (iline=0; iline < NumLines; iline++) {
2046 					char LineText[kMaxLineLength];
2047 
2048 					TextBuffer->GetLine(LineText);
2049 					//Parse the current line: All values will be set in place if the
2050 					//parse is successful (test will return (-) if not). Normal modes
2051 					//shouldn't be pasted so pass in 0 for Mode.
2052 					test = ParseCartLine(LineText, &Type,&Position, &offset, 0);
2053 					if (test > 0) { /*something was wrong with this line so skip it*/
2054 
2055 						//A special atom was entered, store its offset.
2056 						if (Type > 115) {
2057 							if (Type > 255)
2058 								if (((Type - 255) < 1)||((Type - 255) > NumLines)) break;
2059 							if (!MainData->cFrame->AddSpecialAtom(offset, iline)) break;
2060 						}
2061 
2062 						MainData->NewAtom(Type, Position, false);
2063 					}
2064 				}
2065 				MainData->AtomAdded();
2066 				//Done with the text handle so unlock it
2067 				delete TextBuffer;
2068 			}
2069 			catch (...) {
2070 				//Hmm there was a failure in the paste - what should we do to cleanup?
2071 				if (TextBuffer) delete TextBuffer;
2072 			}
2073 			delete [] tbuf;
2074 
2075 			if (iline == 0) {   /*No atoms were found so clear the memory I just allocated*/
2076 				wxTheClipboard->Close();
2077 				return;
2078 			}
2079 
2080 			//If there were special atoms found turn on drawing by default
2081 			if (MainData->cFrame->SpecialAtoms) MainData->SetSpecialAtomDrawMode(true);
2082 
2083 			for (long i=0; i<initialAtomCount; i++) {
2084 				MainData->cFrame->SetAtomSelection(i, false);
2085 			}
2086 			for (long i=initialAtomCount; i<MainData->cFrame->NumAtoms; i++) {
2087 				MainData->cFrame->SetAtomSelection(i, true);
2088 			}
2089 			if (Prefs->GetAutoBond())
2090 				MainData->cFrame->SetBonds(Prefs, false, ProgressInd);
2091 			//Now reset the display to take into account the new atoms
2092 			if (initialAtomCount == 0) {
2093 				MainData->CenterModelWindow();
2094 				if (MainData->MaxSize > 0.1) MainData->WindowSize = 2.0*MainData->MaxSize;
2095 				MainData->ResetRotation();
2096 			} else {
2097 				mHighliteState = true;
2098 			}
2099 			FrameChanged();
2100 		}
2101 		wxTheClipboard->Close();
2102 	}
2103 }
2104 
menuEditClear(wxCommandEvent &)2105 void MolDisplayWin::menuEditClear(wxCommandEvent &/*event*/) {
2106 	DeleteSelected();
2107 }
2108 
menuEditSelectAll(wxCommandEvent &)2109 void MolDisplayWin::menuEditSelectAll(wxCommandEvent &/*event*/) {
2110 
2111 	// Select each atom in the current frame and update.
2112 	SetHighliteMode(true);
2113 	for (int i = 0; i < MainData->cFrame->NumAtoms; i++) {
2114 		MainData->cFrame->SetAtomSelection(i, true);
2115 	}
2116 	SelectionChanged(true);
2117 	UpdateModelDisplay();
2118 
2119 	menuEdit->UpdateUI(); // force accelerators to reenable
2120 
2121 }
2122 
menuEditSelectNone(wxCommandEvent &)2123 void MolDisplayWin::menuEditSelectNone(wxCommandEvent &/*event*/) {
2124 
2125 	// Deselect each atom in the current frame and update.
2126 	MainData->cFrame->resetAllSelectState();
2127 	SetHighliteMode(false);
2128 	SelectionChanged(true);
2129 	UpdateModelDisplay();
2130 
2131 	menuEdit->UpdateUI(); // force accelerators to reenable
2132 
2133 }
2134 
menuBuilderShowToolbar(wxCommandEvent & event)2135 void MolDisplayWin::menuBuilderShowToolbar(wxCommandEvent &event) {
2136 
2137 	ShowToolbar(event.IsChecked());
2138 
2139 }
2140 
ShowToolbar(bool enable)2141 void MolDisplayWin::ShowToolbar(bool enable) {
2142 
2143 	bool needs_change;
2144 
2145 	Prefs->SetToolbarShown(enable);
2146 
2147 	needs_change = Prefs->ToolbarShown() == (toolbar == NULL);
2148 	if (!needs_change) {
2149 		return;
2150 	}
2151 
2152 	if (Prefs->ToolbarShown()) {
2153 		toolbar = CreateToolBar(wxTB_HORIZONTAL | wxTB_FLAT | wxTB_TEXT);
2154 
2155 		//The original plain xpms
2156 #include "xpms/view.xpm"
2157 #include "xpms/rect_lasso.xpm"
2158 #include "xpms/hand.xpm"
2159 
2160 #if wxCHECK_VERSION(2, 8, 0)
2161 		wxStandardPathsBase& gStdPaths = wxStandardPaths::Get();
2162 		wxString pathname = gStdPaths.GetResourcesDir();
2163 #else
2164 		wxString pathname = gStdPaths.GetDataDir();
2165 #ifdef __WXMAC__
2166 		//wxWidgets has a funny idea of where the resources are stored. It locates them as "SharedSupport"
2167 		//but xcode is putting them in Resources.
2168 		pathname.Remove(pathname.Length() - 13);
2169 		pathname += wxT("Resources");
2170 #endif
2171 #endif
2172 		// toolbar->SetMargins(5,5);
2173 		toolbar->SetToolBitmapSize(wxSize(16, 15));
2174 
2175 		wxBitmap enabled_bmp;
2176 		wxBitmap enabled_bmp2;
2177 
2178 //		enabled_bmp = wxBitmap(view_xpm);
2179 		if (! enabled_bmp.LoadFile(pathname + wxT("/view.png"), wxBITMAP_TYPE_PNG))
2180 			enabled_bmp = wxBitmap(view_xpm);
2181 //		std::cout << "view w="<< enabled_bmp.GetWidth() << " h="<<enabled_bmp.GetHeight()<<std::endl;
2182 //		enabled_bmp.SetWidth(16);
2183 //		enabled_bmp.SetHeight(15);
2184 		toolbar->AddRadioTool(MMP_TOOL_ARROW, _("View"), enabled_bmp,
2185 			wxNullBitmap);
2186 
2187 //		std::cout << "lasso w="<< enabled_bmp.GetWidth() << " h="<<enabled_bmp.GetHeight()<<std::endl;
2188 		enabled_bmp = wxBitmap(rect_lasso_xpm);
2189 		enabled_bmp.SetWidth(16);
2190 		enabled_bmp.SetHeight(15);
2191 		toolbar->AddRadioTool(MMP_TOOL_LASSO, _("Select"), enabled_bmp,
2192 			wxNullBitmap);
2193 
2194 		enabled_bmp = wxBitmap(hand_xpm);
2195 //		enabled_bmp.LoadFile(pathname + wxT("/test.jpg"), wxBITMAP_TYPE_JPEG);
2196 //		std::cout << "hand w="<< enabled_bmp.GetWidth() << " h="<<enabled_bmp.GetHeight()<<std::endl;
2197 //		enabled_bmp.SetWidth(16);
2198 //		enabled_bmp.SetHeight(15);
2199 
2200 		toolbar->AddRadioTool(MMP_TOOL_HAND, _("Edit"), enabled_bmp,
2201 			wxNullBitmap);
2202 
2203 		toolbar->AddSeparator();
2204 		toolbar->Realize();
2205 
2206 	} else {
2207 		delete toolbar;
2208 		toolbar = NULL;
2209 
2210 		SetToolBar(NULL);
2211 
2212 		//Default to not allowing undo once out of edit mode
2213 		mUndoBuffer.Clear();
2214 	}
2215 
2216 	glCanvas->SizeChanged();
2217 }
2218 
menuBuilderShowBuildTools(wxCommandEvent &)2219 void MolDisplayWin::menuBuilderShowBuildTools(wxCommandEvent &/*event*/) {
2220 	ToggleBuilderPalette();
2221 }
2222 
OnSaveStructureUpdate(wxUpdateUIEvent & event)2223 void MolDisplayWin::OnSaveStructureUpdate(wxUpdateUIEvent& event) {
2224 
2225 	// Only require some atoms to be selected in order to save a
2226 	// prototype. A single atom as a prototype doesn't make sense.
2227 	event.Enable(MainData->cFrame->GetNumAtomsSelected() > 1);
2228 
2229 }
2230 
menuBuilderSaveStructure(wxCommandEvent &)2231 void MolDisplayWin::menuBuilderSaveStructure(wxCommandEvent &/*event*/) {
2232 
2233 	StopAnimations();
2234 	Frame *frame = MainData->cFrame;
2235 	mpAtom *atoms = frame->Atoms;
2236 	Bond *bonds = frame->Bonds;
2237 	Structure *struc;
2238 	int si = 0;
2239 	int ai, bi;
2240 	int *new_ids;
2241 	int natoms_selected = frame->GetNumAtomsSelected();
2242 	bool has_abinitio = false, has_efrag = false;
2243 	int fragId = -1;
2244 
2245 	// Don't bother adding a prototype if nothing's selected.
2246 	if (!natoms_selected) {
2247 		return;
2248 	}
2249 
2250 	// We make space for the new structure here.  The memory will be owned
2251 	// by the build palette.
2252 	struc = new Structure;
2253 	struc->natoms = natoms_selected;
2254 	struc->atoms = new mpAtom[struc->natoms];
2255 
2256 	// The IDs of the selected atoms will be collapsed so that they're
2257 	// consecutive within the structure.  But to export bonds to the structure,
2258 	// we need a mapping from the current ID to the new ID.
2259 	new_ids = new int[frame->NumAtoms];
2260 
2261 	si = 0;
2262 	for (ai = 0; ai < frame->NumAtoms; ai++) {
2263 		if (frame->GetAtomSelection(ai)) {
2264 			struc->atoms[si] = atoms[ai];
2265 			new_ids[ai] = si;
2266 			si++;
2267 
2268 			// A prototype can be any number of all electron atoms or one
2269 			// effective fragment.
2270 			if (atoms[ai].IsEffectiveFragment()) {
2271 				has_efrag = true;
2272 				if (fragId < 0) {
2273 					fragId = atoms[ai].GetFragmentNumber();
2274 					struc->FragName = MainData->FragmentNames[fragId-1];
2275 				} else if (fragId != atoms[ai].GetFragmentNumber()) {
2276 					MessageAlert("A prototype can consist of only a single effective fragment.");
2277 					delete struc;
2278 					delete[] new_ids;
2279 					return;
2280 				}
2281 			} else {
2282 				has_abinitio = true;
2283 			}
2284 
2285 		} else {
2286 			new_ids[ai] = -1;
2287 		}
2288 	}
2289 
2290 	if (has_abinitio && has_efrag) {
2291 		MessageAlert("Prototypes can not mix all-electron and effective fragment atoms.");
2292 		delete struc;
2293 		delete[] new_ids;
2294 		return;
2295 	}
2296 
2297 	// If this prototype is an effective fragment with a special definition,
2298 	// we have to save out its raw text.
2299 	if (struc->FragName.size()) {
2300 		std::map<std::string, EFrag>::iterator frag;
2301 		frag = MainData->efrags.find(struc->FragName);
2302 		if (frag != MainData->efrags.end()) {
2303 			struc->frag_def = std::string(frag->second.GetText());
2304 		}
2305 	}
2306 
2307 	Bond new_bond;
2308 	std::vector<Bond> new_bonds;
2309 	for (bi = 0; bi < frame->NumBonds; bi++) {
2310 		if (frame->GetAtomSelection(bonds[bi].Atom1) &&
2311 		    frame->GetAtomSelection(bonds[bi].Atom2)) {
2312 			new_bond = Bond(bonds[bi]);
2313 			new_bond.Atom1 = new_ids[new_bond.Atom1];
2314 			new_bond.Atom2 = new_ids[new_bond.Atom2];
2315 			new_bonds.push_back(new_bond);
2316 		}
2317 	}
2318 
2319 	struc->nbonds = new_bonds.size();
2320 	struc->bonds = new Bond[MAX(struc->nbonds,10)];
2321 	if (new_bonds.size() > 0) {
2322 		memcpy(struc->bonds, &(new_bonds[0]), sizeof(Bond) * struc->nbonds);
2323 	}
2324 	delete[] new_ids;
2325 
2326 	wxTextEntryDialog *dlg =
2327 	   new wxTextEntryDialog(this,
2328 				_("Please enter a name for this custom prototype:"),
2329 				_("Add Prototype"));
2330 	int result;
2331 	do {
2332 		result = dlg->ShowModal();
2333 	} while (result != wxID_CANCEL && dlg->GetValue().Len() <= 0);
2334 
2335 	struc->name = dlg->GetValue();
2336 
2337 	if (result == wxID_OK) {
2338 		BuilderTool->AddUserStructure(struc);
2339 	} else {
2340 		delete struc;
2341 	}
2342 
2343 }
FindFragmentDef(std::string fragName)2344 std::map<std::string, EFrag>::const_iterator MolDisplayWin::FindFragmentDef(std::string fragName) {
2345 	std::map<std::string, EFrag>::const_iterator result;
2346 	//first search in the existing list of fragments
2347 	result = MainData->efrags.find(fragName);
2348 	if (result == MainData->efrags.end()) {
2349 		//It's not in the existing list. Search in the builder library
2350 		Structure *struc = BuilderTool->FindFragment(fragName);
2351 		if (struc) {
2352 			//found it. Add it to the current list of fragment definitions
2353 			MainData->efrags.insert(std::pair<std::string, EFrag>(struc->FragName, struc->frag_def));
2354 			result = MainData->efrags.find(fragName);
2355 		}
2356 	}
2357 	return result;
2358 }
2359 
OnShowNormalScreen(wxUpdateUIEvent & event)2360 void MolDisplayWin::OnShowNormalScreen(wxUpdateUIEvent& event) {
2361 	event.Check(show_fullscreen);
2362 }
2363 
menuViewShowFullScreen(wxCommandEvent &)2364 void MolDisplayWin::menuViewShowFullScreen(wxCommandEvent &/*event*/) {
2365 	show_fullscreen = !show_fullscreen;
2366 	ShowFullScreen(show_fullscreen,
2367 				   wxFULLSCREEN_NOCAPTION | wxFULLSCREEN_NOBORDER);
2368 }
2369 
menuViewShowNormalMode(wxCommandEvent &)2370 void MolDisplayWin::menuViewShowNormalMode(wxCommandEvent &/*event*/) {
2371 	MainData->SetDrawMode(1-MainData->GetDrawMode());
2372 	ResetModel(false);
2373 	Dirtify();
2374 }
2375 
menuViewPrevNormalMode(wxCommandEvent &)2376 void MolDisplayWin::menuViewPrevNormalMode(wxCommandEvent &/*event*/) {
2377 	if (MainData->cFrame->Vibs) {
2378 		if (MainData->cFrame->Vibs->CurrentMode>0) {
2379 			ChangeModes(MainData->cFrame->Vibs->CurrentMode - 1);
2380 		}
2381 	}
2382 }
menuViewNextNormalMode(wxCommandEvent &)2383 void MolDisplayWin::menuViewNextNormalMode(wxCommandEvent &/*event*/) {
2384 	if (MainData->cFrame->Vibs) {
2385 		if (MainData->cFrame->Vibs->CurrentMode<(MainData->cFrame->Vibs->NumModes-1)) {
2386 			ChangeModes(MainData->cFrame->Vibs->CurrentMode + 1);
2387 		}
2388 	}
2389 }
menuViewOffsetAlongMode(wxCommandEvent &)2390 void MolDisplayWin::menuViewOffsetAlongMode(wxCommandEvent &/*event*/) {
2391 	StopAnimations();
2392 	CoordinateOffset * co = new CoordinateOffset(this);
2393 	co->ShowModal();
2394 	co->Destroy();
2395 }
OnViewGradientUpdate(wxUpdateUIEvent & event)2396 void MolDisplayWin::OnViewGradientUpdate(wxUpdateUIEvent& event) {
2397 	event.Enable(false);
2398 	event.Check(false);
2399 	event.SetText(_T("Show Energy Gradient\tCtrl+G"));
2400 	if (MainData->GradientVectorAvailable()) {
2401 		event.Enable(true);
2402 		event.Check(Prefs->DisplayGradient());
2403 		if (Prefs->InvertGradient()) event.SetText(_T("Show Force\tCtrl+G"));
2404 	}
2405 }
menuViewShowGradient(wxCommandEvent &)2406 void MolDisplayWin::menuViewShowGradient(wxCommandEvent &/*event*/) {
2407 	Prefs->DisplayGradient(1-Prefs->DisplayGradient());
2408 	ResetModel(false);
2409 	Dirtify();
2410 }
2411 
menuViewCenter(wxCommandEvent &)2412 void MolDisplayWin::menuViewCenter(wxCommandEvent &/*event*/) {
2413 	MainData->CenterModelWindow();
2414 	ResetModel(false);
2415 	Dirtify();
2416 }
menuViewToggleAutoRotation(wxCommandEvent &)2417 void MolDisplayWin::menuViewToggleAutoRotation(wxCommandEvent &/*event*/) {
2418 	if (rotate_timer.IsRunning()) {
2419 		rotate_timer.Stop();
2420 		Prefs->SetAutoRotating(false);
2421 	} else {
2422 		int z;
2423 		Prefs->GetAutoRotationVector(inertia.x, inertia.y, z);
2424 		rotate_timer.Start(33, false);
2425 		Prefs->SetAutoRotating(true);
2426 	}
2427 }
OnModeAnimation(wxTimerEvent &)2428 void MolDisplayWin::OnModeAnimation(wxTimerEvent & /*event*/) {
2429 	if (ModeAnimationData) {
2430 		if (ModeAnimationData->iPoint == ModeAnimationData->NumPoints ||
2431 		    ModeAnimationData->iPoint == -ModeAnimationData->NumPoints) {
2432 			ModeAnimationData->inc *= -1;
2433 			ModeAnimationData->offsetFactor *= -1.0;
2434 		}
2435 		ModeAnimationData->iPoint += ModeAnimationData->inc;
2436 		Frame * lFrame = MainData->cFrame;
2437 		mpAtom * lAtoms = lFrame->Atoms;
2438 		for (int iatm=0; iatm<(lFrame->NumAtoms); iatm++) {
2439 			lAtoms[iatm].Position.x += ModeAnimationData->offsetFactor*(ModeAnimationData->ModeOffset[iatm].x);
2440 			lAtoms[iatm].Position.y += ModeAnimationData->offsetFactor*(ModeAnimationData->ModeOffset[iatm].y);
2441 			lAtoms[iatm].Position.z += ModeAnimationData->offsetFactor*(ModeAnimationData->ModeOffset[iatm].z);
2442 		}
2443 		ResetModel(false);
2444 	}
2445 }
menuViewAnimateMode(wxCommandEvent &)2446 void MolDisplayWin::menuViewAnimateMode(wxCommandEvent &/*event*/) {
2447 	if (ModeAnimationData) { //if data already exists toggle off the animation
2448 		ModeAnimationData->m_timer.Stop();
2449 		MainData->SetDrawMode(ModeAnimationData->SavedDrawMode);
2450 		for (int iatm=0; iatm<(MainData->cFrame->NumAtoms); iatm++) {
2451 			MainData->cFrame->Atoms[iatm].Position = ModeAnimationData->SavedCoordinates[iatm];
2452 		}
2453 		delete ModeAnimationData;
2454 		ModeAnimationData = NULL;
2455 		ResetModel(false);
2456 	} else {
2457 		if (!MainData->cFrame->Vibs) return;
2458 		Frame * lFrame = MainData->cFrame;
2459 		ModeAnimationData = new ModeAnimation();
2460 		ModeAnimationData->SavedDrawMode = false;
2461 		ModeAnimationData->iPoint = 1;
2462 		ModeAnimationData->inc = 1;
2463 		ModeAnimationData->SavedCoordinates.reserve(lFrame->NumAtoms);
2464 		ModeAnimationData->ModeOffset.reserve(lFrame->NumAtoms);
2465 
2466 		if (MainData->GetDrawMode()) {
2467 			ModeAnimationData->SavedDrawMode = true;
2468 			if (!Prefs->GetAnimateMode()) MainData->SetDrawMode(false);
2469 		}
2470 		long cmode = (lFrame->NumAtoms)*(lFrame->Vibs->CurrentMode);
2471 		//The offset factor may need some work yet...
2472 		ModeAnimationData->NumPoints = Prefs->GetAnimationSpeed();
2473 		ModeAnimationData->offsetFactor = 1.0/(4.5*Prefs->GetAnimationSpeed());
2474 		float   VectorScale = Prefs->GetVectorScale();
2475 		mpAtom * lAtoms = lFrame->Atoms;
2476 		CPoint3D temp;
2477 		for (int iatm=0; iatm<(lFrame->NumAtoms); iatm++) {
2478 			ModeAnimationData->SavedCoordinates.push_back(lAtoms[iatm].Position);
2479 			temp = lFrame->Vibs->NormMode[iatm+cmode];
2480 			temp *= VectorScale;
2481 			ModeAnimationData->ModeOffset.push_back(temp);
2482 		}
2483 		ModeAnimationData->m_timer.SetOwner(this, MMP_ANIMATEMODETIMER);
2484 		ModeAnimationData->m_timer.Start(30);//Go for about 30 frames per second
2485 	}
2486 }
menuViewShowAxis(wxCommandEvent &)2487 void MolDisplayWin::menuViewShowAxis(wxCommandEvent &/*event*/) {
2488 	MainData->SetShowAxis(1-MainData->ShowAxis());
2489 	UpdateModelDisplay();
2490 	Dirtify();
2491 }
menuViewShowSymmetryOperators(wxCommandEvent &)2492 void MolDisplayWin::menuViewShowSymmetryOperators(wxCommandEvent &/*event*/) {
2493 	Prefs->ShowSymmetryOperators(1-Prefs->ShowSymmetryOperators());
2494 	UpdateModelDisplay();
2495 	Dirtify();
2496 }
2497 
menuViewHideAtomLabels(wxCommandEvent &)2498 void MolDisplayWin::menuViewHideAtomLabels(wxCommandEvent &/*event*/)
2499 {
2500 	Prefs->ShowAtomicSymbolLabels(false);
2501 	Prefs->ShowAtomNumberLabels(false);
2502 	UpdateModelDisplay();
2503 	Dirtify();
2504 }
2505 
menuViewShowAtomLabel(wxCommandEvent &)2506 void MolDisplayWin::menuViewShowAtomLabel(wxCommandEvent &/*event*/)
2507 {
2508 	Prefs->ShowAtomicSymbolLabels(true);
2509 	Prefs->ShowAtomNumberLabels(false);
2510 	UpdateModelDisplay();
2511 	Dirtify();
2512 }
2513 
menuViewShowAtomNumber(wxCommandEvent &)2514 void MolDisplayWin::menuViewShowAtomNumber(wxCommandEvent &/*event*/)
2515 {
2516 	Prefs->ShowAtomicSymbolLabels(false);
2517 	Prefs->ShowAtomNumberLabels(true);
2518 	UpdateModelDisplay();
2519 	Dirtify();
2520 }
menuViewShowBothAtomLabels(wxCommandEvent &)2521 void MolDisplayWin::menuViewShowBothAtomLabels(wxCommandEvent &/*event*/)
2522 {
2523 	Prefs->ShowAtomicSymbolLabels(true);
2524 	Prefs->ShowAtomNumberLabels(true);
2525 	UpdateModelDisplay();
2526 	Dirtify();
2527 }
menuViewAddMarkAnnotation(wxCommandEvent &)2528 void MolDisplayWin::menuViewAddMarkAnnotation(wxCommandEvent &/*event*/) {
2529 	for (int i=0; i<MainData->cFrame->GetNumAtoms(); i++) {
2530 		if (MainData->cFrame->GetAtomSelection(i)) {
2531 			AnnotationMarker * t = new AnnotationMarker(i);
2532 			MainData->Annotations.push_back(t);
2533 		}
2534 	}
2535 	UpdateModelDisplay();
2536 	Dirtify();
2537 }
menuViewAddAnnotation(wxCommandEvent & event)2538 void MolDisplayWin::menuViewAddAnnotation(wxCommandEvent &event) {
2539 	wxCommandEvent foo;
2540 	foo.SetId(event.GetId()-MMP_ADDMARKANNOTATION+GL_Popup_Mark_Atom);
2541 	glCanvas->AddAnnotation(foo);
2542 }
menuViewDeleteAllAnnotations(wxCommandEvent &)2543 void MolDisplayWin::menuViewDeleteAllAnnotations(wxCommandEvent &/*event*/) {
2544 	MainData->DeleteAllAnnotations();
2545 	UpdateModelDisplay();
2546 	Dirtify();
2547 }
2548 
menuViewShow2DPattern(wxCommandEvent &)2549 void MolDisplayWin::menuViewShow2DPattern(wxCommandEvent &/*event*/) {
2550 	Prefs->Show2DPattern(1-Prefs->Show2DPattern());
2551 	UpdateModelDisplay();
2552 	Dirtify();
2553 }
2554 
menuViewWireFrameStyle(wxCommandEvent &)2555 void MolDisplayWin::menuViewWireFrameStyle(wxCommandEvent &/*event*/)
2556 {
2557 	Prefs->DrawBallnStick(false);
2558 	Prefs->DrawWireFrame(true);
2559 	UpdateModelDisplay();
2560 	Dirtify();
2561 }
menuViewBallAndStickStyle(wxCommandEvent &)2562 void MolDisplayWin::menuViewBallAndStickStyle(wxCommandEvent &/*event*/)
2563 {
2564 	Prefs->DrawBallnStick(true);
2565 	Prefs->DrawWireFrame(false);
2566 	UpdateModelDisplay();
2567 	Dirtify();
2568 }
2569 
menuViewEFP_Wireframe(wxCommandEvent &)2570 void MolDisplayWin::menuViewEFP_Wireframe(wxCommandEvent &/*event*/)
2571 {
2572 	Prefs->ShowEFPWireFrame(1-Prefs->ShowEFPWireFrame());
2573 	UpdateModelDisplay();
2574 	Dirtify();
2575 }
2576 
menuViewToggleAIAtomsVis(wxCommandEvent &)2577 void MolDisplayWin::menuViewToggleAIAtomsVis(wxCommandEvent &/*event*/) {
2578 	MainData->cFrame->toggleAbInitioVisibility();
2579 	ResetModel(false);
2580 	Dirtify();
2581 }
2582 
menuViewToggleMMAtomsVis(wxCommandEvent &)2583 void MolDisplayWin::menuViewToggleMMAtomsVis(wxCommandEvent &/*event*/) {
2584 	MainData->cFrame->toggleMMAtomVisibility();
2585 	ResetModel(false);
2586 	Dirtify();
2587 }
2588 
menuViewToggleEFPAtomsVis(wxCommandEvent &)2589 void MolDisplayWin::menuViewToggleEFPAtomsVis(wxCommandEvent &/*event*/) {
2590 	MainData->cFrame->toggleEFPVisibility();
2591 	ResetModel(false);
2592 	Dirtify();
2593 }
2594 
menuViewAnimateFrames(wxCommandEvent &)2595 void MolDisplayWin::menuViewAnimateFrames(wxCommandEvent &/*event*/) {
2596 	long AnimateTime = 10*Prefs->GetAnimateTime();
2597 	if (AnimateTime < 1) AnimateTime = 1;
2598 	if (m_timer.IsRunning()) {
2599 		m_timer.Stop();
2600 		timerRunning = false;
2601 	} else {
2602 		if (MainData->CurrentFrame >= MainData->NumFrames)
2603 			ChangeFrames(1);
2604 		else
2605 			ChangeFrames(MainData->CurrentFrame+1);
2606 		m_timer.SetOwner(this, MMP_ANIMATEFRAMESTIMER);
2607 		m_timer.Start(AnimateTime, wxTIMER_CONTINUOUS);
2608 		timerRunning = true;
2609 	}
2610 }
2611 
menuViewShrink_10(wxCommandEvent &)2612 void MolDisplayWin::menuViewShrink_10(wxCommandEvent &/*event*/) {
2613 	MainData->WindowSize *= 1.1;
2614 	ResetView();
2615 	Dirtify();
2616 }
2617 
menuViewEnlarge_10(wxCommandEvent &)2618 void MolDisplayWin::menuViewEnlarge_10(wxCommandEvent &/*event*/) {
2619 	MainData->WindowSize *= 0.9;
2620 	ResetView();
2621 	Dirtify();
2622 }
2623 
menuViewSetWindowParameters(wxCommandEvent &)2624 void MolDisplayWin::menuViewSetWindowParameters(wxCommandEvent &/*event*/) {
2625 	windowparameters * temp = new windowparameters(this);
2626 	if (temp->ShowModal() != wxID_CANCEL) {
2627 		Dirtify();
2628 	}
2629 	temp->Destroy();
2630 }
2631 
menuViewRotateInPlace(const Matrix4D new_m)2632 void MolDisplayWin::menuViewRotateInPlace(const Matrix4D new_m) {
2633 
2634 	Matrix4D ri;
2635 	CPoint3D trans_centroid, rot_centroid, rot2_centroid;
2636 
2637 	trans_centroid = MainData->MolCentroid - MainData->Centroid;
2638 	Rotate3DPt(MainData->TotalRotation, trans_centroid, &rot_centroid);
2639 
2640 	CopyMatrix(new_m, MainData->TotalRotation);
2641 
2642 	InverseMatrix(MainData->TotalRotation, ri);
2643 	Rotate3DPt(ri, rot_centroid, &rot2_centroid);
2644 	MainData->Centroid = rot2_centroid - MainData->MolCentroid;
2645 	MainData->Centroid *= -1.0;
2646 	MainData->ResetRotation();
2647 	ResetView();
2648 	Dirtify();
2649 }
2650 
menuViewRotateTo_X_axis(wxCommandEvent &)2651 void MolDisplayWin::menuViewRotateTo_X_axis(wxCommandEvent &/*event*/) {
2652 
2653 	Matrix4D new_m;
2654 	InitRotationMatrix(new_m);
2655 	new_m[0][2] = new_m[1][1] = 1.0;
2656 	new_m[2][0] = -1.0;
2657 	new_m[0][0] = new_m[2][2] = new_m[1][0] = new_m[0][1] =
2658 	   new_m[1][2] = new_m[2][1] = 0.0;
2659 
2660 	menuViewRotateInPlace(new_m);
2661 }
2662 
menuViewRotateTo_Y_axis(wxCommandEvent &)2663 void MolDisplayWin::menuViewRotateTo_Y_axis(wxCommandEvent &/*event*/) {
2664 
2665 	Matrix4D new_m;
2666 	InitRotationMatrix(new_m);
2667 	new_m[0][0] = new_m[1][2] = 1.0;
2668 	new_m[2][1] = -1.0;
2669 	new_m[1][1] = new_m[2][2] = new_m[0][1] = new_m[0][2] =
2670 	   new_m[1][0] = new_m[2][0] = 0.0;
2671 
2672 	menuViewRotateInPlace(new_m);
2673 }
2674 
menuViewRotateTo_Z_axis(wxCommandEvent &)2675 void MolDisplayWin::menuViewRotateTo_Z_axis(wxCommandEvent &/*event*/) {
2676 
2677 	Matrix4D new_m;
2678 	InitRotationMatrix(new_m);
2679 
2680 	menuViewRotateInPlace(new_m);
2681 }
2682 
menuViewRotate180_horizontal(wxCommandEvent &)2683 void MolDisplayWin::menuViewRotate180_horizontal(wxCommandEvent &/*event*/) {
2684 
2685 	Matrix4D tmp;
2686 	Matrix4D new_m;
2687 	CopyMatrix(MainData->TotalRotation, tmp);
2688 	MainData->FlipRotation(0);
2689 	CopyMatrix(MainData->TotalRotation, new_m);
2690 	CopyMatrix(tmp, MainData->TotalRotation);
2691 	menuViewRotateInPlace(new_m);
2692 }
2693 
menuViewRotate180_vertical(wxCommandEvent &)2694 void MolDisplayWin::menuViewRotate180_vertical(wxCommandEvent &/*event*/) {
2695 
2696 	Matrix4D tmp;
2697 	Matrix4D new_m;
2698 	CopyMatrix(MainData->TotalRotation, tmp);
2699 	MainData->FlipRotation(1);
2700 	CopyMatrix(MainData->TotalRotation, new_m);
2701 	CopyMatrix(tmp, MainData->TotalRotation);
2702 	menuViewRotateInPlace(new_m);
2703 }
2704 
menuViewRotatePrinciple_orientation(wxCommandEvent &)2705 void MolDisplayWin::menuViewRotatePrinciple_orientation(wxCommandEvent &/*event*/) {
2706 	StopAnimations();
2707 	MainData->RotateToPrincipleOrientation(Prefs);
2708 	ResetView();
2709 	Dirtify();
2710 }
2711 
menuViewRotateOther(wxCommandEvent &)2712 void MolDisplayWin::menuViewRotateOther(wxCommandEvent &/*event*/) {
2713 	StopAnimations();
2714 	MainData->Centroid = MainData->MolCentroid;
2715 	SetScreenPlane * temp = new SetScreenPlane(this);
2716 	temp->Show();
2717 }
2718 
menuMoleculeSetBondLength(wxCommandEvent &)2719 void MolDisplayWin::menuMoleculeSetBondLength(wxCommandEvent &/*event*/) {
2720 	StopAnimations();
2721 	//The set bond length dialog does the work
2722 	SetBondLength * dlg = new SetBondLength(this);
2723 	dlg->ShowModal();
2724 	dlg->Destroy();
2725 	Dirtify();
2726 }
2727 
menuPreferences(wxCommandEvent & event)2728 void MolDisplayWin::menuPreferences(wxCommandEvent &event)
2729 {
2730 		bool isGlobal;
2731 		int id = event.GetId();
2732 
2733 	if ( id == wxID_PREFERENCES )
2734 		isGlobal = true;
2735 	else if ( id == MMP_LOCAL_PREFERENCES )
2736 		isGlobal = false;
2737 	else
2738 		MessageAlert("This shouldn't happen!");
2739 
2740 	if (prefsDlg) {
2741 		prefsDlg->Raise();
2742 	} else {
2743 		prefsDlg = new setPreference(this, isGlobal);
2744 		if (!isGlobal) {
2745 			winData.PrefsWindowVisible(true);
2746 			prefsDlg->SetSize(winData.GetPrefsWinRect());
2747 		}
2748 		prefsDlg->Show();
2749 	}
2750 }
ClosePrefsWindow(void)2751 void MolDisplayWin::ClosePrefsWindow(void) {
2752 	if (prefsDlg) {
2753 		winData.SetPrefsWinRect(prefsDlg->GetRect());
2754 		prefsDlg->Destroy();
2755 		prefsDlg = NULL;
2756 		winData.PrefsWindowVisible(false);
2757 	}
2758 }
2759 
menuMoleculeSetFrameEnergy(wxCommandEvent &)2760 void MolDisplayWin::menuMoleculeSetFrameEnergy(wxCommandEvent &/*event*/) {
2761 	StopAnimations();
2762 	FrameEnergy * dlg = new FrameEnergy(this);
2763 	dlg->ShowModal();
2764 	dlg->Destroy();
2765 	UpdateFrameText();
2766 	if(energyPlotWindow != NULL) {
2767 		energyPlotWindow->RegenData();
2768 	}
2769 	Dirtify();
2770 }
2771 
menuMoleculeCreateLLMPath(wxCommandEvent &)2772 void MolDisplayWin::menuMoleculeCreateLLMPath(wxCommandEvent &/*event*/) {
2773 	StopAnimations();
2774 	//The create LLM dialog does the work
2775 	LLMDialog * llm = new LLMDialog(this);
2776 	llm->ShowModal();
2777 	llm->Destroy();
2778 	Dirtify();
2779 }
menuMoleculeMinimizeFrameMovements(wxCommandEvent &)2780 void MolDisplayWin::menuMoleculeMinimizeFrameMovements(wxCommandEvent &/*event*/) {
2781 	StopAnimations();
2782 	BeginOperation();
2783 	MainData->LinearLeastSquaresFit(ProgressInd);
2784 	FinishOperation();
2785 	Dirtify();
2786 }
menuSetPointGroup(wxCommandEvent & event)2787 void MolDisplayWin::menuSetPointGroup(wxCommandEvent &event) {
2788 	GAMESSPointGroup pg = (GAMESSPointGroup)(event.GetId() - MMP_PGC1 + GAMESS_C1);
2789 	if (! MainData->InputOptions) MainData->InputOptions = new InputData;
2790 	MainData->InputOptions->Data->SetPointGroup(pg);
2791 	ResetView();
2792 	Dirtify();
2793 }
menuSetPointGroupOrder(wxCommandEvent & event)2794 void MolDisplayWin::menuSetPointGroupOrder(wxCommandEvent &event) {
2795 	int order = event.GetId() - MMP_PGORDER2 + 2;
2796 	if (! MainData->InputOptions) MainData->InputOptions = new InputData;
2797 	MainData->InputOptions->Data->SetPointGroupOrder(order);
2798 	ResetView();
2799 	Dirtify();
2800 }
menuMoleculeDetermineSym(wxCommandEvent &)2801 void MolDisplayWin::menuMoleculeDetermineSym(wxCommandEvent &/*event*/) {
2802 	StopAnimations();
2803 	SymmetryPointGroupDlg * dlg = new SymmetryPointGroupDlg(this);
2804 	if (dlg->ShowModal() != wxID_CANCEL) {
2805 		//retrieve the selection and set the point group
2806 		GAMESSPointGroup temp;
2807 		int order;
2808 		if (dlg->GetSelectedPointGroup(temp, order)) {
2809 			CreateFrameSnapShot();
2810 			if (! MainData->InputOptions) MainData->InputOptions = new InputData;
2811 			MainData->InputOptions->Data->SetPointGroup(temp);
2812 			MainData->InputOptions->Data->SetPointGroupOrder(order);
2813 			MainData->RotateToPrincipleOrientation(Prefs, dlg->GetTolerance());
2814 			MainData->StickCoordinates();
2815 			//update the list of symmetry unique atoms
2816 			MainData->GenerateSymmetryUniqueAtoms(dlg->GetTolerance());
2817 			MainData->SymmetrizeCoordinates();
2818 			MainData->StickCoordinates();
2819 			if (coordsWindow) coordsWindow->FrameChanged();
2820 			ResetView();
2821 			Dirtify();
2822 		}
2823 	}
2824 	dlg->Destroy();
2825 }
menuMoleculeSymCoords(wxCommandEvent &)2826 void MolDisplayWin::menuMoleculeSymCoords(wxCommandEvent &/*event*/) {
2827 	StopAnimations();
2828 	MainData->RotateToPrincipleOrientation(Prefs);
2829 	MainData->StickCoordinates();
2830 	if (coordsWindow) coordsWindow->FrameChanged();
2831 	ResetView();
2832 	Dirtify();
2833 }
menuMoleculeConvertToBohr(wxCommandEvent &)2834 void MolDisplayWin::menuMoleculeConvertToBohr(wxCommandEvent &/*event*/) {
2835 	StopAnimations();
2836 	CreateFrameSnapShot();
2837 	MainData->UnitConversion(0);
2838 	ResetAllWindows();
2839 	Dirtify();
2840 }
menuMoleculeConvertToAngstroms(wxCommandEvent &)2841 void MolDisplayWin::menuMoleculeConvertToAngstroms(wxCommandEvent &/*event*/) {
2842 	StopAnimations();
2843 	CreateFrameSnapShot();
2844 	MainData->UnitConversion(1);
2845 	ResetAllWindows();
2846 	Dirtify();
2847 }
menuMoleculeInvertNormalMode(wxCommandEvent &)2848 void MolDisplayWin::menuMoleculeInvertNormalMode(wxCommandEvent &/*event*/) {
2849 	StopAnimations();
2850 	MainData->InvertMode();
2851 	ResetModel(false);
2852 	Dirtify();
2853 }
2854 
menuBuilderAddHydrogens(wxCommandEvent &)2855 void MolDisplayWin::menuBuilderAddHydrogens(wxCommandEvent &/*event*/) {
2856 	bool snapshotCreated=false;
2857 	Frame *	lFrame=MainData->cFrame;
2858 	long NumAtoms = lFrame->NumAtoms;
2859 
2860 	for (int iatom=0; iatom<NumAtoms; iatom++) {
2861 		short coordination = lFrame->Atoms[iatom].GetCoordinationNumber();
2862 		int bondCount = 0;
2863 		for (long i=0; i<lFrame->NumBonds; i++) {
2864 			if ((iatom == lFrame->Bonds[i].Atom1 ||
2865 			     iatom == lFrame->Bonds[i].Atom2) &&
2866 			     lFrame->Bonds[i].Order > kHydrogenBond) {
2867 				bondCount++;
2868 			}
2869 		}
2870 		for (int k=bondCount; k<coordination; k++) {
2871 			if (!snapshotCreated) {
2872 				CreateFrameSnapShot();
2873 				snapshotCreated = true;
2874 			}
2875 			CPoint3D vector, origin;
2876 			DrawBondingSites(iatom, 0, NULL, k+1, &vector);
2877 			lFrame->GetAtomPosition(iatom, origin);
2878 			MainData->NewAtom(1, origin + vector * 0.01 *
2879 			                  (Prefs->GetAtomSize(lFrame->GetAtomType(iatom)-1) + Prefs->GetAtomSize(0)));
2880 			lFrame->Atoms[lFrame->GetNumAtoms()-1].SetCoordinationNumber(1);
2881 			lFrame->AddBond(iatom,lFrame->GetNumAtoms()-1,kSingleBond);
2882 		}
2883 	}
2884 	if (snapshotCreated) {
2885 		ResetModel(false);
2886 		AtomsChanged(true, false);
2887 		Dirtify();
2888 	}
2889 }
menuBuilderDeleteHydrogens(wxCommandEvent &)2890 void MolDisplayWin::menuBuilderDeleteHydrogens(wxCommandEvent &/*event*/) {
2891 	//Strip off hydrogen atoms from the system. Leave non-bonded hydrogens alone and leave
2892 	//hydrogens that are part of fragments alone. I am tempted to leave hydrogens that are
2893 	//added as part of a precomputed fragment as well. I don't have the infrastructure for that
2894 	//in place yet though.
2895 	bool snapshotCreated=false;
2896 	Frame *	lFrame=MainData->cFrame;
2897 
2898 	for (int iatom=0; iatom<lFrame->NumAtoms; iatom++) {
2899 		if (lFrame->Atoms[iatom].Type == 1 ) {
2900 			if (lFrame->Atoms[iatom].IsEffectiveFragment() || lFrame->Atoms[iatom].IsSIMOMMAtom()) continue;
2901 			bool hasBonds=false;
2902 			for (long i=0; i<lFrame->NumBonds; i++) {
2903 				if ((iatom == lFrame->Bonds[i].Atom1 ||
2904 				     iatom == lFrame->Bonds[i].Atom2) &&
2905 				    lFrame->Bonds[i].Order > kHydrogenBond) {
2906 					hasBonds = true;
2907 					break;
2908 				}
2909 			}
2910 			if (hasBonds) {
2911 				if (!snapshotCreated) {
2912 					CreateFrameSnapShot();
2913 					snapshotCreated = true;
2914 				}
2915 				MainData->DeleteAtom(iatom, false);
2916 				iatom --;
2917 			}
2918 		}
2919 	}
2920 	if (snapshotCreated) {
2921 		ResetModel(false);
2922 		AtomsChanged(true, false);
2923 		Dirtify();
2924 	}
2925 }
2926 
menuBuilderShowBondSites(wxCommandEvent &)2927 void MolDisplayWin::menuBuilderShowBondSites(wxCommandEvent &/*event*/) {
2928 	show_bond_sites = !show_bond_sites;
2929 	UpdateModelDisplay();
2930 }
2931 
menuBuilderSymmetryEdit(wxCommandEvent &)2932 void MolDisplayWin::menuBuilderSymmetryEdit(wxCommandEvent &/*event*/) {
2933 	edit_symmetrically = !edit_symmetrically;
2934 
2935 	// When we start editing symmetrically, we deselect symmetry dependent
2936 	// atoms so they don't bundled together with operations that blindly
2937 	// edit all selected atoms.
2938 	if (edit_symmetrically) {
2939 		Frame *lFrame = MainData->cFrame;
2940 		for (int i = 0; i < lFrame->NumAtoms; i++) {
2941 			if (!lFrame->Atoms[i].IsSymmetryUnique()) {
2942 				lFrame->SetAtomSelection(i, false);
2943 			}
2944 		}
2945 	}
2946 
2947 	UpdateModelDisplay();
2948 }
2949 
2950 #if 0
2951 void MolDisplayWin::menuBuilderRegenSymmetry(wxCommandEvent &event) {
2952 	RegenerateSymmetryDependent();
2953 }
2954 #endif
2955 
KeyHandler(wxKeyEvent & event)2956 void MolDisplayWin::KeyHandler(wxKeyEvent & event) {
2957 	int key = event.GetKeyCode();
2958 	if (!event.HasModifiers()) {
2959 		switch (key) {
2960 			case 'b': case 'B':
2961 				glEdgeFlag(GL_TRUE);
2962 				break;
2963 			case '[':
2964 				if (MainData->cFrame->Vibs &&
2965 				    MainData->cFrame->Vibs->CurrentMode > 0) {
2966 					ChangeModes(MainData->cFrame->Vibs->CurrentMode - 1);
2967 				}
2968 				break;
2969 			case ']':
2970 				if (MainData->cFrame->Vibs &&
2971 				    MainData->cFrame->Vibs->CurrentMode < MainData->cFrame->Vibs->NumModes - 1) {
2972 					ChangeModes(MainData->cFrame->Vibs->CurrentMode + 1);
2973 				}
2974 				break;
2975 			case WXK_BACK:
2976 			case WXK_DELETE:
2977 				DeleteSelected();
2978 				glCanvas->Draw();
2979 				return;
2980 				break;
2981 			case WXK_LEFT:
2982 				if (MainData->CurrentFrame>1) {
2983 					ChangeFrames(MainData->CurrentFrame - 1);
2984 				}
2985 				break;
2986 			case WXK_RIGHT:
2987 				if (MainData->CurrentFrame<MainData->NumFrames) {
2988 					ChangeFrames(MainData->CurrentFrame + 1);
2989 				}
2990 				break;
2991 			case WXK_HOME:
2992 				if (MainData->CurrentFrame>1) {
2993 					ChangeFrames(1);
2994 				}
2995 				break;
2996 			case WXK_END:
2997 				if (MainData->CurrentFrame<MainData->NumFrames) {
2998 					ChangeFrames(MainData->NumFrames);
2999 				}
3000 				break;
3001 			case WXK_ESCAPE:
3002 				if (show_fullscreen) {
3003 					show_fullscreen = false;
3004 					ShowFullScreen(false);
3005 				}
3006 				break;
3007 			default:
3008 				if (InEditMode() &&
3009 				    ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z'))) {
3010 					//Pass general chars to the periodic table to set the atom type
3011 					// TODO: A temporary hack to register outside event.
3012 					event.m_x = -50;
3013 					event.m_y = -50;
3014 					BuilderTool->KeyHandler(event);
3015 					/* return; //I don't think there is any reason to skip on this case? */
3016 				}
3017 				break;
3018 		}
3019 	} else if (key == WXK_ALT && InEditMode()) {
3020 		toolbar->ToggleTool(MMP_TOOL_LASSO, true);
3021 		glCanvas->SetCursor(wxCursor(*wxCROSS_CURSOR));
3022 		UpdateModelDisplay();
3023 
3024 		mAltModifyingToolBar = true;
3025 	} else if (event.AltDown()) {
3026 		switch (key) {	//as long as we are called from a keydown handler these will upper case
3027 			case 'A':   //option - a
3028 				MainData->cFrame->toggleAbInitioVisibility();
3029 				ResetModel(false);
3030 				Dirtify();
3031 				break;
3032 			case 'E':   //option - e
3033 				MainData->cFrame->toggleEFPVisibility();
3034 				ResetModel(false);
3035 				Dirtify();
3036 				break;
3037 			case 'S':   //option - s
3038 				MainData->cFrame->toggleMMAtomVisibility();
3039 				ResetModel(false);
3040 				Dirtify();
3041 				break;
3042 		}
3043 	}
3044 	event.Skip();
3045 }
3046 
3047 /**
3048  * Deletes the selected atoms if currently in edit mode.
3049  */
DeleteSelected()3050 void MolDisplayWin::DeleteSelected() {
3051 
3052 	if (InEditMode()) {
3053 		if (mHighliteState) {
3054 			CreateFrameSnapShot();
3055 
3056 			// Delete each atom that's selected.
3057 			for (long i=MainData->cFrame->NumAtoms-1; i>=0; i--) {
3058 				if (MainData->cFrame->Atoms[i].GetSelectState()) {
3059 					long j = MainData->DeleteAtom(i, false);
3060 						//restart the scan if more than 1 atom is removed.
3061 					if ((j==0)&&(i!=0)) i = MainData->cFrame->GetNumAtoms()-1;
3062 				}
3063 			}
3064 
3065 			// Nothing's highlighted anymore, so turn some features off.
3066 			mHighliteState = false;
3067 			AtomsChanged(true, true);
3068 			/* AdjustMenus(); */
3069 			menuEdit->UpdateUI();
3070 		}
3071 	}
3072 
3073 }
3074 
KeyUpHandler(wxKeyEvent & event)3075 void MolDisplayWin::KeyUpHandler(wxKeyEvent & event) {
3076 	//the only keyup event we care about at the moment is alt up when in edit/select mode
3077 	int key = event.GetKeyCode();
3078 	if (key == WXK_ALT && Prefs->ToolbarShown()) {
3079 		if (mAltModifyingToolBar) {
3080 			toolbar->ToggleTool(MMP_TOOL_HAND, true);
3081 			glCanvas->SetCursor(wxCursor(wxCURSOR_HAND));
3082 			UpdateModelDisplay();
3083 
3084 			mAltModifyingToolBar = false;
3085 		}
3086 	}
3087 	event.Skip();
3088 }
menuWindowBonds(wxCommandEvent &)3089 void MolDisplayWin::menuWindowBonds(wxCommandEvent &/*event*/) {
3090 	if (bondsWindow) { //need to bring it to the front...
3091 		bondsWindow->Raise();
3092 	} else {
3093 		StopAnimations();	//Need to stop animations or a mode animation will cause the bond lengths to be incorrect
3094 		bondsWindow = new BondsDlg(this);
3095 		bondsWindow->SetSize(winData.GetBondsWinRect());
3096 		bondsWindow->Show();
3097 	}
3098 	winData.BondsWindowVisible(true);
3099 }
menuWindowMoleculeDisplay(wxCommandEvent &)3100 void MolDisplayWin::menuWindowMoleculeDisplay(wxCommandEvent &/*event*/) {
3101 	// This function is called by a menu item under a subwindow.
3102 	// Since this window always exists we just need to bring it to the front.
3103 	Raise();
3104 }
CloseBondsWindow(void)3105 void MolDisplayWin::CloseBondsWindow(void) {
3106 	if (bondsWindow) {
3107 		winData.SetBondsWinRect(bondsWindow->GetRect());
3108 		bondsWindow->Destroy();
3109 		bondsWindow = NULL;
3110 	}
3111 	winData.BondsWindowVisible(false);
3112 }
menuWindowCoordinates(wxCommandEvent &)3113 void MolDisplayWin::menuWindowCoordinates(wxCommandEvent &/*event*/) {
3114 	if (coordsWindow) { //need to bring it to the front...
3115 		coordsWindow->Raise();
3116 	} else {
3117 		coordsWindow = new CoordinatesWindow(this);
3118 		coordsWindow->SetSize(winData.GetCoordsWinRect());
3119 		coordsWindow->Show();
3120 	}
3121 	winData.CoordsWindowVisible(true);
3122 }
CloseCoordsWindow(void)3123 void MolDisplayWin::CloseCoordsWindow(void) {
3124 	if (coordsWindow) {
3125 		winData.SetCoordsWinRect(coordsWindow->GetRect());
3126 		coordsWindow->Destroy();
3127 		coordsWindow = NULL;
3128 	}
3129 	winData.CoordsWindowVisible(false);
3130 }
menuWindowEnergy_plot(wxCommandEvent &)3131 void MolDisplayWin::menuWindowEnergy_plot(wxCommandEvent &/*event*/) {
3132 	if(energyPlotWindow) { // need to bring it to the front...
3133 		energyPlotWindow->Raise();
3134 	}
3135 	else {
3136 		energyPlotWindow = new EnergyPlotDialog(this);
3137 		energyPlotWindow->SetSize(winData.GetEnergyWinRect());
3138 		energyPlotWindow->Show();
3139 	}
3140 	winData.EnergyWindowVisible(true);
3141 }
CloseEnergy_plotWindow(void)3142 void MolDisplayWin::CloseEnergy_plotWindow(void) {
3143 	if(energyPlotWindow) {
3144 		winData.SetEnergyWinRect(energyPlotWindow->GetRect());
3145 		energyPlotWindow->Destroy();
3146 		energyPlotWindow = NULL;
3147 	}
3148 	winData.EnergyWindowVisible(false);
3149 }
menuWindowFrequencies(wxCommandEvent &)3150 void MolDisplayWin::menuWindowFrequencies(wxCommandEvent &/*event*/) {
3151 	if(frequenciesWindow) { // need to bring it to the front...
3152 		frequenciesWindow->Raise();
3153 	}
3154 	else {
3155 		frequenciesWindow = new FrequenciesDialog(this);
3156 		frequenciesWindow->SetSize(winData.GetFrequencyWinRect());
3157 		frequenciesWindow->Show();
3158 	}
3159 	winData.FreqWindowVisible(true);
3160 }
CloseFrequenciesWindow(void)3161 void MolDisplayWin::CloseFrequenciesWindow(void) {
3162 	if(frequenciesWindow) {
3163 		winData.SetFrequencyWinRect(frequenciesWindow->GetRect());
3164 		frequenciesWindow->Destroy();
3165 		frequenciesWindow = NULL;
3166 	}
3167 	winData.FreqWindowVisible(false);
3168 }
3169 
menuWindowInput_builder(wxCommandEvent &)3170 void MolDisplayWin::menuWindowInput_builder(wxCommandEvent &/*event*/) {
3171 	if(inputBuilderWindow) {
3172 		inputBuilderWindow->Raise();
3173 	}
3174 	else {
3175 		inputBuilderWindow = new InputBuilderWindow(this);
3176 		inputBuilderWindow->Show();
3177 	}
3178 	winData.InputBWindowVisible(true);
3179 }
3180 
CloseInputBuilderWindow(void)3181 void MolDisplayWin::CloseInputBuilderWindow(void) {
3182 	if(inputBuilderWindow) {
3183 		winData.SetInputBWinRect(inputBuilderWindow->GetRect());
3184 		inputBuilderWindow->Destroy();
3185 		inputBuilderWindow = NULL;
3186 	}
3187 	winData.InputBWindowVisible(false);
3188 }
menuWindowSurfaces(wxCommandEvent &)3189 void MolDisplayWin::menuWindowSurfaces(wxCommandEvent &/*event*/) {
3190 	if(surfacesWindow) { // need to bring it to the front...
3191 	  surfacesWindow->Raise();
3192 	}
3193 	else {
3194 		surfacesWindow = new SurfacesWindow(this);
3195 		surfacesWindow->SetSize(winData.GetSurfacesWinRect());
3196 		surfacesWindow->Show();
3197 	}
3198 	winData.SurfacesWindowVisible(true);
3199 }
CloseSurfacesWindow(void)3200 void MolDisplayWin::CloseSurfacesWindow(void) {
3201 	if(surfacesWindow) {
3202 		winData.SetSurfacesWinRect(surfacesWindow->GetRect());
3203 		surfacesWindow->Destroy();
3204 		surfacesWindow = NULL;
3205 	}
3206 	winData.SurfacesWindowVisible(false);
3207 }
menuWindowZMatrixCalc(wxCommandEvent &)3208 void MolDisplayWin::menuWindowZMatrixCalc(wxCommandEvent &/*event*/) {
3209 	if(zMatCalcDlg) { // need to bring it to the front...
3210 		zMatCalcDlg->Raise();
3211 	} else {
3212 		zMatCalcDlg = new ZMatrixCalculator(this);
3213 		//Since this window is not resizeable leave the width and height alone
3214 		wxRect temp = winData.GetZMatWinRect();
3215 		temp.width = temp.height = -1;
3216 		zMatCalcDlg->SetSize(temp);
3217 		zMatCalcDlg->Show();
3218 	}
3219 	winData.ZMatWindowVisible(true);
3220 }
CloseZMatrixCalc(void)3221 void MolDisplayWin::CloseZMatrixCalc(void) {
3222 	if(zMatCalcDlg) {
3223 		winData.SetZMatWinRect(zMatCalcDlg->GetRect());
3224 		zMatCalcDlg->Destroy();
3225 		zMatCalcDlg = NULL;
3226 	}
3227 	winData.ZMatWindowVisible(false);
3228 }
3229 
3230 /**
3231  * This function regenerates symmetry dependent atoms and should be called
3232  * whenever anything to do with atoms is changed.  It deletes all non-symmetry
3233  * unique atoms and uses the current point group to recreate them based on
3234  * the remaining unique atoms.
3235  */
RegenerateSymmetryDependent()3236 void MolDisplayWin::RegenerateSymmetryDependent() {
3237 
3238 	Frame *lFrame = MainData->GetCurrentFramePtr();
3239 	mpAtom *lAtoms = lFrame->Atoms;
3240 
3241 	for (int i = lFrame->GetNumAtoms() - 1; i >= 0; i--) {
3242 		if (!lAtoms[i].IsSymmetryUnique()) {
3243 			MainData->DeleteAtom(i, false);
3244 		}
3245 	}
3246 
3247 	MainData->GenerateSymmetryDependentAtoms(false);
3248 
3249 	// We changed the atoms, so we better update the bonds.
3250 	lFrame->SetBonds(Prefs, true, ProgressInd, false);
3251 
3252 }
3253 
3254 /**
3255  * This function should be called whenever anything to do with atoms is
3256  * changed.  It triggers symmetry dependent atoms to be regenerated, if
3257  * necessary, updates related windows, and optionally redraws the frame.
3258  * @param updateCoordsWin True to refresh the coordinates display.
3259  * @param updateDisplay True to redraw the OpenGL canvas.
3260  */
AtomsChanged(bool updateCoordsWin,bool updateDisplay)3261 void MolDisplayWin::AtomsChanged(bool updateCoordsWin, bool updateDisplay) {
3262 
3263 	if (InSymmetryEditMode()) {
3264 		RegenerateSymmetryDependent();
3265 #if wxCHECK_VERSION(3, 0, 0)
3266 		MainData->SymmetrizeCoordinates(wxGetMouseState().LeftIsDown());
3267 #else
3268 		MainData->SymmetrizeCoordinates(wxGetMouseState().LeftDown());
3269 #endif
3270 	}
3271 
3272 	if (updateCoordsWin && coordsWindow) coordsWindow->FrameChanged();
3273 	if (bondsWindow) bondsWindow->ResetList();
3274 	if (surfacesWindow) surfacesWindow->Reset();
3275 	if (updateDisplay) FrameChanged();
3276 
3277 	Dirtify();
3278 
3279 }
3280 
BondsChanged(void)3281 void MolDisplayWin::BondsChanged(void) {
3282 	if (bondsWindow) bondsWindow->ResetList();
3283 	FrameChanged();
3284 }
3285 
3286 //scan the new frame changing any mode bits for consistency
FrameChanged(void)3287 void MolDisplayWin::FrameChanged(void) {
3288 	//Check for and update any surfaces depending on the screen plane
3289 	Surface * temp = MainData->cFrame->SurfaceList;
3290 	while (temp) {
3291 		temp->RotateEvent(MainData);
3292 		temp = temp->GetNextSurface();
3293 	}
3294 	UpdateModelDisplay();
3295 	Dirtify();
3296 	AdjustMenus();
3297 }
ChangeFrames(long NewFrame)3298 void MolDisplayWin::ChangeFrames(long NewFrame) {
3299 	if ((NewFrame>0)&&(NewFrame<=MainData->NumFrames)) {
3300 		if (NewFrame < MainData->CurrentFrame) {
3301 			MainData->cFrame = MainData->Frames;
3302 			MainData->CurrentFrame = 1;
3303 		}
3304 		while (MainData->CurrentFrame < NewFrame) {
3305 			MainData->cFrame = MainData->cFrame->NextFrame;
3306 			MainData->CurrentFrame++;
3307 		}
3308 		MainData->ResetRotation();
3309 		FrameChanged();
3310 
3311 		if (coordsWindow) coordsWindow->FrameChanged();
3312 		if (bondsWindow) bondsWindow->ResetList();
3313 		if (energyPlotWindow) energyPlotWindow->FrameChanged();
3314 		if (frequenciesWindow) frequenciesWindow->FrameChanged();
3315 		if (surfacesWindow) surfacesWindow->Reset();
3316 		if (zMatCalcDlg) zMatCalcDlg->UpdateValues();
3317 		myStatus->SetScrollBarValue(MainData->CurrentFrame-1);
3318 	}
3319 }
3320 
SetStatusText(const wxString & label)3321 void MolDisplayWin::SetStatusText(const wxString& label) {
3322 	status_timer.Start(5000, true);
3323 	myStatus->SetStatusText(label);
3324 }
3325 
OnStatusTimer(wxTimerEvent &)3326 void MolDisplayWin::OnStatusTimer(wxTimerEvent& /*event*/) {
3327 	UpdateFrameText();
3328 }
3329 
ModeChanged(void)3330 void MolDisplayWin::ModeChanged(void) {
3331 	StopAnimations();
3332 	if(frequenciesWindow != NULL) {
3333 		frequenciesWindow->ModeChanged();
3334 	}
3335 	if(!MainData->GetDrawMode()) {
3336 		MainData->SetDrawMode(true);
3337 		menuView->Check(MMP_SHOWMODE, true);
3338 	}
3339 	ResetModel(false);
3340 	Dirtify();
3341 }
ChangeModes(long NewMode)3342 void MolDisplayWin::ChangeModes(long NewMode) {
3343 	if(NewMode >= 0 && NewMode < MainData->cFrame->Vibs->GetNumModes()) {
3344 		MainData->cFrame->Vibs->CurrentMode = NewMode;
3345 		ModeChanged();
3346 	}
3347 }
3348 #include <iostream>
UpdateFrameText(void)3349 void MolDisplayWin::UpdateFrameText(void) {
3350 	// Add a little information
3351 	wxString output;
3352 	Boolean WriteEnergy=true;
3353 	if (MainData->cFrame->Vibs) {
3354 	  if (MainData->GetDrawMode()) {
3355 		  wxString str(MainData->cFrame->Vibs->Frequencies[MainData->cFrame->Vibs->CurrentMode].c_str(), wxConvUTF8);
3356 		  output.Printf(wxT("Freq=%s"), str.c_str());
3357 		  WriteEnergy = false;
3358 	  }
3359 	}
3360 	if (WriteEnergy) {
3361 		double  Energy = 0.0;
3362 		EnergyOptions * lEOpts = Prefs->GetEnergyOptions();
3363 		GraphOptions * lPOpts = Prefs->GetGraphOptions();
3364 		float   UnitFactor = 1.0;
3365 		if (lEOpts->GetDisplayUnits() == kKCalPerMole) UnitFactor = kHartreeTokCalPMol;
3366 		if (lEOpts->PlotMPEnergy())
3367 			Energy = (MainData->cFrame->GetMP2Energy()-lEOpts->GetY1Zero())*UnitFactor;
3368 		else if (lEOpts->PlotEnergy())
3369 			Energy = (MainData->cFrame->GetEnergy()-lEOpts->GetY1Zero())*UnitFactor;
3370 		else if (lEOpts->PlotKEnergy())
3371 			Energy = (MainData->cFrame->GetKineticEnergy()-lEOpts->GetY2Zero())*UnitFactor;
3372 		else if (lEOpts->PlotPEnergy())
3373 			Energy = (MainData->cFrame->Energy - MainData->cFrame->GetKineticEnergy()-lEOpts->GetY1Zero())*UnitFactor;
3374 		if (Energy != 0.0) {
3375 			output.Printf(wxT("E=%.*f"), lEOpts->GetNumDigits(), Energy);
3376 		}
3377 		if (lPOpts->PlotRMSGradient()) {
3378 			wxString temp;
3379 			temp.Printf(wxT(" RMS=%.*f"), lEOpts->GetNumDigits(),
3380 					MainData->cFrame->GetRMSGradient()-lEOpts->GetY2Zero());
3381 			output += temp;
3382 		} else if (lPOpts->PlotMaxGradient()) {
3383 			wxString temp;
3384 			temp.Printf(wxT(" Max Grad=%.*f"), lEOpts->GetNumDigits(),
3385 					MainData->cFrame->GetMaxGradient()-lEOpts->GetY2Zero());
3386 			output += temp;
3387 		} else if (lPOpts->PlotBondLength()) {
3388 			long a1, a2;
3389 			float bLength;
3390 			a1 = lPOpts->Get1stAtom();
3391 			a2 = lPOpts->Get2ndAtom();
3392 			if (MainData->cFrame->GetBondLength(a1, a2, &bLength)) {
3393 				wxString temp;
3394 				temp.Printf(wxT(" Bond %ld-%ld=%.*f"), a1+1, a2+1,
3395 						lEOpts->GetNumDigits(), bLength-lEOpts->GetY2Zero());
3396 				output += temp;
3397 			}
3398 		} else if (lPOpts->PlotBondAngle()) {
3399 			long a1, a2, a3;
3400 			float bAngle;
3401 			a1 = lPOpts->Get1stAtom();
3402 			a2 = lPOpts->Get2ndAtom();
3403 			a3 = lPOpts->Get3rdAtom();
3404 			if (MainData->cFrame->GetBondAngle(a1, a2, a3, &bAngle)) {
3405 				wxString temp;
3406 				temp.Printf(wxT(" Angle %ld-%ld-%ld=%.*f"), a1+1, a2+1, a3+1,
3407 						lEOpts->GetNumDigits(), bAngle-lEOpts->GetY2Zero());
3408 				output += temp;
3409 			}
3410 		}
3411 	}
3412 	wxString ft;
3413 	ft.Printf(wxT(" Frame %ld of %ld"), MainData->GetCurrentFrame(), MainData->GetNumFrames());
3414 	output += ft;
3415 
3416 	myStatus->SetStatusText(output);
3417 }
3418 
3419 /**
3420  * This function redraws the scene, essentially.  Use this to do a barebones
3421  * refresh.  If any data has changed, use a more specific function like
3422  * AtomsChanged or BondsChanged.
3423  */
UpdateModelDisplay(void)3424 void MolDisplayWin::UpdateModelDisplay(void) {
3425 	UpdateFrameText();
3426 	ReleaseLists();
3427 	glCanvas->Draw();
3428 }
3429 
ResetView(void)3430 void MolDisplayWin::ResetView(void) {
3431 	//Check for and update any surfaces depending on the screen plane
3432 	Surface * lSurface = MainData->cFrame->SurfaceList;
3433 	while (lSurface) {
3434 		lSurface->RotateEvent(MainData);
3435 		lSurface = lSurface->GetNextSurface();
3436 	}
3437 	//Check the select state
3438 	mHighliteState = false;
3439 	for (long i=0; i<MainData->cFrame->NumAtoms; i++) {
3440 		if (MainData->cFrame->Atoms[i].GetSelectState()) {
3441 			mHighliteState = true;
3442 			break;
3443 		}
3444 	}
3445 	/* glCanvas->UpdateGLView(); */
3446 	glCanvas->Draw();
3447 }
3448 
ResetModel(bool Center)3449 void MolDisplayWin::ResetModel(bool Center) {
3450 	if (Center) {
3451 		MainData->CenterModelWindow();
3452 		MainData->WindowSize = 1.25*(MainData->MaxSize+1.0);
3453 	}
3454 	MainData->ResetRotation();
3455 	//Check for and update any surfaces depending on the screen plane
3456 	Surface * lSurface = MainData->cFrame->SurfaceList;
3457 	while (lSurface) {
3458 		lSurface->RotateEvent(MainData);
3459 		lSurface = lSurface->GetNextSurface();
3460 	}
3461 	ReleaseLists();
3462 	// Reset the frame scroll bar
3463 	myStatus->SetScrollBar(MainData->CurrentFrame-1, MainData->NumFrames);
3464 	UpdateFrameText();
3465 
3466 	glCanvas->Draw();
3467 
3468 	// This is commented out because this function's called on file open,
3469 	// when the scene is definitely not dirty.
3470 	/* Dirtify(); */
3471 
3472 	AdjustMenus();
3473 }
3474 
ResetAllWindows(void)3475 void MolDisplayWin::ResetAllWindows(void) {
3476 	ResetModel(false);
3477 
3478 	//force updates for all the child windows
3479 	if (coordsWindow) coordsWindow->FrameChanged();
3480 	if (bondsWindow) bondsWindow->ResetList();
3481 	if (energyPlotWindow) energyPlotWindow->RegenData();
3482 	if (frequenciesWindow) frequenciesWindow->FrameChanged();
3483 	if (zMatCalcDlg) zMatCalcDlg->UpdateValues();
3484 
3485 }
BeginOperation(void)3486 void MolDisplayWin::BeginOperation(void) {
3487 	ProgressInd = new Progress;
3488 	if (!ProgressInd) throw MemoryError();
3489 	OperationInProgress = true;
3490 }
FinishOperation(void)3491 void MolDisplayWin::FinishOperation(void) {
3492 	if (ProgressInd) {
3493 		delete ProgressInd;
3494 		ProgressInd = NULL;
3495 	}
3496 	OperationInProgress = false;
3497 }
AbortOpen(const char * msg)3498 void MolDisplayWin::AbortOpen(const char * msg) {
3499 	//On non-Mac systems we don't close the last window, instead
3500 	//reinitialize the window data and leave open
3501 #ifndef __WXMAC__
3502 	MpApp & app = wxGetApp();
3503 	if (app.WindowCount() <= 1) {
3504 		//This is the last window! Clear it out, but leave it open
3505 		delete MainData;
3506 		MainData = new MoleculeData(this);
3507 		delete Prefs;
3508 		Prefs = new WinPrefs;
3509 		*Prefs = *gPreferences;
3510 		Dirtify();
3511 		SetTitle(wxT("Untitled"));
3512 		SetName(wxT("Untitled"));
3513 	} else
3514 #endif
3515 	{
3516 		Close(true);
3517 	}
3518 
3519 	if (msg != NULL) MessageAlert(msg);
3520 } /* AbortOpen */
3521 
OpenFile(wxString fileName,float offset,bool flip,bool append)3522 long MolDisplayWin::OpenFile(wxString fileName, float offset, bool flip, bool append) {
3523 	//This is modeled on OpenTextFile in the Mac version
3524 	long                test=0;
3525 	TextFileType type;
3526 
3527 	FILE * myfile = fopen(fileName.mb_str(wxConvUTF8), "rb");
3528 	if (myfile == NULL) {
3529 		if (append)
3530 			AbortOpen("Unable to open the requested file.");
3531 		else
3532 			MessageAlert("Unable to open the requested file.");
3533 		return 0;
3534 	}
3535 	BufferFile * Buffer = NULL;
3536 	try {
3537 		Buffer = new BufferFile(myfile, false);
3538 		//this is temporary, they are supposed to come from the open file dialog
3539 		long flipval = 1;
3540 		if (flip) flipval = -1;
3541 
3542 		// Attempt to identify the file type by looking for key words
3543 		type = Buffer->GetFileType((const char *) fileName.mb_str(wxConvUTF8));
3544 		if (type == kUnknown) {
3545 			Buffer->SetFilePos(0);
3546 			char test[kMaxLineLength];
3547 			Buffer->Read(test, sizeof(char) * 20);
3548 			test[20] = '\0';
3549 			if (strcmp(test, "BMBm") == 0 || strcmp(test, "mBMB") == 0) {
3550 				if (append) MessageAlert("Version 6 and later does not support the MacMolPlt binary format. Please convert to CML with version 5.6 and try again.");
3551 				else AbortOpen("Version 6 and later does not support the MacMolPlt binary format. Please convert to CML with version 5.6 and try again.");
3552 			} else {
3553 				if (FindKeyWord(test, "\rtf", 4)>=0) wxLogMessage(_("This file appears to be an RTF file. MacMolPlt requires all text files to be in the plain text format."));
3554 				else {
3555 					SelectFileType lSelector(this);
3556 
3557 					lSelector.LoadFile(fileName);
3558 					int rcode = lSelector.ShowModal();
3559 					if (rcode == wxID_OK) {
3560 						type = (TextFileType) lSelector.GetFileType();
3561 					}
3562 				}
3563 			}
3564 		}
3565 		BeginOperation();
3566 		switch (type) {
3567 			case kMolType:
3568 				if (!append)
3569 					test = OpenMolPltFile(Buffer);
3570 				break;
3571 			case kGAMESSlogType:
3572 				test = OpenGAMESSlog(Buffer, append, flipval, offset);
3573 				break;
3574 			case kGAMESSIRCType:
3575 				test = OpenGAMESSIRC(Buffer, append,flipval,offset);
3576 				break;
3577 			case kGAMESSDRCType:
3578 				test = OpenGAMESSDRC(Buffer, false, append,flipval,offset);
3579 				break;
3580 			case kGAMESSTRJType:
3581 				test = OpenGAMESSTRJ(Buffer, append,flipval,offset);
3582 				break;
3583 			case kGAMESSInputType:
3584 				if (!append)
3585 					test = OpenGAMESSInput(Buffer);
3586 				break;
3587 			case kXYZType:
3588 				if (!append)
3589 					test = OpenXYZFile(Buffer);
3590 				break;
3591 			case kPDBType:
3592 				if (!append)
3593 					test = OpenPDBFile(Buffer);
3594 				break;
3595 			case kMDLMolFile:
3596 				if (!append)
3597 					test = OpenMDLMolFile(Buffer);
3598 				break;
3599 			case CMLFile:
3600 			{
3601 				if (!append) {
3602 					test = OpenCMLFile(Buffer);
3603 					if (test == 0) AbortOpen(NULL);
3604 				}
3605 			}
3606 				break;
3607 			case MolDenFile:
3608 				test = OpenMoldenFile(Buffer);
3609 				break;
3610 			case MolekelFile:
3611 				test = OpenMKLFile(Buffer);
3612 				break;
3613 			case MOPACarcFile:
3614 				test = OpenMOPACFile(Buffer, type);
3615 				break;
3616 			case MOPACmopFile:
3617 				test = OpenMOPACFile(Buffer, type);
3618 				break;
3619 			default:    //Should only get here for unknown file types.
3620 			{
3621 //				Buffer->SetFilePos(0);
3622 //				char test[kMaxLineLength];
3623 //				Buffer->Read(test, sizeof(char) * kMaxLineLength);
3624 //				if (strcmp(test, "BMBm") == 0 || strcmp(test, "mBMB") == 0) {
3625 //					if (append) MessageAlert("Version 6 and later does not support the MacMolPlt binary format. Please convert to CML with version 5.6 and try again.");
3626 //					else AbortOpen("Version 6 and later does not support the MacMolPlt binary format. Please convert to CML with version 5.6 and try again.");
3627 //				} else {
3628 //					if (FindKeyWord(test, "\rtf", 4)) wxLogMessage(_("This file appears to be an RTF file. MacMolPlt requires all text files to be in the plain text format."));
3629 				if (!append)
3630 					AbortOpen(NULL);
3631 //					if (!append)
3632 //						AbortOpen("Unable to determine the file type.");
3633 //					else
3634 //						MessageAlert("Unable to determine the file type.");
3635 //				}
3636 			}
3637 		}
3638 	}
3639 	catch (std::bad_alloc) {//Out of memory error
3640 		if (!append)
3641 			AbortOpen("Not enough memory to open the file. Aborted!");
3642 	}
3643 	catch (MemoryError) {
3644 		if (!append)
3645 			AbortOpen("Not enough memory to open the file. Aborted!");
3646 	}
3647 	catch (UserCancel) {
3648 		if (!append)
3649 			AbortOpen("File open canceled by user");
3650 	}
3651 //  catch (DataError Error) {//Error parsing the file data
3652 //      if (!Error.ErrorSet())  Window->AbortOpen(21);
3653 //      else {
3654 //          Error.WriteError();
3655 //          delete Window; Window = NULL;
3656 //      }
3657 //  }
3658 	//Some kind of File system related error
3659 	catch (FileError Error) { Error.WriteError();
3660 		if (!append) AbortOpen(NULL);}
3661 	catch (...) {
3662 		if (!append)
3663 			AbortOpen("Unknown error reading the selected file. File open aborted.");
3664 	}
3665 	if (Buffer) delete Buffer;      //Done reading so free up the buffer
3666 	fclose(myfile);					//Text files are not used after opening so close it immediately
3667 	FinishOperation();				//Close the progress dialog, if opened
3668 
3669 	if (test && !append) {//Note test is left 0 if any exception occurs(which causes Window to be deleted)
3670 #ifdef __WXOSX_CARBON__
3671 	  if (gPreferences->ChangeFileType()) {
3672 		  // Looks like this is a good file so set the creator type for the neat icon
3673 		  FSRef mFSRef;
3674 		  const char * t = fileName.mb_str(wxConvUTF8);
3675 		  OSStatus s = FSPathMakeRef((const UInt8 *) t, &mFSRef, false);
3676 		  if (s == noErr) {
3677 			  FSCatalogInfoBitmap fields = kFSCatInfoFinderInfo;
3678 			  FSCatalogInfo info;
3679 
3680 			  FSGetCatalogInfo(&mFSRef, fields, &info, NULL, NULL, NULL);
3681 			  FileInfo * mfinfo = (FileInfo *) (&(info.finderInfo));
3682 			  if (mfinfo->fileCreator != (OSType) 'BMBm') {
3683 				  mfinfo->fileCreator = (OSType) 'BMBm';
3684 				  FSSetCatalogInfo(&mFSRef, fields, &info);
3685 			  }
3686 		  }
3687 	  }
3688 #endif
3689 		if ((type != CMLFile) || (test < 10)) ResetModel(true);
3690 		else ResetModel(false);
3691 
3692 		// Set the path for saving changes
3693 		if(type == CMLFile) {
3694 			currFilePath = fileName;
3695 		} else {
3696 			currFilePath = wxT("");
3697 		}
3698 	}
3699 	if (append) {
3700 		if ((type != CMLFile) || (test < 10)) ResetModel(true);
3701 	}
3702 
3703 	ShowToolbar(Prefs->ToolbarShown());
3704 	menuBuild->Check(MMP_SHOW_TOOLBAR, Prefs->ToolbarShown());
3705 
3706 	return test;
3707 }
3708 
OpenCMLFile(BufferFile * Buffer,bool readPrefs,bool readWindows)3709 long MolDisplayWin::OpenCMLFile(BufferFile * Buffer, bool readPrefs, bool readWindows) {
3710 	bool localprogress=false;
3711 	if (!ProgressInd) {
3712 		localprogress = true;
3713 		BeginOperation();
3714 	}
3715 	ProgressInd->ChangeText("Reading CML file...");
3716 	long test = 0;
3717 	if (readWindows) {
3718 		//This option reads in the saved window rects (if any) and the state of
3719 		//the various subwindows. This option is normally only run when reading in
3720 		//a file to a new window.
3721 		test = MainData->OpenCMLFile(Buffer, Prefs, &winData, ProgressInd, readPrefs);
3722 		if (test) {
3723 			SetSize(winData.GetMolWinRect());
3724 			if (Prefs->ToolbarShown()) {
3725 				ShowToolbar();
3726 				menuBuild->Check(MMP_SHOW_TOOLBAR, Prefs->ToolbarShown());
3727 
3728 				wxCommandEvent foo;
3729 				foo.SetId(MMP_TOOL_HAND);
3730 				OnToggleTool(foo);
3731 			}
3732 			wxCommandEvent foo;	//just a placeholder so we can call the menu event functions
3733 			if (winData.BondsWindowVisible()) menuWindowBonds(foo);
3734 			if (winData.CoordsWindowVisible()) menuWindowCoordinates(foo);
3735 			if (winData.EnergyWindowVisible()) menuWindowEnergy_plot(foo);
3736 			if (winData.FreqWindowVisible()) menuWindowFrequencies(foo);
3737 			if (winData.InputBWindowVisible()) menuWindowInput_builder(foo);
3738 			if (winData.SurfacesWindowVisible()) menuWindowSurfaces(foo);
3739 				//I don't think the prefs window should reopen automatically?
3740 			if (winData.PrefsWindowVisible()) winData.PrefsWindowVisible(false);
3741 			if (winData.ZMatWindowVisible()) menuWindowZMatrixCalc(foo);
3742 			if (Prefs->isAutoRotating()) menuViewToggleAutoRotation(foo);
3743 			Raise();
3744 		}
3745 	} else
3746 		test = MainData->OpenCMLFile(Buffer, Prefs, NULL, ProgressInd, readPrefs);
3747 	for (long i=0; i<MainData->cFrame->NumAtoms; i++) {
3748 		if (MainData->cFrame->Atoms[i].GetSelectState()) {
3749 			mHighliteState = true;
3750 			break;
3751 		}
3752 	}
3753 	if (readPrefs && test >= 10) {
3754 		//Update the canvas since a CMLfile reads in user preferences
3755 		glCanvas->SetCurrent();
3756 		DoPrefDependent();
3757 	}
3758 	if (localprogress) FinishOperation();
3759 	return test;
3760 }
WindowData(void)3761 WindowData::WindowData(void) {
3762 	//These are all used for windows where -1 indicates the default value that
3763 	//causes wx to compute appropriate values
3764 	BondsVis = CoordsVis = EnergyVis = FreqVis = SurfacesVis = InputBVis = PrefVis = ZMatVis = false;
3765 	MolWinRect.x = MolWinRect.y = -1;
3766 	MolWinRect.width = MolWinRect.height = 450;
3767 	BondsWinRect.x = BondsWinRect.y = BondsWinRect.width = BondsWinRect.height = -1;
3768 	CoordsWinRect.x = CoordsWinRect.y = CoordsWinRect.width = CoordsWinRect.height = -1;
3769 	EnergyWinRect.x = EnergyWinRect.y = EnergyWinRect.width = EnergyWinRect.height = -1;
3770 	FreqWinRect.x = FreqWinRect.y = FreqWinRect.width = FreqWinRect.height = -1;
3771 	SurfacesWinRect.x = SurfacesWinRect.y = SurfacesWinRect.width = SurfacesWinRect.height = -1;
3772 	InputBuilderRect.x = InputBuilderRect.y = InputBuilderRect.width = InputBuilderRect.height = -1;
3773 	ZMatRect.x = ZMatRect.y = ZMatRect.width = ZMatRect.height = -1;
3774 	PreferenceWinRect.x = PreferenceWinRect.y = PreferenceWinRect.width = PreferenceWinRect.height = -1;
3775 }
Validate(wxRect & testRect)3776 void WindowData::Validate(wxRect & testRect) {
3777 	bool valid = false;
3778 		//bah... wxDisplay is not implemented on all platforms (doesn't seem to
3779 		//be active on Windoze with wx 2.6.3)
3780 	int displayCount = 1;
3781 #if wxUSE_DISPLAY
3782 	displayCount = wxDisplay::GetCount();
3783 #endif
3784 	for (int i=0; i<displayCount; i++) { //iterate over the displays
3785 		//retrieve the usable rect for this display
3786 		//In theory wx 2.8 has a GetClientArea function that is equivelant to wxGetClientDisplayRect
3787 		//however in 2.8.0 it doesn't properly account for the Mac menu bar
3788 		wxRect displayRect;
3789 		if (i == 0) {
3790 			displayRect = wxGetClientDisplayRect();
3791 		} else {
3792 #if wxUSE_DISPLAY
3793 	//There is no else here because of the #if above
3794 			wxDisplay iDisplay(i);
3795 			displayRect = iDisplay.GetGeometry();
3796 #endif
3797 		}
3798 		//Test the sample rect to see if it lies (at least partially) on this display
3799 		if (testRect.x >= displayRect.x &&
3800 		    testRect.y >= displayRect.y &&
3801 		    testRect.x < (displayRect.x + displayRect.width) &&
3802 		    testRect.y < (displayRect.y + displayRect.height)) {
3803 			//ok rect tests within this window
3804 			//now test the size to make sure the window can be placed fully on this screen
3805 			if (testRect.width < 1) testRect.width = -1;
3806 			else if (testRect.width > displayRect.width) testRect.width = displayRect.width;
3807 			if (testRect.height < 1) testRect.height = -1;
3808 			else if (testRect.height > displayRect.height) testRect.height = displayRect.height;
3809 			valid = true;
3810 			break;
3811 		}
3812 	}
3813 	if (!valid) {
3814 		testRect.x = testRect.y = testRect.width = testRect.height = -1;
3815 	}
3816 }
UpdateWindowData(void)3817 void MolDisplayWin::UpdateWindowData(void) {
3818 	winData.SetMolWinRect(GetRect());
3819 	if (bondsWindow != NULL) {
3820 		winData.BondsWindowVisible(true);
3821 		winData.SetBondsWinRect(bondsWindow->GetRect());
3822 	} else winData.BondsWindowVisible(false);
3823 	if (coordsWindow != NULL) {
3824 		winData.CoordsWindowVisible(true);
3825 		winData.SetCoordsWinRect(coordsWindow->GetRect());
3826 	} else winData.CoordsWindowVisible(false);
3827 	if (energyPlotWindow != NULL) {
3828 		winData.EnergyWindowVisible(true);
3829 		winData.SetEnergyWinRect(energyPlotWindow->GetRect());
3830 	} else winData.EnergyWindowVisible(false);
3831 	if (frequenciesWindow != NULL) {
3832 		winData.FreqWindowVisible(true);
3833 		winData.SetFrequencyWinRect(frequenciesWindow->GetRect());
3834 	} else winData.FreqWindowVisible(false);
3835 	if (surfacesWindow != NULL) {
3836 		winData.SurfacesWindowVisible(true);
3837 		winData.SetSurfacesWinRect(surfacesWindow->GetRect());
3838 	} else winData.SurfacesWindowVisible(false);
3839 	if (inputBuilderWindow != NULL) {
3840 		winData.InputBWindowVisible(true);
3841 		winData.SetInputBWinRect(inputBuilderWindow->GetRect());
3842 	} else winData.InputBWindowVisible(false);
3843 	if (prefsDlg != NULL) {
3844 		winData.PrefsWindowVisible(true);
3845 		winData.SetPrefsWinRect(prefsDlg->GetRect());
3846 	} else winData.PrefsWindowVisible(false);
3847 	if (zMatCalcDlg != NULL) {
3848 		winData.ZMatWindowVisible(true);
3849 		winData.SetZMatWinRect(zMatCalcDlg->GetRect());
3850 	} else winData.ZMatWindowVisible(false);
3851 }
SetDefaultWindowData(void)3852 void MolDisplayWin::SetDefaultWindowData(void) {
3853 	//first make sure the data is up to date
3854 	UpdateWindowData();
3855 	//copy it onto to the defaults
3856 	gWindowDefault = winData;
3857 	//Now save the user preferences (no way to save only the window data)
3858 	gPreferences->WriteUserPrefs();
3859 }
3860 
OnRotateTimer(wxTimerEvent &)3861 void MolDisplayWin::OnRotateTimer(wxTimerEvent& /*event*/) {
3862 
3863 	wxMouseEvent mouse_event = wxMouseEvent(wxEVT_MOTION);
3864 	mouse_event.m_leftDown = true;
3865 	int z;
3866 	Prefs->GetAutoRotationVector(inertia.x, inertia.y, z);
3867 	Rotate(mouse_event);
3868 }
3869 
Rotate(wxMouseEvent & event)3870 void MolDisplayWin::Rotate(wxMouseEvent &event) {
3871 
3872 	wxPoint q, sphereCenter;
3873 	int dx, dy;
3874 	Matrix4D rotationMatrix, tempcopyMatrix;
3875 	wxRect sphereRect;
3876 	long hsize, vsize, width, hoffset, sphereRadius;
3877 	Surface *lSurface;
3878 	bool UpdateSurface = false;
3879 
3880 	/* glCanvas->SetCurrent(); */
3881 
3882 	// Some surfaces need to be adjusted for the new screen plane.
3883 	lSurface = MainData->cFrame->SurfaceList;
3884 	while (lSurface) {
3885 		UpdateSurface = UpdateSurface || lSurface->NeedsUpdateDuringRotation();
3886 		lSurface = lSurface->GetNextSurface();
3887 	}
3888 
3889 	wxRect DisplayRect = glCanvas->GetRect();
3890 	hsize = DisplayRect.GetWidth();
3891 	vsize = DisplayRect.GetHeight();
3892 
3893 	/* Figure out where to place the Virtual Sphere cue. */
3894 	width = hsize;
3895 	sphereCenter.x = hsize/2;
3896 	sphereCenter.y = vsize/2;
3897 	if (sphereCenter.x >= sphereCenter.y)
3898 		sphereRadius   = (long)((float) (sphereCenter.x)*0.9);
3899 	else
3900 		sphereRadius   = (long)((float) (sphereCenter.y)*0.9);
3901 	hoffset = sphereCenter.x;
3902 	hsize = MAX(hsize, vsize);
3903 	sphereRect.SetHeight(sphereRadius);
3904 	sphereRect.SetWidth(sphereRadius);
3905 	sphereRect.SetX(sphereCenter.x - sphereRadius);
3906 	sphereRect.SetY(sphereCenter.y - sphereRadius);
3907 
3908 	// If this mouse event was generated because the user pressed a button
3909 	// down, we reset any autorotation, clear the inertia, and record the
3910 	// position.
3911 	if (event.ButtonDown()) {
3912 
3913 		// The mouse position is normally easy to calculate.  However, if the
3914 		// event was generated by the programmer, the position is (0,0), in
3915 		// which case we must determine the real mouse position.
3916 		mouse_start = event.GetPosition();
3917 		if (mouse_start.x == 0 && mouse_start.y == 0) {
3918 			mouse_start = ScreenToClient(wxGetMousePosition());
3919 		}
3920 		//not sure that the following clear is needed.
3921 	//	inertia.x = 0;
3922 	//	inertia.y = 0;
3923 		if (rotate_timer.IsRunning()) {
3924 			rotate_timer.Stop();
3925 			Prefs->SetAutoRotating(false);
3926 		}
3927 	}
3928 
3929 	// For some reason the mouse position isn't always correct if the click
3930 	// brought focus to the window.
3931 	else if (window_just_focused) {
3932 		mouse_start = ScreenToClient(wxGetMousePosition());
3933 		window_just_focused = false;
3934 	}
3935 
3936 	// Now, if we're dragging we've got to do a bit of work.
3937 	else if (event.Dragging()) {
3938 
3939 		// We're going to need to compare the current mouse position with
3940 		// the previous mouse position to figure out how much to transform.
3941 		// So, we'll need to figure out the current mouse position.
3942 
3943 
3944 		// If autorotation is going on, the actual mouse position isn't really
3945 		// what we want.  Instead, we pretend that the mouse position is the
3946 		// previous mouse position plus the inertial direction.
3947 		if (rotate_timer.IsRunning()) {
3948 			dx = inertia.x;
3949 			dy = inertia.y;
3950 			mouse_start = sphereCenter;
3951 			q.x = mouse_start.x + inertia.x;
3952 			q.y = mouse_start.y + inertia.y;
3953 		}
3954 
3955 		// If no autorotation is happening, the mouse position can be retrieved
3956 		// by normal means.
3957 		else {
3958 			q = event.GetPosition();
3959 			dx = q.x - mouse_start.x;
3960 			dy = q.y - mouse_start.y;
3961 			inertia.x = dx;
3962 			inertia.y = dy;
3963 		}
3964 
3965 		// Don't do any work if there wasn't any mouse movement.
3966 		if (dx != 0 || dy != 0) {
3967 
3968 			// The right mouse button or Command-{Left,Middle} produces a
3969 			// translation along screen spaces axes.
3970 			if (event.CmdDown() || event.RightIsDown()) {
3971 
3972 				// If shift is also held down, we depth-translate along the
3973 				// viewing direction.
3974 				if (event.ShiftDown()) {
3975 					float factor = 1.2f * MainData->WindowSize / hsize;
3976 					CPoint3D eye_z_in_obj(MainData->TotalRotation[0][2],
3977 							              MainData->TotalRotation[1][2],
3978 										  MainData->TotalRotation[2][2]);
3979 
3980 					eye_z_in_obj *= -inertia.y * factor;
3981 					MainData->Centroid -= eye_z_in_obj;
3982 				}
3983 
3984 				// Otherwise we move in proportion to the window size along
3985 				// the screen's x- and y-axes.
3986 				else {
3987 					float factor = 1.2f * MainData->WindowSize / hsize;
3988 					CPoint3D eye_x_in_obj(MainData->TotalRotation[0][0],
3989 							              MainData->TotalRotation[1][0],
3990 										  MainData->TotalRotation[2][0]);
3991 					CPoint3D eye_y_in_obj(MainData->TotalRotation[0][1],
3992 							              MainData->TotalRotation[1][1],
3993 										  MainData->TotalRotation[2][1]);
3994 
3995 					eye_x_in_obj *= inertia.x * factor;
3996 					eye_y_in_obj *= -inertia.y * factor;
3997 					MainData->Centroid -= eye_x_in_obj;
3998 					MainData->Centroid -= eye_y_in_obj;
3999 				}
4000 			}
4001 
4002 			// {Left,Middle} click without Command/Control, at which we rotate or
4003 			// z-translate.
4004 			else {
4005 
4006 				// Z-translate.
4007 				if (event.ShiftDown() || event.MiddleIsDown()) {
4008 					if (dy == 0) return;
4009 					if (dy > 99) dy = 99;
4010 					MainData->WindowSize *= 1.0 + 0.01*dy;
4011 				}
4012 
4013 				// Rotate.
4014 				else {
4015 					VirtualSphereQD3D(mouse_start, q,
4016 					                  sphereCenter, sphereRadius,
4017 					                  rotationMatrix, MainData->TotalRotation);
4018 
4019 					// Concatenate the new rotation with the current rotation
4020 					MultiplyMatrix(rotationMatrix, MainData->TotalRotation, tempcopyMatrix);
4021 					CopyMatrix(tempcopyMatrix, MainData->TotalRotation);
4022 
4023 					// Clean up the rotation matrix make the rotation part orthogonal and magnitude 1
4024 					OrthogonalizeRotationMatrix (MainData->TotalRotation);
4025 				}
4026 			}
4027 
4028 			// Remember previous mouse point for next iteration.
4029 			mouse_start = q;
4030 		}
4031 
4032 	}
4033 
4034 	// If the user releases the Left button while still moving, we cause the
4035 	// atoms to autorotate.
4036 	else if (event.LeftUp() && Prefs->AutoRotationEnabled()) {
4037 		if (abs(inertia.x) > 3 || abs(inertia.y) > 3) {
4038 			rotate_timer.Start(33, false);
4039 			Prefs->SetAutoRotating(true);
4040 			Prefs->SetAutoRotationVector(inertia.x, inertia.y, 0);
4041 		}
4042 	}
4043 	// No matter what mouse button/key combination we have, we update
4044 	// any surfaces that depend on the screen plane.
4045 	// This may update a little more than needed, but it needs to be here to handle the mouse wheel event
4046 	if (UpdateSurface) {
4047 		lSurface = MainData->cFrame->SurfaceList;
4048 		while (lSurface) {
4049 			lSurface->RotateEvent(MainData);
4050 			lSurface = lSurface->GetNextSurface();
4051 		}
4052 	}
4053 
4054 	/* Update the window */
4055 	if (UpdateSurface) ReleaseLists();
4056 
4057 	// If the scene is actively being rotated, we call a function that sorts
4058 	// transparent triangles, draws the atoms and some rotation annotations.
4059 	// For autorotation, a left mouse click is faked, but we don't want to
4060 	// annotate then.
4061 	if (event.LeftIsDown() && event.Dragging()) {
4062 		if (transpTriList) { //update the transparent surface sorting
4063 			SortTransparentTriangles();
4064 		}
4065 		do_rotate_annotation = true;
4066 		glCanvas->Draw();
4067 		do_rotate_annotation = false;
4068 		Dirtify();
4069 	}
4070 
4071 	// Otherwise we do a plain drawing of the atoms.
4072 	else {
4073 		glCanvas->Draw();
4074 	}
4075 
4076 }
4077 
IsRotating(void)4078 bool MolDisplayWin::IsRotating(void) {
4079 
4080 	return rotate_timer.IsRunning();
4081 
4082 }
4083 
SetWindowPreferences(WinPrefs * NewPrefs)4084 void MolDisplayWin::SetWindowPreferences(WinPrefs *NewPrefs) {
4085 
4086 	if (Prefs && Prefs != NewPrefs) {
4087 		*Prefs = *NewPrefs;
4088 	}
4089 
4090 	glCanvas->SetCurrent();
4091 	DoPrefDependent();
4092 	ResetAllWindows();
4093 
4094 }
4095 
SelectionChanged(bool mode)4096 void MolDisplayWin::SelectionChanged(bool mode) {
4097 	if (coordsWindow)
4098 		coordsWindow->UpdateSelection(mode);
4099 	if (bondsWindow)
4100 		bondsWindow->UpdateSelection(mode);
4101 	Dirtify();
4102 }
4103 
4104 //The following is the amount of space to leave for the window sizing box used by
4105 //many window maangers that takes some space away from the client area.
4106 #define kMOLSCROLLOFFSET 16
4107 #define kMOLSCROLLWIDTH	120
MolStatusBar(MolDisplayWin * p)4108 MolStatusBar::MolStatusBar(MolDisplayWin * p) : wxStatusBar(p, wxID_ANY), myScroll(NULL),
4109 				myParent(p) {
4110 	SetFieldsCount(2);
4111 	const int widths[2] = {-1, kMOLSCROLLWIDTH + kMOLSCROLLOFFSET};
4112 	SetStatusWidths(2, widths);
4113 
4114 	myScroll = new wxScrollBar( this, MMP_FRAMESCROLLBAR, wxDefaultPosition, wxSize(kMOLSCROLLWIDTH, -1), wxSB_HORIZONTAL );
4115 	//wxStatusBar sets its window style to small, I don't want a small
4116 	//scroll bar so set its style to normal
4117 	myScroll->SetWindowVariant(wxWINDOW_VARIANT_NORMAL);
4118 	myScroll->SetScrollbar(0, 1, 1, 1);
4119 }
4120 
OnSize(wxSizeEvent & event)4121 void MolStatusBar::OnSize(wxSizeEvent & event) {
4122 	if (!myScroll) return;
4123 		//The size of the scroll bar is left fixed so we just move it around
4124 	wxRect rect;
4125 	GetFieldRect(1, rect);
4126 	myScroll->Move(rect.x, rect.y);
4127 
4128 	event.Skip();
4129 }
4130 
SetScrollBar(int pos,int range)4131 void MolStatusBar::SetScrollBar(int pos, int range) {
4132 	myScroll->SetScrollbar(pos, 1, range, 1);
4133 }
4134 
SetScrollBarValue(int pos)4135 void MolStatusBar::SetScrollBarValue(int pos) {
4136 	myScroll->SetThumbPosition(pos);
4137 }
4138 
OnScrollBarChange(wxScrollEvent & event)4139 void MolStatusBar::OnScrollBarChange(wxScrollEvent & event) {
4140 	myParent->StopAnimations();
4141 	myParent->ChangeFrames(event.GetPosition() + 1);
4142 }
4143 
ChangeAtomOrder(long index)4144 void MolDisplayWin::ChangeAtomOrder(long index) {
4145 	//first make a list of the selected atoms to move.
4146 	//we have to be careful since the initial index may move around as atoms are moved.
4147 	long sel1atom=-1;
4148 	for (long i=0; i < MainData->cFrame->NumAtoms; i++) {
4149 		if (MainData->cFrame->Atoms[i].GetSelectState()) {
4150 			sel1atom = i;
4151 			break;
4152 		}
4153 	}
4154 	if (sel1atom < 0) return;	//no selected atoms found
4155 	if (sel1atom >= index) {
4156 		//if we are moving atoms closer to the beginning of the list it is
4157 		//simple as we just need to find each selected atom and move it.
4158 		while (sel1atom >= 0) {
4159 			MainData->ReorderAtomList(sel1atom, index);
4160 			if (sel1atom == index) sel1atom ++;
4161 			index++;
4162 			long i = sel1atom;
4163 			sel1atom = -1;
4164 			for ( ; i<MainData->cFrame->NumAtoms; i++) {
4165 				if (MainData->cFrame->Atoms[i].GetSelectState()) {
4166 					sel1atom = i;
4167 					break;
4168 				}
4169 			}
4170 		}
4171 	} else {
4172 		//ok moving the atom later in the list. The catch is we don't want to process the
4173 		//same atom twice and the initial atom may not stay put.
4174 		MainData->ReorderAtomList(sel1atom, index);
4175 		long skipstart = index;
4176 		long skipcount = 1;
4177 		while (sel1atom > 0) {
4178 			long i = sel1atom;
4179 			sel1atom = -1;
4180 			for ( ; i<MainData->cFrame->NumAtoms; i++) {
4181 				if (i == skipstart) {
4182 					i += skipcount;
4183 					index++;
4184 					while (MainData->cFrame->Atoms[i].GetSelectState()) {
4185 						//selected atoms immediately after the already moved atoms are fine
4186 						//where they are.
4187 						i++;
4188 						index++;
4189 					}
4190 					continue;
4191 				}
4192 				if (MainData->cFrame->Atoms[i].GetSelectState()) {
4193 					sel1atom = i;
4194 					break;
4195 				}
4196 			}
4197 			if (sel1atom > 0)
4198 				MainData->ReorderAtomList(sel1atom, index);
4199 			if (sel1atom > index) index++;
4200 			else {
4201 				skipcount++;
4202 				skipstart--;
4203 			}
4204 		}
4205 	}
4206 	AtomsChanged(true, true);	//update all the windows
4207 }
4208 
OnToggleTool(wxCommandEvent & event)4209 void MolDisplayWin::OnToggleTool(wxCommandEvent& event) {
4210 
4211 	// The tool is toggled automatically by wx, but we don't really want to
4212 	// allow it to be toggled off.  So, we explicitly force any click on the
4213 	// button to be a toggle on.
4214 	toolbar->ToggleTool(event.GetId(), true);
4215 	mAltModifyingToolBar = false;
4216 
4217 	switch (event.GetId()) {
4218 		case MMP_TOOL_ARROW:
4219 			glCanvas->SetCursor(wxCursor(wxCURSOR_ARROW));
4220 			break;
4221 		case MMP_TOOL_LASSO:
4222 			glCanvas->SetCursor(wxCursor(*wxCROSS_CURSOR));
4223 			break;
4224 		case MMP_TOOL_HAND:
4225 			glCanvas->SetCursor(wxCursor(wxCURSOR_HAND));
4226 			break;
4227 		default:
4228 			glCanvas->SetCursor(wxCursor(*wxSTANDARD_CURSOR));
4229 			break;
4230 	}
4231 
4232 	AdjustMenus();
4233 	UpdateModelDisplay();
4234 
4235 }
4236 
InViewMode(void)4237 bool MolDisplayWin::InViewMode(void) {
4238 	return !toolbar || toolbar->GetToolState(MMP_TOOL_ARROW);
4239 }
4240 
InSelectionMode(void)4241 bool MolDisplayWin::InSelectionMode(void) {
4242 	return toolbar && toolbar->GetToolState(MMP_TOOL_LASSO);
4243 }
4244 
InEditMode(void)4245 bool MolDisplayWin::InEditMode(void) {
4246 	return toolbar && toolbar->GetToolState(MMP_TOOL_HAND);
4247 }
4248 
InSymmetryEditMode(void)4249 bool MolDisplayWin::InSymmetryEditMode(void) {
4250 	return edit_symmetrically;
4251 }
4252 
LassoStart(const int x,const int y)4253 void MolDisplayWin::LassoStart(const int x, const int y) {
4254 	lasso_start.x = x;
4255 	lasso_start.y = y;
4256 	lasso_end.x = x;
4257 	lasso_end.y = y;
4258 	lasso_has_area = false;
4259 }
4260 
LassoGrown(const int x,const int y)4261 void MolDisplayWin::LassoGrown(const int x, const int y) {
4262 	lasso_end.x = x;
4263 	lasso_end.y = y;
4264 	lasso_has_area = true;
4265 }
4266 
LassoEnd(void)4267 void MolDisplayWin::LassoEnd(void) {
4268 	lasso_has_area = false;
4269 }
4270 
LassoHasArea(void)4271 bool MolDisplayWin::LassoHasArea(void) {
4272 	return lasso_has_area;
4273 	// return abs(lasso_end.x - lasso_start.x) > 3 &&
4274 		   // abs(lasso_end.y - lasso_start.y) > 3;
4275 }
4276 
LassoContains(const int x,const int y)4277 bool MolDisplayWin::LassoContains(const int x, const int y) {
4278 	return ((x >= lasso_start.x && x <= lasso_end.x) ||
4279 	        (x <= lasso_start.x && x >= lasso_end.x)) &&
4280 	       ((y >= lasso_start.y && y <= lasso_end.y) ||
4281 	        (y <= lasso_start.y && y >= lasso_end.y));
4282 }
4283 
AddSnapshot(UndoSnapShot * s)4284 void UndoData::AddSnapshot(UndoSnapShot * s) {
4285 	while (position < operationCount) {
4286 		//If we are not at the end of the list delete the remaining items
4287 		UndoSnapShot * t = UndoList.back();
4288 		delete t;
4289 		UndoList.pop_back();
4290 		operationCount --;
4291 	}
4292 	UndoList.push_back(s);
4293 	operationCount++;
4294 	position++;
4295 }
4296 
Clear(void)4297 void UndoData::Clear(void) {
4298 	while (UndoList.size() > 0) {
4299 		UndoSnapShot * t = UndoList.back();
4300 		delete t;
4301 		UndoList.pop_back();
4302 	}
4303 	operationCount = 0;
4304 	position = 0;
4305 }
4306 
UndoOperation(void)4307 void UndoData::UndoOperation(void) {
4308 	if ((position > 0)&&(position<=UndoList.size())) {
4309 		UndoList[position-1]->Restore();
4310 		position --;
4311 	}
4312 }
4313 
RedoOperation(void)4314 void UndoData::RedoOperation(void) {
4315 	if ((position >= 0)&&((position+1)<UndoList.size())) {
4316 		position++;
4317 		UndoList[position]->Restore();
4318 	}
4319 }
4320 
FrameSnapShot(MoleculeData * target)4321 FrameSnapShot::FrameSnapShot(MoleculeData * target) {
4322 	IntCoords = NULL;
4323 	targetData = target;
4324 	mTarget = target->cFrame;
4325 	NumAtoms = mTarget->GetNumAtoms();
4326 	NumBonds = mTarget->GetNumBonds();
4327 	Atoms = new mpAtom[NumAtoms];
4328 	Bonds = new Bond[NumBonds];
4329 	for (int i=0; i<NumAtoms; i++)
4330 		Atoms[i] = mTarget->Atoms[i];
4331 	for (int i=0; i<NumBonds; i++)
4332 		Bonds[i] = mTarget->Bonds[i];
4333 	FragmentNames = target->FragmentNames;
4334 	if (target->IntCoords) {
4335 		IntCoords = new Internals(target->IntCoords);
4336 	}
4337 }
4338 
~FrameSnapShot(void)4339 FrameSnapShot::~FrameSnapShot(void) {
4340 	if (Atoms) delete [] Atoms;
4341 	if (Bonds) delete [] Bonds;
4342 	if (IntCoords) delete IntCoords;
4343 }
4344 
Restore(void)4345 void FrameSnapShot::Restore(void) {
4346 	//Ok this makes a gross assumption on the validity of the frame pointer
4347 	if (mTarget) {
4348 		if (mTarget->AtomAllocation < NumAtoms) {
4349 			delete [] mTarget->Atoms;
4350 			mTarget->Atoms = new mpAtom[NumAtoms];
4351 			mTarget->AtomAllocation = NumAtoms;
4352 		}
4353 		if (mTarget->BondAllocation < NumBonds) {
4354 			delete [] mTarget->Bonds;
4355 			mTarget->Bonds = new Bond[NumBonds];
4356 			mTarget->BondAllocation = NumBonds;
4357 		}
4358 		for (int i=0; i<NumAtoms; i++)
4359 			mTarget->Atoms[i] = Atoms[i];
4360 		mTarget->NumAtoms = NumAtoms;
4361 		for (int i=0; i<NumBonds; i++)
4362 			mTarget->Bonds[i] = Bonds[i];
4363 		mTarget->NumBonds = NumBonds;
4364 
4365 		targetData->FragmentNames = FragmentNames;
4366 
4367 		if (IntCoords) {	//restore the internal coordinate definitions
4368 			if (targetData->IntCoords) delete targetData->IntCoords;
4369 			targetData->IntCoords = new Internals(IntCoords);
4370 		}
4371 	}
4372 }
4373 
CreateFrameSnapShot(void)4374 void MolDisplayWin::CreateFrameSnapShot(void) {
4375 	if (Prefs->ToolbarShown()) {
4376 		FrameSnapShot * f = new FrameSnapShot(MainData);
4377 		mUndoBuffer.AddSnapshot(f);
4378 		menuEdit->UpdateUI();
4379 	}
4380 }
4381 
Dirtify(bool is_dirty)4382 void MolDisplayWin::Dirtify(bool is_dirty) {
4383 
4384 	Dirty = is_dirty;
4385 	menuFile->UpdateUI(); // force accelerators to adjust
4386 
4387 }
4388 
ToggleBuilderPalette(void)4389 void MolDisplayWin::ToggleBuilderPalette(void) {
4390 	// Have to make a top-level window for the miniframe to show the right
4391 	// toolbar under OS X.
4392 	wxGetApp().SetTopWindow(this);
4393 
4394 	if (!BuilderTool->IsPaletteVisible()) {
4395 		BuilderTool->ShowPalette(true);
4396 		wxGetApp().AdjustAllMenus();
4397 	} else {
4398 		BuilderTool->ShowPalette(false);
4399 	Dirtify();;
4400 	}
4401 }
4402 
4403 BEGIN_EVENT_TABLE(MolDisplayWin, wxFrame)
4404 	EVT_MENU (MMP_NEWFRAME,         MolDisplayWin::menuFileAppendNewFrame)
4405 #ifndef __WXMAC__
4406 	EVT_MENU (wxID_OPEN,            MolDisplayWin::menuFileOpen)
4407 #endif
4408 	EVT_MENU (MMP_ADDFRAMES,        MolDisplayWin::menuFileAddFramesFromFile)
4409 	EVT_MENU (wxID_SAVE,            MolDisplayWin::menuFileSave)
4410 	EVT_UPDATE_UI(wxID_SAVE,		MolDisplayWin::OnSaveUpdate)
4411 	EVT_MENU (wxID_SAVEAS,          MolDisplayWin::menuFileSave_as)
4412 	EVT_MENU (wxID_CLOSE,           MolDisplayWin::menuFileClose)
4413 	EVT_CLOSE(                      MolDisplayWin::FileClose)
4414 	EVT_MENU (MMP_DELETEFRAME,      MolDisplayWin::menuFileDeleteFrame)
4415 	EVT_MENU (MMP_IMPORTMENU,       MolDisplayWin::menuFileImport)
4416 	EVT_MENU (MMP_EXPORT,           MolDisplayWin::menuFileExport)
4417 	EVT_MENU (wxID_PRINT_SETUP,     MolDisplayWin::menuFilePage_setup)
4418 	EVT_MENU (MMP_PRINTOPTIONS,     MolDisplayWin::menuFilePrintOptions)
4419 	EVT_MENU (wxID_PREVIEW,         MolDisplayWin::menuFilePrint_preview)
4420 	EVT_MENU (wxID_PRINT,           MolDisplayWin::menuFilePrint)
4421 
4422 	EVT_MENU (wxID_UNDO,            MolDisplayWin::menuEditUndo)
4423 	EVT_MENU (wxID_REDO,            MolDisplayWin::menuEditRedo)
4424 	EVT_UPDATE_UI(wxID_UNDO,		MolDisplayWin::OnUndoUpdate)
4425 	EVT_UPDATE_UI(wxID_REDO,		MolDisplayWin::OnRedoUpdate)
4426 	EVT_MENU (wxID_CUT,             MolDisplayWin::menuEditCut)
4427 	EVT_MENU (wxID_COPY,            MolDisplayWin::menuEditCopy)
4428 	EVT_MENU (MMP_COPYCOORDS,       MolDisplayWin::menuEditCopyCoordinates)
4429 	EVT_MENU (MMP_COPYNWCOORDS,		MolDisplayWin::menuEditCopyNWChemCoordinates)
4430 	EVT_MENU (wxID_PASTE,           MolDisplayWin::menuEditPaste)
4431 	EVT_UPDATE_UI(wxID_PASTE,       MolDisplayWin::OnPasteUpdate)
4432 	EVT_MENU (wxID_CLEAR,           MolDisplayWin::menuEditClear)
4433 	EVT_UPDATE_UI(wxID_CLEAR,       MolDisplayWin::OnDeleteUpdate)
4434 	EVT_MENU (MMP_SELECT_ALL,       MolDisplayWin::menuEditSelectAll)
4435 	EVT_MENU (MMP_SELECT_NONE,		MolDisplayWin::menuEditSelectNone)
4436 	EVT_UPDATE_UI(MMP_SELECT_NONE,	MolDisplayWin::OnSelectNoneUpdate)
4437 	EVT_UPDATE_UI(MMP_SELECT_ALL,	MolDisplayWin::OnSelectAllUpdate)
4438 
4439 	EVT_MENU (MMP_SHOW_FULLSCREEN,  MolDisplayWin::menuViewShowFullScreen)
4440 	EVT_UPDATE_UI(MMP_SHOW_FULLSCREEN, MolDisplayWin::OnShowNormalScreen)
4441 	EVT_MENU (MMP_SHOWMODE,         MolDisplayWin::menuViewShowNormalMode)
4442 	EVT_MENU (MMP_ANIMATEMODE,      MolDisplayWin::menuViewAnimateMode)
4443 	EVT_MENU (MMP_OFFSETMODE,       MolDisplayWin::menuViewOffsetAlongMode)
4444 	EVT_MENU (MMP_PREVMODE,         MolDisplayWin::menuViewPrevNormalMode)
4445 	EVT_MENU (MMP_NEXTMODE,         MolDisplayWin::menuViewNextNormalMode)
4446 	EVT_UPDATE_UI(MMP_SHOWGRADIENT, MolDisplayWin::OnViewGradientUpdate )
4447 	EVT_MENU (MMP_SHOWGRADIENT,     MolDisplayWin::menuViewShowGradient)
4448 	EVT_MENU (MMP_SHOWAXIS,         MolDisplayWin::menuViewShowAxis)
4449 	EVT_MENU (MMP_SHOWSYMMETRYOPERATOR, MolDisplayWin::menuViewShowSymmetryOperators)
4450 	EVT_UPDATE_UI(MMP_SHOWSYMMETRYOPERATOR, MolDisplayWin::OnShowSymOpsUpdate )
4451 	EVT_MENU (MMP_NO_ATOMLABEL,		MolDisplayWin::menuViewHideAtomLabels)
4452 	EVT_MENU (MMP_SHOWATOMLABELS,   MolDisplayWin::menuViewShowAtomLabel)
4453 	EVT_MENU (MMP_SHOWATOMNUMBER,   MolDisplayWin::menuViewShowAtomNumber)
4454 	EVT_MENU (MMP_BOTHATOMLABELS,   MolDisplayWin::menuViewShowBothAtomLabels)
4455 	EVT_MENU (MMP_ADDMARKANNOTATION,   MolDisplayWin::menuViewAddMarkAnnotation)
4456 	EVT_MENU (MMP_ADDLENGTHANNOTATION,   MolDisplayWin::menuViewAddAnnotation)
4457 	EVT_MENU (MMP_ADDANGLEANNOTATION,   MolDisplayWin::menuViewAddAnnotation)
4458 	EVT_MENU (MMP_ADDDIHEDRALANNOTATION,   MolDisplayWin::menuViewAddAnnotation)
4459 	EVT_UPDATE_UI(MMP_ADDMARKANNOTATION, MolDisplayWin::OnAnnotationMarkUpdate )
4460 	EVT_UPDATE_UI(MMP_ADDLENGTHANNOTATION, MolDisplayWin::OnAnnotationLengthUpdate )
4461 	EVT_UPDATE_UI(MMP_ADDANGLEANNOTATION, MolDisplayWin::OnAnnotationAngleUpdate )
4462 	EVT_UPDATE_UI(MMP_ADDDIHEDRALANNOTATION, MolDisplayWin::OnAnnotationDihedralUpdate )
4463 	EVT_MENU (MMP_DELETEALLANNOTATIONS,   MolDisplayWin::menuViewDeleteAllAnnotations)
4464 	EVT_UPDATE_UI(MMP_DELETEALLANNOTATIONS, MolDisplayWin::OnDeleteAnnotationsUpdate )
4465 	EVT_MENU (MMP_WIREFRAMEMODE,	MolDisplayWin::menuViewWireFrameStyle)
4466 	EVT_MENU (MMP_BALLANDSTICKMODE,	MolDisplayWin::menuViewBallAndStickStyle)
4467 	EVT_MENU (MMP_EFP_WIREFRAME,	MolDisplayWin::menuViewEFP_Wireframe)
4468 	EVT_UPDATE_UI(MMP_EFP_WIREFRAME,	MolDisplayWin::OnEFPWireFrameUpdate )
4469 	EVT_MENU (MMP_SHOWPATTERN,		MolDisplayWin::menuViewShow2DPattern)
4470 	EVT_UPDATE_UI(MMP_SHOWPATTERN,	MolDisplayWin::OnShowPatternUpdate )
4471 	EVT_MENU (MMP_ANIMATEFRAMES,    MolDisplayWin::menuViewAnimateFrames)
4472 	EVT_MENU (MMP_TOGGLEABINITIO,	MolDisplayWin::menuViewToggleAIAtomsVis)
4473 	EVT_MENU (MMP_TOGGLEMMATOMS,	MolDisplayWin::menuViewToggleMMAtomsVis)
4474 	EVT_MENU (MMP_TOGGLEEFPATOMS,	MolDisplayWin::menuViewToggleEFPAtomsVis)
4475 	EVT_MENU (MMP_SHRINK10,         MolDisplayWin::menuViewShrink_10)
4476 	EVT_MENU (MMP_ENLARGE10,        MolDisplayWin::menuViewEnlarge_10)
4477 	EVT_MENU (MMP_CENTER,           MolDisplayWin::menuViewCenter)
4478 	EVT_MENU (MMP_AUTOROTATE,       MolDisplayWin::menuViewToggleAutoRotation)
4479 	EVT_UPDATE_UI (MMP_AUTOROTATE,   MolDisplayWin::OnAutoRotationUpdate)
4480 	EVT_MENU (MMP_ROTATETOXAXIS,    MolDisplayWin::menuViewRotateTo_X_axis)
4481 	EVT_MENU (MMP_ROTATETOYAXIS,    MolDisplayWin::menuViewRotateTo_Y_axis)
4482 	EVT_MENU (MMP_ROTATETOZAXIS,    MolDisplayWin::menuViewRotateTo_Z_axis)
4483 	EVT_MENU (MMP_ROTATE180HOR,     MolDisplayWin::menuViewRotate180_horizontal)
4484 	EVT_MENU (MMP_ROTATE180VER,     MolDisplayWin::menuViewRotate180_vertical)
4485 	EVT_MENU (MMP_ROTATEPRINC,      MolDisplayWin::menuViewRotatePrinciple_orientation)
4486 	EVT_MENU (MMP_ROTATEOTHER,      MolDisplayWin::menuViewRotateOther)
4487 	EVT_MENU (MMP_WINDOWPARAMETERS,	MolDisplayWin::menuViewSetWindowParameters)
4488 
4489 	EVT_MENU (MMP_SETBONDLENGTH,      MolDisplayWin::menuMoleculeSetBondLength)
4490 	EVT_MENU (MMP_ENERGYEDIT,         MolDisplayWin::menuMoleculeSetFrameEnergy)
4491 	EVT_UPDATE_UI(MMP_CREATELLMPATH,  MolDisplayWin::OnMoleculeCreateLLMPathUpdate )
4492 	EVT_MENU (MMP_CREATELLMPATH,      MolDisplayWin::menuMoleculeCreateLLMPath)
4493 	EVT_MENU (MMP_MINFRAMEMOVEMENTS,  MolDisplayWin::menuMoleculeMinimizeFrameMovements)
4494 	EVT_UPDATE_UI(MMP_CURPOINTGROUP,	MolDisplayWin::OnShowPointGroupUpdate )
4495 	EVT_MENU (MMP_PGC1,					MolDisplayWin::menuSetPointGroup)
4496 	EVT_MENU (MMP_PGCS,					MolDisplayWin::menuSetPointGroup)
4497 	EVT_MENU (MMP_PGCI,					MolDisplayWin::menuSetPointGroup)
4498 	EVT_MENU (MMP_PGCNH,				MolDisplayWin::menuSetPointGroup)
4499 	EVT_MENU (MMP_PGCNV,				MolDisplayWin::menuSetPointGroup)
4500 	EVT_MENU (MMP_PGCN,					MolDisplayWin::menuSetPointGroup)
4501 	EVT_MENU (MMP_PGS2N,				MolDisplayWin::menuSetPointGroup)
4502 	EVT_MENU (MMP_PGDND,				MolDisplayWin::menuSetPointGroup)
4503 	EVT_MENU (MMP_PGDNH,				MolDisplayWin::menuSetPointGroup)
4504 	EVT_MENU (MMP_PGDN,					MolDisplayWin::menuSetPointGroup)
4505 	EVT_MENU (MMP_PGTD,					MolDisplayWin::menuSetPointGroup)
4506 	EVT_MENU (MMP_PGTH,					MolDisplayWin::menuSetPointGroup)
4507 	EVT_MENU (MMP_PGT,					MolDisplayWin::menuSetPointGroup)
4508 	EVT_MENU (MMP_PGOH,					MolDisplayWin::menuSetPointGroup)
4509 	EVT_MENU (MMP_PGO,					MolDisplayWin::menuSetPointGroup)
4510 	EVT_MENU (MMP_PGORDER2,				MolDisplayWin::menuSetPointGroupOrder)
4511 	EVT_MENU (MMP_PGORDER3,				MolDisplayWin::menuSetPointGroupOrder)
4512 	EVT_MENU (MMP_PGORDER4,				MolDisplayWin::menuSetPointGroupOrder)
4513 	EVT_MENU (MMP_PGORDER5,				MolDisplayWin::menuSetPointGroupOrder)
4514 	EVT_MENU (MMP_PGORDER6,				MolDisplayWin::menuSetPointGroupOrder)
4515 	EVT_MENU (MMP_PGORDER7,				MolDisplayWin::menuSetPointGroupOrder)
4516 	EVT_MENU (MMP_PGORDER8,				MolDisplayWin::menuSetPointGroupOrder)
4517 	EVT_MENU (MMP_DETERMINEPG,			MolDisplayWin::menuMoleculeDetermineSym)
4518 	EVT_MENU (MMP_SYMADAPTCOORDS,		MolDisplayWin::menuMoleculeSymCoords)
4519 	EVT_MENU (MMP_CONVERTTOBOHR,		MolDisplayWin::menuMoleculeConvertToBohr)
4520 	EVT_MENU (MMP_CONVERTTOANGSTROMS,	MolDisplayWin::menuMoleculeConvertToAngstroms)
4521 	EVT_MENU (MMP_INVERTNORMALMODE,		MolDisplayWin::menuMoleculeInvertNormalMode)
4522 	EVT_MENU (MMP_SHOW_TOOLBAR,			MolDisplayWin::menuBuilderShowToolbar)
4523 	EVT_UPDATE_UI(MMP_SHOW_TOOLBAR,		MolDisplayWin::OnShowToolbarUpdate)
4524 	EVT_UPDATE_UI(MMP_SHOWBUILDTOOLS,	MolDisplayWin::OnShowBuildToolsUpdate)
4525 	EVT_MENU (MMP_SHOWBUILDTOOLS,		MolDisplayWin::menuBuilderShowBuildTools)
4526 	EVT_MENU (MMP_ADDHYDROGENS,			MolDisplayWin::menuBuilderAddHydrogens)
4527 	EVT_MENU (MMP_DELETEHYDROGENS,		MolDisplayWin::menuBuilderDeleteHydrogens)
4528 	EVT_MENU (MMP_SHOWBONDSITES,		MolDisplayWin::menuBuilderShowBondSites)
4529 	EVT_MENU (MMP_SYMMETRY_EDIT,		MolDisplayWin::menuBuilderSymmetryEdit)
4530 	/* EVT_MENU (MMP_SYMMETRY_REGEN,		MolDisplayWin::menuBuilderRegenSymmetry) */
4531 	EVT_MENU (MMP_SAVESTRUCTURE,		MolDisplayWin::menuBuilderSaveStructure)
4532 	EVT_UPDATE_UI(MMP_ADDHYDROGENS,		MolDisplayWin::OnAddHydrogensUpdate)
4533 	EVT_UPDATE_UI(MMP_SAVESTRUCTURE,	MolDisplayWin::OnSaveStructureUpdate)
4534 	EVT_UPDATE_UI(MMP_SHOWBONDSITES,	MolDisplayWin::OnShowBondSitesUpdate)
4535 	EVT_UPDATE_UI(MMP_SYMMETRY_EDIT,	MolDisplayWin::OnShowSymmetryEdit)
4536 	EVT_UPDATE_UI_RANGE(MMP_NEWFRAME, MMP_ANNOTATIONSSUBMENU,
4537 	                    MolDisplayWin::UpdateAtomsOptions)
4538 	EVT_UPDATE_UI(wxID_COPY,			MolDisplayWin::UpdateAtomsOptions)
4539 	EVT_MENU(MMP_MOLECULEDISPLAYWINDOW, MolDisplayWin::menuWindowMoleculeDisplay)
4540 	EVT_MENU (MMP_BONDSWINDOW,			MolDisplayWin::menuWindowBonds)
4541 	EVT_MENU (MMP_COORDSWINDOW,			MolDisplayWin::menuWindowCoordinates)
4542 	EVT_MENU (MMP_ENERGYPLOTWINDOW,		MolDisplayWin::menuWindowEnergy_plot)
4543 	EVT_MENU (MMP_FREQUENCIESWINDOW,	MolDisplayWin::menuWindowFrequencies)
4544 	EVT_MENU (MMP_INPUTBUILDERWINDOW,	MolDisplayWin::menuWindowInput_builder)
4545 	EVT_MENU (MMP_SURFACESWINDOW,		MolDisplayWin::menuWindowSurfaces)
4546 	EVT_MENU (MMP_LOCAL_PREFERENCES,		MolDisplayWin::menuPreferences)
4547 	EVT_MENU (MMP_ZMATRIXCALC,			MolDisplayWin::menuWindowZMatrixCalc)
4548 
4549 	EVT_TIMER(MMP_ANIMATEFRAMESTIMER, MolDisplayWin::OnFrameAnimationTimer)
4550 	EVT_TIMER(MMP_ANIMATEMODETIMER, MolDisplayWin::OnModeAnimation)
4551 	EVT_TIMER(MMP_STATUS_TIMER, MolDisplayWin::OnStatusTimer)
4552 	EVT_TIMER(MMP_ROTATE_TIMER, MolDisplayWin::OnRotateTimer)
4553 	EVT_SIZE(MolDisplayWin::eventSize)
4554 	EVT_KEY_DOWN (MolDisplayWin::KeyHandler)
4555 	EVT_KEY_UP (MolDisplayWin::KeyUpHandler)
4556 //	EVT_MENU_OPEN(MolDisplayWin::OnMenuOpen)
4557 	EVT_KILL_FOCUS(MolDisplayWin::OnKillFocus)
4558 	EVT_ACTIVATE(MolDisplayWin::OnActivate)
4559 	EVT_TOOL_RANGE(MMP_TOOL_ARROW, MMP_TOOL_HAND, MolDisplayWin::OnToggleTool)
4560 END_EVENT_TABLE()
4561 
4562