1
0

View_pat.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * View_pat.h
  3. * ----------
  4. * Purpose: Pattern tab, lower panel.
  5. * Notes : (currently none)
  6. * Authors: Olivier Lapicque
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #pragma once
  11. #include "openmpt/all/BuildSettings.hpp"
  12. #include "Globals.h"
  13. #include "PatternCursor.h"
  14. #include "Moddoc.h"
  15. #include "PatternEditorDialogs.h"
  16. #include "PatternClipboard.h"
  17. OPENMPT_NAMESPACE_BEGIN
  18. class CModDoc;
  19. class CEditCommand;
  20. class CEffectVis;
  21. class CInputHandler;
  22. // Drag & Drop info
  23. class DragItem
  24. {
  25. uint32 v = 0;
  26. enum : uint32
  27. {
  28. ValueMask = 0x00FFFFFF,
  29. TypeMask = 0xFF000000,
  30. };
  31. public:
  32. enum DragType : uint32
  33. {
  34. ChannelHeader = 0x01000000,
  35. PatternHeader = 0x02000000,
  36. PluginName = 0x04000000,
  37. };
  38. DragItem() = default;
  39. DragItem(DragType type, uint32 value)
  40. : v(type | value) {}
  41. DragType Type() const { return static_cast<DragType>(v & TypeMask); }
  42. uint32 Value() const { return v & ValueMask; }
  43. INT_PTR ToIntPtr() const { return v; }
  44. bool IsValid() const { return v != 0; }
  45. bool operator==(const DragItem other) const { return v == other.v; }
  46. bool operator!=(const DragItem other) const { return v != other.v; }
  47. };
  48. // Edit Step aka Row Spacing
  49. inline constexpr ROWINDEX MAX_SPACING = MAX_PATTERN_ROWS;
  50. // Struct for controlling selection clearing. This is used to define which data fields should be cleared.
  51. struct RowMask
  52. {
  53. bool note : 1;
  54. bool instrument : 1;
  55. bool volume : 1;
  56. bool command : 1;
  57. bool parameter : 1;
  58. // Default row mask (all rows are selected)
  59. RowMask()
  60. {
  61. note = instrument = volume = command = parameter = true;
  62. };
  63. // Construct mask from list
  64. RowMask(bool n, bool i, bool v, bool c, bool p)
  65. {
  66. note = n;
  67. instrument = i;
  68. volume = v;
  69. command = c;
  70. parameter = p;
  71. }
  72. // Construct mask from column index
  73. RowMask(const PatternCursor &cursor)
  74. {
  75. const PatternCursor::Columns column = cursor.GetColumnType();
  76. note = (column == PatternCursor::noteColumn);
  77. instrument = (column == PatternCursor::instrColumn);
  78. volume = (column == PatternCursor::volumeColumn);
  79. command = (column == PatternCursor::effectColumn);
  80. parameter = (column == PatternCursor::paramColumn);
  81. }
  82. void Clear()
  83. {
  84. note = instrument = volume = command = parameter = false;
  85. }
  86. };
  87. struct PatternEditPos
  88. {
  89. ROWINDEX row = ROWINDEX_INVALID;
  90. ORDERINDEX order = ORDERINDEX_INVALID;
  91. PATTERNINDEX pattern = PATTERNINDEX_INVALID;
  92. CHANNELINDEX channel = CHANNELINDEX_INVALID;
  93. };
  94. // Pattern editing class
  95. class CViewPattern final : public CModScrollView
  96. {
  97. public:
  98. // Pattern status flags
  99. enum PatternStatus
  100. {
  101. psMouseDragSelect = 0x01, // Creating a selection using the mouse
  102. psKeyboardDragSelect = 0x02, // Creating a selection using shortcuts
  103. psFocussed = 0x04, // Is the pattern editor focussed
  104. psFollowSong = 0x08, // Does the cursor follow playback
  105. psRecordingEnabled = 0x10, // Recording enabled
  106. psDragVScroll = 0x40, // Indicates that the vertical scrollbar is being dragged
  107. psShowVUMeters = 0x80, // Display channel VU meters
  108. psChordPlaying = 0x100, // Is a chord playing? (pretty much unused)
  109. psDragnDropEdit = 0x200, // Drag & Drop editing (?)
  110. psDragnDropping = 0x400, // Dragging a selection around
  111. psShiftSelect = 0x800, // User has made at least one selection using Shift-Click since the Shift key has been pressed.
  112. psCtrlDragSelect = 0x1000, // Creating a selection using Ctrl
  113. psShowPluginNames = 0x2000, // Show plugin names in channel headers
  114. psRowSelection = 0x4000, // Selecting a whole pattern row by clicking the row numbers
  115. psChannelSelection = 0x8000, // Double-clicked pattern to select a whole channel
  116. psDragging = 0x10000, // Drag&Drop: Dragging an item around
  117. psShiftDragging = 0x20000, // Drag&Drop: Dragging an item around and holding shift
  118. // All possible drag flags, to test if user is dragging a selection or a scrollbar
  119. psDragActive = psDragVScroll | psMouseDragSelect | psRowSelection | psChannelSelection,
  120. };
  121. protected:
  122. CFastBitmap m_Dib;
  123. CDC m_offScreenDC;
  124. CBitmap m_offScreenBitmap;
  125. CEditCommand *m_pEditWnd = nullptr;
  126. CSize m_szHeader, m_szPluginHeader, m_szCell;
  127. CRect m_oldClient;
  128. UINT m_nMidRow, m_nSpacing, m_nAccelChar, m_nLastPlayedRow, m_nLastPlayedOrder;
  129. FlagSet<PatternStatus> m_Status;
  130. ROWINDEX m_nPlayRow, m_nNextPlayRow;
  131. uint32 m_nPlayTick, m_nTicksOnRow;
  132. PATTERNINDEX m_nPattern = 0, m_nPlayPat = 0;
  133. ORDERINDEX m_nOrder = 0;
  134. static int32 m_nTransposeAmount;
  135. int m_nXScroll = 0, m_nYScroll = 0;
  136. PatternCursor::Columns m_nDetailLevel = PatternCursor::lastColumn; // Visible Columns
  137. // Cursor and selection positions
  138. PatternCursor m_Cursor; // Current cursor position in pattern.
  139. PatternCursor m_StartSel, m_DragPos; // Point where selection was started.
  140. PatternCursor m_MenuCursor; // Position at which context menu was opened.
  141. PatternRect m_Selection; // Upper-left / Lower-right corners of selection.
  142. // Drag&Drop
  143. DragItem m_nDragItem; // Currently dragged item
  144. DragItem m_nDropItem; // Currently hovered item during dragondrop
  145. RECT m_rcDragItem, m_rcDropItem;
  146. bool m_bInItemRect = false;
  147. // Drag-select record group
  148. std::vector<RecordGroup> m_initialDragRecordStatus;
  149. ModCommand::INSTR m_fallbackInstrument = 0;
  150. // Chord auto-detect interval
  151. DWORD m_autoChordStartTime = 0;
  152. ROWINDEX m_autoChordStartRow = ROWINDEX_INVALID;
  153. ORDERINDEX m_autoChordStartOrder = ORDERINDEX_INVALID;
  154. bool m_bContinueSearch : 1, m_bWholePatternFitsOnScreen : 1;
  155. ModCommand m_PCNoteEditMemory; // PC Note edit memory
  156. static ModCommand m_cmdOld; // Quick cursor copy/paste data
  157. QuickChannelProperties m_quickChannelProperties;
  158. // Chord preview
  159. CHANNELINDEX m_chordPatternChannels[MPTChord::notesPerChord];
  160. ModCommand::NOTE m_prevChordNote, m_prevChordBaseNote;
  161. // Note-off event buffer for MIDI sustain pedal
  162. std::array<std::vector<uint32>, 16> m_midiSustainBuffer;
  163. std::bitset<16> m_midiSustainActive;
  164. std::array<uint16, MAX_BASECHANNELS> ChnVUMeters;
  165. std::array<uint16, MAX_BASECHANNELS> OldVUMeters;
  166. std::bitset<128> m_baPlayingNote;
  167. CModDoc::NoteToChannelMap m_noteChannel; // Note -> Preview channel assignment
  168. std::array<ModCommand::NOTE, 10> m_octaveKeyMemory;
  169. std::array<ModCommand::NOTE, MAX_BASECHANNELS> m_previousNote;
  170. std::array<uint8, NOTE_MAX + NOTE_MIN> m_activeNoteChannel;
  171. std::array<uint8, NOTE_MAX + NOTE_MIN> m_splitActiveNoteChannel;
  172. static constexpr uint8 NOTE_CHANNEL_MAP_INVALID = 0xFF;
  173. static_assert(MAX_BASECHANNELS <= std::numeric_limits<decltype(m_activeNoteChannel)::value_type>::max());
  174. static_assert(MAX_BASECHANNELS <= NOTE_CHANNEL_MAP_INVALID);
  175. public:
  176. std::unique_ptr<CEffectVis> m_pEffectVis;
  177. CViewPattern();
  178. ~CViewPattern();
  179. DECLARE_SERIAL(CViewPattern)
  180. public:
  181. const CSoundFile *GetSoundFile() const;
  182. CSoundFile *GetSoundFile();
  183. const ModSequence &Order() const;
  184. ModSequence &Order();
  185. void SetModified(bool updateAllViews = true);
  186. bool UpdateSizes();
  187. void UpdateScrollSize();
  188. void UpdateScrollPos();
  189. void UpdateIndicator(bool updateAccessibility = true);
  190. void UpdateXInfoText();
  191. void UpdateColors();
  192. CString GetCursorDescription() const;
  193. int GetXScrollPos() const { return m_nXScroll; }
  194. int GetYScrollPos() const { return m_nYScroll; }
  195. int GetChannelWidth() const { return m_szCell.cx; }
  196. int GetRowHeight() const { return m_szCell.cy; }
  197. int GetSmoothScrollOffset() const;
  198. PATTERNINDEX GetCurrentPattern() const { return m_nPattern; }
  199. ROWINDEX GetCurrentRow() const { return m_Cursor.GetRow(); }
  200. CHANNELINDEX GetCurrentChannel() const { return m_Cursor.GetChannel(); }
  201. ORDERINDEX GetCurrentOrder() const { return m_nOrder; }
  202. void SetCurrentOrder(ORDERINDEX ord)
  203. {
  204. m_nOrder = ord;
  205. SendCtrlMessage(CTRLMSG_SETCURRENTORDER, ord);
  206. }
  207. // Get ModCommand at the pattern cursor position.
  208. ModCommand &GetCursorCommand() { return GetModCommand(m_Cursor); };
  209. const ModCommand& GetCursorCommand() const { return const_cast<CViewPattern *>(this)->GetModCommand(m_Cursor); };
  210. void SanitizeCursor();
  211. UINT GetColumnOffset(PatternCursor::Columns column) const;
  212. POINT GetPointFromPosition(PatternCursor cursor) const;
  213. PatternCursor GetPositionFromPoint(POINT pt) const;
  214. DragItem GetDragItem(CPoint point, RECT &rect) const;
  215. void StartRecordGroupDragging(const DragItem source);
  216. void ResetRecordGroupDragging() { m_initialDragRecordStatus.clear(); }
  217. bool IsDraggingRecordGroup() const { return !m_initialDragRecordStatus.empty(); }
  218. ROWINDEX GetRowsPerBeat() const;
  219. ROWINDEX GetRowsPerMeasure() const;
  220. // Invalidate functions (for redrawing areas of the pattern)
  221. void InvalidatePattern(bool invalidateChannelHeaders = false, bool invalidateRowHeaders = false);
  222. void InvalidateRow(ROWINDEX n = ROWINDEX_INVALID);
  223. void InvalidateArea(const PatternRect &rect) { InvalidateArea(rect.GetUpperLeft(), rect.GetLowerRight()); };
  224. void InvalidateArea(PatternCursor begin, PatternCursor end);
  225. void InvalidateSelection() { InvalidateArea(m_Selection); }
  226. void InvalidateCell(PatternCursor cursor);
  227. void InvalidateChannelsHeaders(CHANNELINDEX chn = CHANNELINDEX_INVALID);
  228. // Selection functions
  229. void SetCurSel(const PatternRect &rect) { SetCurSel(rect.GetUpperLeft(), rect.GetLowerRight()); };
  230. void SetCurSel(const PatternCursor &point) { SetCurSel(point, point); };
  231. void SetCurSel(PatternCursor beginSel, PatternCursor endSel);
  232. void SetSelToCursor() { SetCurSel(m_Cursor); };
  233. bool SetCurrentPattern(PATTERNINDEX pat, ROWINDEX row = ROWINDEX_INVALID);
  234. ROWINDEX SetCurrentRow(ROWINDEX row, bool wrap = false, bool updateHorizontalScrollbar = true);
  235. bool SetCurrentColumn(const PatternCursor &cursor) { return SetCurrentColumn(cursor.GetChannel(), cursor.GetColumnType()); };
  236. bool SetCurrentColumn(CHANNELINDEX channel, PatternCursor::Columns column = PatternCursor::firstColumn);
  237. // This should be used instead of consecutive calls to SetCurrentRow() then SetCurrentColumn()
  238. bool SetCursorPosition(const PatternCursor &cursor, bool wrap = false);
  239. bool DragToSel(const PatternCursor &cursor, bool scrollHorizontal, bool scrollVertical, bool noMove = false);
  240. bool SetPlayCursor(PATTERNINDEX pat, ROWINDEX row, uint32 tick);
  241. bool UpdateScrollbarPositions(bool updateHorizontalScrollbar = true);
  242. bool ShowEditWindow();
  243. UINT GetCurrentInstrument() const;
  244. void SelectBeatOrMeasure(bool selectBeat);
  245. // Move pattern cursor to left or right, respecting invisible columns.
  246. void MoveCursor(bool moveRight);
  247. bool TransposeSelection(int transp);
  248. bool DataEntry(bool up, bool coarse);
  249. bool PrepareUndo(const PatternRect &selection, const char *description) { return PrepareUndo(selection.GetUpperLeft(), selection.GetLowerRight(), description); };
  250. bool PrepareUndo(const PatternCursor &beginSel, const PatternCursor &endSel, const char *description);
  251. void UndoRedo(bool undo);
  252. bool InsertOrDeleteRows(CHANNELINDEX firstChn, CHANNELINDEX lastChn, bool globalEdit, bool deleteRows);
  253. void DeleteRows(CHANNELINDEX firstChn, CHANNELINDEX lastChn, bool globalEdit = false);
  254. void InsertRows(CHANNELINDEX firstChn, CHANNELINDEX lastChn, bool globalEdit = false);
  255. void OnDropSelection();
  256. public:
  257. void DrawPatternData(HDC hdc, PATTERNINDEX nPattern, bool selEnable, bool isPlaying, ROWINDEX startRow, ROWINDEX numRows, CHANNELINDEX startChan, CRect &rcClient, int *pypaint);
  258. void DrawLetter(int x, int y, char letter, int sizex = 10, int ofsx = 0);
  259. void DrawLetter(int x, int y, wchar_t letter, int sizex = 10, int ofsx = 0);
  260. #if MPT_CXX_AT_LEAST(20)
  261. void DrawLetter(int x, int y, char8_t letter, int sizex = 10, int ofsx = 0);
  262. #endif
  263. void DrawNote(int x, int y, UINT note, CTuning *pTuning = nullptr);
  264. void DrawInstrument(int x, int y, UINT instr);
  265. void DrawVolumeCommand(int x, int y, const ModCommand &mc, bool drawDefaultVolume);
  266. void DrawChannelVUMeter(HDC hdc, int x, int y, UINT nChn);
  267. void UpdateAllVUMeters(Notification *pnotify);
  268. void DrawDragSel(HDC hdc);
  269. void OnDrawDragSel();
  270. // True if default volume should be drawn for a given cell.
  271. static bool DrawDefaultVolume(const ModCommand *m) { return (TrackerSettings::Instance().m_dwPatternSetup & PATTERN_SHOWDEFAULTVOLUME) && m->volcmd == VOLCMD_NONE && m->command != CMD_VOLUME && m->instr != 0 && m->IsNote(); }
  272. void CursorJump(int distance, bool snap);
  273. void TempEnterNote(ModCommand::NOTE n, int vol = -1, bool fromMidi = false);
  274. void TempStopNote(ModCommand::NOTE note, const bool fromMidi = false, bool chordMode = false);
  275. void TempEnterChord(ModCommand::NOTE n);
  276. void TempStopChord(ModCommand::NOTE note) { TempStopNote(note, false, true); }
  277. void TempEnterIns(int val);
  278. void TempEnterOctave(int val);
  279. void TempStopOctave(int val);
  280. void TempEnterVol(int v);
  281. void TempEnterFX(ModCommand::COMMAND c, int v = -1);
  282. void TempEnterFXparam(int v);
  283. void EnterAftertouch(ModCommand::NOTE note, int atValue);
  284. int GetDefaultVolume(const ModCommand &m, ModCommand::INSTR lastInstr = 0) const;
  285. int GetBaseNote() const;
  286. ModCommand::NOTE GetNoteWithBaseOctave(int note) const;
  287. // Construct a chord from the chord presets. Returns number of notes in chord.
  288. int ConstructChord(int note, ModCommand::NOTE (&outNotes)[MPTChord::notesPerChord], ModCommand::NOTE baseNote);
  289. void QuantizeRow(PATTERNINDEX &pat, ROWINDEX &row) const;
  290. PATTERNINDEX GetPrevPattern() const;
  291. PATTERNINDEX GetNextPattern() const;
  292. void SetSpacing(int n);
  293. void OnClearField(const RowMask &mask, bool step, bool ITStyle = false);
  294. void SetSelectionInstrument(const INSTRUMENTINDEX instr, bool setEmptyInstrument);
  295. void FindInstrument();
  296. void JumpToPrevOrNextEntry(bool nextEntry, bool select);
  297. void TogglePluginEditor(int chan);
  298. void ExecutePaste(PatternClipboard::PasteModes mode);
  299. // Reset all channel variables
  300. void ResetChannel(CHANNELINDEX chn);
  301. public:
  302. //{{AFX_VIRTUAL(CViewPattern)
  303. void OnDraw(CDC *) override;
  304. void OnInitialUpdate() override;
  305. BOOL OnScrollBy(CSize sizeScroll, BOOL bDoScroll = TRUE) override;
  306. BOOL PreTranslateMessage(MSG *pMsg) override;
  307. void UpdateView(UpdateHint hint, CObject *pObj = nullptr) override;
  308. LRESULT OnModViewMsg(WPARAM, LPARAM) override;
  309. LRESULT OnPlayerNotify(Notification *) override;
  310. INT_PTR OnToolHitTest(CPoint point, TOOLINFO *pTI) const override;
  311. //}}AFX_VIRTUAL
  312. protected:
  313. //{{AFX_MSG(CViewPattern)
  314. afx_msg BOOL OnEraseBkgnd(CDC *) { return TRUE; }
  315. afx_msg void OnSize(UINT nType, int cx, int cy);
  316. afx_msg void OnDestroy();
  317. afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
  318. afx_msg void OnXButtonUp(UINT nFlags, UINT nButton, CPoint point);
  319. afx_msg void OnMouseMove(UINT, CPoint);
  320. afx_msg void OnLButtonUp(UINT, CPoint);
  321. afx_msg void OnLButtonDown(UINT, CPoint);
  322. afx_msg void OnLButtonDblClk(UINT, CPoint);
  323. afx_msg void OnRButtonDown(UINT, CPoint);
  324. afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar);
  325. afx_msg void OnSetFocus(CWnd *pOldWnd);
  326. afx_msg void OnKillFocus(CWnd *pNewWnd);
  327. afx_msg void OnEditCut();
  328. afx_msg void OnEditCopy();
  329. afx_msg void OnEditPaste() { ExecutePaste(PatternClipboard::pmOverwrite); };
  330. afx_msg void OnEditMixPaste() { ExecutePaste(PatternClipboard::pmMixPaste); };
  331. afx_msg void OnEditMixPasteITStyle() { ExecutePaste(PatternClipboard::pmMixPasteIT); };
  332. afx_msg void OnEditPasteFlood() { ExecutePaste(PatternClipboard::pmPasteFlood); };
  333. afx_msg void OnEditPushForwardPaste() { ExecutePaste(PatternClipboard::pmPushForward); };
  334. afx_msg void OnClearSelection(bool ITStyle = false, RowMask sb = RowMask());
  335. afx_msg void OnGrowSelection();
  336. afx_msg void OnShrinkSelection();
  337. afx_msg void OnEditSelectAll();
  338. afx_msg void OnEditSelectChannel();
  339. afx_msg void OnSelectCurrentChannel();
  340. afx_msg void OnSelectCurrentColumn();
  341. afx_msg void OnEditFind();
  342. afx_msg void OnEditGoto();
  343. afx_msg void OnEditFindNext();
  344. afx_msg void OnEditUndo();
  345. afx_msg void OnEditRedo();
  346. afx_msg void OnChannelReset();
  347. afx_msg void OnMuteFromClick();
  348. afx_msg void OnSoloFromClick();
  349. afx_msg void OnTogglePendingMuteFromClick();
  350. afx_msg void OnPendingSoloChnFromClick();
  351. afx_msg void OnPendingUnmuteAllChnFromClick();
  352. afx_msg void OnSoloChannel(CHANNELINDEX chn);
  353. afx_msg void OnMuteChannel(CHANNELINDEX chn);
  354. afx_msg void OnUnmuteAll();
  355. afx_msg void OnRecordSelect();
  356. afx_msg void OnSplitRecordSelect();
  357. afx_msg void OnDeleteRow();
  358. afx_msg void OnDeleteWholeRow();
  359. afx_msg void OnDeleteRowGlobal();
  360. afx_msg void OnDeleteWholeRowGlobal();
  361. afx_msg void OnInsertRow();
  362. afx_msg void OnInsertWholeRow();
  363. afx_msg void OnInsertRowGlobal();
  364. afx_msg void OnInsertWholeRowGlobal();
  365. afx_msg void OnSplitPattern();
  366. afx_msg void OnPatternStep();
  367. afx_msg void OnSwitchToOrderList();
  368. afx_msg void OnPrevOrder();
  369. afx_msg void OnNextOrder();
  370. afx_msg void OnPrevInstrument() { PostCtrlMessage(CTRLMSG_PAT_PREVINSTRUMENT); }
  371. afx_msg void OnNextInstrument() { PostCtrlMessage(CTRLMSG_PAT_NEXTINSTRUMENT); }
  372. afx_msg void OnPatternRecord() { PostCtrlMessage(CTRLMSG_SETRECORD, -1); }
  373. afx_msg void OnInterpolateVolume() { Interpolate(PatternCursor::volumeColumn); }
  374. afx_msg void OnInterpolateEffect() { Interpolate(PatternCursor::effectColumn); }
  375. afx_msg void OnInterpolateNote() { Interpolate(PatternCursor::noteColumn); }
  376. afx_msg void OnInterpolateInstr() { Interpolate(PatternCursor::instrColumn); }
  377. afx_msg void OnVisualizeEffect();
  378. afx_msg void OnTransposeUp() { TransposeSelection(1); }
  379. afx_msg void OnTransposeDown() { TransposeSelection(-1); }
  380. afx_msg void OnTransposeOctUp() { TransposeSelection(12000); }
  381. afx_msg void OnTransposeOctDown() { TransposeSelection(-12000); }
  382. afx_msg void OnTransposeCustom();
  383. afx_msg void OnTransposeCustomQuick();
  384. afx_msg void OnSetSelInstrument();
  385. afx_msg void OnAddChannelFront() { AddChannel(m_MenuCursor.GetChannel(), false); }
  386. afx_msg void OnAddChannelAfter() { AddChannel(m_MenuCursor.GetChannel(), true); };
  387. afx_msg void OnDuplicateChannel();
  388. afx_msg void OnResetChannelColors();
  389. afx_msg void OnTransposeChannel();
  390. afx_msg void OnRemoveChannel();
  391. afx_msg void OnRemoveChannelDialog();
  392. afx_msg void OnPatternProperties() { ShowPatternProperties(PATTERNINDEX_INVALID); }
  393. void ShowPatternProperties(PATTERNINDEX pat);
  394. void OnCursorCopy();
  395. void OnCursorPaste();
  396. afx_msg void OnPatternAmplify();
  397. afx_msg void OnUpdateUndo(CCmdUI *pCmdUI);
  398. afx_msg void OnUpdateRedo(CCmdUI *pCmdUI);
  399. afx_msg void OnSelectPlugin(UINT nID);
  400. afx_msg LRESULT OnUpdatePosition(WPARAM nOrd, LPARAM nRow);
  401. afx_msg LRESULT OnMidiMsg(WPARAM, LPARAM);
  402. afx_msg LRESULT OnRecordPlugParamChange(WPARAM, LPARAM);
  403. afx_msg LRESULT OnCustomKeyMsg(WPARAM, LPARAM);
  404. afx_msg void OnClearSelectionFromMenu();
  405. afx_msg void OnSelectInstrument(UINT nid);
  406. afx_msg void OnSelectPCNoteParam(UINT nid);
  407. afx_msg void OnRunScript();
  408. afx_msg void OnShowTimeAtRow();
  409. afx_msg void OnTogglePCNotePluginEditor();
  410. afx_msg void OnSetQuantize();
  411. afx_msg void OnLockPatternRows();
  412. //}}AFX_MSG
  413. DECLARE_MESSAGE_MAP()
  414. public:
  415. afx_msg void OnInitMenu(CMenu *pMenu);
  416. private:
  417. // Copy&Paste
  418. bool CopyPattern(PATTERNINDEX nPattern, const PatternRect &selection);
  419. bool PastePattern(PATTERNINDEX nPattern, const PatternCursor &pastePos, PatternClipboard::PasteModes mode);
  420. void SetSplitKeyboardSettings();
  421. bool HandleSplit(ModCommand &m, int note);
  422. bool IsNoteSplit(int note) const;
  423. CHANNELINDEX FindGroupRecordChannel(RecordGroup recordGroup, bool forceFreeChannel, CHANNELINDEX startChannel = 0) const;
  424. bool BuildChannelControlCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  425. bool BuildPluginCtxMenu(HMENU hMenu, UINT nChn, const CSoundFile &sndFile) const;
  426. bool BuildRecordCtxMenu(HMENU hMenu, CInputHandler *ih, CHANNELINDEX nChn) const;
  427. bool BuildSoloMuteCtxMenu(HMENU hMenu, CInputHandler *ih, UINT nChn, const CSoundFile &sndFile) const;
  428. bool BuildRowInsDelCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  429. bool BuildMiscCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  430. bool BuildSelectionCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  431. bool BuildGrowShrinkCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  432. bool BuildInterpolationCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  433. bool BuildInterpolationCtxMenu(HMENU hMenu, PatternCursor::Columns colType, CString label, UINT command) const;
  434. bool BuildEditCtxMenu(HMENU hMenu, CInputHandler *ih, CModDoc *pModDoc) const;
  435. bool BuildVisFXCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  436. bool BuildTransposeCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  437. bool BuildSetInstCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  438. bool BuildAmplifyCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  439. bool BuildPCNoteCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  440. bool BuildTogglePlugEditorCtxMenu(HMENU hMenu, CInputHandler *ih) const;
  441. // Returns an ordered list of all channels in which a given column type is selected.
  442. CHANNELINDEX ListChansWhereColSelected(PatternCursor::Columns colType, std::vector<CHANNELINDEX> &chans) const;
  443. // Check if a column type is selected on any channel in the current selection.
  444. bool IsColumnSelected(PatternCursor::Columns colType) const;
  445. bool IsInterpolationPossible(PatternCursor::Columns colType) const;
  446. bool IsInterpolationPossible(ROWINDEX startRow, ROWINDEX endRow, CHANNELINDEX chan, PatternCursor::Columns colType) const;
  447. void Interpolate(PatternCursor::Columns type);
  448. PatternRect SweepPattern(bool (*startCond)(const ModCommand &), bool (*endCond)(const ModCommand &, const ModCommand &)) const;
  449. // Return true if recording live (i.e. editing while following playback).
  450. bool IsLiveRecord() const
  451. {
  452. const CMainFrame *mainFrm = CMainFrame::GetMainFrame();
  453. const CSoundFile *sndFile = GetSoundFile();
  454. if(mainFrm == nullptr || sndFile == nullptr)
  455. {
  456. return false;
  457. }
  458. // (following song) && (following in correct document) && (playback is on)
  459. return m_Status[psFollowSong] && mainFrm->GetFollowSong(GetDocument()) == m_hWnd && !sndFile->IsPaused();
  460. };
  461. // Returns edit position.
  462. PatternEditPos GetEditPos(const CSoundFile &sndFile, const bool liveRecord) const;
  463. // Returns pointer to modcommand at given position.
  464. // If the position is not valid, a pointer to a dummy command is returned.
  465. ModCommand &GetModCommand(PatternCursor cursor);
  466. ModCommand &GetModCommand(CSoundFile &sndFile, const PatternEditPos &pos);
  467. // Returns true if pattern editing is enabled.
  468. bool IsEditingEnabled() const { return m_Status[psRecordingEnabled]; }
  469. // Like IsEditingEnabled(), but shows some notification when editing is not enabled.
  470. bool IsEditingEnabled_bmsg();
  471. // Play one pattern row and stop ("step mode")
  472. void PatternStep(ROWINDEX row = ROWINDEX_INVALID);
  473. // Add a channel.
  474. void AddChannel(CHANNELINDEX parent, bool afterCurrent);
  475. void DragChannel(CHANNELINDEX source, CHANNELINDEX target, CHANNELINDEX numChannels, bool duplicate);
  476. public:
  477. afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);
  478. private:
  479. void TogglePendingMute(CHANNELINDEX nChn);
  480. void PendingSoloChn(CHANNELINDEX nChn);
  481. template <typename Func>
  482. void ApplyToSelection(Func func);
  483. void PlayNote(ModCommand::NOTE note, ModCommand::INSTR instr, int volume, CHANNELINDEX channel);
  484. void PreviewNote(ROWINDEX row, CHANNELINDEX channel);
  485. public:
  486. afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
  487. HRESULT get_accName(VARIANT varChild, BSTR *pszName) override;
  488. };
  489. DECLARE_FLAGSET(CViewPattern::PatternStatus);
  490. void getXParam(ModCommand::COMMAND command, PATTERNINDEX nPat, ROWINDEX nRow, CHANNELINDEX nChannel, const CSoundFile &sndFile, UINT &xparam, UINT &multiplier);
  491. OPENMPT_NAMESPACE_END