RAM2118 commited on
Commit
c8a084b
·
verified ·
1 Parent(s): ec53c6b

Sprint 2.1: Editor.cpp — system scan + popup menu sorted by manufacturer

Browse files
Files changed (1) hide show
  1. Source/PluginBridgeEditor.cpp +136 -35
Source/PluginBridgeEditor.cpp CHANGED
@@ -3,37 +3,56 @@
3
  PluginBridgeEditor::PluginBridgeEditor(PluginBridgeProcessor& p)
4
  : AudioProcessorEditor(&p), processorRef(p)
5
  {
6
- setSize(320, 200);
 
 
 
 
 
 
 
 
7
 
8
  // Title
9
  titleLabel.setText("PluginBridge", juce::dontSendNotification);
10
- titleLabel.setFont(juce::FontOptions(20.0f));
11
  titleLabel.setJustificationType(juce::Justification::centred);
 
12
  addAndMakeVisible(titleLabel);
13
 
14
  // MCP status
15
  statusLabel.setText("MCP: starting...", juce::dontSendNotification);
16
- statusLabel.setFont(juce::FontOptions(13.0f));
17
  statusLabel.setJustificationType(juce::Justification::centred);
18
  addAndMakeVisible(statusLabel);
19
 
20
  // Port
21
  portLabel.setText("", juce::dontSendNotification);
22
- portLabel.setFont(juce::FontOptions(11.0f));
23
  portLabel.setJustificationType(juce::Justification::centred);
24
- portLabel.setColour(juce::Label::textColourId, juce::Colours::grey);
25
  addAndMakeVisible(portLabel);
26
 
27
- // Hosted plugin name
28
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
29
  pluginLabel.setFont(juce::FontOptions(13.0f));
30
  pluginLabel.setJustificationType(juce::Justification::centred);
31
- pluginLabel.setColour(juce::Label::textColourId, juce::Colours::lightyellow);
32
  addAndMakeVisible(pluginLabel);
33
 
34
- // Load button
35
- loadButton.onClick = [this]() { loadPluginClicked(); };
36
- addAndMakeVisible(loadButton);
 
 
 
 
 
 
 
 
 
 
37
 
38
  startTimerHz(2);
39
  }
@@ -45,20 +64,23 @@ PluginBridgeEditor::~PluginBridgeEditor()
45
 
46
  void PluginBridgeEditor::paint(juce::Graphics& g)
47
  {
48
- g.fillAll(juce::Colour(0xff1a1a2e));
 
 
 
49
  }
50
 
51
  void PluginBridgeEditor::resized()
52
  {
53
- auto area = getLocalBounds().reduced(12);
54
- titleLabel.setBounds(area.removeFromTop(32));
55
- area.removeFromTop(6);
56
- statusLabel.setBounds(area.removeFromTop(22));
57
- portLabel.setBounds(area.removeFromTop(18));
 
 
58
  area.removeFromTop(8);
59
- pluginLabel.setBounds(area.removeFromTop(22));
60
- area.removeFromTop(8);
61
- loadButton.setBounds(area.removeFromTop(28).reduced(60, 0));
62
  }
63
 
64
  void PluginBridgeEditor::timerCallback()
@@ -67,14 +89,14 @@ void PluginBridgeEditor::timerCallback()
67
  if (processorRef.isMcpServerRunning())
68
  {
69
  statusLabel.setText("MCP: running", juce::dontSendNotification);
70
- statusLabel.setColour(juce::Label::textColourId, juce::Colours::limegreen);
71
- portLabel.setText("http://127.0.0.1:" + juce::String(processorRef.getMcpServerPort()) + "/mcp",
72
  juce::dontSendNotification);
73
  }
74
  else
75
  {
76
  statusLabel.setText("MCP: offline", juce::dontSendNotification);
77
- statusLabel.setColour(juce::Label::textColourId, juce::Colours::red);
78
  portLabel.setText("", juce::dontSendNotification);
79
  }
80
 
@@ -82,29 +104,108 @@ void PluginBridgeEditor::timerCallback()
82
  auto& mgr = processorRef.getHostedPluginManager();
83
  if (mgr.isLoaded())
84
  {
85
- pluginLabel.setText(mgr.getPluginName() + " (" + juce::String(mgr.getParameterCount()) + " params)",
86
  juce::dontSendNotification);
87
- pluginLabel.setColour(juce::Label::textColourId, juce::Colours::lightyellow);
 
88
  }
89
  else
90
  {
91
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
92
- pluginLabel.setColour(juce::Label::textColourId, juce::Colours::grey);
 
93
  }
94
  }
