1 /*
2  *  tracker/PatternEditorControl.h
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 //
25 //	PatternEditorTools control class
26 //
27 /////////////////////////////////////////////////////////////////
28 #ifndef PATTERNEDITORCONTROL__H
29 #define PATTERNEDITORCONTROL__H
30 
31 #include "BasicTypes.h"
32 #include "Control.h"
33 #include "Event.h"
34 #include "PatternEditor.h"
35 #include "ScrollBar.h"
36 #include "PatternTools.h"
37 #include "EditModes.h"
38 #include "TrackerConfig.h"
39 
40 // Forwards ------------------------------------------------------
41 class PPScrollbar;
42 class PPFont;
43 class PPContextMenu;
44 class PPDialogBase;
45 
46 class PatternEditorControl;
47 typedef void (PatternEditorControl::*TPatternEditorKeyBindingHandler)();
48 typedef pp_int32 (PatternEditor::*TTransposeFunc)(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate);
49 
50 template<class Type> class PPKeyBindings;
51 
52 class PatternEditorControl :
53 	public PPControl,
54 	public EventListenerInterface,
55 	public EditorBase::EditorNotificationListener,
56 	public PatternEditor::PatternAdvanceInterface
57 {
58 private:
59 	struct SongPos
60 	{
61 		pp_int32 orderListIndex, row;
62 	};
63 
64 	struct UndoInfo
65 	{
66 		pp_int32 startIndex;
67 		pp_int32 startPos;
68 
UndoInfoUndoInfo69 		UndoInfo()
70 		{
71 		}
72 
UndoInfoUndoInfo73 		UndoInfo(pp_int32 startIndex, pp_int32 startPos) :
74 			startIndex(startIndex),
75 			startPos(startPos)
76 		{
77 		}
78 	} undoInfo;
79 
80 	PPColor bgColor;
81 	const PPColor* borderColor;
82 	const PPColor* cursorColor;
83 	const PPColor* selectionColor;
84 
85 	bool border;
86 
87 	struct Properties
88 	{
89 		bool showFocus;
90 
91 		bool rowAdvance;
92 		pp_int32 rowInsertAdd;
93 
94 		pp_uint32 spacing, highlightSpacingPrimary, highlightSpacingSecondary;
95 		bool highLightRowPrimary, highLightRowSecondary;
96 		bool hexCount;
97 		bool wrapAround;
98 		bool prospective;
99 		bool tabToNote;
100 		bool clickToCursor;
101 		bool multiChannelEdit;
102 		ScrollModes scrollMode;
103 		bool invertMouseVscroll;
104 		pp_uint32 muteFade;
105 		char zeroEffectCharacter;
106 		bool ptNoteLimit;
107 
PropertiesProperties108 		Properties() :
109 			showFocus(true),
110 			rowAdvance(true),
111 			rowInsertAdd(1),
112 			spacing(0),
113 			highlightSpacingPrimary(4),
114 			highlightSpacingSecondary(8),
115 			highLightRowPrimary(false),
116 			highLightRowSecondary(false),
117 			hexCount(true),
118 			wrapAround(true),
119 			prospective(false),
120 			tabToNote(true),
121 			clickToCursor(true),
122 			multiChannelEdit(false),
123 			scrollMode(ScrollModeToEnd),
124 			invertMouseVscroll(false),
125 			muteFade(32768),
126 			zeroEffectCharacter('\xf4'),
127 			ptNoteLimit(false)
128 		{
129 		}
130 	} properties;
131 
132 	PPFont* font;
133 
134 	PPScrollbar* hTopScrollbar;
135 	PPScrollbar* hBottomScrollbar;
136 	PPScrollbar* vLeftScrollbar;
137 	PPScrollbar* vRightScrollbar;
138 
139 	PPControl* caughtControl;
140 	bool controlCaughtByLMouseButton, controlCaughtByRMouseButton;
141 
142 	PatternEditor* patternEditor;
143 	XModule* module;
144 	TXMPattern* pattern;
145 	pp_int32 currentOrderlistIndex;
146 	SongPos songPos;
147 
148 	PatternTools patternTools;
149 
150 	pp_int32 startIndex;
151 	pp_int32 startPos;
152 
153 	pp_int32 visibleWidth;
154 	pp_int32 visibleHeight;
155 	pp_int32 slotSize;
156 
157 	pp_uint8 muteChannels[TrackerConfig::MAXCHANNELS];
158 	pp_uint8 recChannels[TrackerConfig::MAXCHANNELS];
159 
160 	// Cursor position within editor
161 	pp_int32 cursorPositions[9];
162 	pp_int32 cursorSizes[8];
163 
164 	PatternEditorTools::Position cursorCopy, preCursor, *ppreCursor;
165 
166 	bool startSelection;
167 	bool keyboardStartSelection;
168 	bool assureUpdate, assureCursor;
169 
170 	pp_int32 selectionTicker;
171 
172 	bool hasDragged;
173 
174 	bool moveSelection;
175 	PatternEditorTools::Position moveSelectionInitialPos;
176 	PatternEditorTools::Position moveSelectionFinalPos;
177 
178 	// edit menu
179 	pp_int32 menuPosX;
180 	pp_int32 menuPosXOffset;
181 	pp_int32 menuPosY;
182 	pp_int32 menuInvokeChannel;
183 	pp_int32 lastMenuInvokeChannel;
184 
185 	PPContextMenu* editMenuControl;
186 
187 	// Keyboard shortcuts
188 	PPKeyBindings<TPatternEditorKeyBindingHandler>* eventKeyDownBindings;
189 	PPKeyBindings<TPatternEditorKeyBindingHandler>* scanCodeBindings;
190 
191 	PPKeyBindings<TPatternEditorKeyBindingHandler>* eventKeyDownBindingsMilkyTracker;
192 	PPKeyBindings<TPatternEditorKeyBindingHandler>* scanCodeBindingsMilkyTracker;
193 	PPKeyBindings<TPatternEditorKeyBindingHandler>* eventKeyDownBindingsFastTracker;
194 	PPKeyBindings<TPatternEditorKeyBindingHandler>* scanCodeBindingsFastTracker;
195 
196 	// Edit mode
197 	EditModes editMode;
198 	pp_int32 selectionKeyModifier;
199 
200 public:
201 	PatternEditorControl(pp_int32 id, PPScreen* parentScreen, EventListenerInterface* eventListener,
202 						 const PPPoint& location, const PPSize& size,
203 						 bool border = true);
204 
205 	virtual ~PatternEditorControl();
206 
setColor(PPColor color)207 	void setColor(PPColor color) { bgColor = color; }
208 	void setFont(PPFont* font);
209 
setShowFocus(bool showFocus)210 	void setShowFocus(bool showFocus) { properties.showFocus = showFocus; }
setScrollMode(ScrollModes mode)211 	void setScrollMode(ScrollModes mode) { properties.scrollMode = mode; adjustScrollBarPositionsAndSizes(); assureCursorVisible(); }
setInvertMouseVscroll(bool invert)212 	void setInvertMouseVscroll(bool invert) { properties.invertMouseVscroll = invert; }
213 
214 	// from PPControl
215 	virtual void setSize(const PPSize& size);
216 	virtual void setLocation(const PPPoint& location);
217 	virtual void paint(PPGraphicsAbstract* graphics);
gainsFocus()218 	virtual bool gainsFocus() const { return true; }
gainedFocusByMouse()219 	virtual bool gainedFocusByMouse() const { return caughtControl == NULL; }
220 	virtual pp_int32 dispatchEvent(PPEvent* event);
221 
222 	// from EventListenerInterface
223 	pp_int32 handleEvent(PPObject* sender, PPEvent* event);
224 
225 	void attachPatternEditor(PatternEditor* patternEditor);
226 
227 	void reset();
228 
isDraggingVertical()229 	bool isDraggingVertical() const
230 	{
231 		return (caughtControl == vLeftScrollbar) || (caughtControl == vRightScrollbar);
232 	}
233 
234 	// set number of visible channels, if this is -1 it will dynamically adjust it
235 	void setNumVisibleChannels(pp_int32 numChannels);
236 
getRowInsertAdd()237 	pp_int32 getRowInsertAdd() { return properties.rowInsertAdd; }
setRowInsertAdd(pp_int32 rowInsertAdd)238 	void setRowInsertAdd(pp_int32 rowInsertAdd) { properties.rowInsertAdd = rowInsertAdd; }
239 
increaseRowInsertAdd()240 	void increaseRowInsertAdd() { properties.rowInsertAdd = (properties.rowInsertAdd+1) % 17; }
decreaseRowInsertAdd()241 	void decreaseRowInsertAdd() { properties.rowInsertAdd--; if (properties.rowInsertAdd == -1) properties.rowInsertAdd = 16; }
242 
setOrderlistIndex(pp_int32 currentOrderlistIndex)243 	void setOrderlistIndex(pp_int32 currentOrderlistIndex) { this->currentOrderlistIndex = currentOrderlistIndex; }
244 	void setRow(pp_int32 row, bool bAssureCursorVisible = true);
getRow()245 	pp_int32 getRow() { return patternEditor->getCursor().row; }
setSongPosition(pp_int32 currentOrderlistIndex,pp_int32 row)246 	void setSongPosition(pp_int32 currentOrderlistIndex, pp_int32 row) { songPos.row = row; songPos.orderListIndex = currentOrderlistIndex; }
getSongPosition(pp_int32 & currentOrderlistIndex,pp_int32 & row)247 	void getSongPosition(pp_int32& currentOrderlistIndex, pp_int32& row) { row = songPos.row; currentOrderlistIndex = songPos.orderListIndex; }
248 	void setChannel(pp_int32 chn, pp_int32 posInner);
249 
getCurrentChannel()250 	pp_int32 getCurrentChannel() const { return patternEditor->getCursor().channel; }
getCurrentRow()251 	pp_int32 getCurrentRow() const { return patternEditor->getCursor().row; }
getCursorPosInner()252 	pp_int32 getCursorPosInner() const { return patternEditor->getCursor().inner; }
253 
254 	pp_int32 ScanCodeToNote(pp_int16 keyCode);
255 
setCurrentInstrument(pp_int32 ins)256 	void setCurrentInstrument(pp_int32 ins) { patternEditor->setCurrentInstrument(ins); }
enableInstrument(bool b)257 	void enableInstrument(bool b) { patternEditor->enableInstrument(b); }
isInstrumentEnabled()258 	bool isInstrumentEnabled() const { return patternEditor->isInstrumentEnabled(); }
setInstrumentBackTrace(bool b)259 	void setInstrumentBackTrace(bool b) { patternEditor->setInstrumentBackTrace(b); }
260 
261 	bool hasValidSelection() const;
262 
263 	//////////////////////////////////////////////////////////////////////////
264 	// --- more flags coming
265 	//////////////////////////////////////////////////////////////////////////
setSpacing(pp_uint32 spacing)266 	void setSpacing(pp_uint32 spacing) { properties.spacing = spacing; }
setHighlightSpacingPrimary(pp_uint32 spacing)267 	void setHighlightSpacingPrimary(pp_uint32 spacing) { properties.highlightSpacingPrimary = spacing; }
setHighLightRowPrimary(bool b)268 	void setHighLightRowPrimary(bool b) { properties.highLightRowPrimary = b; }
setHighlightSpacingSecondary(pp_uint32 spacing)269 	void setHighlightSpacingSecondary(pp_uint32 spacing) { properties.highlightSpacingSecondary = spacing; }
setHighLightRowSecondary(bool b)270 	void setHighLightRowSecondary(bool b) { properties.highLightRowSecondary = b; }
271 	// use zero effect zeros
showZeroEffect(bool b)272 	void showZeroEffect(bool b) { properties.zeroEffectCharacter = (b ? '0' : '\xf4'); }
273 	// hex count
setHexCount(bool b)274 	void setHexCount(bool b) { properties.hexCount = b; }
275 	// set prospective mode
setProspective(bool b)276 	void setProspective(bool b) { properties.prospective = b; }
getProspective()277 	bool getProspective() const { return properties.prospective; }
278 	// set wraparound mode
setWrapAround(bool b)279 	void setWrapAround(bool b) { properties.wrapAround = b; }
getWrapAround()280 	bool getWrapAround() const { return properties.wrapAround; }
281 	// set tab to note
setTabToNote(bool b)282 	void setTabToNote(bool b) { properties.tabToNote = b; }
getTabToNote()283 	bool getTabToNote() const { return properties.tabToNote; }
284 	// mouse click allows cursor-repositioning
setClickToCursor(bool b)285 	void setClickToCursor(bool b) { properties.clickToCursor = b; }
getClickToCursor()286 	bool getClickToCursor() const { return properties.clickToCursor; }
287 	// autoresize
setAutoResize(bool b)288 	void setAutoResize(bool b) { patternEditor->setAutoResize(b); }
getAutoResize()289 	bool getAutoResize() { return patternEditor->getAutoResize(); }
290 	// multichannel edit
setMultiChannelEdit(bool b)291 	void setMultiChannelEdit(bool b) { properties.multiChannelEdit = b; }
292 	// Highlight notes outside the PT 3 octave limit
setPtNoteLimit(bool l)293 	void setPtNoteLimit(bool l) { properties.ptNoteLimit = l; }
294 
setRowAdvance(bool b)295 	void setRowAdvance(bool b) { properties.rowAdvance = b; }
296 
297 	void switchEditMode(EditModes mode);
298 
setMuteFade(pp_int32 fade)299 	void setMuteFade(pp_int32 fade) { if (fade > 65536) fade = 65536; if (fade < 0) fade = 0; properties.muteFade = fade; }
300 
muteChannel(pp_int32 index,bool b)301 	void muteChannel(pp_int32 index, bool b) { muteChannels[index] = (b ? 1 : 0); }
recordChannel(pp_int32 index,bool b)302 	void recordChannel(pp_int32 index, bool b) { recChannels[index] = (b ? 1 : 0); }
303 	void unmuteAll();
304 
305 	void setRecordMode(bool b);
306 
307 	void advanceRow(bool assureCursor = true, bool repaint = true);
308 
getPatternEditor()309 	PatternEditor* getPatternEditor() const { return patternEditor; }
310 
311 	// --- these are defined in PatternEditorControlTransposeHandler.cpp -----
312 	void showNoteTransposeWarningMessageBox(pp_int32 fuckups);
313 	pp_int32 noteTransposeTrack(const PatternEditorTools::TransposeParameters& transposeParameters);
314 	pp_int32 noteTransposePattern(const PatternEditorTools::TransposeParameters& transposeParameters);
315 	pp_int32 noteTransposeSelection(const PatternEditorTools::TransposeParameters& transposeParameters);
316 
317 private:
318 	// --- Transpose handler
319 	class TransposeHandlerResponder : public DialogResponder
320 	{
321 	private:
322 		PatternEditorControl& patternEditorControl;
323 		PatternEditorTools::TransposeParameters transposeParameters;
324 		TTransposeFunc transposeFunc;
325 
326 	public:
327 		TransposeHandlerResponder(PatternEditorControl& thePatternEditorControl);
328 
setTransposeParameters(const PatternEditorTools::TransposeParameters & transposeParameters)329 		void setTransposeParameters(const PatternEditorTools::TransposeParameters& transposeParameters) { this->transposeParameters = transposeParameters; }
setTransposeFunc(TTransposeFunc transposeFunc)330 		void setTransposeFunc(TTransposeFunc transposeFunc) { this->transposeFunc = transposeFunc; }
331 
332 		virtual pp_int32 ActionOkay(PPObject* sender);
333 		virtual pp_int32 ActionCancel(PPObject* sender);
334 	};
335 
336 	friend class TransposeHandlerResponder;
337 
338 	PPDialogBase* dialog;
339 	TransposeHandlerResponder* transposeHandlerResponder;
340 
341 private:
342 	pp_int32 getRowCountWidth();
343 
344 	void adjustExtents();
345 
346 	void adjustVerticalScrollBarPositions(mp_sint32 startIndex);
347 	void adjustHorizontalScrollBarPositions(mp_sint32 startPos);
348 
349 	void adjustScrollBarPositionsAndSizes();
350 	void adjustScrollBarSizes();
351 
352 	void setScrollbarPositions(mp_sint32 startIndex, mp_sint32 startPos);
353 
354 	void scrollCursorDown();
355 	void scrollCursorUp();
356 
357 	void assureCursorVisible(bool row = true, bool channel = true);
358 
359 	mp_sint32 getNextRecordingChannel(mp_sint32 currentChannel);
360 
361 	virtual void advance();
362 
363 	void validate();
364 
365 	// ------- menu stuff ------------------------------------------
366 	enum MenuCommandIDs
367 	{
368 		MenuCommandIDMuteChannel = 100,
369 		MenuCommandIDSoloChannel,
370 		MenuCommandIDUnmuteAll,
371 		MenuCommandIDSelectChannel,
372 		MenuCommandIDPorousPaste,
373 		MenuCommandIDSwapChannels,
374 	};
375 
376 	void invokeMenu(pp_int32 channel, const PPPoint& p);
377 
378 	void executeMenuCommand(pp_int32 commandId);
379 
380 	void handleDeleteKey(pp_uint16 keyCode, pp_int32& result);
381 	void handleKeyChar(pp_uint8 character);
382 	void handleKeyDown(pp_uint16 keyCode, pp_uint16 scanCode, pp_uint16 character);
383 
384 	void selectionModifierKeyDown();
385 	void selectionModifierKeyUp();
386 
387 	// mark channel
388 	void markChannel(pp_int32 channel, bool invert = true);
389 
390 	// select ALL
391 	void selectAll();
392 
393 	// deselect ALL
394 	void deselectAll();
395 
396 	enum RMouseDownActions
397 	{
398 		RMouseDownActionInvalid,
399 		RMouseDownActionFirstRClick,
400 		RMouseDownActionFirstLClick,
401 		RMouseDownActionSecondLClick
402 	};
403 
404 	RMouseDownActions lastAction;
405 	pp_int32 RMouseDownInChannelHeading;
406 
407 	pp_int32 pointInChannelHeading(PPPoint& cp);
408 	bool isSoloChannel(pp_int32 c);
409 
410 private:
411 	bool executeBinding(const PPKeyBindings<TPatternEditorKeyBindingHandler>* bindings, pp_uint16 keyCode);
412 	void initKeyBindings();
413 
414 	// Original FT2 bindings
415 	void eventKeyDownBinding_LEFT();
416 	void eventKeyDownBinding_RIGHT();
417 	void eventKeyDownBinding_UP();
418 	void eventKeyDownBinding_DOWN();
419 	void eventKeyDownBinding_PRIOR();
420 	void eventKeyDownBinding_NEXT();
421 	void eventKeyDownBinding_HOME();
422 	void eventKeyDownBinding_END();
423 
424 	void eventKeyDownBinding_FIRSTQUARTER();
425 	void eventKeyDownBinding_SECONDQUARTER();
426 	void eventKeyDownBinding_THIRDQUARTER();
427 
428 	void eventKeyDownBinding_ReadMacro1();
429 	void eventKeyDownBinding_ReadMacro2();
430 	void eventKeyDownBinding_ReadMacro3();
431 	void eventKeyDownBinding_ReadMacro4();
432 	void eventKeyDownBinding_ReadMacro5();
433 	void eventKeyDownBinding_ReadMacro6();
434 	void eventKeyDownBinding_ReadMacro7();
435 	void eventKeyDownBinding_ReadMacro8();
436 	void eventKeyDownBinding_ReadMacro9();
437 	void eventKeyDownBinding_ReadMacro0();
438 
439 	void eventKeyDownBinding_WriteMacro1();
440 	void eventKeyDownBinding_WriteMacro2();
441 	void eventKeyDownBinding_WriteMacro3();
442 	void eventKeyDownBinding_WriteMacro4();
443 	void eventKeyDownBinding_WriteMacro5();
444 	void eventKeyDownBinding_WriteMacro6();
445 	void eventKeyDownBinding_WriteMacro7();
446 	void eventKeyDownBinding_WriteMacro8();
447 	void eventKeyDownBinding_WriteMacro9();
448 	void eventKeyDownBinding_WriteMacro0();
449 
450 	void eventKeyDownBinding_SC_Q();
451 	void eventKeyDownBinding_SC_W();
452 	void eventKeyDownBinding_SC_E();
453 	void eventKeyDownBinding_SC_R();
454 	void eventKeyDownBinding_SC_T();
455 	void eventKeyDownBinding_SC_Z();
456 	void eventKeyDownBinding_SC_U();
457 	void eventKeyDownBinding_SC_I();
458 
459 	void eventKeyDownBinding_SC_A();
460 	void eventKeyDownBinding_SC_S();
461 	void eventKeyDownBinding_SC_D();
462 	void eventKeyDownBinding_SC_F();
463 	void eventKeyDownBinding_SC_G();
464 	void eventKeyDownBinding_SC_H();
465 	void eventKeyDownBinding_SC_J();
466 	void eventKeyDownBinding_SC_K();
467 
468 	void eventKeyDownBinding_SC_IncreaseRowInsertAdd();
469 	void eventKeyDownBinding_SC_DecreaseRowInsertAdd();
470 
471 	void eventKeyDownBinding_PreviousChannel();
472 	void eventKeyDownBinding_NextChannel();
473 
474 	void eventKeyDownBinding_DeleteNote();
475 	void eventKeyDownBinding_DeleteNoteVolumeAndEffect();
476 	void eventKeyDownBinding_DeleteVolumeAndEffect();
477 	void eventKeyDownBinding_DeleteEffect();
478 
479 	void eventKeyDownBinding_InsertNote();
480 	void eventKeyDownBinding_InsertLine();
481 	void eventKeyDownBinding_DeleteNoteSlot();
482 	void eventKeyDownBinding_DeleteLine();
483 
484 	void eventKeyDownBinding_InsIncSelection();
485 	void eventKeyDownBinding_InsDecSelection();
486 	void eventKeyDownBinding_InsIncTrack();
487 	void eventKeyDownBinding_InsDecTrack();
488 
489 	void eventKeyDownBinding_CutTrack();
490 	void eventKeyDownBinding_CopyTrack();
491 	void eventKeyDownBinding_PasteTrack();
492 	void eventKeyDownBinding_TransparentPasteTrack();
493 
494 	void eventKeyDownBinding_CutPattern();
495 	void eventKeyDownBinding_CopyPattern();
496 	void eventKeyDownBinding_PastePattern();
497 	void eventKeyDownBinding_TransparentPastePattern();
498 
499 	void eventKeyCharBinding_Undo();
500 	void eventKeyCharBinding_Redo();
501 	void eventKeyCharBinding_Cut();		// Operates on block
502 	void eventKeyCharBinding_Copy();	// Operates on block
503 	void eventKeyCharBinding_Paste();   // Operates on block
504 	void eventKeyCharBinding_TransparentPaste();
505 	void eventKeyCharBinding_SelectAll();
506 	void eventKeyCharBinding_MuteChannel();
507 	void eventKeyCharBinding_InvertMuting();
508 	void eventKeyCharBinding_Interpolate();
509 
510 public:
511 	enum AdvanceCodes
512 	{
513 		AdvanceCodeJustUpdate,
514 		AdvanceCodeCursorUpWrappedStart,
515 		AdvanceCodeCursorDownWrappedEnd,
516 		AdvanceCodeCursorPageUpWrappedStart,
517 		AdvanceCodeCursorPageDownWrappedEnd,
518 		AdvanceCodeWrappedEnd,
519 		AdvanceCodeSelectNewRow
520 	};
521 
522 private:
523 	virtual void editorNotification(EditorBase* sender, EditorBase::EditorNotifications notification);
524 
525 	pp_int32 notifyUpdate(pp_int32 code = AdvanceCodeJustUpdate)
526 	{
527 		PPEvent e(eUpdated, &code, sizeof(code));
528 		return eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e);
529 	}
530 };
531 
532 #endif
533