Initial VST FilePresenter implementation

This commit is contained in:
Jack Andersen 2016-06-11 18:52:40 -10:00
parent 6f538dc19c
commit e4ae1f1f88
9 changed files with 796 additions and 18 deletions

View File

@ -0,0 +1,310 @@
#include "AudioGroupFilePresenter.hpp"
#include "VSTBackend.hpp"
namespace amuse
{
bool AudioGroupDataCollection::loadProj()
{
std::wstring path = m_path + L"\\proj";
athena::io::FileReader r(path, 1024 * 32, false);
if (r.hasError())
return false;
std::vector<uint8_t>& ret = m_projData;
size_t len = r.length();
ret.resize(len);
r.readUBytesToBuf(ret.data(), len);
return ret.size() != 0;
}
bool AudioGroupDataCollection::loadPool()
{
std::wstring path = m_path + L"\\pool";
athena::io::FileReader r(path, 1024 * 32, false);
if (r.hasError())
return false;
std::vector<uint8_t>& ret = m_poolData;
size_t len = r.length();
ret.resize(len);
r.readUBytesToBuf(ret.data(), len);
return ret.size() != 0;
}
bool AudioGroupDataCollection::loadSdir()
{
std::wstring path = m_path + L"\\sdir";
athena::io::FileReader r(path, 1024 * 32, false);
if (r.hasError())
return false;
std::vector<uint8_t>& ret = m_sdirData;
size_t len = r.length();
ret.resize(len);
r.readUBytesToBuf(ret.data(), len);
return ret.size() != 0;
}
bool AudioGroupDataCollection::loadSamp()
{
std::wstring path = m_path + L"\\samp";
athena::io::FileReader r(path, 1024 * 32, false);
if (r.hasError())
return false;
std::vector<uint8_t>& ret = m_sampData;
size_t len = r.length();
ret.resize(len);
r.readUBytesToBuf(ret.data(), len);
return ret.size() != 0;
}
bool AudioGroupDataCollection::loadMeta()
{
std::wstring path = m_path + L"\\meta";
athena::io::FileReader r(path, 1024 * 32, false);
if (r.hasError())
return false;
std::experimental::optional<MetaData>& ret = m_metaData;
ret.emplace(r);
return ret.operator bool();
}
AudioGroupDataCollection::AudioGroupDataCollection(const std::wstring& path, const std::wstring& name)
: m_path(path), m_name(name)
{
}
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter& presenter)
{
if (m_metaData && m_loadedData && m_loadedGroup)
return true;
if (!loadProj())
return false;
if (!loadPool())
return false;
if (!loadSdir())
return false;
if (!loadSamp())
return false;
if (!loadMeta())
return false;
return _indexData(presenter);
}
bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter& presenter)
{
amuse::Engine& engine = presenter.getBackend().getAmuseEngine();
switch (m_metaData->fmt)
{
case amuse::DataFormat::GCN:
default:
m_loadedData.emplace(m_projData.data(), m_projData.size(),
m_poolData.data(), m_poolData.size(),
m_sdirData.data(), m_sdirData.size(),
m_sampData.data(), m_sampData.size(),
amuse::GCNDataTag{});
break;
case amuse::DataFormat::N64:
m_loadedData.emplace(m_projData.data(), m_projData.size(),
m_poolData.data(), m_poolData.size(),
m_sdirData.data(), m_sdirData.size(),
m_sampData.data(), m_sampData.size(),
m_metaData->absOffs, amuse::N64DataTag{});
break;
case amuse::DataFormat::PC:
m_loadedData.emplace(m_projData.data(), m_projData.size(),
m_poolData.data(), m_poolData.size(),
m_sdirData.data(), m_sdirData.size(),
m_sampData.data(), m_sampData.size(),
m_metaData->absOffs, amuse::PCDataTag{});
break;
}
m_loadedGroup = engine.addAudioGroup(*m_loadedData);
m_groupTokens.clear();
if (m_loadedGroup)
{
m_groupTokens.reserve(m_loadedGroup->getProj().songGroups().size() +
m_loadedGroup->getProj().sfxGroups().size());
{
const auto& songGroups = m_loadedGroup->getProj().songGroups();
std::map<int, const amuse::SongGroupIndex*> sortGroups;
for (const auto& pair : songGroups)
sortGroups[pair.first] = &pair.second;
for (const auto& pair : sortGroups)
m_groupTokens.emplace_back(pair.first, pair.second);
}
{
const auto& sfxGroups = m_loadedGroup->getProj().sfxGroups();
std::map<int, const amuse::SFXGroupIndex*> sortGroups;
for (const auto& pair : sfxGroups)
sortGroups[pair.first] = &pair.second;
for (const auto& pair : sortGroups)
m_groupTokens.emplace_back(pair.first, pair.second);
}
}
return m_loadedData && m_loadedGroup;
}
AudioGroupCollection::AudioGroupCollection(const std::wstring& path, const std::wstring& name)
: m_path(path), m_name(name)
{
}
void AudioGroupCollection::addCollection(AudioGroupFilePresenter& presenter,
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
{
for (std::pair<std::wstring, amuse::IntrusiveAudioGroupData>& pair : collection)
{
std::wstring collectionPath = m_path + L'\\' + pair.first;
amuse::IntrusiveAudioGroupData& dataIn = pair.second;
auto search = m_groups.find(pair.first);
if (search == m_groups.end())
{
search = m_groups.emplace(pair.first,
std::make_unique<AudioGroupDataCollection>(collectionPath,
pair.first)).first;
}
AudioGroupDataCollection& dataCollection = *search->second;
dataCollection.m_projData.resize(dataIn.getProjSize());
memmove(dataCollection.m_projData.data(), dataIn.getProj(), dataIn.getProjSize());
dataCollection.m_poolData.resize(dataIn.getPoolSize());
memmove(dataCollection.m_poolData.data(), dataIn.getPool(), dataIn.getPoolSize());
dataCollection.m_sdirData.resize(dataIn.getSdirSize());
memmove(dataCollection.m_sdirData.data(), dataIn.getSdir(), dataIn.getSdirSize());
dataCollection.m_sampData.resize(dataIn.getSampSize());
memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize());
dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true);
dataCollection._indexData(presenter);
}
}
void AudioGroupCollection::update(AudioGroupFilePresenter& presenter)
{
std::wstring path = m_path + L"\\*";
WIN32_FIND_DATAW d;
HANDLE dir = FindFirstFileW(path.c_str(), &d);
if (dir == INVALID_HANDLE_VALUE)
return;
do
{
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L".."))
continue;
if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
std::wstring nameStr(d.cFileName);
auto search = m_groups.find(nameStr);
if (search == m_groups.end())
{
search =
m_groups.emplace(nameStr,
std::make_unique<AudioGroupDataCollection>(m_path + L'\\' + nameStr,
nameStr)).first;
search->second->_attemptLoad(presenter);
}
}
} while (FindNextFileW(dir, &d));
FindClose(dir);
}
void AudioGroupFilePresenter::update()
{
std::wstring path = m_backend.getUserDir() + L"\\*";
std::map<std::wstring, std::unique_ptr<AudioGroupCollection>>& theMap = m_audioGroupCollections;
WIN32_FIND_DATAW d;
HANDLE dir = FindFirstFileW(path.c_str(), &d);
if (dir == INVALID_HANDLE_VALUE)
return;
do
{
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L".."))
continue;
if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
std::wstring nameStr(d.cFileName);
auto search = theMap.find(nameStr);
if (search == theMap.end())
{
search = theMap.emplace(nameStr,
std::make_unique<AudioGroupCollection>(m_backend.getUserDir() + L'\\' + nameStr, nameStr)).first;
search->second->update(*this);
}
}
} while (FindNextFileW(dir, &d));
FindClose(dir);
}
void AudioGroupFilePresenter::addCollection(const std::wstring& name,
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection)
{
std::wstring path = m_backend.getUserDir() + L'\\' + name;
AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(path, name)).first->second;
insert.addCollection(*this, std::move(collection));
for (std::pair<const std::wstring, std::unique_ptr<AudioGroupDataCollection>>& pair : insert.m_groups)
{
std::wstring collectionPath = insert.m_path + L'\\' + pair.first;
CreateDirectory(collectionPath.c_str(), nullptr);
FILE* fp = _wfopen((collectionPath + L"\\proj").c_str(), L"wb");
if (fp)
{
fwrite(pair.second->m_projData.data(), 1, pair.second->m_projData.size(), fp);
fclose(fp);
}
fp = _wfopen((collectionPath + L"\\pool").c_str(), L"wb");
if (fp)
{
fwrite(pair.second->m_poolData.data(), 1, pair.second->m_poolData.size(), fp);
fclose(fp);
}
fp = _wfopen((collectionPath + L"\\sdir").c_str(), L"wb");
if (fp)
{
fwrite(pair.second->m_sdirData.data(), 1, pair.second->m_sdirData.size(), fp);
fclose(fp);
}
fp = _wfopen((collectionPath + L"\\samp").c_str(), L"wb");
if (fp)
{
fwrite(pair.second->m_sampData.data(), 1, pair.second->m_sampData.size(), fp);
fclose(fp);
}
fp = _wfopen((collectionPath + L"\\meta").c_str(), L"wb");
if (fp)
{
fwrite(&*pair.second->m_metaData, 1, sizeof(*pair.second->m_metaData), fp);
fclose(fp);
}
}
}
void AudioGroupFilePresenter::populateEditor(VSTEditor& editor)
{
for (const auto& cgollection : m_audioGroupCollections)
{
}
}
}

