File: wxgolly.cpp

package info (click to toggle)
golly 3.3-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 20,176 kB
  • sloc: cpp: 72,638; ansic: 25,919; python: 7,921; sh: 4,245; objc: 3,721; java: 2,781; xml: 1,362; makefile: 530; javascript: 279; perl: 69
file content (382 lines) | stat: -rwxr-xr-x 12,544 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
// This file is part of Golly.
// See docs/License.html for the copyright notice.

// A GUI for Golly, implemented in wxWidgets (www.wxwidgets.org).
// Unfinished code is flagged by "!!!".
// Uncertain code is flagged by "???".

#include "wx/wxprec.h"     // for compilers that support precompilation
#ifndef WX_PRECOMP
    #include "wx/wx.h"     // for all others include the necessary headers
#endif

#include "wx/image.h"      // for wxImage
#include "wx/stdpaths.h"   // for wxStandardPaths
#include "wx/sysopt.h"     // for wxSystemOptions
#include "wx/filename.h"   // for wxFileName
#include "wx/fs_inet.h"    // for wxInternetFSHandler
#include "wx/fs_zip.h"     // for wxZipFSHandler

#include "lifepoll.h"
#include "util.h"          // for lifeerrors

#include "wxgolly.h"       // defines GollyApp class
#include "wxmain.h"        // defines MainFrame class
#include "wxstatus.h"      // defines StatusBar class
#include "wxview.h"        // defines PatternView class
#include "wxutils.h"       // for Warning, Fatal, BeginProgress, etc
#include "wxprefs.h"       // for GetPrefs, gollydir, rulesdir, userrules

#ifdef __WXMSW__
    // app icons are loaded via .rc file
#else
    #include "icons/appicon.xpm"
#endif

// -----------------------------------------------------------------------------

// Create a new application object: this macro will allow wxWidgets to create
// the application object during program execution and also implements the
// accessor function wxGetApp() which will return the reference of the correct
// type (ie. GollyApp and not wxApp).

IMPLEMENT_APP(GollyApp)

// -----------------------------------------------------------------------------

#define STRINGIFY(arg) STR2(arg)
#define STR2(arg) #arg

MainFrame* mainptr = NULL;       // main window
PatternView* viewptr = NULL;     // current viewport window (possibly a tile)
PatternView* bigview = NULL;     // main viewport window
StatusBar* statusptr = NULL;     // status bar window
wxStopWatch* stopwatch;          // global stopwatch
bool insideYield = false;        // processing an event via Yield()?

// -----------------------------------------------------------------------------

// let non-wx modules call Fatal, Warning, BeginProgress, etc

class wx_errors : public lifeerrors
{
public:
    virtual void fatal(const char* s) {
        Fatal(wxString(s,wxConvLocal));
    }
    
    virtual void warning(const char* s) {
        Warning(wxString(s,wxConvLocal));
    }
    
    virtual void status(const char* s) {
        statusptr->DisplayMessage(wxString(s,wxConvLocal));
    }
    
    virtual void beginprogress(const char* s) {
        BeginProgress(wxString(s,wxConvLocal));
        // init flag for isaborted() calls in non-wx modules
        aborted = false;
    }
    
    virtual bool abortprogress(double f, const char* s) {
        return AbortProgress(f, wxString(s,wxConvLocal));
    }
    
    virtual void endprogress() {
        EndProgress();
    }
    
    virtual const char* getuserrules() {
        // need to be careful converting Unicode wxString to char*
        #ifdef __WXMAC__
            // we need to convert path to decomposed UTF8 so fopen will work
            dirbuff = userrules.fn_str();
        #else
            dirbuff = userrules.mb_str(wxConvLocal);
        #endif
        return (const char*) dirbuff;
    }
    
    virtual const char* getrulesdir() {
        // need to be careful converting Unicode wxString to char*
        #ifdef __WXMAC__
            // we need to convert path to decomposed UTF8 so fopen will work
            dirbuff = rulesdir.fn_str();
        #else
            dirbuff = rulesdir.mb_str(wxConvLocal);
        #endif
        return (const char*) dirbuff;
    }
    
private:
    wxCharBuffer dirbuff;
};

wx_errors wxerrhandler;    // create instance

// -----------------------------------------------------------------------------

// let non-wx modules process events

class wx_poll : public lifepoll
{
public:
    virtual int checkevents();
    virtual void updatePop();
    long nextcheck;
};

