1 /*
2 * tracker/TabManager.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 /*
24 * TabManager.cpp
25 * MilkyTracker
26 *
27 * Created by Peter Barth on 20.12.07.
28 *
29 */
30
31 #include "TabManager.h"
32 #include "Tracker.h"
33 #include "SimpleVector.h"
34 #include "PlayerMaster.h"
35 #include "PlayerController.h"
36 #include "PlayerLogic.h"
37 #include "ModuleEditor.h"
38 #include "PatternEditor.h"
39 #include "TabHeaderControl.h"
40 #include "TabTitleProvider.h"
41 #include "ControlIDs.h"
42 #include "Screen.h"
43 #include "Container.h"
44 #include "TrackerSettingsDatabase.h"
45 #include "Tools.h"
46 #include "Zapper.h"
47
Document(ModuleEditor * moduleEditor,PlayerController * playerController)48 TabManager::Document::Document(ModuleEditor* moduleEditor, PlayerController* playerController) :
49 moduleEditor(moduleEditor),
50 playerController(playerController)
51 {
52 }
53
~Document()54 TabManager::Document::~Document()
55 {
56 // player controller is deleted from the PlayerMaster
57 delete moduleEditor;
58 }
59
TabManager(Tracker & tracker)60 TabManager::TabManager(Tracker& tracker) :
61 tracker(tracker),
62 currentDocument(NULL),
63 stopOnTabSwitch(false),
64 resumeOnTabSwitch(false)
65 {
66 documents = new PPSimpleVector<Document>();
67 }
68
~TabManager()69 TabManager::~TabManager()
70 {
71 delete documents;
72 }
73
getTabHeaderControl()74 TabHeaderControl* TabManager::getTabHeaderControl()
75 {
76 return static_cast<TabHeaderControl*>(tracker.screen->getControlByID(TABHEADER_CONTROL));
77 }
78
createModuleEditor()79 ModuleEditor* TabManager::createModuleEditor()
80 {
81 ModuleEditor* moduleEditor = new ModuleEditor();
82 moduleEditor->createNewSong(tracker.playerController->getPlayMode() == PlayerController::PlayMode_FastTracker2 ? 8 : 4);
83 moduleEditor->setCurrentPatternIndex(moduleEditor->getOrderPosition(0));
84 return moduleEditor;
85 }
86
createPlayerController()87 PlayerController* TabManager::createPlayerController()
88 {
89 // use "fake" scopes on the PDA
90 // fake scopes are always showing linear interpolated output
91 #ifdef __LOWRES__
92 PlayerController* playerController = tracker.playerMaster->createPlayerController(true);
93 #else
94 PlayerController* playerController = tracker.playerMaster->createPlayerController(false);
95 #endif
96
97 if (playerController == NULL)
98 return NULL;
99
100 applyPlayerDefaults(playerController);
101 return playerController;
102 }
103
applyPlayerDefaults(PlayerController * playerController)104 void TabManager::applyPlayerDefaults(PlayerController* playerController)
105 {
106 PPString value = tracker.settingsDatabase->restore("PLAYMODE")->getStringValue();
107 if (value.compareTo("PROTRACKER2") == 0)
108 {
109 playerController->switchPlayMode(PlayerController::PlayMode_ProTracker2, false);
110 }
111 else if (value.compareTo("PROTRACKER3") == 0)
112 {
113 playerController->switchPlayMode(PlayerController::PlayMode_ProTracker3, false);
114 }
115 else
116 {
117 playerController->switchPlayMode(PlayerController::PlayMode_FastTracker2, false);
118 }
119
120 bool v = tracker.settingsDatabase->restore("PLAYMODE_ADVANCED_ALLOW8xx")->getBoolValue();
121 playerController->enablePlayModeOption(PlayerController::PlayModeOptionPanning8xx, v);
122
123 v = tracker.settingsDatabase->restore("PLAYMODE_ADVANCED_ALLOWE8x")->getBoolValue();
124 playerController->enablePlayModeOption(PlayerController::PlayModeOptionPanningE8x, v);
125
126 v = tracker.settingsDatabase->restore("PLAYMODE_ADVANCED_PTPITCHLIMIT")->getBoolValue();
127 playerController->enablePlayModeOption(PlayerController::PlayModeOptionForcePTPitchLimit, v);
128
129 value = tracker.settingsDatabase->restore("PLAYMODE_ADVANCED_PTPANNING")->getStringValue();
130 {
131 pp_uint8* panning = new pp_uint8[TrackerConfig::numPlayerChannels];
132 if (PPTools::decodeByteArray(panning, TrackerConfig::numPlayerChannels, value))
133 {
134 pp_int32 i;
135 for (i = 0; i < TrackerConfig::numPlayerChannels; i++)
136 playerController->setPanning((pp_uint8)i, panning[i]);
137 }
138 delete[] panning;
139 }
140
141 }
142
openNewTab(PlayerController * playerController,ModuleEditor * moduleEditor)143 void TabManager::openNewTab(PlayerController* playerController/* = NULL*/, ModuleEditor* moduleEditor/* = NULL*/)
144 {
145 #ifndef __LOWRES__
146 TabHeaderControl* tabHeader = getTabHeaderControl();
147
148 if (playerController == NULL)
149 {
150 playerController = createPlayerController();
151 if (playerController == NULL)
152 {
153 tracker.showMessageBox(MESSAGEBOX_UNIVERSAL, "Too many open modules.", Tracker::MessageBox_OK);
154 return;
155 }
156 }
157
158 if (moduleEditor == NULL)
159 {
160 moduleEditor = createModuleEditor();
161 }
162
163 playerController->attachModuleEditor(moduleEditor);
164 moduleEditor->attachPlayerCriticalSection(playerController->getCriticalSection());
165 playerController->setSpeed(moduleEditor->getSongBPM(), moduleEditor->getSongTickSpeed());
166
167 Document* doc = new Document(moduleEditor, playerController);
168 documents->add(doc);
169
170 TabTitleProvider tabTitleProvider(*moduleEditor);
171 PPString tabTitle = tabTitleProvider.getTabTitle();
172 tabHeader->addTab(TabHeaderControl::TabHeader(tabTitle, documents->size()-1));
173 selectModuleEditor(doc);
174 #else
175 if (moduleEditor == NULL || playerController == NULL)
176 return;
177
178 playerController->attachModuleEditor(moduleEditor);
179 moduleEditor->attachPlayerCriticalSection(playerController->getCriticalSection());
180 playerController->setSpeed(moduleEditor->getSongBPM(), moduleEditor->getSongTickSpeed());
181
182 documents->add(new Document(moduleEditor, playerController));
183 #endif
184 }
185
switchToTab(pp_uint32 index)186 void TabManager::switchToTab(pp_uint32 index)
187 {
188 #ifndef __LOWRES__
189 TabHeaderControl* tabHeader = getTabHeaderControl();
190 ASSERT(tabHeader);
191 index = tabHeader->getTab(index)->ID;
192 selectModuleEditor(documents->get(index));
193 #endif
194 }
195
closeTab(pp_int32 index)196 void TabManager::closeTab(pp_int32 index/* = -1*/)
197 {
198 #ifndef __LOWRES__
199 TabHeaderControl* tabHeader = getTabHeaderControl();
200
201 // when there is only a single tab open
202 // we zap the module if it has changed or is not empty
203 if (tabHeader->getNumTabs() <= 1)
204 {
205 if (tracker.moduleEditor->hasChanged() ||
206 !tracker.moduleEditor->isEmpty())
207 {
208 Zapper zapper(tracker);
209 zapper.zapAll();
210 tracker.updateSongInfo(false);
211 tracker.screen->paint();
212 }
213 return;
214 }
215
216 if (index == -1)
217 index = tabHeader->getSelectedTabIndex();
218
219 pp_int32 moduleIndex = tabHeader->getTab(index)->ID;
220
221 bool res = tracker.checkForChanges(documents->get(moduleIndex)->moduleEditor);
222 if (!res)
223 return;
224
225 TabHeaderControl::TabHeader* tabs = new TabHeaderControl::TabHeader[tabHeader->getNumTabs()];
226
227 pp_int32 j = 0;
228 pp_int32 i;
229 for (i = 0; i < (signed)tabHeader->getNumTabs(); i++)
230 {
231 if (i != index)
232 {
233 tabs[j] = *tabHeader->getTab(i);
234 j++;
235 }
236 }
237
238 tabHeader->clear();
239
240 for (i = 0; i < j; i++)
241 {
242 if ((signed)tabs[i].ID > moduleIndex)
243 tabs[i].ID--;
244 }
245
246 Document* doc = documents->removeNoDestroy(moduleIndex);
247
248 if (index >= documents->size())
249 index = documents->size()-1;
250
251 for (i = 0; i < j; i++)
252 {
253 tabHeader->addTab(tabs[i]);
254 }
255
256 delete[] tabs;
257
258 tabHeader->setSelectedTab(index);
259
260 switchToTab(tabHeader->getTab(index)->ID);
261
262 if (doc->moduleEditor != tracker.moduleEditor)
263 {
264 tracker.playerMaster->destroyPlayerController(doc->playerController);
265 delete doc;
266 }
267 #endif
268 }
269
selectModuleEditor(Document * document)270 void TabManager::selectModuleEditor(Document* document)
271 {
272 #ifndef __LOWRES__
273 PPContainer* container = static_cast<PPContainer*>(tracker.screen->getControlByID(CONTAINER_OPENREMOVETABS));
274 ASSERT(container);
275 TabHeaderControl* tabHeader = getTabHeaderControl();
276 ASSERT(tabHeader);
277 container->show(tabHeader->getNumTabs() > 1);
278
279 if (tracker.moduleEditor != document->moduleEditor)
280 {
281 // store current position
282 tracker.moduleEditor->setCurrentCursorPosition(tracker.getPatternEditor()->getCursor());
283
284 // switch
285 tracker.moduleEditor = document->moduleEditor;
286 tracker.playerController = document->playerController;
287
288 if (stopOnTabSwitch)
289 tracker.playerLogic->stopAll();
290
291 if (tracker.playerController->isPaused())
292 {
293 if (!resumeOnTabSwitch)
294 tracker.playerLogic->stopSong();
295 tracker.playerController->unpause();
296 }
297
298 // update
299 tracker.updateAfterTabSwitch();
300 }
301 currentDocument = document;
302
303 #endif
304 }
305
getModuleEditorFromTabIndex(pp_int32 index)306 ModuleEditor* TabManager::getModuleEditorFromTabIndex(pp_int32 index)
307 {
308 #ifndef __LOWRES__
309 TabHeaderControl* tabHeader = getTabHeaderControl();
310 return documents->get(tabHeader->getTab(index)->ID)->moduleEditor;
311 #else
312 return tracker.moduleEditor;
313 #endif
314 }
315
getPlayerControllerFromTabIndex(pp_int32 index)316 PlayerController* TabManager::getPlayerControllerFromTabIndex(pp_int32 index)
317 {
318 #ifndef __LOWRES__
319 TabHeaderControl* tabHeader = getTabHeaderControl();
320 return documents->get(tabHeader->getTab(index)->ID)->playerController;
321 #else
322 return tracker.playerController;
323 #endif
324 }
325
getSelectedTabIndex()326 pp_uint32 TabManager::getSelectedTabIndex()
327 {
328 #ifndef __LOWRES__
329 TabHeaderControl* tabHeader = getTabHeaderControl();
330 return tabHeader->getSelectedTabIndex();
331 #else
332 return 0;
333 #endif
334 }
335
cycleTab(pp_int32 offset)336 void TabManager::cycleTab(pp_int32 offset)
337 {
338 #ifndef __LOWRES__
339 TabHeaderControl* tabHeader = getTabHeaderControl();
340 ASSERT(tabHeader);
341 pp_int32 index = tabHeader->getSelectedTabIndex();
342 index+=offset;
343 if (index >= (signed)tabHeader->getNumTabs())
344 index = tabHeader->getNumTabs()-1;
345 if (index < 0)
346 index = 0;
347
348 if (index != tabHeader->getSelectedTabIndex())
349 {
350 tabHeader->setSelectedTab(index);
351 tracker.screen->paintControl(tabHeader);
352 switchToTab(index);
353 }
354 #endif
355 }
356
getNumTabs() const357 pp_int32 TabManager::getNumTabs() const
358 {
359 return documents->size();
360 }
361