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
|
||||
SOURCES
|
||||
bg.png
|
||||
newlogo.png
|
||||
logo.png
|
||||
metalknob.png
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# ChromaFlock
|
||||
|
||||

|
||||

|
||||
|
||||
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 <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,
|
||||
float sliderPos, float rotaryStartAngle,
|
||||
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();
|
||||
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
|
||||
juce::ColourGradient bodyGrad(juce::Colour(0xb3404040), rx, ry,
|
||||
juce::Colour(0xb31a1a1a), rx + rw, ry + rw, true);
|
||||
juce::ColourGradient bodyGrad(juce::Colour(0xa3191919), rx, ry,
|
||||
juce::Colour(0xd31f1f1f), rx + rw, ry + rw, true);
|
||||
g.setGradientFill(bodyGrad);
|
||||
g.fillEllipse(rx, ry, rw, rw);
|
||||
|
||||
// Soft inner shadow ring (bottom-right dark edge, subtle)
|
||||
g.setColour(juce::Colour(0x18000000));
|
||||
auto shadowArc = juce::Path();
|
||||
float innerR = radius - 2.0f;
|
||||
shadowArc.addCentredArc(centreX, centreY, innerR, innerR, 0.0f,
|
||||
0.5f, 2.7f, true);
|
||||
g.strokePath(shadowArc, juce::PathStrokeType(1.5f));
|
||||
// g.setColour(juce::Colour(0x18000000));
|
||||
// auto shadowArc = juce::Path();
|
||||
// float innerR = radius - 2.0f;
|
||||
// shadowArc.addCentredArc(centreX, centreY, innerR, innerR, 0.0f, 0.5f, 2.7f, true);
|
||||
// g.strokePath(shadowArc, juce::PathStrokeType(1.5f));
|
||||
|
||||
// Outer rim
|
||||
g.setColour(juce::Colour(0xff555555));
|
||||
g.drawEllipse(rx, ry, rw, rw, 1.5f);
|
||||
// g.setColour(juce::Colour(0xff555555));
|
||||
// g.drawEllipse(rx, ry, rw, rw, 1.5f);
|
||||
|
||||
// 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);
|
||||
|
|
@ -931,7 +946,7 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
|||
// Load logo
|
||||
if (!logoLoaded) {
|
||||
auto img = juce::ImageFileFormat::loadFrom(
|
||||
BinaryData::newlogo_png, BinaryData::newlogo_pngSize);
|
||||
BinaryData::logo_png, BinaryData::logo_pngSize);
|
||||
if (img.isValid()) {
|
||||
juce::Image::BitmapData bd(img, juce::Image::BitmapData::readOnly);
|
||||
int minX = bd.width, maxX = 0, minY = bd.height, maxY = 0;
|
||||
|
|
@ -954,15 +969,15 @@ void MainContentComponent::paint(juce::Graphics& g) {
|
|||
logoLoaded = true;
|
||||
}
|
||||
if (logoImage.isValid()) {
|
||||
int logoW = 440;
|
||||
int logoW = 352;
|
||||
int logoH = logoImage.getWidth() > 0
|
||||
? static_cast<int>(logoW * static_cast<double>(logoImage.getHeight()) / logoImage.getWidth())
|
||||
: logoW;
|
||||
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);
|
||||
juce::Graphics::ScopedSaveState saved(g);
|
||||
g.setOpacity(0.8f);
|
||||
g.setOpacity(1.0f);
|
||||
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);
|
||||
};
|
||||
|
||||
drawSection(10, 128, 498, 200);
|
||||
drawSection(518, 128, 624, 200);
|
||||
drawSection(1152, 128, 498, 200);
|
||||
drawSection(10, 338, 563, 160);
|
||||
drawSection(583, 338, 502, 160);
|
||||
drawSection(1095, 338, 555, 160);
|
||||
drawSection(10, 956, 1640, 136);
|
||||
drawSection(10, 80, 498, 200);
|
||||
drawSection(518, 80, 624, 200);
|
||||
drawSection(1152, 80, 498, 200);
|
||||
drawSection(10, 290, 563, 160);
|
||||
drawSection(583, 290, 502, 160);
|
||||
drawSection(1095, 290, 555, 160);
|
||||
drawSection(10, 884, 1640, 136);
|
||||
|
||||
// FX sub-sections
|
||||
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);
|
||||
};
|
||||
|
||||
drawSubSection(10, 508, 510, 140, "DISTORTION", 6);
|
||||
drawSubSection(528, 508, 468, 140, "COMPRESSION", 6);
|
||||
drawSubSection(1004, 508, 268, 140, "PANNING", 6);
|
||||
drawSubSection(1280, 508, 370, 140, "LIMITER", 6);
|
||||
drawSubSection(10, 460, 510, 115, "DISTORTION", 6);
|
||||
drawSubSection(528, 460, 468, 115, "COMPRESSION", 6);
|
||||
drawSubSection(1004, 460, 268, 115, "PANNING", 6);
|
||||
drawSubSection(1280, 460, 370, 115, "LIMITER", 6);
|
||||
|
||||
// LFO sub-sections
|
||||
drawSubSection(10, 658, 540, 150, "LFO 1", 4);
|
||||
drawSubSection(560, 658, 530, 150, "LFO 2", 4);
|
||||
drawSubSection(10, 586, 540, 150, "LFO 1", 4);
|
||||
drawSubSection(560, 586, 530, 150, "LFO 2", 4);
|
||||
|
||||
// FX2 sub-sections
|
||||
drawSubSection(1015, 658, 375, 150, "DELAY", 4);
|
||||
drawSubSection(1395, 658, 255, 150, "REVERB", 4);
|
||||
drawSubSection(1015, 586, 375, 150, "DELAY", 4);
|
||||
drawSubSection(1395, 586, 255, 150, "REVERB", 4);
|
||||
}
|
||||
|
||||
void MainContentComponent::resized() {
|
||||
auto sectionY = 132;
|
||||
auto sectionY = 84;
|
||||
auto knobSize = 112;
|
||||
auto knobSpacing = 10;
|
||||
auto labelH = 18;
|
||||
|
|
@ -1055,33 +1070,33 @@ void MainContentComponent::resized() {
|
|||
filterEnvAmtKnob.setBounds(1162 + (knobSize + knobSpacing) * 2, 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 sx = 10 + (563 - rowW) / 2;
|
||||
int knobYA = 352 + labelH + 6;
|
||||
int knobYA = 304 + labelH + 6;
|
||||
envAttackKnob.setBounds(sx, knobYA, knobSize, knobSize);
|
||||
envDecayKnob.setBounds(sx + (knobSize + knobSpacing), knobYA, knobSize, knobSize);
|
||||
envSustainKnob.setBounds(sx + (knobSize + knobSpacing) * 2, 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 sx = 583 + (502 - rowW) / 2;
|
||||
int knobYFE = 352 + labelH + 6;
|
||||
int knobYFE = 304 + labelH + 6;
|
||||
fEnvAttackKnob.setBounds(sx, knobYFE, knobSize, knobSize);
|
||||
fEnvDecayKnob.setBounds(sx + (knobSize + knobSpacing), knobYFE, knobSize, knobSize);
|
||||
fEnvSustainKnob.setBounds(sx + (knobSize + knobSpacing) * 2, 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 sx = 1095 + (555 - rowW) / 2;
|
||||
int knobYM = 352 + labelH + 6;
|
||||
int knobYM = 304 + labelH + 6;
|
||||
panKnob.setBounds(sx, knobYM, knobSize, knobSize);
|
||||
driveKnob.setBounds(sx + (knobSize + knobSpacing), knobYM, knobSize, knobSize);
|
||||
masterKnob.setBounds(sx + (knobSize + knobSpacing) * 2, knobYM, knobSize, knobSize);
|
||||
|
|
@ -1089,7 +1104,7 @@ void MainContentComponent::resized() {
|
|||
}
|
||||
|
||||
// --- FX SECTION ---
|
||||
int fxY = 480;
|
||||
int fxY = 432;
|
||||
int fxKnobSize = 80;
|
||||
int fxLabelH = 16;
|
||||
int fxKnobY = fxY + 54; // sub-section y(476) + titlePad(6) + titleH(14) + bottomPad(6) + 4
|
||||
|
|
@ -1138,9 +1153,9 @@ void MainContentComponent::resized() {
|
|||
}
|
||||
|
||||
// --- LFO SECTION ---
|
||||
int lfoY = 638;
|
||||
int lfoY = 566;
|
||||
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);
|
||||
fx2Label.setBounds(1015, lfoY, 635, fxLabelH);
|
||||
|
|
@ -1180,7 +1195,7 @@ void MainContentComponent::resized() {
|
|||
}
|
||||
|
||||
// --- PRESET + SCALE (vertically centered within top section, y: 0..128) ---
|
||||
int headerH = 128;
|
||||
int headerH = 80;
|
||||
int btnH = 28, btnGap = 8;
|
||||
int presetGroupH = btnH * 2 + btnGap;
|
||||
int presetStartY = (headerH - presetGroupH) / 2;
|
||||
|
|
@ -1209,14 +1224,14 @@ void MainContentComponent::resized() {
|
|||
uiScaleBox.setBounds(1560, comboY2, 80, comboH2);
|
||||
|
||||
// Visualizer area
|
||||
int vizY = 818;
|
||||
int vizY = 746;
|
||||
int vizH = 128;
|
||||
vuMeter.setBounds(10, vizY, 40, vizH);
|
||||
waveformDisplay.setBounds(60, vizY, 790, vizH);
|
||||
spectrumAnalyzer.setBounds(860, vizY, 790, vizH);
|
||||
|
||||
// Piano roll
|
||||
pianoRoll.setBounds(10, 956, 1640, 136);
|
||||
pianoRoll.setBounds(10, 884, 1640, 136);
|
||||
}
|
||||
|
||||
// ===== PianoRollComponent =====
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@
|
|||
|
||||
class KnobLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
public:
|
||||
KnobLookAndFeel();
|
||||
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height,
|
||||
float sliderPos, float rotaryStartAngle,
|
||||
float rotaryEndAngle, juce::Slider& slider) override;
|
||||
private:
|
||||
juce::Image knobOverlay;
|
||||
};
|
||||
|
||||
class ComboBoxLookAndFeel : public juce::LookAndFeel_V4 {
|
||||
|
|
@ -249,7 +252,7 @@ private:
|
|||
MainContentComponent content;
|
||||
float currentScale = 1.0f;
|
||||
static constexpr int baseWidth = 1660;
|
||||
static constexpr int baseHeight = 1100;
|
||||
static constexpr int baseHeight = 1028;
|
||||
|
||||
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