95
 
96
- void PluginBridgeEditor::loadPluginClicked()
97
  {
98
- auto chooser = std::make_shared<juce::FileChooser>(
99
- "Select VST3 or AU plugin",
100
- juce::File("/Library/Audio/Plug-Ins"),
101
- "*.vst3;*.component");
 
102
 
103
- chooser->launchAsync(juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles,
104
- [this, chooser](const juce::FileChooser& fc)
 
 
 
 
 
 
 
 
105
  {
106
- auto file = fc.getResult();
107
- if (file.exists())
108
- processorRef.loadPluginFromFile(file);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  });
110
  }
 
 
 
 
 
 
 
 
 
 
 
 
3
  PluginBridgeEditor::PluginBridgeEditor(PluginBridgeProcessor& p)
4
  : AudioProcessorEditor(&p), processorRef(p)
5
  {
6
+ setSize(360, 220);
7
+
8
+ // Register formats for scanning
9
+ #if JUCE_PLUGINHOST_VST3
10
+ scanFormatManager.addFormat(new juce::VST3PluginFormat());
11
+ #endif
12
+ #if JUCE_PLUGINHOST_AU
13
+ scanFormatManager.addFormat(new juce::AudioUnitPluginFormat());
14
+ #endif
15
 
16
  // Title
17
  titleLabel.setText("PluginBridge", juce::dontSendNotification);
18
+ titleLabel.setFont(juce::FontOptions(22.0f));
19
  titleLabel.setJustificationType(juce::Justification::centred);
20
+ titleLabel.setColour(juce::Label::textColourId, juce::Colours::white);
21
  addAndMakeVisible(titleLabel);
22
 
23
  // MCP status
24
  statusLabel.setText("MCP: starting...", juce::dontSendNotification);
25
+ statusLabel.setFont(juce::FontOptions(12.0f));
26
  statusLabel.setJustificationType(juce::Justification::centred);
27
  addAndMakeVisible(statusLabel);
28
 
29
  // Port
30
  portLabel.setText("", juce::dontSendNotification);
31
+ portLabel.setFont(juce::FontOptions(10.0f));
32
  portLabel.setJustificationType(juce::Justification::centred);
33
+ portLabel.setColour(juce::Label::textColourId, juce::Colour(0xff888888));
34
  addAndMakeVisible(portLabel);
35
 
36
+ // Plugin name display
37
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
38
  pluginLabel.setFont(juce::FontOptions(13.0f));
39
  pluginLabel.setJustificationType(juce::Justification::centred);
40
+ pluginLabel.setColour(juce::Label::textColourId, juce::Colour(0xffaaaaaa));
41
  addAndMakeVisible(pluginLabel);
42
 
43
+ // Plugin selector button (opens popup menu)
44
+ pluginButton.onClick = [this]() { showPluginMenu(); };
45
+ pluginButton.setColour(juce::TextButton::buttonColourId, juce::Colour(0xff2d2d44));
46
+ pluginButton.setColour(juce::TextButton::textColourOffId, juce::Colours::white);
47
+ addAndMakeVisible(pluginButton);
48
+
49
+ // Scan plugins in background on first open
50
+ if (!hasScanned)
51
+ {
52
+ hasScanned = true;
53
+ // Scan runs on message thread — fast enough for installed plugins
54
+ scanPlugins();
55
+ }
56
 
57
  startTimerHz(2);
58
  }
 
64
 
65
  void PluginBridgeEditor::paint(juce::Graphics& g)
66
  {
67
+ // Dark gradient background
68
+ g.fillAll(juce::Colour(0xff12121f));
69
+ g.setColour(juce::Colour(0xff1e1e35));
70
+ g.fillRoundedRectangle(getLocalBounds().toFloat().reduced(4), 6.0f);
71
  }
72
 
73
  void PluginBridgeEditor::resized()
74
  {
75
+ auto area = getLocalBounds().reduced(14);
76
+ titleLabel.setBounds(area.removeFromTop(30));
77
+ area.removeFromTop(4);
78
+ statusLabel.setBounds(area.removeFromTop(18));
79
+ portLabel.setBounds(area.removeFromTop(16));
80
+ area.removeFromTop(10);
81
+ pluginButton.setBounds(area.removeFromTop(30).reduced(20, 0));
82
  area.removeFromTop(8);
83
+ pluginLabel.setBounds(area.removeFromTop(20));
 
 
84
  }
85
 
86
  void PluginBridgeEditor::timerCallback()
 
89
  if (processorRef.isMcpServerRunning())
