RAM2118 commited on
Commit
adbb96a
·
verified ·
1 Parent(s): a33ab3c

Out-of-process rebuild: Add Plugin/PluginBridgeEditor.cpp — clean modern dark UI with status indicators

Browse files
Files changed (1) hide show
  1. Source/Plugin/PluginBridgeEditor.cpp +213 -0
Source/Plugin/PluginBridgeEditor.cpp ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "PluginBridgeEditor.h"
2
+
3
+ static const juce::Colour kBgDark (0xff0d0d1a);
4
+ static const juce::Colour kBgPanel (0xff1a1a2e);
5
+ static const juce::Colour kAccent (0xff6c63ff); // Purple accent
6
+ static const juce::Colour kAccentDim (0xff4a42cc);
7
+ static const juce::Colour kTextPrimary (0xffe8e8f0);
8
+ static const juce::Colour kTextSecondary(0xff8888aa);
9
+ static const juce::Colour kGreen (0xff4cef50);
10
+ static const juce::Colour kRed (0xffef5350);
11
+ static const juce::Colour kYellow (0xffffeb3b);
12
+ static const juce::Colour kBtnBg (0xff2a2a44);
13
+
14
+ PluginBridgeEditor::PluginBridgeEditor(PluginBridgeProcessor& p)
15
+ : AudioProcessorEditor(&p), processorRef(p)
16
+ {
17
+ setSize(340, 200);
18
+
19
+ // Title
20
+ titleLabel.setText("PluginBridge", juce::dontSendNotification);
21
+ titleLabel.setFont(juce::FontOptions(18.0f));
22
+ titleLabel.setJustificationType(juce::Justification::centredLeft);
23
+ titleLabel.setColour(juce::Label::textColourId, kTextPrimary);
24
+ addAndMakeVisible(titleLabel);
25
+
26
+ // MCP status
27
+ mcpStatusLabel.setFont(juce::FontOptions(11.0f));
28
+ mcpStatusLabel.setJustificationType(juce::Justification::centredRight);
29
+ addAndMakeVisible(mcpStatusLabel);
30
+
31
+ // Plugin status
32
+ pluginStatusLabel.setFont(juce::FontOptions(13.0f));
33
+ pluginStatusLabel.setJustificationType(juce::Justification::centredLeft);
34
+ pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
35
+ addAndMakeVisible(pluginStatusLabel);
36
+
37
+ // Connection status
38
+ connectionLabel.setFont(juce::FontOptions(10.0f));
39
+ connectionLabel.setJustificationType(juce::Justification::centredLeft);
40
+ connectionLabel.setColour(juce::Label::textColourId, kTextSecondary);
41
+ addAndMakeVisible(connectionLabel);
42
+
43
+ // Select plugin button
44
+ selectButton.onClick = [this]() { showPluginMenu(); };
45
+ selectButton.setColour(juce::TextButton::buttonColourId, kAccent);
46
+ selectButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
47
+ addAndMakeVisible(selectButton);
48
+
49
+ // Open GUI button
50
+ guiButton.onClick = [this]() { processorRef.showPluginGui(); };
51
+ guiButton.setColour(juce::TextButton::buttonColourId, kBtnBg);
52
+ guiButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
53
+ addAndMakeVisible(guiButton);
54
+
55
+ // Reload button (shown after crash)
56
+ reloadButton.onClick = [this]() {
57
+ auto path = processorRef.getLoadedPluginName();
58
+ // Re-attempt load with same plugin
59
+ // For now, just respawn helper
60
+ processorRef.loadPlugin(processorRef.getLoadedPluginName());
61
+ };
62
+ reloadButton.setColour(juce::TextButton::buttonColourId, kRed);
63
+ reloadButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
64
+ reloadButton.setVisible(false);
65
+ addAndMakeVisible(reloadButton);
66
+
67
+ startTimerHz(8);
68
+ }
69
+
70
+ PluginBridgeEditor::~PluginBridgeEditor()
71
+ {
72
+ stopTimer();
73
+ }
74
+
75
+ void PluginBridgeEditor::paint(juce::Graphics& g)
76
+ {
77
+ g.fillAll(kBgDark);
78
+
79
+ // Main panel
80
+ auto panelArea = getLocalBounds().reduced(8);
81
+ g.setColour(kBgPanel);
82
+ g.fillRoundedRectangle(panelArea.toFloat(), 8.0f);
83
+
84
+ // Subtle border
85
+ g.setColour(kAccent.withAlpha(0.3f));
86
+ g.drawRoundedRectangle(panelArea.toFloat(), 8.0f, 1.0f);
87
+ }
88
+
89
+ void PluginBridgeEditor::resized()
90
+ {
91
+ auto area = getLocalBounds().reduced(16);
92
+
93
+ // Top row: title + MCP status
94
+ auto topRow = area.removeFromTop(24);
95
+ titleLabel.setBounds(topRow.removeFromLeft(160));
96
+ mcpStatusLabel.setBounds(topRow);
97
+
98
+ area.removeFromTop(8);
99
+
100
+ // Plugin status line
101
+ pluginStatusLabel.setBounds(area.removeFromTop(20));
102
+ connectionLabel.setBounds(area.removeFromTop(16));
103
+
104
+ area.removeFromTop(12);
105
+
106
+ // Button row
107
+ auto buttonRow = area.removeFromTop(32);
108
+ selectButton.setBounds(buttonRow.removeFromLeft(140));
109
+ buttonRow.removeFromLeft(8);
110
+ guiButton.setBounds(buttonRow.removeFromLeft(90));
111
+ buttonRow.removeFromLeft(8);
112
+ reloadButton.setBounds(buttonRow);
113
+ }
114
+
115
+ void PluginBridgeEditor::timerCallback()
116
+ {
117
+ // MCP status
118
+ if (processorRef.isMcpServerRunning())
119
+ {
120
+ mcpStatusLabel.setText("MCP:" + juce::String(processorRef.getMcpServerPort()), juce::dontSendNotification);
121
+ mcpStatusLabel.setColour(juce::Label::textColourId, kGreen);
122
+ }
123
+ else
124
+ {
125
+ mcpStatusLabel.setText("MCP: off", juce::dontSendNotification);
126
+ mcpStatusLabel.setColour(juce::Label::textColourId, kRed);
127
+ }
128
+
129
+ // Plugin + connection status
130
+ auto connState = processorRef.getConnectionState();
131
+
132
+ if (processorRef.isPluginLoaded())
133
+ {
134
+ pluginStatusLabel.setText(processorRef.getLoadedPluginName() + " • " +
135
+ juce::String(processorRef.getLoadedPluginParamCount()) + " params",
136
+ juce::dontSendNotification);
137
+ pluginStatusLabel.setColour(juce::Label::textColourId, kTextPrimary);
138
+ selectButton.setButtonText(processorRef.getLoadedPluginName());
139
+ guiButton.setVisible(true);
140
+ reloadButton.setVisible(false);
141
+ }
142
+ else
143
+ {
144
+ pluginStatusLabel.setText("No plugin loaded", juce::dontSendNotification);
145
+ pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
146
+ selectButton.setButtonText("Select Plugin");
147
+ guiButton.setVisible(false);
148
+ }
149
+
150
+ switch (connState)
151
+ {
152
+ case HelperConnection::State::Disconnected:
153
+ connectionLabel.setText("", juce::dontSendNotification);
154
+ break;
155
+ case HelperConnection::State::Starting:
156
+ connectionLabel.setText("⏳ Starting helper...", juce::dontSendNotification);
157
+ connectionLabel.setColour(juce::Label::textColourId, kYellow);
158
+ break;
159
+ case HelperConnection::State::Connected:
160
+ connectionLabel.setText("⚡ Helper connected", juce::dontSendNotification);
161
+ connectionLabel.setColour(juce::Label::textColourId, kGreen);
162
+ break;
163
+ case HelperConnection::State::Crashed:
164
+ connectionLabel.setText("💥 Plugin crashed — click Reload", juce::dontSendNotification);
165
+ connectionLabel.setColour(juce::Label::textColourId, kRed);
166
+ reloadButton.setVisible(true);
167
+ guiButton.setVisible(false);
168
+ break;
169
+ }
170
+ }
171
+
172
+ void PluginBridgeEditor::showPluginMenu()
173
+ {
174
+ auto files = processorRef.getInstalledPluginFiles();
175
+
176
+ juce::PopupMenu menu;
177
+
178
+ if (files.isEmpty())
179
+ {
180
+ menu.addItem(-1, "(No plugins found)", false);
181
+ menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&selectButton), [](int) {});
182
+ return;
183
+ }
184
+
185
+ juce::PopupMenu vst3Menu;
186
+ juce::PopupMenu auMenu;
187
+ int itemId = 1;
188
+
189
+ for (int i = 0; i < files.size(); ++i)
190
+ {
191
+ const auto& file = files[i];
192
+ auto name = file.getFileNameWithoutExtension();
193
+
194
+ if (file.getFileExtension() == ".vst3")
195
+ vst3Menu.addItem(itemId, name);
196
+ else
197
+ auMenu.addItem(itemId, name);
198
+
199
+ itemId++;
200
+ }
201
+
202
+ if (vst3Menu.getNumItems() > 0)
203
+ menu.addSubMenu("VST3", vst3Menu);
204
+ if (auMenu.getNumItems() > 0)
205
+ menu.addSubMenu("Audio Units", auMenu);
206
+
207
+ menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&selectButton),
208
+ [this, files](int result)
209
+ {
210
+ if (result > 0 && result <= files.size())
211
+ processorRef.loadPlugin(files[result - 1].getFullPathName());
212
+ });
213
+ }