RAM2118 commited on
Commit
01a8444
·
verified ·
1 Parent(s): 9f7698e

Upload Source/Plugin/PluginBridgeEditor.cpp

Browse files
Files changed (1) hide show
  1. Source/Plugin/PluginBridgeEditor.cpp +92 -94
Source/Plugin/PluginBridgeEditor.cpp CHANGED
@@ -7,93 +7,102 @@ static const juce::Colour kTextPrimary (0xffe8e8f0);
7
  static const juce::Colour kTextSecondary(0xff8888aa);
8
  static const juce::Colour kGreen (0xff4cef50);
9
  static const juce::Colour kRed (0xffef5350);
10
- static const juce::Colour kYellow (0xffffeb3b);
11
- static const juce::Colour kBtnBg (0xff2a2a44);
12
 
13
  PluginBridgeEditor::PluginBridgeEditor(PluginBridgeProcessor& p)
14
  : AudioProcessorEditor(&p), processorRef(p)
15
  {
16
- setSize(340, 200);
 
17
 
 
18
  titleLabel.setText("PluginBridge", juce::dontSendNotification);
19
- titleLabel.setFont(juce::FontOptions(18.0f));
20
  titleLabel.setJustificationType(juce::Justification::centredLeft);
21
  titleLabel.setColour(juce::Label::textColourId, kTextPrimary);
22
  addAndMakeVisible(titleLabel);
23
 
 
24
  mcpStatusLabel.setFont(juce::FontOptions(11.0f));
25
  mcpStatusLabel.setJustificationType(juce::Justification::centredRight);
26
  addAndMakeVisible(mcpStatusLabel);
27
 
28
- pluginStatusLabel.setFont(juce::FontOptions(13.0f));
 
29
  pluginStatusLabel.setJustificationType(juce::Justification::centredLeft);
30
  pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
31
  addAndMakeVisible(pluginStatusLabel);
32
 
33
- connectionLabel.setFont(juce::FontOptions(10.0f));
34
- connectionLabel.setJustificationType(juce::Justification::centredLeft);
35
- connectionLabel.setColour(juce::Label::textColourId, kTextSecondary);
36
- addAndMakeVisible(connectionLabel);
37
-
38
  selectButton.onClick = [this]() { showPluginMenu(); };
39
  selectButton.setColour(juce::TextButton::buttonColourId, kAccent);
40
  selectButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
41
  addAndMakeVisible(selectButton);
42
 
43
- guiButton.onClick = [this]() { toggleGui(); };
44
- guiButton.setColour(juce::TextButton::buttonColourId, kBtnBg);
45
- guiButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
46
- addAndMakeVisible(guiButton);
 
47
 
48
- reloadButton.onClick = [this]() {
49
- auto path = processorRef.getLastPluginPath();
50
- if (path.isNotEmpty())
51
- processorRef.loadPlugin(path);
52
  };
53
- reloadButton.setColour(juce::TextButton::buttonColourId, kRed);
54
- reloadButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
55
- reloadButton.setVisible(false);
56
- addAndMakeVisible(reloadButton);
57
 
58
- startTimerHz(8);
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
 
61
  PluginBridgeEditor::~PluginBridgeEditor()
62
  {
63
  stopTimer();
 
 
 
 
64
  }
65
 
66
  void PluginBridgeEditor::paint(juce::Graphics& g)
67
  {
68
  g.fillAll(kBgDark);
69
 
70
- auto panelArea = getLocalBounds().reduced(8);
 
71
  g.setColour(kBgPanel);
72
- g.fillRoundedRectangle(panelArea.toFloat(), 8.0f);
73
 
 
74
  g.setColour(kAccent.withAlpha(0.3f));
75
- g.drawRoundedRectangle(panelArea.toFloat(), 8.0f, 1.0f);
76
  }
77
 
78
  void PluginBridgeEditor::resized()
79
  {
80
- auto area = getLocalBounds().reduced(16);
81
-
82
- auto topRow = area.removeFromTop(24);
83
- titleLabel.setBounds(topRow.removeFromLeft(160));
84
- mcpStatusLabel.setBounds(topRow);
85
-
86
- area.removeFromTop(8);
87
- pluginStatusLabel.setBounds(area.removeFromTop(20));
88
- connectionLabel.setBounds(area.removeFromTop(16));
89
- area.removeFromTop(12);
90
-
91
- auto buttonRow = area.removeFromTop(32);
92
- selectButton.setBounds(buttonRow.removeFromLeft(130));
93
- buttonRow.removeFromLeft(6);
94
- guiButton.setBounds(buttonRow.removeFromLeft(90));
95
- buttonRow.removeFromLeft(6);
96
- reloadButton.setBounds(buttonRow);
97
  }
98
 
99
  void PluginBridgeEditor::timerCallback()
@@ -105,68 +114,47 @@ void PluginBridgeEditor::timerCallback()
105
  }
