1 /**********************************************************************
2
3 NyqBench.cpp
4
5 Leland Lucius
6
7 **********************************************************************/
8
9
10
11 #include <wx/defs.h>
12
13 #include <wx/aboutdlg.h>
14 #include <wx/filedlg.h>
15 #include <wx/font.h>
16 #include <wx/fontdlg.h>
17 #include <wx/menu.h>
18 #include <wx/msgdlg.h>
19 #include <wx/settings.h>
20 #include <wx/sizer.h>
21 #include <wx/splitter.h>
22 #include <wx/statbox.h>
23 #include <wx/textctrl.h>
24 #include <wx/toolbar.h>
25
26 #include "ActiveProject.h"
27 #include "AudioIOBase.h"
28 #include "CommonCommandFlags.h"
29 #include "ModuleConstants.h"
30 #include "Prefs.h"
31 #include "Project.h"
32 #include "ShuttleGui.h"
33 #include "effects/EffectManager.h"
34 #include "effects/EffectUI.h"
35 #include "effects/nyquist/Nyquist.h"
36 #include "../images/AudacityLogo.xpm"
37 #include "../../src/commands/CommandContext.h"
38 #include "../../src/commands/CommandManager.h"
39 #include "widgets/AudacityMessageBox.h"
40
41 #include "NyqBench.h"
42
43 #include <iostream>
44 #include <ostream>
45 #include <sstream>
46
47 //
48 // Images are from the Tango Icon Gallery
49 // http://tango.freedesktop.org/Tango_Icon_Gallery
50 //
51 #include "images/document-new-small.xpm"
52 #include "images/document-open-small.xpm"
53 #include "images/document-save-as-small.xpm"
54 #include "images/document-save-small.xpm"
55 #include "images/edit-clear-small.xpm"
56 #include "images/edit-copy-small.xpm"
57 #include "images/edit-cut-small.xpm"
58 #include "images/edit-delete-small.xpm"
59 #include "images/edit-find-small.xpm"
60 #include "images/edit-paste-small.xpm"
61 #include "images/edit-redo-small.xpm"
62 #include "images/edit-select-all-small.xpm"
63 #include "images/edit-undo-small.xpm"
64 #include "images/go-top-small.xpm"
65 #include "images/go-up-small.xpm"
66 #include "images/go-previous-small.xpm"
67 #include "images/go-next-small.xpm"
68 #include "images/system-search-small.xpm"
69 #include "images/media-playback-start-small.xpm"
70 #include "images/media-playback-stop-small.xpm"
71
72 #include "images/document-new-large.xpm"
73 #include "images/document-open-large.xpm"
74 #include "images/document-save-as-large.xpm"
75 #include "images/document-save-large.xpm"
76 #include "images/edit-clear-large.xpm"
77 #include "images/edit-copy-large.xpm"
78 #include "images/edit-cut-large.xpm"
79 #include "images/edit-delete-large.xpm"
80 #include "images/edit-find-large.xpm"
81 #include "images/edit-paste-large.xpm"
82 #include "images/edit-redo-large.xpm"
83 #include "images/edit-select-all-large.xpm"
84 #include "images/edit-undo-large.xpm"
85 #include "images/go-top-large.xpm"
86 #include "images/go-up-large.xpm"
87 #include "images/go-previous-large.xpm"
88 #include "images/go-next-large.xpm"
89 #include "images/system-search-large.xpm"
90 #include "images/media-playback-start-large.xpm"
91 #include "images/media-playback-stop-large.xpm"
92
93 /*
94 //#define ModuleDispatchName "ModuleDispatch"
95 See the example in this file. It has several cases/options in it.
96 */
97
98 namespace {
findme(AudacityProject &)99 CommandHandlerObject &findme(AudacityProject&)
100 {
101 return *NyqBench::GetBench();
102 }
103
RegisterMenuItems()104 void RegisterMenuItems()
105 {
106 // Get here only after the module version check passes
107 using namespace MenuTable;
108 static AttachedItem sAttachment{ wxT("Tools"),
109 ( FinderScope( findme ), Section( wxT("NyquistWorkBench"),
110 Command( wxT("NyqBench"), XXO("&Nyquist Workbench..."),
111 static_cast<CommandFunctorPointer>(&NyqBench::ShowNyqBench),
112 AudioIONotBusyFlag())
113 ) )
114 };
115 }
116 }
117
118 DEFINE_VERSION_CHECK
119
120 extern "C"
121 {
122 static NyqBench *gBench = NULL;
123
124 extern int DLL_API ModuleDispatch(ModuleDispatchTypes type);
125 // ModuleDispatch
126 // is called by Audacity to initialize/terminate the module
127 int ModuleDispatch(ModuleDispatchTypes type){
128 switch (type){
129 case ModuleInitialize:
130 RegisterMenuItems();
131 break;
132 case AppQuiting: {
133 //It is perfectly OK for gBench to be NULL.
134 //Can happen if the menu item was never invoked.
135 //wxASSERT(gBench != NULL);
136 if (gBench) {
137 // be sure to do this while gPrefs still exists:
138 gBench->SavePrefs();
139 gBench->Destroy();
140 gBench = NULL;
141 }
142 }
143 break;
144 default:
145 break;
146 }
147 return 1;
148 }
149 };
150
151 //----------------------------------------------------------------------------
152 // NyqTextCtrl
153 //----------------------------------------------------------------------------
154
BEGIN_EVENT_TABLE(NyqTextCtrl,wxTextCtrl)155 BEGIN_EVENT_TABLE(NyqTextCtrl, wxTextCtrl)
156 #if defined(__WXMAC__)
157 EVT_KEY_DOWN(NyqTextCtrl::OnKeyDown)
158 #endif
159 EVT_KEY_UP(NyqTextCtrl::OnKeyUp)
160 EVT_CHAR(NyqTextCtrl::OnChar)
161 EVT_UPDATE_UI(wxID_ANY, NyqTextCtrl::OnUpdate)
162 END_EVENT_TABLE()
163
164 NyqTextCtrl::NyqTextCtrl(wxWindow *parent,
165 wxWindowID id,
166 const wxString &value,
167 const wxPoint & pos,
168 const wxSize & size,
169 int style)
170 : wxTextCtrl(parent, id, value, pos, size, style)
171 {
172 mLastCaretPos = -1;
173 mLeftParen = -1;
174 mRightParen = -1;
175
176 mOn.SetTextColour(*wxRED);
177 mOff.SetTextColour(*wxBLACK);
178 }
179
SetFocusFromKbd()180 void NyqTextCtrl::SetFocusFromKbd()
181 {
182 #if defined(__WXMSW__)
183 // We do this to prevent wxMSW from selecting all text when the
184 // user tabs into the text controls.
185 wxWindowBase::SetFocusFromKbd();
186 #else
187 wxTextCtrl::SetFocusFromKbd();
188 #endif
189 }
190
MarkDirty()191 void NyqTextCtrl::MarkDirty()
192 {
193 wxTextCtrl::MarkDirty();
194 FindParens();
195 }
196
OnChar(wxKeyEvent & e)197 void NyqTextCtrl::OnChar(wxKeyEvent & e)
198 {
199 e.Skip();
200
201 // Hide any previously highlighted parens
202 if (mLeftParen >= 0) {
203 #if defined(__WXMSW__)
204 Freeze(); // Prevents selection flashing on Windows
205 #endif
206
207 SetStyle(mLeftParen, mLeftParen + 1, mOff);
208 SetStyle(mLeftParens[mLeftParen], mLeftParens[mLeftParen] + 1, mOff);
209 mLeftParen = -1;
210 mRightParen = -1;
211
212 #if defined(__WXMSW__)
213 Thaw(); // Prevents selection flashing on Windows
214 #endif
215 }
216 }
217
218 #if defined(__WXMAC__REMOVED_UNTIL_ITS_PROVEN_THAT_IT_IS_STILL_NEEDED)
219 #include <wx/mac/uma.h>
220
221 // This is hackage to correct a problem on Leopard where the
222 // caret jumps up two lines when the up arrow is pressed and
223 // the caret is at the beginning of the line.
OnKeyDown(wxKeyEvent & e)224 void NyqTextCtrl::OnKeyDown(wxKeyEvent & e)
225 {
226 e.Skip();
227 if (UMAGetSystemVersion() >= 0x1050) {
228 if (e.GetKeyCode() == WXK_UP && e.GetModifiers() == 0) {
229 long x;
230 long y;
231
232 PositionToXY(GetInsertionPoint(), &x, &y);
233 if (x == 0 && y > 1) {
234 y--;
235 SetInsertionPoint(XYToPosition(x, y) - 1);
236 e.Skip(false);
237 }
238 }
239 }
240 }
241 #endif
242
OnKeyUp(wxKeyEvent & e)243 void NyqTextCtrl::OnKeyUp(wxKeyEvent & e)
244 {
245 e.Skip();
246
247 int pos = GetInsertionPoint();
248 int lpos = wxMax(0, pos - 1);
249
250 wxString text = GetRange(lpos, pos);
251
252 if (text[0] == wxT('(')) {
253 wxLongToLongHashMap::const_iterator left = mLeftParens.find(lpos);
254 if (left != mLeftParens.end()) {
255 Colorize(lpos, left->second);
256 }
257 }
258 else if (text[0] == wxT(')')) {
259 wxLongToLongHashMap::const_iterator right = mRightParens.find(lpos);
260 if (right != mRightParens.end()) {
261 Colorize(right->second, lpos);
262 }
263 }
264 }
265
OnUpdate(wxUpdateUIEvent & e)266 void NyqTextCtrl::OnUpdate(wxUpdateUIEvent & e)
267 {
268 int pos = GetInsertionPoint();
269
270 if (pos != mLastCaretPos) {
271 int lpos = wxMax(0, pos - 1);
272
273 wxString text = GetRange(lpos, pos);
274 if (text.Length() > 0) {
275 if (text[0] == wxT('(')) {
276 wxLongToLongHashMap::const_iterator left = mLeftParens.find(lpos);
277 if (left != mLeftParens.end()) {
278 Colorize(lpos, left->second);
279 }
280 }
281 else if (text[0] == wxT(')')) {
282 wxLongToLongHashMap::const_iterator right = mRightParens.find(lpos);
283 if (right != mRightParens.end()) {
284 Colorize(right->second, lpos);
285 }
286 }
287 }
288
289 mLastCaretPos = pos;
290 }
291 }
292
GoMatch()293 void NyqTextCtrl::GoMatch()
294 {
295 MoveCursor(mRightParen, mLeftParen);
296 }
297
GoTop()298 void NyqTextCtrl::GoTop()
299 {
300 wxLongToLongHashMap::const_iterator it;
301 long first = -1;
302 long second = -1;
303
304 if (mLeftParen != -1) {
305 for (it = mLeftParens.begin(); it != mLeftParens.end(); it++) {
306 if (mLeftParen > it->first && mLeftParen < it->second) {
307 if (first == -1 || it->first < first) {
308 first = it->first;
309 second = it->second;
310 }
311 }
312 }
313 }
314
315 if (first != -1) {
316 MoveCursor(first, second);
317 }
318 }
319
GoUp()320 void NyqTextCtrl::GoUp()
321 {
322 wxLongToLongHashMap::const_iterator it;
323 long first = -1;
324 long second = -1;
325
326 if (mLeftParen != -1) {
327 for (it = mLeftParens.begin(); it != mLeftParens.end(); it++) {
328 if (mLeftParen > it->first && mLeftParen < it->second) {
329 if (first == -1 || it->first > first) {
330 first = it->first;
331 second = it->second;
332 }
333 }
334 }
335 }
336
337 if (first != -1) {
338 MoveCursor(first, second);
339 }
340 }
341
GoPrev()342 void NyqTextCtrl::GoPrev()
343 {
344 wxLongToLongHashMap::const_iterator it;
345 long first = -1;
346 long second = -1;
347
348 if (mLeftParen != -1) {
349 for (it = mLeftParens.begin(); it != mLeftParens.end(); it++) {
350 if (it->first < mLeftParen && it->first >= first) {
351 first = it->first;
352 second = it->second;
353 }
354 }
355 }
356
357 if (first != -1) {
358 MoveCursor(first, second);
359 }
360 }
361
GoNext()362 void NyqTextCtrl::GoNext()
363 {
364 wxLongToLongHashMap::const_iterator it;
365 long first = -1;
366 long second = -1;
367
368 if (mLeftParen != -1) {
369 for (it = mLeftParens.begin(); it != mLeftParens.end(); it++) {
370 if (it->first > mLeftParen && (first == -1 || it->first < first)) {
371 first = it->first;
372 second = it->second;
373 }
374 }
375 }
376
377 if (first != -1) {
378 MoveCursor(first, second);
379 }
380 }
381
MoveCursor(long first,long second)382 void NyqTextCtrl::MoveCursor(long first, long second)
383 {
384 int pos = GetInsertionPoint();
385 int lpos = wxMax(0, pos - 1);
386
387 wxString text = GetRange(lpos, pos);
388
389 if (text[0] == wxT('(')) {
390 SetInsertionPoint(first + 1);
391 Colorize(first, second);
392 }
393 else if (text[0] == wxT(')')) {
394 SetInsertionPoint(second + 1);
395 Colorize(first, second);
396 }
397 }
398
Colorize(long left,long right)399 void NyqTextCtrl::Colorize(long left, long right)
400 {
401 // Hide any previously highlighted parens
402 if (mLeftParen >= 0) {
403 #if defined(__WXMSW__)
404 Freeze(); // Prevents selection flashing on Windows
405 #endif
406
407 SetStyle(mLeftParen, mLeftParen + 1, mOff);
408 SetStyle(mLeftParens[mLeftParen], mLeftParens[mLeftParen] + 1, mOff);
409 mLeftParen = -1;
410 mRightParen = -1;
411
412 #if defined(__WXMSW__)
413 Thaw(); // Prevents selection flashing on Windows
414 #endif
415 }
416
417 mLeftParen = left;
418 mRightParen = right;
419
420 if (mLeftParen != -1) {
421 SetStyle(mLeftParen, mLeftParen + 1, mOn);
422 SetStyle(mRightParen, mRightParen + 1, mOn);
423
424 SetStyle(mLeftParen + 1, mLeftParen + 1, mOff);
425 SetStyle(mRightParen + 1, mRightParen + 1, mOff);
426 }
427 }
428
FindParens()429 void NyqTextCtrl::FindParens()
430 {
431 wxString text = GetValue();
432 bool inquotes = false;
433 wxArrayInt stack;
434 long len = (long) text.Length();
435 long pos;
436
437 mLeftParens.clear();
438 mRightParens.clear();
439
440 for (pos = 0; pos < len; pos++) {
441 wxChar c = text[pos];
442 switch (c)
443 {
444 case wxT('"'):
445 inquotes = !inquotes;
446 break;
447
448 case wxT(';'):
449 if (!inquotes) {
450 pos = (long)text.find(wxT('\n'), pos);
451 if (pos == (long)wxString::npos) {
452 pos = len;
453 }
454 }
455 break;
456
457 case wxT('#'):
458 if (!inquotes) {
459 long ndx = pos + 1;
460 if (ndx < len && text[(int)ndx] == wxT('|')) {
461 // Shamelessly stolen from xlread.c/pcomment()
462 wxChar lastch = -1;
463 int n = 1;
464
465 /* look for the matching delimiter (and handle nesting) */
466 while (n > 0 && ++pos < len) {
467 wxChar ch = text[(int)pos];
468 if (lastch == '|' && ch == '#') {
469 --n;
470 ch = -1;
471 }
472 else if (lastch == '#' && ch == '|') {
473 ++n;
474 ch = -1;
475 }
476 lastch = ch;
477 }
478 }
479 }
480 break;
481
482 case wxT('('):
483 if (!inquotes) {
484 stack.Add(pos);
485 }
486 break;
487
488 case wxT(')'):
489 if (!inquotes) {
490 if (stack.GetCount() > 0) {
491 int left = stack.Last();
492 stack.RemoveAt(stack.GetCount() - 1);
493
494 mLeftParens[left] = pos;
495 mRightParens[pos] = left;
496 }
497 }
498 break;
499 }
500 }
501 }
502
503 //----------------------------------------------------------------------------
504 // NyqRedirector
505 //----------------------------------------------------------------------------
506
NyqRedirector(NyqTextCtrl * text)507 NyqRedirector::NyqRedirector(NyqTextCtrl *text)
508 : mText(text)
509 {
510 mOld = std::cout.rdbuf(this);
511 }
512
~NyqRedirector()513 NyqRedirector::~NyqRedirector()
514 {
515 std::cout.flush();
516 std::cout.rdbuf(mOld);
517 if (s.length() > 0) {
518 AppendText();
519 }
520 }
521
overflow(int c)522 int NyqRedirector::overflow(int c)
523 {
524 s += (char)c;
525 if (c == '\n') {
526 AppendText();
527 }
528
529 return 0;
530 }
531
AppendText()532 void NyqRedirector::AppendText()
533 {
534 mText->AppendText(wxString(s.c_str(), wxConvISO8859_1));
535 s.clear();
536 }
537
538 //----------------------------------------------------------------------------
539 // NyqBench
540 //----------------------------------------------------------------------------
541
542 enum
543 {
544 ID_AUTOLOAD = 20000,
545
546 ID_AUTOWRAP,
547
548 ID_FONT,
549 ID_SPLITV,
550 ID_SPLITH,
551 ID_TOGGLECODE,
552 ID_TOGGLEOUTPUT,
553 ID_SMALLICONS,
554 ID_LARGEICONS,
555 ID_MATCH,
556 ID_TOP,
557 ID_UP,
558 ID_PREVIOUS,
559 ID_NEXT,
560
561 ID_GO,
562 ID_STOP,
563
564 ID_SCRIPT,
565 ID_OUTPUT
566 };
567
BEGIN_EVENT_TABLE(NyqBench,wxFrame)568 BEGIN_EVENT_TABLE(NyqBench, wxFrame)
569 EVT_CLOSE(NyqBench::OnClose)
570 EVT_MOVE(NyqBench::OnMove)
571 EVT_SIZE(NyqBench::OnSize)
572
573 EVT_MENU(wxID_NEW, NyqBench::OnNew)
574 EVT_MENU(wxID_OPEN, NyqBench::OnOpen)
575 EVT_MENU(wxID_SAVE, NyqBench::OnSave)
576 EVT_MENU(wxID_SAVEAS, NyqBench::OnSaveAs)
577 EVT_MENU(wxID_REVERT_TO_SAVED, NyqBench::OnRevert)
578 EVT_MENU(ID_AUTOLOAD, NyqBench::OnAutoLoad)
579 EVT_MENU(wxID_CLOSE, NyqBench::OnCloseWindow)
580
581 EVT_MENU(wxID_UNDO, NyqBench::OnUndo)
582 EVT_MENU(wxID_REDO, NyqBench::OnRedo)
583 EVT_MENU(wxID_CUT, NyqBench::OnCut)
584 EVT_MENU(wxID_COPY, NyqBench::OnCopy)
585 EVT_MENU(wxID_PASTE, NyqBench::OnPaste)
586 EVT_MENU(wxID_CLEAR, NyqBench::OnClear)
587 EVT_MENU(wxID_SELECTALL, NyqBench::OnSelectAll)
588 EVT_MENU(wxID_FIND, NyqBench::OnFind)
589 EVT_MENU(ID_MATCH, NyqBench::OnGoMatch)
590 EVT_MENU(ID_TOP, NyqBench::OnGoTop)
591 EVT_MENU(ID_UP, NyqBench::OnGoUp)
592 EVT_MENU(ID_PREVIOUS, NyqBench::OnGoPrev)
593 EVT_MENU(ID_NEXT, NyqBench::OnGoNext)
594 EVT_MENU(ID_AUTOWRAP, NyqBench::OnAutoWrap)
595
596 EVT_MENU(ID_FONT, NyqBench::OnFont)
597 EVT_MENU(ID_SPLITV, NyqBench::OnSplitV)
598 EVT_MENU(ID_SPLITH, NyqBench::OnSplitH)
599 EVT_MENU(ID_TOGGLECODE, NyqBench::OnToggleCode)
600 EVT_MENU(ID_TOGGLEOUTPUT, NyqBench::OnToggleOutput)
601 EVT_MENU(ID_SMALLICONS, NyqBench::OnSmallIcons)
602 EVT_MENU(ID_LARGEICONS, NyqBench::OnLargeIcons)
603
604 EVT_MENU(ID_GO, NyqBench::OnGo)
605 EVT_MENU(ID_STOP, NyqBench::OnStop)
606
607 EVT_MENU(wxID_ABOUT, NyqBench::OnAbout)
608
609 EVT_FIND(wxID_ANY, NyqBench::OnFindDialog)
610 EVT_FIND_NEXT(wxID_ANY, NyqBench::OnFindDialog)
611 EVT_FIND_REPLACE(wxID_ANY, NyqBench::OnFindDialog)
612 EVT_FIND_REPLACE_ALL(wxID_ANY, NyqBench::OnFindDialog)
613 EVT_FIND_CLOSE(wxID_ANY, NyqBench::OnFindDialog)
614
615 EVT_TEXT(ID_SCRIPT, NyqBench::OnTextUpdate)
616
617 EVT_UPDATE_UI(wxID_SAVE, NyqBench::OnMenuUpdate)
618 EVT_UPDATE_UI(wxID_SAVEAS, NyqBench::OnMenuUpdate)
619 EVT_UPDATE_UI(wxID_REVERT_TO_SAVED, NyqBench::OnMenuUpdate)
620
621 EVT_UPDATE_UI(wxID_UNDO, NyqBench::OnUndoUpdate)
622 EVT_UPDATE_UI(wxID_REDO, NyqBench::OnRedoUpdate)
623 EVT_UPDATE_UI(wxID_CUT, NyqBench::OnCutUpdate)
624 EVT_UPDATE_UI(wxID_COPY, NyqBench::OnCopyUpdate)
625 EVT_UPDATE_UI(wxID_PASTE, NyqBench::OnPasteUpdate)
626 EVT_UPDATE_UI(wxID_CLEAR, NyqBench::OnClearUpdate)
627
628 EVT_UPDATE_UI(ID_SPLITH, NyqBench::OnViewUpdate)
629 EVT_UPDATE_UI(ID_SPLITV, NyqBench::OnViewUpdate)
630 EVT_UPDATE_UI(ID_TOGGLECODE, NyqBench::OnViewUpdate)
631 EVT_UPDATE_UI(ID_TOGGLEOUTPUT, NyqBench::OnViewUpdate)
632
633 EVT_UPDATE_UI(ID_GO, NyqBench::OnRunUpdate)
634
635 EVT_UPDATE_UI(ID_SCRIPT, NyqBench::OnScriptUpdate)
636 EVT_UPDATE_UI(ID_OUTPUT, NyqBench::OnOutputUpdate)
637 END_EVENT_TABLE()
638
639 /*static*/ NyqBench *NyqBench::GetBench()
640 {
641 if (gBench == nullptr)
642 {
643 gBench = new NyqBench(NULL);
644 }
645
646 return gBench;
647 }
648
NyqBench(wxWindow * parent)649 NyqBench::NyqBench(wxWindow * parent)
650 : wxFrame(NULL,
651 wxID_ANY,
652 wxEmptyString,
653 wxDefaultPosition,
654 wxDefaultSize,
655 wxDEFAULT_FRAME_STYLE |
656 wxMINIMIZE_BOX |
657 wxMAXIMIZE_BOX |
658 wxRESIZE_BORDER)
659 {
660 mFindDlg = NULL;
661 mRunning = false;
662 mScriptBox = NULL;
663 mOutputBox = NULL;
664 mScript = NULL;
665 mOutput = NULL;
666
667 mPath = gPrefs->Read(wxT("NyqBench/Path"), wxEmptyString);
668 mAutoLoad = (gPrefs->Read(wxT("NyqBench/AutoLoad"), 0L) != 0);
669 mAutoWrap = (gPrefs->Read(wxT("NyqBench/AutoWrap"), true) != 0);
670 mLargeIcons = (gPrefs->Read(wxT("NyqBench/LargeIcons"), 0L) != 0);
671 mSplitMode = gPrefs->Read(wxT("NyqBench/SplitMode"), wxSPLIT_VERTICAL);
672 mShowCode = (gPrefs->Read(wxT("NyqBench/ShowScript"), true) != 0);
673 mShowOutput = (gPrefs->Read(wxT("NyqBench/ShowOutput"), true) != 0);
674
675 SetIcon(wxICON(AudacityLogo));
676 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
677 ShuttleGui S(this, eIsCreating);
678 PopulateOrExchange(S);
679 wxMenuBar *bar = new wxMenuBar();
680
681 wxMenu *menu = new wxMenu();
682 menu->Append(wxID_NEW, wxT("&New\tCtrl+N"));
683 menu->Append(wxID_OPEN, wxT("&Open...\tCtrl+O"));
684 menu->Append(wxID_SAVE, wxT("&Save...\tCtrl+S"));
685 menu->Append(wxID_SAVEAS, wxT("Save &As...\tCtrl+Shift+S"));
686 menu->AppendSeparator();
687 menu->Append(wxID_REVERT_TO_SAVED, _T("&Revert to Saved"));
688 menu->AppendSeparator();
689 menu->AppendCheckItem(ID_AUTOLOAD, _T("Auto &Load Last File"))->Check(mAutoLoad);
690 menu->AppendSeparator();
691 menu->Append(wxID_CLOSE, wxT("&Close Window\tCtrl+W"));
692 bar->Append(menu, wxT("&File"));
693
694 menu = new wxMenu();
695 menu->Append(wxID_UNDO, _("&Undo\tCtrl+Z"));
696 menu->Append(wxID_REDO, _("&Redo\tCtrl+Y"));
697 menu->AppendSeparator();
698 menu->Append(wxID_CUT, _("Cu&t\tCtrl+X"));
699 menu->Append(wxID_COPY, _("&Copy\tCtrl+C"));
700 menu->Append(wxID_PASTE, _("&Paste\tCtrl+V"));
701 menu->Append(wxID_CLEAR, _("Cle&ar\tCtrl+L"));
702 menu->AppendSeparator();
703 menu->Append(wxID_SELECTALL, _("Select A&ll\tCtrl+A"));
704 menu->AppendSeparator();
705 menu->Append(wxID_FIND, _("&Find...\tCtrl+F"));
706 menu->AppendSeparator();
707 wxMenu *sub = new wxMenu();
708 sub->Append(ID_MATCH, _("&Matching Paren\tF8"));
709 sub->Append(ID_TOP, _("&Top S-expr\tF9"));
710 sub->Append(ID_UP, _("&Higher S-expr\tF10"));
711 sub->Append(ID_PREVIOUS, _("&Previous S-expr\tF11"));
712 sub->Append(ID_NEXT, _("&Next S-expr\tF12"));
713 menu->AppendSubMenu(sub, _("&Go to"));
714 menu->AppendSeparator();
715 menu->AppendCheckItem(ID_AUTOWRAP, _T("Auto &Wrap"))->Check(mAutoWrap);
716 bar->Append(menu, wxT("&Edit"));
717
718 menu = new wxMenu();
719 menu->Append(ID_FONT, _("Select &Font..."));
720 menu->AppendSeparator();
721 menu->Append(ID_SPLITV, _("Split &Vertically"));
722 menu->Append(ID_SPLITH, _("Split &Horizontally"));
723 menu->AppendSeparator();
724 menu->AppendCheckItem(ID_TOGGLECODE, _("Show S&cript"));
725 menu->AppendCheckItem(ID_TOGGLEOUTPUT, _("Show &Output"));
726 menu->AppendSeparator();
727 sub = new wxMenu();
728 sub->AppendRadioItem(ID_LARGEICONS, _("&Large Icons"));
729 sub->AppendRadioItem(ID_SMALLICONS, _("&Small Icons"));
730 menu->AppendSubMenu(sub, _("Toolbar"));
731 bar->Append(menu, wxT("&View"));
732
733 menu = new wxMenu();
734 menu->Append(ID_GO, _("&Go\tF5"));
735 menu->Append(ID_STOP, _("&Stop\tF6"));
736 bar->Append(menu, wxT("&Run"));
737
738 #if defined(__WXMAC__)
739 menu->Append(wxID_ABOUT, _("&About"));
740 #else
741 menu = new wxMenu();
742 menu->Append(wxID_ABOUT, _("&About"));
743 bar->Append(menu, wxT("Help"));
744 #endif
745
746 SetMenuBar(bar);
747
748 RecreateToolbar(mLargeIcons);
749
750 wxRect r;
751 r.SetX(gPrefs->Read(wxT("NyqBench/Window/X"), -1));
752 r.SetY(gPrefs->Read(wxT("NyqBench/Window/Y"), -1));
753 r.SetWidth(gPrefs->Read(wxT("NyqBench/Window/Width"), -1));
754 r.SetHeight(gPrefs->Read(wxT("NyqBench/Window/Height"), -1));
755 if (r == wxRect(-1, -1, -1, -1)) {
756 Center();
757 }
758 else {
759 SetSize(r);
760 }
761
762 bool maximized = false;
763 gPrefs->Read(wxT("NyqBench/Window/Maximized"), maximized);
764 if (maximized) {
765 Maximize();
766 }
767
768 long sashpos;
769 sashpos = gPrefs->Read(wxT("NyqBench/SplitX"), 0l);
770 if (sashpos > 0) {
771 mSplitter->SetSashPosition(sashpos);
772 }
773
774 wxString dflt = wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT).GetNativeFontInfoDesc();
775 wxString desc;
776 wxTextAttr attr;
777
778 desc = gPrefs->Read(wxT("NyqBench/ScriptFont"), dflt);
779 mScriptFont.SetNativeFontInfo(desc);
780 #if defined(__WXMSW__)
781 // Force SYSTEM encoding to prevent conversion to Unicode in wxTextCtrl::DoWriteText().
782 // I don't know if this is something I'm doing wrong, but I'll have to look at this
783 // later if I get bored.
784 mScriptFont.SetEncoding(wxFONTENCODING_SYSTEM);
785 #endif
786 attr.SetFont(mScriptFont);
787 mScript->SetDefaultStyle(attr);
788
789 desc = gPrefs->Read(wxT("NyqBench/OutputFont"), dflt);
790 mOutputFont.SetNativeFontInfo(desc);
791 #if defined(__WXMSW__)
792 // Force SYSTEM encoding to prevent conversion to Unicode in wxTextCtrl::DoWriteText().
793 // I don't know if this is something I'm doing wrong, but I'll have to look at this
794 // later if I get bored.
795 mOutputFont.SetEncoding(wxFONTENCODING_SYSTEM);
796 #endif
797 attr.SetFont(mOutputFont);
798 mOutput->SetDefaultStyle(attr);
799
800 if (mAutoLoad && !mPath.GetFullPath().IsEmpty()) {
801 LoadFile();
802 }
803
804 SetWindowTitle();
805 }
806
~NyqBench()807 NyqBench::~NyqBench()
808 {
809 }
810
SavePrefs()811 void NyqBench::SavePrefs()
812 {
813 gPrefs->Write(wxT("NyqBench/Window/Maximized"), IsMaximized());
814 if (!IsMaximized()) {
815 wxRect r = GetRect();
816
817 #if !defined(__WXMAC__)
818 if (IsIconized()) {
819 r = mLastSize;
820 }
821 #endif
822
823 gPrefs->Write(wxT("NyqBench/Window/X"), r.GetX());
824 gPrefs->Write(wxT("NyqBench/Window/Y"), r.GetY());
825 gPrefs->Write(wxT("NyqBench/Window/Width"), r.GetWidth());
826 gPrefs->Write(wxT("NyqBench/Window/Height"), r.GetHeight());
827 }
828
829 gPrefs->Write(wxT("NyqBench/AutoLoad"), mAutoLoad);
830 gPrefs->Write(wxT("NyqBench/AutoWrap"), mAutoWrap);
831 gPrefs->Write(wxT("NyqBench/ScriptFont"), mScriptFont.GetNativeFontInfoDesc());
832 gPrefs->Write(wxT("NyqBench/OutputFont"), mOutputFont.GetNativeFontInfoDesc());
833 gPrefs->Write(wxT("NyqBench/LargeIcons"), mLargeIcons);
834 gPrefs->Write(wxT("NyqBench/SplitX"), mSplitter->IsSplit() ? mSplitter->GetSashPosition() : 0);
835 gPrefs->Write(wxT("NyqBench/SplitMode"), mSplitter->IsSplit() ? mSplitter->GetSplitMode() : 0);
836 gPrefs->Write(wxT("NyqBench/ShowCode"), mScript->IsShown());
837 gPrefs->Write(wxT("NyqBench/ShowOutput"), mOutput->IsShown());
838 }
839
PopulateOrExchange(ShuttleGui & S)840 void NyqBench::PopulateOrExchange(ShuttleGui & S)
841 {
842 S.StartHorizontalLay(wxEXPAND, true);
843 {
844 wxPanel *scriptp;
845 wxPanel *outputp;
846 wxStaticBoxSizer *scripts;
847 wxStaticBoxSizer *outputs;
848 wxBoxSizer *bs;
849
850 mSplitter = new wxSplitterWindow(this,
851 wxID_ANY,
852 wxDefaultPosition,
853 wxDefaultSize,
854 wxSP_LIVE_UPDATE |
855 wxSP_3DSASH |
856 wxSP_NOBORDER);
857
858 scriptp = new wxPanel(mSplitter,
859 wxID_ANY,
860 wxDefaultPosition,
861 wxDefaultSize,
862 wxNO_FULL_REPAINT_ON_RESIZE |
863 wxCLIP_CHILDREN);
864 bs = new wxBoxSizer(wxVERTICAL);
865 scriptp->SetSizer(bs);
866
867 mScriptBox = new wxStaticBox(scriptp,
868 wxID_ANY,
869 _("Script"));
870
871 scripts = new wxStaticBoxSizer(mScriptBox,
872 wxVERTICAL);
873 bs->Add(scripts, true, wxEXPAND);
874
875 mScript = new NyqTextCtrl(scriptp,
876 ID_SCRIPT,
877 wxEmptyString,
878 wxDefaultPosition,
879 wxDefaultSize,
880 wxTE_RICH2 | wxTE_RICH |
881 (mAutoWrap ? wxTE_BESTWRAP : wxTE_DONTWRAP) |
882 wxTE_NOHIDESEL |
883 wxTE_MULTILINE);
884 scripts->Add(mScript, true, wxEXPAND);
885
886 outputp = new wxPanel(mSplitter,
887 wxID_ANY,
888 wxDefaultPosition,
889 wxDefaultSize,
890 wxNO_FULL_REPAINT_ON_RESIZE |
891 wxCLIP_CHILDREN);
892 bs = new wxBoxSizer(wxVERTICAL);
893 outputp->SetSizer(bs);
894
895 mOutputBox = new wxStaticBox(outputp,
896 wxID_ANY,
897 _("Output"));
898 outputs = new wxStaticBoxSizer(mOutputBox,
899 wxVERTICAL);
900 bs->Add(outputs, true, wxEXPAND);
901
902 mOutput = new NyqTextCtrl(outputp,
903 ID_OUTPUT,
904 wxEmptyString,
905 wxDefaultPosition,
906 wxDefaultSize,
907 wxTE_READONLY |
908 #if !defined(__WXMAC__)
909 // I could not get the bloody horizontal scroll bar to appear on
910 // wxMac, so we can't use wxTE_DONTWRAP as you can't easily scroll
911 // left and right.
912 wxTE_DONTWRAP |
913 #endif
914 wxTE_NOHIDESEL |
915 wxTE_MULTILINE);
916 outputs->Add(mOutput, true, wxEXPAND);
917
918 switch (mSplitMode)
919 {
920 case wxSPLIT_VERTICAL:
921 mSplitter->SplitVertically(scriptp, outputp, 300);
922 break;
923
924 case wxSPLIT_HORIZONTAL:
925 mSplitter->SplitHorizontally(scriptp, outputp, 300);
926 break;
927
928 default:
929 mSplitter->Initialize((mShowCode ? scriptp : outputp));
930 break;
931 }
932
933 mSplitter->SetMinimumPaneSize(50);
934
935 S.AddSpace(5, 1);
936 S.Prop(true);
937 S.Position(wxEXPAND).AddWindow(mSplitter);
938 S.AddSpace(5, 1);
939
940 mSplitter->SetMinSize(wxSize(600, 400));
941 }
942 S.EndHorizontalLay();
943
944 S.AddSpace(1, 5);
945
946 return;
947 }
948
OnClose(wxCloseEvent & e)949 void NyqBench::OnClose(wxCloseEvent & e)
950 {
951 if (!Validate()) {
952 e.Veto();
953 }
954 else {
955 Show(false);
956 }
957 }
958
OnMove(wxMoveEvent & e)959 void NyqBench::OnMove(wxMoveEvent & e)
960 {
961 e.Skip();
962 if (!IsIconized() && !IsMaximized()) {
963 mLastSize.SetPosition(e.GetPosition());
964 }
965 }
966
OnSize(wxSizeEvent & e)967 void NyqBench::OnSize(wxSizeEvent & e)
968 {
969 e.Skip();
970 if (!IsIconized() && !IsMaximized()) {
971 mLastSize.SetSize(e.GetSize());
972 }
973 }
974
OnCloseWindow(wxCommandEvent & e)975 void NyqBench::OnCloseWindow(wxCommandEvent & e)
976 {
977 Close();
978 }
979
OnNew(wxCommandEvent & e)980 void NyqBench::OnNew(wxCommandEvent & e)
981 {
982 if (!Validate()) {
983 return;
984 }
985
986 mPath.SetFullName(wxEmptyString);
987
988 while (mScript->CanUndo()) {
989 mScript->Undo();
990 }
991
992 mScript->Clear();
993 mScript->DiscardEdits();
994
995 SetWindowTitle();
996 }
997
OnOpen(wxCommandEvent & e)998 void NyqBench::OnOpen(wxCommandEvent & e)
999 {
1000 if (mScript->IsModified() && !Validate()) {
1001 return;
1002 }
1003
1004 wxFileDialog dlog(this,
1005 _("Load Nyquist script"),
1006 mPath.GetPath(),
1007 wxEmptyString,
1008 _("Nyquist scripts (*.ny)|*.ny|Lisp scripts (*.lsp)|*.lsp|All files|*"),
1009 wxFD_OPEN | wxRESIZE_BORDER);
1010
1011 if (dlog.ShowModal() != wxID_OK) {
1012 return;
1013 }
1014
1015 mPath = dlog.GetPath();
1016 gPrefs->Write(wxT("NyqBench/Path"), mPath.GetFullPath());
1017
1018 LoadFile();
1019
1020 SetWindowTitle();
1021 }
1022
OnSave(wxCommandEvent & e)1023 void NyqBench::OnSave(wxCommandEvent & e)
1024 {
1025 if (mScript->GetLastPosition() == 0) {
1026 return;
1027 }
1028
1029 if (mPath.GetFullPath().IsEmpty()) {
1030 OnSaveAs(e);
1031 return;
1032 }
1033
1034 if (!mScript->SaveFile(mPath.GetFullPath()))
1035 {
1036 AudacityMessageBox(XO("Script was not saved."),
1037 XO("Warning"),
1038 wxICON_EXCLAMATION,
1039 this);
1040 return;
1041 }
1042 }
1043
OnSaveAs(wxCommandEvent & e)1044 void NyqBench::OnSaveAs(wxCommandEvent & e)
1045 {
1046 if (mScript->GetLastPosition() == 0) {
1047 return;
1048 }
1049
1050 wxFileDialog dlog(this,
1051 _("Save Nyquist script"),
1052 mPath.GetFullPath(),
1053 wxEmptyString,
1054 _("Nyquist scripts (*.ny)|*.ny|Lisp scripts (*.lsp)|*.lsp|All files|*"),
1055 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER);
1056
1057 if (dlog.ShowModal() != wxID_OK) {
1058 return;
1059 }
1060
1061 mPath = dlog.GetPath();
1062 gPrefs->Write(wxT("NyqBench/Path"), mPath.GetFullPath());
1063
1064 if (!mScript->SaveFile(mPath.GetFullPath()))
1065 {
1066 AudacityMessageBox(XO("Script was not saved."),
1067 XO("Warning"),
1068 wxICON_EXCLAMATION,
1069 this);
1070 return;
1071 }
1072
1073 SetWindowTitle();
1074 }
1075
OnAutoLoad(wxCommandEvent & e)1076 void NyqBench::OnAutoLoad(wxCommandEvent & e)
1077 {
1078 mAutoLoad = e.IsChecked();
1079 }
1080
OnRevert(wxCommandEvent & e)1081 void NyqBench::OnRevert(wxCommandEvent & e)
1082 {
1083 if (mPath.GetFullPath().IsEmpty()) {
1084 return;
1085 }
1086
1087 if (!Validate()) {
1088 return;
1089 }
1090
1091 LoadFile();
1092 }
1093
OnUndo(wxCommandEvent & e)1094 void NyqBench::OnUndo(wxCommandEvent & e)
1095 {
1096 (FindFocus() == mScript ? mScript : mOutput)->Undo();
1097 }
1098
OnRedo(wxCommandEvent & e)1099 void NyqBench::OnRedo(wxCommandEvent & e)
1100 {
1101 (FindFocus() == mScript ? mScript : mOutput)->Redo();
1102 }
1103
OnCut(wxCommandEvent & e)1104 void NyqBench::OnCut(wxCommandEvent & e)
1105 {
1106 (FindFocus() == mScript ? mScript : mOutput)->Cut();
1107 }
1108
OnCopy(wxCommandEvent & e)1109 void NyqBench::OnCopy(wxCommandEvent & e)
1110 {
1111 (FindFocus() == mScript ? mScript : mOutput)->Copy();
1112 }
1113
OnPaste(wxCommandEvent & e)1114 void NyqBench::OnPaste(wxCommandEvent & e)
1115 {
1116 (FindFocus() == mScript ? mScript : mOutput)->Paste();
1117 }
1118
OnClear(wxCommandEvent & e)1119 void NyqBench::OnClear(wxCommandEvent & e)
1120 {
1121 (FindFocus() == mScript ? mScript : mOutput)->Clear();
1122 }
1123
OnSelectAll(wxCommandEvent & e)1124 void NyqBench::OnSelectAll(wxCommandEvent & e)
1125 {
1126 (FindFocus() == mScript ? mScript : mOutput)->SetSelection(-1, -1);
1127 }
1128
OnFind(wxCommandEvent & e)1129 void NyqBench::OnFind(wxCommandEvent & e)
1130 {
1131 if (mFindDlg ) {
1132 delete mFindDlg;
1133 mFindDlg = NULL;
1134 }
1135 else {
1136 NyqTextCtrl *w = (NyqTextCtrl *) FindFocus();
1137 if (w == mScript || w == mOutput) {
1138 mFindText = w;
1139
1140 int flags = 0;
1141
1142 flags |= (gPrefs->Read(wxT("NyqBench/Find/Down"), 0L) ? wxFR_DOWN : 0);
1143 flags |= (gPrefs->Read(wxT("NyqBench/Find/Word"), 0L) ? wxFR_WHOLEWORD : 0);
1144 flags |= (gPrefs->Read(wxT("NyqBench/Find/Case"), 0L) ? wxFR_MATCHCASE : 0);
1145
1146 mFindData.SetFlags(flags);
1147
1148 mFindDlg = new wxFindReplaceDialog(this,
1149 &mFindData,
1150 _("Find dialog"),
1151 wxFR_NOWHOLEWORD);
1152 mFindDlg->Show(true);
1153 }
1154 }
1155 }
1156
OnGoMatch(wxCommandEvent & e)1157 void NyqBench::OnGoMatch(wxCommandEvent & e)
1158 {
1159 mScript->GoMatch();
1160 }
1161
OnGoTop(wxCommandEvent & e)1162 void NyqBench::OnGoTop(wxCommandEvent & e)
1163 {
1164 mScript->GoTop();
1165 }
1166
OnGoUp(wxCommandEvent & e)1167 void NyqBench::OnGoUp(wxCommandEvent & e)
1168 {
1169 mScript->GoUp();
1170 }
1171
OnGoPrev(wxCommandEvent & e)1172 void NyqBench::OnGoPrev(wxCommandEvent & e)
1173 {
1174 mScript->GoPrev();
1175 }
1176
OnGoNext(wxCommandEvent & e)1177 void NyqBench::OnGoNext(wxCommandEvent & e)
1178 {
1179 mScript->GoNext();
1180 }
1181
OnAutoWrap(wxCommandEvent & e)1182 void NyqBench::OnAutoWrap(wxCommandEvent & e)
1183 {
1184 mAutoWrap = e.IsChecked();
1185
1186 wxWindow *parent = mScript->GetParent();
1187 wxString text = mScript->GetValue();
1188 bool focused = wxWindow::FindFocus() == mScript;
1189 long pos = mScript->GetInsertionPoint();
1190 long from;
1191 long to;
1192 mScript->GetSelection(&from, &to);
1193
1194 wxSizer *s = mScript->GetContainingSizer();
1195 s->Detach(mScript);
1196 delete mScript;
1197
1198 mScript = new NyqTextCtrl(parent,
1199 ID_SCRIPT,
1200 wxEmptyString,
1201 wxDefaultPosition,
1202 wxDefaultSize,
1203 (mAutoWrap ? wxTE_BESTWRAP : wxTE_DONTWRAP) |
1204 wxTE_NOHIDESEL | wxTE_RICH2 |
1205 wxTE_MULTILINE);
1206 s->Add(mScript, 1, wxEXPAND);
1207 s->Layout();
1208
1209 mScript->ChangeValue(text);
1210 mScript->SetInsertionPoint(pos);
1211 mScript->SetSelection(from, to);
1212
1213 if (focused) {
1214 mScript->SetFocus();
1215 }
1216 }
1217
OnFont(wxCommandEvent & e)1218 void NyqBench::OnFont(wxCommandEvent & e)
1219 {
1220 wxWindow *w = FindFocus();
1221 wxFontData data;
1222 wxFontDialog dlg(this, data);
1223
1224 if (w != mScript && w != mOutput) {
1225 return;
1226 }
1227
1228 data.SetInitialFont(w == mScript ? mScriptFont : mOutputFont);
1229
1230 if (dlg.ShowModal() == wxID_OK) {
1231 wxFontData retData = dlg.GetFontData();
1232 wxFont font = retData.GetChosenFont();
1233 wxTextAttr attr;
1234 attr.SetFont(font);
1235
1236 if (w == mScript) {
1237 mScriptFont = font;
1238 }
1239 else {
1240 mOutputFont = font;
1241 }
1242
1243 ((wxTextCtrl *)w)->SetDefaultStyle(attr);
1244 ((wxTextCtrl *)w)->SetStyle(0, ((wxTextCtrl *)w)->GetLastPosition(), attr);
1245 w->Refresh();
1246 }
1247 }
1248
OnSplitV(wxCommandEvent & e)1249 void NyqBench::OnSplitV(wxCommandEvent & e)
1250 {
1251 if (mSplitter->IsSplit()) {
1252 mSplitter->Unsplit();
1253 }
1254
1255 mSplitter->SplitVertically(mScript->GetParent(), mOutput->GetParent());
1256 }
1257
OnSplitH(wxCommandEvent & e)1258 void NyqBench::OnSplitH(wxCommandEvent & e)
1259 {
1260 if (mSplitter->IsSplit()) {
1261 mSplitter->Unsplit();
1262 }
1263
1264 mSplitter->SplitHorizontally(mScript->GetParent(), mOutput->GetParent());
1265 }
1266
OnToggleCode(wxCommandEvent & e)1267 void NyqBench::OnToggleCode(wxCommandEvent & e)
1268 {
1269 if (e.IsChecked()) {
1270 if (mSplitter->IsSplit()) {
1271 // Should never happen
1272 return;
1273 }
1274
1275 if (mSplitMode == wxSPLIT_VERTICAL) {
1276 mSplitter->SplitVertically(mScript->GetParent(), mOutput->GetParent());
1277 }
1278 else {
1279 mSplitter->SplitHorizontally(mScript->GetParent(), mOutput->GetParent());
1280 }
1281 }
1282 else {
1283 if (!mSplitter->IsSplit()) {
1284 // Should never happen
1285 return;
1286 }
1287
1288 mSplitMode = mSplitter->GetSplitMode();
1289 mSplitter->Unsplit(mScript->GetParent());
1290 }
1291 }
1292
OnToggleOutput(wxCommandEvent & e)1293 void NyqBench::OnToggleOutput(wxCommandEvent & e)
1294 {
1295 if (e.IsChecked()) {
1296 if (mSplitter->IsSplit()) {
1297 // Should never happen
1298 return;
1299 }
1300
1301 if (mSplitMode == wxSPLIT_VERTICAL) {
1302 mSplitter->SplitVertically(mScript->GetParent(), mOutput->GetParent());
1303 }
1304 else {
1305 mSplitter->SplitHorizontally(mScript->GetParent(), mOutput->GetParent());
1306 }
1307 }
1308 else {
1309 if (!mSplitter->IsSplit()) {
1310 // Should never happen
1311 return;
1312 }
1313
1314 mSplitMode = mSplitter->GetSplitMode();
1315 mSplitter->Unsplit(mOutput->GetParent());
1316 }
1317 }
1318
OnSmallIcons(wxCommandEvent & e)1319 void NyqBench::OnSmallIcons(wxCommandEvent & e)
1320 {
1321 RecreateToolbar(false);
1322 }
1323
OnLargeIcons(wxCommandEvent & e)1324 void NyqBench::OnLargeIcons(wxCommandEvent & e)
1325 {
1326 RecreateToolbar(true);
1327 }
1328
OnGo(wxCommandEvent & e)1329 void NyqBench::OnGo(wxCommandEvent & e)
1330 {
1331 auto pEffect =
1332 std::make_unique<NyquistEffect>(L"Nyquist Effect Workbench");
1333 mEffect = pEffect.get();
1334 const PluginID & ID =
1335 EffectManager::Get().RegisterEffect(std::move(pEffect));
1336
1337 mEffect->SetCommand(mScript->GetValue());
1338 mEffect->RedirectOutput();
1339
1340 auto p = GetActiveProject().lock();
1341 wxASSERT(p);
1342
1343 if (p) {
1344 wxWindowDisabler disable(this);
1345 NyqRedirector redir((NyqTextCtrl *)mOutput);
1346
1347 mRunning = true;
1348 UpdateWindowUI();
1349
1350 EffectUI::DoEffect(ID, CommandContext(*p), 0);
1351
1352 mRunning = false;
1353 UpdateWindowUI();
1354 }
1355
1356 Raise();
1357
1358 EffectManager::Get().UnregisterEffect(ID);
1359 }
1360
OnStop(wxCommandEvent & e)1361 void NyqBench::OnStop(wxCommandEvent & e)
1362 {
1363 mRunning = false;
1364 mEffect->Stop();
1365 }
1366
OnAbout(wxCommandEvent & e)1367 void NyqBench::OnAbout(wxCommandEvent & e)
1368 {
1369 wxAboutDialogInfo i;
1370
1371 i.AddArtist(_("Harvey Lubin (logo)"));
1372 i.AddArtist(_("Tango Icon Gallery (toolbar icons)"));
1373 i.AddDeveloper(_("Leland Lucius"));
1374 i.SetCopyright(_("(C) 2009 by Leland Lucius"));
1375 i.SetDescription(_("External Audacity module which provides a simple IDE for writing effects."));
1376 i.SetName(_("Nyquist Effect Workbench"));
1377 i.SetVersion(__TDATE__);
1378
1379 wxAboutBox(i);
1380 }
1381
OnFindDialog(wxFindDialogEvent & e)1382 void NyqBench::OnFindDialog(wxFindDialogEvent & e)
1383 {
1384 wxEventType type = e.GetEventType();
1385
1386 if (type == wxEVT_COMMAND_FIND_CLOSE) {
1387 wxFindReplaceDialog *dlg = e.GetDialog();
1388
1389 dlg->Destroy();
1390
1391 int flags = mFindData.GetFlags();
1392
1393 gPrefs->Write(wxT("NyqBench/Find/Down"), (flags & wxFR_DOWN) != 0);
1394 gPrefs->Write(wxT("NyqBench/Find/Word"), (flags & wxFR_WHOLEWORD) != 0);
1395 gPrefs->Write(wxT("NyqBench/Find/Case"), (flags & wxFR_MATCHCASE) != 0);
1396
1397 mFindDlg = NULL;
1398 mFindText = NULL;
1399
1400 return;
1401 }
1402
1403 wxString text = mFindText->GetValue();
1404
1405 #if defined(__WXMSW__)
1406 // We cheat on Windows. We know that the Windows text control
1407 // uses CRLF for line endings and if we don't account for that,
1408 // the selection positions will be off.
1409 //
1410 // Not sure why I thought I needed this, but it appears not to
1411 // be. Leaving just in case.
1412 //
1413 // text.Replace(wxT("\n"), wxT("\r\n"));
1414 #endif
1415
1416 size_t startpos = mFindText->GetInsertionPoint();
1417 size_t len = mFindText->GetLastPosition();
1418 size_t pos;
1419
1420 wxString find = e.GetFindString();
1421 bool down = (e.GetFlags() & wxFR_DOWN) != 0;
1422 bool mixed = (e.GetFlags() & wxFR_MATCHCASE) != 0;
1423
1424 if (!mixed) {
1425 text.MakeUpper();
1426 find.MakeUpper();
1427 }
1428
1429 if (down) {
1430 pos = text.find(find, startpos);
1431 if (type == wxEVT_COMMAND_FIND_NEXT && pos == startpos && pos < len) {
1432 pos = text.find(find, startpos + 1);
1433 }
1434 }
1435 else {
1436 pos = text.rfind(find, startpos);
1437 if (type == wxEVT_COMMAND_FIND_NEXT && pos == startpos && pos > 0) {
1438 pos = text.rfind(find, startpos - 1);
1439 }
1440 }
1441
1442 if (pos == wxString::npos) {
1443 AudacityMessageBox(XO("No matches found"),
1444 XO("Nyquist Effect Workbench"),
1445 wxOK | wxCENTER,
1446 e.GetDialog());
1447
1448 return;
1449 }
1450
1451 mFindText->SetInsertionPoint((long)pos);
1452
1453 #if defined(__WXGTK__)
1454 // GTK's selection and intertion pointer interact where the insertion
1455 // pointer winds up after the second parameter, so we reverse them to
1456 // force the pointer at the beginning of the selection. Doing so
1457 // allows reverse find to work properly.
1458 mFindText->SetSelection((long)(pos + find.Length()), (long)pos);
1459 #else
1460 mFindText->SetSelection((long)pos, (long)(pos + find.Length()));
1461 #endif
1462
1463 #if defined(__WXMAC__)
1464 // Doing this coaxes the text control to update the selection. Without
1465 // it the selection doesn't appear to change if the found string is within
1466 // the currently displayed text, i.e., no reposition is needed.
1467 mFindText->Show(false);
1468 mFindText->Show(true);
1469 #endif
1470 }
1471
OnTextUpdate(wxCommandEvent & e)1472 void NyqBench::OnTextUpdate(wxCommandEvent & e)
1473 {
1474 // This really shouldn't be necessary, but Paste()ing doesn't mark the
1475 // control as dirty...at least on the Mac.
1476 ((NyqTextCtrl *) e.GetEventObject())->MarkDirty();
1477 }
1478
OnMenuUpdate(wxUpdateUIEvent & e)1479 void NyqBench::OnMenuUpdate(wxUpdateUIEvent & e)
1480 {
1481 if (e.GetId() != wxID_REVERT_TO_SAVED) {
1482 e.Enable((mScript->GetLastPosition() > 0) || mScript->IsModified());
1483 }
1484 else {
1485 e.Enable(mScript->IsModified());
1486 }
1487 }
1488
OnUndoUpdate(wxUpdateUIEvent & e)1489 void NyqBench::OnUndoUpdate(wxUpdateUIEvent & e)
1490 {
1491 e.Enable((FindFocus() == mScript ? mScript : mOutput)->CanUndo());
1492 }
1493
OnRedoUpdate(wxUpdateUIEvent & e)1494 void NyqBench::OnRedoUpdate(wxUpdateUIEvent & e)
1495 {
1496 e.Enable((FindFocus() == mScript ? mScript : mOutput)->CanRedo());
1497 }
1498
OnCutUpdate(wxUpdateUIEvent & e)1499 void NyqBench::OnCutUpdate(wxUpdateUIEvent & e)
1500 {
1501 e.Enable((FindFocus() == mScript ? mScript : mOutput)->CanCut());
1502 }
1503
OnCopyUpdate(wxUpdateUIEvent & e)1504 void NyqBench::OnCopyUpdate(wxUpdateUIEvent & e)
1505 {
1506 e.Enable((FindFocus() == mScript ? mScript : mOutput)->CanCopy());
1507 }
1508
OnPasteUpdate(wxUpdateUIEvent & e)1509 void NyqBench::OnPasteUpdate(wxUpdateUIEvent & e)
1510 {
1511 e.Enable((FindFocus() == mScript ? mScript : mOutput)->CanPaste());
1512 }
1513
OnClearUpdate(wxUpdateUIEvent & e)1514 void NyqBench::OnClearUpdate(wxUpdateUIEvent & e)
1515 {
1516 e.Enable(FindFocus() == mOutput ? true : false);
1517 }
1518
OnViewUpdate(wxUpdateUIEvent & e)1519 void NyqBench::OnViewUpdate(wxUpdateUIEvent & e)
1520 {
1521 wxMenuBar *bar = GetMenuBar();
1522 bar->Enable(ID_SPLITV, !mSplitter->IsSplit() || mSplitter->GetSplitMode() != wxSPLIT_VERTICAL);
1523 bar->Enable(ID_SPLITH, !mSplitter->IsSplit() || mSplitter->GetSplitMode() != wxSPLIT_HORIZONTAL);
1524 bar->Check(ID_TOGGLECODE, mScript->GetParent()->IsShown());
1525 bar->Check(ID_TOGGLEOUTPUT, mOutput->GetParent()->IsShown());
1526 bar->Check(ID_LARGEICONS, mLargeIcons);
1527 bar->Check(ID_SMALLICONS, !mLargeIcons);
1528 }
1529
OnRunUpdate(wxUpdateUIEvent & e)1530 void NyqBench::OnRunUpdate(wxUpdateUIEvent & e)
1531 {
1532 auto p = GetActiveProject().lock();
1533 wxToolBar *tbar = GetToolBar();
1534 wxMenuBar *mbar = GetMenuBar();
1535
1536 auto gAudioIO = AudioIOBase::Get();
1537 if (p && gAudioIO->IsBusy()) {
1538 mbar->Enable(ID_GO, false);
1539 mbar->Enable(ID_STOP, false);
1540
1541 tbar->EnableTool(ID_GO, false);
1542 tbar->EnableTool(ID_STOP, false);
1543 }
1544 else {
1545 mbar->Enable(ID_GO, (mScript->GetLastPosition() > 0) && !mRunning);
1546 mbar->Enable(ID_STOP, (mScript->GetLastPosition() > 0) && mRunning);
1547
1548 tbar->EnableTool(ID_GO, (mScript->GetLastPosition() > 0) && !mRunning);
1549 tbar->EnableTool(ID_STOP, (mScript->GetLastPosition() > 0) && mRunning);
1550 }
1551 }
1552
OnScriptUpdate(wxUpdateUIEvent & e)1553 void NyqBench::OnScriptUpdate(wxUpdateUIEvent & e)
1554 {
1555 if (mScriptBox && mScript && FindFocus() == mScript) {
1556 wxString label = mScriptBox->GetLabel();
1557 if (label == _("Script")) {
1558 label += wxT("*");
1559 mScriptBox->SetLabel(label);
1560 mOutputBox->SetLabel(_("Output"));
1561 }
1562 }
1563 }
1564
OnOutputUpdate(wxUpdateUIEvent & e)1565 void NyqBench::OnOutputUpdate(wxUpdateUIEvent & e)
1566 {
1567 if (mOutputBox && mOutput && FindFocus() == mOutput) {
1568 wxString label = mOutputBox->GetLabel();
1569 if (label == _("Output")) {
1570 label += wxT("*");
1571 mOutputBox->SetLabel(label);
1572 mScriptBox->SetLabel(_("Script"));
1573 }
1574 }
1575 }
1576
Validate()1577 bool NyqBench::Validate()
1578 {
1579 if (mScript->GetLastPosition() > 0 && mScript->IsModified()) {
1580 int ans;
1581 ans = AudacityMessageBox(XO("Code has been modified. Are you sure?"),
1582 XO("Warning"),
1583 wxYES_NO | wxICON_QUESTION,
1584 this);
1585 if (ans == wxNO) {
1586 return false;
1587 }
1588 }
1589
1590 return true;
1591 }
1592
SetWindowTitle()1593 void NyqBench::SetWindowTitle()
1594 {
1595 wxString name = _("Untitled");
1596
1597 if (!mPath.GetFullPath().IsEmpty()) {
1598 name = mPath.GetFullName();
1599 }
1600
1601 SetTitle(_("Nyquist Effect Workbench - ") + name);
1602 }
1603
RecreateToolbar(bool large)1604 void NyqBench::RecreateToolbar(bool large)
1605 {
1606 mLargeIcons = large;
1607
1608 wxToolBar *tb = GetToolBar();
1609 if (tb) {
1610 delete tb;
1611 }
1612 tb = CreateToolBar();
1613
1614 wxSize sz;
1615
1616 if (!mLargeIcons) {
1617 tb->SetToolBitmapSize(wxSize(16, 16));
1618 mPics[0] = wxBitmap(document_new_small);
1619 mPics[1] = wxBitmap(document_open_small);
1620 mPics[2] = wxBitmap(document_save_as_small);
1621 mPics[3] = wxBitmap(document_save_small);
1622 mPics[4] = wxBitmap(edit_copy_small);
1623 mPics[5] = wxBitmap(edit_cut_small);
1624 mPics[6] = wxBitmap(edit_paste_small);
1625 mPics[7] = wxBitmap(edit_clear_small);
1626 mPics[8] = wxBitmap(edit_delete_small);
1627 mPics[9] = wxBitmap(edit_select_all_small);
1628 mPics[10] = wxBitmap(edit_undo_small);
1629 mPics[11] = wxBitmap(edit_redo_small);
1630 mPics[12] = wxBitmap(edit_find_small);
1631 mPics[13] = wxBitmap(system_search_small);
1632 mPics[14] = wxBitmap(go_top_small);
1633 mPics[15] = wxBitmap(go_up_small);
1634 mPics[16] = wxBitmap(go_previous_small);
1635 mPics[17] = wxBitmap(go_next_small);
1636 mPics[18] = wxBitmap(media_playback_start_small);
1637 mPics[19] = wxBitmap(media_playback_stop_small);
1638 }
1639 else {
1640 tb->SetToolBitmapSize(wxSize(32, 32));
1641 mPics[0] = wxBitmap(document_new_large);
1642 mPics[1] = wxBitmap(document_open_large);
1643 mPics[2] = wxBitmap(document_save_as_large);
1644 mPics[3] = wxBitmap(document_save_large);
1645 mPics[4] = wxBitmap(edit_copy_large);
1646 mPics[5] = wxBitmap(edit_cut_large);
1647 mPics[6] = wxBitmap(edit_paste_large);
1648 mPics[7] = wxBitmap(edit_clear_large);
1649 mPics[8] = wxBitmap(edit_delete_large);
1650 mPics[9] = wxBitmap(edit_select_all_large);
1651 mPics[10] = wxBitmap(edit_undo_large);
1652 mPics[11] = wxBitmap(edit_redo_large);
1653 mPics[12] = wxBitmap(edit_find_large);
1654 mPics[13] = wxBitmap(system_search_large);
1655 mPics[14] = wxBitmap(go_top_large);
1656 mPics[15] = wxBitmap(go_up_large);
1657 mPics[16] = wxBitmap(go_previous_large);
1658 mPics[17] = wxBitmap(go_next_large);
1659 mPics[18] = wxBitmap(media_playback_start_large);
1660 mPics[19] = wxBitmap(media_playback_stop_large);
1661 }
1662
1663 tb->SetMargins(2, 2);
1664
1665 tb->AddTool(wxID_NEW, _("New"), mPics[0], _("New script"));
1666 tb->AddTool(wxID_OPEN, _("Open"), mPics[1], _("Open script"));
1667 tb->AddTool(wxID_SAVE, _("Save"), mPics[2], _("Save script"));
1668 tb->AddTool(wxID_SAVEAS, _("Save As"), mPics[3], _("Save script as..."));
1669 tb->AddSeparator();
1670 tb->AddTool(wxID_COPY, _("Copy"), mPics[4], _("Copy to clipboard"));
1671 tb->AddTool(wxID_CUT, _("Cut"), mPics[5], _("Cut to clipboard"));
1672 tb->AddTool(wxID_PASTE, _("Paste"), mPics[6], _("Paste from clipboard"));
1673 tb->AddTool(wxID_CLEAR, _("Clear"), mPics[7], _("Clear selection"));
1674 tb->AddTool(wxID_SELECTALL, _("Select All"), mPics[9], _("Select all text"));
1675 tb->AddSeparator();
1676 tb->AddTool(wxID_UNDO, _("Undo"), mPics[10], _("Undo last change"));
1677 tb->AddTool(wxID_REDO, _("Redo"), mPics[11], _("Redo previous change"));
1678 tb->AddSeparator();
1679 tb->AddTool(wxID_FIND, _("Find"), mPics[12], _("Find text"));
1680 tb->AddSeparator();
1681 tb->AddTool(ID_MATCH, _("Match"), mPics[13], _("Go to matching paren"));
1682 tb->AddTool(ID_TOP, _("Top"), mPics[14], _("Go to top S-expr"));
1683 tb->AddTool(ID_UP, _("Up"), mPics[15], _("Go to higher S-expr"));
1684 tb->AddTool(ID_PREVIOUS, _("Previous"), mPics[16], _("Go to previous S-expr"));
1685 tb->AddTool(ID_NEXT, _("Next"), mPics[17], _("Go to next S-expr"));
1686 tb->AddSeparator();
1687 tb->AddTool(ID_GO, _("Start"), mPics[18], _("Start script"));
1688 tb->AddTool(ID_STOP, _("Stop"), mPics[19], _("Stop script"));
1689
1690 tb->Realize();
1691
1692 Layout();
1693 Fit();
1694 SetMinSize(GetSize());
1695 }
1696
LoadFile()1697 void NyqBench::LoadFile()
1698 {
1699 wxString path = mPath.GetFullPath();
1700
1701 if (path.IsEmpty()) {
1702 return;
1703 }
1704
1705 wxFFile f(path);
1706 if (f.IsOpened()) {
1707 wxString t;
1708 if (f.ReadAll(&t)) {
1709 //#if defined(__WXGTK__) || defined(__WXMAC__)
1710 t.Replace(wxT("\r\n"), wxT("\n"));
1711 t.Replace(wxT("\r"), wxT("\n"));
1712 //#elif defined(__WXMSW__)
1713 // t.Replace("\r\n", "\n");
1714 //#endif
1715 mScript->SetValue(t);
1716 mScript->DiscardEdits();
1717 }
1718 }
1719
1720 // mScript->LoadFile(mPath.GetFullPath());
1721 }
1722
1723 //----------------------------------------------------------------------------
1724 // Connects Audacity menu item to an action in this dll.
1725 // Only one action implemented so far.
1726 //----------------------------------------------------------------------------
ShowNyqBench(const CommandContext &)1727 void NyqBench::ShowNyqBench(const CommandContext &)
1728 {
1729 Show();
1730 }
1731