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