106
  else
107
  {
108
- mcpStatusLabel.setText("MCP: off", juce::dontSendNotification);
109
  mcpStatusLabel.setColour(juce::Label::textColourId, kRed);
110
  }
111
 
112
- auto connState = processorRef.getConnectionState();
113
-
114
  if (processorRef.isPluginLoaded())
115
  {
116
- pluginStatusLabel.setText(processorRef.getLoadedPluginName() + " • " +
117
- juce::String(processorRef.getLoadedPluginParamCount()) + " params",
118
- juce::dontSendNotification);
119
- pluginStatusLabel.setColour(juce::Label::textColourId, kTextPrimary);
120
  selectButton.setButtonText(processorRef.getLoadedPluginName());
121
- guiButton.setVisible(true);
122
- reloadButton.setVisible(false);
123
  }
124
- else
125
  {
 
126
  pluginStatusLabel.setText("No plugin loaded", juce::dontSendNotification);
127
  pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
128
- selectButton.setButtonText("Select Plugin");
129
- guiButton.setVisible(false);
130
  }
 
131
 
132
- switch (connState)
133
- {
134
- case HelperConnection::State::Disconnected:
135
- connectionLabel.setText("", juce::dontSendNotification);
136
- break;
137
- case HelperConnection::State::Starting:
138
- connectionLabel.setText("Starting helper...", juce::dontSendNotification);
139
- connectionLabel.setColour(juce::Label::textColourId, kYellow);
140
- break;
141
- case HelperConnection::State::Connected:
142
- connectionLabel.setText("Helper connected", juce::dontSendNotification);
143
- connectionLabel.setColour(juce::Label::textColourId, kGreen);
144
- break;
145
- case HelperConnection::State::Crashed:
146
- connectionLabel.setText("Plugin crashed - click Reload", juce::dontSendNotification);
147
- connectionLabel.setColour(juce::Label::textColourId, kRed);
148
- reloadButton.setVisible(true);
149
- guiButton.setVisible(false);
150
- guiOpen = false;
151
- break;
152
- }
153
  }
154
 
155
- void PluginBridgeEditor::toggleGui()
156
  {
157
- if (guiOpen)
158
  {
159
- processorRef.hidePluginGui();
160
- guiButton.setButtonText("Open GUI");
161
- guiButton.setColour(juce::TextButton::buttonColourId, kBtnBg);
162
- guiOpen = false;
163
- }
164
- else
165
- {
166
- processorRef.showPluginGui();
167
- guiButton.setButtonText("Close GUI");
168
- guiButton.setColour(juce::TextButton::buttonColourId, kRed.withAlpha(0.7f));
169
- guiOpen = true;
170
  }
171
  }
172
 
@@ -191,11 +179,13 @@ void PluginBridgeEditor::showPluginMenu()
191
  {
192
  const auto& file = files[i];
193
  auto name = file.getFileNameWithoutExtension();
 
 
194
 
195
  if (file.getFileExtension() == ".vst3")
196
- vst3Menu.addItem(itemId, name);
197
  else
198
- auMenu.addItem(itemId, name);
199
 
200
  itemId++;
201
  }
@@ -205,14 +195,22 @@ void PluginBridgeEditor::showPluginMenu()
205
  if (auMenu.getNumItems() > 0)
206
  menu.addSubMenu("Audio Units", auMenu);
207
 
 
 
 
208
  menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&selectButton),
209
  [this, files](int result)
