123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- /*
- * view_tre.h
- * ----------
- * Purpose: Tree view for managing open songs, sound files, file browser, ...
- * Notes : (currently none)
- * Authors: Olivier Lapicque
- * OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #pragma once
- #include "openmpt/all/BuildSettings.hpp"
- #include <vector>
- #include <bitset>
- OPENMPT_NAMESPACE_BEGIN
- class CModDoc;
- class CModTree;
- class CSoundFile;
- class CDLSBank;
- struct ModTreeDocInfo
- {
- // Tree state variables
- std::vector<std::vector<HTREEITEM>> tiOrders;
- std::vector<HTREEITEM> tiSequences, tiPatterns;
- CModDoc &modDoc;
- HTREEITEM hSong = nullptr, hPatterns = nullptr, hSamples = nullptr, hInstruments = nullptr, hComments = nullptr, hOrders = nullptr, hEffects = nullptr;
- // Module information
- ORDERINDEX ordSel = ORDERINDEX_INVALID;
- SEQUENCEINDEX seqSel = SEQUENCEINDEX_INVALID;
- std::bitset<MAX_SAMPLES> samplesPlaying;
- std::bitset<MAX_INSTRUMENTS> instrumentsPlaying;
- ModTreeDocInfo(CModDoc &modDoc);
- };
- class CModTreeDropTarget: public COleDropTarget
- {
- protected:
- CModTree *m_pModTree;
- public:
- CModTreeDropTarget() { m_pModTree = nullptr; }
- BOOL Register(CModTree *pWnd);
- public:
- DROPEFFECT OnDragEnter(CWnd *pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override;
- DROPEFFECT OnDragOver(CWnd *pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override;
- BOOL OnDrop(CWnd *pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) override;
- };
- class CModTree: public CTreeCtrl
- {
- protected:
- enum TreeStatus
- {
- TREESTATUS_RDRAG = 0x01,
- TREESTATUS_LDRAG = 0x02,
- TREESTATUS_SINGLEEXPAND = 0x04,
- TREESTATUS_DRAGGING = (TREESTATUS_RDRAG | TREESTATUS_LDRAG)
- };
- enum ModItemType : uint8
- {
- MODITEM_NULL = 0,
- MODITEM_BEGIN_SONGITEMS,
- MODITEM_ORDER = MODITEM_BEGIN_SONGITEMS,
- MODITEM_PATTERN,
- MODITEM_SAMPLE,
- MODITEM_INSTRUMENT,
- MODITEM_COMMENTS,
- MODITEM_EFFECT,
- MODITEM_SEQUENCE,
- MODITEM_HDR_SONG,
- MODITEM_HDR_ORDERS,
- MODITEM_HDR_PATTERNS,
- MODITEM_HDR_SAMPLES,
- MODITEM_HDR_INSTRUMENTS,
- MODITEM_HDR_EFFECTS,
- MODITEM_END_SONGITEMS = MODITEM_HDR_EFFECTS,
- MODITEM_HDR_INSTRUMENTLIB,
- MODITEM_HDR_MIDILIB,
- MODITEM_HDR_MIDIGROUP,
- MODITEM_MIDIINSTRUMENT,
- MODITEM_MIDIPERCUSSION,
- MODITEM_INSLIB_FOLDER,
- MODITEM_INSLIB_SAMPLE,
- MODITEM_INSLIB_INSTRUMENT,
- MODITEM_INSLIB_SONG,
- MODITEM_DLSBANK_FOLDER,
- MODITEM_DLSBANK_INSTRUMENT,
- };
- // Bit mask magic
- enum
- {
- MIDILIB_SHIFT = 16,
- MIDILIB_MASK = (1 << MIDILIB_SHIFT) - 1,
- // Must be consistent with CCtrlPatterns::OnActivatePage
- SEQU_SHIFT = 16,
- SEQU_MASK = (1 << SEQU_SHIFT) - 1,
- SEQU_INDICATOR = 0x80000000,
- // Soundbank instrument identification (must be consistent with CViewInstrument::OnDragonDrop / CViewSample::OnDragonDrop)
- DLS_TYPEPERC = 0x80000000,
- DLS_INSTRMASK = 0x0000FFFF,
- DLS_REGIONMASK = 0x7FFF0000, // Drum region
- DLS_REGIONSHIFT = 16,
- DLS_DRUM_FOLDER_LPARAM = 0x12345678,
- };
- static_assert((ORDERINDEX_INVALID & SEQU_MASK) == ORDERINDEX_INVALID, "ORDERINDEX doesn't fit in GetItemData() parameter");
- static_assert((ORDERINDEX_MAX & SEQU_MASK) == ORDERINDEX_MAX, "ORDERINDEX doesn't fit in GetItemData() parameter");
- static_assert((((SEQUENCEINDEX_INVALID << SEQU_SHIFT) & ~SEQU_INDICATOR) >> SEQU_SHIFT) == SEQUENCEINDEX_INVALID, "SEQUENCEINDEX doesn't fit in GetItemData() parameter");
- struct ModItem
- {
- uint32 val1;
- uint16 val2;
- ModItemType type;
- ModItem(ModItemType t = MODITEM_NULL, uint32 v1 = 0, uint16 v2 = 0) : val1(v1), val2(v2), type(t) { }
- bool IsSongItem() const noexcept { return type >= MODITEM_BEGIN_SONGITEMS && type <= MODITEM_END_SONGITEMS; }
- bool operator==(const ModItem &other) const noexcept { return val1 == other.val1 && val2 == other.val2 && type == other.type; }
- bool operator!=(const ModItem &other) const noexcept { return !(*this == other); }
- };
- struct DlsItem : public ModItem
- {
- explicit DlsItem(uint16 instr) : ModItem(MODITEM_DLSBANK_INSTRUMENT, instr, 0) { }
- DlsItem(uint16 instr, uint16 region) : ModItem(MODITEM_DLSBANK_INSTRUMENT, (instr & DLS_INSTRMASK) | ((region << DLS_REGIONSHIFT) & DLS_REGIONMASK) | DLS_TYPEPERC, 0) { }
- uint32 GetRegion() const noexcept { return (val1 & DLS_REGIONMASK) >> DLS_REGIONSHIFT; }
- uint32 GetInstr() const noexcept { return (val1 & DLS_INSTRMASK); }
- bool IsPercussion() const noexcept { return ((val1 & DLS_TYPEPERC) == DLS_TYPEPERC); }
- bool IsMelodic() const noexcept { return !IsPercussion(); }
- static ModItem FromLPARAM(uint32 lparam) { return ModItem{MODITEM_DLSBANK_INSTRUMENT, lparam, 0}; }
- static LPARAM ToLPARAM(uint16 instr, uint16 region, bool isPerc) { return (instr & DLS_INSTRMASK) | ((region << DLS_REGIONSHIFT) & DLS_REGIONMASK) | (isPerc ? DLS_TYPEPERC : 0); }
- };
- static CSoundFile *m_SongFile; // For browsing samples and instruments inside modules on disk
- CModTreeDropTarget m_DropTarget;
- 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.
- HWND m_hDropWnd = nullptr;
- mpt::mutex m_WatchDirMutex;
- HANDLE m_hSwitchWatchDir = nullptr;
- mpt::PathString m_WatchDir;
- HANDLE m_hWatchDirKillThread = nullptr;
- std::thread m_WatchDirThread;
- ModItem m_itemDrag;
- DWORD m_dwStatus = 0;
- CModDoc *m_selectedDoc = nullptr, *m_dragDoc = nullptr;
- HTREEITEM m_hItemDrag = nullptr, m_hItemDrop = nullptr;
- HTREEITEM m_hInsLib = nullptr, m_hMidiLib = nullptr;
- HTREEITEM m_tiMidi[128];
- HTREEITEM m_tiPerc[128];
- std::vector<HTREEITEM> m_tiDLS;
- std::map<const CModDoc *, ModTreeDocInfo> m_docInfo;
- std::unique_ptr<CDLSBank> m_cachedBank;
- mpt::PathString m_cachedBankName;
- CString m_compareStrL, m_compareStrR; // Cache for ModTreeInsLibCompareNamesProc to avoid constant re-allocations
- #if (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
- DWORD m_stringCompareFlags = NORM_IGNORECASE | NORM_IGNOREWIDTH | SORT_DIGITSASNUMBERS;
- #else
- DWORD m_stringCompareFlags = NORM_IGNORECASE | NORM_IGNOREWIDTH;
- #endif
- // Instrument library
- mpt::PathString m_InstrLibPath; // Current path to be explored
- mpt::PathString m_InstrLibHighlightPath; // Folder to highlight in browser after a refresh
- mpt::PathString m_SongFileName; // Name of open module, without path (== m_InstrLibPath).
- mpt::PathString m_previousPath; // The folder from which we came from when navigating one folder up
- std::vector<const char*> m_modExtensions; // cached in order to avoid querying too often when changing browsed folder
- std::vector<mpt::PathString> m_MediaFoundationExtensions; // cached in order to avoid querying too often when changing browsed folder
- bool m_showAllFiles = false;
- bool m_doLabelEdit = false;
- public:
- CModTree(CModTree *pDataTree);
- ~CModTree();
- // Attributes
- public:
- void Init();
- bool InsLibSetFullPath(const mpt::PathString &libPath, const mpt::PathString &songFolder);
- mpt::PathString InsLibGetFullPath(HTREEITEM hItem) const;
- bool SetSoundFile(FileReader &file);
- void RefreshMidiLibrary();
- void RefreshDlsBanks();
- void RefreshInstrumentLibrary();
- void EmptyInstrumentLibrary();
- void FillInstrumentLibrary(const TCHAR *selectedItem = nullptr);
- void MonitorInstrumentLibrary();
- ModItem GetModItem(HTREEITEM hItem);
- BOOL SetMidiInstrument(UINT nIns, const mpt::PathString &fileName);
- BOOL SetMidiPercussion(UINT nPerc, const mpt::PathString &fileName);
- bool ExecuteItem(HTREEITEM hItem);
- void DeleteTreeItem(HTREEITEM hItem);
- static void PlayDLSItem(const CDLSBank &dlsBank, const DlsItem &item, ModCommand::NOTE note);
- BOOL PlayItem(HTREEITEM hItem, ModCommand::NOTE nParam, int volume = -1);
- BOOL OpenTreeItem(HTREEITEM hItem);
- BOOL OpenMidiInstrument(DWORD dwItem);
- void SetFullInstrumentLibraryPath(mpt::PathString path);
- void InstrumentLibraryChDir(mpt::PathString dir, bool isSong);
- bool GetDropInfo(DRAGONDROP &dropInfo, mpt::PathString &fullPath);
- void OnOptionsChanged();
- void AddDocument(CModDoc &modDoc);
- void RemoveDocument(const CModDoc &modDoc);
- void UpdateView(ModTreeDocInfo &info, UpdateHint hint);
- void OnUpdate(CModDoc *pModDoc, UpdateHint hint, CObject *pHint);
- bool CanDrop(HTREEITEM hItem, bool bDoDrop);
- void UpdatePlayPos(CModDoc &modDoc, Notification *pNotify);
- bool IsItemExpanded(HTREEITEM hItem);
- void DeleteChildren(HTREEITEM hItem);
- HTREEITEM GetNthChildItem(HTREEITEM hItem, int index) const;
- HTREEITEM GetParentRootItem(HTREEITEM hItem) const;
- bool IsSampleBrowser() const { return m_pDataTree == nullptr; }
- CModTree *GetSampleBrowser() { return IsSampleBrowser() ? this : m_pDataTree; }
- // Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CModTree)
- public:
- BOOL PreTranslateMessage(MSG* pMsg) override;
- //}}AFX_VIRTUAL
- // Drag & Drop operations
- public:
- DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
- DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
- BOOL OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
- protected:
- int ModTreeInsLibCompareNamesGetItem(HTREEITEM item, CString &resultStr);
- static int CALLBACK ModTreeInsLibCompareNamesProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
- static int CALLBACK ModTreeInsLibCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
- static int CALLBACK ModTreeDrumCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
- HTREEITEM InsertInsLibItem(const TCHAR *name, int image, const TCHAR *selectIfMatch);
- ModTreeDocInfo *GetDocumentInfoFromItem(HTREEITEM hItem);
- CModDoc *GetDocumentFromItem(HTREEITEM hItem) { ModTreeDocInfo *info = GetDocumentInfoFromItem(hItem); return info ? &info->modDoc : nullptr; }
- ModTreeDocInfo *GetDocumentInfoFromModDoc(CModDoc &modDoc);
- size_t GetDLSBankIndexFromItem(HTREEITEM hItem) const;
- CDLSBank *GetDLSBankFromItem(HTREEITEM hItem) const;
- void InsertOrDupItem(bool insert);
- void OnItemRightClick(HTREEITEM hItem, CPoint pt);
- static bool HasEffectPlugins(const CSoundFile &sndFile);
- static bool AllPluginsBypassed(const CSoundFile &sndFile, bool onlyEffects);
- static void BypassAllPlugins(CSoundFile &sndFile, bool bypass, bool onlyEffects);
- // Generated message map functions
- protected:
- //{{AFX_MSG(CModTree)
- afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
- afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
- afx_msg void OnXButtonUp(UINT nFlags, UINT nButton, CPoint point);
- afx_msg void OnMouseMove(UINT nFlags, CPoint point);
- afx_msg void OnBeginDrag(HTREEITEM, bool bLeft, LRESULT *pResult);
- afx_msg void OnBeginLDrag(LPNMHDR, LRESULT *pResult);
- afx_msg void OnBeginRDrag(LPNMHDR, LRESULT *pResult);
- afx_msg void OnEndDrag(DWORD dwMask);
- afx_msg void OnItemDblClk(LPNMHDR phdr, LRESULT *pResult);
- afx_msg void OnItemReturn(LPNMHDR, LRESULT *pResult);
- afx_msg void OnItemLeftClick(LPNMHDR pNMHDR, LRESULT *pResult);
- afx_msg void OnItemRightClick(LPNMHDR, LRESULT *pResult);
- afx_msg void OnItemExpanded(LPNMHDR pnmhdr, LRESULT *pResult);
- afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
- afx_msg void OnRefreshTree();
- afx_msg void OnExecuteItem();
- afx_msg void OnPlayTreeItem();
- afx_msg void OnDeleteTreeItem();
- afx_msg void OnOpenTreeItem();
- afx_msg void OnMuteTreeItem();
- afx_msg void OnMuteOnlyEffects();
- afx_msg void OnSoloTreeItem();
- afx_msg void OnUnmuteAllTreeItem();
- afx_msg void OnDuplicateTreeItem() { InsertOrDupItem(false); }
- afx_msg void OnInsertTreeItem() { InsertOrDupItem(true); }
- afx_msg void OnSwitchToTreeItem(); // hack for sequence items to avoid double-click action
- afx_msg void OnCloseItem();
- afx_msg void OnRenameItem();
- afx_msg void OnBeginLabelEdit(NMHDR *nmhdr, LRESULT *result);
- afx_msg void OnEndLabelEdit(NMHDR *nmhdr, LRESULT *result);
- afx_msg void OnDropFiles(HDROP hDropInfo);
- afx_msg void OnSetItemPath();
- afx_msg void OnSaveItem();
- afx_msg void OnSaveAll();
- afx_msg void OnReloadItem();
- afx_msg void OnReloadAll();
- afx_msg void OnFindMissing();
- afx_msg void OnAddDlsBank();
- afx_msg void OnImportMidiLib();
- afx_msg void OnExportMidiLib();
- afx_msg void OnSoundBankProperties();
- afx_msg void OnRefreshInstrLib();
- afx_msg void OnShowDirectories();
- afx_msg void OnShowAllFiles();
- afx_msg void OnShowSoundFiles();
- afx_msg void OnGotoInstrumentDir();
- afx_msg void OnGotoSampleDir();
- afx_msg LRESULT OnCustomKeyMsg(WPARAM, LPARAM);
- LRESULT OnMidiMsg(WPARAM midiData, LPARAM);
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
- public:
- afx_msg void OnKillFocus(CWnd *pNewWnd);
- afx_msg void OnSetFocus(CWnd *pOldWnd);
- };
- OPENMPT_NAMESPACE_END
|