| 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_BEGINclass 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();// Attributespublic:	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 operationspublic:	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 functionsprotected:	//{{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
 |