View File

@ -0,0 +1,92 @@
#ifndef __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__
#define __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__
#include <map>
#include <memory>
#include "optional.hpp"
#include <amuse/amuse.hpp>
#include <athena/FileReader.hpp>
namespace amuse
{
class VSTBackend;
class VSTEditor;
class AudioGroupFilePresenter;
struct AudioGroupDataCollection
{
std::wstring m_path;
std::wstring m_name;
std::vector<uint8_t> m_projData;
std::vector<uint8_t> m_poolData;
std::vector<uint8_t> m_sdirData;
std::vector<uint8_t> m_sampData;
struct MetaData
{
amuse::DataFormat fmt;
uint32_t absOffs;
uint32_t active;
MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn)
: fmt(fmtIn), absOffs(absOffsIn), active(activeIn) {}
MetaData(athena::io::FileReader& r)
: fmt(amuse::DataFormat(r.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little()) {}
};
std::experimental::optional<MetaData> m_metaData;
std::experimental::optional<amuse::AudioGroupData> m_loadedData;
const amuse::AudioGroup* m_loadedGroup;
struct GroupToken
{
int m_groupId;
const amuse::SongGroupIndex* m_song = nullptr;
const amuse::SFXGroupIndex* m_sfx = nullptr;
GroupToken(int id, const amuse::SongGroupIndex* song) : m_groupId(id), m_song(song) {}
GroupToken(int id, const amuse::SFXGroupIndex* sfx) : m_groupId(id), m_sfx(sfx) {}
};
std::vector<GroupToken> m_groupTokens;
bool loadProj();
bool loadPool();
bool loadSdir();
bool loadSamp();
bool loadMeta();
AudioGroupDataCollection(const std::wstring& path, const std::wstring& name);
bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;}
bool _attemptLoad(AudioGroupFilePresenter& presenter);
bool _indexData(AudioGroupFilePresenter& presenter);
};
struct AudioGroupCollection
{
std::wstring m_path;
std::wstring m_name;
std::map<std::wstring, std::unique_ptr<AudioGroupDataCollection>> m_groups;
AudioGroupCollection(const std::wstring& path, const std::wstring& name);
void addCollection(AudioGroupFilePresenter& presenter,
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
void update(AudioGroupFilePresenter& presenter);
//void populate
};
class AudioGroupFilePresenter
{
VSTBackend& m_backend;
std::map<std::wstring, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
public:
AudioGroupFilePresenter(VSTBackend& backend) : m_backend(backend) {}
void update();
void populateEditor(VSTEditor& editor);
void addCollection(const std::wstring& name,
std::vector<std::pair<std::wstring, amuse::IntrusiveAudioGroupData>>&& collection);
VSTBackend& getBackend() {return m_backend;}
};
}
#endif // __AMUSE_AUDIOGROUPFILEPRESENTER_HPP__