210
  {
 
 
 
 
 
 
211
  if (result > 0 && result <= files.size())
212
  {
213
- guiOpen = false;
214
- guiButton.setButtonText("Open GUI");
215
- guiButton.setColour(juce::TextButton::buttonColourId, juce::Colour(0xff2a2a44));
216
  processorRef.loadPlugin(files[result - 1].getFullPathName());
217
  }
218
  });
 
7
  static const juce::Colour kTextSecondary(0xff8888aa);
8
  static const juce::Colour kGreen (0xff4cef50);
9
  static const juce::Colour kRed (0xffef5350);
 
 
10
 
11
  PluginBridgeEditor::PluginBridgeEditor(PluginBridgeProcessor& p)
12
  : AudioProcessorEditor(&p), processorRef(p)
13
  {
14
+ setSize(kDefaultWidth, kDefaultHeight);
15
+ setResizable(true, true);
16
 
17
+ // Title
18
  titleLabel.setText("PluginBridge", juce::dontSendNotification);
19
+ titleLabel.setFont(juce::FontOptions(14.0f));
20
  titleLabel.setJustificationType(juce::Justification::centredLeft);
21
  titleLabel.setColour(juce::Label::textColourId, kTextPrimary);
22
  addAndMakeVisible(titleLabel);
23
 
24
+ // MCP status
25
  mcpStatusLabel.setFont(juce::FontOptions(11.0f));
26
  mcpStatusLabel.setJustificationType(juce::Justification::centredRight);
27
  addAndMakeVisible(mcpStatusLabel);
28
 
29
+ // Plugin name
30
+ pluginStatusLabel.setFont(juce::FontOptions(11.0f));
31
  pluginStatusLabel.setJustificationType(juce::Justification::centredLeft);
32
  pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
33
  addAndMakeVisible(pluginStatusLabel);
34
 
35
+ // Select button
 
 
 
 
36
  selectButton.onClick = [this]() { showPluginMenu(); };
37
  selectButton.setColour(juce::TextButton::buttonColourId, kAccent);
38
  selectButton.setColour(juce::TextButton::textColourOffId, kTextPrimary);
39
  addAndMakeVisible(selectButton);
40
 
41
+ // Callbacks from processor
42
+ processorRef.onPluginLoaded = [this]()
43
+ {
44
+ juce::MessageManager::callAsync([this]() { embedPluginEditor(); });
45
+ };
46
 
47
+ processorRef.onPluginUnloaded = [this]()
48
+ {
49
+ juce::MessageManager::callAsync([this]() { removePluginEditor(); });
 
50
  };
 
 
 
 
51
 
52
+ processorRef.onLoadFailed = [this](const juce::String& error)
53
+ {
54
+ juce::MessageManager::callAsync([this, error]()
55
+ {
56
+ pluginStatusLabel.setText(error, juce::dontSendNotification);
57
+ pluginStatusLabel.setColour(juce::Label::textColourId, kRed);
58
+ });
59
+ };
60
+
61
+ // If plugin already loaded (e.g. restoring state), embed it
62
+ if (processorRef.isPluginLoaded())
63
+ embedPluginEditor();
64
+
65
+ startTimerHz(4);
66
  }
67
 
68
  PluginBridgeEditor::~PluginBridgeEditor()
69
  {
70
  stopTimer();
71
+ processorRef.onPluginLoaded = nullptr;
72
+ processorRef.onPluginUnloaded = nullptr;
73
+ processorRef.onLoadFailed = nullptr;
74
+ removePluginEditor();
75
  }
76
 
77
  void PluginBridgeEditor::paint(juce::Graphics& g)
78
  {
79
  g.fillAll(kBgDark);
80
 
81
+ // Top bar background
82
+ auto topBar = getLocalBounds().removeFromTop(kTopBarHeight);
83
  g.setColour(kBgPanel);
84
+ g.fillRect(topBar);
85
 
86
+ // Separator line
87
  g.setColour(kAccent.withAlpha(0.3f));
88
+ g.drawHorizontalLine(kTopBarHeight - 1, 0.0f, (float)getWidth());
89
  }
90
 
91
  void PluginBridgeEditor::resized()
