1 // This file is part of Golly.
2 // See docs/License.html for the copyright notice.
3
4 #include "wx/wxprec.h" // for compilers that support precompilation
5 #ifndef WX_PRECOMP
6 #include "wx/wx.h" // for all others include the necessary headers
7 #endif
8
9 #if wxUSE_TOOLTIPS
10 #include "wx/tooltip.h" // for wxToolTip
11 #endif
12 #include "wx/dnd.h" // for wxFileDropTarget
13 #include "wx/filename.h" // for wxFileName
14 #include "wx/dir.h" // for wxDir
15 #include "wx/clipbrd.h" // for wxTheClipboard
16
17 #include "bigint.h"
18 #include "lifealgo.h"
19 #include "qlifealgo.h"
20 #include "hlifealgo.h"
21
22 #include "wxgolly.h" // for wxGetApp, statusptr, viewptr, bigview
23 #include "wxutils.h" // for Warning, Fatal, etc
24 #include "wxprefs.h" // for gollydir, datadir, SavePrefs, etc
25 #include "wxinfo.h" // for ShowInfo, GetInfoFrame
26 #include "wxhelp.h" // for ShowHelp, GetHelpFrame
27 #include "wxstatus.h" // for statusptr->...
28 #include "wxview.h" // for viewptr->...
29 #include "wxrender.h" // for DestroyDrawingData, etc
30 #include "wxedit.h" // for CreateEditBar, EditBarHeight, etc
31 #include "wxscript.h" // for inscript, PassKeyToScript
32 #include "wxalgos.h" // for algo_type, algomenu, algomenupop
33 #include "wxlayer.h" // for AddLayer, MAX_LAYERS, currlayer
34 #include "wxoverlay.h" // for curroverlay
35 #include "wxundo.h" // for currlayer->undoredo->...
36 #include "wxtimeline.h" // for CreateTimelineBar, TimelineExists, etc
37 #include "wxmain.h"
38
39 #ifdef __WXMAC__
40 #include <Carbon/Carbon.h> // for GetCurrentProcess, etc
41 #endif
42
43 #ifdef USING_VISUAL_LEAK_DETECTOR
44 #include <vld.h>
45 #endif
46
47 // -----------------------------------------------------------------------------
48
49 #ifdef __WXMSW__
50 static bool set_focus = false; // OnIdle needs to call SetFocus?
51 static wxString editpath = wxEmptyString; // OnIdle calls EditFile if this isn't empty
52 #endif
53
54 static bool call_close = false; // OnIdle needs to call Close?
55 static bool edit_file = false; // edit the clicked file?
56
57 // -----------------------------------------------------------------------------
58
59 // ids for bitmap buttons in tool bar
60 enum {
61 START_TOOL = 0,
62 STOP_TOOL,
63 RESET_TOOL,
64 ALGO_TOOL,
65 AUTOFIT_TOOL,
66 HYPER_TOOL,
67 NEW_TOOL,
68 OPEN_TOOL,
69 SAVE_TOOL,
70 FILES_TOOL,
71 INFO_TOOL,
72 HELP_TOOL,
73 NUM_BUTTONS // must be last
74 };
75
76 // bitmaps for tool bar buttons
77 #include "bitmaps/play.xpm"
78 #include "bitmaps/stop.xpm"
79 #include "bitmaps/reset.xpm"
80 #include "bitmaps/algo.xpm"
81 #include "bitmaps/autofit.xpm"
82 #include "bitmaps/hyper.xpm"
83 #include "bitmaps/new.xpm"
84 #include "bitmaps/open.xpm"
85 #include "bitmaps/save.xpm"
86 #include "bitmaps/files.xpm"
87 #include "bitmaps/info.xpm"
88 #include "bitmaps/help.xpm"
89 // bitmaps for down state of toggle buttons
90 #include "bitmaps/autofit_down.xpm"
91 #include "bitmaps/hyper_down.xpm"
92 #include "bitmaps/files_down.xpm"
93
94 // -----------------------------------------------------------------------------
95
96 // Define our own vertical tool bar to avoid bugs and limitations in wxToolBar:
97
98 // derive from wxPanel so we get current theme's background color on Windows
99 class ToolBar : public wxPanel
100 {
101 public:
102 ToolBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht);
~ToolBar()103 ~ToolBar() {}
104
105 // add a bitmap button to tool bar
106 void AddButton(int id, const wxString& tip);
107
108 // add a vertical gap between buttons
109 void AddSeparator();
110
111 // enable/disable button
112 void EnableButton(int id, bool enable);
113
114 // set state of start/stop button
115 void SetStartStopButton();
116
117 // set state of a toggle button
118 void SelectButton(int id, bool select);
119
120 // detect press and release of a bitmap button
121 void OnButtonDown(wxMouseEvent& event);
122 void OnButtonUp(wxMouseEvent& event);
123 void OnKillFocus(wxFocusEvent& event);
124
125 private:
126 // any class wishing to process wxWidgets events must use this macro
127 DECLARE_EVENT_TABLE()
128
129 // event handlers
130 void OnPaint(wxPaintEvent& event);
131 void OnMouseDown(wxMouseEvent& event);
132 void OnButton(wxCommandEvent& event);
133
134 // bitmaps for normal or down state
135 wxBitmap normtool[NUM_BUTTONS];
136 wxBitmap downtool[NUM_BUTTONS];
137
138 #ifdef __WXMSW__
139 // on Windows we need bitmaps for disabled buttons
140 wxBitmap disnormtool[NUM_BUTTONS];
141 wxBitmap disdowntool[NUM_BUTTONS];
142 #endif
143
144 // remember state of toggle buttons to avoid unnecessary drawing;
145 // 0 = not yet initialized, 1 = selected, -1 = not selected
146 int buttstate[NUM_BUTTONS];
147
148 // positioning data used by AddButton and AddSeparator
149 int ypos, xpos, smallgap, biggap;
150 };
151
152 BEGIN_EVENT_TABLE(ToolBar, wxPanel)
153 EVT_PAINT ( ToolBar::OnPaint)
154 EVT_LEFT_DOWN ( ToolBar::OnMouseDown)
155 EVT_BUTTON (wxID_ANY, ToolBar::OnButton)
156 END_EVENT_TABLE()
157
158 ToolBar* toolbarptr = NULL; // global pointer to tool bar
159 const int TOOLBARWD = 32; // width of (vertical) tool bar
160
161 // tool bar buttons (must be global to use Connect/Disconnect on Windows)
162 wxBitmapButton* tbbutt[NUM_BUTTONS];
163
164 // width and height of bitmap buttons
165 #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0)
166 // note that BUTTON_WD will have to be at least 26 to avoid clipping bitmaps
167 // if we decide to use wxBORDER_SUNKEN rather than wxBORDER_SIMPLE
168 // (and TOOLBARWD will probably need to be increased to 48)
169 const int BUTTON_WD = 24;
170 const int BUTTON_HT = 24;
171 #elif defined(__WXOSX_COCOA__) || defined(__WXGTK__)
172 const int BUTTON_WD = 28;
173 const int BUTTON_HT = 28;
174 #else
175 const int BUTTON_WD = 24;
176 const int BUTTON_HT = 24;
177 #endif
178
179 // -----------------------------------------------------------------------------
180
ToolBar(wxWindow * parent,wxCoord xorg,wxCoord yorg,int wd,int ht)181 ToolBar::ToolBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht)
182 : wxPanel(parent, wxID_ANY, wxPoint(xorg,yorg), wxSize(wd,ht),
183 wxNO_FULL_REPAINT_ON_RESIZE)
184 {
185 #ifdef __WXGTK__
186 // avoid erasing background on GTK+
187 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
188 #endif
189
190 // init bitmaps for normal state
191 normtool[START_TOOL] = XPM_BITMAP(play);
192 normtool[STOP_TOOL] = XPM_BITMAP(stop);
193 normtool[RESET_TOOL] = XPM_BITMAP(reset);
194 normtool[ALGO_TOOL] = XPM_BITMAP(algo);
195 normtool[AUTOFIT_TOOL] = XPM_BITMAP(autofit);
196 normtool[HYPER_TOOL] = XPM_BITMAP(hyper);
197 normtool[NEW_TOOL] = XPM_BITMAP(new);
198 normtool[OPEN_TOOL] = XPM_BITMAP(open);
199 normtool[SAVE_TOOL] = XPM_BITMAP(save);
200 normtool[FILES_TOOL] = XPM_BITMAP(files);
201 normtool[INFO_TOOL] = XPM_BITMAP(info);
202 normtool[HELP_TOOL] = XPM_BITMAP(help);
203
204 // toggle buttons also have a down state
205 downtool[AUTOFIT_TOOL] = XPM_BITMAP(autofit_down);
206 downtool[HYPER_TOOL] = XPM_BITMAP(hyper_down);
207 downtool[FILES_TOOL] = XPM_BITMAP(files_down);
208
209 #ifdef __WXMSW__
210 for (int i = 0; i < NUM_BUTTONS; i++) {
211 CreatePaleBitmap(normtool[i], disnormtool[i]);
212 }
213 CreatePaleBitmap(downtool[AUTOFIT_TOOL], disdowntool[AUTOFIT_TOOL]);
214 CreatePaleBitmap(downtool[HYPER_TOOL], disdowntool[HYPER_TOOL]);
215 CreatePaleBitmap(downtool[FILES_TOOL], disdowntool[FILES_TOOL]);
216 #endif
217
218 for (int i = 0; i < NUM_BUTTONS; i++) {
219 buttstate[i] = 0;
220 }
221
222 // init position variables used by AddButton and AddSeparator
223 #ifdef __WXGTK__
224 // buttons are a different size in wxGTK
225 xpos = 2;
226 ypos = 2;
227 smallgap = 6;
228 #else
229 xpos = (32 - BUTTON_WD) / 2;
230 ypos = (32 - BUTTON_HT) / 2;
231 smallgap = 4;
232 #endif
233 biggap = 16;
234 }
235
236 // -----------------------------------------------------------------------------
237
OnPaint(wxPaintEvent & WXUNUSED (event))238 void ToolBar::OnPaint(wxPaintEvent& WXUNUSED(event))
239 {
240 wxPaintDC dc(this);
241
242 int wd, ht;
243 GetClientSize(&wd, &ht);
244 if (wd < 1 || ht < 1 || !showtool) return;
245
246 wxRect r = wxRect(0, 0, wd, ht);
247 #ifdef __WXMSW__
248 dc.Clear();
249 // draw gray line at top edge
250 dc.SetPen(*wxGREY_PEN);
251 dc.DrawLine(0, 0, r.width, 0);
252 dc.SetPen(wxNullPen);
253 #else
254 // draw gray line at right edge
255 #ifdef __WXMAC__
256 wxBrush brush(wxColor(202,202,202));
257 FillRect(dc, r, brush);
258 wxPen linepen(wxColor(140,140,140));
259 dc.SetPen(linepen);
260 #else
261 dc.SetPen(*wxLIGHT_GREY_PEN);
262 #endif
263 dc.DrawLine(r.GetRight(), 0, r.GetRight(), r.height);
264 dc.SetPen(wxNullPen);
265 #endif
266 }
267
268 // -----------------------------------------------------------------------------
269
OnMouseDown(wxMouseEvent & WXUNUSED (event))270 void ToolBar::OnMouseDown(wxMouseEvent& WXUNUSED(event))
271 {
272 // this is NOT called if user clicks a tool bar button;
273 // on Windows we need to reset keyboard focus to viewport window
274 viewptr->SetFocus();
275 }
276
277 // -----------------------------------------------------------------------------
278
OnButton(wxCommandEvent & event)279 void ToolBar::OnButton(wxCommandEvent& event)
280 {
281 int id = event.GetId();
282
283 int cmdid;
284 switch (id) {
285 case START_TOOL: cmdid = ID_START; break;
286 case RESET_TOOL: cmdid = ID_RESET; break;
287 case ALGO_TOOL: return; // handled in OnButtonDown
288 case AUTOFIT_TOOL: cmdid = ID_AUTO; break;
289 case HYPER_TOOL: cmdid = ID_HYPER; break;
290 case NEW_TOOL: cmdid = wxID_NEW; break;
291 case OPEN_TOOL: cmdid = wxID_OPEN; break;
292 case SAVE_TOOL: cmdid = wxID_SAVE; break;
293 case FILES_TOOL: cmdid = ID_SHOW_FILES; break;
294 case INFO_TOOL: cmdid = ID_INFO; break;
295 case HELP_TOOL: cmdid = ID_HELP_BUTT; break;
296 default: Warning(_("Unexpected button id!")); return;
297 }
298
299 // call MainFrame::OnMenu after OnButton finishes;
300 // this avoids start/stop button problem in GTK app
301 wxCommandEvent cmdevt(wxEVT_COMMAND_MENU_SELECTED, cmdid);
302 wxPostEvent(mainptr->GetEventHandler(), cmdevt);
303
304 // avoid weird bug on Mac where all buttons can be disabled after hitting
305 // RESET_TOOL button *and* the "All controls" option is ticked in
306 // System Prefs > Keyboard & Mouse > Keyboard Shortcuts
307 // (might also fix similar problem on Windows)
308 viewptr->SetFocus();
309 }
310
311 // -----------------------------------------------------------------------------
312
OnKillFocus(wxFocusEvent & event)313 void ToolBar::OnKillFocus(wxFocusEvent& event)
314 {
315 int id = event.GetId();
316 tbbutt[id]->SetFocus(); // don't let button lose focus
317 }
318
319 // -----------------------------------------------------------------------------
320
OnButtonDown(wxMouseEvent & event)321 void ToolBar::OnButtonDown(wxMouseEvent& event)
322 {
323 // a tool bar button has been pressed
324 int id = event.GetId();
325
326 #ifdef __WXMSW__
327 // connect a handler that keeps focus with the pressed button
328 if (id != ALGO_TOOL)
329 tbbutt[id]->Connect(id, wxEVT_KILL_FOCUS,
330 wxFocusEventHandler(ToolBar::OnKillFocus));
331 #endif
332
333 #ifdef __WXMAC__
334 // close any open tool tip window (probably wxMac bug)
335 wxToolTip::RemoveToolTips();
336 #endif
337
338 // we want pop-up menu to appear as soon as ALGO_TOOL button is pressed
339 if (id == ALGO_TOOL) {
340 // we use algomenupop here rather than algomenu to avoid assert messages in wx 2.9+
341 #ifdef __WXMSW__
342 tbbutt[id]->PopupMenu(algomenupop, 0, 25);
343 // fix prob on Win (almost -- button-up doesn't always close menu)
344 viewptr->SetFocus();
345 return;
346 #else
347 tbbutt[id]->PopupMenu(algomenupop, 0, 30);
348 #endif
349
350 #ifdef __WXOSX_COCOA__
351 viewptr->SetFocus();
352 // don't call event.Skip() otherwise algo button will remain selected
353 return;
354 #endif
355 }
356
357 event.Skip();
358 }
359
360 // -----------------------------------------------------------------------------
361
OnButtonUp(wxMouseEvent & event)362 void ToolBar::OnButtonUp(wxMouseEvent& event)
363 {
364 // a tool bar button has been released (only called in wxMSW)
365 int id = event.GetId();
366
367 wxPoint pt = tbbutt[id]->ScreenToClient( wxGetMousePosition() );
368
369 int wd, ht;
370 tbbutt[id]->GetClientSize(&wd, &ht);
371 wxRect r(0, 0, wd, ht);
372
373 // diconnect kill-focus handler
374 if (id != ALGO_TOOL)
375 tbbutt[id]->Disconnect(id, wxEVT_KILL_FOCUS,
376 wxFocusEventHandler(ToolBar::OnKillFocus));
377 viewptr->SetFocus();
378
379 if ( r.Contains(pt) ) {
380 // call OnButton
381 wxCommandEvent buttevt(wxEVT_COMMAND_BUTTON_CLICKED, id);
382 buttevt.SetEventObject(tbbutt[id]);
383 tbbutt[id]->GetEventHandler()->ProcessEvent(buttevt);
384 }
385 }
386
387 // -----------------------------------------------------------------------------
388
AddButton(int id,const wxString & tip)389 void ToolBar::AddButton(int id, const wxString& tip)
390 {
391 tbbutt[id] = new wxBitmapButton(this, id, normtool[id], wxPoint(xpos,ypos),
392 #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0)
393 wxSize(BUTTON_WD, BUTTON_HT), wxBORDER_SIMPLE
394 #else
395 wxSize(BUTTON_WD, BUTTON_HT)
396 #endif
397 );
398 if (tbbutt[id] == NULL) {
399 Fatal(_("Failed to create tool bar button!"));
400 } else {
401 ypos += BUTTON_HT + smallgap;
402 tbbutt[id]->SetToolTip(tip);
403 #ifdef __WXMSW__
404 // fix problem with tool bar buttons when generating/inscript
405 // due to focus being changed to viewptr
406 tbbutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(ToolBar::OnButtonDown));
407 tbbutt[id]->Connect(id, wxEVT_LEFT_UP, wxMouseEventHandler(ToolBar::OnButtonUp));
408 #else
409 // allow pop-up menu to appear as soon as ALGO_TOOL button is pressed
410 tbbutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(ToolBar::OnButtonDown));
411 #endif
412 }
413 }
414
415 // -----------------------------------------------------------------------------
416
AddSeparator()417 void ToolBar::AddSeparator()
418 {
419 ypos += biggap - smallgap;
420 }
421
422 // -----------------------------------------------------------------------------
423
EnableButton(int id,bool enable)424 void ToolBar::EnableButton(int id, bool enable)
425 {
426 if (enable == tbbutt[id]->IsEnabled()) return;
427
428 #ifdef __WXMSW__
429 if (id == START_TOOL && (inscript || mainptr->generating)) {
430 tbbutt[id]->SetBitmapDisabled(disnormtool[STOP_TOOL]);
431
432 } else if (id == AUTOFIT_TOOL && currlayer->autofit) {
433 tbbutt[id]->SetBitmapDisabled(disdowntool[id]);
434
435 } else if (id == HYPER_TOOL && currlayer->hyperspeed) {
436 tbbutt[id]->SetBitmapDisabled(disdowntool[id]);
437
438 } else if (id == FILES_TOOL && showfiles) {
439 tbbutt[id]->SetBitmapDisabled(disdowntool[id]);
440
441 } else {
442 tbbutt[id]->SetBitmapDisabled(disnormtool[id]);
443 }
444 #endif
445
446 tbbutt[id]->Enable(enable);
447 }
448
449 // -----------------------------------------------------------------------------
450
SetStartStopButton()451 void ToolBar::SetStartStopButton()
452 {
453 if (inscript || mainptr->generating) {
454 // show stop bitmap
455 if (buttstate[START_TOOL] == 1) return;
456 buttstate[START_TOOL] = 1;
457 tbbutt[START_TOOL]->SetBitmapLabel(normtool[STOP_TOOL]);
458 if (inscript)
459 tbbutt[START_TOOL]->SetToolTip(_("Stop script"));
460 else
461 tbbutt[START_TOOL]->SetToolTip(_("Stop generating"));
462 } else {
463 // show start bitmap
464 if (buttstate[START_TOOL] == -1) return;
465 buttstate[START_TOOL] = -1;
466 tbbutt[START_TOOL]->SetBitmapLabel(normtool[START_TOOL]);
467 tbbutt[START_TOOL]->SetToolTip(_("Start generating"));
468 }
469
470 tbbutt[START_TOOL]->Refresh(false);
471 }
472
473 // -----------------------------------------------------------------------------
474
SelectButton(int id,bool select)475 void ToolBar::SelectButton(int id, bool select)
476 {
477 if (select) {
478 if (buttstate[id] == 1) return;
479 buttstate[id] = 1;
480 tbbutt[id]->SetBitmapLabel(downtool[id]);
481 } else {
482 if (buttstate[id] == -1) return;
483 buttstate[id] = -1;
484 tbbutt[id]->SetBitmapLabel(normtool[id]);
485 }
486
487 tbbutt[id]->Refresh(false);
488 }
489
490 // -----------------------------------------------------------------------------
491
CreateToolbar()492 void MainFrame::CreateToolbar()
493 {
494 int wd, ht;
495 GetClientSize(&wd, &ht);
496
497 toolbarptr = new ToolBar(this, 0, 0, TOOLBARWD, ht);
498
499 // add buttons to tool bar
500 toolbarptr->AddButton(START_TOOL, _("Start generating"));
501 toolbarptr->AddButton(RESET_TOOL, _("Reset"));
502 toolbarptr->AddSeparator();
503 toolbarptr->AddButton(ALGO_TOOL, _("Set algorithm"));
504 toolbarptr->AddButton(AUTOFIT_TOOL, _("Auto fit"));
505 toolbarptr->AddButton(HYPER_TOOL, _("Hyperspeed"));
506 toolbarptr->AddSeparator();
507 toolbarptr->AddButton(NEW_TOOL, _("New pattern"));
508 toolbarptr->AddButton(OPEN_TOOL, _("Open pattern"));
509 toolbarptr->AddButton(SAVE_TOOL, _("Save pattern"));
510 toolbarptr->AddSeparator();
511 toolbarptr->AddButton(FILES_TOOL, _("Show/hide files"));
512 toolbarptr->AddSeparator();
513 toolbarptr->AddButton(INFO_TOOL, _("Show pattern information"));
514 toolbarptr->AddButton(HELP_TOOL, _("Show help window"));
515
516 toolbarptr->Show(showtool);
517 }
518
519 // -----------------------------------------------------------------------------
520
UpdateToolBar()521 void MainFrame::UpdateToolBar()
522 {
523 // update tool bar buttons according to the current state
524 if (toolbarptr && showtool) {
525 bool active = !viewptr->waitingforclick;
526 bool timeline = TimelineExists();
527
528 // set state of start/stop button
529 toolbarptr->SetStartStopButton();
530
531 // set state of toggle buttons
532 toolbarptr->SelectButton(AUTOFIT_TOOL, currlayer->autofit);
533 toolbarptr->SelectButton(HYPER_TOOL, currlayer->hyperspeed);
534 toolbarptr->SelectButton(FILES_TOOL, showfiles);
535
536 toolbarptr->EnableButton(START_TOOL, active && !timeline);
537 toolbarptr->EnableButton(RESET_TOOL, active && !timeline && !inscript &&
538 (generating || currlayer->algo->getGeneration() > currlayer->startgen));
539 toolbarptr->EnableButton(ALGO_TOOL, active && !timeline && !inscript);
540 toolbarptr->EnableButton(AUTOFIT_TOOL, active);
541 toolbarptr->EnableButton(HYPER_TOOL, active && !timeline);
542 toolbarptr->EnableButton(NEW_TOOL, active && !inscript);
543 toolbarptr->EnableButton(OPEN_TOOL, active && !inscript);
544 toolbarptr->EnableButton(SAVE_TOOL, active && !inscript);
545 toolbarptr->EnableButton(FILES_TOOL, active);
546 toolbarptr->EnableButton(INFO_TOOL, active && !currlayer->currfile.IsEmpty());
547 toolbarptr->EnableButton(HELP_TOOL, active);
548 }
549 }
550
551 // -----------------------------------------------------------------------------
552
ClipboardHasText()553 bool MainFrame::ClipboardHasText()
554 {
555 bool hastext = false;
556 #ifdef __WXGTK__
557 // avoid re-entrancy bug in wxGTK 2.9.x
558 if (wxTheClipboard->IsOpened()) return false;
559 #endif
560 if (wxTheClipboard->Open()) {
561 hastext = wxTheClipboard->IsSupported(wxDF_TEXT);
562 if (!hastext) {
563 // we'll try to convert bitmap data to text pattern
564 hastext = wxTheClipboard->IsSupported(wxDF_BITMAP);
565 }
566 wxTheClipboard->Close();
567 }
568 return hastext;
569 }
570
571 // -----------------------------------------------------------------------------
572
EnableAllMenus(bool enable)573 void MainFrame::EnableAllMenus(bool enable)
574 {
575 wxMenuBar* mbar = GetMenuBar();
576 if (mbar) {
577 int count = (int)(mbar->GetMenuCount());
578 int i;
579 for (i = 0; i < count; i++) {
580 mbar->EnableTop(i, enable);
581 }
582 #ifdef __WXOSX_COCOA__
583 // enable/disable items in app menu
584 mbar->Enable(wxID_ABOUT, enable);
585 mbar->Enable(wxID_PREFERENCES, enable);
586 mbar->Enable(wxID_EXIT, enable);
587 #endif
588 }
589 }
590
591 // -----------------------------------------------------------------------------
592
UpdateMenuItems()593 void MainFrame::UpdateMenuItems()
594 {
595 // update menu bar items according to the given state
596 wxMenuBar* mbar = GetMenuBar();
597 if (mbar) {
598 // we need to disable most menu items if main window is not in front so user can
599 // hit return key to close help/info window rather than start/stop generating
600 bool active = infront && !viewptr->waitingforclick;
601
602 bool selexists = viewptr->SelectionExists();
603 bool timeline = TimelineExists();
604 bool textinclip = ClipboardHasText();
605
606 mbar->Enable(wxID_NEW, active && !inscript);
607 mbar->Enable(wxID_OPEN, active && !inscript);
608 mbar->Enable(ID_OPEN_CLIP, active && !inscript && textinclip);
609 mbar->Enable(ID_OPEN_RECENT, active && !inscript && numpatterns > 0);
610 mbar->Enable(wxID_SAVE, active && !inscript);
611 mbar->Enable(ID_SAVE_XRLE, active);
612 mbar->Enable(ID_RUN_SCRIPT, active && !timeline && !inscript);
613 mbar->Enable(ID_RUN_CLIP, active && !timeline && !inscript && textinclip);
614 mbar->Enable(ID_RUN_RECENT, active && !timeline && !inscript && numscripts > 0);
615 mbar->Enable(ID_SHOW_FILES, active);
616 mbar->Enable(ID_FILE_DIR, active);
617 // safer not to allow prefs dialog while script is running???
618 // mbar->Enable(wxID_PREFERENCES, !inscript);
619
620 bool can_undo = active && !timeline && currlayer->undoredo->CanUndo();
621 bool can_redo = active && !timeline && currlayer->undoredo->CanRedo();
622
623 mbar->Enable(ID_UNDO, can_undo);
624 mbar->Enable(ID_REDO, can_redo);
625 mbar->Enable(ID_NO_UNDO, active && !inscript);
626 mbar->Enable(ID_CUT, active && !timeline && !inscript && selexists);
627 mbar->Enable(ID_COPY, active && !inscript && selexists);
628 mbar->Enable(ID_CLEAR, active && !timeline && !inscript && selexists);
629 mbar->Enable(ID_OUTSIDE, active && !timeline && !inscript && selexists);
630 mbar->Enable(ID_PASTE, active && !timeline && !inscript && textinclip);
631 mbar->Enable(ID_PASTE_SEL, active && !timeline && !inscript && textinclip && selexists);
632 mbar->Enable(ID_PLOCATION, active);
633 mbar->Enable(ID_PMODE, active);
634 mbar->Enable(ID_SELECTALL, active && !inscript);
635 mbar->Enable(ID_REMOVE, active && !inscript && selexists);
636 mbar->Enable(ID_SHRINK, active && !inscript && selexists);
637 mbar->Enable(ID_RANDOM, active && !timeline && !inscript && selexists);
638 mbar->Enable(ID_FLIPTB, active && !timeline && !inscript && selexists);
639 mbar->Enable(ID_FLIPLR, active && !timeline && !inscript && selexists);
640 mbar->Enable(ID_ROTATEC, active && !timeline && !inscript && selexists);
641 mbar->Enable(ID_ROTATEA, active && !timeline && !inscript && selexists);
642 mbar->Enable(ID_CMODE, active);
643
644 if (inscript) {
645 // WARNING: next line is no longer needed on wxMac and actually caused a bad memory leak!
646 // mbar->SetLabel(ID_START, _("x"));
647 // escape key can be used to abort a running script
648 mbar->SetLabel(ID_START, _("Stop Script\tEscape"));
649 } else if (generating) {
650 mbar->SetLabel(ID_START, _("Stop Generating") + GetAccelerator(DO_STARTSTOP));
651 } else if (timeline && !currlayer->algo->isrecording()) {
652 if (TimelineIsPlaying())
653 mbar->SetLabel(ID_START, _("Stop Playing Timeline") + GetAccelerator(DO_STARTSTOP));
654 else
655 mbar->SetLabel(ID_START, _("Start Playing Timeline") + GetAccelerator(DO_STARTSTOP));
656 } else {
657 mbar->SetLabel(ID_START, _("Start Generating") + GetAccelerator(DO_STARTSTOP));
658 }
659
660 if (currlayer->algo->isrecording()) {
661 mbar->SetLabel(ID_RECORD, _("Stop Recording") + GetAccelerator(DO_RECORD));
662 } else {
663 mbar->SetLabel(ID_RECORD, _("Start Recording") + GetAccelerator(DO_RECORD));
664 }
665
666 mbar->Enable(ID_START, active && !currlayer->algo->isrecording());
667 #ifdef __WXMAC__
668 // for some unknown reason we need to disable these menu items when generating
669 // otherwise auto-repeating space/tab key doesn't work all the time
670 mbar->Enable(ID_NEXT, active && !timeline && !inscript && !generating);
671 mbar->Enable(ID_STEP, active && !timeline && !inscript && !generating);
672 #else
673 mbar->Enable(ID_NEXT, active && !timeline && !inscript);
674 mbar->Enable(ID_STEP, active && !timeline && !inscript);
675 #endif
676 mbar->Enable(ID_RESET, active && !timeline && !inscript &&
677 (generating || currlayer->algo->getGeneration() > currlayer->startgen));
678 mbar->Enable(ID_SETGEN, active && !timeline && !inscript);
679 mbar->Enable(ID_FASTER, active && !inscript && !(timeline && currlayer->algo->isrecording()));
680 mbar->Enable(ID_SLOWER, active && !inscript && !(timeline && currlayer->algo->isrecording()));
681 mbar->Enable(ID_SETBASE, active && !timeline && !inscript);
682 mbar->Enable(ID_AUTO, active);
683 mbar->Enable(ID_HYPER, active && !timeline);
684 mbar->Enable(ID_HINFO, active);
685 mbar->Enable(ID_SHOW_POP, active);
686 mbar->Enable(ID_RECORD, active && !inscript && currlayer->algo->hyperCapable());
687 mbar->Enable(ID_DELTIME, active && !inscript && timeline && !currlayer->algo->isrecording());
688 mbar->Enable(ID_CONVERT, active && !timeline && !inscript);
689 mbar->Enable(ID_SETALGO, active && !timeline && !inscript);
690 mbar->Enable(ID_SETRULE, active && !timeline && !inscript);
691
692 mbar->Enable(ID_FULL, active);
693 mbar->Enable(ID_FIT, active);
694 mbar->Enable(ID_FIT_SEL, active && selexists);
695 mbar->Enable(ID_MIDDLE, active);
696 mbar->Enable(ID_RESTORE00, active && (currlayer->originx != bigint::zero ||
697 currlayer->originy != bigint::zero));
698 mbar->Enable(wxID_ZOOM_IN, active /* && viewptr->GetMag() < MAX_MAG */);
699 // don't do this test because Win users won't hear beep
700 mbar->Enable(wxID_ZOOM_OUT, active);
701 mbar->Enable(ID_SET_SCALE, active);
702 mbar->Enable(ID_TOOL_BAR, active);
703 mbar->Enable(ID_LAYER_BAR, active);
704 mbar->Enable(ID_EDIT_BAR, active);
705 mbar->Enable(ID_ALL_STATES, active);
706 mbar->Enable(ID_STATUS_BAR, active);
707 mbar->Enable(ID_EXACT, active);
708 mbar->Enable(ID_GRID, active);
709 mbar->Enable(ID_ICONS, active);
710 mbar->Enable(ID_INVERT, active);
711 mbar->Enable(ID_SMARTSCALE, active);
712 mbar->Enable(ID_TIMELINE, active);
713 mbar->Enable(ID_SCROLL, active);
714 mbar->Enable(ID_INFO, !currlayer->currfile.IsEmpty());
715
716 mbar->Enable(ID_SAVE_OVERLAY, active && showoverlay && curroverlay->GetOverlayData());
717 mbar->Enable(ID_SHOW_OVERLAY, active);
718 mbar->Enable(ID_DEL_OVERLAY, active && !inscript && curroverlay->GetOverlayData());
719 mbar->Enable(ID_ADD_LAYER, active && !inscript && numlayers < MAX_LAYERS);
720 mbar->Enable(ID_CLONE, active && !inscript && numlayers < MAX_LAYERS);
721 mbar->Enable(ID_DUPLICATE, active && !inscript && numlayers < MAX_LAYERS);
722 mbar->Enable(ID_DEL_LAYER, active && !inscript && numlayers > 1);
723 mbar->Enable(ID_DEL_OTHERS, active && !inscript && numlayers > 1);
724 mbar->Enable(ID_MOVE_LAYER, active && !inscript && numlayers > 1);
725 mbar->Enable(ID_NAME_LAYER, active && !inscript);
726 mbar->Enable(ID_SET_COLORS, active && !inscript);
727 mbar->Enable(ID_SYNC_VIEW, active);
728 mbar->Enable(ID_SYNC_CURS, active);
729 mbar->Enable(ID_STACK, active);
730 mbar->Enable(ID_TILE, active);
731 for (int i = 0; i < numlayers; i++)
732 mbar->Enable(ID_LAYER0 + i, active && CanSwitchLayer(i));
733
734 // tick/untick menu items created using AppendCheckItem
735 mbar->Check(ID_SAVE_XRLE, savexrle);
736 mbar->Check(ID_SHOW_FILES, showfiles);
737 mbar->Check(ID_NO_UNDO, !allowundo);
738 mbar->Check(ID_AUTO, currlayer->autofit);
739 mbar->Check(ID_HYPER, currlayer->hyperspeed);
740 mbar->Check(ID_HINFO, currlayer->showhashinfo);
741 mbar->Check(ID_SHOW_POP, showpopulation);
742 mbar->Check(ID_TOOL_BAR, showtool);
743 mbar->Check(ID_LAYER_BAR, showlayer);
744 mbar->Check(ID_EDIT_BAR, showedit);
745 mbar->Check(ID_ALL_STATES, showallstates);
746 mbar->Check(ID_STATUS_BAR, showstatus);
747 mbar->Check(ID_EXACT, showexact);
748 mbar->Check(ID_GRID, showgridlines);
749 mbar->Check(ID_ICONS, showicons);
750 mbar->Check(ID_INVERT, swapcolors);
751 mbar->Check(ID_SMARTSCALE, smartscale);
752 mbar->Check(ID_TIMELINE, showtimeline);
753 mbar->Check(ID_SCROLL, showscrollbars);
754 mbar->Check(ID_PL_TL, plocation == TopLeft);
755 mbar->Check(ID_PL_TR, plocation == TopRight);
756 mbar->Check(ID_PL_BR, plocation == BottomRight);
757 mbar->Check(ID_PL_BL, plocation == BottomLeft);
758 mbar->Check(ID_PL_MID, plocation == Middle);
759 mbar->Check(ID_PM_AND, pmode == And);
760 mbar->Check(ID_PM_COPY, pmode == Copy);
761 mbar->Check(ID_PM_OR, pmode == Or);
762 mbar->Check(ID_PM_XOR, pmode == Xor);
763 mbar->Check(ID_DRAW, currlayer->curs == curs_pencil);
764 mbar->Check(ID_PICK, currlayer->curs == curs_pick);
765 mbar->Check(ID_SELECT, currlayer->curs == curs_cross);
766 mbar->Check(ID_MOVE, currlayer->curs == curs_hand);
767 mbar->Check(ID_ZOOMIN, currlayer->curs == curs_zoomin);
768 mbar->Check(ID_ZOOMOUT, currlayer->curs == curs_zoomout);
769 mbar->Check(ID_SCALE_1, viewptr->GetMag() == 0);
770 mbar->Check(ID_SCALE_2, viewptr->GetMag() == 1);
771 mbar->Check(ID_SCALE_4, viewptr->GetMag() == 2);
772 mbar->Check(ID_SCALE_8, viewptr->GetMag() == 3);
773 mbar->Check(ID_SCALE_16, viewptr->GetMag() == 4);
774 mbar->Check(ID_SCALE_32, viewptr->GetMag() == 5);
775 mbar->Check(ID_SYNC_VIEW, syncviews);
776 mbar->Check(ID_SYNC_CURS, synccursors);
777 mbar->Check(ID_STACK, stacklayers);
778 mbar->Check(ID_TILE, tilelayers);
779 mbar->Check(ID_SHOW_OVERLAY, showoverlay);
780 for (int i = 0; i < NumAlgos(); i++) {
781 mbar->Check(ID_ALGO0 + i, currlayer->algtype == i);
782 // keep algomenupop in sync with algomenu
783 algomenupop->Check(ID_ALGO0 + i, currlayer->algtype == i);
784 }
785 for (int i = 0; i < numlayers; i++) {
786 mbar->Check(ID_LAYER0 + i, currindex == i);
787 }
788 }
789 }
790
791 // -----------------------------------------------------------------------------
792
UpdateUserInterface()793 void MainFrame::UpdateUserInterface()
794 {
795 UpdateToolBar();
796 UpdateLayerBar();
797 UpdateEditBar();
798 UpdateTimelineBar();
799 UpdateMenuItems();
800 viewptr->CheckCursor(infront);
801 statusptr->CheckMouseLocation(infront);
802
803 #ifdef __WXMSW__
804 // ensure viewport window has keyboard focus if main window is active
805 if (infront) viewptr->SetFocus();
806 #endif
807 }
808
809 // -----------------------------------------------------------------------------
810
811 // update everything in main window, and menu bar and cursor
UpdateEverything()812 void MainFrame::UpdateEverything()
813 {
814 if (IsIconized()) {
815 // main window has been minimized, so only update menu bar items
816 UpdateMenuItems();
817 return;
818 }
819
820 // update all tool bars, menus and cursor
821 UpdateUserInterface();
822
823 if (inscript) {
824 // make sure scroll bars are accurate while running script
825 bigview->UpdateScrollBars();
826 return;
827 }
828
829 int wd, ht;
830 GetClientSize(&wd, &ht); // includes status bar and viewport
831
832 if (wd > 0 && ht > statusptr->statusht) {
833 bigview->Refresh(false);
834 bigview->UpdateScrollBars();
835 }
836
837 if (wd > 0 && ht > 0 && showstatus) {
838 statusptr->Refresh(false);
839 }
840 }
841
842 // -----------------------------------------------------------------------------
843
844 // only update viewport and status bar
UpdatePatternAndStatus(bool update_now)845 void MainFrame::UpdatePatternAndStatus(bool update_now)
846 {
847 if (inscript || currlayer->undoredo->doingscriptchanges) return;
848
849 if (!IsIconized()) {
850 bigview->Refresh(false);
851 if (update_now) bigview->Update();
852 if (showstatus) {
853 statusptr->CheckMouseLocation(infront);
854 statusptr->Refresh(false);
855 if (update_now) statusptr->Update();
856 }
857 }
858 }
859
860 // -----------------------------------------------------------------------------
861
862 // only update status bar
UpdateStatus()863 void MainFrame::UpdateStatus()
864 {
865 if (inscript || currlayer->undoredo->doingscriptchanges) return;
866
867 if (!IsIconized()) {
868 if (showstatus) {
869 statusptr->CheckMouseLocation(infront);
870 statusptr->Refresh(false);
871 }
872 }
873 }
874
875 // -----------------------------------------------------------------------------
876
SimplifyTree(wxString & indir,wxTreeCtrl * treectrl,wxTreeItemId root)877 void MainFrame::SimplifyTree(wxString& indir, wxTreeCtrl* treectrl, wxTreeItemId root)
878 {
879 // delete old tree (except root)
880 treectrl->DeleteChildren(root);
881
882 // remove any terminating separator
883 wxString dir = indir;
884 if (dir.Last() == wxFILE_SEP_PATH) dir.Truncate(dir.Length()-1);
885
886 // append dir as only child
887 wxDirItemData* diritem = new wxDirItemData(dir, dir, true);
888 wxTreeItemId id;
889 id = treectrl->AppendItem(root, dir.AfterLast(wxFILE_SEP_PATH), 0, 0, diritem);
890 if ( diritem->HasFiles() || diritem->HasSubDirs() ) {
891 treectrl->SetItemHasChildren(id);
892 treectrl->Expand(id);
893 #ifndef __WXMSW__
894 // can cause crash on Windows
895 treectrl->ScrollTo(root);
896 #endif
897 }
898
899 // select top folder so hitting left arrow can collapse it and won't cause an assert
900 wxTreeItemIdValue cookie;
901 id = treectrl->GetFirstChild(root, cookie);
902 if (id.IsOk()) treectrl->SelectItem(id);
903 }
904
905 // -----------------------------------------------------------------------------
906
907 // Define a window for right pane of split window:
908
909 class RightWindow : public wxWindow
910 {
911 public:
RightWindow(wxWindow * parent)912 RightWindow(wxWindow* parent)
913 : wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
914 wxNO_BORDER |
915 #ifdef __WXMSW__
916 // need this to avoid layer/edit/timeline bar buttons flashing on Windows
917 wxNO_FULL_REPAINT_ON_RESIZE
918 #else
919 // better for Mac and Linux
920 wxFULL_REPAINT_ON_RESIZE
921 #endif
922 )
923 {
924 #ifdef __WXGTK__
925 // avoid erasing background on GTK+
926 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
927 #endif
928 }
~RightWindow()929 ~RightWindow() {}
930
931 // event handlers
932 void OnSize(wxSizeEvent& event);
933 void OnEraseBackground(wxEraseEvent& event);
934
935 DECLARE_EVENT_TABLE()
936 };
937
BEGIN_EVENT_TABLE(RightWindow,wxWindow)938 BEGIN_EVENT_TABLE(RightWindow, wxWindow)
939 EVT_ERASE_BACKGROUND (RightWindow::OnEraseBackground)
940 EVT_SIZE (RightWindow::OnSize)
941 END_EVENT_TABLE()
942
943 // -----------------------------------------------------------------------------
944
945 void RightWindow::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
946 {
947 // do nothing because layer/edit/timeline bars and viewport cover all of right pane
948 }
949
950 // -----------------------------------------------------------------------------
951
952 static bool ok_to_resize = true;
953
OnSize(wxSizeEvent & event)954 void RightWindow::OnSize(wxSizeEvent& event)
955 {
956 // we need this to update right pane when dragging sash, or when toggling left pane
957 if (mainptr && ok_to_resize) {
958 mainptr->ResizeBigView();
959 }
960 event.Skip();
961 }
962
963 // -----------------------------------------------------------------------------
964
965 RightWindow* rightpane;
966
RightPane()967 wxWindow* MainFrame::RightPane()
968 {
969 return rightpane;
970 }
971
972 // -----------------------------------------------------------------------------
973
ResizeSplitWindow(int wd,int ht)974 void MainFrame::ResizeSplitWindow(int wd, int ht)
975 {
976 int x = showtool ? TOOLBARWD : 0;
977 int y = statusptr->statusht;
978 int w = showtool ? wd - TOOLBARWD : wd;
979 int h = ht > statusptr->statusht ? ht - statusptr->statusht : 0;
980
981 if (w < 0) w = 0;
982 if (h < 0) h = 0;
983
984 // following will call RightWindow::OnSize so avoid ResizeBigView being called twice
985 ok_to_resize = false;
986 splitwin->SetSize(x, y, w, h);
987 ok_to_resize = true;
988
989 ResizeBigView();
990 }
991
992 // -----------------------------------------------------------------------------
993
ResizeBigView()994 void MainFrame::ResizeBigView()
995 {
996 int wd, ht;
997 rightpane->GetClientSize(&wd, &ht);
998
999 if (wd > 0 && ht > 0) {
1000 // resize layer/edit/timeline bars and main viewport window
1001 int y = 0;
1002 if (showlayer) {
1003 ResizeLayerBar(wd);
1004 y += LayerBarHeight();
1005 ht -= LayerBarHeight();
1006 }
1007 if (showedit) {
1008 ResizeEditBar(wd);
1009 y += EditBarHeight();
1010 ht -= EditBarHeight();
1011 }
1012 if (showtimeline) {
1013 ht -= TimelineBarHeight();
1014 // timeline bar goes underneath viewport
1015 ResizeTimelineBar(y + ht, wd);
1016 }
1017
1018 if (!fullscreen && showscrollbars) {
1019 // make room for hbar and vbar
1020 wd -= 15;
1021 ht -= 15;
1022 if (wd < 0) wd = 0;
1023 if (ht < 0) ht = 0;
1024 // resize hbar and vbar
1025 #ifdef __WXMSW__
1026 // extend scroll bar to right edge to avoid seeing junk
1027 // in bottom right corner (need to figure out how to create a gripper!!!)
1028 hbar->SetSize(0, y + ht, wd+15, 15);
1029 #else
1030 hbar->SetSize(0, y + ht, wd, 15);
1031 #endif
1032 vbar->SetSize(wd, y, 15, ht);
1033 }
1034
1035 if (wd < 0) wd = 0;
1036 if (ht < 0) ht = 0;
1037 bigview->SetSize(0, y, wd, ht);
1038 }
1039 }
1040
1041 // -----------------------------------------------------------------------------
1042
ResizeStatusBar(int wd,int ht)1043 void MainFrame::ResizeStatusBar(int wd, int ht)
1044 {
1045 wxUnusedVar(ht);
1046 // assume showstatus is true
1047 statusptr->statusht = showexact ? STATUS_EXHT : STATUS_HT;
1048 if (showtool) wd -= TOOLBARWD;
1049 if (wd < 0) wd = 0;
1050 statusptr->SetSize(showtool ? TOOLBARWD : 0, 0, wd, statusptr->statusht);
1051 }
1052
1053 // -----------------------------------------------------------------------------
1054
ToggleStatusBar()1055 void MainFrame::ToggleStatusBar()
1056 {
1057 showstatus = !showstatus;
1058 int wd, ht;
1059 GetClientSize(&wd, &ht);
1060 if (wd < 0) wd = 0;
1061 if (ht < 0) ht = 0;
1062 if (showstatus) {
1063 ResizeStatusBar(wd, ht);
1064 } else {
1065 statusptr->statusht = 0;
1066 statusptr->SetSize(0, 0, 0, 0);
1067 }
1068 ResizeSplitWindow(wd, ht);
1069 UpdateEverything();
1070 }
1071
1072 // -----------------------------------------------------------------------------
1073
ToggleExactNumbers()1074 void MainFrame::ToggleExactNumbers()
1075 {
1076 showexact = !showexact;
1077 int wd, ht;
1078 GetClientSize(&wd, &ht);
1079 if (wd < 0) wd = 0;
1080 if (ht < 0) ht = 0;
1081 if (showstatus) {
1082 ResizeStatusBar(wd, ht);
1083 ResizeSplitWindow(wd, ht);
1084 UpdateEverything();
1085 } else if (showexact) {
1086 // show the status bar using new size
1087 ToggleStatusBar();
1088 } else {
1089 UpdateMenuItems();
1090 }
1091 }
1092
1093 // -----------------------------------------------------------------------------
1094
ToggleToolBar()1095 void MainFrame::ToggleToolBar()
1096 {
1097 showtool = !showtool;
1098 int wd, ht;
1099 GetClientSize(&wd, &ht);
1100 if (wd < 0) wd = 0;
1101 if (ht < 0) ht = 0;
1102 if (showstatus) {
1103 ResizeStatusBar(wd, ht);
1104 }
1105 if (showtool) {
1106 // resize tool bar in case window was made larger while tool bar hidden
1107 toolbarptr->SetSize(0, 0, TOOLBARWD, ht);
1108 }
1109 ResizeSplitWindow(wd, ht);
1110 toolbarptr->Show(showtool);
1111 }
1112
1113 // -----------------------------------------------------------------------------
1114
ToggleScrollBars()1115 void MainFrame::ToggleScrollBars()
1116 {
1117 showscrollbars = !showscrollbars;
1118 if (showscrollbars) {
1119 hbar->Show(true);
1120 vbar->Show(true);
1121 } else {
1122 // hide scroll bars
1123 hbar->Show(false);
1124 vbar->Show(false);
1125 }
1126 // adjust size of viewport
1127 int wd, ht;
1128 GetClientSize(&wd, &ht);
1129 ResizeSplitWindow(wd, ht);
1130 UpdateEverything();
1131 }
1132
1133 // -----------------------------------------------------------------------------
1134
ToggleFullScreen()1135 void MainFrame::ToggleFullScreen()
1136 {
1137 static bool restorestatusbar; // restore status bar at end of full screen mode?
1138 static bool restorelayerbar; // restore layer bar?
1139 static bool restoreeditbar; // restore edit bar?
1140 static bool restoretimelinebar; // restore timeline bar?
1141 static bool restoretoolbar; // restore tool bar?
1142 static bool restorefiledir; // restore file directory?
1143
1144 if (!fullscreen) {
1145 // save current location and size for use in SavePrefs
1146 wxRect r = GetRect();
1147 mainx = r.x;
1148 mainy = r.y;
1149 mainwd = r.width;
1150 mainht = r.height;
1151 }
1152
1153 fullscreen = !fullscreen;
1154 ShowFullScreen(fullscreen, wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
1155
1156 if (fullscreen) {
1157 if (showscrollbars) {
1158 // hide scroll bars
1159 hbar->Show(false);
1160 vbar->Show(false);
1161 }
1162
1163 // hide status bar if necessary
1164 restorestatusbar = showstatus;
1165 if (restorestatusbar) {
1166 showstatus = false;
1167 statusptr->statusht = 0;
1168 statusptr->SetSize(0, 0, 0, 0);
1169 }
1170
1171 // hide layer bar if necessary
1172 restorelayerbar = showlayer;
1173 if (restorelayerbar) {
1174 ToggleLayerBar();
1175 }
1176
1177 // hide edit bar if necessary
1178 restoreeditbar = showedit;
1179 if (restoreeditbar) {
1180 ToggleEditBar();
1181 }
1182
1183 // hide timeline bar if necessary
1184 restoretimelinebar = showtimeline;
1185 if (restoretimelinebar) {
1186 ToggleTimelineBar();
1187 }
1188
1189 // hide tool bar if necessary
1190 restoretoolbar = showtool;
1191 if (restoretoolbar) {
1192 ToggleToolBar();
1193 }
1194
1195 // hide file directory if necessary
1196 restorefiledir = showfiles;
1197 if (restorefiledir) {
1198 dirwinwd = splitwin->GetSashPosition();
1199 splitwin->Unsplit(filectrl);
1200 showfiles = false;
1201 }
1202
1203 } else {
1204 // first show tool bar if necessary
1205 if (restoretoolbar && !showtool) {
1206 ToggleToolBar();
1207 if (showstatus) {
1208 // reduce width of status bar below
1209 restorestatusbar = true;
1210 }
1211 }
1212
1213 // show status bar if necessary;
1214 // note that even if it's visible we may have to resize width
1215 if (restorestatusbar) {
1216 showstatus = true;
1217 int wd, ht;
1218 GetClientSize(&wd, &ht);
1219 ResizeStatusBar(wd, ht);
1220 }
1221
1222 // show layer bar if necessary
1223 if (restorelayerbar && !showlayer) ToggleLayerBar();
1224
1225 // show edit bar if necessary
1226 if (restoreeditbar && !showedit) ToggleEditBar();
1227
1228 // show timeline bar if necessary
1229 if (restoretimelinebar && !showtimeline) ToggleTimelineBar();
1230
1231 // restore file directory if necessary
1232 if ( restorefiledir && !splitwin->IsSplit() ) {
1233 splitwin->SplitVertically(filectrl, RightPane(), dirwinwd);
1234 showfiles = true;
1235 }
1236
1237 if (showscrollbars) {
1238 // restore scroll bars
1239 hbar->Show(true);
1240 vbar->Show(true);
1241 }
1242 }
1243
1244 // adjust size of viewport (and file directory if visible)
1245 int wd, ht;
1246 GetClientSize(&wd, &ht);
1247 ResizeSplitWindow(wd, ht);
1248 UpdateEverything();
1249 }
1250
1251 // -----------------------------------------------------------------------------
1252
ToggleOverlay()1253 void MainFrame::ToggleOverlay()
1254 {
1255 showoverlay = !showoverlay;
1256 UpdateEverything();
1257 }
1258
1259 // -----------------------------------------------------------------------------
1260
DeleteOverlay()1261 void MainFrame::DeleteOverlay()
1262 {
1263 curroverlay->DeleteOverlay();
1264 UpdateEverything();
1265 }
1266
1267 // -----------------------------------------------------------------------------
1268
ToggleAllowUndo()1269 void MainFrame::ToggleAllowUndo()
1270 {
1271 if (generating) {
1272 command_pending = true;
1273 cmdevent.SetId(ID_NO_UNDO);
1274 Stop();
1275 return;
1276 }
1277
1278 allowundo = !allowundo;
1279 if (allowundo) {
1280 if (currlayer->algo->getGeneration() > currlayer->startgen) {
1281 // undo list is empty but user can Reset, so add a generating change
1282 // to undo list so user can Undo or Reset (and then Redo if they wish)
1283 currlayer->undoredo->AddGenChange();
1284 }
1285 } else {
1286 currlayer->undoredo->ClearUndoRedo();
1287 // don't clear undo/redo history for other layers here; only do it
1288 // if allowundo is false when user switches to another layer
1289 }
1290 }
1291
1292 // -----------------------------------------------------------------------------
1293
ShowPatternInfo()1294 void MainFrame::ShowPatternInfo()
1295 {
1296 if (viewptr->waitingforclick || currlayer->currfile.IsEmpty()) return;
1297 ShowInfo(currlayer->currfile);
1298 }
1299
1300 // -----------------------------------------------------------------------------
1301
1302 // event table and handlers for main window:
1303
BEGIN_EVENT_TABLE(MainFrame,wxFrame)1304 BEGIN_EVENT_TABLE(MainFrame, wxFrame)
1305 EVT_MENU (wxID_ANY, MainFrame::OnMenu)
1306 EVT_SET_FOCUS ( MainFrame::OnSetFocus)
1307 EVT_ACTIVATE ( MainFrame::OnActivate)
1308 EVT_IDLE ( MainFrame::OnIdle)
1309 EVT_SIZE ( MainFrame::OnSize)
1310 EVT_TREE_SEL_CHANGED (wxID_TREECTRL, MainFrame::OnDirTreeSelection)
1311 EVT_SPLITTER_DCLICK (wxID_ANY, MainFrame::OnSashDblClick)
1312 EVT_TIMER (ID_GENTIMER, MainFrame::OnGenTimer)
1313 EVT_TIMER (ID_OPENTIMER, MainFrame::OnOpenTimer)
1314 EVT_CLOSE ( MainFrame::OnClose)
1315 EVT_COMMAND_SCROLL (wxID_ANY, MainFrame::OnScroll)
1316 END_EVENT_TABLE()
1317
1318 // -----------------------------------------------------------------------------
1319
1320 void MainFrame::OnMenu(wxCommandEvent& event)
1321 {
1322 showbanner = false;
1323 if (keepmessage) {
1324 // don't clear message created by script while generating a pattern
1325 keepmessage = false;
1326 } else {
1327 statusptr->ClearMessage();
1328 }
1329
1330 int id = event.GetId();
1331 switch (id) {
1332 // File menu
1333 case wxID_NEW: NewPattern(); break;
1334 case wxID_OPEN: OpenPattern(); break;
1335 case ID_OPEN_CLIP: OpenClipboard(); break;
1336 case wxID_SAVE: SavePattern(); break;
1337 case ID_SAVE_XRLE: savexrle = !savexrle; break;
1338 case ID_RUN_SCRIPT: OpenScript(); break;
1339 case ID_RUN_CLIP: RunClipboard(); break;
1340 case ID_SHOW_FILES: ToggleShowFiles(); break;
1341 case ID_FILE_DIR: ChangeFileDir(); break;
1342 case wxID_PREFERENCES: ShowPrefsDialog(); break;
1343 case wxID_EXIT: QuitApp(); break;
1344
1345 // Edit menu
1346 case ID_UNDO: currlayer->undoredo->UndoChange(); break;
1347 case ID_REDO: currlayer->undoredo->RedoChange(); break;
1348 case ID_NO_UNDO: ToggleAllowUndo(); break;
1349 case ID_CUT: viewptr->CutSelection(); break;
1350 case ID_COPY: viewptr->CopySelection(); break;
1351 case ID_CLEAR: viewptr->ClearSelection(); break;
1352 case ID_OUTSIDE: viewptr->ClearOutsideSelection(); break;
1353 case ID_PASTE: viewptr->PasteClipboard(false); break;
1354 case ID_PASTE_SEL: viewptr->PasteClipboard(true); break;
1355 case ID_PL_TL: SetPasteLocation("TopLeft"); break;
1356 case ID_PL_TR: SetPasteLocation("TopRight"); break;
1357 case ID_PL_BR: SetPasteLocation("BottomRight"); break;
1358 case ID_PL_BL: SetPasteLocation("BottomLeft"); break;
1359 case ID_PL_MID: SetPasteLocation("Middle"); break;
1360 case ID_PM_AND: SetPasteMode("And"); break;
1361 case ID_PM_COPY: SetPasteMode("Copy"); break;
1362 case ID_PM_OR: SetPasteMode("Or"); break;
1363 case ID_PM_XOR: SetPasteMode("Xor"); break;
1364 case ID_SELECTALL: viewptr->SelectAll(); break;
1365 case ID_REMOVE: viewptr->RemoveSelection(); break;
1366 case ID_SHRINK: viewptr->ShrinkSelection(false); break;
1367 case ID_SHRINKFIT: viewptr->ShrinkSelection(true); break;
1368 case ID_RANDOM: viewptr->RandomFill(); break;
1369 case ID_FLIPTB: viewptr->FlipSelection(true); break;
1370 case ID_FLIPLR: viewptr->FlipSelection(false); break;
1371 case ID_ROTATEC: viewptr->RotateSelection(true); break;
1372 case ID_ROTATEA: viewptr->RotateSelection(false); break;
1373 case ID_DRAW: viewptr->SetCursorMode(curs_pencil); break;
1374 case ID_PICK: viewptr->SetCursorMode(curs_pick); break;
1375 case ID_SELECT: viewptr->SetCursorMode(curs_cross); break;
1376 case ID_MOVE: viewptr->SetCursorMode(curs_hand); break;
1377 case ID_ZOOMIN: viewptr->SetCursorMode(curs_zoomin); break;
1378 case ID_ZOOMOUT: viewptr->SetCursorMode(curs_zoomout); break;
1379
1380 // Control menu
1381 case ID_START: StartOrStop(); break;
1382 case ID_NEXT: NextGeneration(false); break;
1383 case ID_STEP: NextGeneration(true); break;
1384 case ID_RESET: ResetPattern(); break;
1385 case ID_SETGEN: SetGeneration(); break;
1386 case ID_FASTER: GoFaster(); break;
1387 case ID_SLOWER: GoSlower(); break;
1388 case ID_SETBASE: SetBaseStep(); break;
1389 case ID_AUTO: ToggleAutoFit(); break;
1390 case ID_HYPER: ToggleHyperspeed(); break;
1391 case ID_HINFO: ToggleHashInfo(); break;
1392 case ID_SHOW_POP: ToggleShowPopulation(); break;
1393 case ID_RECORD: StartStopRecording(); break;
1394 case ID_DELTIME: DeleteTimeline(); break;
1395 case ID_CONVERT: ConvertOldRules(); break;
1396 case ID_SETRULE: ShowRuleDialog(); break;
1397
1398 // View menu
1399 case ID_FULL: ToggleFullScreen(); break;
1400 case ID_FIT: viewptr->FitPattern(); break;
1401 case ID_FIT_SEL: viewptr->FitSelection(); break;
1402 case ID_MIDDLE: viewptr->ViewOrigin(); break;
1403 case ID_RESTORE00: viewptr->RestoreOrigin(); break;
1404 case wxID_ZOOM_IN: viewptr->ZoomIn(); break;
1405 case wxID_ZOOM_OUT: viewptr->ZoomOut(); break;
1406 case ID_SCALE_1: viewptr->SetPixelsPerCell(1); break;
1407 case ID_SCALE_2: viewptr->SetPixelsPerCell(2); break;
1408 case ID_SCALE_4: viewptr->SetPixelsPerCell(4); break;
1409 case ID_SCALE_8: viewptr->SetPixelsPerCell(8); break;
1410 case ID_SCALE_16: viewptr->SetPixelsPerCell(16); break;
1411 case ID_SCALE_32: viewptr->SetPixelsPerCell(32); break;
1412 case ID_TOOL_BAR: ToggleToolBar(); break;
1413 case ID_LAYER_BAR: ToggleLayerBar(); break;
1414 case ID_EDIT_BAR: ToggleEditBar(); break;
1415 case ID_ALL_STATES: ToggleAllStates(); break;
1416 case ID_STATUS_BAR: ToggleStatusBar(); break;
1417 case ID_EXACT: ToggleExactNumbers(); break;
1418 case ID_GRID: viewptr->ToggleGridLines(); break;
1419 case ID_ICONS: viewptr->ToggleCellIcons(); break;
1420 case ID_INVERT: viewptr->ToggleCellColors(); break;
1421 case ID_SMARTSCALE: viewptr->ToggleSmarterScaling(); break;
1422 case ID_TIMELINE: ToggleTimelineBar(); break;
1423 case ID_SCROLL: ToggleScrollBars(); break;
1424 case ID_INFO: ShowPatternInfo(); break;
1425
1426 // Layer menu
1427 case ID_SAVE_OVERLAY: SaveOverlay(); break;
1428 case ID_SHOW_OVERLAY: ToggleOverlay(); break;
1429 case ID_DEL_OVERLAY: DeleteOverlay(); break;
1430 case ID_ADD_LAYER: AddLayer(); break;
1431 case ID_CLONE: CloneLayer(); break;
1432 case ID_DUPLICATE: DuplicateLayer(); break;
1433 case ID_DEL_LAYER: DeleteLayer(); break;
1434 case ID_DEL_OTHERS: DeleteOtherLayers(); break;
1435 case ID_MOVE_LAYER: MoveLayerDialog(); break;
1436 case ID_NAME_LAYER: NameLayerDialog(); break;
1437 case ID_SET_COLORS: SetLayerColors(); break;
1438 case ID_SYNC_VIEW: ToggleSyncViews(); break;
1439 case ID_SYNC_CURS: ToggleSyncCursors(); break;
1440 case ID_STACK: ToggleStackLayers(); break;
1441 case ID_TILE: ToggleTileLayers(); break;
1442
1443 // Help menu
1444 case ID_HELP_INDEX: ShowHelp(_("Help/index.html")); break;
1445 case ID_HELP_INTRO: ShowHelp(_("Help/intro.html")); break;
1446 case ID_HELP_TIPS: ShowHelp(_("Help/tips.html")); break;
1447 case ID_HELP_ALGOS: ShowHelp(_("Help/algos.html")); break;
1448 case ID_HELP_LEXICON: ShowHelp(_("Help/Lexicon/lex.htm")); break;
1449 case ID_HELP_ARCHIVES: ShowHelp(_("Help/archives.html")); break;
1450 case ID_HELP_LUA: ShowHelp(_("Help/lua.html")); break;
1451 case ID_HELP_OVERLAY: ShowHelp(_("Help/overlay.html")); break;
1452 case ID_HELP_PYTHON: ShowHelp(_("Help/python.html")); break;
1453 case ID_HELP_KEYBOARD: ShowHelp(SHOW_KEYBOARD_SHORTCUTS); break;
1454 case ID_HELP_MOUSE: ShowHelp(_("Help/mouse.html")); break;
1455 case ID_HELP_FILE: ShowHelp(_("Help/file.html")); break;
1456 case ID_HELP_EDIT: ShowHelp(_("Help/edit.html")); break;
1457 case ID_HELP_CONTROL: ShowHelp(_("Help/control.html")); break;
1458 case ID_HELP_VIEW: ShowHelp(_("Help/view.html")); break;
1459 case ID_HELP_LAYER: ShowHelp(_("Help/layer.html")); break;
1460 case ID_HELP_HELP: ShowHelp(_("Help/help.html")); break;
1461 case ID_HELP_REFS: ShowHelp(_("Help/refs.html")); break;
1462 case ID_HELP_FORMATS: ShowHelp(_("Help/formats.html")); break;
1463 case ID_HELP_BOUNDED: ShowHelp(_("Help/bounded.html")); break;
1464 case ID_HELP_PROBLEMS: ShowHelp(_("Help/problems.html")); break;
1465 case ID_HELP_CHANGES: ShowHelp(_("Help/changes.html")); break;
1466 case ID_HELP_CREDITS: ShowHelp(_("Help/credits.html")); break;
1467 case ID_HELP_BUTT: ShowHelp(wxEmptyString); break;
1468 case wxID_ABOUT: ShowAboutBox(); break;
1469
1470 // Open/Run Recent submenus
1471 case ID_CLEAR_MISSING_PATTERNS: ClearMissingPatterns(); break;
1472 case ID_CLEAR_ALL_PATTERNS: ClearAllPatterns(); break;
1473 case ID_CLEAR_MISSING_SCRIPTS: ClearMissingScripts(); break;
1474 case ID_CLEAR_ALL_SCRIPTS: ClearAllScripts(); break;
1475
1476 default:
1477 if ( id > ID_OPEN_RECENT && id <= ID_OPEN_RECENT + numpatterns ) {
1478 OpenRecentPattern(id);
1479
1480 } else if ( id > ID_RUN_RECENT && id <= ID_RUN_RECENT + numscripts ) {
1481 OpenRecentScript(id);
1482
1483 } else if ( id >= ID_ALGO0 && id <= ID_ALGOMAX ) {
1484 int newtype = id - ID_ALGO0;
1485 ChangeAlgorithm(newtype);
1486
1487 } else if ( id >= ID_LAYER0 && id <= ID_LAYERMAX ) {
1488 SetLayer(id - ID_LAYER0);
1489
1490 } else {
1491 // wxOSX app needs this to handle app menu items like "Hide Golly"
1492 event.Skip();
1493 }
1494 }
1495
1496 UpdateUserInterface();
1497
1498 if (inscript) {
1499 // update viewport, status bar, scroll bars, window title
1500 inscript = false;
1501 UpdatePatternAndStatus();
1502 bigview->UpdateScrollBars();
1503 SetWindowTitle(wxEmptyString);
1504 inscript = true;
1505 }
1506 }
1507
1508 // -----------------------------------------------------------------------------
1509
OnSetFocus(wxFocusEvent & WXUNUSED (event))1510 void MainFrame::OnSetFocus(wxFocusEvent& WXUNUSED(event))
1511 {
1512 // this is never called in Mac app, presumably because it doesn't
1513 // make any sense for a wxFrame to get the keyboard focus
1514
1515 #ifdef __WXMSW__
1516 // fix wxMSW problem: don't let main window get focus after being minimized
1517 if (viewptr) viewptr->SetFocus();
1518 #endif
1519 }
1520
1521 // -----------------------------------------------------------------------------
1522
OnActivate(wxActivateEvent & event)1523 void MainFrame::OnActivate(wxActivateEvent& event)
1524 {
1525 // IsActive() is not always reliable so we set infront flag
1526 infront = event.GetActive();
1527
1528 if (viewptr->waitingforclick && !infront) {
1529 // cancel paste if main window is no longer in front
1530 viewptr->AbortPaste();
1531 }
1532
1533 if (infront) {
1534 // we must only call UpdateMenuItems when main window is being activated
1535 // (otherwise menu problems will occur on Ubuntu when using Unity)
1536 UpdateUserInterface();
1537 viewptr->SetFocus(); // play safe
1538 }
1539
1540 event.Skip();
1541 }
1542
1543 // -----------------------------------------------------------------------------
1544
OnSize(wxSizeEvent & event)1545 void MainFrame::OnSize(wxSizeEvent& event)
1546 {
1547 #ifdef __WXMSW__
1548 // save current location and size for use in SavePrefs if app
1549 // is closed when window is minimized
1550 wxRect r = GetRect();
1551 mainx = r.x;
1552 mainy = r.y;
1553 mainwd = r.width;
1554 mainht = r.height;
1555 #endif
1556
1557 int wd, ht;
1558 GetClientSize(&wd, &ht);
1559 if (wd > 0 && ht > 0) {
1560 // toolbarptr/statusptr/viewptr might be NULL if OnSize is called from MainFrame ctor
1561 if (toolbarptr && showtool) {
1562 // adjust size of tool bar
1563 toolbarptr->SetSize(0, 0, TOOLBARWD, ht);
1564 }
1565 if (statusptr && showstatus) {
1566 // adjust size of status bar
1567 ResizeStatusBar(wd, ht);
1568 }
1569 if (viewptr && statusptr && ht > statusptr->statusht) {
1570 // adjust size of viewport (and file directory if visible)
1571 ResizeSplitWindow(wd, ht);
1572 }
1573 }
1574
1575 #ifdef __WXGTK__
1576 // need to do default processing for menu bar and tool bar
1577 event.Skip();
1578 #else
1579 wxUnusedVar(event);
1580 #endif
1581 }
1582
1583 // -----------------------------------------------------------------------------
1584
1585 // avoid recursive call of OpenFile
1586 static bool inopen = false;
1587
OnOpenTimer(wxTimerEvent & WXUNUSED (event))1588 void MainFrame::OnOpenTimer(wxTimerEvent& WXUNUSED(event))
1589 {
1590 if (inopen) {
1591 if (inscript && pass_file_events && pendingfiles.GetCount() > 0) {
1592 // OpenFile has called RunScript so pass a pending file
1593 // to the script after updating pendingfiles
1594 wxString filepath = pendingfiles[0];
1595 if (pendingfiles.GetCount() == 1) {
1596 pendingfiles.Clear();
1597 } else {
1598 pendingfiles.RemoveAt(0);
1599 }
1600 PassFileToScript(filepath);
1601 }
1602 return;
1603 }
1604 if (pendingfiles.GetCount() > 0) {
1605 size_t count = pendingfiles.GetCount();
1606 if (count >= 2 && pendingfiles[count-2] == pendingfiles[count-1]) {
1607 // avoid opening same file twice (can happen in wxMSW and wxMac)
1608 pendingfiles.RemoveAt(count-1);
1609 }
1610 wxString filepath = pendingfiles[0];
1611 // update pendingfiles before calling OpenFile
1612 if (pendingfiles.GetCount() == 1) {
1613 pendingfiles.Clear();
1614 } else {
1615 pendingfiles.RemoveAt(0);
1616 }
1617 // note that OnIdle will be called from OpenFile if it calls RunScript
1618 inopen = true;
1619 OpenFile(filepath);
1620 inopen = false;
1621 }
1622 }
1623
1624 // -----------------------------------------------------------------------------
1625
OnIdle(wxIdleEvent & event)1626 void MainFrame::OnIdle(wxIdleEvent& event)
1627 {
1628 #ifdef __WXMSW__
1629 if (set_focus) {
1630 set_focus = false;
1631 // calling SetFocus once doesn't stuff up layer bar buttons
1632 if (infront && viewptr) viewptr->SetFocus();
1633 }
1634
1635 if (!editpath.IsEmpty()) {
1636 EditFile(editpath);
1637 editpath.Clear();
1638 }
1639 #else
1640 // ensure viewport window has keyboard focus if main window is active;
1641 // note that we can't do this on Windows because it stuffs up clicks
1642 // in layer bar buttons
1643 if (infront && viewptr) viewptr->SetFocus();
1644 #endif
1645
1646 if (call_close) {
1647 call_close = false;
1648 Close(false); // false allows OnClose handler to veto close
1649 } else {
1650 // process any pending script/pattern files
1651 if (pendingfiles.GetCount() > 0) {
1652 // there are problems with calling OpenFile in OnIdle, at least on Mac OS
1653 // (if it runs an interactive script then scroll bars don't immediately
1654 // update the viewport, and in some cases modal dialogs can't be closed),
1655 // so we call OpenFile from OnOpenTimer after a short delay
1656 opentimer->Start(10, wxTIMER_ONE_SHOT);
1657 }
1658 }
1659
1660 event.Skip();
1661 }
1662
1663 // -----------------------------------------------------------------------------
1664
EditFile(const wxString & filepath)1665 void MainFrame::EditFile(const wxString& filepath)
1666 {
1667 // prompt user if text editor hasn't been set yet
1668 if (texteditor.IsEmpty()) {
1669 ChooseTextEditor(this, texteditor);
1670 if (texteditor.IsEmpty()) return;
1671 }
1672
1673 // execute a command to open given file in user's preferred text editor
1674 wxString cmd = wxString::Format(wxT("\"%s\" \"%s\""), texteditor.c_str(), filepath.c_str());
1675 long result = wxExecute(cmd, wxEXEC_ASYNC);
1676
1677 #if defined(__WXMSW__)
1678 // on Windows, wxExecute returns 0 if cmd fails
1679 if (result == 0)
1680 #elif defined(__WXMAC__)
1681 // on Mac, wxExecute returns -1 if cmd succeeds (bug, or wx docs are wrong)
1682 if (result != -1)
1683 #elif defined(__WXGTK__)
1684 // on Linux, wxExecute always returns a +ve number (pid?) if cmd fails OR succeeds (sheesh!)
1685 // but if it fails an error message appears in shell window
1686 if (result <= 0)
1687 #endif
1688 {
1689 wxString msg = _("Failed to open file in your preferred text editor.\n");
1690 msg += _("Try choosing a different editor in Preferences > File.");
1691 Warning(msg);
1692 }
1693 }
1694
1695 // -----------------------------------------------------------------------------
1696
1697 #if defined(__WXMAC__) && wxCHECK_VERSION(2,9,0)
1698 // wxMOD_CONTROL has been changed to mean Command key down (sheesh!)
1699 #define wxMOD_CONTROL wxMOD_RAW_CONTROL
1700 #define ControlDown RawControlDown
1701 #endif
1702
OnTreeClick(wxMouseEvent & event)1703 void MainFrame::OnTreeClick(wxMouseEvent& event)
1704 {
1705 // set global flag for testing in OnDirTreeSelection
1706 edit_file = event.ControlDown() || event.RightDown();
1707
1708 wxGenericDirCtrl* dirctrl = NULL;
1709 if (showfiles) dirctrl = mainptr->filectrl;
1710 if (dirctrl) {
1711 wxTreeCtrl* treectrl = dirctrl->GetTreeCtrl();
1712 if (treectrl) {
1713 // determine if an item was clicked
1714 wxPoint pt = event.GetPosition();
1715 int flags;
1716 wxTreeItemId id = treectrl->HitTest(pt, flags);
1717 if (!id.IsOk()) {
1718 // click wasn't in any item
1719 event.Skip();
1720 return;
1721 }
1722
1723 if (treectrl->ItemHasChildren(id)) {
1724 // click was in a folder item
1725 event.Skip();
1726 return;
1727 }
1728
1729 // check for click in an already selected item
1730 if (id == treectrl->GetSelection()) {
1731 // force a selection change so OnDirTreeSelection gets called
1732 treectrl->Unselect();
1733 }
1734
1735 treectrl->SelectItem(id);
1736 // OnDirTreeSelection will be called -- don't call event.Skip()
1737 }
1738 }
1739 }
1740
1741 // -----------------------------------------------------------------------------
1742
OnDirTreeSelection(wxTreeEvent & event)1743 void MainFrame::OnDirTreeSelection(wxTreeEvent& event)
1744 {
1745 if (viewptr == NULL) return; // ignore 1st call from MainFrame::MainFrame
1746
1747 wxTreeItemId id = event.GetItem();
1748 if ( !id.IsOk() ) return;
1749
1750 wxGenericDirCtrl* dirctrl = NULL;
1751 if (showfiles) dirctrl = filectrl;
1752 if (dirctrl == NULL) return;
1753
1754 wxString filepath = dirctrl->GetFilePath();
1755
1756 if ( filepath.IsEmpty() ) {
1757 // user clicked on a folder name
1758
1759 } else if (edit_file) {
1760 // open file in text editor
1761 #ifdef __WXMSW__
1762 // call EditFile in later OnIdle to avoid right-click problem
1763 editpath = filepath;
1764 #else
1765 EditFile(filepath);
1766 #endif
1767
1768 } else {
1769 // user clicked on a file name
1770 #ifdef __WXMAC__
1771 if ( !wxFileName::FileExists(filepath) ) {
1772 // avoid wxMac bug in wxGenericDirCtrl::GetFilePath; ie. file name
1773 // can contain "/" rather than ":" (but directory path is okay)
1774 wxFileName fullpath(filepath);
1775 wxString dir = fullpath.GetPath();
1776 wxString name = fullpath.GetFullName();
1777 wxString newpath = dir + wxT(":") + name;
1778 if ( wxFileName::FileExists(newpath) ) filepath = newpath;
1779 }
1780 #endif
1781 if ( inscript ) {
1782 if (pass_file_events) {
1783 PassFileToScript(filepath);
1784 }
1785 } else {
1786 if (generating) {
1787 command_pending = true;
1788 if ( IsScriptFile(filepath) ) {
1789 AddRecentScript(filepath);
1790 cmdevent.SetId(ID_RUN_RECENT + 1);
1791 } else {
1792 AddRecentPattern(filepath);
1793 cmdevent.SetId(ID_OPEN_RECENT + 1);
1794 }
1795 Stop();
1796 } else {
1797 // load pattern or run script;
1798 // call OpenFile in later OnIdle -- this prevents the main window
1799 // moving in front of the help window if a script calls help(...)
1800 pendingfiles.Add(filepath);
1801 }
1802 }
1803 }
1804
1805 #ifdef __WXMSW__
1806 // call SetFocus in next OnIdle
1807 set_focus = true;
1808 #else
1809 viewptr->SetFocus();
1810 #endif
1811 }
1812
1813 // -----------------------------------------------------------------------------
1814
OnSashDblClick(wxSplitterEvent & WXUNUSED (event))1815 void MainFrame::OnSashDblClick(wxSplitterEvent& WXUNUSED(event))
1816 {
1817 // splitwin's sash was double-clicked
1818 ToggleShowFiles();
1819 UpdateMenuItems();
1820 UpdateToolBar();
1821 }
1822
1823 // -----------------------------------------------------------------------------
1824
OnScroll(wxScrollEvent & event)1825 void MainFrame::OnScroll(wxScrollEvent& event)
1826 {
1827 WXTYPE type = event.GetEventType();
1828 WXTYPE newtype = type;
1829
1830 // build equivalent wxScrollWinEvent and post it to bigview so that
1831 // PatternView::OnScroll gets called and hbar/vbar are updated
1832
1833 if (type == wxEVT_SCROLL_LINEUP) newtype = wxEVT_SCROLLWIN_LINEUP;
1834 if (type == wxEVT_SCROLL_LINEDOWN) newtype = wxEVT_SCROLLWIN_LINEDOWN;
1835 if (type == wxEVT_SCROLL_PAGEUP) newtype = wxEVT_SCROLLWIN_PAGEUP;
1836 if (type == wxEVT_SCROLL_PAGEDOWN) newtype = wxEVT_SCROLLWIN_PAGEDOWN;
1837 if (type == wxEVT_SCROLL_THUMBTRACK) newtype = wxEVT_SCROLLWIN_THUMBTRACK;
1838 if (type == wxEVT_SCROLL_THUMBRELEASE) newtype = wxEVT_SCROLLWIN_THUMBRELEASE;
1839
1840 wxScrollWinEvent newevt(newtype, event.GetPosition(), event.GetOrientation());
1841 wxPostEvent(bigview->GetEventHandler(), newevt);
1842 }
1843
1844 // -----------------------------------------------------------------------------
1845
SaveCurrentLayer()1846 bool MainFrame::SaveCurrentLayer()
1847 {
1848 if (currlayer->algo->isEmpty()) return true; // no need to save empty universe
1849 wxString query;
1850 if (numlayers > 1) {
1851 // make it clear which layer we're asking about
1852 query.Printf(_("Save the changes to layer %d: \"%s\"?"),
1853 currindex, currlayer->currname.c_str());
1854 } else {
1855 query.Printf(_("Save the changes to \"%s\"?"), currlayer->currname.c_str());
1856 }
1857 int answer = SaveChanges(query, _("If you don't save, your changes will be lost."));
1858 switch (answer) {
1859 case 2: {
1860 bool result = SavePattern(); // true only if pattern was saved
1861 if (inscript && !result) {
1862 PassKeyToScript(WXK_ESCAPE); // abort script
1863 }
1864 return result;
1865 }
1866 case 1: {
1867 // don't save changes (but continue)
1868 return true;
1869 }
1870 default: {
1871 // answer == 0 (ie. user selected Cancel)
1872 if (inscript) {
1873 PassKeyToScript(WXK_ESCAPE); // abort script
1874 }
1875 return false;
1876 }
1877 }
1878 }
1879
1880 // -----------------------------------------------------------------------------
1881
OnClose(wxCloseEvent & event)1882 void MainFrame::OnClose(wxCloseEvent& event)
1883 {
1884 if (event.CanVeto()) {
1885 if (inscript || generating) Stop();
1886
1887 // if insideYield is true then we might have been called from
1888 // StepPattern in OnGenTimer, so we need to call OnClose again via
1889 // OnIdle until insideYield is false and OnGenTimer has finished
1890 if (insideYield) {
1891 call_close = true;
1892 event.Veto();
1893 return;
1894 }
1895
1896 // we can cancel the close event if necessary
1897 if (viewptr->waitingforclick) {
1898 event.Veto();
1899 return;
1900 }
1901
1902 if (askonquit) {
1903 // keep track of which unique clones have been seen;
1904 // we add 1 below to allow for cloneseen[0] (always false)
1905 const int maxseen = MAX_LAYERS/2 + 1;
1906 bool cloneseen[maxseen];
1907 for (int i = 0; i < maxseen; i++) cloneseen[i] = false;
1908
1909 // for each dirty layer, ask user if they want to save changes
1910 int oldindex = currindex;
1911 for (int i = 0; i < numlayers; i++) {
1912 // only ask once for each unique clone (cloneid == 0 for non-clone)
1913 int cid = GetLayer(i)->cloneid;
1914 if (!cloneseen[cid]) {
1915 if (cid > 0) cloneseen[cid] = true;
1916 if (GetLayer(i)->dirty) {
1917 if (i != currindex) SetLayer(i);
1918 if (!SaveCurrentLayer()) {
1919 // user cancelled "save changes" dialog so restore layer
1920 SetLayer(oldindex);
1921 UpdateUserInterface();
1922 event.Veto();
1923 return;
1924 }
1925 }
1926 }
1927 }
1928 }
1929 }
1930
1931 if (GetHelpFrame()) GetHelpFrame()->Close(true);
1932 if (GetInfoFrame()) GetInfoFrame()->Close(true);
1933
1934 if (splitwin->IsSplit()) dirwinwd = splitwin->GetSashPosition();
1935
1936 // if script is running or pattern is generating then CanVeto was false
1937 // (probably due to user logging out or shutting down system)
1938 // and we need to call exit below
1939 bool callexit = inscript || generating;
1940
1941 // abort any running script and tidy up; also restores current directory
1942 // to location of Golly app so prefs file will be saved in correct place
1943 FinishScripting();
1944
1945 // save main window location and other user preferences
1946 SavePrefs();
1947
1948 // delete any temporary files
1949 if (wxFileExists(luafile)) wxRemoveFile(luafile);
1950 if (wxFileExists(perlfile)) wxRemoveFile(perlfile);
1951 if (wxFileExists(pythonfile)) wxRemoveFile(pythonfile);
1952 for (int i = 0; i < numlayers; i++) {
1953 Layer* layer = GetLayer(i);
1954 if (wxFileExists(layer->tempstart)) wxRemoveFile(layer->tempstart);
1955 // clear all undo/redo history for this layer
1956 layer->undoredo->ClearUndoRedo();
1957 }
1958
1959 if (wxFileName::DirExists(tempdir)) {
1960 // delete all files in tempdir (we assume it has no subdirs)
1961 wxDir* dir = new wxDir(tempdir);
1962 wxArrayString files;
1963 wxString filename;
1964 bool more = dir->GetFirst(&filename);
1965 while (more) {
1966 files.Add(tempdir + filename);
1967 more = dir->GetNext(&filename);
1968 }
1969 // delete wxDir object now otherwise Rmdir below will fail on Windows
1970 delete dir;
1971 for (size_t n = 0; n < files.GetCount(); n++) {
1972 wxRemoveFile(files[n]);
1973 }
1974 // delete the (hopefully) empty tempdir
1975 if (!wxFileName::Rmdir(tempdir)) {
1976 Warning(_("Could not delete temporary directory:\n") + tempdir);
1977 }
1978 }
1979
1980 // allow clipboard data to persist after app exits
1981 // (needed on Windows, not needed on Mac, doesn't work on Linux -- sheesh!)
1982 if (wxTheClipboard->Open()) {
1983 wxTheClipboard->Flush();
1984 wxTheClipboard->Close();
1985 }
1986
1987 // avoid possible error message or seg fault
1988 if (callexit) exit(0);
1989
1990 Destroy();
1991
1992 #ifdef __WXGTK__
1993 // avoid seg fault on Linux (only happens if ctrl-Q is used to quit)
1994 exit(0);
1995 #endif
1996
1997 // deallocate things (usually no need) to help find any real memory leaks
1998 if (debuglevel == 666) {
1999 wxGetApp().Yield(); // (because Destroy() doesn't act immediately)
2000 if (numlayers > 1) DeleteOtherLayers();
2001 delete currlayer;
2002 delete stopwatch;
2003 DeleteAlgorithms();
2004 FreeCursors();
2005 FreeDefaultColors();
2006 }
2007 }
2008
2009 // -----------------------------------------------------------------------------
2010
QuitApp()2011 void MainFrame::QuitApp()
2012 {
2013 Close(false); // false allows OnClose handler to veto close
2014 }
2015
2016 // -----------------------------------------------------------------------------
2017
2018 #if wxUSE_DRAG_AND_DROP
2019
2020 // derive a simple class for handling dropped files
2021 class DnDFile : public wxFileDropTarget
2022 {
2023 public:
DnDFile()2024 DnDFile() {}
2025 virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames);
2026 };
2027
OnDropFiles(wxCoord,wxCoord,const wxArrayString & filenames)2028 bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
2029 {
2030 // bring app to front
2031 #ifdef __WXMAC__
2032 ProcessSerialNumber process;
2033 if ( GetCurrentProcess(&process) == noErr )
2034 SetFrontProcess(&process);
2035 #endif
2036 #ifdef __WXMSW__
2037 SetForegroundWindow( (HWND)mainptr->GetHandle() );
2038 #endif
2039 mainptr->Raise();
2040
2041 size_t numfiles = filenames.GetCount();
2042 for ( size_t n = 0; n < numfiles; n++ ) {
2043 // safer to call OpenFile via OnIdle
2044 mainptr->pendingfiles.Add(filenames[n]);
2045 }
2046
2047 return true;
2048 }
2049
NewDropTarget()2050 wxDropTarget* MainFrame::NewDropTarget()
2051 {
2052 return new DnDFile();
2053 }
2054
2055 #endif // wxUSE_DRAG_AND_DROP
2056
2057 // -----------------------------------------------------------------------------
2058
SetRandomFillPercentage()2059 void MainFrame::SetRandomFillPercentage()
2060 {
2061 // update Random Fill menu item to show randomfill value
2062 wxMenuBar* mbar = GetMenuBar();
2063 if (mbar) {
2064 wxString randlabel;
2065 randlabel.Printf(_("Random Fill (%d%c)"), randomfill, '%');
2066 randlabel += GetAccelerator(DO_RANDFILL);
2067 mbar->SetLabel(ID_RANDOM, randlabel);
2068 }
2069 }
2070
2071 // -----------------------------------------------------------------------------
2072
UpdateLayerItem(int index)2073 void MainFrame::UpdateLayerItem(int index)
2074 {
2075 // update name in given layer's menu item
2076 Layer* layer = GetLayer(index);
2077 wxMenuBar* mbar = GetMenuBar();
2078 if (mbar) {
2079 wxString label = wxEmptyString;
2080
2081 // we no longer show index in front of name
2082 // label.Printf(_("%d: "), index);
2083
2084 // display asterisk if pattern has been modified
2085 if (layer->dirty) label += wxT("*");
2086
2087 int cid = layer->cloneid;
2088 while (cid > 0) {
2089 // display one or more "=" chars to indicate this is a cloned layer
2090 label += wxT("=");
2091 cid--;
2092 }
2093
2094 if (layer->currname.IsEmpty()) {
2095 // this should never happen, but play safe
2096 label += wxT("UNKNOWN");
2097 } else {
2098 label += layer->currname;
2099 }
2100
2101 // duplicate any ampersands so they appear
2102 label.Replace(wxT("&"), wxT("&&"));
2103
2104 mbar->SetLabel(ID_LAYER0 + index, label);
2105
2106 // also update name in corresponding layer button
2107 UpdateLayerButton(index, label);
2108 }
2109 }
2110
2111 // -----------------------------------------------------------------------------
2112
AppendLayerItem()2113 void MainFrame::AppendLayerItem()
2114 {
2115 wxMenuBar* mbar = GetMenuBar();
2116 if (mbar) {
2117 wxMenu* layermenu = mbar->GetMenu( mbar->FindMenu(_("Layer")) );
2118 if (layermenu) {
2119 // no point setting the item name here because UpdateLayerItem
2120 // will be called very soon
2121 layermenu->AppendCheckItem(ID_LAYER0 + numlayers - 1, _("foo"));
2122 } else {
2123 Warning(_("Could not find Layer menu!"));
2124 }
2125 }
2126 }
2127
2128 // -----------------------------------------------------------------------------
2129
RemoveLayerItem()2130 void MainFrame::RemoveLayerItem()
2131 {
2132 wxMenuBar* mbar = GetMenuBar();
2133 if (mbar) {
2134 wxMenu* layermenu = mbar->GetMenu( mbar->FindMenu(_("Layer")) );
2135 if (layermenu) {
2136 layermenu->Delete(ID_LAYER0 + numlayers);
2137 } else {
2138 Warning(_("Could not find Layer menu!"));
2139 }
2140 }
2141 }
2142
2143 // -----------------------------------------------------------------------------
2144
CreateMenus()2145 void MainFrame::CreateMenus()
2146 {
2147 wxMenu* fileMenu = new wxMenu();
2148 wxMenu* editMenu = new wxMenu();
2149 wxMenu* controlMenu = new wxMenu();
2150 wxMenu* viewMenu = new wxMenu();
2151 wxMenu* layerMenu = new wxMenu();
2152 wxMenu* helpMenu = new wxMenu();
2153
2154 // create submenus
2155 wxMenu* plocSubMenu = new wxMenu();
2156 wxMenu* pmodeSubMenu = new wxMenu();
2157 wxMenu* cmodeSubMenu = new wxMenu();
2158 wxMenu* scaleSubMenu = new wxMenu();
2159
2160 plocSubMenu->AppendCheckItem(ID_PL_TL, _("Top Left"));
2161 plocSubMenu->AppendCheckItem(ID_PL_TR, _("Top Right"));
2162 plocSubMenu->AppendCheckItem(ID_PL_BR, _("Bottom Right"));
2163 plocSubMenu->AppendCheckItem(ID_PL_BL, _("Bottom Left"));
2164 plocSubMenu->AppendCheckItem(ID_PL_MID, _("Middle"));
2165
2166 pmodeSubMenu->AppendCheckItem(ID_PM_AND, _("And"));
2167 pmodeSubMenu->AppendCheckItem(ID_PM_COPY, _("Copy"));
2168 pmodeSubMenu->AppendCheckItem(ID_PM_OR, _("Or"));
2169 pmodeSubMenu->AppendCheckItem(ID_PM_XOR, _("Xor"));
2170
2171 cmodeSubMenu->AppendCheckItem(ID_DRAW, _("Draw") + GetAccelerator(DO_CURSDRAW));
2172 cmodeSubMenu->AppendCheckItem(ID_PICK, _("Pick") + GetAccelerator(DO_CURSPICK));
2173 cmodeSubMenu->AppendCheckItem(ID_SELECT, _("Select") + GetAccelerator(DO_CURSSEL));
2174 cmodeSubMenu->AppendCheckItem(ID_MOVE, _("Move") + GetAccelerator(DO_CURSMOVE));
2175 cmodeSubMenu->AppendCheckItem(ID_ZOOMIN, _("Zoom In") + GetAccelerator(DO_CURSIN));
2176 cmodeSubMenu->AppendCheckItem(ID_ZOOMOUT, _("Zoom Out") + GetAccelerator(DO_CURSOUT));
2177
2178 scaleSubMenu->AppendCheckItem(ID_SCALE_1, _("1:1") + GetAccelerator(DO_SCALE1));
2179 scaleSubMenu->AppendCheckItem(ID_SCALE_2, _("1:2") + GetAccelerator(DO_SCALE2));
2180 scaleSubMenu->AppendCheckItem(ID_SCALE_4, _("1:4") + GetAccelerator(DO_SCALE4));
2181 scaleSubMenu->AppendCheckItem(ID_SCALE_8, _("1:8") + GetAccelerator(DO_SCALE8));
2182 scaleSubMenu->AppendCheckItem(ID_SCALE_16, _("1:16") + GetAccelerator(DO_SCALE16));
2183 scaleSubMenu->AppendCheckItem(ID_SCALE_32, _("1:32") + GetAccelerator(DO_SCALE32));
2184
2185 fileMenu->Append(wxID_NEW, _("New Pattern") + GetAccelerator(DO_NEWPATT));
2186 fileMenu->AppendSeparator();
2187 fileMenu->Append(wxID_OPEN, _("Open Pattern...") + GetAccelerator(DO_OPENPATT));
2188 fileMenu->Append(ID_OPEN_CLIP, _("Open Clipboard") + GetAccelerator(DO_OPENCLIP));
2189 fileMenu->Append(ID_OPEN_RECENT, _("Open Recent"), patternSubMenu);
2190 fileMenu->AppendSeparator();
2191 fileMenu->Append(wxID_SAVE, _("Save Pattern...") + GetAccelerator(DO_SAVE));
2192 fileMenu->AppendCheckItem(ID_SAVE_XRLE, _("Save Extended RLE") + GetAccelerator(DO_SAVEXRLE));
2193 fileMenu->AppendSeparator();
2194 fileMenu->Append(ID_RUN_SCRIPT, _("Run Script...") + GetAccelerator(DO_RUNSCRIPT));
2195 fileMenu->Append(ID_RUN_CLIP, _("Run Clipboard") + GetAccelerator(DO_RUNCLIP));
2196 fileMenu->Append(ID_RUN_RECENT, _("Run Recent"), scriptSubMenu);
2197 fileMenu->AppendSeparator();
2198 fileMenu->AppendCheckItem(ID_SHOW_FILES, _("Show Files") + GetAccelerator(DO_SHOWFILES));
2199 fileMenu->Append(ID_FILE_DIR, _("Set File Folder...") + GetAccelerator(DO_FILEDIR));
2200 #if !defined(__WXOSX_COCOA__)
2201 fileMenu->AppendSeparator();
2202 #endif
2203 // on the Mac the wxID_PREFERENCES item is moved to the app menu
2204 fileMenu->Append(wxID_PREFERENCES, _("Preferences...") + GetAccelerator(DO_PREFS));
2205 #if !defined(__WXOSX_COCOA__)
2206 fileMenu->AppendSeparator();
2207 #endif
2208 // on the Mac the wxID_EXIT item is moved to the app menu and the app name is appended to "Quit "
2209 fileMenu->Append(wxID_EXIT, _("Quit") + GetAccelerator(DO_QUIT));
2210
2211 editMenu->Append(ID_UNDO, _("Undo") + GetAccelerator(DO_UNDO));
2212 editMenu->Append(ID_REDO, _("Redo") + GetAccelerator(DO_REDO));
2213 editMenu->AppendCheckItem(ID_NO_UNDO, _("Disable Undo/Redo") + GetAccelerator(DO_DISABLE));
2214 editMenu->AppendSeparator();
2215 editMenu->Append(ID_CUT, _("Cut") + GetAccelerator(DO_CUT));
2216 editMenu->Append(ID_COPY, _("Copy") + GetAccelerator(DO_COPY));
2217 editMenu->Append(ID_CLEAR, _("Clear") + GetAccelerator(DO_CLEAR));
2218 editMenu->Append(ID_OUTSIDE, _("Clear Outside") + GetAccelerator(DO_CLEAROUT));
2219 editMenu->AppendSeparator();
2220 editMenu->Append(ID_PASTE, _("Paste") + GetAccelerator(DO_PASTE));
2221 editMenu->Append(ID_PMODE, _("Paste Mode"), pmodeSubMenu);
2222 editMenu->Append(ID_PLOCATION, _("Paste Location"), plocSubMenu);
2223 editMenu->Append(ID_PASTE_SEL, _("Paste to Selection") + GetAccelerator(DO_PASTESEL));
2224 editMenu->AppendSeparator();
2225 editMenu->Append(ID_SELECTALL, _("Select All") + GetAccelerator(DO_SELALL));
2226 editMenu->Append(ID_REMOVE, _("Remove Selection") + GetAccelerator(DO_REMOVESEL));
2227 editMenu->Append(ID_SHRINK, _("Shrink Selection") + GetAccelerator(DO_SHRINK));
2228 // full label will be set later by SetRandomFillPercentage
2229 editMenu->Append(ID_RANDOM, _("Random Fill") + GetAccelerator(DO_RANDFILL));
2230 editMenu->Append(ID_FLIPTB, _("Flip Top-Bottom") + GetAccelerator(DO_FLIPTB));
2231 editMenu->Append(ID_FLIPLR, _("Flip Left-Right") + GetAccelerator(DO_FLIPLR));
2232 editMenu->Append(ID_ROTATEC, _("Rotate Clockwise") + GetAccelerator(DO_ROTATECW));
2233 editMenu->Append(ID_ROTATEA, _("Rotate Anticlockwise") + GetAccelerator(DO_ROTATEACW));
2234 editMenu->AppendSeparator();
2235 editMenu->Append(ID_CMODE, _("Cursor Mode"), cmodeSubMenu);
2236
2237 controlMenu->Append(ID_START, _("Start Generating") + GetAccelerator(DO_STARTSTOP));
2238 controlMenu->Append(ID_NEXT, _("Next Generation") + GetAccelerator(DO_NEXTGEN));
2239 controlMenu->Append(ID_STEP, _("Next Step") + GetAccelerator(DO_NEXTSTEP));
2240 controlMenu->AppendSeparator();
2241 controlMenu->Append(ID_RESET, _("Reset") + GetAccelerator(DO_RESET));
2242 controlMenu->Append(ID_SETGEN, _("Set Generation...") + GetAccelerator(DO_SETGEN));
2243 controlMenu->AppendSeparator();
2244 controlMenu->Append(ID_FASTER, _("Faster") + GetAccelerator(DO_FASTER));
2245 controlMenu->Append(ID_SLOWER, _("Slower") + GetAccelerator(DO_SLOWER));
2246 controlMenu->Append(ID_SETBASE, _("Set Base Step...") + GetAccelerator(DO_SETBASE));
2247 controlMenu->AppendSeparator();
2248 controlMenu->AppendCheckItem(ID_AUTO, _("Auto Fit") + GetAccelerator(DO_AUTOFIT));
2249 controlMenu->AppendCheckItem(ID_HYPER, _("Hyperspeed") + GetAccelerator(DO_HYPER));
2250 controlMenu->AppendCheckItem(ID_HINFO, _("Show Hash Info") + GetAccelerator(DO_HASHINFO));
2251 controlMenu->AppendCheckItem(ID_SHOW_POP, _("Show Population") + GetAccelerator(DO_SHOWPOP));
2252 controlMenu->AppendSeparator();
2253 controlMenu->Append(ID_RECORD, _("Start Recording") + GetAccelerator(DO_RECORD));
2254 controlMenu->Append(ID_DELTIME, _("Delete Timeline") + GetAccelerator(DO_DELTIME));
2255 controlMenu->AppendSeparator();
2256 controlMenu->Append(ID_CONVERT, _("Convert Old Rules")); // rarely used, so no accelerator
2257 controlMenu->AppendSeparator();
2258 controlMenu->Append(ID_SETALGO, _("Set Algorithm"), algomenu);
2259 controlMenu->Append(ID_SETRULE, _("Set Rule...") + GetAccelerator(DO_SETRULE));
2260
2261 viewMenu->Append(ID_FULL, _("Full Screen") + GetAccelerator(DO_FULLSCREEN));
2262 viewMenu->AppendSeparator();
2263 viewMenu->Append(ID_FIT, _("Fit Pattern") + GetAccelerator(DO_FIT));
2264 viewMenu->Append(ID_FIT_SEL, _("Fit Selection") + GetAccelerator(DO_FITSEL));
2265 viewMenu->Append(ID_MIDDLE, _("Middle") + GetAccelerator(DO_MIDDLE));
2266 viewMenu->Append(ID_RESTORE00, _("Restore Origin") + GetAccelerator(DO_RESTORE00));
2267 viewMenu->AppendSeparator();
2268 viewMenu->Append(wxID_ZOOM_IN, _("Zoom In") + GetAccelerator(DO_ZOOMIN));
2269 viewMenu->Append(wxID_ZOOM_OUT, _("Zoom Out") + GetAccelerator(DO_ZOOMOUT));
2270 viewMenu->Append(ID_SET_SCALE, _("Set Scale"), scaleSubMenu);
2271 viewMenu->AppendSeparator();
2272 viewMenu->AppendCheckItem(ID_TOOL_BAR, _("Show Tool Bar") + GetAccelerator(DO_SHOWTOOL));
2273 viewMenu->AppendCheckItem(ID_LAYER_BAR, _("Show Layer Bar") + GetAccelerator(DO_SHOWLAYER));
2274 viewMenu->AppendCheckItem(ID_EDIT_BAR, _("Show Edit Bar") + GetAccelerator(DO_SHOWEDIT));
2275 viewMenu->AppendCheckItem(ID_ALL_STATES, _("Show All States") + GetAccelerator(DO_SHOWSTATES));
2276 viewMenu->AppendCheckItem(ID_STATUS_BAR, _("Show Status Bar") + GetAccelerator(DO_SHOWSTATUS));
2277 viewMenu->AppendCheckItem(ID_EXACT, _("Show Exact Numbers") + GetAccelerator(DO_SHOWEXACT));
2278 viewMenu->AppendCheckItem(ID_GRID, _("Show Grid Lines") + GetAccelerator(DO_SHOWGRID));
2279 viewMenu->AppendCheckItem(ID_ICONS, _("Show Cell Icons") + GetAccelerator(DO_SHOWICONS));
2280 viewMenu->AppendCheckItem(ID_INVERT, _("Invert Colors") + GetAccelerator(DO_INVERT));
2281 viewMenu->AppendCheckItem(ID_SMARTSCALE, _("Smarter Scaling") + GetAccelerator(DO_SMARTSCALE));
2282 viewMenu->AppendCheckItem(ID_TIMELINE, _("Show Timeline") + GetAccelerator(DO_SHOWTIME));
2283 viewMenu->AppendCheckItem(ID_SCROLL, _("Show Scroll Bars") + GetAccelerator(DO_SHOWSCROLL));
2284 viewMenu->AppendSeparator();
2285 viewMenu->Append(ID_INFO, _("Pattern Info") + GetAccelerator(DO_INFO));
2286
2287 layerMenu->Append(ID_SAVE_OVERLAY, _("Save Overlay...") + GetAccelerator(DO_SAVEOVERLAY));
2288 layerMenu->AppendCheckItem(ID_SHOW_OVERLAY, _("Show Overlay") + GetAccelerator(DO_SHOWOVERLAY));
2289 layerMenu->Append(ID_DEL_OVERLAY, _("Delete Overlay") + GetAccelerator(DO_DELOVERLAY));
2290 layerMenu->AppendSeparator();
2291 layerMenu->Append(ID_ADD_LAYER, _("Add Layer") + GetAccelerator(DO_ADD));
2292 layerMenu->Append(ID_CLONE, _("Clone Layer") + GetAccelerator(DO_CLONE));
2293 layerMenu->Append(ID_DUPLICATE, _("Duplicate Layer") + GetAccelerator(DO_DUPLICATE));
2294 layerMenu->AppendSeparator();
2295 layerMenu->Append(ID_DEL_LAYER, _("Delete Layer") + GetAccelerator(DO_DELETE));
2296 layerMenu->Append(ID_DEL_OTHERS, _("Delete Other Layers") + GetAccelerator(DO_DELOTHERS));
2297 layerMenu->AppendSeparator();
2298 layerMenu->Append(ID_MOVE_LAYER, _("Move Layer...") + GetAccelerator(DO_MOVELAYER));
2299 layerMenu->Append(ID_NAME_LAYER, _("Name Layer...") + GetAccelerator(DO_NAMELAYER));
2300 layerMenu->Append(ID_SET_COLORS, _("Set Layer Colors...") + GetAccelerator(DO_SETCOLORS));
2301 layerMenu->AppendSeparator();
2302 layerMenu->AppendCheckItem(ID_SYNC_VIEW, _("Synchronize Views") + GetAccelerator(DO_SYNCVIEWS));
2303 layerMenu->AppendCheckItem(ID_SYNC_CURS, _("Synchronize Cursors") + GetAccelerator(DO_SYNCCURS));
2304 layerMenu->AppendSeparator();
2305 layerMenu->AppendCheckItem(ID_STACK, _("Stack Layers") + GetAccelerator(DO_STACK));
2306 layerMenu->AppendCheckItem(ID_TILE, _("Tile Layers") + GetAccelerator(DO_TILE));
2307 layerMenu->AppendSeparator();
2308 layerMenu->AppendCheckItem(ID_LAYER0, _("0"));
2309 // UpdateLayerItem will soon change the above item name
2310
2311 helpMenu->Append(ID_HELP_INDEX, _("Contents"));
2312 helpMenu->Append(ID_HELP_INTRO, _("Introduction"));
2313 helpMenu->Append(ID_HELP_TIPS, _("Hints and Tips"));
2314 helpMenu->Append(ID_HELP_ALGOS, _("Algorithms"));
2315 helpMenu->Append(ID_HELP_LEXICON, _("Life Lexicon"));
2316 helpMenu->Append(ID_HELP_ARCHIVES, _("Online Archives"));
2317 helpMenu->AppendSeparator();
2318 helpMenu->Append(ID_HELP_LUA, _("Lua Scripting"));
2319 helpMenu->Append(ID_HELP_OVERLAY, _("Overlay"));
2320 helpMenu->Append(ID_HELP_PYTHON, _("Python Scripting"));
2321 helpMenu->AppendSeparator();
2322 helpMenu->Append(ID_HELP_KEYBOARD, _("Keyboard Shortcuts"));
2323 helpMenu->Append(ID_HELP_MOUSE, _("Mouse Shortcuts"));
2324 helpMenu->AppendSeparator();
2325 helpMenu->Append(ID_HELP_FILE, _("File Menu"));
2326 helpMenu->Append(ID_HELP_EDIT, _("Edit Menu"));
2327 helpMenu->Append(ID_HELP_CONTROL, _("Control Menu"));
2328 helpMenu->Append(ID_HELP_VIEW, _("View Menu"));
2329 helpMenu->Append(ID_HELP_LAYER, _("Layer Menu"));
2330 helpMenu->Append(ID_HELP_HELP, _("Help Menu"));
2331 helpMenu->AppendSeparator();
2332 helpMenu->Append(ID_HELP_REFS, _("References"));
2333 helpMenu->Append(ID_HELP_FORMATS, _("File Formats"));
2334 helpMenu->Append(ID_HELP_BOUNDED, _("Bounded Grids"));
2335 helpMenu->Append(ID_HELP_PROBLEMS, _("Known Problems"));
2336 helpMenu->Append(ID_HELP_CHANGES, _("Changes"));
2337 helpMenu->Append(ID_HELP_CREDITS, _("Credits"));
2338 #ifndef __WXMAC__
2339 helpMenu->AppendSeparator();
2340 #endif
2341 // on the Mac the wxID_ABOUT item gets moved to the app menu
2342 helpMenu->Append(wxID_ABOUT, _("About Golly") + GetAccelerator(DO_ABOUT));
2343
2344 // create the menu bar and append menus;
2345 // avoid using "&" in menu names because it prevents using keyboard shortcuts
2346 // like Alt+L on Linux
2347 wxMenuBar* menuBar = new wxMenuBar();
2348 menuBar->Append(fileMenu, _("File"));
2349 menuBar->Append(editMenu, _("Edit"));
2350 menuBar->Append(controlMenu, _("Control"));
2351 menuBar->Append(viewMenu, _("View"));
2352 menuBar->Append(layerMenu, _("Layer"));
2353 #ifdef __WXMAC__
2354 // wxMac bug: need the "&" otherwise we get an extra Help menu
2355 menuBar->Append(helpMenu, _("&Help"));
2356 #else
2357 menuBar->Append(helpMenu, _("Help"));
2358 #endif
2359
2360 #ifdef __WXMAC__
2361 // prevent Window menu being added automatically by wxMac 2.6.1+
2362 menuBar->SetAutoWindowMenu(false);
2363 #endif
2364
2365 // attach menu bar to the frame
2366 SetMenuBar(menuBar);
2367 }
2368
2369 // -----------------------------------------------------------------------------
2370
UpdateMenuAccelerators()2371 void MainFrame::UpdateMenuAccelerators()
2372 {
2373 // keyboard shortcuts have changed, so update all menu item accelerators
2374 wxMenuBar* mbar = GetMenuBar();
2375 if (mbar) {
2376 // wxMac bug: these app menu items aren't updated (but user isn't likely
2377 // to change them so don't bother trying to fix the bug)
2378 SetAccelerator(mbar, wxID_ABOUT, DO_ABOUT);
2379 SetAccelerator(mbar, wxID_PREFERENCES, DO_PREFS);
2380 SetAccelerator(mbar, wxID_EXIT, DO_QUIT);
2381
2382 SetAccelerator(mbar, ID_DRAW, DO_CURSDRAW);
2383 SetAccelerator(mbar, ID_PICK, DO_CURSPICK);
2384 SetAccelerator(mbar, ID_SELECT, DO_CURSSEL);
2385 SetAccelerator(mbar, ID_MOVE, DO_CURSMOVE);
2386 SetAccelerator(mbar, ID_ZOOMIN, DO_CURSIN);
2387 SetAccelerator(mbar, ID_ZOOMOUT, DO_CURSOUT);
2388
2389 SetAccelerator(mbar, ID_SCALE_1, DO_SCALE1);
2390 SetAccelerator(mbar, ID_SCALE_2, DO_SCALE2);
2391 SetAccelerator(mbar, ID_SCALE_4, DO_SCALE4);
2392 SetAccelerator(mbar, ID_SCALE_8, DO_SCALE8);
2393 SetAccelerator(mbar, ID_SCALE_16, DO_SCALE16);
2394 SetAccelerator(mbar, ID_SCALE_32, DO_SCALE32);
2395
2396 SetAccelerator(mbar, wxID_NEW, DO_NEWPATT);
2397 SetAccelerator(mbar, wxID_OPEN, DO_OPENPATT);
2398 SetAccelerator(mbar, ID_OPEN_CLIP, DO_OPENCLIP);
2399 SetAccelerator(mbar, wxID_SAVE, DO_SAVE);
2400 SetAccelerator(mbar, ID_SAVE_XRLE, DO_SAVEXRLE);
2401 SetAccelerator(mbar, ID_RUN_SCRIPT, DO_RUNSCRIPT);
2402 SetAccelerator(mbar, ID_RUN_CLIP, DO_RUNCLIP);
2403 SetAccelerator(mbar, ID_SHOW_FILES, DO_SHOWFILES);
2404 SetAccelerator(mbar, ID_FILE_DIR, DO_FILEDIR);
2405
2406 SetAccelerator(mbar, ID_UNDO, DO_UNDO);
2407 SetAccelerator(mbar, ID_REDO, DO_REDO);
2408 SetAccelerator(mbar, ID_NO_UNDO, DO_DISABLE);
2409 SetAccelerator(mbar, ID_CUT, DO_CUT);
2410 SetAccelerator(mbar, ID_COPY, DO_COPY);
2411 SetAccelerator(mbar, ID_CLEAR, DO_CLEAR);
2412 SetAccelerator(mbar, ID_OUTSIDE, DO_CLEAROUT);
2413 SetAccelerator(mbar, ID_PASTE, DO_PASTE);
2414 SetAccelerator(mbar, ID_PASTE_SEL, DO_PASTESEL);
2415 SetAccelerator(mbar, ID_SELECTALL, DO_SELALL);
2416 SetAccelerator(mbar, ID_REMOVE, DO_REMOVESEL);
2417 SetAccelerator(mbar, ID_SHRINK, DO_SHRINK);
2418 SetAccelerator(mbar, ID_RANDOM, DO_RANDFILL);
2419 SetAccelerator(mbar, ID_FLIPTB, DO_FLIPTB);
2420 SetAccelerator(mbar, ID_FLIPLR, DO_FLIPLR);
2421 SetAccelerator(mbar, ID_ROTATEC, DO_ROTATECW);
2422 SetAccelerator(mbar, ID_ROTATEA, DO_ROTATEACW);
2423
2424 SetAccelerator(mbar, ID_START, DO_STARTSTOP);
2425 SetAccelerator(mbar, ID_NEXT, DO_NEXTGEN);
2426 SetAccelerator(mbar, ID_STEP, DO_NEXTSTEP);
2427 SetAccelerator(mbar, ID_RESET, DO_RESET);
2428 SetAccelerator(mbar, ID_SETGEN, DO_SETGEN);
2429 SetAccelerator(mbar, ID_FASTER, DO_FASTER);
2430 SetAccelerator(mbar, ID_SLOWER, DO_SLOWER);
2431 SetAccelerator(mbar, ID_SETBASE, DO_SETBASE);
2432 SetAccelerator(mbar, ID_AUTO, DO_AUTOFIT);
2433 SetAccelerator(mbar, ID_HYPER, DO_HYPER);
2434 SetAccelerator(mbar, ID_HINFO, DO_HASHINFO);
2435 SetAccelerator(mbar, ID_SHOW_POP, DO_SHOWPOP);
2436 SetAccelerator(mbar, ID_RECORD, DO_RECORD);
2437 SetAccelerator(mbar, ID_DELTIME, DO_DELTIME);
2438 SetAccelerator(mbar, ID_SETRULE, DO_SETRULE);
2439
2440 SetAccelerator(mbar, ID_FULL, DO_FULLSCREEN);
2441 SetAccelerator(mbar, ID_FIT, DO_FIT);
2442 SetAccelerator(mbar, ID_FIT_SEL, DO_FITSEL);
2443 SetAccelerator(mbar, ID_MIDDLE, DO_MIDDLE);
2444 SetAccelerator(mbar, ID_RESTORE00, DO_RESTORE00);
2445 SetAccelerator(mbar, wxID_ZOOM_IN, DO_ZOOMIN);
2446 SetAccelerator(mbar, wxID_ZOOM_OUT, DO_ZOOMOUT);
2447 SetAccelerator(mbar, ID_TOOL_BAR, DO_SHOWTOOL);
2448 SetAccelerator(mbar, ID_LAYER_BAR, DO_SHOWLAYER);
2449 SetAccelerator(mbar, ID_EDIT_BAR, DO_SHOWEDIT);
2450 SetAccelerator(mbar, ID_ALL_STATES, DO_SHOWSTATES);
2451 SetAccelerator(mbar, ID_STATUS_BAR, DO_SHOWSTATUS);
2452 SetAccelerator(mbar, ID_EXACT, DO_SHOWEXACT);
2453 SetAccelerator(mbar, ID_GRID, DO_SHOWGRID);
2454 SetAccelerator(mbar, ID_ICONS, DO_SHOWICONS);
2455 SetAccelerator(mbar, ID_INVERT, DO_INVERT);
2456 SetAccelerator(mbar, ID_SMARTSCALE, DO_SMARTSCALE);
2457 SetAccelerator(mbar, ID_TIMELINE, DO_SHOWTIME);
2458 SetAccelerator(mbar, ID_SCROLL, DO_SHOWSCROLL);
2459 SetAccelerator(mbar, ID_INFO, DO_INFO);
2460
2461 SetAccelerator(mbar, ID_SAVE_OVERLAY, DO_SAVEOVERLAY);
2462 SetAccelerator(mbar, ID_SHOW_OVERLAY, DO_SHOWOVERLAY);
2463 SetAccelerator(mbar, ID_DEL_OVERLAY, DO_DELOVERLAY);
2464 SetAccelerator(mbar, ID_ADD_LAYER, DO_ADD);
2465 SetAccelerator(mbar, ID_CLONE, DO_CLONE);
2466 SetAccelerator(mbar, ID_DUPLICATE, DO_DUPLICATE);
2467 SetAccelerator(mbar, ID_DEL_LAYER, DO_DELETE);
2468 SetAccelerator(mbar, ID_DEL_OTHERS, DO_DELOTHERS);
2469 SetAccelerator(mbar, ID_MOVE_LAYER, DO_MOVELAYER);
2470 SetAccelerator(mbar, ID_NAME_LAYER, DO_NAMELAYER);
2471 SetAccelerator(mbar, ID_SET_COLORS, DO_SETCOLORS);
2472 SetAccelerator(mbar, ID_SYNC_VIEW, DO_SYNCVIEWS);
2473 SetAccelerator(mbar, ID_SYNC_CURS, DO_SYNCCURS);
2474 SetAccelerator(mbar, ID_STACK, DO_STACK);
2475 SetAccelerator(mbar, ID_TILE, DO_TILE);
2476 }
2477 }
2478
2479 // -----------------------------------------------------------------------------
2480
CreateDirControl()2481 void MainFrame::CreateDirControl()
2482 {
2483 filectrl = new wxGenericDirCtrl(splitwin, wxID_ANY, wxEmptyString,
2484 wxDefaultPosition, wxDefaultSize,
2485 #ifdef __WXMSW__
2486 // speed up a bit
2487 wxDIRCTRL_DIR_ONLY | wxNO_BORDER,
2488 #else
2489 wxNO_BORDER,
2490 #endif
2491 wxEmptyString // see all file types
2492 );
2493
2494 #ifdef __WXMSW__
2495 // now remove wxDIRCTRL_DIR_ONLY so we see files
2496 filectrl->SetWindowStyle(wxNO_BORDER);
2497 #endif
2498
2499 #if defined(__WXGTK__)
2500 // make sure background is white when using KDE's GTK theme
2501 #if wxCHECK_VERSION(2,9,0)
2502 filectrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_ERASE);
2503 #else
2504 filectrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_COLOUR);
2505 #endif
2506 filectrl->GetTreeCtrl()->SetBackgroundColour(*wxWHITE);
2507 // reduce indent a bit
2508 filectrl->GetTreeCtrl()->SetIndent(8);
2509 #elif defined(__WXMAC__)
2510 // reduce indent a bit more
2511 filectrl->GetTreeCtrl()->SetIndent(6);
2512 #else
2513 // reduce indent a lot on Windows
2514 filectrl->GetTreeCtrl()->SetIndent(4);
2515 #endif
2516
2517 #ifdef __WXMAC__
2518 // reduce font size (to get this to reduce line height we had to
2519 // make a few changes to wxMac/src/generic/treectlg.cpp)
2520 wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
2521 font.SetPointSize(12);
2522 filectrl->GetTreeCtrl()->SetFont(font);
2523 #endif
2524
2525 if ( wxFileName::DirExists(filedir) ) {
2526 // only show filedir and its contents
2527 SimplifyTree(filedir, filectrl->GetTreeCtrl(), filectrl->GetRootId());
2528 }
2529
2530 // install event handler to detect clicking on a file
2531 filectrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick));
2532 filectrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick));
2533 filectrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_LEFT_DCLICK, wxMouseEventHandler(MainFrame::OnTreeClick));
2534 }
2535
2536 // -----------------------------------------------------------------------------
2537
2538 // create the main window
MainFrame()2539 MainFrame::MainFrame()
2540 : wxFrame(NULL, wxID_ANY, wxEmptyString, wxPoint(mainx,mainy), wxSize(mainwd,mainht))
2541 {
2542 wxGetApp().SetFrameIcon(this);
2543
2544 pendingfiles.Clear(); // no pending script/pattern files
2545 command_pending = false; // no pending command
2546 draw_pending = false; // no pending draw
2547 keepmessage = false; // clear status message
2548 generating = false; // not generating pattern
2549 fullscreen = false; // not in full screen mode
2550 showbanner = true; // avoid first file clearing banner message
2551
2552 // initialize paths to some temporary files (in datadir so no need to be hidden);
2553 // they must be absolute paths in case they are used from a script command when the
2554 // current directory has been changed to the location of the script file
2555 clipfile = datadir + wxT("golly_clipboard");
2556 luafile = datadir + wxT("golly_clip.lua");
2557 perlfile = datadir + wxT("golly_clip.pl");
2558 pythonfile = datadir + wxT("golly_clip.py");
2559
2560 // create timer for generating patterns (see OnGenTimer in wxcontrol.cpp)
2561 gentimer = new wxTimer(this, ID_GENTIMER);
2562
2563 // create timer for calling OpenFile via OnIdle
2564 opentimer = new wxTimer(this, ID_OPENTIMER);
2565
2566 // create a scriptable graphics layer
2567 curroverlay = new Overlay();
2568
2569 CreateMenus();
2570 CreateToolbar();
2571
2572 // if tool bar is visible then adjust position of other child windows
2573 int toolwd = showtool ? TOOLBARWD : 0;
2574
2575 int wd, ht;
2576 GetClientSize(&wd, &ht);
2577 // wd or ht might be < 1 on Windows
2578 if (wd < 1) wd = 1;
2579 if (ht < 1) ht = 1;
2580
2581 // wxStatusBar can only appear at bottom of frame so we use our own
2582 // status bar class which creates a child window at top of frame
2583 // but to the right of the tool bar
2584 int statht = showexact ? STATUS_EXHT : STATUS_HT;
2585 if (!showstatus) statht = 0;
2586 statusptr = new StatusBar(this, toolwd, 0, wd - toolwd, statht);
2587
2588 // create a split window with file directory in left pane
2589 // and layer/edit/timeline bars and pattern viewport in right pane
2590 splitwin = new wxSplitterWindow(this, wxID_ANY,
2591 wxPoint(toolwd, statht),
2592 wxSize(wd - toolwd, ht - statht),
2593 #ifdef __WXMSW__
2594 wxSP_BORDER |
2595 #endif
2596 wxSP_3DSASH | wxSP_NO_XP_THEME | wxSP_LIVE_UPDATE);
2597
2598 // create filectrl in left pane
2599 CreateDirControl();
2600
2601 // create a window for right pane which contains layer/edit/timeline bars
2602 // and pattern viewport
2603 rightpane = new RightWindow(splitwin);
2604
2605 // create layer bar and initial layer
2606 CreateLayerBar(rightpane);
2607 AddLayer();
2608
2609 // create edit bar
2610 CreateEditBar(rightpane);
2611
2612 // create timeline bar
2613 CreateTimelineBar(rightpane);
2614
2615 // enable/disable tool tips after creating bars with buttons
2616 #if wxUSE_TOOLTIPS
2617 wxToolTip::Enable(showtips);
2618 wxToolTip::SetDelay(1500); // 1.5 secs
2619 #endif
2620
2621 CreateTranslucentControls(); // must be done BEFORE creating viewport
2622
2623 // create viewport at minimum size
2624 int y = 0;
2625 if (showlayer) y += LayerBarHeight();
2626 if (showedit) y += EditBarHeight();
2627 viewptr = new PatternView(rightpane, 0, y, 40, 40,
2628 wxNO_BORDER |
2629 wxWANTS_CHARS | // receive all keyboard events
2630 wxFULL_REPAINT_ON_RESIZE);
2631
2632 // this is the main viewport window (tile windows have a tileindex >= 0)
2633 viewptr->tileindex = -1;
2634 bigview = viewptr;
2635
2636 // create the scroll bars
2637 hbar = new wxScrollBar(rightpane, wxID_ANY, wxPoint(0,0), wxSize(-1, 15), wxSB_HORIZONTAL);
2638 vbar = new wxScrollBar(rightpane, wxID_ANY, wxPoint(0,0), wxSize(15, -1), wxSB_VERTICAL);
2639 hbar->SetMinSize(wxDefaultSize);
2640 vbar->SetMinSize(wxDefaultSize);
2641
2642 if (!showscrollbars) {
2643 // hide scroll bars
2644 hbar->Show(false);
2645 vbar->Show(false);
2646 }
2647
2648 #if wxUSE_DRAG_AND_DROP
2649 // let users drop files onto viewport
2650 viewptr->SetDropTarget(new DnDFile());
2651 #endif
2652
2653 // these seemingly redundant steps are needed to avoid problems on Windows
2654 splitwin->SplitVertically(filectrl, rightpane, dirwinwd);
2655 splitwin->SetSashPosition(dirwinwd);
2656 splitwin->SetMinimumPaneSize(MIN_DIRWD);
2657 splitwin->Unsplit(filectrl);
2658 splitwin->UpdateSize();
2659
2660 if (showfiles) splitwin->SplitVertically(filectrl, rightpane, dirwinwd);
2661 }
2662
2663 // -----------------------------------------------------------------------------
2664
~MainFrame()2665 MainFrame::~MainFrame()
2666 {
2667 delete hbar;
2668 delete vbar;
2669 delete curroverlay;
2670 delete gentimer;
2671 delete opentimer;
2672 DestroyDrawingData();
2673 }
2674