View File

@ -7,10 +7,12 @@ if (WIN32 AND (EXISTS ${VST3_SDK_ROOT}))
add_library(amuse-vst SHARED
VSTBackend.hpp VSTBackend.cpp
VSTEditor.hpp VSTEditor.cpp
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.cpp
${VST2_DIR}/vstplugmain.cpp
${VST2_DIR}/audioeffect.cpp
${VST2_DIR}/audioeffectx.cpp)
${VST2_DIR}/audioeffectx.cpp
FileOpenDialog.hpp FileOpenDialog.cpp)
target_link_libraries(amuse-vst amuse boo soxr ${ZLIB_LIBRARIES} ${BOO_SYS_LIBS}
Msimg32 logvisor athena-core)
Msimg32 Shlwapi logvisor athena-core)
set_target_properties(amuse-vst PROPERTIES LINK_FLAGS "/EXPORT:VSTPluginMain")
endif()

238
VST/FileOpenDialog.cpp Normal file
View File

@ -0,0 +1,238 @@
#include "FileOpenDialog.hpp"
#define WIN32_LEAN_AND_MEAN
#include <windows.h> // For common windows data types and function headers
#define STRICT_TYPED_ITEMIDS
#include <objbase.h> // For COM headers
#include <shobjidl.h> // for IFileDialogEvents and IFileDialogControlEvents
#include <shlwapi.h>
#include <knownfolders.h> // for KnownFolder APIs/datatypes/function headers
#include <propvarutil.h> // for PROPVAR-related functions
#include <propkey.h> // for the Property key APIs/datatypes
#include <propidl.h> // for the Property System APIs
#include <strsafe.h> // for StringCchPrintfW
#include <shtypes.h> // for COMDLG_FILTERSPEC
#include <new>
// Controls
#define CONTROL_GROUP 2000
#define CONTROL_RADIOBUTTONLIST 2
#define CONTROL_RADIOBUTTON1 1
#define CONTROL_RADIOBUTTON2 2 // It is OK for this to have the same IDas CONTROL_RADIOBUTTONLIST,
// because it is a child control under CONTROL_RADIOBUTTONLIST
// IDs for the Task Dialog Buttons
#define IDC_BASICFILEOPEN 100
#define IDC_ADDITEMSTOCUSTOMPLACES 101
#define IDC_ADDCUSTOMCONTROLS 102
#define IDC_SETDEFAULTVALUESFORPROPERTIES 103
#define IDC_WRITEPROPERTIESUSINGHANDLERS 104
#define IDC_WRITEPROPERTIESWITHOUTUSINGHANDLERS 105
HWND ghMainWnd = 0;
HINSTANCE ghAppInst = 0;
RECT winRect;
class CDialogEventHandler : public IFileDialogEvents,
public IFileDialogControlEvents
{
public:
// IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] = {
QITABENT(CDialogEventHandler, IFileDialogEvents),
QITABENT(CDialogEventHandler, IFileDialogControlEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
delete this;
return cRef;
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) { return S_OK; };
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnSelectionChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
IFACEMETHODIMP OnTypeChange(IFileDialog *pfd);
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
// IFileDialogControlEvents methods
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem);
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; };
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize *, DWORD, BOOL) { return S_OK; };
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; };
CDialogEventHandler() : _cRef(1) { };
private:
~CDialogEventHandler() { };
long _cRef;
};
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv);
std::wstring openDB()
{
std::wstring ret;
//Cocreate the file open dialog object
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
//Stuff needed for later
const COMDLG_FILTERSPEC rgFExt[] = {{L"Audio Group Archive (*.*)", L"*.*"}};
//Create event handling
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if(SUCCEEDED(hr))
{
//Hook the event handler
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
//Set options for the dialog
DWORD dwFlags;
//Get options first so we do not override
hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr))
{
//Get shell items only
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
if (SUCCEEDED(hr))
{
//Types of files to display (not default)
hr = pfd->SetFileTypes(ARRAYSIZE(rgFExt), rgFExt);
if (SUCCEEDED(hr))
{
//Set default file type to display
//hr = pfd->SetDefaultExtension(L"sqlite");
//if (SUCCEEDED(hr))
//{
//Show dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
//Get the result once the user clicks on open
IShellItem *result;
hr = pfd->GetResult(&result);
if (SUCCEEDED(hr))
{
//Print out the file name
PWSTR fName = NULL;
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &fName);
if (SUCCEEDED(hr))
{
ret.assign(fName);
CoTaskMemFree(fName);
}
result->Release();
}
}
//}
}
}
}
}
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
pfd->Release();
return ret;
}
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
{
*ppv = NULL;
CDialogEventHandler *pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pDialogEventHandler->QueryInterface(riid, ppv);
pDialogEventHandler->Release();
}
return hr;
}
HRESULT CDialogEventHandler::OnTypeChange(IFileDialog *pfd)
{
IFileSaveDialog *pfsd;
HRESULT hr = pfd->QueryInterface(&pfsd);
if (SUCCEEDED(hr))
{
UINT uIndex;
hr = pfsd->GetFileTypeIndex(&uIndex); // index of current file-type
if (SUCCEEDED(hr))
{
IPropertyDescriptionList *pdl = NULL;
}
pfsd->Release();
}
return hr;
}
// IFileDialogControlEvents
// This method gets called when an dialog control item selection happens (radio-button selection. etc).
// For sample sake, let's react to this event by changing the dialog title.
HRESULT CDialogEventHandler::OnItemSelected(IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem)
{
IFileDialog *pfd = NULL;
HRESULT hr = pfdc->QueryInterface(&pfd);
if (SUCCEEDED(hr))
{
if (dwIDCtl == CONTROL_RADIOBUTTONLIST)
{
switch (dwIDItem)
{
case CONTROL_RADIOBUTTON1:
hr = pfd->SetTitle(L"Longhorn Dialog");
break;
case CONTROL_RADIOBUTTON2:
hr = pfd->SetTitle(L"Vista Dialog");
break;
}
}
pfd->Release();
}
return hr;
}

