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