92
  {
93
+ auto area = getLocalBounds();
94
+ auto topBar = area.removeFromTop(kTopBarHeight).reduced(6, 4);
95
+
96
+ // Top bar layout
97
+ titleLabel.setBounds(topBar.removeFromLeft(90));
98
+ selectButton.setBounds(topBar.removeFromLeft(110).reduced(0, 2));
99
+ topBar.removeFromLeft(6);
100
+ pluginStatusLabel.setBounds(topBar.removeFromLeft(topBar.getWidth() - 70));
101
+ mcpStatusLabel.setBounds(topBar);
102
+
103
+ // Plugin editor fills the rest
104
+ if (hostedEditor)
105
+ hostedEditor->setBounds(area);
 
 
 
 
106
  }
107
 
108
  void PluginBridgeEditor::timerCallback()
 
114
  }
115
  else
116
  {
117
+ mcpStatusLabel.setText("MCP:off", juce::dontSendNotification);
118
  mcpStatusLabel.setColour(juce::Label::textColourId, kRed);
119
  }
120
 
 
 
121
  if (processorRef.isPluginLoaded())
122
  {
 
 
 
 
123
  selectButton.setButtonText(processorRef.getLoadedPluginName());
124
+ pluginStatusLabel.setText(juce::String(processorRef.getLoadedPluginParamCount()) + " params", juce::dontSendNotification);
125
+ pluginStatusLabel.setColour(juce::Label::textColourId, kGreen);
126
  }
127
+ else if (pluginStatusLabel.getColour(juce::Label::textColourId) != kRed)
128
  {
129
+ selectButton.setButtonText("Select Plugin");
130
  pluginStatusLabel.setText("No plugin loaded", juce::dontSendNotification);
131
  pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
 
 
132
  }
133
+ }
134
 
135
+ void PluginBridgeEditor::embedPluginEditor()
136
+ {
137
+ removePluginEditor();
138
+
139
+ auto* editor = processorRef.createHostedPluginEditor();
140
+ if (!editor) return;
141
+
142
+ hostedEditor.reset(editor);
143
+ addAndMakeVisible(hostedEditor.get());
144
+
145
+ // Resize PluginBridge editor to fit the hosted plugin's GUI + top bar
146
+ auto editorWidth = std::max(hostedEditor->getWidth(), kDefaultWidth);
147
+ auto editorHeight = hostedEditor->getHeight() + kTopBarHeight;
148
+ setSize(editorWidth, editorHeight);
 
 
 
 
 
 
 
149
  }
150
 
151
+ void PluginBridgeEditor::removePluginEditor()
152
  {
153
+ if (hostedEditor)
154
  {
155
+ removeChildComponent(hostedEditor.get());
156
+ hostedEditor.reset();
157
+ setSize(kDefaultWidth, kDefaultHeight);
 
 
 
 
 
 
 
 
158
  }
159
  }
160
 
 
179
  {
180
  const auto& file = files[i];
181
  auto name = file.getFileNameWithoutExtension();
182
+ auto path = file.getFullPathName();
183
+ bool blocked = processorRef.isBlocked(path);
184
 
185
  if (file.getFileExtension() == ".vst3")
186
+ vst3Menu.addItem(itemId, blocked ? name + " (not compatible)" : name, !blocked);
187
  else
188
+ auMenu.addItem(itemId, blocked ? name + " (not compatible)" : name, !blocked);
189
 
190
  itemId++;
191
  }
 
195
  if (auMenu.getNumItems() > 0)
196
  menu.addSubMenu("Audio Units", auMenu);
197
 
198
+ menu.addSeparator();
199
+ menu.addItem(9999, "Clear blocklist");
200
+
201
  menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&selectButton),
202
  [this, files](int result)
203
  {
204
+ if (result == 9999)
205
+ {
206
+ processorRef.getBlocklist().clear();
207
+ return;
208
+ }
209
+
210
  if (result > 0 && result <= files.size())
211
  {
212
+ pluginStatusLabel.setText("Loading...", juce::dontSendNotification);
213
+ pluginStatusLabel.setColour(juce::Label::textColourId, kTextSecondary);
 
214
  processorRef.loadPlugin(files[result - 1].getFullPathName());
215
  }
216
  });