mirror of
https://codeberg.org/armin/chromaflock.git
synced 2026-09-01 04:10:47 +02:00
Tighten layout: reduce gaps, shrink header, reposition logo, rename newlogo→logo
This commit is contained in:
parent
37f3881355
commit
4acca46260
6 changed files with 64 additions and 45 deletions
|
|
@ -23,7 +23,8 @@ juce_add_binary_data(ChromaFlockBinaryData
|
||||||
NAMESPACE BinaryData
|
NAMESPACE BinaryData
|
||||||
SOURCES
|
SOURCES
|
||||||
bg.png
|
bg.png
|
||||||
newlogo.png
|
logo.png
|
||||||
|
metalknob.png
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# ChromaFlock
|
# ChromaFlock
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
A subtractive synthesizer plugin built with [JUCE](https://juce.com). macOS (VST3, AU, Standalone) and Linux (VST3, Standalone).
|
A subtractive synthesizer plugin built with [JUCE](https://juce.com). macOS (VST3, AU, Standalone) and Linux (VST3, Standalone).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
#include "PluginEditor.h"
|
#include "PluginEditor.h"
|
||||||
#include <BinaryData.h>
|
#include <BinaryData.h>
|
||||||
|
|
||||||
|
KnobLookAndFeel::KnobLookAndFeel() {
|
||||||
|
knobOverlay = juce::ImageCache::getFromMemory(BinaryData::metalknob_png,
|
||||||
|
BinaryData::metalknob_pngSize);
|
||||||
|
}
|
||||||
|
|
||||||
void KnobLookAndFeel::drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
void KnobLookAndFeel::drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||||
float sliderPos, float rotaryStartAngle,
|
float sliderPos, float rotaryStartAngle,
|
||||||
float rotaryEndAngle, juce::Slider& slider) {
|
float rotaryEndAngle, juce::Slider& slider) {
|
||||||
|
|
@ -25,23 +30,33 @@ void KnobLookAndFeel::drawRotarySlider(juce::Graphics& g, int x, int y, int widt
|
||||||
auto bevelPath = juce::Path();
|
auto bevelPath = juce::Path();
|
||||||
bevelPath.addEllipse(rx, ry, rw, rw);
|
bevelPath.addEllipse(rx, ry, rw, rw);
|
||||||
|
|
||||||
|
// Metal knob overlay (clipped to circle, behind gradient)
|
||||||
|
if (knobOverlay.isValid()) {
|
||||||
|
juce::Graphics::ScopedSaveState state(g);
|
||||||
|
juce::Path circlePath;
|
||||||
|
circlePath.addEllipse(rx, ry, rw, rw);
|
||||||
|
g.reduceClipRegion(circlePath);
|
||||||
|
g.setOpacity(0.55f);
|
||||||
|
g.drawImageWithin(knobOverlay, (int)rx, (int)ry, (int)rw, (int)rw, juce::RectanglePlacement::stretchToFit);
|
||||||
|
g.setOpacity(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
// Knob body gradient — light top-left to dark bottom-right for 3D bulge
|
// Knob body gradient — light top-left to dark bottom-right for 3D bulge
|
||||||
juce::ColourGradient bodyGrad(juce::Colour(0xb3404040), rx, ry,
|
juce::ColourGradient bodyGrad(juce::Colour(0xa3191919), rx, ry,
|
||||||
juce::Colour(0xb31a1a1a), rx + rw, ry + rw, true);
|
juce::Colour(0xd31f1f1f), rx + rw, ry + rw, true);
|
||||||
g.setGradientFill(bodyGrad);
|
g.setGradientFill(bodyGrad);
|
||||||
g.fillEllipse(rx, ry, rw, rw);
|
g.fillEllipse(rx, ry, rw, rw);
|
||||||
|
|
||||||
// Soft inner shadow ring (bottom-right dark edge, subtle)
|
// Soft inner shadow ring (bottom-right dark edge, subtle)
|
||||||
g.setColour(juce::Colour(0x18000000));
|
// g.setColour(juce::Colour(0x18000000));
|
||||||
auto shadowArc = juce::Path();
|
// auto shadowArc = juce::Path();
|
||||||
float innerR = radius - 2.0f;
|
// float innerR = radius - 2.0f;
|
||||||
shadowArc.addCentredArc(centreX, centreY, innerR, innerR, 0.0f,
|
// shadowArc.addCentredArc(centreX, centreY, innerR, innerR, 0.0f, 0.5f, 2.7f, true);
|
||||||
0.5f, 2.7f, true);
|
// g.strokePath(shadowArc, juce::PathStrokeType(1.5f));
|
||||||
g.strokePath(shadowArc, juce::PathStrokeType(1.5f));
|
|
||||||
|
|
||||||
// Outer rim
|
// Outer rim
|
||||||
g.setColour(juce::Colour(0xff555555));
|
// g.setColour(juce::Colour(0xff555555));
|
||||||
g.drawEllipse(rx, ry, rw, rw, 1.5f);
|
// g.drawEllipse(rx, ry, rw, rw, 1.5f);
|
||||||
|
|
||||||
// Pointer line with glow — green (left) → yellow (mid) → red (right)
|
// Pointer line with glow — green (left) → yellow (mid) → red (right)
|
||||||
auto indicatorColour = juce::Colour::fromHSV(0.33f * (1.0f - sliderPos), 0.85f, 0.9f, 1.0f);
|
auto indicatorColour = juce::Colour::fromHSV(0.33f * (1.0f - sliderPos), 0.85f, 0.9f, 1.0f);
|
||||||
|
|
@ -931,7 +946,7 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
||||||
// Load logo
|
// Load logo
|
||||||
if (!logoLoaded) {
|
if (!logoLoaded) {
|
||||||
auto img = juce::ImageFileFormat::loadFrom(
|
auto img = juce::ImageFileFormat::loadFrom(
|
||||||
BinaryData::newlogo_png, BinaryData::newlogo_pngSize);
|
BinaryData::logo_png, BinaryData::logo_pngSize);
|
||||||
if (img.isValid()) {
|
if (img.isValid()) {
|
||||||
juce::Image::BitmapData bd(img, juce::Image::BitmapData::readOnly);
|
juce::Image::BitmapData bd(img, juce::Image::BitmapData::readOnly);
|
||||||
int minX = bd.width, maxX = 0, minY = bd.height, maxY = 0;
|
int minX = bd.width, maxX = 0, minY = bd.height, maxY = 0;
|
||||||
|
|
@ -954,15 +969,15 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
||||||
logoLoaded = true;
|
logoLoaded = true;
|
||||||
}
|
}
|
||||||
if (logoImage.isValid()) {
|
if (logoImage.isValid()) {
|
||||||
int logoW = 440;
|
int logoW = 352;
|
||||||
int logoH = logoImage.getWidth() > 0
|
int logoH = logoImage.getWidth() > 0
|
||||||
? static_cast<int>(logoW * static_cast<double>(logoImage.getHeight()) / logoImage.getWidth())
|
? static_cast<int>(logoW * static_cast<double>(logoImage.getHeight()) / logoImage.getWidth())
|
||||||
: logoW;
|
: logoW;
|
||||||
int logoX = (getWidth() - logoW) / 2;
|
int logoX = (getWidth() - logoW) / 2;
|
||||||
int logoY = (124 - logoH) / 2 + 32;
|
int logoY = (80 - logoH) / 2 - 2;
|
||||||
auto logoArea = juce::Rectangle<int>(logoX, logoY, logoW, logoH);
|
auto logoArea = juce::Rectangle<int>(logoX, logoY, logoW, logoH);
|
||||||
juce::Graphics::ScopedSaveState saved(g);
|
juce::Graphics::ScopedSaveState saved(g);
|
||||||
g.setOpacity(0.8f);
|
g.setOpacity(1.0f);
|
||||||
g.drawImage(logoImage, logoArea.toFloat(), juce::RectanglePlacement::centred);
|
g.drawImage(logoImage, logoArea.toFloat(), juce::RectanglePlacement::centred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -983,13 +998,13 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
||||||
g.drawRoundedRectangle(rect, 9.0f, 1.0f);
|
g.drawRoundedRectangle(rect, 9.0f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
drawSection(10, 128, 498, 200);
|
drawSection(10, 80, 498, 200);
|
||||||
drawSection(518, 128, 624, 200);
|
drawSection(518, 80, 624, 200);
|
||||||
drawSection(1152, 128, 498, 200);
|
drawSection(1152, 80, 498, 200);
|
||||||
drawSection(10, 338, 563, 160);
|
drawSection(10, 290, 563, 160);
|
||||||
drawSection(583, 338, 502, 160);
|
drawSection(583, 290, 502, 160);
|
||||||
drawSection(1095, 338, 555, 160);
|
drawSection(1095, 290, 555, 160);
|
||||||
drawSection(10, 956, 1640, 136);
|
drawSection(10, 884, 1640, 136);
|
||||||
|
|
||||||
// FX sub-sections
|
// FX sub-sections
|
||||||
auto drawSubSection = [&](int x, int y, int w, int h, const juce::String& title, int titlePadY = 2) {
|
auto drawSubSection = [&](int x, int y, int w, int h, const juce::String& title, int titlePadY = 2) {
|
||||||
|
|
@ -1009,22 +1024,22 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
||||||
g.drawText(title, x + 6, y + titlePadY, w - 12, 14, juce::Justification::centred);
|
g.drawText(title, x + 6, y + titlePadY, w - 12, 14, juce::Justification::centred);
|
||||||
};
|
};
|
||||||
|
|
||||||
drawSubSection(10, 508, 510, 140, "DISTORTION", 6);
|
drawSubSection(10, 460, 510, 115, "DISTORTION", 6);
|
||||||
drawSubSection(528, 508, 468, 140, "COMPRESSION", 6);
|
drawSubSection(528, 460, 468, 115, "COMPRESSION", 6);
|
||||||
drawSubSection(1004, 508, 268, 140, "PANNING", 6);
|
drawSubSection(1004, 460, 268, 115, "PANNING", 6);
|
||||||
drawSubSection(1280, 508, 370, 140, "LIMITER", 6);
|
drawSubSection(1280, 460, 370, 115, "LIMITER", 6);
|
||||||
|
|
||||||
// LFO sub-sections
|
// LFO sub-sections
|
||||||
drawSubSection(10, 658, 540, 150, "LFO 1", 4);
|
drawSubSection(10, 586, 540, 150, "LFO 1", 4);
|
||||||
drawSubSection(560, 658, 530, 150, "LFO 2", 4);
|
drawSubSection(560, 586, 530, 150, "LFO 2", 4);
|
||||||
|
|
||||||
// FX2 sub-sections
|
// FX2 sub-sections
|
||||||
drawSubSection(1015, 658, 375, 150, "DELAY", 4);
|
drawSubSection(1015, 586, 375, 150, "DELAY", 4);
|
||||||
drawSubSection(1395, 658, 255, 150, "REVERB", 4);
|
drawSubSection(1395, 586, 255, 150, "REVERB", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainContentComponent::resized() {
|
void MainContentComponent::resized() {
|
||||||
auto sectionY = 132;
|
auto sectionY = 84;
|
||||||
auto knobSize = 112;
|
auto knobSize = 112;
|
||||||
auto knobSpacing = 10;
|
auto knobSpacing = 10;
|
||||||
auto labelH = 18;
|
auto labelH = 18;
|
||||||
|
|
@ -1055,33 +1070,33 @@ void MainContentComponent::resized() {
|
||||||
filterEnvAmtKnob.setBounds(1162 + (knobSize + knobSpacing) * 2, knobYF, knobSize, knobSize);
|
filterEnvAmtKnob.setBounds(1162 + (knobSize + knobSpacing) * 2, knobYF, knobSize, knobSize);
|
||||||
keyTrackKnob.setBounds(1162 + (knobSize + knobSpacing) * 3, knobYF, knobSize, knobSize);
|
keyTrackKnob.setBounds(1162 + (knobSize + knobSpacing) * 3, knobYF, knobSize, knobSize);
|
||||||
|
|
||||||
envLabel.setBounds(10, 342, 563, labelH);
|
envLabel.setBounds(10, 294, 563, labelH);
|
||||||
{
|
{
|
||||||
int rowW = 4 * knobSize + 3 * knobSpacing;
|
int rowW = 4 * knobSize + 3 * knobSpacing;
|
||||||
int sx = 10 + (563 - rowW) / 2;
|
int sx = 10 + (563 - rowW) / 2;
|
||||||
int knobYA = 352 + labelH + 6;
|
int knobYA = 304 + labelH + 6;
|
||||||
envAttackKnob.setBounds(sx, knobYA, knobSize, knobSize);
|
envAttackKnob.setBounds(sx, knobYA, knobSize, knobSize);
|
||||||
envDecayKnob.setBounds(sx + (knobSize + knobSpacing), knobYA, knobSize, knobSize);
|
envDecayKnob.setBounds(sx + (knobSize + knobSpacing), knobYA, knobSize, knobSize);
|
||||||
envSustainKnob.setBounds(sx + (knobSize + knobSpacing) * 2, knobYA, knobSize, knobSize);
|
envSustainKnob.setBounds(sx + (knobSize + knobSpacing) * 2, knobYA, knobSize, knobSize);
|
||||||
envReleaseKnob.setBounds(sx + (knobSize + knobSpacing) * 3, knobYA, knobSize, knobSize);
|
envReleaseKnob.setBounds(sx + (knobSize + knobSpacing) * 3, knobYA, knobSize, knobSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
fEnvLabel.setBounds(583, 342, 502, labelH);
|
fEnvLabel.setBounds(583, 294, 502, labelH);
|
||||||
{
|
{
|
||||||
int rowW = 4 * knobSize + 3 * knobSpacing;
|
int rowW = 4 * knobSize + 3 * knobSpacing;
|
||||||
int sx = 583 + (502 - rowW) / 2;
|
int sx = 583 + (502 - rowW) / 2;
|
||||||
int knobYFE = 352 + labelH + 6;
|
int knobYFE = 304 + labelH + 6;
|
||||||
fEnvAttackKnob.setBounds(sx, knobYFE, knobSize, knobSize);
|
fEnvAttackKnob.setBounds(sx, knobYFE, knobSize, knobSize);
|
||||||
fEnvDecayKnob.setBounds(sx + (knobSize + knobSpacing), knobYFE, knobSize, knobSize);
|
fEnvDecayKnob.setBounds(sx + (knobSize + knobSpacing), knobYFE, knobSize, knobSize);
|
||||||
fEnvSustainKnob.setBounds(sx + (knobSize + knobSpacing) * 2, knobYFE, knobSize, knobSize);
|
fEnvSustainKnob.setBounds(sx + (knobSize + knobSpacing) * 2, knobYFE, knobSize, knobSize);
|
||||||
fEnvReleaseKnob.setBounds(sx + (knobSize + knobSpacing) * 3, knobYFE, knobSize, knobSize);
|
fEnvReleaseKnob.setBounds(sx + (knobSize + knobSpacing) * 3, knobYFE, knobSize, knobSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
globalLabel.setBounds(1095, 342, 555, labelH);
|
globalLabel.setBounds(1095, 294, 555, labelH);
|
||||||
{
|
{
|
||||||
int rowW = 4 * knobSize + 3 * knobSpacing;
|
int rowW = 4 * knobSize + 3 * knobSpacing;
|
||||||
int sx = 1095 + (555 - rowW) / 2;
|
int sx = 1095 + (555 - rowW) / 2;
|
||||||
int knobYM = 352 + labelH + 6;
|
int knobYM = 304 + labelH + 6;
|
||||||
panKnob.setBounds(sx, knobYM, knobSize, knobSize);
|
panKnob.setBounds(sx, knobYM, knobSize, knobSize);
|
||||||
driveKnob.setBounds(sx + (knobSize + knobSpacing), knobYM, knobSize, knobSize);
|
driveKnob.setBounds(sx + (knobSize + knobSpacing), knobYM, knobSize, knobSize);
|
||||||
masterKnob.setBounds(sx + (knobSize + knobSpacing) * 2, knobYM, knobSize, knobSize);
|
masterKnob.setBounds(sx + (knobSize + knobSpacing) * 2, knobYM, knobSize, knobSize);
|
||||||
|
|
@ -1089,7 +1104,7 @@ void MainContentComponent::resized() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FX SECTION ---
|
// --- FX SECTION ---
|
||||||
int fxY = 480;
|
int fxY = 432;
|
||||||
int fxKnobSize = 80;
|
int fxKnobSize = 80;
|
||||||
int fxLabelH = 16;
|
int fxLabelH = 16;
|
||||||
int fxKnobY = fxY + 54; // sub-section y(476) + titlePad(6) + titleH(14) + bottomPad(6) + 4
|
int fxKnobY = fxY + 54; // sub-section y(476) + titlePad(6) + titleH(14) + bottomPad(6) + 4
|
||||||
|
|
@ -1138,9 +1153,9 @@ void MainContentComponent::resized() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- LFO SECTION ---
|
// --- LFO SECTION ---
|
||||||
int lfoY = 638;
|
int lfoY = 566;
|
||||||
int lfoKnobSize = 80;
|
int lfoKnobSize = 80;
|
||||||
int lfoKnobY = 658 + 4 + 14 + 6; // subSectionY + titlePad + titleH + bottomPad
|
int lfoKnobY = 586 + 4 + 14 + 6; // subSectionY + titlePad + titleH + bottomPad
|
||||||
|
|
||||||
lfoLabel.setBounds(10, lfoY, 1080, fxLabelH);
|
lfoLabel.setBounds(10, lfoY, 1080, fxLabelH);
|
||||||
fx2Label.setBounds(1015, lfoY, 635, fxLabelH);
|
fx2Label.setBounds(1015, lfoY, 635, fxLabelH);
|
||||||
|
|
@ -1180,7 +1195,7 @@ void MainContentComponent::resized() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- PRESET + SCALE (vertically centered within top section, y: 0..128) ---
|
// --- PRESET + SCALE (vertically centered within top section, y: 0..128) ---
|
||||||
int headerH = 128;
|
int headerH = 80;
|
||||||
int btnH = 28, btnGap = 8;
|
int btnH = 28, btnGap = 8;
|
||||||
int presetGroupH = btnH * 2 + btnGap;
|
int presetGroupH = btnH * 2 + btnGap;
|
||||||
int presetStartY = (headerH - presetGroupH) / 2;
|
int presetStartY = (headerH - presetGroupH) / 2;
|
||||||
|
|
@ -1209,14 +1224,14 @@ void MainContentComponent::resized() {
|
||||||
uiScaleBox.setBounds(1560, comboY2, 80, comboH2);
|
uiScaleBox.setBounds(1560, comboY2, 80, comboH2);
|
||||||
|
|
||||||
// Visualizer area
|
// Visualizer area
|
||||||
int vizY = 818;
|
int vizY = 746;
|
||||||
int vizH = 128;
|
int vizH = 128;
|
||||||
vuMeter.setBounds(10, vizY, 40, vizH);
|
vuMeter.setBounds(10, vizY, 40, vizH);
|
||||||
waveformDisplay.setBounds(60, vizY, 790, vizH);
|
waveformDisplay.setBounds(60, vizY, 790, vizH);
|
||||||
spectrumAnalyzer.setBounds(860, vizY, 790, vizH);
|
spectrumAnalyzer.setBounds(860, vizY, 790, vizH);
|
||||||
|
|
||||||
// Piano roll
|
// Piano roll
|
||||||
pianoRoll.setBounds(10, 956, 1640, 136);
|
pianoRoll.setBounds(10, 884, 1640, 136);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== PianoRollComponent =====
|
// ===== PianoRollComponent =====
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,12 @@
|
||||||
|
|
||||||
class KnobLookAndFeel : public juce::LookAndFeel_V4 {
|
class KnobLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
|
KnobLookAndFeel();
|
||||||
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||||
float sliderPos, float rotaryStartAngle,
|
float sliderPos, float rotaryStartAngle,
|
||||||
float rotaryEndAngle, juce::Slider& slider) override;
|
float rotaryEndAngle, juce::Slider& slider) override;
|
||||||
|
private:
|
||||||
|
juce::Image knobOverlay;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ComboBoxLookAndFeel : public juce::LookAndFeel_V4 {
|
class ComboBoxLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
|
|
@ -249,7 +252,7 @@ private:
|
||||||
MainContentComponent content;
|
MainContentComponent content;
|
||||||
float currentScale = 1.0f;
|
float currentScale = 1.0f;
|
||||||
static constexpr int baseWidth = 1660;
|
static constexpr int baseWidth = 1660;
|
||||||
static constexpr int baseHeight = 1100;
|
static constexpr int baseHeight = 1028;
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChromaFlockEditor)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChromaFlockEditor)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
BIN
logo.png
BIN
logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 784 KiB |
BIN
newlogo.png
BIN
newlogo.png
Binary file not shown.
|
Before Width: | Height: | Size: 178 KiB |
Loading…
Add table
Add a link
Reference in a new issue