int wx_poll::checkevents()
{
    // avoid calling Yield too often
    long t = stopwatch->Time();
    if (t > nextcheck) {
        nextcheck = t + 100;        // call 10 times per sec
        if (mainptr->infront) {
            // make sure viewport window keeps keyboard focus
            viewptr->SetFocus();
        }
        insideYield = true;
        wxGetApp().Yield(true);
        insideYield = false;
    }
    return isInterrupted();
}

void wx_poll::updatePop()
{
    if (showstatus && !mainptr->IsIconized()) {
        statusptr->Refresh(false);
    }
}

wx_poll wxpoller;    // create instance

lifepoll* GollyApp::Poller()
{
    return &wxpoller;
}

void GollyApp::PollerReset()
{
    wxpoller.resetInterrupted();
    wxpoller.nextcheck = 0;
}

void GollyApp::PollerInterrupt()
{
    wxpoller.setInterrupted();
    wxpoller.nextcheck = 0;
}

// -----------------------------------------------------------------------------

void SetAppDirectory(const char* argv0)
{
#ifdef __WXMSW__
    // on Windows we need to reset current directory to app directory if user
    // dropped file from somewhere else onto app to start it up (otherwise we
    // can't find Help files)
    wxString appdir = wxStandardPaths::Get().GetDataDir();
    wxString currdir = wxGetCwd();
    if ( currdir.CmpNoCase(appdir) != 0 )
        wxSetWorkingDirectory(appdir);
    // avoid VC++ warning
    wxUnusedVar(argv0);
#elif defined(__WXMAC__)
    // wxMac has set current directory to location of .app bundle so no need
    // to do anything
#else // assume Unix
    // first, try to switch to GOLLYDIR if that is set to a sensible value:
    static const char *gd = STRINGIFY(GOLLYDIR);
    if ( *gd == '/' && wxSetWorkingDirectory(wxString(gd,wxConvLocal)) ) {
        return;
    }
    // otherwise, use the executable directory as the application directory.
    // user might have started app from a different directory so find
    // last "/" in argv0 and change cwd if "/" isn't part of "./" prefix
    unsigned int pos = strlen(argv0);
    while (pos > 0) {
        pos--;
        if (argv0[pos] == '/') break;
    }
    if ( pos > 0 && !(pos == 1 && argv0[0] == '.') ) {
        char appdir[2048];
        if (pos < sizeof(appdir)) {
            strncpy(appdir, argv0, pos);
            appdir[pos] = 0;
            wxSetWorkingDirectory(wxString(appdir,wxConvLocal));
        }
    }
#endif
}

// -----------------------------------------------------------------------------

void GollyApp::SetFrameIcon(wxFrame* frame)
{
    // set frame icon
#ifdef __WXMSW__
    // create a bundle with 32x32 and 16x16 icons
    wxIconBundle icb(wxICON(appicon0));
    icb.AddIcon(wxICON(appicon1));
    frame->SetIcons(icb);
#else
    // use appicon.xpm on other platforms (ignored on Mac)
    frame->SetIcon(wxICON(appicon));
#endif
}

// -----------------------------------------------------------------------------

static wxString initdir;    // set to current working directory when app starts

#ifdef __WXMAC__

// open file double-clicked or dropped onto Golly icon

void GollyApp::MacOpenFile(const wxString& path)
{
    mainptr->Raise();
    wxFileName filename(path);
    // convert given path to a full path if not one already
    if (!filename.IsAbsolute()) filename = initdir + path;
    mainptr->pendingfiles.Add(filename.GetFullPath());

    // next OnIdle will call OpenFile (if we call OpenFile here with a script
    // that opens a modal dialog then dialog can't be closed!)
}

#endif

// -----------------------------------------------------------------------------

// app execution starts here

