1 /*
2 * tracker/Tracker.cpp
3 *
4 * Copyright 2009 Peter Barth
5 *
6 * This file is part of Milkytracker.
7 *
8 * Milkytracker is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Milkytracker is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Milkytracker. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include "Tracker.h"
24 #include "TrackerConfig.h"
25 #include "TabManager.h"
26 #include "PlayerController.h"
27 #include "PlayerMaster.h"
28 #include "PlayerLogic.h"
29 #include "RecorderLogic.h"
30 #include "SamplePlayer.h"
31 #include "SimpleVector.h"
32 #include "ModuleEditor.h"
33 #include "TabTitleProvider.h"
34 #include "PPUI.h"
35 #include "PatternTools.h"
36 #include "PatternEditorControl.h"
37 #include "EnvelopeEditorControl.h"
38 #include "PianoControl.h"
39 #include "PeakLevelControl.h"
40 #include "ScopesControl.h"
41 #include "TabHeaderControl.h"
42 #include "SampleEditorControl.h"
43 #include "TrackerSettingsDatabase.h"
44 #include "KeyBindings.h"
45 #include "ModuleServices.h"
46 #include "FileIdentificator.h"
47 #include "FileExtProvider.h"
48 #include "Decompressor.h"
49 #include "Zapper.h"
50 #include "TitlePageManager.h"
51
52 // Sections
53 #include "SectionSwitcher.h"
54 #include "SectionTranspose.h"
55 #include "SectionAdvancedEdit.h"
56 #include "SectionDiskMenu.h"
57 #include "SectionHDRecorder.h"
58 #include "SectionSettings.h"
59 #include "SectionInstruments.h"
60 #include "SectionSamples.h"
61 #include "SectionQuickOptions.h"
62 #include "SectionOptimize.h"
63 #include "SectionAbout.h"
64
65 #include "InputControlListener.h"
66
67 // Some helper messageboxes & button handlers
68 #include "DialogHandlers.h"
69 #include "DialogChannelSelector.h"
70 #include "DialogZap.h"
71 // Helper class to invoke tools which need parameters
72 #include "ToolInvokeHelper.h"
73
74 #include "ControlIDs.h"
75
76 // OS Interface
77 #include "PPOpenPanel.h"
78 #include "PPSavePanel.h"
79
myMod(pp_int32 a,pp_int32 b)80 static inline pp_int32 myMod(pp_int32 a, pp_int32 b)
81 {
82 pp_int32 res = a%b;
83 if (res<0) res+=b;
84 return res;
85 }
86
87 #ifndef __LOWRES__
SCOPESHEIGHT()88 pp_int32 Tracker::SCOPESHEIGHT()
89 {
90 return (48*screen->getHeight()) / 480;
91 }
92
CURRENTSCOPESHEIGHT()93 pp_int32 Tracker::CURRENTSCOPESHEIGHT()
94 {
95 if (!scopesControl)
96 return 0;
97
98 if (scopesControl->isVisible())
99 return SCOPESHEIGHT();
100
101 return 0;
102 }
103
SAMPLESECTIONDEFAULTHEIGHT()104 pp_int32 Tracker::SAMPLESECTIONDEFAULTHEIGHT()
105 {
106 return screen->getHeight() < 480 ? 180 : 240;
107 }
108
109 #endif
110
MAXEDITORHEIGHT()111 pp_int32 Tracker::MAXEDITORHEIGHT()
112 {
113 #ifndef __LOWRES__
114 TabHeaderControl* tabControl = static_cast<TabHeaderControl*>(screen->getControlByID(TABHEADER_CONTROL));
115 if (tabControl != NULL)
116 {
117 return tabControl->getNumTabs() > 1 ? screen->getHeight() - TABHEADERHEIGHT() : screen->getHeight();
118 }
119 #endif
120 return screen->getHeight();
121 }
122
Tracker()123 Tracker::Tracker() :
124 screen(NULL),
125 peakLevelControl(NULL),
126 scopesControl(NULL),
127 messageBoxContainerGeneric(NULL),
128 dialog(NULL),
129 responder(NULL),
130 playTimeText(NULL),
131 instrumentChooser(NULL),
132 inputContainerCurrent(NULL),
133 inputContainerDefault(NULL),
134 inputContainerExtended(NULL),
135 settingsDatabaseCopy(NULL),
136 eventKeyDownBindings(NULL),
137 eventKeyDownBindingsMilkyTracker(NULL),
138 eventKeyDownBindingsFastTracker(NULL),
139 currentFileName(TrackerConfig::untitledSong),
140 lastState(false),
141 editMode(EditModeFastTracker),
142 extendedOrderlist(false),
143 followSong(true),
144 caughtMouseInUpperLeftCorner(false),
145 useClassicBrowser(false),
146 savePanel(NULL),
147 fileSystemChangedListener(NULL)
148 {
149 resetStateMemories();
150
151 settingsDatabase = new TrackerSettingsDatabase();
152
153 buildDefaultSettings();
154
155 tabManager = new TabManager(*this);
156
157 playerMaster = new PlayerMaster(TrackerConfig::numTabs);
158 playerController = tabManager->createPlayerController();
159
160 moduleEditor = tabManager->createModuleEditor();
161
162 playerLogic = new PlayerLogic(*this);
163 recorderLogic = new RecorderLogic(*this);
164
165 // Sections
166 sectionSwitcher = new SectionSwitcher(*this);
167
168 sections = new PPSimpleVector<SectionAbstract>();
169
170 sectionTranspose = new SectionTranspose(*this);
171 sections->add(sectionTranspose);
172 sectionAdvancedEdit = new SectionAdvancedEdit(*this);
173 sections->add(sectionAdvancedEdit);
174 sectionDiskMenu = new SectionDiskMenu(*this);
175 sections->add(sectionDiskMenu);
176 sectionHDRecorder = new SectionHDRecorder(*this);
177 sections->add(sectionHDRecorder);
178 sectionSettings = new SectionSettings(*this);
179 sections->add(sectionSettings);
180 sectionInstruments = new SectionInstruments(*this);
181 sections->add(sectionInstruments);
182 sectionSamples = new SectionSamples(*this);
183 sections->add(sectionSamples);
184 sectionQuickOptions = new SectionQuickOptions(*this);
185 sections->add(sectionQuickOptions);
186 sectionOptimize = new SectionOptimize(*this);
187 sections->add(sectionOptimize);
188 sectionAbout = new SectionAbout(*this);
189 sections->add(sectionAbout);
190
191 inputControlListener = new InputControlListener(*this);
192
193 toolInvokeHelper = new ToolInvokeHelper(*this);
194
195 pp_int32 i;
196
197 muteChannels = new bool[TrackerConfig::maximumPlayerChannels];
198
199 for (i = 0; i < TrackerConfig::maximumPlayerChannels; i++)
200 muteChannels[i] = false;
201
202 initKeyBindings();
203 }
204
~Tracker()205 Tracker::~Tracker()
206 {
207 delete eventKeyDownBindingsMilkyTracker;
208 delete eventKeyDownBindingsFastTracker;
209
210 delete toolInvokeHelper;
211 delete responder;
212 delete dialog;
213 delete inputControlListener;
214
215 delete sections;
216 delete sectionSwitcher;
217
218 delete recorderLogic;
219 delete playerLogic;
220
221 delete playerMaster;
222
223 delete messageBoxContainerGeneric;
224
225 delete[] muteChannels;
226
227 delete instrumentChooser;
228
229 delete settingsDatabaseCopy;
230 delete settingsDatabase;
231 }
232
getPatternEditor()233 PatternEditor* Tracker::getPatternEditor()
234 {
235 return moduleEditor->getPatternEditor();
236 }
237
getSampleEditor()238 SampleEditor* Tracker::getSampleEditor()
239 {
240 return moduleEditor->getSampleEditor();
241 }
242
getEnvelopeEditor()243 EnvelopeEditor* Tracker::getEnvelopeEditor()
244 {
245 return moduleEditor->getEnvelopeEditor();
246 }
247
getOrderListBoxIndex()248 pp_int32 Tracker::getOrderListBoxIndex()
249 {
250 return listBoxOrderList->getSelectedIndex();
251 }
252
setOrderListIndex(pp_int32 index)253 void Tracker::setOrderListIndex(pp_int32 index)
254 {
255 // do not accept values which exceed the current number of orders
256 if (index >= moduleEditor->getNumOrders())
257 index = moduleEditor->getNumOrders()-1;
258
259 listBoxOrderList->setSelectedIndex(index);
260 updateOrderlist();
261 // fake selection from orderlist, so everything will be updated correctly
262 PPEvent e(eSelection, &index, sizeof(index));
263 handleEvent(reinterpret_cast<PPObject*>(listBoxOrderList), &e);
264 }
265
isEditingCurrentOrderlistPattern()266 bool Tracker::isEditingCurrentOrderlistPattern()
267 {
268 return moduleEditor->isEditingOrderPosition(getOrderListBoxIndex());
269 }
270
getInstrumentToPlay(pp_int32 note,PlayerController * & playerController)271 pp_int32 Tracker::getInstrumentToPlay(pp_int32 note, PlayerController*& playerController)
272 {
273 if (PPControl* ctrl = screen->getModalControl())
274 {
275 note--;
276
277 PPContainer* container = static_cast<PPContainer*>(ctrl);
278
279 PPListBox* listBoxSrc = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC));
280 PPListBox* listBoxSrcSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
281 PPListBox* listBoxSrcModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC3));
282 PPListBox* listBoxDst = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST));
283 PPListBox* listBoxDstSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
284 PPListBox* listBoxDstModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST3));
285
286 if (!listBoxSrc || !listBoxDst)
287 return -1;
288
289 PPListBox* focusedListBox = static_cast<PPListBox*>(container->getFocusedControl());
290 if (focusedListBox == NULL)
291 return getPatternEditorControl()->isInstrumentEnabled() ? listBoxInstruments->getSelectedIndex() + 1 : 0;
292
293 // not having any module selection boxes
294 if (listBoxSrc && listBoxDst &&
295 !listBoxSrcModule && !listBoxDstModule)
296 {
297 // return the selected index from the focused list box
298 if (focusedListBox == listBoxSrc ||
299 focusedListBox == listBoxDst)
300 return focusedListBox->getSelectedIndex() + 1;
301 }
302
303 // focus is on instruments
304 if (focusedListBox == listBoxSrc ||
305 focusedListBox == listBoxSrcModule)
306 {
307 playerController = tabManager->getPlayerControllerFromTabIndex(listBoxSrcModule->getSelectedIndex());
308 // return the selected index from the focused list box
309 return listBoxSrc->getSelectedIndex() + 1;
310 }
311 else if (focusedListBox == listBoxDst ||
312 focusedListBox == listBoxDstModule)
313 {
314 playerController = tabManager->getPlayerControllerFromTabIndex(listBoxDstModule->getSelectedIndex());
315 // return the selected index from the focused list box
316 return listBoxDst->getSelectedIndex() + 1;
317 }
318
319 // if focus is on one of the samples list boxes set up some sample playing
320 // on the sample playing channels of the current player
321 ModuleEditor* src = listBoxSrcModule ? tabManager->getModuleEditorFromTabIndex(listBoxSrcModule->getSelectedIndex()) : this->moduleEditor;
322 ModuleEditor* dst = listBoxDstModule ? tabManager->getModuleEditorFromTabIndex(listBoxDstModule->getSelectedIndex()) : this->moduleEditor;
323
324 if (focusedListBox == listBoxSrcSmp)
325 {
326 SamplePlayer samplePlayer(*src, *playerController);
327 if (focusedListBox == listBoxSrcSmp)
328 samplePlayer.playSample(listBoxSrc->getSelectedIndex(),
329 listBoxSrcSmp->getSelectedIndex(), note);
330 else
331 samplePlayer.playSample(listBoxSrc->getSelectedIndex(),
332 note);
333 return -1;
334 }
335
336 if (focusedListBox == listBoxDstSmp)
337 {
338 SamplePlayer samplePlayer(*dst, *playerController);
339 if (focusedListBox == listBoxDstSmp)
340 samplePlayer.playSample(listBoxDst->getSelectedIndex(),
341 listBoxDstSmp->getSelectedIndex(), note);
342 else
343 samplePlayer.playSample(listBoxDst->getSelectedIndex(),
344 note);
345 return -1;
346 }
347
348 return focusedListBox->getSelectedIndex() + 1;
349 }
350 else
351 {
352 return getPatternEditorControl()->isInstrumentEnabled() ? listBoxInstruments->getSelectedIndex() + 1 : 0;
353 }
354 }
355
setNumChannels(pp_int32 numChannels,bool repaint)356 void Tracker::setNumChannels(pp_int32 numChannels, bool repaint/* = true*/)
357 {
358 getPatternEditorControl()->setNumVisibleChannels(numChannels);
359 scopesControl->setNumChannels(numChannels);
360 updatePatternEditorControl(repaint, false);
361 }
362
showSongSettings(bool show)363 void Tracker::showSongSettings(bool show)
364 {
365 screen->getControlByID(CONTAINER_ABOUT)->show(show);
366 screen->getControlByID(CONTAINER_ORDERLIST)->show(show);
367 screen->getControlByID(CONTAINER_SPEED)->show(show);
368 screen->getControlByID(CONTAINER_PATTERN)->show(show);
369 }
370
showMainOptions(bool show)371 void Tracker::showMainOptions(bool show)
372 {
373 screen->getControlByID(CONTAINER_MENU)->show(show);
374 }
375
showMainMenu(bool show,bool showInstrumentSelector)376 void Tracker::showMainMenu(bool show, bool showInstrumentSelector)
377 {
378 #ifndef __LOWRES__
379 showSongSettings(show);
380 showMainOptions(show);
381 if (showInstrumentSelector)
382 screen->getControlByID(CONTAINER_INSTRUMENTLIST)->show(show);
383 #else
384 if (!show)
385 {
386 showSongSettings(false);
387 showMainOptions(false);
388 screen->getControlByID(CONTAINER_LOWRES_MENUSWITCH)->show(false);
389 screen->getControlByID(CONTAINER_INSTRUMENTLIST)->show(false);
390 screen->getControlByID(CONTAINER_LOWRES_TINYMENU)->show(false);
391 }
392 else
393 {
394 sectionSwitcher->showCurrentSubMenu(false);
395 screen->getControlByID(CONTAINER_LOWRES_MENUSWITCH)->show(true);
396 }
397 #endif
398 }
399
400 #ifdef __LOWRES__
selectScopesControl(pp_int32 ctrlType)401 void Tracker::selectScopesControl(pp_int32 ctrlType)
402 {
403 scopesControl->setCurrentClickType((ScopesControl::ClickTypes)ctrlType);
404
405 updateScopesControlButtons();
406
407 screen->paintControl(screen->getControlByID(CONTAINER_SCOPECONTROL));
408 }
409
updateScopesControlButtons()410 void Tracker::updateScopesControlButtons()
411 {
412 PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_SCOPECONTROL));
413
414 ASSERT(container);
415
416 if (!container->isVisible())
417 return;
418
419 if (!scopesControl)
420 return;
421
422 static_cast<PPButton*>(container->getControlByID(BUTTON_SCOPECONTROL_MUTE))->setPressed(false);
423 static_cast<PPButton*>(container->getControlByID(BUTTON_SCOPECONTROL_SOLO))->setPressed(false);
424 static_cast<PPButton*>(container->getControlByID(BUTTON_SCOPECONTROL_REC))->setPressed(false);
425
426 switch (scopesControl->getCurrentClickType())
427 {
428 case ScopesControl::ClickTypeMute:
429 static_cast<PPButton*>(container->getControlByID(BUTTON_SCOPECONTROL_MUTE))->setPressed(true);
430 break;
431 case ScopesControl::ClickTypeSolo:
432 static_cast<PPButton*>(container->getControlByID(BUTTON_SCOPECONTROL_SOLO))->setPressed(true);
433 break;
434 case ScopesControl::ClickTypeRec:
435 static_cast<PPButton*>(container->getControlByID(BUTTON_SCOPECONTROL_REC))->setPressed(true);
436 break;
437 }
438 }
439
toggleJamMenuPianoSize()440 void Tracker::toggleJamMenuPianoSize()
441 {
442 PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_LOWRES_JAMMENU));
443 ASSERT(container);
444
445 PianoControl* pCtrl = static_cast<PianoControl*>(container->getControlByID(PIANO_CONTROL));
446 ASSERT(pCtrl);
447
448 bool largePiano = (pCtrl->getxScale() == 6 && pCtrl->getyScale() == 3);
449
450 PPButton* button = static_cast<PPButton*>(container->getControlByID(BUTTON_JAMMENU_TOGGLEPIANOSIZE));
451 ASSERT(button);
452
453 button->setText(largePiano ? TrackerConfig::stringButtonCollapsed : TrackerConfig::stringButtonExtended);
454
455 if (largePiano)
456 {
457 container->setSize(PPSize(container->getSize().width, container->getSize().height - 25*2));
458 container->setLocation(PPPoint(container->getLocation().x, container->getLocation().y + 25*2));
459 pCtrl->setLocation(PPPoint(pCtrl->getLocation().x, pCtrl->getLocation().y + 25*2));
460 pCtrl->setxScale(3);
461 pCtrl->setyScale(1);
462 pCtrl->setSize(PPSize(screen->getWidth() - 4, 25*1+12));
463
464 getPatternEditorControl()->setSize(PPSize(getPatternEditorControl()->getSize().width, getPatternEditorControl()->getSize().height + 25*2));
465 }
466 else
467 {
468 container->setSize(PPSize(container->getSize().width, container->getSize().height + 25*2));
469 container->setLocation(PPPoint(container->getLocation().x, container->getLocation().y - 25*2));
470 pCtrl->setLocation(PPPoint(pCtrl->getLocation().x, pCtrl->getLocation().y - 25*2));
471 pCtrl->setxScale(6);
472 pCtrl->setyScale(3);
473 pCtrl->setSize(PPSize(screen->getWidth() - 4, 25*3+12));
474
475 getPatternEditorControl()->setSize(PPSize(getPatternEditorControl()->getSize().width, getPatternEditorControl()->getSize().height - 25*2));
476 }
477
478 screen->paint();
479 }
480
flipInstrumentListBoxes()481 void Tracker::flipInstrumentListBoxes()
482 {
483 PPContainer* ctrl = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_INSTRUMENTLIST));
484
485 PPListBox* listBoxIns = static_cast<PPListBox*>(ctrl->getControlByID(LISTBOX_INSTRUMENTS));
486 PPListBox* listBoxSmp = static_cast<PPListBox*>(ctrl->getControlByID(LISTBOX_SAMPLES));
487
488 bool b = listBoxIns->isHidden();
489
490 PPPoint insPos = listBoxIns->getLocation();
491 PPSize insSize = listBoxIns->getSize();
492
493 PPPoint smpPos = listBoxSmp->getLocation();
494 PPSize smpSize = listBoxSmp->getSize();
495
496 listBoxSmp->setLocation(insPos);
497 listBoxSmp->setSize(insSize);
498
499 listBoxIns->setLocation(smpPos);
500 listBoxIns->setSize(smpSize);
501
502 listBoxSmp->hide(b);
503 listBoxIns->hide(!b);
504
505 ctrl->getControlByID(STATICTEXT_INSTRUMENTS_ALTERNATIVEHEADER)->hide(b);
506 ctrl->getControlByID(STATICTEXT_INSTRUMENTS_ALTERNATIVEHEADER2)->hide(b);
507
508 ctrl->getControlByID(BUTTON_INSTRUMENT)->hide(!b);
509 ctrl->getControlByID(STATICTEXT_SAMPLEHEADER)->hide(!b);
510 ctrl->getControlByID(BUTTON_INSTRUMENTS_PLUS)->hide(!b);
511 ctrl->getControlByID(BUTTON_INSTRUMENTS_MINUS)->hide(!b);
512
513 screen->paintControl(ctrl);
514 }
515
516 #endif
517
setModuleNumChannels(pp_uint32 numChannels)518 void Tracker::setModuleNumChannels(pp_uint32 numChannels)
519 {
520 moduleEditor->setNumChannels(numChannels);
521 setNumChannels(numChannels);
522 }
523
handleEvent(PPObject * sender,PPEvent * event)524 pp_int32 Tracker::handleEvent(PPObject* sender, PPEvent* event)
525 {
526 char buffer[100];
527
528 if (event->getID() == eFileDragDropped)
529 {
530 if (screen->getModalControl())
531 return 0;
532 const PPSystemString* str = *(reinterpret_cast<PPSystemString* const*>(event->getDataPtr()));
533 loadGenericFileType(*str);
534 event->cancel();
535 }
536 else if (event->getID() == eUpdateChanged)
537 {
538 updateWindowTitle();
539 }
540 else if (event->getID() == eKeyDown ||
541 event->getID() == eKeyChar ||
542 event->getID() == eKeyUp)
543 {
544 processShortcuts(event);
545 }
546 else if (event->getID() == eTimer)
547 {
548 doFollowSong();
549 }
550 #ifndef __LOWRES__
551 else if (event->getID() == eLMouseDown)
552 {
553 PPPoint* p = (PPPoint*)event->getDataPtr();
554 caughtMouseInUpperLeftCorner = (p->x <= TrackerConfig::trackerExitBounds.x && p->y <= TrackerConfig::trackerExitBounds.y) ? true : false;
555 if (caughtMouseInUpperLeftCorner)
556 event->cancel();
557 }
558 else if (event->getID() == eLMouseUp)
559 {
560 PPPoint* p = (PPPoint*)event->getDataPtr();
561
562 if ((p->x <= TrackerConfig::trackerExitBounds.x && p->y <= TrackerConfig::trackerExitBounds.y) && caughtMouseInUpperLeftCorner)
563 {
564 event->cancel();
565 eventKeyDownBinding_ExitApplication();
566 }
567 else
568 caughtMouseInUpperLeftCorner = false;
569 }
570 #endif
571 else if (event->getID() == eCommand || event->getID() == eCommandRepeat)
572 {
573
574 switch (reinterpret_cast<PPControl*>(sender)->getID())
575 {
576 // test
577 /*case BUTTON_MENU_ITEM_0+8:
578 {
579 if (event->getID() != eCommand)
580 break;
581
582 eventKeyDownBinding_InvokeSectionHDRecorder();
583 break;
584 }*/
585
586 case BUTTON_INSTRUMENT:
587 {
588 if (event->getID() != eCommand)
589 break;
590
591 enableInstrument(!getPatternEditorControl()->isInstrumentEnabled());
592 break;
593 }
594
595 case STATICTEXT_ABOUT_HEADING:
596 {
597 if (event->getID() != eCommand)
598 break;
599
600 TitlePageManager titlePageManager(*screen);
601 titlePageManager.setPeakControlHeadingColor(PPUIConfig::getInstance()->getColor(PPUIConfig::ColorStaticText));
602 break;
603 }
604
605 case BUTTON_ABOUT_SHOWTITLE:
606 {
607 if (event->getID() != eCommand)
608 break;
609
610 TitlePageManager titlePageManager(*screen);
611 titlePageManager.showTitlePage(TitlePageManager::PageTitle);
612 break;
613 }
614
615 case BUTTON_ABOUT_SHOWTIME:
616 {
617 if (event->getID() != eCommand)
618 break;
619 TitlePageManager titlePageManager(*screen);
620 titlePageManager.showTitlePage(TitlePageManager::PageTime);
621 break;
622 }
623
624 case BUTTON_ABOUT_ESTIMATESONGLENGTH:
625 {
626 if (event->getID() != eCommand)
627 break;
628 estimateSongLength(true);
629 break;
630 }
631
632 case BUTTON_ABOUT_SHOWPEAK:
633 {
634 if (event->getID() != eCommand)
635 break;
636 TitlePageManager titlePageManager(*screen);
637 titlePageManager.showTitlePage(TitlePageManager::PagePeak);
638 break;
639 }
640
641 case BUTTON_ABOUT_FOLLOWSONG:
642 {
643 if (event->getID() != eCommand)
644 break;
645 eventKeyDownBinding_ToggleFollowSong();
646 break;
647 }
648
649 case BUTTON_ABOUT_PROSPECTIVE:
650 {
651 if (event->getID() != eCommand)
652 break;
653 eventKeyDownBinding_ToggleProspectiveMode();
654 break;
655 }
656
657 case BUTTON_ABOUT_WRAPCURSOR:
658 {
659 if (event->getID() != eCommand)
660 break;
661 eventKeyDownBinding_ToggleCursorWrapAround();
662 break;
663 }
664
665 case BUTTON_ABOUT_LIVESWITCH:
666 {
667 if (event->getID() != eCommand)
668 break;
669 eventKeyDownBinding_ToggleLiveSwitch();
670 break;
671 }
672
673 case BUTTON_ORDERLIST_EXTENT:
674 {
675 if (event->getID() != eCommand)
676 break;
677 expandOrderlist(!extendedOrderlist);
678 screen->paintControl(screen->getControlByID(CONTAINER_ORDERLIST));
679 break;
680 }
681
682 case BUTTON_SPEEDCONTAINERFLIP:
683 {
684 if (event->getID() != eCommand)
685 break;
686 flipSpeedSection();
687 screen->paintControl(screen->getControlByID(CONTAINER_SPEED));
688 break;
689 }
690
691 #ifdef __LOWRES__
692 // -------- submenus ------------------------------
693 case BUTTON_APP_EXIT:
694 if (event->getID() != eCommand)
695 break;
696
697 eventKeyDownBinding_ExitApplication();
698 break;
699 case BUTTON_0:
700 case BUTTON_1:
701 case BUTTON_2:
702 case BUTTON_3:
703 case BUTTON_4:
704 {
705 if (event->getID() != eCommand)
706 break;
707
708 PPButton* button = reinterpret_cast<PPButton*>(sender);
709
710 sectionSwitcher->switchToSubMenu((SectionSwitcher::ActiveLowerSectionPages)(button->getID() - BUTTON_0));
711 break;
712 }
713 #endif
714
715 // -------- generic message box -------------------
716 case PP_MESSAGEBOX_BUTTON_YES:
717 case PP_MESSAGEBOX_BUTTON_NO:
718 case PP_MESSAGEBOX_BUTTON_CANCEL:
719 case PP_MESSAGEBOX_BUTTON_USER1:
720 case PP_MESSAGEBOX_BUTTON_USER2:
721 case PP_MESSAGEBOX_BUTTON_USER3:
722 case PP_MESSAGEBOX_BUTTON_USER4:
723 case PP_MESSAGEBOX_BUTTON_USER5:
724 case PP_MESSAGEBOX_BUTTON_USER6:
725 case PP_MESSAGEBOX_BUTTON_USER7:
726 case PP_MESSAGEBOX_BUTTON_USER8:
727 case PP_MESSAGEBOX_BUTTON_USER9:
728 // little hack, user buttons below PP_MESSAGEBOX_BUTTON_USER10
729 // are not allowed to send repeatable pressed down events
730 if (event->getID() != eCommand)
731 break;
732 case PP_MESSAGEBOX_BUTTON_USER10:
733 case PP_MESSAGEBOX_BUTTON_USER11:
734 case PP_MESSAGEBOX_BUTTON_USER12:
735 case PP_MESSAGEBOX_BUTTON_USER13:
736 case PP_MESSAGEBOX_BUTTON_USER14:
737 case PP_MESSAGEBOX_BUTTON_USER15:
738 {
739 bool res = messageBoxEventListener(screen->getModalControl()->getID(),
740 reinterpret_cast<PPControl*>(sender)->getID());
741
742 if (res)
743 screen->setModalControl(NULL); // repaints
744
745 break;
746 }
747
748 case MAINMENU_PLAY_SONG:
749 playerLogic->playSong();
750 break;
751
752 case MAINMENU_PLAY_PATTERN:
753 playerLogic->playPattern();
754 break;
755
756 case MAINMENU_PLAY_POSITION:
757 playerLogic->playPosition();
758 break;
759
760 case MAINMENU_STOP:
761 playerLogic->stopSong();
762 break;
763
764 // -------- ZAP message box ---------------------
765 case MAINMENU_ZAP:
766 if (event->getID() != eCommand)
767 break;
768
769 if (dialog)
770 delete dialog;
771
772 if (responder)
773 delete responder;
774
775 responder = new ZapHandler(Zapper(*this));
776 dialog = new DialogZap(screen, responder, PP_DEFAULT_ID);
777
778 dialog->show();
779 break;
780
781 // open song
782 case MAINMENU_LOAD:
783 {
784 if (event->getID() != eCommand)
785 break;
786
787 eventKeyDownBinding_Open();
788 break;
789 }
790
791 case MAINMENU_SAVE:
792 {
793 if (event->getID() != eCommand)
794 break;
795
796 eventKeyDownBinding_Save();
797 break;
798 }
799
800 case MAINMENU_SAVEAS:
801 {
802 if (event->getID() != eCommand)
803 break;
804
805 eventKeyDownBinding_SaveAs();
806 break;
807 }
808
809 // disk op
810 case MAINMENU_DISKMENU:
811 {
812 if (event->getID() != eCommand)
813 break;
814
815 eventKeyDownBinding_InvokeSectionDiskMenu();
816 break;
817 }
818
819 // Only Fasttracker II editing mode:
820 // Edit button
821 case MAINMENU_EDIT:
822 {
823 if (event->getID() != eCommand)
824 break;
825
826 switch (editMode)
827 {
828 case EditModeFastTracker:
829 eventKeyDownBinding_ToggleFT2Edit();
830 break;
831
832 case EditModeMilkyTracker:
833 eventKeyDownBinding_Edit();
834 break;
835 }
836 break;
837 }
838
839 // instrument editor
840 case MAINMENU_INSEDIT:
841 {
842 if (event->getID() != eCommand)
843 break;
844
845 eventKeyDownBinding_InvokeSectionInstruments();
846 break;
847 }
848
849 case BUTTON_INSTRUMENTEDITOR_EXIT:
850 case BUTTON_SAMPLEEDITOR_EXIT:
851 {
852 if (event->getID() != eCommand)
853 break;
854
855 sectionSwitcher->showBottomSection(SectionSwitcher::ActiveBottomSectionNone);
856 screen->paint(true, true);
857 break;
858 }
859
860 // sample editor
861 case MAINMENU_SMPEDIT:
862 {
863 if (event->getID() != eCommand)
864 break;
865
866 eventKeyDownBinding_InvokeSectionSamples();
867 break;
868 }
869
870 // settings
871 case MAINMENU_ADVEDIT:
872 {
873 if (event->getID() != eCommand)
874 break;
875
876 eventKeyDownBinding_InvokeSectionAdvancedEdit();
877 break;
878 }
879
880 // transpose
881 case MAINMENU_TRANSPOSE:
882 {
883 if (event->getID() != eCommand)
884 break;
885
886 eventKeyDownBinding_InvokeSectionTranspose();
887 break;
888 }
889
890 // settings
891 case MAINMENU_CONFIG:
892 {
893 if (event->getID() != eCommand)
894 break;
895
896 eventKeyDownBinding_InvokeSectionSettings();
897 break;
898 }
899
900 // quick options
901 case MAINMENU_QUICKOPTIONS:
902 {
903 if (event->getID() != eCommand)
904 break;
905
906 eventKeyDownBinding_InvokeSectionQuickOptions();
907 break;
908 }
909
910 // optimize
911 case MAINMENU_OPTIMIZE:
912 {
913 if (event->getID() != eCommand)
914 break;
915
916 eventKeyDownBinding_InvokeSectionOptimize();
917 break;
918 }
919
920 case MAINMENU_ABOUT:
921 {
922 if (event->getID() != eCommand)
923 break;
924
925 eventKeyDownBinding_InvokeSectionAbout();
926 break;
927 }
928
929 #ifdef __LOWRES__
930 case BUTTON_SAMPLES_INVOKEHDRECORDER:
931 {
932 if (event->getID() != eCommand)
933 break;
934
935 // The bottom section fills up the entire screen
936 // so we first need to hide the entire section before we can show
937 // the HD recorder section
938 screen->pauseUpdate(true);
939 sectionSwitcher->hideBottomSection();
940
941 sectionHDRecorder->selectSampleOutput();
942 eventKeyDownBinding_InvokeSectionHDRecorder();
943 screen->pauseUpdate(false);
944 screen->paint();
945 break;
946 }
947 #endif
948
949 case BUTTON_ORDERLIST_SONGLENGTH_PLUS:
950 moduleEditor->increaseSongLength();
951 updateSongLength();
952 sectionHDRecorder->adjustOrders();
953 break;
954
955 case BUTTON_ORDERLIST_SONGLENGTH_MINUS:
956 moduleEditor->decreaseSongLength();
957 updateSongLength();
958 sectionHDRecorder->adjustOrders();
959 break;
960
961 case BUTTON_ORDERLIST_REPEAT_PLUS:
962 moduleEditor->increaseRepeatPos();
963 updateSongRepeat();
964 break;
965
966 case BUTTON_ORDERLIST_REPEAT_MINUS:
967 moduleEditor->decreaseRepeatPos();
968 updateSongRepeat();
969 break;
970
971 // insert position into orderlist
972 case BUTTON_ORDERLIST_INSERT:
973 moduleEditor->insertNewOrderPosition(getOrderListBoxIndex());
974 updateOrderlist();
975 sectionHDRecorder->adjustOrders();
976 playerLogic->continuePlayingSong();
977 break;
978
979 // delete current orderlist position
980 case BUTTON_ORDERLIST_DELETE:
981 moduleEditor->deleteOrderPosition(getOrderListBoxIndex());
982 updateOrderlist();
983 sectionHDRecorder->adjustOrders();
984 playerLogic->continuePlayingSong();
985 break;
986
987 // insert position into orderlist
988 case BUTTON_ORDERLIST_SEQENTRY:
989 {
990 moduleEditor->seqCurrentOrderPosition(getOrderListBoxIndex());
991 updateSongLength(false);
992 pp_int32 index = getOrderListBoxIndex()+1;
993 setOrderListIndex(index);
994 sectionHDRecorder->adjustOrders();
995 playerLogic->continuePlayingSong();
996 break;
997 }
998
999 // insert position into orderlist and clone the current selected pattern
1000 case BUTTON_ORDERLIST_CLNENTRY:
1001 {
1002 moduleEditor->seqCurrentOrderPosition(getOrderListBoxIndex(), true);
1003 updateSongLength(false);
1004 pp_int32 index = getOrderListBoxIndex()+1;
1005 setOrderListIndex(index);
1006 sectionHDRecorder->adjustOrders();
1007 playerLogic->continuePlayingSong();
1008 break;
1009 }
1010
1011 // select next pattern in current orderlist position
1012 case BUTTON_ORDERLIST_NEXT:
1013 moduleEditor->increaseOrderPosition(getOrderListBoxIndex());
1014 updateOrderlist();
1015 playerLogic->continuePlayingSong();
1016 break;
1017
1018 // select previous pattern in current orderlist position
1019 case BUTTON_ORDERLIST_PREVIOUS:
1020 moduleEditor->decreaseOrderPosition(getOrderListBoxIndex());
1021 updateOrderlist();
1022 playerLogic->continuePlayingSong();
1023 break;
1024
1025 case BUTTON_OCTAVE_MINUS:
1026 getPatternEditor()->decreaseCurrentOctave();
1027 updatePatternAddAndOctave();
1028 break;
1029 case BUTTON_OCTAVE_PLUS:
1030 getPatternEditor()->increaseCurrentOctave();
1031 updatePatternAddAndOctave();
1032 break;
1033
1034 case BUTTON_ADD_PLUS:
1035 getPatternEditorControl()->increaseRowInsertAdd();
1036 updatePatternAddAndOctave();
1037 break;
1038
1039 case BUTTON_ADD_MINUS:
1040 getPatternEditorControl()->decreaseRowInsertAdd();
1041 updatePatternAddAndOctave();
1042 break;
1043
1044 case BUTTON_BPM_PLUS:
1045 {
1046 setChanged();
1047 mp_sint32 bpm,speed;
1048 playerController->getSpeed(bpm, speed);
1049 playerController->setSpeed(bpm+1, speed);
1050 updateSpeed();
1051 break;
1052 }
1053
1054 case BUTTON_BPM_MINUS:
1055 {
1056 setChanged();
1057 mp_sint32 bpm,speed;
1058 playerController->getSpeed(bpm, speed);
1059 playerController->setSpeed(bpm-1, speed);
1060 updateSpeed();
1061 break;
1062 }
1063
1064 case BUTTON_SPEED_PLUS:
1065 {
1066 setChanged();
1067 mp_sint32 bpm,speed;
1068 playerController->getSpeed(bpm, speed);
1069 playerController->setSpeed(bpm, speed+1);
1070 updateSpeed();
1071 break;
1072 }
1073
1074 case BUTTON_SPEED_MINUS:
1075 {
1076 setChanged();
1077 mp_sint32 bpm,speed;
1078 playerController->getSpeed(bpm, speed);
1079 playerController->setSpeed(bpm, speed-1);
1080 updateSpeed();
1081 break;
1082 }
1083
1084 // go to next pattern
1085 case BUTTON_PATTERN_PLUS:
1086 eventKeyDownBinding_NextPattern();
1087 break;
1088
1089 // go to previous pattern
1090 case BUTTON_PATTERN_MINUS:
1091 eventKeyDownBinding_PreviousPattern();
1092 break;
1093
1094 // expand current pattern
1095 case BUTTON_PATTERN_EXPAND:
1096 getPatternEditor()->expandPattern();
1097 updatePatternLength(false);
1098 screen->update();
1099 break;
1100
1101 // shrink current pattern
1102 case BUTTON_PATTERN_SHRINK:
1103 getPatternEditor()->shrinkPattern();
1104 updatePatternLength(false);
1105 screen->update();
1106 break;
1107
1108 // grow length
1109 case BUTTON_PATTERN_SIZE_PLUS:
1110 getPatternEditor()->resizePattern(moduleEditor->getPattern(moduleEditor->getCurrentPatternIndex())->rows + 1);
1111 updatePatternLength(false);
1112 screen->update();
1113 break;
1114
1115 // decrease length
1116 case BUTTON_PATTERN_SIZE_MINUS:
1117 getPatternEditor()->resizePattern(moduleEditor->getPattern(moduleEditor->getCurrentPatternIndex())->rows - 1);
1118 updatePatternLength(false);
1119 screen->update();
1120 break;
1121
1122 #ifdef __LOWRES__
1123 // go to next order
1124 case BUTTON_JAMMENU_NEXTORDERLIST:
1125 selectNextOrder();
1126 break;
1127
1128 // go to previous order
1129 case BUTTON_JAMMENU_PREVORDERLIST:
1130 selectPreviousOrder();
1131 break;
1132
1133 case BUTTON_JAMMENU_NEXTINSTRUMENT:
1134 selectNextInstrument();
1135 break;
1136
1137 case BUTTON_JAMMENU_PREVINSTRUMENT:
1138 selectPreviousInstrument();
1139 break;
1140
1141 case BUTTON_JAMMENU_TOGGLEPIANOSIZE:
1142 if (event->getID() != eCommand)
1143 break;
1144
1145 toggleJamMenuPianoSize();
1146 break;
1147
1148 case BUTTON_INSTRUMENTS_FLIP:
1149 if (event->getID() != eCommand)
1150 break;
1151
1152 flipInstrumentListBoxes();
1153 break;
1154 #endif
1155
1156 // add channels to song (affects pattern editor)
1157 case BUTTON_MENU_ITEM_ADDCHANNELS:
1158 case BUTTON_MENU_ITEM_SUBCHANNELS:
1159 {
1160 mp_sint32 numChannels = moduleEditor->getNumChannels() +
1161 (reinterpret_cast<PPControl*>(sender)->getID() == BUTTON_MENU_ITEM_ADDCHANNELS ? 2 : -2);
1162
1163 if (numChannels > TrackerConfig::numPlayerChannels)
1164 numChannels = TrackerConfig::numPlayerChannels;
1165 if (numChannels < 2)
1166 numChannels = 2;
1167
1168 setModuleNumChannels(numChannels);
1169 break;
1170 }
1171
1172 case BUTTON_INSTRUMENTS_PLUS:
1173 moduleEditor->allocateInstrument();
1174 updateInstrumentsListBox(false);
1175 sectionInstruments->update(false);
1176 screen->update();
1177 break;
1178
1179 case BUTTON_INSTRUMENTS_MINUS:
1180 {
1181 pp_uint32 i = listBoxInstruments->getSelectedIndex();
1182 moduleEditor->freeInstrument();
1183 updateInstrumentsListBox(false);
1184
1185 if (listBoxInstruments->getSelectedIndex() != i)
1186 {
1187 getPatternEditorControl()->setCurrentInstrument(listBoxInstruments->getSelectedIndex() + 1);
1188 updateSampleEditorAndInstrumentSection(false);
1189 }
1190
1191 screen->update();
1192 break;
1193 }
1194
1195 case BUTTON_TAB_OPEN:
1196 {
1197 eventKeyDownBinding_OpenTab();
1198 break;
1199 }
1200
1201 case BUTTON_TAB_CLOSE:
1202 {
1203 eventKeyDownBinding_CloseTab();
1204 break;
1205 }
1206
1207 #ifdef __LOWRES__
1208 case BUTTON_SCOPECONTROL_MUTE:
1209 if (event->getID() != eCommand)
1210 break;
1211 selectScopesControl(ScopesControl::ClickTypeMute);
1212 break;
1213
1214 case BUTTON_SCOPECONTROL_SOLO:
1215 if (event->getID() != eCommand)
1216 break;
1217 selectScopesControl(ScopesControl::ClickTypeSolo);
1218 break;
1219
1220 case BUTTON_SCOPECONTROL_REC:
1221 if (event->getID() != eCommand)
1222 break;
1223 selectScopesControl(ScopesControl::ClickTypeRec);
1224 break;
1225 #endif
1226 }
1227
1228 // Check if something has changed
1229 updateWindowTitle();
1230
1231 }
1232 else if (event->getID() == ePreSelection)
1233 {
1234 switch (reinterpret_cast<PPControl*>(sender)->getID())
1235 {
1236 // new instrument has been selected, we need to assure
1237 // that the sample changes are committed before we wipe out
1238 // the current sample listbox data
1239 case LISTBOX_INSTRUMENTS:
1240 if (listBoxSamples->isEditing())
1241 listBoxSamples->commitChanges();
1242 break;
1243 }
1244 }
1245 else if (event->getID() == eSelection)
1246 {
1247 switch (reinterpret_cast<PPControl*>(sender)->getID())
1248 {
1249 case TABHEADER_CONTROL:
1250 {
1251 pp_int32 index = *((pp_int32*)event->getDataPtr());
1252 tabManager->switchToTab(index);
1253 break;
1254 }
1255
1256 // new pattern has been selected in the orderlist
1257 case LISTBOX_ORDERLIST:
1258 {
1259 pp_int32 orderIndex = *((pp_int32*)event->getDataPtr());
1260 moduleEditor->setCurrentOrderIndex(orderIndex);
1261 moduleEditor->setCurrentPatternIndex(moduleEditor->getOrderPosition(orderIndex));
1262
1263 updatePatternEditorControl(false);
1264 updatePatternIndex(false);
1265 updatePatternLength(false);
1266 #ifdef __LOWRES__
1267 updateJamMenuOrder(false);
1268 #endif
1269 screen->update();
1270
1271 if (playerController->isPlayingPattern())
1272 playerLogic->continuePlayingPattern();
1273 else
1274 playerLogic->continuePlayingSong();
1275 break;
1276 }
1277
1278 // new instrument has been selected
1279 case LISTBOX_INSTRUMENTS:
1280 {
1281 pp_int32 index = *((pp_int32*)event->getDataPtr()) + 1;
1282 selectInstrument(index);
1283 screen->update();
1284 break;
1285 }
1286
1287 case LISTBOX_SAMPLES:
1288 {
1289 pp_int32 index = *((pp_int32*)event->getDataPtr());
1290 moduleEditor->setCurrentSampleIndex(index);
1291 updateSampleEditorAndInstrumentSection(false);
1292 for (pp_int32 i = 0; i < sections->size(); i++)
1293 sections->get(i)->notifySampleSelect(index);
1294 screen->update();
1295 break;
1296 }
1297
1298 // Instrument chooser
1299 case INSTRUMENT_CHOOSER_LIST_SRC3:
1300 case INSTRUMENT_CHOOSER_LIST_DST3:
1301 {
1302 PPContainer* container = static_cast<PPContainer*>(screen->getModalControl());
1303
1304 PPStaticText* staticText = static_cast<PPStaticText*>(container->getControlByID(INSTRUMENT_CHOOSER_USERSTR1));
1305
1306 PPListBox* listBoxChangeIns = NULL;
1307 PPListBox* listBoxChangeSmp = NULL;
1308
1309 PPListBox* listBoxSrcIns = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC));
1310 PPListBox* listBoxSrcSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
1311
1312 PPListBox* listBoxDstIns = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST));;
1313 PPListBox* listBoxDstSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
1314
1315 if (reinterpret_cast<PPControl*>(sender)->getID() == INSTRUMENT_CHOOSER_LIST_SRC3)
1316 {
1317 listBoxChangeIns = listBoxSrcIns;
1318 listBoxChangeSmp = listBoxSrcSmp;
1319 }
1320 else if (reinterpret_cast<PPControl*>(sender)->getID() == INSTRUMENT_CHOOSER_LIST_DST3)
1321 {
1322 listBoxChangeIns = listBoxDstIns;
1323 listBoxChangeSmp = listBoxDstSmp;
1324 }
1325
1326 if (listBoxChangeIns && listBoxChangeSmp)
1327 {
1328 listBoxChangeIns->clear();
1329 listBoxChangeSmp->clear();
1330
1331 fillInstrumentListBox(listBoxChangeIns,
1332 tabManager->getModuleEditorFromTabIndex((reinterpret_cast<PPListBox*>(sender))->getSelectedIndex()));
1333
1334 fillSampleListBox(listBoxChangeSmp, listBoxChangeIns->getSelectedIndex(),
1335 tabManager->getModuleEditorFromTabIndex((reinterpret_cast<PPListBox*>(sender))->getSelectedIndex()));
1336 }
1337
1338 // update text depending on the type of the instrument chooser dialog
1339 switch (container->getID())
1340 {
1341 case INSTRUMENT_CHOOSER_COPY:
1342 sprintf(buffer, "Copy ins. %x to %x", listBoxSrcIns->getSelectedIndex()+1, listBoxDstIns->getSelectedIndex()+1);
1343 break;
1344 case INSTRUMENT_CHOOSER_SWAP:
1345 sprintf(buffer, "Swap ins. %x with %x", listBoxSrcSmp->getSelectedIndex()+1, listBoxDstSmp->getSelectedIndex()+1);
1346 break;
1347 }
1348
1349 staticText->setText(buffer);
1350 screen->paintControl(screen->getModalControl());
1351 break;
1352 }
1353
1354 // Instrument chooser
1355 case INSTRUMENT_CHOOSER_LIST_SRC:
1356 case INSTRUMENT_CHOOSER_LIST_DST:
1357 {
1358 PPContainer* container = static_cast<PPContainer*>(screen->getModalControl());
1359
1360 PPStaticText* staticText = static_cast<PPStaticText*>(container->getControlByID(INSTRUMENT_CHOOSER_USERSTR1));
1361
1362 PPListBox* listBoxSrc = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC));
1363 PPListBox* listBoxDst = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST));
1364
1365 PPListBox* listBoxSrcModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC3));
1366 PPListBox* listBoxDstModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST3));
1367
1368 ModuleEditor* src = listBoxSrcModule ? tabManager->getModuleEditorFromTabIndex(listBoxSrcModule->getSelectedIndex()) : this->moduleEditor;
1369 ModuleEditor* dst = listBoxDstModule ? tabManager->getModuleEditorFromTabIndex(listBoxDstModule->getSelectedIndex()) : this->moduleEditor;
1370
1371 PPListBox* listBoxChange = NULL;
1372 ModuleEditor* moduleEditor = this->moduleEditor;
1373
1374 // A new instrument has been selected in either of the two instrument list boxes
1375 // now it's up to update the samples belonging to the instrument in the sample listboxes
1376 if (reinterpret_cast<PPControl*>(sender)->getID() == INSTRUMENT_CHOOSER_LIST_SRC)
1377 {
1378 listBoxChange = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
1379 moduleEditor = src;
1380 }
1381 else if (reinterpret_cast<PPControl*>(sender)->getID() == INSTRUMENT_CHOOSER_LIST_DST)
1382 {
1383 listBoxChange = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
1384 moduleEditor = dst;
1385 }
1386
1387 if (listBoxChange)
1388 {
1389 listBoxChange->clear();
1390 fillSampleListBox(listBoxChange, reinterpret_cast<PPListBox*>(sender)->getSelectedIndex(), moduleEditor);
1391 }
1392
1393 // update text depending on the type of the instrument chooser dialog
1394 switch (container->getID())
1395 {
1396 case INSTRUMENT_CHOOSER_COPY:
1397 sprintf(buffer, "Copy ins. %x to %x", listBoxSrc->getSelectedIndex()+1, listBoxDst->getSelectedIndex()+1);
1398 break;
1399 case INSTRUMENT_CHOOSER_SWAP:
1400 sprintf(buffer, "Swap ins. %x with %x", listBoxSrc->getSelectedIndex()+1, listBoxDst->getSelectedIndex()+1);
1401 break;
1402 case MESSAGEBOX_INSREMAP:
1403 sprintf(buffer, "Remap ins. %x to %x", listBoxSrc->getSelectedIndex()+1, listBoxDst->getSelectedIndex()+1);
1404 break;
1405 }
1406
1407 staticText->setText(buffer);
1408 screen->paintControl(screen->getModalControl());
1409 break;
1410 }
1411
1412 case INSTRUMENT_CHOOSER_LIST_SRC2:
1413 case INSTRUMENT_CHOOSER_LIST_DST2:
1414 {
1415 PPContainer* container = static_cast<PPContainer*>(screen->getModalControl());
1416
1417 PPStaticText* staticText = static_cast<PPStaticText*>(container->getControlByID(INSTRUMENT_CHOOSER_USERSTR2));
1418
1419 PPListBox* listBoxSrc = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
1420 PPListBox* listBoxDst = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
1421
1422 switch (container->getID())
1423 {
1424 case INSTRUMENT_CHOOSER_COPY:
1425 sprintf(buffer, "Copy smp. %x to %x", listBoxSrc->getSelectedIndex(), listBoxDst->getSelectedIndex());
1426 break;
1427 case INSTRUMENT_CHOOSER_SWAP:
1428 sprintf(buffer, "Swap smp. %x with %x", listBoxSrc->getSelectedIndex(), listBoxDst->getSelectedIndex());
1429 break;
1430 }
1431
1432 staticText->setText(buffer);
1433 screen->paintControl(screen->getModalControl());
1434 break;
1435 }
1436
1437 }
1438
1439 }
1440 else if (event->getID() == eValueChanged)
1441 {
1442 switch (reinterpret_cast<PPControl*>(sender)->getID())
1443 {
1444 case LISTBOX_SONGTITLE:
1445 {
1446 moduleEditor->setTitle(**(reinterpret_cast<const PPString* const*>(event->getDataPtr())), ModuleEditor::MAX_TITLETEXT);
1447 break;
1448 }
1449
1450 case LISTBOX_INSTRUMENTS:
1451 {
1452 moduleEditor->setInstrumentName(listBoxInstruments->getSelectedIndex(),
1453 **(reinterpret_cast<const PPString* const*>(event->getDataPtr())), ModuleEditor::MAX_INSTEXT);
1454 break;
1455 }
1456
1457 case LISTBOX_SAMPLES:
1458 {
1459 moduleEditor->setCurrentSampleName(**(reinterpret_cast<const PPString* const*>(event->getDataPtr())),
1460 ModuleEditor::MAX_SMPTEXT);
1461 break;
1462 }
1463
1464 // channels have been muted/unmuted in pattern editor
1465 case PATTERN_EDITOR:
1466 {
1467 const bool* muteChannelsPtr = reinterpret_cast<const bool*>(event->getDataPtr());
1468
1469 for (pp_int32 i = 0; i < TrackerConfig::numPlayerChannels; i++)
1470 {
1471 muteChannels[i] = muteChannelsPtr[i];
1472 bool b = (muteChannels[i] != 0);
1473 playerController->muteChannel(i, b);
1474 scopesControl->muteChannel(i, b);
1475 }
1476
1477 if (scopesControl->needsUpdate())
1478 screen->paintControl(scopesControl);
1479 break;
1480 }
1481
1482 // channels have been muted/unmuted in scopes
1483 case SCOPES_CONTROL:
1484 {
1485 switch (event->getMetaData())
1486 {
1487 case ScopesControl::ChangeValueMuting:
1488 {
1489 const bool* muteChannelsPtr = reinterpret_cast<const bool*>(event->getDataPtr());
1490
1491 for (pp_int32 i = 0; i < TrackerConfig::numPlayerChannels; i++)
1492 {
1493 muteChannels[i] = muteChannelsPtr[i];
1494 bool b = (muteChannels[i] != 0);
1495 playerController->muteChannel(i, b);
1496 getPatternEditorControl()->muteChannel(i, b);
1497 }
1498
1499 if (scopesControl->needsUpdate())
1500 screen->paintControl(scopesControl, false);
1501 screen->paintControl(getPatternEditorControl(), false);
1502
1503 screen->update();
1504 break;
1505 }
1506
1507 case ScopesControl::ChangeValueRecording:
1508 {
1509 const pp_uint8* recordChannelsPtr = reinterpret_cast<const pp_uint8*>(event->getDataPtr());
1510
1511 for (pp_int32 i = 0; i < TrackerConfig::numPlayerChannels; i++)
1512 {
1513 bool b = (recordChannelsPtr[i] != 0);
1514 playerController->recordChannel(i, b);
1515 getPatternEditorControl()->recordChannel(i, b);
1516 }
1517
1518 playerController->resetFirstPlayingChannel();
1519
1520 if (scopesControl->needsUpdate())
1521 screen->paintControl(scopesControl, false);
1522
1523 screen->update();
1524 break;
1525 }
1526 }
1527 break;
1528 }
1529
1530 }
1531
1532 // Check if something has changed
1533 updateWindowTitle();
1534
1535 }
1536 else if (event->getID() == eUpdated)
1537 {
1538 PatternEditorControl* patternEditorControl = reinterpret_cast<PatternEditorControl*>(sender);
1539 PatternEditor* patternEditor = patternEditorControl->getPatternEditor();
1540 pp_int32 numRows = patternEditor->getNumRows();
1541 pp_int32 row = patternEditorControl->getCurrentRow();
1542
1543 bool isPlaying = playerController->isPlaying() && !playerController->isPlayingRowOnly();
1544
1545 switch (reinterpret_cast<PPControl*>(sender)->getID())
1546 {
1547 // The pattern editor sends PPEvent::eUpated when the cursor has been moved
1548 // It can either be moved out of the current pattern or within the pattern
1549 // Depending on what the user data says
1550 case PATTERN_EDITOR:
1551 {
1552 switch (*(pp_int32*)event->getDataPtr())
1553 {
1554 case PatternEditorControl::AdvanceCodeJustUpdate:
1555 updatePatternLength();
1556 updatePatternAddAndOctave();
1557 break;
1558
1559 // End of pattern has been wrapped with cursor down
1560 case PatternEditorControl::AdvanceCodeCursorDownWrappedEnd:
1561 {
1562 bool b = isEditingCurrentOrderlistPattern() && listBoxOrderList->isLastEntry();
1563 // When we're playing and we're not playing a pattern
1564 // OR when we're not playing and NOT wrapping cursor around
1565 // => select next order from orderlist
1566 if ((isPlaying && !playerController->isReallyPlayingPattern()) ||
1567 (playerController->isPlaying() && playerController->isPlayingPattern() && playerLogic->rowPlay) ||
1568 (!isPlaying && !patternEditorControl->getWrapAround()))
1569 {
1570 // we're editing the pattern from the current selected order and this is not the last order list entry
1571 // advance to the next order in the list
1572 if (!b)
1573 {
1574 screen->pauseUpdate(true);
1575 selectNextOrder();
1576 screen->pauseUpdate(false);
1577 }
1578 }
1579 // Calculate new position within pattern and update player position
1580 ASSERT(row > 0);
1581
1582 // when we're in wraparound mode and we're not in the last
1583 // pattern & row of the last order, wrap around cursor in current pattern
1584 if (!b || patternEditorControl->getWrapAround())
1585 patternEditorControl->setRow(myMod(row - numRows, patternEditor->getNumRows()), false);
1586 else
1587 patternEditorControl->setRow(numRows-1, false);
1588
1589 updateSongLength(true);
1590 updatePatternIndex(true);
1591 updatePatternLength(true);
1592 updateSongRow();
1593 return 1;
1594 }
1595
1596 // Start of pattern has been wrapped with cursor up
1597 case PatternEditorControl::AdvanceCodeCursorUpWrappedStart:
1598 {
1599 bool b = isEditingCurrentOrderlistPattern() && listBoxOrderList->isFirstEntry();
1600 // When we're playing and we're not playing a pattern
1601 // OR when we're not playing and NOT wrapping cursor around
1602 // => select previous order from orderlist
1603 if ((isPlaying && !playerController->isReallyPlayingPattern()) ||
1604 (playerController->isPlaying() && playerController->isPlayingPattern() && playerLogic->rowPlay) ||
1605 (!isPlaying && !patternEditorControl->getWrapAround()))
1606 {
1607 // we're editing the pattern from the current selected order and this is not the last order list entry
1608 // advance to the previous order in the list
1609 if (!b)
1610 {
1611 screen->pauseUpdate(true);
1612 selectPreviousOrder();
1613 screen->pauseUpdate(false);
1614 }
1615 }
1616 // Calculate new position within pattern and update player position
1617 ASSERT(row < 0);
1618
1619 // when we're in wraparound mode and we're not in the last
1620 // pattern & row of the last order, wrap around cursor in current pattern
1621 if (!b || patternEditorControl->getWrapAround())
1622 patternEditorControl->setRow(myMod(patternEditor->getNumRows() + row, patternEditor->getNumRows()), false);
1623 else
1624 patternEditorControl->setRow(0, false);
1625
1626 updateSongLength(true);
1627 updatePatternIndex(true);
1628 updatePatternLength(true);
1629 updateSongRow();
1630 return 1;
1631 }
1632
1633 // End of pattern has been wrapped with page down key
1634 case PatternEditorControl::AdvanceCodeCursorPageDownWrappedEnd:
1635 // Not playing? Do nothing at all
1636 if (!playerController->isPlaying()/* && !patternEditor->getWrapAround()*/)
1637 return 0;
1638 // Last entry in orderlist? Do nothing at all
1639 //if (listBoxOrderList->isLastEntry())
1640 // return 0;
1641
1642 // Not playing pattern? Select new order
1643 if (!playerController->isReallyPlayingPattern())
1644 {
1645 screen->pauseUpdate(true);
1646 selectNextOrder(true);
1647 screen->pauseUpdate(false);
1648 }
1649
1650 // Calculate new position within pattern and update player position
1651 ASSERT(row > 0);
1652 patternEditorControl->setRow(myMod(row - numRows, patternEditor->getNumRows()), false);
1653 updateSongLength(true);
1654 updatePatternIndex(true);
1655 updatePatternLength(true);
1656 updateSongRow();
1657 return 1;
1658
1659 // Start of pattern has been wrapped with page up key
1660 case PatternEditorControl::AdvanceCodeCursorPageUpWrappedStart:
1661 // Not playing? Do nothing at all
1662 if (!playerController->isPlaying()/* && !patternEditor->getWrapAround()*/)
1663 return 0;
1664 // Last entry in orderlist? Do nothing at all
1665 //if (listBoxOrderList->isFirstEntry())
1666 // return 0;
1667
1668 // Not playing pattern? Select previous order
1669 if (!playerController->isReallyPlayingPattern())
1670 {
1671 screen->pauseUpdate(true);
1672 selectPreviousOrder(true);
1673 screen->pauseUpdate(false);
1674 }
1675
1676 // Calculate new position within pattern and update player position
1677 ASSERT(row < 0);
1678 patternEditorControl->setRow(myMod(patternEditor->getNumRows() + row, patternEditor->getNumRows()), false);
1679 updateSongLength(true);
1680 updatePatternIndex(true);
1681 updatePatternLength(true);
1682 updateSongRow();
1683 return 1;
1684
1685 // End of pattern has been wrapped with page down key
1686 case PatternEditorControl::AdvanceCodeWrappedEnd:
1687 if (!patternEditorControl->getWrapAround() && !listBoxOrderList->isLastEntry())
1688 {
1689 screen->pauseUpdate(true);
1690 selectNextOrder(true);
1691 screen->pauseUpdate(false);
1692 patternEditorControl->setRow(myMod(row - numRows, patternEditor->getNumRows()), false);
1693 }
1694 // if we are in the last order of the order list and in the last row of this order don't advance to the next pattern
1695 else if (!patternEditorControl->getWrapAround() && listBoxOrderList->isLastEntry())
1696 {
1697 patternEditorControl->setRow(numRows - 1, false);
1698 }
1699 else
1700 {
1701 // Calculate new position within pattern and update player position
1702 ASSERT(row > 0);
1703 patternEditorControl->setRow(myMod(row - numRows, patternEditor->getNumRows()), false);
1704 }
1705
1706 updateSongLength(true);
1707 updatePatternIndex(true);
1708 updatePatternLength(true);
1709 updateSongRow();
1710 return 1;
1711
1712 // Not wrapped at all... Just calculate new position within pattern and update player position
1713 case PatternEditorControl::AdvanceCodeSelectNewRow:
1714 if (shouldFollowSong() &&
1715 isEditingCurrentOrderlistPattern())
1716 updateSongRow();
1717 break;
1718 }
1719 break;
1720 }
1721 }
1722 }
1723 // frontend layer sends PPEvent::eFullScreen when the APP is going fullscreen
1724 else if (event->getID() == eFullScreen)
1725 {
1726 TrackerSettingsDatabase* settingsDatabaseCopySecond = new TrackerSettingsDatabase(*settingsDatabase);
1727
1728 if (settingsDatabaseCopy)
1729 settingsDatabaseCopy->store("FULLSCREEN", !screen->isFullScreen());
1730 settingsDatabaseCopySecond->store("FULLSCREEN", !screen->isFullScreen());
1731
1732 applySettings(settingsDatabaseCopySecond, settingsDatabase);
1733
1734 delete settingsDatabase;
1735 settingsDatabase = settingsDatabaseCopySecond;
1736
1737 sectionSettings->update();
1738 }
1739
1740 return 0;
1741 }
1742
1743 ///////////////////////////////////////////////////////////////////////////////
1744 // remember:
1745 // user buttons below ID PP_MESSAGEBOX_BUTTON_USER10
1746 // are not allowed to send repeatable pressed down events
1747 ///////////////////////////////////////////////////////////////////////////////
swapAndCopyHandler(pp_int32 messageBoxID,pp_int32 messageBoxButtonID)1748 bool Tracker::swapAndCopyHandler(pp_int32 messageBoxID, pp_int32 messageBoxButtonID)
1749 {
1750 PPContainer* container = static_cast<PPContainer*>(screen->getModalControl());
1751 PPListBox* listBoxSrc = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC));
1752 PPListBox* listBoxSrcModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC3));
1753 PPListBox* listBoxDst = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST));
1754 PPListBox* listBoxDstModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST3));
1755
1756 ModuleEditor* src = listBoxSrcModule ? tabManager->getModuleEditorFromTabIndex(listBoxSrcModule->getSelectedIndex()) : this->moduleEditor;
1757 ModuleEditor* dst = listBoxDstModule ? tabManager->getModuleEditorFromTabIndex(listBoxDstModule->getSelectedIndex()) : this->moduleEditor;
1758
1759 switch (messageBoxButtonID)
1760 {
1761 case PP_MESSAGEBOX_BUTTON_USER1:
1762 case PP_MESSAGEBOX_BUTTON_USER3:
1763 {
1764 switch (messageBoxID)
1765 {
1766 case INSTRUMENT_CHOOSER_COPY:
1767 this->moduleEditor->copyInstrument(*dst, listBoxDst->getSelectedIndex(),
1768 *src, listBoxSrc->getSelectedIndex());
1769 break;
1770 case INSTRUMENT_CHOOSER_SWAP:
1771 this->moduleEditor->swapInstruments(*dst, listBoxDst->getSelectedIndex(),
1772 *src, listBoxSrc->getSelectedIndex());
1773 break;
1774 default:
1775 ASSERT(false);
1776 }
1777
1778 if (messageBoxButtonID == PP_MESSAGEBOX_BUTTON_USER3)
1779 {
1780 pp_int32 index = listBoxDst->getSelectedIndex()+1;
1781 listBoxDst->setSelectedIndex(index, false, true);
1782 index = listBoxSrc->getSelectedIndex()+1;
1783 listBoxSrc->setSelectedIndex(index, false, true);
1784 }
1785
1786 break;
1787 }
1788
1789 case PP_MESSAGEBOX_BUTTON_USER2:
1790 case PP_MESSAGEBOX_BUTTON_USER4:
1791 {
1792 PPListBox* listBoxSrcSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
1793 PPListBox* listBoxDstSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
1794
1795 switch (messageBoxID)
1796 {
1797 case INSTRUMENT_CHOOSER_COPY:
1798 this->moduleEditor->copySample(*dst, listBoxDst->getSelectedIndex(), listBoxDstSmp->getSelectedIndex(),
1799 *src, listBoxSrc->getSelectedIndex(), listBoxSrcSmp->getSelectedIndex());
1800 break;
1801 case INSTRUMENT_CHOOSER_SWAP:
1802 this->moduleEditor->swapSamples(*dst, listBoxDst->getSelectedIndex(), listBoxDstSmp->getSelectedIndex(),
1803 *src, listBoxSrc->getSelectedIndex(), listBoxSrcSmp->getSelectedIndex());
1804 break;
1805 default:
1806 ASSERT(false);
1807 }
1808
1809 if (messageBoxButtonID == PP_MESSAGEBOX_BUTTON_USER4)
1810 {
1811 pp_int32 index = listBoxDstSmp->getSelectedIndex()+1;
1812 listBoxDstSmp->setSelectedIndex(index, false, true);
1813 index = listBoxSrcSmp->getSelectedIndex()+1;
1814 listBoxSrcSmp->setSelectedIndex(index, false, true);
1815 }
1816 break;
1817 }
1818
1819 // swap source/destination list boxes
1820 case PP_MESSAGEBOX_BUTTON_USER5:
1821 {
1822 if (listBoxSrcModule == NULL || listBoxDstModule == NULL)
1823 return true;
1824
1825 PPListBox* listBoxSrcSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
1826 PPListBox* listBoxDstSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
1827
1828 pp_int32 srcModIndex = listBoxSrcModule->getSelectedIndex();
1829 pp_int32 dstModIndex = listBoxDstModule->getSelectedIndex();
1830
1831 pp_int32 srcInsIndex = listBoxSrc->getSelectedIndex();
1832 pp_int32 dstInsIndex = listBoxDst->getSelectedIndex();
1833
1834 pp_int32 srcSmpIndex = listBoxSrcSmp->getSelectedIndex();
1835 pp_int32 dstSmpIndex = listBoxDstSmp->getSelectedIndex();
1836
1837 listBoxSrcModule->setSelectedIndex(dstModIndex, false);
1838 listBoxDstModule->setSelectedIndex(srcModIndex, false);
1839
1840 updateInstrumentChooser(false);
1841
1842 listBoxSrc->setSelectedIndex(dstInsIndex, false);
1843 listBoxDst->setSelectedIndex(srcInsIndex, false);
1844
1845 listBoxSrcSmp->setSelectedIndex(dstSmpIndex, false);
1846 listBoxDstSmp->setSelectedIndex(srcSmpIndex, false);
1847
1848 updateInstrumentChooser(true);
1849 screen->paint();
1850 return true;
1851 }
1852
1853 // one more instrument in the source module
1854 case PP_MESSAGEBOX_BUTTON_USER10:
1855 {
1856 src->allocateInstrument();
1857 break;
1858 }
1859
1860 // delete one instrument in the source module
1861 case PP_MESSAGEBOX_BUTTON_USER11:
1862 {
1863 src->freeInstrument();
1864 break;
1865 }
1866
1867 // one more instrument in the destination module
1868 case PP_MESSAGEBOX_BUTTON_USER12:
1869 {
1870 dst->allocateInstrument();
1871 break;
1872 }
1873
1874 // delete one instrument in the destination module
1875 case PP_MESSAGEBOX_BUTTON_USER13:
1876 {
1877 dst->freeInstrument();
1878 break;
1879 }
1880
1881 case PP_MESSAGEBOX_BUTTON_USER6:
1882 {
1883 // play source
1884 SamplePlayer samplePlayer(*src, *playerController);
1885 PPListBox* listBoxSrcSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
1886
1887 samplePlayer.playSample(listBoxSrc->getSelectedIndex(),
1888 listBoxSrcSmp->getSelectedIndex(),
1889 sectionSamples->getCurrentSamplePlayNote());
1890 return true;
1891 }
1892
1893 case PP_MESSAGEBOX_BUTTON_USER7:
1894 {
1895 // play dest
1896 SamplePlayer samplePlayer(*dst, *playerController);
1897 PPListBox* listBoxDstSmp = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
1898
1899 samplePlayer.playSample(listBoxDst->getSelectedIndex(),
1900 listBoxDstSmp->getSelectedIndex(),
1901 sectionSamples->getCurrentSamplePlayNote());
1902 return true;
1903 }
1904
1905 default:
1906 return false;
1907 }
1908
1909 updateInstrumentChooser(false);
1910
1911 if (listBoxInstruments->getSelectedIndex() == listBoxDst->getSelectedIndex() &&
1912 dst == this->moduleEditor)
1913 {
1914 updateInstrumentsListBox(false);
1915 sectionInstruments->resetEnvelopeEditor();
1916 sectionSamples->resetSampleEditor();
1917 }
1918
1919 PPButton* button = static_cast<PPButton*>(container->getControlByID(PP_MESSAGEBOX_BUTTON_CANCEL));
1920 button->setText("Done");
1921
1922 sectionSamples->updateAfterLoad();
1923
1924 screen->paint();
1925 return true;
1926 }
1927
handleQuit()1928 void Tracker::handleQuit()
1929 {
1930 if (sectionSettings->isVisible())
1931 sectionSettings->cancelSettings();
1932 screen->shutDown();
1933 }
1934
messageBoxEventListener(pp_int32 messageBoxID,pp_int32 messageBoxButtonID)1935 bool Tracker::messageBoxEventListener(pp_int32 messageBoxID, pp_int32 messageBoxButtonID)
1936 {
1937 switch (messageBoxID)
1938 {
1939 case MESSAGEBOX_REALLYQUIT:
1940 {
1941 if (messageBoxButtonID == PP_MESSAGEBOX_BUTTON_YES)
1942 {
1943 handleQuit();
1944 }
1945 break;
1946 }
1947
1948 case INSTRUMENT_CHOOSER_COPY:
1949 case INSTRUMENT_CHOOSER_SWAP:
1950 {
1951 if (swapAndCopyHandler(messageBoxID, messageBoxButtonID))
1952 return false;
1953
1954 break;
1955 }
1956
1957 case MESSAGEBOX_INSREMAP:
1958 {
1959 switch (messageBoxButtonID)
1960 {
1961 case PP_MESSAGEBOX_BUTTON_USER1:
1962 case PP_MESSAGEBOX_BUTTON_USER2:
1963 case PP_MESSAGEBOX_BUTTON_USER3:
1964 case PP_MESSAGEBOX_BUTTON_USER4:
1965 {
1966 PPContainer* container = static_cast<PPContainer*>(screen->getModalControl());
1967 PPListBox* listBoxSrc = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC));
1968 PPListBox* listBoxDst = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST));
1969
1970 pp_int32 newIns = listBoxDst->getSelectedIndex()+1;
1971 pp_int32 oldIns = listBoxSrc->getSelectedIndex()+1;
1972
1973 pp_int32 res = 0;
1974
1975 switch (messageBoxButtonID)
1976 {
1977 case PP_MESSAGEBOX_BUTTON_USER1:
1978 res = getPatternEditor()->insRemapTrack(oldIns, newIns);
1979 break;
1980 case PP_MESSAGEBOX_BUTTON_USER2:
1981 res = getPatternEditor()->insRemapPattern(oldIns, newIns);
1982 break;
1983 case PP_MESSAGEBOX_BUTTON_USER3:
1984 res = moduleEditor->insRemapSong(oldIns, newIns);
1985 break;
1986 case PP_MESSAGEBOX_BUTTON_USER4:
1987 res = getPatternEditor()->insRemapSelection(oldIns, newIns);
1988 break;
1989 }
1990
1991 char buffer[100];
1992 sprintf(buffer, "%i Instruments have been remapped", res);
1993 showMessageBox(MESSAGEBOX_UNIVERSAL, buffer, MessageBox_OK);
1994
1995 screen->paint();
1996 return false;
1997 }
1998 }
1999
2000 break;
2001 }
2002 }
2003
2004 return true;
2005 }
2006
2007 ///////////////////////////////////////////////////////////
2008 // check if editing of any textfield is currently
2009 // performed, if so we are not allowed to play instruments
2010 ///////////////////////////////////////////////////////////
isActiveEditing()2011 bool Tracker::isActiveEditing()
2012 {
2013 // check for focus of song title edit field
2014 PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_ABOUT));
2015 PPListBox* listBox = static_cast<PPListBox*>(container->getControlByID(LISTBOX_SONGTITLE));
2016
2017 if (screen->hasFocus(container) && listBox->isEditing())
2018 return true;
2019
2020 container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_INSTRUMENTLIST));
2021 listBox = listBoxInstruments;
2022
2023 if (screen->hasFocus(container) && listBox->isEditing())
2024 return true;
2025
2026 container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_INSTRUMENTLIST));
2027 listBox = listBoxSamples;
2028
2029 if (screen->hasFocus(container) && listBox->isEditing())
2030 return true;
2031
2032 if (sectionDiskMenu->isActiveEditing())
2033 return true;
2034
2035 return false;
2036 }
2037
ensureSongStopped(bool bResetMainVolume,bool suspend)2038 void Tracker::ensureSongStopped(bool bResetMainVolume, bool suspend)
2039 {
2040 updatePianoControl(sectionInstruments->getPianoControl());
2041 #ifdef __LOWRES__
2042 {
2043 PianoControl* pianoControl = static_cast<PianoControl*>(inputContainerCurrent->getControlByID(PIANO_CONTROL));
2044 updatePianoControl(pianoControl);
2045 }
2046 #endif
2047 playerLogic->ensureSongStopped(bResetMainVolume, suspend);
2048 }
2049
ensureSongPlaying(bool continuePlaying)2050 void Tracker::ensureSongPlaying(bool continuePlaying)
2051 {
2052 playerLogic->ensureSongPlaying(continuePlaying);
2053 }
2054
initPlayback()2055 void Tracker::initPlayback()
2056 {
2057 resetStateMemories();
2058
2059 playerController->resetPlayTimeCounter();
2060
2061 recorderLogic->init();
2062 }
2063
setChanged()2064 void Tracker::setChanged()
2065 {
2066 moduleEditor->setChanged();
2067 updateWindowTitle();
2068 }
2069
shouldFollowSong()2070 bool Tracker::shouldFollowSong()
2071 {
2072 if (playerController->getNextOrderToPlay() != -1 ||
2073 playerController->getNextPatternToPlay() != -1)
2074 return false;
2075
2076 return getFollowSong();
2077 }
2078
getFollowSong()2079 bool Tracker::getFollowSong()
2080 {
2081 return followSong;
2082 }
2083
setFollowSong(bool b,bool repaint)2084 void Tracker::setFollowSong(bool b, bool repaint/* = true*/)
2085 {
2086 followSong = b;
2087 updateAboutToggleButton(BUTTON_ABOUT_FOLLOWSONG, b, repaint);
2088 }
2089
getProspectiveMode()2090 bool Tracker::getProspectiveMode()
2091 {
2092 return getPatternEditorControl()->getProspective();
2093 }
2094
setProspectiveMode(bool b,bool repaint)2095 void Tracker::setProspectiveMode(bool b, bool repaint/* = true*/)
2096 {
2097 getPatternEditorControl()->setProspective(b);
2098 updateAboutToggleButton(BUTTON_ABOUT_PROSPECTIVE, b, repaint);
2099 }
2100
getCursorWrapAround()2101 bool Tracker::getCursorWrapAround()
2102 {
2103 return getPatternEditorControl()->getWrapAround();
2104 }
2105
setCursorWrapAround(bool b,bool repaint)2106 void Tracker::setCursorWrapAround(bool b, bool repaint/* = true*/)
2107 {
2108 getPatternEditorControl()->setWrapAround(b);
2109 updateAboutToggleButton(BUTTON_ABOUT_WRAPCURSOR, b, repaint);
2110 }
2111
setLiveSwitch(bool b,bool repaint)2112 void Tracker::setLiveSwitch(bool b, bool repaint/* = true*/)
2113 {
2114 playerLogic->setLiveSwitch(b);
2115 updateAboutToggleButton(BUTTON_ABOUT_LIVESWITCH, b, repaint);
2116 }
2117
updateSongRow(bool checkFollowSong)2118 void Tracker::updateSongRow(bool checkFollowSong/* = true*/)
2119 {
2120 if (checkFollowSong && !shouldFollowSong())
2121 return;
2122
2123 mp_sint32 row = getPatternEditorControl()->getCurrentRow();
2124 mp_sint32 pos = listBoxOrderList->getSelectedIndex();
2125
2126 playerController->setPatternPos(pos, row);
2127 }
2128
selectInstrument(pp_int32 instrument)2129 void Tracker::selectInstrument(pp_int32 instrument)
2130 {
2131 // instrument index starts at 0 in the module editor
2132 // but from 1 everywhere else
2133 moduleEditor->setCurrentInstrumentIndex(instrument-1);
2134
2135 getPatternEditorControl()->setCurrentInstrument(instrument);
2136
2137 sectionTranspose->setCurrentInstrument(instrument, false);
2138
2139 updateSamplesListBox(false);
2140
2141 // update instrument/sample editor
2142 // important: sample editor first => will reload sample into sample editor
2143 updateSampleEditor(false);
2144 // update instrument/sample editor
2145 sectionInstruments->update(false);
2146
2147 for (pp_int32 i = 0; i < sections->size(); i++)
2148 sections->get(i)->notifyInstrumentSelect(instrument);
2149 }
2150
fillInstrumentListBox(PPListBox * listBox,ModuleEditor * moduleEditor)2151 void Tracker::fillInstrumentListBox(PPListBox* listBox, ModuleEditor* moduleEditor/* = NULL*/)
2152 {
2153 if (moduleEditor == NULL)
2154 moduleEditor = this->moduleEditor;
2155 char name[MP_MAXTEXT];
2156 for (pp_int32 j = 0; j < moduleEditor->getNumInstruments(); j++)
2157 {
2158 memset(name, 0, sizeof(name));
2159 moduleEditor->getInstrumentName(j, name, ModuleEditor::MAX_INSTEXT);
2160 listBox->addItem(name);
2161 }
2162 }
2163
fillSampleListBox(PPListBox * listBox,pp_int32 insIndex,ModuleEditor * moduleEditor)2164 void Tracker::fillSampleListBox(PPListBox* listBox, pp_int32 insIndex, ModuleEditor* moduleEditor/* = NULL*/)
2165 {
2166 if (moduleEditor == NULL)
2167 moduleEditor = this->moduleEditor;
2168 for (pp_int32 j = 0; j < moduleEditor->getNumSamples(insIndex); j++)
2169 {
2170 char name[MP_MAXTEXT];
2171 moduleEditor->getSampleName(insIndex, j, name, ModuleEditor::MAX_SMPTEXT);
2172 listBox->addItem(name);
2173 }
2174 }
2175
fillModuleListBox(PPListBox * listBox)2176 void Tracker::fillModuleListBox(PPListBox* listBox)
2177 {
2178 #ifndef __LOWRES__
2179 TabHeaderControl* tabHeader = static_cast<TabHeaderControl*>(screen->getControlByID(TABHEADER_CONTROL));
2180 for (pp_int32 i = 0; i < (signed)tabHeader->getNumTabs(); i++)
2181 {
2182 TabTitleProvider tabTitleProvider(*tabManager->getModuleEditorFromTabIndex(i));
2183 listBox->addItem(tabTitleProvider.getTabTitle());
2184 }
2185 #endif
2186 }
2187
rearrangePatternEditorControl()2188 void Tracker::rearrangePatternEditorControl()
2189 {
2190 #ifdef __LOWRES__
2191 PatternEditorControl* control = getPatternEditorControl();
2192
2193 if (control)
2194 {
2195 PPPoint location = control->getLocation();
2196
2197 pp_int32 height = inputContainerCurrent->getLocation().y;
2198
2199 control->setSize(PPSize(screen->getWidth(), height - location.y));
2200 if (inputContainerCurrent)
2201 inputContainerCurrent->show(true);
2202 }
2203 #endif
2204 }
2205
rearrangePatternEditorControlOrInstrumentContainer()2206 void Tracker::rearrangePatternEditorControlOrInstrumentContainer()
2207 {
2208 if (sectionDiskMenu->isDiskMenuVisible())
2209 sectionDiskMenu->resizeInstrumentContainer();
2210 else
2211 rearrangePatternEditorControl();
2212 }
2213
showScopes(bool visible,pp_uint32 style)2214 void Tracker::showScopes(bool visible, pp_uint32 style)
2215 {
2216 if (!scopesControl)
2217 return;
2218
2219 scopesControl->setAppearance((ScopesControl::AppearanceTypes)style);
2220
2221 #ifndef __LOWRES__
2222 if (visible && scopesControl->isVisible())
2223 return;
2224
2225 if (!visible && !scopesControl->isVisible())
2226 return;
2227
2228 PPSize size = getPatternEditorControl()->getSize();
2229 PPPoint location = getPatternEditorControl()->getLocation();
2230
2231 if (visible)
2232 {
2233 scopesControl->hide(false);
2234 size.height -= scopesControl->getSize().height;
2235 location.y += scopesControl->getSize().height;
2236 getPatternEditorControl()->setSize(size);
2237 getPatternEditorControl()->setLocation(location);
2238 }
2239 else
2240 {
2241 scopesControl->hide(true);
2242 size.height += scopesControl->getSize().height;
2243 location.y -= scopesControl->getSize().height;
2244 getPatternEditorControl()->setSize(size);
2245 getPatternEditorControl()->setLocation(location);
2246 }
2247
2248 // store settings
2249 settingsDatabase->store("SCOPES", (visible ? 1 : 0) | (style << 1));
2250
2251 // if config menu is visible, update the toggles
2252 if (sectionSettings->isVisible())
2253 sectionSettings->update(false);
2254
2255 #endif
2256
2257 screen->paint();
2258 }
2259
setInputControl(SIPs sip)2260 void Tracker::setInputControl(SIPs sip)
2261 {
2262 switch (sip)
2263 {
2264 case SIPDefault:
2265 {
2266 inputContainerCurrent = inputContainerDefault;
2267 inputContainerExtended->hide(true);
2268 inputContainerCurrent->hide(false);
2269 break;
2270 }
2271
2272 case SIPExtended:
2273 {
2274 inputContainerCurrent = inputContainerExtended;
2275 inputContainerDefault->hide(true);
2276 inputContainerCurrent->hide(false);
2277 break;
2278 }
2279 }
2280
2281 rearrangePatternEditorControlOrInstrumentContainer();
2282
2283 screen->update();
2284 }
2285
expandOrderlist(bool b)2286 void Tracker::expandOrderlist(bool b)
2287 {
2288 extendedOrderlist = b;
2289
2290 PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_ORDERLIST));
2291
2292 PPPoint p = container->getLocation();
2293 pp_int32 x = p.x;
2294 pp_int32 y = p.y;
2295
2296 ASSERT(container);
2297
2298 if (b)
2299 {
2300 container->getControlByID(BUTTON_ORDERLIST_SONGLENGTH_PLUS)->setLocation(PPPoint(x+2 + 78-2, y+2+12+12+12));
2301 container->getControlByID(BUTTON_ORDERLIST_SONGLENGTH_MINUS)->setLocation(PPPoint(x+2 + 78-2 + 17, y+2+12+12+12));
2302
2303 container->getControlByID(BUTTON_ORDERLIST_REPEAT_PLUS)->hide(true);
2304 container->getControlByID(BUTTON_ORDERLIST_REPEAT_MINUS)->hide(true);
2305 container->getControlByID(STATICTEXT_ORDERLIST_SONGLENGTH)->setLocation(PPPoint(x+ 8*12, y+2+12+12+12+2+12));
2306 container->getControlByID(STATICTEXT_ORDERLIST_REPEAT)->hide(true);
2307 container->getControlByID(0)->hide(true);
2308 container->getControlByID(1)->hide(false);
2309 container->getControlByID(2)->hide(true);
2310 static_cast<PPButton*>(container->getControlByID(BUTTON_ORDERLIST_EXTENT))->setText(TrackerConfig::stringButtonExtended);
2311
2312 PPSize size = container->getControlByID(LISTBOX_ORDERLIST)->getSize();
2313 size.height = 60;
2314 container->getControlByID(LISTBOX_ORDERLIST)->setSize(size);
2315 }
2316 else
2317 {
2318 container->getControlByID(BUTTON_ORDERLIST_SONGLENGTH_PLUS)->setLocation(PPPoint(x+2 + 78-2, y+2+12+12+12));
2319 container->getControlByID(BUTTON_ORDERLIST_SONGLENGTH_MINUS)->setLocation(PPPoint(x+2 + 78-2 + 17, y+2+12+12+12));
2320
2321 container->getControlByID(BUTTON_ORDERLIST_REPEAT_PLUS)->hide(false);
2322 container->getControlByID(BUTTON_ORDERLIST_REPEAT_MINUS)->hide(false);
2323 container->getControlByID(STATICTEXT_ORDERLIST_SONGLENGTH)->setLocation(PPPoint(x+2 + 8*7, y+2+12+12+12+2));
2324 container->getControlByID(STATICTEXT_ORDERLIST_REPEAT)->hide(false);
2325 container->getControlByID(0)->hide(false);
2326 container->getControlByID(1)->hide(true);
2327 container->getControlByID(2)->hide(false);
2328 static_cast<PPButton*>(container->getControlByID(BUTTON_ORDERLIST_EXTENT))->setText(TrackerConfig::stringButtonCollapsed);
2329
2330 PPSize size = container->getControlByID(LISTBOX_ORDERLIST)->getSize();
2331 size.height = 36;
2332 container->getControlByID(LISTBOX_ORDERLIST)->setSize(size);
2333 }
2334
2335 }
2336
flipSpeedSection()2337 void Tracker::flipSpeedSection()
2338 {
2339 PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_SPEED));
2340 ASSERT(container);
2341
2342 PPControl* control = container->getControlByID(STATICTEXT_SPEED_OCTAVE);
2343 ASSERT(control);
2344
2345 pp_int32 dy = container->getControlByID(STATICTEXT_SPEED_SPEED)->getLocation().y -
2346 container->getControlByID(STATICTEXT_SPEED_BPM)->getLocation().y;
2347
2348 if (control->isHidden())
2349 {
2350 // Show octave integer field
2351 control->hide(false);
2352 // Show octave description text ("Oct")
2353 control = container->getControlByID(STATICTEXT_SPEED_OCTAVE_DESC);
2354 control->hide(false);
2355 // Show octave minus button
2356 control = container->getControlByID(BUTTON_OCTAVE_MINUS);
2357 control->hide(false);
2358 // Show octave plus button
2359 control = container->getControlByID(BUTTON_OCTAVE_PLUS);
2360 control->hide(false);
2361
2362 // show mainvol text
2363 control = container->getControlByID(STATICTEXT_SPEED_MAINVOL);
2364 control->hide(false);
2365 // show mainvol description text ("Mainvol")
2366 control = container->getControlByID(STATICTEXT_SPEED_MAINVOL_DESC);
2367 control->hide(false);
2368
2369 // hide BPM text fields + buttons
2370 control = container->getControlByID(STATICTEXT_SPEED_BPM);
2371 control->hide(true);
2372 control = container->getControlByID(STATICTEXT_SPEED_BPM_DESC);
2373 control->hide(true);
2374 control = container->getControlByID(BUTTON_BPM_MINUS);
2375 control->hide(true);
2376 control = container->getControlByID(BUTTON_BPM_PLUS);
2377 control->hide(true);
2378
2379 // hide tick speed text fields + buttons
2380 control = container->getControlByID(BUTTON_SPEED_MINUS);
2381 control->hide(true);
2382 control = container->getControlByID(BUTTON_SPEED_PLUS);
2383 control->hide(true);
2384 control = container->getControlByID(STATICTEXT_SPEED_SPEED);
2385 control->hide(true);
2386 control = container->getControlByID(STATICTEXT_SPEED_SPEED_DESC);
2387 control->hide(true);
2388
2389 // Move pattern add text fields + buttons one row upwards
2390 control = container->getControlByID(STATICTEXT_SPEED_PATTERNADD);
2391 PPPoint p = control->getLocation();
2392 p.y-=dy;
2393 control->setLocation(p);
2394 control = container->getControlByID(STATICTEXT_SPEED_PATTERNADD_DESC);
2395 p = control->getLocation();
2396 p.y-=dy;
2397 control->setLocation(p);
2398 control = container->getControlByID(BUTTON_ADD_PLUS);
2399 p = control->getLocation();
2400 p.y-=dy;
2401 control->setLocation(p);
2402 control = container->getControlByID(BUTTON_ADD_MINUS);
2403 p = control->getLocation();
2404 p.y-=dy;
2405 control->setLocation(p);
2406 }
2407 else
2408 {
2409 // The hide octave texts + buttons
2410 control->hide(true);
2411 control = container->getControlByID(STATICTEXT_SPEED_OCTAVE_DESC);
2412 control->hide(true);
2413 control = container->getControlByID(BUTTON_OCTAVE_MINUS);
2414 control->hide(true);
2415 control = container->getControlByID(BUTTON_OCTAVE_PLUS);
2416 control->hide(true);
2417
2418 // hide mainvol text
2419 control = container->getControlByID(STATICTEXT_SPEED_MAINVOL);
2420 control->hide(true);
2421 control = container->getControlByID(STATICTEXT_SPEED_MAINVOL_DESC);
2422 control->hide(true);
2423
2424 // show bpm text + buttons
2425 control = container->getControlByID(STATICTEXT_SPEED_BPM);
2426 control->hide(false);
2427 control = container->getControlByID(STATICTEXT_SPEED_BPM_DESC);
2428 control->hide(false);
2429 control = container->getControlByID(BUTTON_BPM_MINUS);
2430 control->hide(false);
2431 control = container->getControlByID(BUTTON_BPM_PLUS);
2432 control->hide(false);
2433
2434 // show tick speed text + buttons
2435 control = container->getControlByID(BUTTON_SPEED_MINUS);
2436 control->hide(false);
2437 control = container->getControlByID(BUTTON_SPEED_PLUS);
2438 control->hide(false);
2439 control = container->getControlByID(STATICTEXT_SPEED_SPEED);
2440 control->hide(false);
2441 control = container->getControlByID(STATICTEXT_SPEED_SPEED_DESC);
2442 control->hide(false);
2443
2444 // move pattern add text one row downwards
2445 control = container->getControlByID(STATICTEXT_SPEED_PATTERNADD);
2446 PPPoint p = control->getLocation();
2447 p.y+=dy;
2448 control->setLocation(p);
2449 control = container->getControlByID(STATICTEXT_SPEED_PATTERNADD_DESC);
2450 p = control->getLocation();
2451 p.y+=dy;
2452 control->setLocation(p);
2453 control = container->getControlByID(BUTTON_ADD_PLUS);
2454 p = control->getLocation();
2455 p.y+=dy;
2456 control->setLocation(p);
2457 control = container->getControlByID(BUTTON_ADD_MINUS);
2458 p = control->getLocation();
2459 p.y+=dy;
2460 control->setLocation(p);
2461 }
2462 }
2463
enableInstrument(bool b)2464 void Tracker::enableInstrument(bool b)
2465 {
2466 getPatternEditorControl()->enableInstrument(b);
2467 PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_INSTRUMENTLIST));
2468 ASSERT(container);
2469 PPButton* button = static_cast<PPButton*>(container->getControlByID(BUTTON_INSTRUMENT));
2470 ASSERT(button);
2471 button->setPressed(b);
2472 listBoxInstruments->setOnlyShowIndexSelection(!b);
2473 screen->paintControl(listBoxInstruments);
2474 screen->paintControl(button);
2475 }
2476
commitListBoxChanges()2477 void Tracker::commitListBoxChanges()
2478 {
2479 if (listBoxInstruments->isEditing())
2480 listBoxInstruments->commitChanges();
2481
2482 if (listBoxSamples->isEditing())
2483 listBoxSamples->commitChanges();
2484 }
2485
getCurrentSelectedSampleSaveType()2486 FileTypes Tracker::getCurrentSelectedSampleSaveType()
2487 {
2488 return (FileTypes)sectionDiskMenu->getCurrentSelectedSampleSaveType();
2489 }
2490
fileTypeToHint(FileTypes type)2491 pp_uint32 Tracker::fileTypeToHint(FileTypes type)
2492 {
2493 switch (type)
2494 {
2495 case FileTypes::FileTypeSongAllModules:
2496 case FileTypes::FileTypeSongMOD:
2497 case FileTypes::FileTypeSongXM:
2498 return DecompressorBase::HintModules;
2499
2500 case FileTypes::FileTypePatternXP:
2501 return DecompressorBase::HintPatterns;
2502
2503 case FileTypes::FileTypeTrackXT:
2504 return DecompressorBase::HintTracks;
2505
2506 case FileTypes::FileTypeSongAllInstruments:
2507 case FileTypes::FileTypeInstrumentXI:
2508 return DecompressorBase::HintInstruments;
2509
2510 case FileTypes::FileTypeSongAllSamples:
2511 case FileTypes::FileTypeSampleWAV:
2512 case FileTypes::FileTypeSampleIFF:
2513 return DecompressorBase::HintSamples;
2514
2515 default:
2516 return DecompressorBase::HintAll;
2517
2518 }
2519 }
2520
prepareLoadSaveUI()2521 void Tracker::prepareLoadSaveUI()
2522 {
2523 #ifdef __LOWRES__
2524 // The bottom section fills up the entire screen
2525 // so we first need to hide the entire section before we can show the disk menu
2526 screen->pauseUpdate(true);
2527 sectionSwitcher->hideBottomSection();
2528 #endif
2529 }
2530
finishLoadSaveUI()2531 void Tracker::finishLoadSaveUI()
2532 {
2533 #ifdef __LOWRES__
2534 screen->pauseUpdate(false);
2535 screen->paint();
2536 #endif
2537 }
2538
loadGenericFileType(const PPSystemString & fileName)2539 bool Tracker::loadGenericFileType(const PPSystemString& fileName)
2540 {
2541 // we need to find out what file type this is
2542 // so we can do appropriate loading
2543 FileIdentificator* fileIdentificator = new FileIdentificator(fileName);
2544 FileIdentificator::FileTypes type = fileIdentificator->getFileType();
2545 delete fileIdentificator;
2546 // check for compression
2547 if (type == FileIdentificator::FileTypeCompressed)
2548 {
2549 // if this is compressed, we try to uncompress it
2550 // and choose that file type
2551 PPSystemString tempFile(ModuleEditor::getTempFilename());
2552 Decompressor decompressor(fileName);
2553 if (decompressor.decompress(tempFile, (DecompressorBase::Hints)fileTypeToHint(FileTypes::FileTypeAllFiles)))
2554 {
2555 fileIdentificator = new FileIdentificator(tempFile);
2556 type = fileIdentificator->getFileType();
2557 delete fileIdentificator;
2558 Decompressor::removeFile(tempFile);
2559 }
2560 else
2561 {
2562 showMessageBox(MESSAGEBOX_UNIVERSAL, "Unrecognized type/corrupt file", MessageBox_OK);
2563 return false;
2564 }
2565 }
2566
2567 switch (type)
2568 {
2569 case FileIdentificator::FileTypeModule:
2570 return loadTypeFromFile(FileTypes::FileTypeSongAllModules, fileName);
2571 case FileIdentificator::FileTypeInstrument:
2572 return loadTypeFromFile(FileTypes::FileTypeSongAllInstruments, fileName);
2573 case FileIdentificator::FileTypeSample:
2574 return loadTypeFromFile(FileTypes::FileTypeSongAllSamples, fileName);
2575 case FileIdentificator::FileTypePattern:
2576 return loadTypeFromFile(FileTypes::FileTypePatternXP, fileName);
2577 case FileIdentificator::FileTypeTrack:
2578 return loadTypeFromFile(FileTypes::FileTypeTrackXT, fileName);
2579 default:
2580 return false;
2581 }
2582 }
2583
prepareLoading(FileTypes eType,const PPSystemString & fileName,bool suspendPlayer,bool repaint,bool saveCheck)2584 bool Tracker::prepareLoading(FileTypes eType, const PPSystemString& fileName, bool suspendPlayer, bool repaint, bool saveCheck)
2585 {
2586 loadingParameters.deleteFile = false;
2587 loadingParameters.didOpenTab = false;
2588 loadingParameters.eType = eType;
2589 loadingParameters.filename = fileName;
2590 loadingParameters.preferredFilename = fileName;
2591 loadingParameters.suspendPlayer = suspendPlayer;
2592 loadingParameters.repaint = repaint;
2593
2594 loadingParameters.res = true;
2595
2596 if (saveCheck && eType == FileTypes::FileTypeSongAllModules && !checkForChangesOpenModule())
2597 return false;
2598
2599 loadingParameters.lastError = "Error while loading/unknown format";
2600
2601 signalWaitState(true);
2602
2603 if (eType == FileTypes::FileTypeSongAllModules &&
2604 settingsDatabase->restore("TABS_LOADMODULEINNEWTAB")->getBoolValue() &&
2605 (moduleEditor->hasChanged() || !moduleEditor->isEmpty()))
2606 {
2607 loadingParameters.didOpenTab = true;
2608 tabManager->openNewTab();
2609 }
2610
2611 bool rowPlay = playerController->isPlayingRowOnly();
2612 loadingParameters.wasPlaying = rowPlay ? false : (playerController->isPlaying() || playerController->isPlayingPattern());
2613 loadingParameters.wasPlayingPattern = rowPlay ? false : playerController->isPlayingPattern();
2614
2615 if (loadingParameters.suspendPlayer)
2616 {
2617 #ifndef __LOWRES__
2618 scopesControl->enable(false);
2619 #endif
2620 playerController->suspendPlayer();
2621 }
2622
2623 // check for compressed file type
2624 FileIdentificator* fileIdentificator = new FileIdentificator(fileName);
2625 FileIdentificator::FileTypes type = fileIdentificator->getFileType();
2626 delete fileIdentificator;
2627
2628 if (type == FileIdentificator::FileTypeCompressed)
2629 {
2630 // if this is compressed, try to decompress
2631 PPSystemString tempFile(ModuleEditor::getTempFilename());
2632 Decompressor decompressor(fileName);
2633 if (decompressor.decompress(tempFile, (DecompressorBase::Hints)fileTypeToHint(eType)))
2634 {
2635 // we compressed to a temporary file
2636 // load that instead, but keep the original file name as preferred
2637 // base name for the module we're going to edit
2638 loadingParameters.preferredFilename = loadingParameters.filename;
2639 loadingParameters.filename = tempFile;
2640 // delete file after loading, it's temporary
2641 loadingParameters.deleteFile = true;
2642 }
2643 else
2644 {
2645 loadingParameters.lastError = "Unrecognized type/corrupt file";
2646 loadingParameters.res = false;
2647 finishLoading();
2648 return false;
2649 }
2650 }
2651
2652 return true;
2653 }
2654
finishLoading()2655 bool Tracker::finishLoading()
2656 {
2657 signalWaitState(false);
2658
2659 if (loadingParameters.repaint)
2660 {
2661 screen->paint();
2662 updateWindowTitle(moduleEditor->getModuleFileName());
2663 }
2664
2665 if (!loadingParameters.res && !loadingParameters.abortLoading)
2666 showMessageBox(MESSAGEBOX_UNIVERSAL, loadingParameters.lastError, MessageBox_OK);
2667
2668 if (loadingParameters.suspendPlayer)
2669 {
2670 playerController->resumePlayer(true);
2671 scopesControl->enable(true);
2672 }
2673
2674 if (loadingParameters.deleteFile)
2675 Decompressor::removeFile(loadingParameters.filename);
2676
2677 if (!loadingParameters.res && loadingParameters.didOpenTab)
2678 tabManager->closeTab();
2679
2680 return loadingParameters.abortLoading ? true : loadingParameters.res;
2681 }
2682
loadTypeFromFile(FileTypes eType,const PPSystemString & fileName,bool suspendPlayer,bool repaint,bool saveCheck)2683 bool Tracker::loadTypeFromFile(FileTypes eType, const PPSystemString& fileName, bool suspendPlayer/* = true*/, bool repaint/* = true*/, bool saveCheck/* = true*/)
2684 {
2685 bool res = prepareLoading(eType, fileName, suspendPlayer, repaint, saveCheck);
2686 if (!res)
2687 return false;
2688
2689 switch (eType)
2690 {
2691 case FileTypes::FileTypeSongAllModules:
2692 {
2693 if (loadingParameters.preferredFilename.length())
2694 loadingParameters.res = moduleEditor->openSong(loadingParameters.filename,
2695 loadingParameters.preferredFilename);
2696 else
2697 loadingParameters.res = moduleEditor->openSong(loadingParameters.filename,
2698 NULL);
2699
2700 updateAfterLoad(loadingParameters.res, loadingParameters.wasPlaying, loadingParameters.wasPlayingPattern);
2701 break;
2702 }
2703
2704 case FileTypes::FileTypePatternXP:
2705 {
2706 loadingParameters.res = getPatternEditor()->loadExtendedPattern(loadingParameters.filename);
2707 updateSongInfo();
2708 break;
2709 }
2710
2711 case FileTypes::FileTypeTrackXT:
2712 {
2713 loadingParameters.res = getPatternEditor()->loadExtendedTrack(loadingParameters.filename);
2714 updateSongInfo();
2715 break;
2716 }
2717
2718 case FileTypes::FileTypeSongAllInstruments:
2719 {
2720 loadingParameters.res = moduleEditor->loadInstrument(loadingParameters.filename, listBoxInstruments->getSelectedIndex());
2721 sectionInstruments->updateAfterLoad();
2722 break;
2723 }
2724
2725 case FileTypes::FileTypeSongAllSamples:
2726 {
2727 pp_int32 numSampleChannels = moduleEditor->getNumSampleChannels(loadingParameters.filename);
2728
2729 pp_int32 chnIndex = 0;
2730 if (numSampleChannels <= 0)
2731 {
2732 loadingParameters.res = false;
2733 break;
2734 }
2735 else if (numSampleChannels > 1 &&
2736 !settingsDatabase->restore("AUTOMIXDOWNSAMPLES")->getIntValue())
2737 {
2738 if (dialog)
2739 delete dialog;
2740
2741 if (responder)
2742 delete responder;
2743
2744 responder = new SampleLoadChannelSelectionHandler(*this);
2745 dialog = new DialogChannelSelector(screen, responder, PP_DEFAULT_ID, "Choose channel to load" PPSTR_PERIODS);
2746
2747 // Add names of sample channels to instrument box
2748 for (pp_int32 i = 0; i < numSampleChannels; i++)
2749 static_cast<DialogChannelSelector*>(dialog)->getListBox()->addItem(moduleEditor->getNameOfSampleChannel(loadingParameters.filename, i));
2750
2751 static_cast<SampleLoadChannelSelectionHandler*>(responder)->setCurrentFileName(loadingParameters.filename);
2752 static_cast<SampleLoadChannelSelectionHandler*>(responder)->setPreferredFileName(loadingParameters.preferredFilename);
2753 static_cast<SampleLoadChannelSelectionHandler*>(responder)->suspendPlayer = suspendPlayer;
2754
2755 signalWaitState(false);
2756
2757 dialog->show();
2758 return true;
2759 }
2760 else if (numSampleChannels > 1 &&
2761 settingsDatabase->restore("AUTOMIXDOWNSAMPLES")->getIntValue())
2762 {
2763 chnIndex = -1;
2764 }
2765
2766 if (loadingParameters.preferredFilename.length())
2767 loadingParameters.res = moduleEditor->loadSample(loadingParameters.filename,
2768 listBoxInstruments->getSelectedIndex(),
2769 listBoxSamples->getSelectedIndex(),
2770 chnIndex,
2771 loadingParameters.preferredFilename);
2772 else
2773 loadingParameters.res = moduleEditor->loadSample(loadingParameters.filename,
2774 listBoxInstruments->getSelectedIndex(),
2775 listBoxSamples->getSelectedIndex(),
2776 chnIndex);
2777
2778 sectionSamples->updateAfterLoad();
2779 break;
2780 }
2781
2782 }
2783
2784 return finishLoading();
2785 }
2786
2787 // load different things
loadTypeWithDialog(FileTypes eLoadType,bool suspendPlayer,bool repaint)2788 bool Tracker::loadTypeWithDialog(FileTypes eLoadType, bool suspendPlayer/* = true*/, bool repaint/* = true*/)
2789 {
2790 FileExtProvider fileExtProvider;
2791
2792 PPOpenPanel* openPanel = NULL;
2793
2794 switch (eLoadType)
2795 {
2796 case FileTypes::FileTypeSongAllModules:
2797 {
2798 if (!checkForChangesOpenModule())
2799 return false;
2800 openPanel = new PPOpenPanel(screen, "Open Module");
2801 openPanel->addExtensions(fileExtProvider.getModuleExtensions());
2802 break;
2803 }
2804
2805 case FileTypes::FileTypePatternXP:
2806 {
2807 openPanel = new PPOpenPanel(screen, "Open Extended Pattern");
2808 openPanel->addExtensions(fileExtProvider.getPatternExtensions());
2809 break;
2810 }
2811
2812 case FileTypes::FileTypeTrackXT:
2813 {
2814 openPanel = new PPOpenPanel(screen, "Open Extended Track");
2815 openPanel->addExtensions(fileExtProvider.getTrackExtensions());
2816 break;
2817 }
2818
2819 case FileTypes::FileTypeSongAllInstruments:
2820 {
2821 openPanel = new PPOpenPanel(screen, "Open Instrument");
2822 openPanel->addExtensions(fileExtProvider.getInstrumentExtensions());
2823 break;
2824 }
2825
2826 case FileTypes::FileTypeSongAllSamples:
2827 {
2828 openPanel = new PPOpenPanel(screen, "Open Sample");
2829 openPanel->addExtensions(fileExtProvider.getSampleExtensions());
2830 break;
2831 }
2832 }
2833
2834 if (!openPanel)
2835 return false;
2836
2837 bool res = true;
2838
2839 if (openPanel->runModal() == PPModalDialog::ReturnCodeOK)
2840 {
2841 PPSystemString file = openPanel->getFileName();
2842
2843 if (file.length())
2844 {
2845 PPSystemString fileName = file;
2846 res = loadTypeFromFile(eLoadType, fileName, suspendPlayer, repaint, false);
2847 }
2848
2849 delete openPanel;
2850 }
2851
2852 return res;
2853 }
2854
loadType(FileTypes eType)2855 void Tracker::loadType(FileTypes eType)
2856 {
2857 if (useClassicBrowser)
2858 {
2859 prepareLoadSaveUI();
2860
2861 sectionDiskMenu->selectSaveType(eType);
2862 eventKeyDownBinding_InvokeSectionDiskMenu();
2863
2864 finishLoadSaveUI();
2865 }
2866 else
2867 {
2868 loadTypeWithDialog(eType);
2869 }
2870 }
2871
prepareSavingWithDialog(FileTypes eSaveType)2872 bool Tracker::prepareSavingWithDialog(FileTypes eSaveType)
2873 {
2874 FileExtProvider fileExtProvider;
2875
2876 currentSaveFileType = eSaveType;
2877
2878 switch (eSaveType)
2879 {
2880 case FileTypes::FileTypeSongMOD:
2881 {
2882 savePanel = new PPSavePanel(screen, "Save Protracker Module", moduleEditor->getModuleFileName(ModuleEditor::ModSaveTypeMOD));
2883 savePanel->addExtension(fileExtProvider.getModuleExtension(FileExtProvider::ModuleExtensionMOD),
2884 fileExtProvider.getModuleDescription(FileExtProvider::ModuleExtensionMOD));
2885
2886 pp_uint32 err = moduleEditor->getPTIncompatibilityCode();
2887
2888 if (err)
2889 {
2890 buildMODSaveErrorWarning(err);
2891 return false;
2892 }
2893 break;
2894 }
2895
2896 case FileTypes::FileTypeSongXM:
2897 savePanel = new PPSavePanel(screen, "Save Extended Module", moduleEditor->getModuleFileName(ModuleEditor::ModSaveTypeXM));
2898 savePanel->addExtension(fileExtProvider.getModuleExtension(FileExtProvider::ModuleExtensionXM),
2899 fileExtProvider.getModuleDescription(FileExtProvider::ModuleExtensionXM));
2900 break;
2901
2902 case FileTypes::FileTypePatternXP:
2903 {
2904 PPSystemString fileName = moduleEditor->getModuleFileName().stripExtension();
2905 fileName.append(".xp");
2906 savePanel = new PPSavePanel(screen, "Save Extended Pattern", fileName);
2907 savePanel->addExtension(fileExtProvider.getPatternExtension(FileExtProvider::PatternExtensionXP),
2908 fileExtProvider.getPatternDescription(FileExtProvider::PatternExtensionXP));
2909 break;
2910 }
2911
2912 case FileTypes::FileTypeTrackXT:
2913 {
2914 PPSystemString fileName = moduleEditor->getModuleFileName().stripExtension();
2915 fileName.append(".xt");
2916 savePanel = new PPSavePanel(screen, "Save Extended Track", fileName);
2917 savePanel->addExtension(fileExtProvider.getTrackExtension(FileExtProvider::TrackExtensionXT),
2918 fileExtProvider.getTrackDescription(FileExtProvider::TrackExtensionXT));
2919 break;
2920 }
2921
2922 case FileTypes::FileTypeInstrumentXI:
2923 {
2924 PPSystemString sampleFileName = moduleEditor->getInstrumentFileName(listBoxInstruments->getSelectedIndex());
2925 sampleFileName.append(".xi");
2926 savePanel = new PPSavePanel(screen, "Save Instrument", sampleFileName);
2927 savePanel->addExtension(fileExtProvider.getInstrumentExtension(FileExtProvider::InstrumentExtensionXI),
2928 fileExtProvider.getInstrumentDescription(FileExtProvider::InstrumentExtensionXI));
2929 break;
2930 }
2931
2932 case FileTypes::FileTypeSampleWAV:
2933 {
2934 PPSystemString sampleFileName = moduleEditor->getSampleFileName(listBoxInstruments->getSelectedIndex(), listBoxSamples->getSelectedIndex());
2935 sampleFileName.append(".wav");
2936 savePanel = new PPSavePanel(screen, "Save uncompressed WAV",sampleFileName);
2937 savePanel->addExtension(fileExtProvider.getSampleExtension(FileExtProvider::SampleExtensionWAV),
2938 fileExtProvider.getSampleDescription(FileExtProvider::SampleExtensionWAV));
2939 break;
2940 }
2941
2942 case FileTypes::FileTypeSampleIFF:
2943 {
2944 PPSystemString sampleFileName = moduleEditor->getSampleFileName(listBoxInstruments->getSelectedIndex(), listBoxSamples->getSelectedIndex());
2945 sampleFileName.append(".iff");
2946 savePanel = new PPSavePanel(screen, "Save uncompressed IFF",sampleFileName);
2947 savePanel->addExtension(fileExtProvider.getSampleExtension(FileExtProvider::SampleExtensionIFF),
2948 fileExtProvider.getSampleDescription(FileExtProvider::SampleExtensionIFF));
2949 break;
2950 }
2951 }
2952
2953 return true;
2954 }
2955
2956 // Save different things
saveTypeWithDialog(FileTypes eSaveType,EventListenerInterface * fileSystemChangedListener)2957 bool Tracker::saveTypeWithDialog(FileTypes eSaveType, EventListenerInterface* fileSystemChangedListener/* = NULL*/)
2958 {
2959 if (savePanel == NULL)
2960 {
2961 if (!prepareSavingWithDialog(eSaveType))
2962 {
2963 this->fileSystemChangedListener = fileSystemChangedListener;
2964 return true;
2965 }
2966
2967 if (!savePanel)
2968 return true;
2969 }
2970
2971 bool res = true;
2972
2973 if (savePanel->runModal() == PPModalDialog::ReturnCodeOK)
2974 {
2975 PPSystemString file = savePanel->getFileName();
2976
2977 if (file.length())
2978 {
2979 loadingParameters.lastError = "Error while saving";
2980
2981 signalWaitState(true);
2982
2983 switch (eSaveType)
2984 {
2985 case FileTypes::FileTypeSongMOD:
2986 commitListBoxChanges();
2987 res = moduleEditor->saveSong(file, ModuleEditor::ModSaveTypeMOD);
2988 break;
2989
2990 case FileTypes::FileTypeSongXM:
2991 commitListBoxChanges();
2992 res = moduleEditor->saveSong(file, ModuleEditor::ModSaveTypeXM);
2993 break;
2994
2995 case FileTypes::FileTypeTrackXT:
2996 {
2997 res = getPatternEditor()->saveExtendedTrack(file);
2998 break;
2999 }
3000
3001 case FileTypes::FileTypePatternXP:
3002 {
3003 res = getPatternEditor()->saveExtendedPattern(file);
3004 break;
3005 }
3006
3007 case FileTypes::FileTypeInstrumentXI:
3008 commitListBoxChanges();
3009 res = moduleEditor->saveInstrument(file, listBoxInstruments->getSelectedIndex());
3010 break;
3011
3012 case FileTypes::FileTypeSampleWAV:
3013 commitListBoxChanges();
3014 res = moduleEditor->saveSample(file, listBoxInstruments->getSelectedIndex(),
3015 listBoxSamples->getSelectedIndex(), ModuleEditor::SampleFormatTypeWAV);
3016 break;
3017
3018 case FileTypes::FileTypeSampleIFF:
3019 commitListBoxChanges();
3020 res = moduleEditor->saveSample(file, listBoxInstruments->getSelectedIndex(),
3021 listBoxSamples->getSelectedIndex(), ModuleEditor::SampleFormatTypeIFF);
3022 break;
3023 }
3024
3025 if (res && fileSystemChangedListener)
3026 {
3027 PPEvent event(eFileSystemChanged);
3028 fileSystemChangedListener->handleEvent(reinterpret_cast<PPObject*>(this), &event);
3029 }
3030
3031 signalWaitState(false);
3032 screen->paint();
3033 updateWindowTitle(moduleEditor->getModuleFileName());
3034 }
3035
3036 }
3037
3038 if (!res)
3039 showMessageBox(MESSAGEBOX_UNIVERSAL, loadingParameters.lastError, MessageBox_OK);
3040
3041 delete savePanel;
3042 savePanel = NULL;
3043 fileSystemChangedListener = NULL;
3044
3045 return res;
3046 }
3047
saveCurrentModuleAsSelectedType()3048 bool Tracker::saveCurrentModuleAsSelectedType()
3049 {
3050 signalWaitState(true);
3051
3052 loadingParameters.lastError = "Error while saving.\nFile might be write protected.";
3053
3054 pp_int32 res = moduleEditor->saveSong(moduleEditor->getModuleFileNameFull(), moduleEditor->getSaveType());
3055 signalWaitState(false);
3056
3057 if (!res)
3058 showMessageBoxSized(MESSAGEBOX_UNIVERSAL, loadingParameters.lastError, MessageBox_OK, -1, -1);
3059
3060 screen->paint();
3061
3062 if (res)
3063 updateWindowTitle();
3064
3065 return res == 0;
3066 }
3067
saveType(FileTypes eType)3068 void Tracker::saveType(FileTypes eType)
3069 {
3070 if (useClassicBrowser)
3071 {
3072 prepareLoadSaveUI();
3073
3074 sectionDiskMenu->selectSaveType(eType);
3075
3076 if (eType == FileTypes::FileTypeSongWAV)
3077 sectionDiskMenu->setModuleTypeAdjust(false);
3078
3079 eventKeyDownBinding_InvokeSectionDiskMenu();
3080
3081 if (eType == FileTypes::FileTypeSongWAV)
3082 sectionDiskMenu->setModuleTypeAdjust(true);
3083
3084 finishLoadSaveUI();
3085 }
3086 else
3087 {
3088 saveTypeWithDialog(eType);
3089 }
3090 }
3091
save()3092 void Tracker::save()
3093 {
3094 if (TrackerConfig::untitledSong.compareTo(moduleEditor->getModuleFileNameFull().stripExtension()) == 0)
3095 {
3096 saveAs();
3097 }
3098 else
3099 {
3100 if (moduleEditor->getSaveType() == ModuleEditor::ModSaveTypeMOD)
3101 {
3102 pp_uint32 err = moduleEditor->getPTIncompatibilityCode();
3103
3104 if (err)
3105 {
3106 // remove save panel
3107 // => the handler for the upcoming modal dialog
3108 // will note from the absent save panel that saving will be
3109 // done to the current document
3110 if (savePanel)
3111 {
3112 delete savePanel;
3113 savePanel = NULL;
3114 }
3115 buildMODSaveErrorWarning((pp_int32)err);
3116 return;
3117 }
3118 }
3119 saveCurrentModuleAsSelectedType();
3120 }
3121 }
3122
saveAs()3123 void Tracker::saveAs()
3124 {
3125 switch (moduleEditor->getSaveType())
3126 {
3127 case ModuleEditor::ModSaveTypeMOD:
3128 saveType(FileTypes::FileTypeSongMOD);
3129 break;
3130
3131 case ModuleEditor::ModSaveTypeXM:
3132 saveType(FileTypes::FileTypeSongXM);
3133 break;
3134
3135 default:
3136 ASSERT(false);
3137 }
3138 }
3139
handleSaveProceed()3140 void Tracker::handleSaveProceed()
3141 {
3142 // if there is a save panel present we save with file name
3143 // selection, otherwise we simply save the current document
3144 // in the current format
3145 if (savePanel != NULL)
3146 saveTypeWithDialog(currentSaveFileType, fileSystemChangedListener);
3147 else
3148 saveCurrentModuleAsSelectedType();
3149 }
3150
handleSaveCancel()3151 void Tracker::handleSaveCancel()
3152 {
3153 delete savePanel;
3154 savePanel = NULL;
3155 }
3156
buildMODSaveErrorWarning(pp_int32 error)3157 void Tracker::buildMODSaveErrorWarning(pp_int32 error)
3158 {
3159 static const char* warnings[] = {"Song contains more than 31 instruments\nSave anyway?",
3160
3161 "Song uses linear frequencies\nSave anyway?",
3162
3163 "Song contains incompatible samples \n\n"\
3164 "Check for the following conditions:\n"\
3165 "* No 16 bit samples \n"\
3166 "* All samples are below 64kb \n"\
3167 "* No ping-pong looping \n"\
3168 "* Panning is set to 0x80 (middle) \n"\
3169 "* Relative note is C-4 (number 0) \n\nSave anyway?",
3170
3171 "Song contains FT2-style instruments\n\n"\
3172 "Check for the following conditions:\n"\
3173 "* No envelopes \n"\
3174 "* No autovibrato \n"\
3175 "* Only one sample per instrument \n\nSave anyway?",
3176
3177 "Incompatible pattern data \n\n"\
3178 "Check for the following conditions:\n"\
3179 "* Pattern length is exactly 64 rows\n"\
3180 "* Only notes between C-3 and B-5 \n"\
3181 "* Volume column is not used \n"\
3182 "* Only effects between 0 and F \n\nSave anyway?"};
3183
3184 if (dialog)
3185 delete dialog;
3186
3187 if (responder)
3188 delete responder;
3189
3190 responder = new SaveProceedHandler(*this);
3191
3192 dialog = new PPDialogBase(screen, responder, MESSAGEBOX_SAVEPROCEED, "");
3193
3194 showMessageBoxSized(MESSAGEBOX_SAVEPROCEED, warnings[error-1], MessageBox_YESNO, 318, -1, false);
3195
3196 // Transfer ownership of modal overlayed container to dialog
3197 // => also set new event listener
3198 dialog->setMessageBoxContainer(messageBoxContainerGeneric);
3199 messageBoxContainerGeneric->setEventListener(dialog);
3200 PPSimpleVector<PPControl>& controls = messageBoxContainerGeneric->getControls();
3201 for (pp_int32 i = 0; i < controls.size(); i++)
3202 controls.get(i)->setEventListener(dialog);
3203
3204 messageBoxContainerGeneric = NULL;
3205
3206 dialog->show();
3207 }
3208
estimateSongLength(bool signalWait)3209 void Tracker::estimateSongLength(bool signalWait/* = false*/)
3210 {
3211 if (signalWait)
3212 signalWaitState(true);
3213
3214 moduleEditor->getModuleServices()->estimateSongLength();
3215
3216 if (signalWait)
3217 {
3218 signalWaitState(false);
3219 screen->update();
3220 }
3221 }
3222
signalWaitState(bool b)3223 void Tracker::signalWaitState(bool b)
3224 {
3225 screen->signalWaitState(b, TrackerConfig::colorThemeMain);
3226 }
3227
3228