#include "PluginEditor.h" #include "BuildInfo.h" #include RackEditor::RackEditor (RMX19AudioProcessor& p) : AudioProcessorEditor (p) , proc (p) , display (p) { face = juce::Colour (0xff16130f); up = new NavButton (-1, "^", "UP"); down = new NavButton (1, "v", "DOWN"); left = new NavButton (-1, "<", "LEFT"); right = new NavButton (1, ">", "RIGHT"); enterB = new OkButton ("ENTER", true); backB = new OkButton ("BACK", false); for (auto* b : { (juce::Button*) up, (juce::Button*) down, (juce::Button*) left, (juce::Button*) right, (juce::Button*) enterB, (juce::Button*) backB }) addAndMakeVisible (b); up->onClick = [this] { display.navUp(); }; down->onClick = [this] { display.navDown(); }; left->onClick = [this] { display.navLeft(); }; right->onClick = [this] { display.navRight(); }; enterB->onClick = [this] { display.navEnter(); }; backB->onClick = [this] { display.navExit(); }; addAndMakeVisible (display); setWantsKeyboardFocus (true); setSize (656, 248); startTimerHz (18); } RackEditor::~RackEditor() { stopTimer(); } void RackEditor::paint (juce::Graphics& g) { const auto b = getLocalBounds(); // --- metal rack face --- g.setColour (face); g.fillRect (b); // brushed texture g.setColour (juce::Colour::fromRGBA (255, 255, 255, 7)); for (int x = 0; x < b.getWidth(); x += 3) g.fillRect (x, 0, 1, b.getHeight()); // rack rails (top/bottom) g.setColour (juce::Colour (0xff221e1a)); g.fillRect (0, 0, b.getWidth(), 4); g.fillRect (0, b.getHeight() - 4, b.getWidth(), 4); g.setColour (juce::Colour (0xff5a5347)); g.fillRect (0, 4, b.getWidth(), 1); g.fillRect (0, b.getHeight() - 5, b.getWidth(), 1); // screw holes const auto screw = [&] (int x, int y) { g.setColour (juce::Colour (0xff2a2620)); g.fillEllipse (x - 4, y - 4, 8, 8); g.setColour (juce::Colour (0xff8a7f6e)); g.drawEllipse (x - 4.5f, y - 4.5f, 9, 9, 1.0f); g.drawLine (x - 3, y, x + 3, y, 1.0f); }; screw (8, 8); screw (b.getWidth() - 9, 8); screw (8, b.getHeight() - 9); screw (b.getWidth() - 9, b.getHeight() - 9); // brand plate g.setColour (juce::Colour (0xff614f3a)); g.fillRect (12, 6, 150, 12); g.setColour (juce::Colour (0xffc9a86f)); g.setFont (juce::FontOptions ("Arial", 10.0f, juce::Font::bold)); g.drawFittedText ("RMX-19 RACK SYNTH", 12, 6, 150, 12, juce::Justification::centred, 1); // power LED (right of LCD status) const int ledX = getWidth() - 20, ledY = 18; g.setColour (juce::Colour (0xff3a0d0d)); g.fillEllipse (ledX - 3, ledY - 3, 8, 8); g.setColour (juce::Colour::fromFloatRGBA (0.95f, 0.25f + 0.1f * powerPulse, 0.1f, 1.0f)); g.fillEllipse (ledX - 2, ledY - 2, 6, 6); g.setColour (juce::Colour (0xff8a7f6e)); g.setFont (juce::FontOptions ("Arial", 8.0f, juce::Font::plain)); g.drawFittedText ("PWR", ledX - 26, ledY - 5, 20, 10, juce::Justification::centredRight, 1); // rear engraving text g.setColour (juce::Colour (0xff6e6657)); g.setFont (juce::FontOptions ("Courier New", 8.0f, juce::Font::plain)); const juce::String ser = "S/N 0001-1943 MIDI OUT (R) MIDI IN (R) AUDIO 24BIT/96K"; g.drawFittedText (ser, 12, getHeight() - 16, getWidth() - 24, 11, juce::Justification::centred, 1); } void RackEditor::resized() { const auto b = getLocalBounds(); // LCD recessed module const juce::Rectangle lcdArea (14, 24, 356, 168); display.setBounds (lcdArea); // nav diamond + enter/back to the right of the LCD const juce::Rectangle navArea (lcdArea.getRight() + 16, 26, b.getWidth() - lcdArea.getRight() - 30, 164); const int bw = 58, bh = 20; const int cx = navArea.getX() + (navArea.getWidth() - bw) / 2; const int rowY = navArea.getY(); up->setBounds (cx, rowY, bw, bh); left->setBounds (navArea.getX() + 2, rowY + bh + 6, bw, bh); down->setBounds (cx, rowY + bh + 6, bw, bh); right->setBounds (navArea.getRight() - bw - 2, rowY + bh + 6, bw, bh); enterB->setBounds (navArea.getX() + 2, rowY + 2 * (bh + 6) + 4, bw, bh); backB->setBounds (navArea.getRight() - bw - 2, rowY + 2 * (bh + 6) + 4, bw, bh); } void RackEditor::timerCallback() { powerPulse = 0.5f + 0.5f * std::sin (juce::Time::getMillisecondCounter() * 0.0022f); repaint (getLocalBounds()); } bool RackEditor::keyPressed (const juce::KeyPress& k) { if (display.keyTrap (k)) { repaint(); return true; } return false; } // ---- buttons ------------------------------------------------------------- void RackEditor::NavButton::paintButton (juce::Graphics& g, bool, bool down) { const auto b = getLocalBounds(); const juce::Colour base = juce::Colour (0xff221d18); const juce::Colour edge = juce::Colour (0xff6b5f4e); const juce::Colour text = juce::Colour (0xfffff3d8); if (down) { g.setColour (edge.darker (0.4f)); g.fillRect (b); g.setColour (base.brighter (0.1f)); g.fillRect (b.reduced (2, 2)); } else { g.setColour (base); g.fillRect (b); g.setColour (edge); g.drawRect (b, 1); } // glyph g.setColour (text); g.setFont (juce::FontOptions ("Arial", 12.0f, juce::Font::bold)); g.drawFittedText (mark, b.withTrimmedBottom (9), juce::Justification::centred, 1); g.setFont (juce::FontOptions ("Arial", 7.0f, juce::Font::plain)); g.drawFittedText (getName(), b.withTrimmedTop (b.getHeight() - 8), juce::Justification::centred, 1); } void RackEditor::OkButton::paintButton (juce::Graphics& g, bool over, bool down) { const auto b = getLocalBounds(); const juce::Colour base = enter ? juce::Colour (0xff263a28) : juce::Colour (0xff332a20); const juce::Colour edge = juce::Colour (0xff8a9b6a); if (down) { g.setColour (edge.darker (0.35f)); g.fillRect (b); g.setColour (base.brighter (0.12f)); g.fillRect (b.reduced (2, 2)); } else { g.setColour (base); g.fillRect (b); g.setColour (edge); g.drawRect (b, 1); } g.setColour (over ? juce::Colour (0xffffd977) : juce::Colour (0xffd8d2c6)); g.setFont (juce::FontOptions ("Arial", 9.0f, juce::Font::bold)); g.drawFittedText (getName(), b, juce::Justification::centred, 1); }