bool GollyApp::OnInit()
{
    SetAppName(_("Golly"));    // for use in Warning/Fatal dialogs
    
    // create a stopwatch so we can use Time() to get elapsed millisecs
    stopwatch = new wxStopWatch();
    
    // set variable seed for later rand() calls
    srand(time(0));
    
#if defined(__WXMAC__) && !wxCHECK_VERSION(2,7,2)
    // prevent rectangle animation when windows open/close
    wxSystemOptions::SetOption(wxMAC_WINDOW_PLAIN_TRANSITION, 1);
    // prevent position problem in wxTextCtrl with wxTE_DONTWRAP style
    // (but doesn't fix problem with I-beam cursor over scroll bars)
    wxSystemOptions::SetOption(wxMAC_TEXTCONTROL_USE_MLTE, 1);
#endif
    
    // get current working directory before calling SetAppDirectory
    initdir = wxFileName::GetCwd();
    if (initdir.Last() != wxFILE_SEP_PATH) initdir += wxFILE_SEP_PATH;
    
    // make sure current working directory contains application otherwise
    // we can't open Help files
    SetAppDirectory( wxString(argv[0]).mb_str(wxConvLocal) );
    
    // now set global gollydir for use in GetPrefs and elsewhere
    gollydir = wxFileName::GetCwd();
    if (gollydir.Last() != wxFILE_SEP_PATH) gollydir += wxFILE_SEP_PATH;
    
    // let non-wx modules call Fatal, Warning, BeginProgress, etc
    lifeerrors::seterrorhandler(&wxerrhandler);
    
    // allow .html files to include common graphic formats,
    // and .icons files to be in any of these formats;
    // note that wxBMPHandler is always installed, so it needs not be added,
    // and we can assume that if HAVE_WX_BMP_HANDLER is not defined, then
    // the handlers have not been auto-detected (and we just install them all).
#if !defined(HAVE_WX_BMP_HANDLER) || defined(HAVE_WX_GIF_HANDLER)
    wxImage::AddHandler(new wxGIFHandler);
#endif
#if !defined(HAVE_WX_BMP_HANDLER) || defined(HAVE_WX_PNG_HANDLER)
    wxImage::AddHandler(new wxPNGHandler);
#endif
#if !defined(HAVE_WX_BMP_HANDLER) || defined(HAVE_WX_TIFF_HANDLER)
    wxImage::AddHandler(new wxTIFFHandler);
#endif
    
    // wxInternetFSHandler is needed to allow downloading files
    wxFileSystem::AddHandler(new wxInternetFSHandler);
    wxFileSystem::AddHandler(new wxZipFSHandler);
    
    // get main window location and other user preferences
    GetPrefs();
    
    // create main window (also initializes viewptr, bigview, statusptr)
    mainptr = new MainFrame();
    if (mainptr == NULL) Fatal(_("Failed to create main window!"));
    
    // initialize some stuff before showing main window
    mainptr->SetRandomFillPercentage();
    mainptr->SetMinimumStepExponent();
    
    wxString banner = _("This is Golly version ");
    banner +=         _(STRINGIFY(VERSION)); 
    banner +=         _(" (");
#ifdef GOLLY64BIT
    banner +=         _("64-bit");
#else
    banner +=         _("32-bit");
#endif
#ifdef ENABLE_SOUND
    banner +=         _(", Sound");
#endif
    banner +=         _(").  Copyright 2005-2019 The Golly Gang.");
    if (debuglevel > 0) {
        banner += wxString::Format(_("  *** debuglevel = %d ***"), debuglevel);
    }
    statusptr->SetMessage(banner);
    
    mainptr->NewPattern();
    
    // script/pattern files are stored in the pendingfiles array for later processing
    // in OnIdle; this avoids a crash in Win app if a script is run before showing
    // the main window, and also avoids event problems in Win app with a long-running
    // script (eg. user can't hit escape to abort script)
    const wxString START_LUA = wxT("golly-start.lua");
    const wxString START_PYTHON = wxT("golly-start.py");
    wxString startscript = gollydir + START_LUA;
    if (wxFileExists(startscript)) {
        mainptr->pendingfiles.Add(startscript);
    } else {
        // look in user-specific data directory
        startscript = datadir + START_LUA;
        if (wxFileExists(startscript)) {
            mainptr->pendingfiles.Add(startscript);
        }
    }
    startscript = gollydir + START_PYTHON;
    if (wxFileExists(startscript)) {
        mainptr->pendingfiles.Add(startscript);
    } else {
        // look in user-specific data directory
        startscript = datadir + START_PYTHON;
        if (wxFileExists(startscript)) {
            mainptr->pendingfiles.Add(startscript);
        }
    }
    
    // argc is > 1 if command line has one or more script/pattern files
    for (int n = 1; n < argc; n++) {
        wxFileName filename(argv[n]);
        // convert given path to a full path if not one already
        if (!filename.IsAbsolute()) filename = initdir + argv[n];
        mainptr->pendingfiles.Add(filename.GetFullPath());
    }
    
    // show main window
    if (maximize) mainptr->Maximize(true);
    mainptr->Show(true);
    SetTopWindow(mainptr);
    
    // true means call wxApp::OnRun() which will enter the main event loop;
    // false means exit immediately
    return true;
}