justasample/Source/CustomLookAndFeel.h

227 lines
9 KiB
C++

/*
==============================================================================
LookAndFeel.h
Created: 19 Sep 2023 4:48:33pm
Author: binya
==============================================================================
*/
#pragma once
#include <JuceHeader.h>
/** This struct contains the plugin's colors. */
struct Colors
{
/** Background for the editor */
juce::Colour background;
/** Foreground for the controls */
juce::Colour foreground;
/** Dark color */
juce::Colour dark;
/** Highlight color for controls */
juce::Colour highlight;
/** Loop color */
juce::Colour loop;
/** Lighter slate for some buttons */
juce::Colour slate;
/** Darker slate for waveform and some buttons */
juce::Colour darkerSlate;
/** Background neutral color (outside editor) */
juce::Colour light;
/** Prompt background color */
juce::Colour prompt;
static constexpr int backgroundColorId{ -1 };
static constexpr int painterColorId{ -2 };
};
static const Colors defaultTheme
{
.background = juce::Colour{0xFFFDF6C3},
.foreground = juce::Colour{0xFFEAFFF7},
.dark = juce::Colour{0xFF171614},
.highlight = juce::Colour{0xFFFF595E},
.loop = juce::Colour{0xFFFFDA22},
.slate = juce::Colour{0xFF6E7894},
.darkerSlate = juce::Colour{0xFF403D37},
.light = juce::Colour{0xFFFFFFFF},
.prompt = juce::Colour{0xFF171614}.withAlpha(0.3f)
};
static const Colors darkTheme
{
.background = juce::Colour{0xFF0F0F1A},
.foreground = juce::Colour{0xFF1A1A30},
.dark = juce::Colour{0xFF8888AA},
.highlight = juce::Colour{0xFF3A73E5},
.loop = juce::Colour{0xFFEE8833},
.slate = juce::Colour{0xFF2A2A4A},
.darkerSlate = juce::Colour{0xFF1A192D},
.light = juce::Colour{0xFFFFFFFF},
.prompt = juce::Colour{0xFF0F0F1A}.withAlpha(0.8f)
};
/** This struct contains layout constants. */
struct Layout
{
// Toolbar values should all be scaled according to the window width
static constexpr int figmaWidth{ 1999 };
static constexpr int controlsHeight{ 159 };
static constexpr int controlsPaddingX{ 16 };
static constexpr int moduleGap{ 36 };
static constexpr int moduleLabelHeight{ 42 };
static constexpr int moduleLabelPadding{ 3 };
static constexpr int moduleLabelGap{ 3 };
static constexpr int moduleControlsGap{ 22 };
static constexpr int tuningWidth{ 320 }; // As ratios of the window width
static constexpr int attackWidth{ 204 };
static constexpr int releaseWidth{ 204 };
static constexpr int playbackWidth{ 534 };
static constexpr int loopWidth{ 310 };
static constexpr int masterWidth{ 295 };
static constexpr int standardRotarySize{ 87 }; // Not including padding
static constexpr float rotaryHeightRatio{ 0.965f }; // The height of the rotary slider as a ratio of its width
static constexpr float rotaryPadding{ 0.09f };
static constexpr float rotaryTextSize{ 0.40f };
static constexpr float boundsWidth{ 0.0045f };
static constexpr float handleWidth{ boundsWidth / 2.f };
static constexpr float playheadWidth{ handleWidth * 0.66f };
static constexpr juce::Point<int> sampleControlsMargin{ 46, 25 };
static constexpr int sampleControlsHeight{ 45 };
static constexpr int fileControlsWidth{ 1179 };
static constexpr int waveformModeWidth{ 238 };
static constexpr int playbackControlsWidth{ 137 };
static constexpr float expandWidth{ 1.185f }; // Ratio of combobox height
static constexpr int sampleNavigatorHeight{ 93 };
static constexpr float navigatorBoundsWidth{ 0.002f };
static constexpr juce::Point<int> navigatorControlsSize{ 124, 52 };
static constexpr int fxChainHeight{ 384 };
static constexpr float fxChainDivider{ 0.001f };
static constexpr float fxModuleHeader{ 73.f };
static constexpr float fxDisplayStrokeWidth{ 0.004f };
static constexpr int footerHeight{ 64 };
};
/** This struct contains certain UX constants */
struct Feel
{
static constexpr int MOUSE_SENSITIVITY{ 60 };
static constexpr int DRAGGABLE_SNAP{ 10 };
static constexpr int MINIMUM_BOUNDS_DISTANCE{ 10 }; // This needs to be at some minimum value
static constexpr int MINIMUM_VIEW{ 6 * MINIMUM_BOUNDS_DISTANCE }; // Minimum view size in samples
};
//==============================================================================
/** Some utilities */
struct ComponentProps
{
inline static const juce::String& ROTARY_UNIT{ "props_unit" }; // The rotary unit
inline static const juce::String& ROTARY_GREATER_UNIT{ "greater_unit" }; // A larger unit (e.g. s instead of ms)
inline static const juce::String& ROTARY_ICON{ "label_icon" }; // An icon to display in place of the unit
inline static const juce::String& ROTARY_PARAMETER_NAME{ "parameter_name" }; // For use in a custom rotaries help text
inline static const juce::String& LABEL_ELLIPSES{ "label_ellipses" }; // Use ellipses for the label
};
class ReferenceCountedPath final : public juce::ReferenceCountedObject
{
public:
explicit ReferenceCountedPath(juce::Path path) : path(std::move(path)) {}
juce::Path path;
};
const juce::Font& getInriaSans();
const juce::Font& getInriaSansBold();
const juce::Font& getInter();
const juce::Font& getInterBold();
juce::Path getOutlineFromSVG(const char* data);
//==============================================================================
class CustomLookAndFeel : public juce::LookAndFeel_V4
{
using Colour = juce::Colour;
public:
CustomLookAndFeel();
void setTheme(const Colors& theme);
juce::Slider::SliderLayout getSliderLayout(juce::Slider& slider) override;
juce::Label* createSliderTextBox(juce::Slider& slider) override;
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height, float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, juce::Slider& slider) override;
void drawLabel(juce::Graphics&, juce::Label&) override;
juce::Button* createFilenameComponentBrowseButton(const juce::String& text) override;
void layoutFilenameComponent(juce::FilenameComponent&, juce::ComboBox* filenameBox, juce::Button* browseButton) override;
juce::Font getComboBoxFont(juce::ComboBox&) override;
juce::Label* createComboBoxTextBox(juce::ComboBox&) override;
void positionComboBoxText(juce::ComboBox&, juce::Label& label) override;
void drawComboBox(juce::Graphics&, int width, int height, bool isButtonDown, int buttonX, int buttonY, int buttonW, int buttonH, juce::ComboBox&) override;
void drawComboBoxTextWhenNothingSelected(juce::Graphics&, juce::ComboBox&, juce::Label&) override;
juce::PopupMenu::Options getOptionsForComboBoxPopupMenu(juce::ComboBox&, juce::Label&) override;
juce::Font getPopupMenuFont() override;
void drawPopupMenuBackground(juce::Graphics&, int width, int height) override;
void drawPopupMenuItem(juce::Graphics&, const juce::Rectangle<int>& area, bool isSeparator, bool isActive, bool isHighlighted, bool isTicked, bool hasSubMenu, const juce::String& text, const juce::String& shortcutKeyText, const juce::Drawable* icon, const Colour* textColour) override;
void drawPopupMenuUpDownArrow(juce::Graphics&, int width, int height, bool isScrollUpArrow) override;
juce::Path getTickShape(float height) override;
void drawTickBox(juce::Graphics&, juce::Component&, float x, float y, float w, float h, bool ticked, bool isEnabled, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
juce::Font getAlertWindowTitleFont() override { return getInterBold().withHeight(18.f); }
juce::Font getAlertWindowMessageFont() override { return getInter().withHeight(16.f); }
juce::Font getAlertWindowFont() override { return getInter().withHeight(14.f); }
void drawCornerResizer(juce::Graphics&, int w, int h, bool isMouseOver, bool isMouseDragging) override;
Colors colors;
};
//==============================================================================
/** Here's a custom look and feel for the envelope sliders. A template was not the only way to do this, but I thought I'd try it. */
enum class EnvelopeSlider : std::uint8_t
{
attack,
release
};
template <EnvelopeSlider Direction>
class EnvelopeSliderLookAndFeel final : public CustomLookAndFeel
{
void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height, float sliderPos, float rotaryStartAngle, float rotaryEndAngle, juce::Slider& slider) override;
};
template class EnvelopeSliderLookAndFeel<EnvelopeSlider::attack>;
template class EnvelopeSliderLookAndFeel<EnvelopeSlider::release>;
//==============================================================================
/** Here's a custom look and feel for the volume slider. */
class VolumeSliderLookAndFeel final : public CustomLookAndFeel
{
juce::Slider::SliderLayout getSliderLayout(juce::Slider& slider) override;
juce::Label* createSliderTextBox(juce::Slider& slider) override;
void drawLinearSlider(juce::Graphics& g, int x, int y, int width, int height, float sliderPos, float minSliderPos, float maxSliderPos, juce::Slider::SliderStyle, juce::Slider&) override;
};