8
VST/FileOpenDialog.hpp Normal file
View File

@ -0,0 +1,8 @@
#ifndef __AMUSE_FILEOPENDIALOG_HPP__
#define __AMUSE_FILEOPENDIALOG_HPP__
#include <string>
std::wstring openDB();
#endif // __AMUSE_FILEOPENDIALOG_HPP__

View File

@ -1,5 +1,6 @@
#include "VSTBackend.hpp"
#include "audiodev/AudioVoiceEngine.hpp"
#include <Shlobj.h>
#include <logvisor/logvisor.hpp>
struct VSTVoiceEngine : boo::BaseAudioVoiceEngine
@ -141,6 +142,13 @@ VSTBackend::VSTBackend(audioMasterCallback cb)
m_booBackend = std::make_unique<VSTVoiceEngine>();
m_voxAlloc.emplace(*m_booBackend);
m_engine.emplace(*m_voxAlloc);
WCHAR path[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path)))
{
m_userDir = std::wstring(path) + L"\\Amuse";
CreateDirectory(m_userDir.c_str(), nullptr);
}
}
VSTBackend::~VSTBackend()

View File

@ -31,6 +31,7 @@ class VSTBackend : public AudioEffectX
std::experimental::optional<amuse::VSTBackendVoiceAllocator> m_voxAlloc;
std::experimental::optional<amuse::Engine> m_engine;
size_t m_curFrame = 0;
std::wstring m_userDir;
VSTEditor m_editor;
public:
VSTBackend(audioMasterCallback cb);
@ -48,6 +49,9 @@ public:
VstInt32 getNumMidiInputChannels();
void setSampleRate(float sampleRate);
void setBlockSize(VstInt32 blockSize);
amuse::Engine& getAmuseEngine() {return *m_engine;}
const std::wstring& getUserDir() const {return m_userDir;}
};
}