90
  {
91
  statusLabel.setText("MCP: running", juce::dontSendNotification);
92
+ statusLabel.setColour(juce::Label::textColourId, juce::Colour(0xff4cef50));
93
+ portLabel.setText("127.0.0.1:" + juce::String(processorRef.getMcpServerPort()),
94
  juce::dontSendNotification);
95
  }
96
  else
97
  {
98
  statusLabel.setText("MCP: offline", juce::dontSendNotification);
99
+ statusLabel.setColour(juce::Label::textColourId, juce::Colour(0xffef5350));
100
  portLabel.setText("", juce::dontSendNotification);
101
  }
102
 
 
104
  auto& mgr = processorRef.getHostedPluginManager();
105
  if (mgr.isLoaded())
106
  {
107
+ pluginLabel.setText(mgr.getPluginName() + " | " + juce::String(mgr.getParameterCount()) + " params",
108
  juce::dontSendNotification);
109
+ pluginLabel.setColour(juce::Label::textColourId, juce::Colour(0xffffeb3b));
110
+ pluginButton.setButtonText(mgr.getPluginName());
111
  }
112
  else
113
  {
114
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
115
+ pluginLabel.setColour(juce::Label::textColourId, juce::Colour(0xff888888));
116
+ pluginButton.setButtonText("Select Plugin...");
117
  }
118
  }
119
 
120
+ void PluginBridgeEditor::scanPlugins()
121
  {
122
+ // Scan standard plugin directories
123
+ for (int i = 0; i < scanFormatManager.getNumFormats(); ++i)
124
+ {
125
+ auto* format = scanFormatManager.getFormat(i);
126
+ auto searchPaths = format->getDefaultLocationsToSearch();
127
 
128
+ juce::PluginDirectoryScanner scanner(
129
+ knownPlugins,
130
+ *format,
131
+ searchPaths,
132
+ true, // recursive
133
+ juce::File() // no dead-mans-pedal for speed
134
+ );
135
+
136
+ juce::String pluginName;
137
+ while (scanner.scanNextFile(false, pluginName))
138
  {
139
+ // Scanning...
140
+ }
141
+ }
142
+
143
+ DBG("PluginBridge: Scanned " + juce::String(knownPlugins.getNumTypes()) + " plugins");
144
+ }
145
+
146
+ void PluginBridgeEditor::showPluginMenu()
147
+ {
148
+ juce::PopupMenu menu;
149
+
150
+ // Sort by manufacturer → plugin name
151
+ auto types = knownPlugins.getTypes();
152
+
153
+ // Group by manufacturer
154
+ juce::StringArray manufacturers;
155
+ for (auto& desc : types)
156
+ {
157
+ if (!manufacturers.contains(desc.manufacturerName))
158
+ manufacturers.add(desc.manufacturerName);
159
+ }
160
+ manufacturers.sort(true);
161
+
162
+ int itemId = 1;
163
+ for (auto& mfr : manufacturers)
164
+ {
165
+ juce::PopupMenu subMenu;
166
+ for (int i = 0; i < types.size(); ++i)
167
+ {
168
+ if (types[i].manufacturerName == mfr)
169
+ {
170
+ subMenu.addItem(itemId, types[i].name + " (" + types[i].pluginFormatName + ")");
171
+ }
172
+ itemId++;
173
+ }
174
+ menu.addSubMenu(mfr, subMenu);
175
+ // Reset itemId for proper indexing
176
+ itemId = 1;
177
+ for (int i = 0; i < types.size(); ++i)
178
+ {
179
+ if (types[i].manufacturerName == mfr)
180
+ itemId++;
181
+ }
182
+ }
183
+
184
+ // Simpler approach: flat list with manufacturer prefix, proper IDs
185
+ menu.clear();
186
+ for (int i = 0; i < types.size(); ++i)
187
+ {
188
+ menu.addItem(i + 1, types[i].manufacturerName + " — " + types[i].name
189
+ + " [" + types[i].pluginFormatName + "]");
190
+ }
191
+
192
+ menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&pluginButton),
193
+ [this, types](int result)
194
+ {
195
+ if (result > 0 && result <= types.size())
196
+ {
197
+ loadPluginByIndex(result - 1);
198
+ }
199
  });
200
  }
201
+
202
+ void PluginBridgeEditor::loadPluginByIndex(int index)
203
+ {
204
+ auto types = knownPlugins.getTypes();
205
+ if (index >= 0 && index < types.size())
206
+ {
207
+ auto& desc = types[index];
208
+ juce::File pluginFile(desc.fileOrIdentifier);
209
+ processorRef.loadPluginFromFile(pluginFile);
210
+ }
211
+ }