mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Implement the plugin side of IContextMenu
This commit is contained in:
@@ -187,6 +187,10 @@ using CallbackRequest = std::variant<Vst3ContextMenuProxy::Destruct,
|
|||||||
// `IConnectionPoint::notify` calls through
|
// `IConnectionPoint::notify` calls through
|
||||||
// there
|
// there
|
||||||
YaConnectionPoint::Notify,
|
YaConnectionPoint::Notify,
|
||||||
|
YaContextMenu::GetItemCount,
|
||||||
|
YaContextMenu::AddItem,
|
||||||
|
YaContextMenu::RemoveItem,
|
||||||
|
YaContextMenu::Popup,
|
||||||
YaHostApplication::GetName,
|
YaHostApplication::GetName,
|
||||||
YaPlugFrame::ResizeView,
|
YaPlugFrame::ResizeView,
|
||||||
YaUnitHandler::NotifyUnitSelection,
|
YaUnitHandler::NotifyUnitSelection,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "context-menu-target.h"
|
#include "context-menu-target.h"
|
||||||
|
|
||||||
|
YaContextMenuTarget::ConstructArgs::ConstructArgs() {}
|
||||||
|
|
||||||
YaContextMenuTarget::ConstructArgs::ConstructArgs(
|
YaContextMenuTarget::ConstructArgs::ConstructArgs(
|
||||||
native_size_t owner_instance_id,
|
native_size_t owner_instance_id,
|
||||||
native_size_t context_menu_id,
|
native_size_t context_menu_id,
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pluginterfaces/vst/ivstcontextmenu.h>
|
#include <pluginterfaces/vst/ivstcontextmenu.h>
|
||||||
|
#include "bitsery/ext/std_optional.h"
|
||||||
|
|
||||||
#include "../../common.h"
|
#include "../../common.h"
|
||||||
#include "../base.h"
|
#include "../base.h"
|
||||||
|
#include "../context-menu-target.h"
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||||
@@ -105,19 +107,19 @@ class YaContextMenu : public Steinberg::Vst::IContextMenu {
|
|||||||
Steinberg::Vst::IContextMenuItem item;
|
Steinberg::Vst::IContextMenuItem item;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will be true if the plugin passed a `target` pointer. I'm not sure if
|
* Will be a nullopt if the plugin does not pass a `target` pointer. I'm
|
||||||
* this is optional since there are no implementations for this
|
* not sure if this is optional since there are no implementations for
|
||||||
* interface to be found, but I can imagine that this could be optional
|
* this interface to be found, but I can imagine that this could be
|
||||||
* for disabled menu items or for group starts/ends.
|
* optional for disabled menu items or for group starts/ends.
|
||||||
*/
|
*/
|
||||||
bool has_target;
|
std::optional<YaContextMenuTarget::ConstructArgs> target;
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
void serialize(S& s) {
|
void serialize(S& s) {
|
||||||
s.value8b(owner_instance_id);
|
s.value8b(owner_instance_id);
|
||||||
s.value8b(context_menu_id);
|
s.value8b(context_menu_id);
|
||||||
s.object(item);
|
s.object(item);
|
||||||
s.value1b(has_target);
|
s.ext(target, bitsery::ext::StdOptional{});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -186,7 +188,7 @@ namespace Steinberg {
|
|||||||
namespace Vst {
|
namespace Vst {
|
||||||
template <typename S>
|
template <typename S>
|
||||||
void serialize(S& s, IContextMenuItem& item) {
|
void serialize(S& s, IContextMenuItem& item) {
|
||||||
s.text2b(item.name, std::extent_v<Steinberg::Vst::String128>);
|
s.text2b(item.name);
|
||||||
s.value4b(item.tag);
|
s.value4b(item.tag);
|
||||||
s.value4b(item.flags);
|
s.value4b(item.flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
|
|
||||||
#include "plug-view-proxy.h"
|
#include "plug-view-proxy.h"
|
||||||
|
|
||||||
|
Vst3PluginProxyImpl::ContextMenu::ContextMenu(
|
||||||
|
Steinberg::IPtr<Steinberg::Vst::IContextMenu> menu)
|
||||||
|
: menu(menu) {}
|
||||||
|
|
||||||
Vst3PluginProxyImpl::Vst3PluginProxyImpl(Vst3PluginBridge& bridge,
|
Vst3PluginProxyImpl::Vst3PluginProxyImpl(Vst3PluginBridge& bridge,
|
||||||
Vst3PluginProxy::ConstructArgs&& args)
|
Vst3PluginProxy::ConstructArgs&& args)
|
||||||
: Vst3PluginProxy(std::move(args)), bridge(bridge) {
|
: Vst3PluginProxy(std::move(args)), bridge(bridge) {
|
||||||
|
|||||||
@@ -258,6 +258,26 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
|
|||||||
*/
|
*/
|
||||||
Vst3PlugViewProxyImpl* last_created_plug_view = nullptr;
|
Vst3PlugViewProxyImpl* last_created_plug_view = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pointer to a context menu returned by the host as a response to a call
|
||||||
|
* to `IComponentHandler3::createContextMenu`, as well as all targets we've
|
||||||
|
* created for it. This way we can drop both all at once.
|
||||||
|
*/
|
||||||
|
struct ContextMenu {
|
||||||
|
ContextMenu(Steinberg::IPtr<Steinberg::Vst::IContextMenu> menu);
|
||||||
|
|
||||||
|
Steinberg::IPtr<Steinberg::Vst::IContextMenu> menu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All targets we pass to `IContextMenu::addItem`. We'll store them per
|
||||||
|
* item tag, so we can drop them together with the menu. We probably
|
||||||
|
* don't have to use smart pointers for this, but the docs are missing a
|
||||||
|
* lot of details o how this should be implemented and there's no
|
||||||
|
* example implementation around.
|
||||||
|
*/
|
||||||
|
std::map<int32, Steinberg::IPtr<YaContextMenuTarget>> targets;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All context menus created by this object through
|
* All context menus created by this object through
|
||||||
* `IComponentHandler3::createContextMenu()`. We'll generate a unique
|
* `IComponentHandler3::createContextMenu()`. We'll generate a unique
|
||||||
@@ -269,8 +289,7 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
|
|||||||
* @see Vst3PluginProxyImpl::register_context_menu
|
* @see Vst3PluginProxyImpl::register_context_menu
|
||||||
* @see Vst3PluginProxyImpl::unregister_context_menu
|
* @see Vst3PluginProxyImpl::unregister_context_menu
|
||||||
*/
|
*/
|
||||||
std::map<size_t, Steinberg::IPtr<Steinberg::Vst::IContextMenu>>
|
std::map<size_t, ContextMenu> context_menus;
|
||||||
context_menus;
|
|
||||||
std::mutex context_menus_mutex;
|
std::mutex context_menus_mutex;
|
||||||
|
|
||||||
// The following pointers are cast from `host_context` if
|
// The following pointers are cast from `host_context` if
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "vst3.h"
|
#include "vst3.h"
|
||||||
|
|
||||||
#include "src/common/serialization/vst3.h"
|
#include "src/common/serialization/vst3.h"
|
||||||
|
#include "vst3-impls/context-menu-target.h"
|
||||||
#include "vst3-impls/plugin-factory.h"
|
#include "vst3-impls/plugin-factory.h"
|
||||||
#include "vst3-impls/plugin-proxy.h"
|
#include "vst3-impls/plugin-proxy.h"
|
||||||
|
|
||||||
@@ -148,6 +149,57 @@ Vst3PluginBridge::Vst3PluginBridge()
|
|||||||
.context_menu_args = std::nullopt};
|
.context_menu_args = std::nullopt};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[&](const YaContextMenu::GetItemCount& request)
|
||||||
|
-> YaContextMenu::GetItemCount::Response {
|
||||||
|
return plugin_proxies.at(request.owner_instance_id)
|
||||||
|
.get()
|
||||||
|
.context_menus.at(request.context_menu_id)
|
||||||
|
.menu->getItemCount();
|
||||||
|
},
|
||||||
|
[&](YaContextMenu::AddItem& request)
|
||||||
|
-> YaContextMenu::AddItem::Response {
|
||||||
|
Vst3PluginProxyImpl::ContextMenu& context_menu =
|
||||||
|
plugin_proxies.at(request.owner_instance_id)
|
||||||
|
.get()
|
||||||
|
.context_menus.at(request.context_menu_id);
|
||||||
|
|
||||||
|
if (request.target) {
|
||||||
|
context_menu.targets[request.item.tag] =
|
||||||
|
Steinberg::owned(new YaContextMenuTargetImpl(
|
||||||
|
*this, std::move(*request.target)));
|
||||||
|
|
||||||
|
return context_menu.menu->addItem(
|
||||||
|
request.item,
|
||||||
|
context_menu.targets[request.item.tag]);
|
||||||
|
} else {
|
||||||
|
return context_menu.menu->addItem(request.item,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const YaContextMenu::RemoveItem& request)
|
||||||
|
-> YaContextMenu::RemoveItem::Response {
|
||||||
|
Vst3PluginProxyImpl::ContextMenu& context_menu =
|
||||||
|
plugin_proxies.at(request.owner_instance_id)
|
||||||
|
.get()
|
||||||
|
.context_menus.at(request.context_menu_id);
|
||||||
|
|
||||||
|
if (const auto it =
|
||||||
|
context_menu.targets.find(request.item.tag);
|
||||||
|
it != context_menu.targets.end()) {
|
||||||
|
return context_menu.menu->removeItem(request.item,
|
||||||
|
it->second);
|
||||||
|
} else {
|
||||||
|
return context_menu.menu->removeItem(request.item,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const YaContextMenu::Popup& request)
|
||||||
|
-> YaContextMenu::Popup::Response {
|
||||||
|
return plugin_proxies.at(request.owner_instance_id)
|
||||||
|
.get()
|
||||||
|
.context_menus.at(request.context_menu_id)
|
||||||
|
.menu->popup(request.x, request.y);
|
||||||
|
},
|
||||||
[&](YaConnectionPoint::Notify& request)
|
[&](YaConnectionPoint::Notify& request)
|
||||||
-> YaConnectionPoint::Notify::Response {
|
-> YaConnectionPoint::Notify::Response {
|
||||||
return plugin_proxies.at(request.instance_id)
|
return plugin_proxies.at(request.instance_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user