1 /*
2  *  tracker/TrackerUpdate.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 "TabManager.h"
25 #include "TrackerConfig.h"
26 #include "PlayerController.h"
27 #include "PlayerMaster.h"
28 #include "ModuleEditor.h"
29 #include "ModuleServices.h"
30 #include "TabTitleProvider.h"
31 #include "EnvelopeEditor.h"
32 #include "PatternTools.h"
33 #include "PPUIConfig.h"
34 #include "Container.h"
35 #include "ListBox.h"
36 #include "StaticText.h"
37 #include "PatternEditorControl.h"
38 #include "EnvelopeEditorControl.h"
39 #include "PianoControl.h"
40 #include "PeakLevelControl.h"
41 #include "ScopesControl.h"
42 #include "SampleEditorControl.h"
43 #include "TrackerSettingsDatabase.h"
44 #include "SectionInstruments.h"
45 #include "SectionSamples.h"
46 #include "SectionHDRecorder.h"
47 #include "SectionQuickOptions.h"
48 #include "TabHeaderControl.h"
49 #include "PPOpenPanel.h"
50 #include "TitlePageManager.h"
51 
52 #include "ControlIDs.h"
53 
updateAboutToggleButton(pp_int32 id,bool b,bool repaint)54 void Tracker::updateAboutToggleButton(pp_int32 id, bool b, bool repaint/* = true*/)
55 {
56 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_ABOUT));
57 	ASSERT(container);
58 	PPButton* button = static_cast<PPButton*>(container->getControlByID(id));
59 	if (button == NULL)
60 		return;
61 	button->setPressed(b);
62 
63 	if (repaint)
64 		screen->paintControl(button);
65 }
66 
updatePianoControl(PianoControl * pianoControl)67 bool Tracker::updatePianoControl(PianoControl* pianoControl)
68 {
69 	if (!pianoControl)
70 		return false;
71 
72 	if (!pianoControl->isVisible())
73 		return false;
74 
75 	pp_int32 ins = listBoxInstruments->getSelectedIndex() + 1;
76 
77 	pp_int32 i;
78 
79 	bool tab[ModuleEditor::MAX_NOTE];
80 
81 	for (i = 0; i < ModuleEditor::MAX_NOTE; i++)
82 	{
83 		tab[i] = pianoControl->getNoteState(i);
84 		pianoControl->pressNote(i, false);
85 	}
86 
87 	for (i = 0; i < playerController->getPlayerNumPlayingChannels(); i++)
88 	{
89 		pp_int32 note;
90 		bool muted = false;
91 		if (playerController->isNotePlaying(ins, i, note, muted))
92 			pianoControl->pressNote(note - 1, true, muted);
93 	}
94 
95 	bool update = false;
96 	for (i = 0; i < ModuleEditor::MAX_NOTE; i++)
97 	{
98 		if (pianoControl->getNoteState(i) != tab[i])
99 		{
100 			update = true;
101 			break;
102 		}
103 	}
104 
105 	if (update)
106 		screen->paintControl(pianoControl, false);
107 
108 	return update;
109 }
110 
updatePeakLevelControl()111 bool Tracker::updatePeakLevelControl()
112 {
113 	const pp_int32 maxPeakThreshold = 32700*2;
114 
115 	if (!peakLevelControl)
116 		return false;
117 
118 	if (!peakLevelControl->isVisible())
119 		return false;
120 
121 	bool bUpdateL = false;
122 	bool bUpdateR = false;
123 
124 	bool bUpdateEntire = false;
125 
126 	pp_int32 left, right;
127 	playerMaster->getCurrentSamplePeak(left, right);
128 
129 	// Left channel
130 	pp_int32 oldPeak = peakLevelControl->getPeak(0);
131 	pp_int32 newPeak = left << 1;
132 	if (newPeak >= maxPeakThreshold)
133 	{
134 		TitlePageManager titlePageManager(*screen);
135 		titlePageManager.setPeakControlHeadingColor(TrackerConfig::colorPeakClipIndicator, false);
136 		bUpdateEntire = true;
137 	}
138 	if (newPeak < oldPeak)
139 	{
140 		newPeak = oldPeak;
141 		newPeak -= 2048;
142 		if (newPeak < 0)
143 			newPeak = 0;
144 	}
145 	if (oldPeak != newPeak)
146 	{
147 		peakLevelControl->setPeak(0, newPeak);
148 		bUpdateL = true;
149 	}
150 
151 	// Right channel
152 	oldPeak = peakLevelControl->getPeak(1);
153 	newPeak = right << 1;
154 	if (newPeak >= maxPeakThreshold)
155 	{
156 		TitlePageManager titlePageManager(*screen);
157 		titlePageManager.setPeakControlHeadingColor(TrackerConfig::colorRecordModeButtonText, false);
158 		bUpdateEntire = true;
159 	}
160 	if (newPeak < oldPeak)
161 	{
162 		newPeak = oldPeak;
163 		newPeak -= 2048;
164 		if (newPeak < 0)
165 			newPeak = 0;
166 	}
167 	if (oldPeak != newPeak)
168 	{
169 		peakLevelControl->setPeak(1, newPeak);
170 		bUpdateR = true;
171 	}
172 
173 	if (bUpdateEntire)
174 	{
175 		screen->paintControl(screen->getControlByID(CONTAINER_ABOUT), false);
176 		return true;
177 	}
178 	else if (bUpdateL || bUpdateR)
179 	{
180 		screen->paintControl(peakLevelControl, false);
181 		return true;
182 	}
183 
184 	return false;
185 }
186 
updatePlayTime()187 bool Tracker::updatePlayTime()
188 {
189 	if (!playTimeText)
190 		return false;
191 
192 	if (!playTimeText->isVisible())
193 		return false;
194 
195 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_ABOUT));
196 
197 	char buffer[100], buffer2[100];
198 
199 	pp_int32 playtime = (pp_int32)playerController->getPlayTime();
200 
201 	if (!playerController->isPlaying())
202 		playtime = 0;
203 
204 	pp_int32 seconds = playtime % 60;
205 	pp_int32 minutes = (playtime / 60) % 60;
206 	pp_int32 hours = (playtime / 3600) % 100;
207 
208 	sprintf(buffer,"%02i:%02i:%02i", hours, minutes, seconds);
209 
210 	playtime = moduleEditor->getModuleServices()->getEstimatedSongLength();
211 	if (playtime == -1)
212 	{
213 		// strcpy(buffer2,"(--:--:--)");
214 		// believe it or not, the VC 6.0 compiler
215 		// fucks up the above strcpy, now providing some awesome workaround ;)
216 		buffer2[0] = '(';
217 		buffer2[1] = '-';
218 		buffer2[2] = '-';
219 		buffer2[3] = ':';
220 		buffer2[4] = '-';
221 		buffer2[5] = '-';
222 		buffer2[6] = ':';
223 		buffer2[7] = '-';
224 		buffer2[8] = '-';
225 		buffer2[9] = ')';
226 		buffer2[10] = 0;
227 	}
228 	else
229 	{
230 		pp_int32 seconds = playtime % 60;
231 		pp_int32 minutes = (playtime / 60) % 60;
232 		pp_int32 hours = (playtime / 3600) % 100;
233 		sprintf(buffer2,"(%02i:%02i:%02i)", hours, minutes, seconds);
234 	}
235 
236 	strcat(buffer, buffer2);
237 
238 	if (strcmp(playTimeText->getText(), buffer) != 0)
239 	{
240 		playTimeText->setText(buffer);
241 		screen->paintControl(container, false);
242 		return true;
243 	}
244 
245 	return false;
246 }
247 
248 ///////////////////////////////////////////
249 // update song title
250 ///////////////////////////////////////////
updateSongTitle(bool repaint)251 void Tracker::updateSongTitle(bool repaint)
252 {
253 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_ABOUT));
254 
255 	PPListBox* listBox = static_cast<PPListBox*>(container->getControlByID(LISTBOX_SONGTITLE));
256 
257 	listBox->clear();
258 	char str[MP_MAXTEXT+1];
259 	moduleEditor->getTitle(str, ModuleEditor::MAX_TITLETEXT);
260 
261 	listBox->addItem(str);
262 	listBox->setMaxEditSize(ModuleEditor::MAX_TITLETEXT);
263 
264 	screen->paintControl(container, repaint);
265 }
266 
267 #ifdef __LOWRES__
updateJamMenuOrder(bool repaint)268 void Tracker::updateJamMenuOrder(bool repaint/* = true*/)
269 {
270 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_LOWRES_JAMMENU));
271 	PPStaticText* staticText = static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_JAMMENU_CURORDER));
272 	staticText->setHexValue(getOrderListBoxIndex(), 2);
273 	if (container->isVisible())
274 		screen->paintControl(container, repaint);
275 }
276 #endif
277 
updateOrderlist(bool repaint)278 void Tracker::updateOrderlist(bool repaint/* = true*/)
279 {
280 	// First of all: update orderlist (something might have been removed/added)
281 	updateSongLength(false);
282 	// Now update patterns
283 	moduleEditor->setCurrentPatternIndex(moduleEditor->getOrderPosition(getOrderListBoxIndex()));
284 	moduleEditor->setCurrentOrderIndex(getOrderListBoxIndex());
285 
286 	updatePattern(false);
287 
288 	if (repaint)
289 		screen->update();
290 }
291 
292 ///////////////////////////////////////////
293 // update song length field + orderlist
294 ///////////////////////////////////////////
updateSongLength(bool repaint)295 void Tracker::updateSongLength(bool repaint)
296 {
297 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_ORDERLIST));
298 
299 	static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_ORDERLIST_SONGLENGTH))->setHexValue(moduleEditor->getNumOrders(), 2);
300 
301 	listBoxOrderList->setShowIndex(true);
302 	listBoxOrderList->setIndexBaseCount(0);
303 
304 	listBoxOrderList->saveState();
305 
306 	bool update = true;
307 	if (listBoxOrderList->getNumItems() != moduleEditor->getNumOrders())
308 	{
309 		listBoxOrderList->clear();
310 		update = false;
311 	}
312 
313 	for (pp_int32 i = 0; i < moduleEditor->getNumOrders(); i++)
314 	{
315 		char orderlistEntry[4];
316 
317 		PatternTools::convertToHex(orderlistEntry, moduleEditor->getOrderPosition(i), 2);
318 
319 		if (update)
320 			listBoxOrderList->updateItem(i, orderlistEntry);
321 		else
322 			listBoxOrderList->addItem(orderlistEntry);
323 	}
324 
325 	if (!update)
326 	{
327 		listBoxOrderList->restoreState();
328 		listBoxOrderList->setSelectedIndex(moduleEditor->getCurrentOrderIndex());
329 	}
330 
331 	screen->paintControl(container, repaint);
332 }
333 
334 ///////////////////////////////////////////
335 // update song restart position field
336 ///////////////////////////////////////////
updateSongRepeat(bool repaint)337 void Tracker::updateSongRepeat(bool repaint)
338 {
339 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_ORDERLIST));
340 	static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_ORDERLIST_REPEAT))->setHexValue(moduleEditor->getRepeatPos(), 2);
341 
342 	screen->paintControl(container, repaint);
343 }
344 
345 ///////////////////////////////////////////
346 // update speed field
347 ///////////////////////////////////////////
updateSpeed(bool repaint)348 bool Tracker::updateSpeed(bool repaint)
349 {
350 	mp_sint32 speed, bpm, mainvol;
351 
352 	playerController->getSpeed(bpm, speed);
353 	mainvol = playerController->getSongMainVolume();
354 
355 	if (bpm != lastBPM ||
356 		lastSpeed != speed ||
357 		lastMainVol != mainvol)
358 	{
359 		lastBPM = bpm;
360 		lastSpeed = speed;
361 		lastMainVol = mainvol;
362 		PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_SPEED));
363 		static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_SPEED_SPEED))->setIntValue(speed, 2);
364 		static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_SPEED_BPM))->setIntValue(bpm, 3);
365 		static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_SPEED_MAINVOL))->setHexValue((mainvol*64)/255, 2);
366 
367 		screen->paintControl(container, repaint);
368 		return true;
369 	}
370 	return false;
371 }
372 
373 ///////////////////////////////////////////
374 // update pattern add field
375 ///////////////////////////////////////////
updatePatternAddAndOctave(bool repaint)376 void Tracker::updatePatternAddAndOctave(bool repaint)
377 {
378 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_SPEED));
379 
380 	pp_int32 currentPatternAdd = getPatternEditorControl()->getRowInsertAdd();
381 	static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_SPEED_PATTERNADD))->setIntValue(currentPatternAdd, 2);
382 	pp_int32 currentOctave = getPatternEditor()->getCurrentOctave();
383 	static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_SPEED_OCTAVE))->setIntValue(currentOctave-1, 2);
384 
385 	screen->paintControl(container, repaint);
386 }
387 
388 
389 ///////////////////////////////////////////
390 // update current pattern index
391 ///////////////////////////////////////////
updatePatternIndex(bool repaint)392 void Tracker::updatePatternIndex(bool repaint)
393 {
394 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_PATTERN));
395 	static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_PATTERN_INDEX))->setHexValue(moduleEditor->getCurrentPatternIndex(), 2);
396 
397 #ifdef __LOWRES__
398 	{
399 		PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_LOWRES_JAMMENU));
400 		PPStaticText* staticText = static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_JAMMENU_CURPATTERN));
401 		staticText->setHexValue(moduleEditor->getCurrentPatternIndex(), 2);
402 		if (container->isVisible())
403 			screen->paintControl(container, repaint);
404 	}
405 #endif
406 	screen->paintControl(container, repaint);
407 }
408 
409 ///////////////////////////////////////////
410 // update current pattern's length
411 ///////////////////////////////////////////
updatePatternLength(bool repaint)412 void Tracker::updatePatternLength(bool repaint)
413 {
414 	PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_PATTERN));
415 	static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_PATTERN_LENGTH))->setHexValue(getPatternEditor()->getNumRows(),3);
416 
417 	screen->paintControl(container, repaint);
418 }
419 
420 ///////////////////////////////////////////
421 // update pattern and it's length and index
422 ///////////////////////////////////////////
updatePattern(bool repaint)423 void Tracker::updatePattern(bool repaint)
424 {
425 	updatePatternEditorControl(false);
426 	updatePatternIndex(false);
427 	updatePatternLength(false);
428 
429 	if (repaint)
430 		screen->update();
431 }
432 
433 ///////////////////////////////////////////
434 // update samples listbox
435 ///////////////////////////////////////////
updateSamplesListBox(bool repaint)436 void Tracker::updateSamplesListBox(bool repaint)
437 {
438 	listBoxSamples->saveState();
439 
440 	listBoxSamples->clear();
441 
442 	fillSampleListBox(listBoxSamples, listBoxInstruments->getSelectedIndex());
443 
444 	listBoxSamples->restoreState();
445 
446 	// check for visibility of parent container before updating
447 	if (static_cast<PPContainer*>(screen->getControlByID(CONTAINER_INSTRUMENTLIST))->isVisible())
448 		screen->paintControl(listBoxSamples, repaint);
449 
450 #ifdef __LOWRES__
451 	{
452 		pp_int32 i = listBoxInstruments->getSelectedIndex();
453 
454 		PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_LOWRES_JAMMENU));
455 		PPStaticText* staticText = static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_JAMMENU_CURINSTRUMENT));
456 		staticText->setHexValue(i+1, 2);
457 		if (container->isVisible())
458 			screen->paintControl(container, repaint);
459 
460 		container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_INSTRUMENTLIST));
461 		staticText = static_cast<PPStaticText*>(container->getControlByID(STATICTEXT_INSTRUMENTS_ALTERNATIVEHEADER2));
462 		staticText->setHexValue(i+1, 2);
463 		if (container->isVisible())
464 			screen->paintControl(container, repaint);
465 	}
466 #endif
467 }
468 
469 ///////////////////////////////////////////
470 // update instruments listbox
471 ///////////////////////////////////////////
updateInstrumentsListBox(bool repaint)472 void Tracker::updateInstrumentsListBox(bool repaint)
473 {
474 	listBoxInstruments->saveState();
475 
476 	listBoxInstruments->clear();
477 
478 	fillInstrumentListBox(listBoxInstruments);
479 
480 	listBoxInstruments->restoreState();
481 
482 	// check for visibility of parent container before updating
483 	if (!static_cast<PPContainer*>(screen->getControlByID(CONTAINER_INSTRUMENTLIST))->isVisible())
484 		return;
485 
486 	screen->paintControl(listBoxInstruments, repaint);
487 }
488 
489 ///////////////////////////////////////////
490 // update pattern editor
491 ///////////////////////////////////////////
updatePatternEditorControl(bool repaint,bool fast)492 void Tracker::updatePatternEditorControl(/*TXMPattern* pattern, */bool repaint/* = true*/, bool fast/* = false*/)
493 {
494 	PatternEditorControl* patternEditorCtrl = getPatternEditorControl();
495 
496 	moduleEditor->reloadCurrentPattern();
497 
498 	TXMPattern* pattern = getPatternEditor()->getPattern();
499 
500 	if (pattern)
501 	{
502 		if (isEditingCurrentOrderlistPattern())
503 			patternEditorCtrl->setOrderlistIndex(getOrderListBoxIndex());
504 		else
505 			patternEditorCtrl->setOrderlistIndex(-1);
506 
507 		//patternEditorCtrl->attachPattern(pattern, moduleEditor->getModule());
508 	}
509 
510 	if (!fast)
511 		screen->paintControl(patternEditorCtrl, repaint);
512 }
513 
514 ///////////////////////////////////////////
515 // update instrument editor
516 ///////////////////////////////////////////
updateSampleEditor(bool repaint,bool force)517 void Tracker::updateSampleEditor(bool repaint, bool force)
518 {
519 	sectionSamples->realUpdate(repaint, force, true);
520 }
521 
updateSampleEditorAndInstrumentSection(bool repaint)522 void Tracker::updateSampleEditorAndInstrumentSection(bool repaint/* = true*/)
523 {
524 	// update instrument/sample editor
525 	// important: sample editor first => will reload sample into sample editor
526 	updateSampleEditor(repaint);
527 	sectionInstruments->update(repaint);
528 }
529 
updateSongInfo(bool repaint)530 void Tracker::updateSongInfo(bool repaint/* = true*/)
531 {
532 	updateSongTitle(repaint);
533 
534 	updateSongLength(repaint);
535 	updateSongRepeat(repaint);
536 
537 	//updateBPM(repaint);
538 	updateSpeed(repaint);
539 	updatePatternAddAndOctave(repaint);
540 
541 	updatePatternIndex(repaint);
542 	updatePatternLength(repaint);
543 
544 	updateInstrumentsListBox(repaint);
545 	updateSamplesListBox(repaint);
546 
547 	getPatternEditorControl()->reset();
548 	getPatternEditorControl()->unmuteAll();
549 	sectionInstruments->resetEnvelopeEditor();
550 	sectionInstruments->updateEnvelopeEditor(false, true);
551 	sectionInstruments->resetPianoAssignment();
552 	sectionSamples->resetSampleEditor();
553 
554 	setNumChannels(moduleEditor->getNumChannels(), false);
555 
556 	updatePatternEditorControl(repaint);
557 
558 	updateSampleEditorAndInstrumentSection(repaint);
559 
560 	updateWindowTitle(moduleEditor->getModuleFileName());
561 
562 	if (repaint)
563 		screen->update();
564 }
565 
updateInstrumentChooser(bool repaint)566 void Tracker::updateInstrumentChooser(bool repaint/* = true*/)
567 {
568 	PPContainer* container = static_cast<PPContainer*>(screen->getModalControl());
569 
570 	PPListBox* listBoxSrc = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC));
571 	PPListBox* listBoxSrcModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC3));
572 	PPListBox* listBoxDst = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST));
573 	PPListBox* listBoxDstModule = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST3));
574 
575 	ModuleEditor* src = listBoxSrcModule ? tabManager->getModuleEditorFromTabIndex(listBoxSrcModule->getSelectedIndex()) : this->moduleEditor;
576 	ModuleEditor* dst = listBoxDstModule ? tabManager->getModuleEditorFromTabIndex(listBoxDstModule->getSelectedIndex()) : this->moduleEditor;
577 
578 	listBoxSrc->saveState();
579 	listBoxSrc->clear();
580 	fillInstrumentListBox(listBoxSrc, src);
581 	listBoxSrc->restoreState();
582 
583 	listBoxDst->saveState();
584 	listBoxDst->clear();
585 	fillInstrumentListBox(listBoxDst, dst);
586 	listBoxDst->restoreState();
587 
588 	mp_sint32 srcInsIndex = listBoxSrc->getSelectedIndex();
589 	mp_sint32 dstInsIndex = listBoxDst->getSelectedIndex();
590 
591 	listBoxSrc = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_SRC2));
592 	listBoxDst = static_cast<PPListBox*>(container->getControlByID(INSTRUMENT_CHOOSER_LIST_DST2));
593 
594 	listBoxSrc->saveState();
595 	listBoxSrc->clear();
596 
597 	fillSampleListBox(listBoxSrc, srcInsIndex, src);
598 
599 	listBoxSrc->restoreState();
600 
601 	listBoxDst->saveState();
602 	listBoxDst->clear();
603 
604 	fillSampleListBox(listBoxDst, dstInsIndex, dst);
605 
606 	listBoxDst->restoreState();
607 
608 	if (repaint)
609 		screen->update();
610 }
611 
updateTabTitle()612 void Tracker::updateTabTitle()
613 {
614 	TabHeaderControl* tabHeader = static_cast<TabHeaderControl*>(screen->getControlByID(TABHEADER_CONTROL));
615 
616 	if (tabHeader != NULL)
617 	{
618 		TabTitleProvider tabTitleProvider(*moduleEditor);
619 		PPString tabTitle = tabTitleProvider.getTabTitle();
620 		if (moduleEditor->hasChanged())
621 			tabTitle.append("*");
622 
623 		bool refresh = false;
624 
625 		for (pp_int32 i = 0; i < (signed)tabHeader->getNumTabs(); i++)
626 		{
627 			if (tabManager->getModuleEditorFromTabIndex(i) == this->moduleEditor)
628 			{
629 				if (tabHeader->getTab(i)->text.compareTo(tabTitle) != 0)
630 				{
631 					tabHeader->setTabHeaderText(i, tabTitle);
632 					refresh = true;
633 				}
634 			}
635 		}
636 
637 		if (refresh)
638 			screen->paintControl(tabHeader);
639 	}
640 }
641 
updateWindowTitle()642 void Tracker::updateWindowTitle()
643 {
644 	if (moduleEditor->hasChanged() != lastState)
645 	{
646 		PPSystemString title = "MilkyTracker - ";
647 
648 		title.append(currentFileName);
649 
650 		if (moduleEditor->hasChanged())
651 			title.append(" (modified)");
652 
653 		screen->setTitle(title);
654 
655 		updateTabTitle();
656 
657 		lastState = moduleEditor->hasChanged();
658 	}
659 }
660 
updateWindowTitle(const PPSystemString & fileName)661 void Tracker::updateWindowTitle(const PPSystemString& fileName)
662 {
663 	lastState = !moduleEditor->hasChanged();
664 
665 	currentFileName = fileName.stripPath();
666 
667 	updateWindowTitle();
668 }
669 
updateSongPosition(pp_int32 pos,pp_int32 row,bool fast)670 bool Tracker::updateSongPosition(pp_int32 pos/* = -1*/, pp_int32 row/* = -1*/, bool fast/* = false*/)
671 {
672 	mp_sint32 thePos, theRow;
673 	playerController->getPosition(thePos, theRow);
674 
675 #if 0
676 	static int counter = 0;
677 	if (thePos == 0 && theRow == 63 && (theRow != lastRow || thePos != lastPos))
678 		counter++;
679 
680 	if (counter == 2)
681 	{
682 		int i = 0;
683 		i++;
684 		i--;
685 	}
686 #endif
687 
688 	if (pos == -1)
689 		pos = thePos;
690 	if (row == -1)
691 		row = theRow;
692 
693 	bool redraw = false;
694 
695 	// I'm now trying to understand what happens here ------>
696 	// When the current row is different from the last row
697 	// or the current order position is different from the last one
698 	// we're doing some screen refreshing
699 	if (row != lastRow || pos != lastPos)
700 	{
701 		// if we're not playing a single pattern, we're most likely playing the entire song
702 		// and in that case if we're instructed to follow the song while playing we're doing some
703 		// order list position updates and stuff ------>
704 		if (!playerController->isPlayingPattern() && shouldFollowSong())
705 		{
706 			// if the current order list index is different from the current
707 			// order list position from the player UPDATE ------>
708 			if (getOrderListBoxIndex() != pos)
709 			{
710 				listBoxOrderList->setSelectedIndex(pos, false);
711 				moduleEditor->setCurrentOrderIndex(pos);
712 				// in low res mode we also need to update
713 				// the order position in the "Jam"-section
714 #ifdef __LOWRES__
715 				if (!fast)
716 					updateJamMenuOrder(false);
717 #endif
718 				// now tell the module editor that we're editing another pattern
719 				moduleEditor->setCurrentPatternIndex(moduleEditor->getOrderPosition(pos));
720 				// update pattern editor with current order list pattern
721 				// but don't redraw/update, just get it from the module editor and attach it to the pattern editor
722 				updatePatternEditorControl(false, true);
723 			}
724 
725 			if (!fast)
726 			{
727 				// update pattern property fields
728 				updateSongLength(false);
729 				updatePatternIndex(false);
730 				updatePatternLength(false);
731 			}
732 
733 			// only follow song if the pattern index matches the one from the
734 			// order list, otherwise the user has probably selected a different
735 			// pattern while playing takes place
736 			if (moduleEditor->getCurrentPatternIndex() == moduleEditor->getOrderPosition(pos))
737 			{
738 				// song positon is only used in non-follow mode
739 				getPatternEditorControl()->setSongPosition(-1, -1);
740 				// but we should probably update the current row in the pattern editor as well
741 				// as long as the user is not currently dragging the scroll bars in the sample editor
742 				getPatternEditorControl()->setRow(row, fast ? false : !getPatternEditorControl()->isDraggingVertical());
743 			}
744 		}
745 		else if (playerController->isPlayingPattern() && !shouldFollowSong())
746 		{
747 			// we're playing the current pattern and don't follow the song
748 			// just update the current playing row in the pattern editor
749 			if (playerController->isPlayingPattern(moduleEditor->getCurrentPatternIndex()))
750 				getPatternEditorControl()->setSongPosition(-1, row);
751 			// we're playing a pattern different from the one in the editor
752 			// don't show any positions
753 			else
754 				getPatternEditorControl()->setSongPosition(-1, -1);
755 		}
756 		else if (playerController->isPlayingPattern() && shouldFollowSong())
757 		{
758 			getPatternEditorControl()->setSongPosition(-1, -1);
759 			getPatternEditorControl()->setRow(row, fast ? false : !getPatternEditorControl()->isDraggingVertical());
760 		}
761 		else
762 		{
763 			getPatternEditorControl()->setSongPosition(pos, row);
764 		}
765 
766 		updatePatternEditorControl(false, fast);
767 
768 		redraw = true;
769 
770 		lastRow = row;
771 		lastPos = pos;
772 	}
773 
774 	if (!fast)
775 		return updateSpeed(false) || redraw;
776 	else
777 		return redraw;
778 }
779 
updateRecordButton(PPContainer * container,const PPColor & pColor)780 void Tracker::updateRecordButton(PPContainer* container, const PPColor& pColor)
781 {
782 	ASSERT(container);
783 
784 	// now if the parent container is visible,
785 	// we're going to update the record button
786 	if (container->isVisible())
787 	{
788 		// get button from container
789 		PPButton* button = static_cast<PPButton*>(container->getControlByID(MAINMENU_EDIT));
790 		ASSERT(button);
791 
792 		// if it's visible and the color is not what we're going to set
793 		// set new text color and repaint
794 		if (button->isVisible() && (&pColor) != button->getTextColor())
795 		{
796 			button->setTextColor(pColor);
797 			screen->paintControl(button);
798 		}
799 	}
800 }
801 
doFollowSong()802 void Tracker::doFollowSong()
803 {
804 	// check if we need to update the record button
805 	// this is done periodically and only in MilkyTracker mode
806 	if (editMode == EditModeMilkyTracker)
807 	{
808 		// If the pattern editor has got the focus
809 		// we're in record mode, so get the record button text color
810 		const PPColor& pColor = getPatternEditorControl()->gotFocus() ? TrackerConfig::colorRecordModeButtonText : PPUIConfig::getInstance()->getColor(PPUIConfig::ColorDefaultButtonText);
811 
812 		// we're going to update the record button
813 		updateRecordButton(static_cast<PPContainer*>(screen->getControlByID(CONTAINER_MENU)), pColor);
814 
815 #ifdef __LOWRES__
816 		// in low-res mode, the record buttons appears
817 		// also in some other containers (e.g. TINYMENU) ...
818 		updateRecordButton(static_cast<PPContainer*>(screen->getControlByID(CONTAINER_LOWRES_TINYMENU)), pColor);
819 
820 		// ... also the JAMMENU
821 		updateRecordButton(static_cast<PPContainer*>(screen->getControlByID(CONTAINER_LOWRES_JAMMENU)), pColor);
822 #endif
823 	}
824 
825 	// check if the piano has been updated
826 	bool updatePiano = updatePianoControl(sectionInstruments->getPianoControl());
827 
828 	// check if the play time has been updated
829 	bool updatePlayTime = this->updatePlayTime();
830 
831 #ifdef __LOWRES__
832 	// in low-res mode a piano might be embedded into other containers as well
833 	// => check for updates
834 	if (inputContainerCurrent->isVisible())
835 	{
836 		PianoControl* pianoControl = static_cast<PianoControl*>(inputContainerCurrent->getControlByID(PIANO_CONTROL));
837 		updatePiano |= updatePianoControl(pianoControl);
838 	}
839 	else if (screen->getControlByID(CONTAINER_LOWRES_JAMMENU)->isVisible())
840 	{
841 		PPContainer* container = static_cast<PPContainer*>(screen->getControlByID(CONTAINER_LOWRES_JAMMENU));
842 		PianoControl* pianoControl = static_cast<PianoControl*>(container->getControlByID(PIANO_CONTROL));
843 		updatePiano |= updatePianoControl(pianoControl);
844 	}
845 #endif
846 
847 	bool importantRefresh = false;
848 
849 	// now for updating the sample editor control
850 	SampleEditorControl* sampleEditorControl = sectionSamples->getSampleEditorControl(false);
851 
852 	if (sampleEditorControl)
853 	{
854 		bool showMarksVisibleOld = sampleEditorControl->isVisible() ? sampleEditorControl->showMarksVisible() : false;
855 		bool updateSample = false;
856 
857 		TXMSample* smp = getSampleEditor()->getSample();
858 
859 		for (pp_int32 i = 0; i < playerController->getAllNumPlayingChannels(); i++)
860 		{
861 			pp_int32 pos, vol, pan;
862 			if (playerController->isSamplePlaying(*smp, i, pos, vol, pan))
863 			{
864 				// it is there
865 				// => set the position mark
866 				sampleEditorControl->setShowMark(i, pos, vol, pan);
867 				updateSample = true;
868 			}
869 			else
870 			{
871 				// it is not there
872 				// => clear the position mark
873 				if (sampleEditorControl->getShowMarkPos(i) != -1)
874 				{
875 					sampleEditorControl->setShowMark(i, -1, 0);
876 					updateSample = true;
877 				}
878 			}
879 		}
880 
881 		if (updateSample && sampleEditorControl->isVisible())
882 		{
883 			bool showMarksVisible = sampleEditorControl->showMarksVisible();
884 
885 			// if either show marks HAVE BEEN visible and they're no longer visble OR
886 			// no show marks have been visible and now they're some visible
887 			// => redraw
888 			if (showMarksVisible || showMarksVisibleOld)
889 			{
890 				sectionSamples->updateSampleWindow(false);
891 				importantRefresh = true;
892 			}
893 		}
894 
895 	}
896 
897 	if (sectionInstruments->isEnvelopeVisible())
898 	{
899 		EnvelopeEditorControl* eeCtrl = sectionInstruments->getEnvelopeEditorControl();
900 
901 		bool redrawEnvelopeEditor = false;
902 
903 		if (eeCtrl->hasShowMarks())
904 		{
905 			eeCtrl->clearShowMarks();
906 			redrawEnvelopeEditor = true;
907 		}
908 
909 		EnvelopeEditor* ee = getEnvelopeEditor();
910 
911 		for (pp_int32 i = 0; i < playerController->getPlayerNumPlayingChannels(); i++)
912 		{
913 			pp_int32 pos;
914 			if (playerController->isEnvelopePlaying(*ee->getEnvelope(), sectionInstruments->getVisibleEnvelopeType(), i, pos))
915 			{
916 				eeCtrl->setShowMark(i, pos);
917 
918 				if (pos != -1)
919 					redrawEnvelopeEditor = true;
920 			}
921 		}
922 
923 		if (redrawEnvelopeEditor)
924 		{
925 			sectionInstruments->updateEnvelopeWindow(false);
926 			importantRefresh = true;
927 		}
928 
929 	}
930 
931 	if (playerController->isPlaying() &&
932 		!playerController->isPlayingRowOnly()/* && getFollowSong()*/)
933 	{
934 		importantRefresh |= updateSongPosition();
935 	}
936 
937 	bool updatePeak = updatePeakLevelControl();
938 
939 	bool updateScopes = false;
940 	if (scopesControl && scopesControl->isVisible())
941 	{
942 		updateScopes = scopesControl->needsUpdate();
943 		if (updateScopes && !updatePiano && !importantRefresh && !updatePlayTime && !updatePeak)
944 		{
945 			screen->paintControl(scopesControl);
946 			return;
947 		}
948 		else if (updateScopes)
949 			screen->paintControl(scopesControl, false);
950 	}
951 
952 	importantRefresh |= updatePiano;
953 
954 	if (!importantRefresh)
955 	{
956 		if (updatePeak || updatePlayTime)
957 		{
958 			screen->updateControl(screen->getControlByID(CONTAINER_ABOUT));
959 		}
960 
961 		if (updateScopes)
962 		{
963 			screen->updateControl(scopesControl);
964 		}
965 	}
966 	else
967 	{
968 		screen->update();
969 	}
970 }
971 
updateAfterLoad(bool loadResult,bool wasPlaying,bool wasPlayingPattern)972 void Tracker::updateAfterLoad(bool loadResult, bool wasPlaying, bool wasPlayingPattern)
973 {
974 	ASSERT(settingsDatabase->restore("AUTOESTPLAYTIME"));
975 	if (loadResult && settingsDatabase->restore("AUTOESTPLAYTIME")->getIntValue())
976 		estimateSongLength();
977 	else
978 		moduleEditor->getModuleServices()->resetEstimatedSongLength();
979 
980 	// special updates
981 	listBoxOrderList->setSelectedIndex(0);
982 	moduleEditor->setCurrentOrderIndex(0);
983 
984 	moduleEditor->setCurrentPatternIndex(moduleEditor->getOrderPosition(0));
985 
986 	listBoxInstruments->setSelectedIndex(0);
987 	moduleEditor->setCurrentInstrumentIndex(0);
988 	listBoxSamples->setSelectedIndex(0);
989 	moduleEditor->setCurrentSampleIndex(0);
990 
991 	updateSongInfo(false);
992 
993 	playerController->resetMainVolume();
994 	getPatternEditorControl()->setChannel(0,0);
995 	getPatternEditorControl()->setCurrentInstrument(1);
996 
997 	if (wasPlaying)
998 	{
999 		if (!wasPlayingPattern && shouldFollowSong())
1000 		{
1001 			getPatternEditorControl()->setSongPosition(-1, -1);
1002 			getPatternEditorControl()->setRow(0);
1003 		}
1004 		else if (wasPlayingPattern && !shouldFollowSong())
1005 		{
1006 			getPatternEditorControl()->setSongPosition(-1, 0);
1007 		}
1008 		else if (wasPlayingPattern && shouldFollowSong())
1009 		{
1010 			getPatternEditorControl()->setSongPosition(-1, -1);
1011 			getPatternEditorControl()->setRow(0);
1012 		}
1013 	}
1014 	else
1015 	{
1016 		getPatternEditorControl()->setSongPosition(-1, -1);
1017 		getPatternEditorControl()->setRow(0);
1018 	}
1019 
1020 	if (loadResult)
1021 	{
1022 		playerController->resetPlayTimeCounter();
1023 
1024 		sectionHDRecorder->resetCurrentFileName();
1025 		sectionHDRecorder->adjustOrders();
1026 
1027 		updateWindowTitle(moduleEditor->getModuleFileName());
1028 
1029 		// !!! Remember this !!!
1030 		// It's important to apply new speed settings before the playmode is switched
1031 		playerController->setSpeed(moduleEditor->getSongBPM(), moduleEditor->getSongTickSpeed());
1032 
1033 		if (!sectionQuickOptions->keepSettings())
1034 		{
1035 			switch (moduleEditor->getSaveType())
1036 			{
1037 				case ModuleEditor::ModSaveTypeMOD:
1038 					if (moduleEditor->getNumChannels() == 4)
1039 						playerController->switchPlayMode(PlayerController::PlayMode_ProTracker2);
1040 					else
1041 						playerController->switchPlayMode(PlayerController::PlayMode_ProTracker3);
1042 					break;
1043 				case ModuleEditor::ModSaveTypeXM:
1044 					playerController->switchPlayMode(PlayerController::PlayMode_FastTracker2);
1045 					break;
1046 				default:
1047 					ASSERT(false);
1048 			}
1049 		}
1050 
1051 		if (wasPlaying && !wasPlayingPattern)
1052 		{
1053 			playerController->restartPlaying();
1054 		}
1055 		else if (wasPlaying && wasPlayingPattern)
1056 		{
1057 			eventKeyDownBinding_Stop();
1058 			eventKeyDownBinding_PlayPattern();
1059 		}
1060 	}
1061 
1062 	updateSongInfo(false);
1063 }
1064 
updateAfterTabSwitch()1065 void Tracker::updateAfterTabSwitch()
1066 {
1067 	pp_int32 i;
1068 
1069 	getPatternEditorControl()->attachPatternEditor(moduleEditor->getPatternEditor());
1070 	sectionSamples->getSampleEditorControl(false)->attachSampleEditor(moduleEditor->getSampleEditor());
1071 	sectionInstruments->getEnvelopeEditorControl()->attachEnvelopeEditor(moduleEditor->getEnvelopeEditor());
1072 	// -----------------------------------------------------------------------
1073 	sectionHDRecorder->resetCurrentFileName();
1074 	sectionHDRecorder->adjustOrders();
1075 
1076 	updateSongTitle(false);
1077 
1078 	updateSongLength(false);
1079 	updateSongRepeat(false);
1080 
1081 	updateSpeed(false);
1082 	updatePatternAddAndOctave(false);
1083 
1084 	updatePatternIndex(false);
1085 	updatePatternLength(false);
1086 
1087 	updateInstrumentsListBox(false);
1088 	updateSamplesListBox(false);
1089 
1090 	// -----------------------------------------------------------------------
1091 	// restore old positions
1092 	listBoxInstruments->setSelectedIndex(moduleEditor->getCurrentInstrumentIndex(), false);
1093 	listBoxSamples->setSelectedIndex(moduleEditor->getCurrentSampleIndex(), false);
1094 
1095 	if (!playerController->isPlaying())
1096 	{
1097 		listBoxOrderList->setSelectedIndex(moduleEditor->getCurrentOrderIndex());
1098 		updatePatternEditorControl(false, true);
1099 		getPatternEditor()->setCursor(moduleEditor->getCurrentCursorPosition());
1100 	}
1101 
1102 	getPatternEditorControl()->setSize(PPSize(screen->getWidth(),MAXEDITORHEIGHT()-UPPERSECTIONDEFAULTHEIGHT()));
1103 
1104 	// let tabs handle their own update
1105 	for (i = 0; i < sections->size(); i++)
1106 		sections->get(i)->notifyTabSwitch();
1107 
1108 	setNumChannels(moduleEditor->getNumChannels(), false);
1109 	scopesControl->attachSource(playerController);
1110 	updateSampleEditorAndInstrumentSection(false);
1111 	updateWindowTitle(moduleEditor->getModuleFileName());
1112 
1113 	// apply muting from playercontroller
1114 	const pp_int32 numChannels = TrackerConfig::numPlayerChannels;
1115 	for (i = 0; i < numChannels; i++)
1116 	{
1117 		bool b = playerController->isChannelMuted(i);
1118 		muteChannels[i] = b ? 1 : 0;
1119 		getPatternEditorControl()->muteChannel(i, b);
1120 		scopesControl->muteChannel(i, b);
1121 
1122 		b = playerController->isChannelRecording(i);
1123 		scopesControl->recordChannel(i, b);
1124 	}
1125 
1126 	if (playerController->isPlaying())
1127 	{
1128 		screen->pauseUpdate(true);
1129 		doFollowSong();
1130 		screen->pauseUpdate(false);
1131 	}
1132 	screen->paint(true);
1133 }
1134 
1135