View File

@ -1,5 +1,8 @@
#include "VSTEditor.hpp"
#include "VSTBackend.hpp"
#include "FileOpenDialog.hpp"
#include <Windowsx.h>
#include <shellapi.h>
extern void* hInstance;
static WNDPROC OriginalListViewProc = 0;
@ -45,6 +48,31 @@ LRESULT CALLBACK VSTEditor::WindowProc(HWND hwnd,
editor.selectPage(itemAct.iItem);
return 0;
}
case TVN_GETDISPINFO:
{
NMTVDISPINFO& treeDispInfo = *reinterpret_cast<LPNMTVDISPINFO>(lParam);
if (treeDispInfo.item.mask & TVIF_CHILDREN)
{
}
return 0;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
case WM_COMMAND:
{
switch (HIWORD(wParam))
{
case BN_CLICKED:
{
HWND button = HWND(lParam);
if (button == editor.m_collectionAdd)
editor.addAction();
else if (button == editor.m_collectionRemove)
editor.removeAction();
return 0;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
@ -137,34 +165,56 @@ bool VSTEditor::open(void* ptr)
SetWindowLongPtrW(m_rootView, 0, LONG_PTR(this));
ShowWindow(m_rootView, SW_SHOW);
TVINSERTSTRUCT treeItem = {};
treeItem.hParent = TVI_ROOT;
treeItem.hInsertAfter = TVI_LAST;
treeItem.item.mask = TVIF_CHILDREN | TVIF_TEXT;
treeItem.item.cChildren = 1;
treeItem.item.pszText = L"Root A";
LVCOLUMN column = {};
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
column.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH;
column.cx = 200;
column.cx = 199;
LVITEM item = {};
item.mask = LVIF_TEXT | LVIF_GROUPID;
item.mask = LVIF_TEXT;
item.pszText = L"Test";
item.iGroupId = 1;
m_collectionTree = CreateWindowW(WC_TREEVIEW,
L"",
WS_CHILD | WS_BORDER | TVS_HASLINES,
0, 24,
201,
m_windowRect.bottom - m_windowRect.top - 24,
WS_CHILD | WS_CLIPSIBLINGS | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS,
1, 25,
199,
m_windowRect.bottom - m_windowRect.top - 26,
m_rootView,
nullptr,
nullptr,
nullptr);
TreeView_SetBkColor(m_collectionTree, RGB(64,64,64));
TreeView_SetTextColor(m_collectionTree, RGB(255,255,255));
HTREEITEM rootItemA = TreeView_InsertItem(m_collectionTree, &treeItem);
treeItem.item.pszText = L"Root B";
HTREEITEM rootItemB = TreeView_InsertItem(m_collectionTree, &treeItem);
treeItem.hParent = rootItemA;
treeItem.item.cChildren = 0;
treeItem.item.pszText = L"Child A";
TreeView_InsertItem(m_collectionTree, &treeItem);
treeItem.item.pszText = L"Child B";
TreeView_InsertItem(m_collectionTree, &treeItem);
treeItem.hParent = rootItemB;
treeItem.item.pszText = L"Child A";
TreeView_InsertItem(m_collectionTree, &treeItem);
treeItem.item.pszText = L"Child B";
TreeView_InsertItem(m_collectionTree, &treeItem);
ShowWindow(m_collectionTree, SW_SHOW);
m_collectionHeader = CreateWindowW(WC_HEADER,
L"",
WS_CHILD,
1, 1,
200,
199,
24,
m_rootView,
nullptr,
@ -174,12 +224,39 @@ bool VSTEditor::open(void* ptr)
OriginalListViewProc = WNDPROC(SetWindowLongPtr(m_collectionHeader, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc)));
ShowWindow(m_collectionHeader, SW_SHOW);
m_collectionAdd = CreateWindowW(WC_BUTTON,
L"+",
WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON,
1, m_windowRect.bottom - m_windowRect.top - 26,
25, 24,
m_rootView,
nullptr,
nullptr,
nullptr);
SetWindowFont(m_collectionAdd, GetStockObject(ANSI_FIXED_FONT), FALSE);
Button_Enable(m_collectionAdd, TRUE);
SetWindowPos(m_collectionAdd, HWND_TOP, 1, m_windowRect.bottom - m_windowRect.top - 26, 25, 24, SWP_SHOWWINDOW);
m_collectionRemove = CreateWindowW(WC_BUTTON,
L"-",
WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON,
26, m_windowRect.bottom - m_windowRect.top - 26,
25, 24,
m_rootView,
nullptr,
nullptr,
nullptr);
SetWindowFont(m_collectionRemove, GetStockObject(ANSI_FIXED_FONT), FALSE);
Button_Enable(m_collectionRemove, TRUE);
SetWindowPos(m_collectionRemove, HWND_TOP, 26, m_windowRect.bottom - m_windowRect.top - 26, 25, 24, SWP_SHOWWINDOW);
m_groupListView = CreateWindowW(WC_LISTVIEW,
L"",
WS_CHILD | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
200, 0,
201,
m_windowRect.bottom - m_windowRect.top,
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
201, 1,
199,
m_windowRect.bottom - m_windowRect.top - 2,
m_rootView,
nullptr,
nullptr,
@ -189,25 +266,32 @@ bool VSTEditor::open(void* ptr)
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
ListView_SetBkColor(m_groupListView, RGB(64,64,64));
ListView_SetTextBkColor(m_groupListView, CLR_NONE);
ListView_SetTextColor(m_groupListView, RGB(255,255,255));
ListView_InsertColumn(m_groupListView, 0, &column);
ListView_InsertItem(m_groupListView, &item);
ShowWindow(m_groupListView, SW_SHOW);
m_pageListView = CreateWindowW(WC_LISTVIEW,
L"",
WS_CHILD | WS_BORDER | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
400, 0,
200,
m_windowRect.bottom - m_windowRect.top,
WS_CHILD | LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER,
401, 1,
198,
m_windowRect.bottom - m_windowRect.top - 2,
m_rootView,
nullptr,
nullptr,
nullptr);
column.pszText = L"Page";
column.cx = 198;
header = ListView_GetHeader(m_pageListView);
SetWindowLongPtrW(header, GWLP_USERDATA, LONG_PTR(column.pszText));
SetWindowLongPtr(header, GWLP_WNDPROC, LONG_PTR(ColHeaderWindowProc));
ListView_SetBkColor(m_pageListView, RGB(64,64,64));
ListView_SetTextBkColor(m_pageListView, CLR_NONE);
ListView_SetTextColor(m_pageListView, RGB(255,255,255));
ListView_InsertColumn(m_pageListView, 0, &column);
ListView_InsertItem(m_pageListView, &item);
ShowWindow(m_pageListView, SW_SHOW);
return true;
@ -224,6 +308,31 @@ void VSTEditor::update()
}
void VSTEditor::addAction()
{
VstFileSelect fSelect = {};
fSelect.command = kVstFileLoad;
fSelect.type = kVstFileType;
strcpy(fSelect.title, "Select Audio Group Archive");
if (m_backend.openFileSelector(&fSelect))
{
m_backend.closeFileSelector(&fSelect);
}
else
{
std::wstring path = openDB();
if (path.size())
{
}
}
}
void VSTEditor::removeAction()
{
}
void VSTEditor::selectCollection(int idx)
{

View File

@ -14,12 +14,16 @@ class VSTBackend;
/** Editor UI class */
class VSTEditor : public AEffEditor
{
friend class AudioGroupFilePresenter;
VSTBackend& m_backend;
ERect m_windowRect = {0, 0, 420, 600};
HWND m_rootView;
HWND m_collectionHeader;
HWND m_collectionTree;
HWND m_collectionAdd;
HWND m_collectionRemove;
HWND m_groupListView;
HWND m_pageListView;
@ -43,6 +47,9 @@ public:
void close();
void update();
void addAction();
void removeAction();
void selectCollection(int idx);
void selectGroup(int idx);
void selectPage(int idx);