pluginbridge / Source /Plugin /PluginBridgeEditor.cpp
RAM2118's picture
Upload Source/Plugin/PluginBridgeEditor.cpp
01a8444 verified
Raw History Blame
7.07 kB
#include "PluginBridgeEditor.h"
static const juce::Colour kBgDark (0xff0d0d1a);
static const juce::Colour kBgPanel (0xff1a1a2e);
static const juce::Colour kAccent (0xff6c63ff);
static const juce::Colour kTextPrimary (0xffe8e8f0);
static const juce::Colour kTextSecondary(0xff8888aa);
static const juce::Colour kGreen (0xff4cef50);
static const juce::Colour kRed (0xffef5350);
PluginBridgeEditor::PluginBridgeEditor(PluginBridgeProcessor& p)
: AudioProcessorEditor(&p), processorRef(p)
{
setSize(kDefaultWidth, kDefaultHeight);
setResizable(true, true);
// Title
titleLabel.setText("PluginBridge", juce::dontSendNotification);
titleLabel.setFont(juce::FontOptions(14.0f));
titleLabel.setJustificationType(juce::Justification::centredLeft);
titleLabel.setColour(juce::Label::textColourId, kTextPrimary);
addAndMakeVisible(titleLabel);
// MCP status
mcpStatusLabel.setFont(juce::FontOptions(11.0f));
mcpStatusLabel.setJustificationType(juce::Justification::centredRight);
addAndMakeVisible(mcpStatusLabel);
// Plugin name
pluginStatusLabel.setFont(juce::FontOptions(11.0f));
pluginStatusLabel.setJustificationType(juce::Justification::centredLeft);
pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
addAndMakeVisible(pluginStatusLabel);
// Select button
selectButton.onClick = [this]() { showPluginMenu(); };
selectButton.setColour(juce::TextButton::buttonColourId, kAccent);
selectButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
addAndMakeVisible(selectButton);
// Callbacks from processor
processorRef.onPluginLoaded = [this]()
{
juce::MessageManager::callAsync([this]() { embedPluginEditor(); });
};
processorRef.onPluginUnloaded = [this]()
{
juce::MessageManager::callAsync([this]() { removePluginEditor(); });
};
processorRef.onLoadFailed = [this](const juce::String& error)
{
juce::MessageManager::callAsync([this, error]()
{
pluginStatusLabel.setText(error, juce::dontSendNotification);
pluginStatusLabel.setColour(juce::Label::textColourId, kRed);
});
};
// If plugin already loaded (e.g. restoring state), embed it
if (processorRef.isPluginLoaded())
embedPluginEditor();
startTimerHz(4);
}
PluginBridgeEditor::~PluginBridgeEditor()
{
stopTimer();
processorRef.onPluginLoaded = nullptr;
processorRef.onPluginUnloaded = nullptr;
processorRef.onLoadFailed = nullptr;
removePluginEditor();
}
void PluginBridgeEditor::paint(juce::Graphics& g)
{
g.fillAll(kBgDark);
// Top bar background
auto topBar = getLocalBounds().removeFromTop(kTopBarHeight);
g.setColour(kBgPanel);
g.fillRect(topBar);
// Separator line
g.setColour(kAccent.withAlpha(0.3f));
g.drawHorizontalLine(kTopBarHeight - 1, 0.0f, (float)getWidth());
}
void PluginBridgeEditor::resized()
{
auto area = getLocalBounds();
auto topBar = area.removeFromTop(kTopBarHeight).reduced(6, 4);
// Top bar layout
titleLabel.setBounds(topBar.removeFromLeft(90));
selectButton.setBounds(topBar.removeFromLeft(110).reduced(0, 2));
topBar.removeFromLeft(6);
pluginStatusLabel.setBounds(topBar.removeFromLeft(topBar.getWidth() - 70));
mcpStatusLabel.setBounds(topBar);
// Plugin editor fills the rest
if (hostedEditor)
hostedEditor->setBounds(area);
}
void PluginBridgeEditor::timerCallback()
{
if (processorRef.isMcpServerRunning())
{
mcpStatusLabel.setText("MCP:" + juce::String(processorRef.getMcpServerPort()), juce::dontSendNotification);
mcpStatusLabel.setColour(juce::Label::textColourId, kGreen);
}
else
{
mcpStatusLabel.setText("MCP:off", juce::dontSendNotification);
mcpStatusLabel.setColour(juce::Label::textColourId, kRed);
}
if (processorRef.isPluginLoaded())
{
selectButton.setButtonText(processorRef.getLoadedPluginName());
pluginStatusLabel.setText(juce::String(processorRef.getLoadedPluginParamCount()) + " params", juce::dontSendNotification);
pluginStatusLabel.setColour(juce::Label::textColourId, kGreen);
}
else if (pluginStatusLabel.getColour(juce::Label::textColourId) != kRed)
{
selectButton.setButtonText("Select Plugin");
pluginStatusLabel.setText("No plugin loaded", juce::dontSendNotification);
pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
}
}
void PluginBridgeEditor::embedPluginEditor()
{
removePluginEditor();
auto* editor = processorRef.createHostedPluginEditor();
if (!editor) return;
hostedEditor.reset(editor);
addAndMakeVisible(hostedEditor.get());
// Resize PluginBridge editor to fit the hosted plugin's GUI + top bar
auto editorWidth = std::max(hostedEditor->getWidth(), kDefaultWidth);
auto editorHeight = hostedEditor->getHeight() + kTopBarHeight;
setSize(editorWidth, editorHeight);
}
void PluginBridgeEditor::removePluginEditor()
{
if (hostedEditor)
{
removeChildComponent(hostedEditor.get());
hostedEditor.reset();
setSize(kDefaultWidth, kDefaultHeight);
}
}
void PluginBridgeEditor::showPluginMenu()
{
auto files = processorRef.getInstalledPluginFiles();
juce::PopupMenu menu;
if (files.isEmpty())
{
menu.addItem(-1, "(No plugins found)", false);
menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&selectButton), [](int) {});
return;
}
juce::PopupMenu vst3Menu;
juce::PopupMenu auMenu;
int itemId = 1;
for (int i = 0; i < files.size(); ++i)
{
const auto& file = files[i];
auto name = file.getFileNameWithoutExtension();
auto path = file.getFullPathName();
bool blocked = processorRef.isBlocked(path);
if (file.getFileExtension() == ".vst3")
vst3Menu.addItem(itemId, blocked ? name + " (not compatible)" : name, !blocked);
else
auMenu.addItem(itemId, blocked ? name + " (not compatible)" : name, !blocked);
itemId++;
}
if (vst3Menu.getNumItems() > 0)
menu.addSubMenu("VST3", vst3Menu);
if (auMenu.getNumItems() > 0)
menu.addSubMenu("Audio Units", auMenu);
menu.addSeparator();
menu.addItem(9999, "Clear blocklist");
menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&selectButton),
[this, files](int result)
{
if (result == 9999)
{
processorRef.getBlocklist().clear();
return;
}
if (result > 0 && result <= files.size())
{
pluginStatusLabel.setText("Loading...", juce::dontSendNotification);
pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
processorRef.loadPlugin(files[result - 1].getFullPathName());
}
});
}