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