1 /* 2 * tracker/PatternEditor.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 * PatternEditor.h 25 * MilkyTracker 26 * 27 * Created by Peter Barth on 16.11.07. 28 * 29 */ 30 31 #ifndef __PATTERNEDITOR_H__ 32 #define __PATTERNEDITOR_H__ 33 34 #include "EditorBase.h" 35 #include "PatternEditorTools.h" 36 #include "Undo.h" 37 38 struct TXMPattern; 39 class XModule; 40 41 class PatternEditor : public EditorBase 42 { 43 public: 44 // These are the clipboards, FT2 uses different clipboard buffers for 45 // copy/cut/paste block/track/pattern operations, so we imitate these too 46 enum ClipBoardTypes 47 { 48 ClipBoardTypeSelection, 49 ClipBoardTypeTrack, 50 ClipBoardTypePattern, 51 // do not use 52 ClipBoardTypeLAST 53 }; 54 55 class PatternAdvanceInterface 56 { 57 public: 58 virtual void advance() = 0; 59 }; 60 61 class Selection 62 { 63 private: 64 bool copyValid; 65 66 public: 67 PatternEditorTools::Position start, end, startCopy, endCopy; 68 Selection()69 Selection() 70 { 71 reset(); 72 startCopy = start; 73 endCopy = end; 74 copyValid = false; 75 } 76 reset()77 void reset() 78 { 79 start.channel = -1; 80 start.row = -1; 81 start.inner = 0; 82 end.channel = -1; 83 end.row = -1; 84 end.inner = 7; 85 } 86 isValid()87 bool isValid() 88 { 89 return (start.channel >= 0 && start.row >= 0 && 90 end.channel >= 0 && end.row >= 0); 91 } 92 isCopyValid()93 bool isCopyValid() 94 { 95 return (startCopy.channel >= 0 && startCopy.row >= 0 && 96 endCopy.channel >= 0 && endCopy.row >= 0) && copyValid; 97 } 98 99 void backup(); 100 101 void restore(); 102 }; 103 104 struct TCommand 105 { 106 pp_uint8 effect; 107 pp_uint8 operand; 108 }; 109 110 private: 111 class ClipBoard 112 { 113 private: 114 mp_ubyte* buffer; 115 116 PatternEditorTools::Position selectionStart, selectionEnd; 117 118 pp_int32 selectionWidth; 119 pp_int32 selectionHeight; 120 121 // FT2 uses different clipboards for track/pattern/block operations 122 // so a regular singleton design won't cut it 123 static ClipBoard* instances[ClipBoardTypeLAST]; 124 125 ClipBoard(); 126 127 public: 128 ~ClipBoard(); 129 130 static ClipBoard* getInstance(ClipBoardTypes type); 131 132 void makeCopy(TXMPattern& pattern, 133 const PatternEditorTools::Position& ss, const PatternEditorTools::Position& se, 134 bool clear = false); 135 void paste(TXMPattern& pattern, pp_int32 sc, pp_int32 sr, bool transparent = false); isEmpty()136 bool isEmpty() const { return buffer == NULL; } 137 getNumRows()138 pp_int32 getNumRows() { return selectionHeight; } getNumChannels()139 pp_int32 getNumChannels() { return selectionWidth; } 140 }; 141 142 // operations 143 enum LastChanges 144 { 145 LastChangeNone, 146 LastChangeSlotChange, 147 LastChangeInsertNote, 148 LastChangeInsertLine, 149 LastChangeDeleteNote, 150 LastChangeDeleteLine, 151 LastChangeDeleteNoteVolumeAndEffect, 152 LastChangeDeleteVolumeAndEffect, 153 LastChangeDeleteEffect, 154 LastChangeWriteMacro, 155 LastChangeCut, 156 LastChangePaste, 157 LastChangeDeleteSelection, 158 LastChangeMoveSelection, 159 LastChangeCloneSelection, 160 161 LastChangeExpandPattern, 162 LastChangeShrinkPattern, 163 LastChangeResizePattern, 164 165 LastChangeLoadXPattern, 166 LastChangeLoadXTrack, 167 168 LastChangeInsIncSelection, 169 LastChangeInsDecSelection, 170 LastChangeInsIncTrack, 171 LastChangeInsDecTrack, 172 LastChangeInsRemapTrack, 173 LastChangeInsRemapPattern, 174 LastChangeInsRemapSelection, 175 176 LastChangeNoteTransposeTrack, 177 LastChangeNoteTransposePattern, 178 LastChangeNoteTransposeSelection, 179 180 LastChangeNoteInterpolate, 181 LastChangeSplitTrack, 182 LastChangeSwapChannels, 183 LastChangeScaleVolume, 184 185 LastChangeZeroOperandsTrack, 186 LastChangeZeroOperandsPattern, 187 LastChangeZeroOperandsSelection, 188 189 LastChangeFillOperandsTrack, 190 LastChangeFillOperandsPattern, 191 LastChangeFillOperandsSelection, 192 193 LastChangeRelocateCommandsTrack, 194 LastChangeRelocateCommandsPattern, 195 LastChangeRelocateCommandsSelection 196 }; 197 198 private: 199 TXMPattern* pattern; 200 201 // Current cursor position 202 PatternEditorTools::Position cursor; 203 // Current selection 204 Selection selection; 205 206 pp_int32 numVisibleChannels; 207 bool autoResize; 208 pp_int32 currentInstrument; 209 bool instrumentEnabled; 210 bool instrumentBackTrace; 211 pp_int32 currentOctave; 212 213 // undo/redo information 214 UndoStackEntry::UserData undoUserData; 215 PatternUndoStackEntry* before; 216 PPUndoStack<PatternUndoStackEntry>* undoStack; 217 UndoHistory<TXMPattern, PatternUndoStackEntry>* undoHistory; 218 LastChanges lastChange; 219 bool lastOperationDidChangeRows; 220 bool lastOperationDidChangeCursor; 221 222 TCommand effectMacros[20]; 223 224 void prepareUndo(); 225 bool finishUndo(LastChanges lastChange, bool nonRepeat = false); 226 227 bool revoke(const PatternUndoStackEntry* stackEntry); 228 229 void cut(ClipBoard& clipBoard); 230 void copy(ClipBoard& clipBoard); 231 void paste(ClipBoard& clipBoard, bool transparent = false, pp_int32 fromChannel = -1); 232 233 void clearRange(const PatternEditorTools::Position& rangeStart, const PatternEditorTools::Position& rangeEnd); 234 235 public: 236 PatternEditor(); 237 virtual ~PatternEditor(); 238 239 // query status getLastOperationDidChangeRows()240 bool getLastOperationDidChangeRows() const { return lastOperationDidChangeRows; } getLastOperationDidChangeCursor()241 bool getLastOperationDidChangeCursor() const { return lastOperationDidChangeCursor; } 242 243 void attachPattern(TXMPattern* pattern, XModule* module); getPattern()244 TXMPattern* getPattern() { return pattern; } 245 246 void reset(); 247 248 pp_int32 getNumChannels() const; 249 pp_int32 getNumRows() const; 250 setNumVisibleChannels(pp_int32 numVisibleChannels)251 void setNumVisibleChannels(pp_int32 numVisibleChannels) { this->numVisibleChannels = numVisibleChannels; } setAutoResize(bool autoResize)252 void setAutoResize(bool autoResize) { this->autoResize = autoResize; } getAutoResize()253 bool getAutoResize() const { return autoResize; } 254 255 // dealing with current cursor setCursor(const PatternEditorTools::Position & cursor)256 void setCursor(const PatternEditorTools::Position& cursor) { this->cursor = cursor; } getCursor()257 PatternEditorTools::Position& getCursor() { return cursor; } 258 resetCursor()259 void resetCursor() { cursor.row = cursor.channel = cursor.inner = 0; } 260 261 // dealing with the selection setSelection(const Selection & selection)262 void setSelection(const Selection& selection) { this->selection = selection; } getSelection()263 Selection& getSelection() { return selection; } setSelectionStart(const PatternEditorTools::Position & pos)264 void setSelectionStart(const PatternEditorTools::Position& pos) { selection.start = pos; } setSelectionEnd(const PatternEditorTools::Position & pos)265 void setSelectionEnd(const PatternEditorTools::Position& pos) { selection.end = pos; } resetSelection()266 void resetSelection() { selection.reset(); } 267 bool hasValidSelection(); 268 bool canMoveSelection(pp_int32 channels, pp_int32 rows); 269 bool selectionContains(const PatternEditorTools::Position& pos); 270 void selectChannel(pp_int32 channel); 271 void selectAll(); 272 273 // dealing with instrument setCurrentInstrument(pp_int32 ins)274 void setCurrentInstrument(pp_int32 ins) { currentInstrument = ins; } 275 pp_int32 getCurrentActiveInstrument(); enableInstrument(bool instrumentEnabled)276 void enableInstrument(bool instrumentEnabled) { this->instrumentEnabled = instrumentEnabled; } isInstrumentEnabled()277 bool isInstrumentEnabled() { return instrumentEnabled; } 278 // Intelligent instrument backtrace? setInstrumentBackTrace(bool instrumentBackTrace)279 void setInstrumentBackTrace(bool instrumentBackTrace) { this->instrumentBackTrace = instrumentBackTrace; } 280 setCurrentOctave(pp_int32 octave)281 void setCurrentOctave(pp_int32 octave) { currentOctave = octave; } getCurrentOctave()282 pp_int32 getCurrentOctave() const { return currentOctave; } increaseCurrentOctave()283 void increaseCurrentOctave() { if (currentOctave < 8) currentOctave++; } decreaseCurrentOctave()284 void decreaseCurrentOctave() { if (currentOctave > 1) currentOctave--; } 285 286 // --- Multilevel UNDO / REDO -------------------------------------------- canUndo()287 bool canUndo() const { if (undoStack) return !undoStack->IsEmpty(); else return false; } canRedo()288 bool canRedo() const { if (undoStack) return !undoStack->IsTop(); else return false; } 289 // undo last changes 290 bool undo(); 291 // redo last changes 292 bool redo(); setUndoUserData(const void * data,pp_uint32 dataLen)293 void setUndoUserData(const void* data, pp_uint32 dataLen) { this->undoUserData = UndoStackEntry::UserData((pp_uint8*)data, dataLen); } getUndoUserDataLen()294 pp_uint32 getUndoUserDataLen() const { return undoUserData.getDataLen(); } getUndoUserData()295 const void* getUndoUserData() const { return (void*)undoUserData.getData(); } 296 297 // --- dealing with the pattern data ------------------------------------- 298 void clearSelection(); 299 300 void clearPattern(); 301 clipBoardSelectionIsEmpty()302 bool clipBoardSelectionIsEmpty() const { return ClipBoard::getInstance(ClipBoardTypeSelection)->isEmpty(); } 303 304 void cut(ClipBoardTypes clipBoardType); 305 void copy(ClipBoardTypes clipBoardType); 306 void paste(ClipBoardTypes clipBoardType, bool transparent = false, pp_int32 fromChannel = -1); 307 308 // resize pattern to a new number of rows 309 bool resizePattern(pp_int32 newRowNum, bool withUndo = true); 310 311 // insert a blank line after each pattern line 312 bool expandPattern(); 313 314 // delete every odd pattern line 315 bool shrinkPattern(); 316 317 // Load extended pattern from file (.XP) 318 bool loadExtendedPattern(const PPSystemString& fileName); 319 bool saveExtendedPattern(const PPSystemString& fileName); 320 321 // Load extended track from file (.XT) 322 bool loadExtendedTrack(const PPSystemString& fileName); 323 bool saveExtendedTrack(const PPSystemString& fileName); 324 325 // --- increase/decrease/remap instruments ------------------------------------------------- 326 pp_int32 insIncSelection(); 327 pp_int32 insDecSelection(); 328 pp_int32 insIncTrack(); 329 pp_int32 insDecTrack(); 330 pp_int32 insRemapTrack(pp_int32 oldIns, pp_int32 newIns); 331 pp_int32 insRemapPattern(pp_int32 oldIns, pp_int32 newIns); 332 pp_int32 insRemapSelection(pp_int32 oldIns, pp_int32 newIns); 333 334 // --- transpose notes --------------------------------------------------- 335 pp_int32 noteTransposeTrackCore(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate); 336 pp_int32 noteTransposePatternCore(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate); 337 pp_int32 noteTransposeSelectionCore(const PatternEditorTools::TransposeParameters& transposeParameters, bool evaluate); 338 339 // --- interpolate values in current selection --------------------------- 340 pp_int32 interpolateValuesInSelection(); 341 342 // --- split track ------------------------------------------------------- 343 pp_int32 splitTrack(pp_int32 useChannels, bool selectionOnly, bool insertNoteOff); 344 345 // --- swap channels ----------------------------------------------------- 346 pp_int32 swapChannels(pp_int32 dstChannel, pp_int32 srcChannel); 347 348 // --- FT2 compatible scale volume function ------------------------------ 349 pp_int32 scaleVolume(const PatternEditorTools::Position& startSelection, const PatternEditorTools::Position& endSelection, float startScale, float endScale); 350 pp_int32 scaleVolumeTrack(float startScale, float endScale); 351 pp_int32 scaleVolumePattern(float startScale, float endScale); 352 pp_int32 scaleVolumeSelection(float startScale, float endScale); 353 354 // --- Zero out unecessary operands -------------------------------------- 355 pp_int32 zeroOperandsTrack(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 356 pp_int32 zeroOperandsPattern(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 357 pp_int32 zeroOperandsSelection(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 358 359 // --- Fill in zero operands --------------------------------------------- 360 pp_int32 fillOperandsTrack(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 361 pp_int32 fillOperandsPattern(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 362 pp_int32 fillOperandsSelection(const PatternEditorTools::OperandOptimizeParameters& optimizeParameters, bool evaluate); 363 364 // --- Relocate FX into volume column if possible ------------------------ 365 pp_int32 relocateCommandsTrack(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate); 366 pp_int32 relocateCommandsPattern(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate); 367 pp_int32 relocateCommandsSelection(const PatternEditorTools::RelocateParameters& relocateParameters, bool evaluate); 368 369 // --- write slot data --------------------------------------------------- 370 bool writeNote(pp_int32 note, 371 bool withUndo = false, 372 PatternAdvanceInterface* advanceImpl = NULL); 373 374 // --- write through, without undo etc. ---------------------------------- 375 void writeDirectNote(pp_int32 note, 376 pp_int32 track = -1, 377 pp_int32 row = -1, 378 pp_int32 order = -1); 379 380 enum NibbleTypes 381 { 382 NibbleTypeLow, 383 NibbleTypeHigh, 384 NibbleTypeBoth 385 }; 386 387 bool writeInstrument(NibbleTypes nibleType, pp_uint8 value, bool withUndo = false, PatternAdvanceInterface* advanceImpl = NULL); 388 bool writeFT2Volume(NibbleTypes nibleType, pp_uint8 value, bool withUndo = false, PatternAdvanceInterface* advanceImpl = NULL); 389 bool writeEffectNumber(pp_uint8 value, bool withUndo = false, PatternAdvanceInterface* advanceImpl = NULL); 390 bool writeEffectOperand(NibbleTypes nibleType, pp_uint8 value, bool withUndo = false, PatternAdvanceInterface* advanceImpl = NULL); 391 392 bool writeEffect(pp_int32 effNum, pp_uint8 eff, pp_uint8 op, 393 bool withUndo = false, 394 PatternAdvanceInterface* advanceImpl = NULL); 395 396 // --- write through, without undo etc. ---------------------------------- 397 void writeDirectEffect(pp_int32 effNum, pp_uint8 eff, pp_uint8 op, 398 pp_int32 track = -1, 399 pp_int32 row = -1, 400 pp_int32 order = -1); 401 402 // --- dealing with FT2 style effect macros ------------------------------ 403 void storeMacroFromCursor(pp_int32 slot); 404 void writeMacroToCursor(pp_int32 slot, PatternAdvanceInterface* advanceImpl = NULL); 405 406 void getMacroOperands(pp_int32 slot, pp_uint8& eff, pp_uint8& op); 407 void setMacroOperands(pp_int32 slot, pp_uint8 eff, pp_uint8 op); 408 409 // --- deleting slot data ------------------------------------------------ 410 void deleteCursorSlotData(PatternAdvanceInterface* advanceImpl = NULL); 411 void deleteCursorSlotDataEntire(PatternAdvanceInterface* advanceImpl = NULL); 412 void deleteCursorSlotDataVolumeAndEffect(PatternAdvanceInterface* advanceImpl = NULL); 413 void deleteCursorSlotDataEffect(PatternAdvanceInterface* advanceImpl = NULL); 414 415 // --- inserting/deleting entire rows ------------------------------------ 416 void insertNote(pp_int32 channel, pp_int32 row); 417 void insertLine(pp_int32 row); 418 void deleteNote(pp_int32 channel, pp_int32 row); 419 void deleteLine(pp_int32 row); 420 421 // --- moving entire selection ------------------------------------------- 422 void moveSelection(pp_int32 channels, pp_int32 rows); 423 void cloneSelection(pp_int32 channels, pp_int32 rows); 424 425 }; 426 427 #endif 428