View_tre.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * view_tre.h
  3. * ----------
  4. * Purpose: Tree view for managing open songs, sound files, file browser, ...
  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 <vector>
  13. #include <bitset>
  14. OPENMPT_NAMESPACE_BEGIN
  15. class CModDoc;
  16. class CModTree;
  17. class CSoundFile;
  18. class CDLSBank;
  19. struct ModTreeDocInfo
  20. {
  21. // Tree state variables
  22. std::vector<std::vector<HTREEITEM>> tiOrders;
  23. std::vector<HTREEITEM> tiSequences, tiPatterns;
  24. CModDoc &modDoc;
  25. HTREEITEM hSong = nullptr, hPatterns = nullptr, hSamples = nullptr, hInstruments = nullptr, hComments = nullptr, hOrders = nullptr, hEffects = nullptr;
  26. // Module information
  27. ORDERINDEX ordSel = ORDERINDEX_INVALID;
  28. SEQUENCEINDEX seqSel = SEQUENCEINDEX_INVALID;
  29. std::bitset<MAX_SAMPLES> samplesPlaying;
  30. std::bitset<MAX_INSTRUMENTS> instrumentsPlaying;
  31. ModTreeDocInfo(CModDoc &modDoc);
  32. };
  33. class CModTreeDropTarget: public COleDropTarget
  34. {
  35. protected:
  36. CModTree *m_pModTree;
  37. public:
  38. CModTreeDropTarget() { m_pModTree = nullptr; }
  39. BOOL Register(CModTree *pWnd);
  40. public:
  41. DROPEFFECT OnDragEnter(CWnd *pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override;
  42. DROPEFFECT OnDragOver(CWnd *pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override;
  43. BOOL OnDrop(CWnd *pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) override;
  44. };
  45. class CModTree: public CTreeCtrl
  46. {
  47. protected:
  48. enum TreeStatus
  49. {
  50. TREESTATUS_RDRAG = 0x01,
  51. TREESTATUS_LDRAG = 0x02,
  52. TREESTATUS_SINGLEEXPAND = 0x04,
  53. TREESTATUS_DRAGGING = (TREESTATUS_RDRAG | TREESTATUS_LDRAG)
  54. };
  55. enum ModItemType : uint8
  56. {
  57. MODITEM_NULL = 0,
  58. MODITEM_BEGIN_SONGITEMS,
  59. MODITEM_ORDER = MODITEM_BEGIN_SONGITEMS,
  60. MODITEM_PATTERN,
  61. MODITEM_SAMPLE,
  62. MODITEM_INSTRUMENT,
  63. MODITEM_COMMENTS,
  64. MODITEM_EFFECT,
  65. MODITEM_SEQUENCE,
  66. MODITEM_HDR_SONG,
  67. MODITEM_HDR_ORDERS,
  68. MODITEM_HDR_PATTERNS,
  69. MODITEM_HDR_SAMPLES,
  70. MODITEM_HDR_INSTRUMENTS,
  71. MODITEM_HDR_EFFECTS,
  72. MODITEM_END_SONGITEMS = MODITEM_HDR_EFFECTS,
  73. MODITEM_HDR_INSTRUMENTLIB,
  74. MODITEM_HDR_MIDILIB,
  75. MODITEM_HDR_MIDIGROUP,
  76. MODITEM_MIDIINSTRUMENT,
  77. MODITEM_MIDIPERCUSSION,
  78. MODITEM_INSLIB_FOLDER,
  79. MODITEM_INSLIB_SAMPLE,
  80. MODITEM_INSLIB_INSTRUMENT,
  81. MODITEM_INSLIB_SONG,
  82. MODITEM_DLSBANK_FOLDER,
  83. MODITEM_DLSBANK_INSTRUMENT,
  84. };
  85. // Bit mask magic
  86. enum
  87. {
  88. MIDILIB_SHIFT = 16,
  89. MIDILIB_MASK = (1 << MIDILIB_SHIFT) - 1,
  90. // Must be consistent with CCtrlPatterns::OnActivatePage
  91. SEQU_SHIFT = 16,
  92. SEQU_MASK = (1 << SEQU_SHIFT) - 1,
  93. SEQU_INDICATOR = 0x80000000,
  94. // Soundbank instrument identification (must be consistent with CViewInstrument::OnDragonDrop / CViewSample::OnDragonDrop)
  95. DLS_TYPEPERC = 0x80000000,
  96. DLS_INSTRMASK = 0x0000FFFF,
  97. DLS_REGIONMASK = 0x7FFF0000, // Drum region
  98. DLS_REGIONSHIFT = 16,
  99. DLS_DRUM_FOLDER_LPARAM = 0x12345678,
  100. };
  101. static_assert((ORDERINDEX_INVALID & SEQU_MASK) == ORDERINDEX_INVALID, "ORDERINDEX doesn't fit in GetItemData() parameter");
  102. static_assert((ORDERINDEX_MAX & SEQU_MASK) == ORDERINDEX_MAX, "ORDERINDEX doesn't fit in GetItemData() parameter");
  103. static_assert((((SEQUENCEINDEX_INVALID << SEQU_SHIFT) & ~SEQU_INDICATOR) >> SEQU_SHIFT) == SEQUENCEINDEX_INVALID, "SEQUENCEINDEX doesn't fit in GetItemData() parameter");
  104. struct ModItem
  105. {
  106. uint32 val1;
  107. uint16 val2;
  108. ModItemType type;
  109. ModItem(ModItemType t = MODITEM_NULL, uint32 v1 = 0, uint16 v2 = 0) : val1(v1), val2(v2), type(t) { }
  110. bool IsSongItem() const noexcept { return type >= MODITEM_BEGIN_SONGITEMS && type <= MODITEM_END_SONGITEMS; }
  111. bool operator==(const ModItem &other) const noexcept { return val1 == other.val1 && val2 == other.val2 && type == other.type; }
  112. bool operator!=(const ModItem &other) const noexcept { return !(*this == other); }
  113. };
  114. struct DlsItem : public ModItem
  115. {
  116. explicit DlsItem(uint16 instr) : ModItem(MODITEM_DLSBANK_INSTRUMENT, instr, 0) { }
  117. DlsItem(uint16 instr, uint16 region) : ModItem(MODITEM_DLSBANK_INSTRUMENT, (instr & DLS_INSTRMASK) | ((region << DLS_REGIONSHIFT) & DLS_REGIONMASK) | DLS_TYPEPERC, 0) { }
  118. uint32 GetRegion() const noexcept { return (val1 & DLS_REGIONMASK) >> DLS_REGIONSHIFT; }
  119. uint32 GetInstr() const noexcept { return (val1 & DLS_INSTRMASK); }
  120. bool IsPercussion() const noexcept { return ((val1 & DLS_TYPEPERC) == DLS_TYPEPERC); }
  121. bool IsMelodic() const noexcept { return !IsPercussion(); }
  122. static ModItem FromLPARAM(uint32 lparam) { return ModItem{MODITEM_DLSBANK_INSTRUMENT, lparam, 0}; }
  123. static LPARAM ToLPARAM(uint16 instr, uint16 region, bool isPerc) { return (instr & DLS_INSTRMASK) | ((region << DLS_REGIONSHIFT) & DLS_REGIONMASK) | (isPerc ? DLS_TYPEPERC : 0); }
  124. };
  125. static CSoundFile *m_SongFile; // For browsing samples and instruments inside modules on disk
  126. CModTreeDropTarget m_DropTarget;
  127. CModTree *m_pDataTree = nullptr; // Pointer to instrument browser (lower part of tree view) - if it's a nullptr, this object is the instrument browser itself.
  128. HWND m_hDropWnd = nullptr;
  129. mpt::mutex m_WatchDirMutex;
  130. HANDLE m_hSwitchWatchDir = nullptr;
  131. mpt::PathString m_WatchDir;
  132. HANDLE m_hWatchDirKillThread = nullptr;
  133. std::thread m_WatchDirThread;
  134. ModItem m_itemDrag;
  135. DWORD m_dwStatus = 0;
  136. CModDoc *m_selectedDoc = nullptr, *m_dragDoc = nullptr;
  137. HTREEITEM m_hItemDrag = nullptr, m_hItemDrop = nullptr;
  138. HTREEITEM m_hInsLib = nullptr, m_hMidiLib = nullptr;
  139. HTREEITEM m_tiMidi[128];
  140. HTREEITEM m_tiPerc[128];
  141. std::vector<HTREEITEM> m_tiDLS;
  142. std::map<const CModDoc *, ModTreeDocInfo> m_docInfo;
  143. std::unique_ptr<CDLSBank> m_cachedBank;
  144. mpt::PathString m_cachedBankName;
  145. CString m_compareStrL, m_compareStrR; // Cache for ModTreeInsLibCompareNamesProc to avoid constant re-allocations
  146. #if (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
  147. DWORD m_stringCompareFlags = NORM_IGNORECASE | NORM_IGNOREWIDTH | SORT_DIGITSASNUMBERS;
  148. #else
  149. DWORD m_stringCompareFlags = NORM_IGNORECASE | NORM_IGNOREWIDTH;
  150. #endif
  151. // Instrument library
  152. mpt::PathString m_InstrLibPath; // Current path to be explored
  153. mpt::PathString m_InstrLibHighlightPath; // Folder to highlight in browser after a refresh
  154. mpt::PathString m_SongFileName; // Name of open module, without path (== m_InstrLibPath).
  155. mpt::PathString m_previousPath; // The folder from which we came from when navigating one folder up
  156. std::vector<const char*> m_modExtensions; // cached in order to avoid querying too often when changing browsed folder
  157. std::vector<mpt::PathString> m_MediaFoundationExtensions; // cached in order to avoid querying too often when changing browsed folder
  158. bool m_showAllFiles = false;
  159. bool m_doLabelEdit = false;
  160. public:
  161. CModTree(CModTree *pDataTree);
  162. ~CModTree();
  163. // Attributes
  164. public:
  165. void Init();
  166. bool InsLibSetFullPath(const mpt::PathString &libPath, const mpt::PathString &songFolder);
  167. mpt::PathString InsLibGetFullPath(HTREEITEM hItem) const;
  168. bool SetSoundFile(FileReader &file);
  169. void RefreshMidiLibrary();
  170. void RefreshDlsBanks();
  171. void RefreshInstrumentLibrary();
  172. void EmptyInstrumentLibrary();
  173. void FillInstrumentLibrary(const TCHAR *selectedItem = nullptr);
  174. void MonitorInstrumentLibrary();
  175. ModItem GetModItem(HTREEITEM hItem);
  176. BOOL SetMidiInstrument(UINT nIns, const mpt::PathString &fileName);
  177. BOOL SetMidiPercussion(UINT nPerc, const mpt::PathString &fileName);
  178. bool ExecuteItem(HTREEITEM hItem);
  179. void DeleteTreeItem(HTREEITEM hItem);
  180. static void PlayDLSItem(const CDLSBank &dlsBank, const DlsItem &item, ModCommand::NOTE note);
  181. BOOL PlayItem(HTREEITEM hItem, ModCommand::NOTE nParam, int volume = -1);
  182. BOOL OpenTreeItem(HTREEITEM hItem);
  183. BOOL OpenMidiInstrument(DWORD dwItem);
  184. void SetFullInstrumentLibraryPath(mpt::PathString path);
  185. void InstrumentLibraryChDir(mpt::PathString dir, bool isSong);
  186. bool GetDropInfo(DRAGONDROP &dropInfo, mpt::PathString &fullPath);
  187. void OnOptionsChanged();
  188. void AddDocument(CModDoc &modDoc);
  189. void RemoveDocument(const CModDoc &modDoc);
  190. void UpdateView(ModTreeDocInfo &info, UpdateHint hint);
  191. void OnUpdate(CModDoc *pModDoc, UpdateHint hint, CObject *pHint);
  192. bool CanDrop(HTREEITEM hItem, bool bDoDrop);
  193. void UpdatePlayPos(CModDoc &modDoc, Notification *pNotify);
  194. bool IsItemExpanded(HTREEITEM hItem);
  195. void DeleteChildren(HTREEITEM hItem);
  196. HTREEITEM GetNthChildItem(HTREEITEM hItem, int index) const;
  197. HTREEITEM GetParentRootItem(HTREEITEM hItem) const;
  198. bool IsSampleBrowser() const { return m_pDataTree == nullptr; }
  199. CModTree *GetSampleBrowser() { return IsSampleBrowser() ? this : m_pDataTree; }
  200. // Overrides
  201. // ClassWizard generated virtual function overrides
  202. //{{AFX_VIRTUAL(CModTree)
  203. public:
  204. BOOL PreTranslateMessage(MSG* pMsg) override;
  205. //}}AFX_VIRTUAL
  206. // Drag & Drop operations
  207. public:
  208. DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
  209. DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
  210. BOOL OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
  211. protected:
  212. int ModTreeInsLibCompareNamesGetItem(HTREEITEM item, CString &resultStr);
  213. static int CALLBACK ModTreeInsLibCompareNamesProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
  214. static int CALLBACK ModTreeInsLibCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
  215. static int CALLBACK ModTreeDrumCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
  216. HTREEITEM InsertInsLibItem(const TCHAR *name, int image, const TCHAR *selectIfMatch);
  217. ModTreeDocInfo *GetDocumentInfoFromItem(HTREEITEM hItem);
  218. CModDoc *GetDocumentFromItem(HTREEITEM hItem) { ModTreeDocInfo *info = GetDocumentInfoFromItem(hItem); return info ? &info->modDoc : nullptr; }
  219. ModTreeDocInfo *GetDocumentInfoFromModDoc(CModDoc &modDoc);
  220. size_t GetDLSBankIndexFromItem(HTREEITEM hItem) const;
  221. CDLSBank *GetDLSBankFromItem(HTREEITEM hItem) const;
  222. void InsertOrDupItem(bool insert);
  223. void OnItemRightClick(HTREEITEM hItem, CPoint pt);
  224. static bool HasEffectPlugins(const CSoundFile &sndFile);
  225. static bool AllPluginsBypassed(const CSoundFile &sndFile, bool onlyEffects);
  226. static void BypassAllPlugins(CSoundFile &sndFile, bool bypass, bool onlyEffects);
  227. // Generated message map functions
  228. protected:
  229. //{{AFX_MSG(CModTree)
  230. afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
  231. afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
  232. afx_msg void OnXButtonUp(UINT nFlags, UINT nButton, CPoint point);
  233. afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  234. afx_msg void OnBeginDrag(HTREEITEM, bool bLeft, LRESULT *pResult);
  235. afx_msg void OnBeginLDrag(LPNMHDR, LRESULT *pResult);
  236. afx_msg void OnBeginRDrag(LPNMHDR, LRESULT *pResult);
  237. afx_msg void OnEndDrag(DWORD dwMask);
  238. afx_msg void OnItemDblClk(LPNMHDR phdr, LRESULT *pResult);
  239. afx_msg void OnItemReturn(LPNMHDR, LRESULT *pResult);
  240. afx_msg void OnItemLeftClick(LPNMHDR pNMHDR, LRESULT *pResult);
  241. afx_msg void OnItemRightClick(LPNMHDR, LRESULT *pResult);
  242. afx_msg void OnItemExpanded(LPNMHDR pnmhdr, LRESULT *pResult);
  243. afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
  244. afx_msg void OnRefreshTree();
  245. afx_msg void OnExecuteItem();
  246. afx_msg void OnPlayTreeItem();
  247. afx_msg void OnDeleteTreeItem();
  248. afx_msg void OnOpenTreeItem();
  249. afx_msg void OnMuteTreeItem();
  250. afx_msg void OnMuteOnlyEffects();
  251. afx_msg void OnSoloTreeItem();
  252. afx_msg void OnUnmuteAllTreeItem();
  253. afx_msg void OnDuplicateTreeItem() { InsertOrDupItem(false); }
  254. afx_msg void OnInsertTreeItem() { InsertOrDupItem(true); }
  255. afx_msg void OnSwitchToTreeItem(); // hack for sequence items to avoid double-click action
  256. afx_msg void OnCloseItem();
  257. afx_msg void OnRenameItem();
  258. afx_msg void OnBeginLabelEdit(NMHDR *nmhdr, LRESULT *result);
  259. afx_msg void OnEndLabelEdit(NMHDR *nmhdr, LRESULT *result);
  260. afx_msg void OnDropFiles(HDROP hDropInfo);
  261. afx_msg void OnSetItemPath();
  262. afx_msg void OnSaveItem();
  263. afx_msg void OnSaveAll();
  264. afx_msg void OnReloadItem();
  265. afx_msg void OnReloadAll();
  266. afx_msg void OnFindMissing();
  267. afx_msg void OnAddDlsBank();
  268. afx_msg void OnImportMidiLib();
  269. afx_msg void OnExportMidiLib();
  270. afx_msg void OnSoundBankProperties();
  271. afx_msg void OnRefreshInstrLib();
  272. afx_msg void OnShowDirectories();
  273. afx_msg void OnShowAllFiles();
  274. afx_msg void OnShowSoundFiles();
  275. afx_msg void OnGotoInstrumentDir();
  276. afx_msg void OnGotoSampleDir();
  277. afx_msg LRESULT OnCustomKeyMsg(WPARAM, LPARAM);
  278. LRESULT OnMidiMsg(WPARAM midiData, LPARAM);
  279. //}}AFX_MSG
  280. DECLARE_MESSAGE_MAP()
  281. public:
  282. afx_msg void OnKillFocus(CWnd *pNewWnd);
  283. afx_msg void OnSetFocus(CWnd *pOldWnd);
  284. };
  285. OPENMPT_NAMESPACE_END