horizont/Source/HorizontLookAndFeel.cpp

201 lines
8.9 KiB
C++
Raw Permalink Normal View History

2026-08-10 12:55:02 +02:00
#include "HorizontLookAndFeel.h"
namespace
{
const juce::Colour tealAccent (0xFF3CE0C8);
const juce::Colour textMain (0xFFE8F6F4);
const juce::Colour textDim (0xFFB8CCCC);
const juce::Colour charcoal (0xFF0B0E10);
}
HorizontLookAndFeel::HorizontLookAndFeel()
{
setColour (juce::ComboBox::outlineColourId, juce::Colour (0xFF2A3A3D));
setColour (juce::ComboBox::textColourId, textMain);
setColour (juce::ComboBox::arrowColourId, tealAccent);
setColour (juce::PopupMenu::backgroundColourId, juce::Colour (0xFF141B1E));
setColour (juce::PopupMenu::highlightedBackgroundColourId, juce::Colour (0xFF1E3A3C));
setColour (juce::PopupMenu::textColourId, textMain);
setColour (juce::TooltipWindow::textColourId, textMain);
setColour (juce::TooltipWindow::backgroundColourId, juce::Colour (0xFF122A2B));
setColour (juce::TooltipWindow::outlineColourId, tealAccent);
}
void HorizontLookAndFeel::drawRotarySlider (juce::Graphics& g, int x, int y, int width, int height,
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
juce::Slider&)
{
const auto bounds = juce::Rectangle<float> ((float) x, (float) y, (float) width, (float) height);
const auto centre = bounds.getCentre();
const float radius = jmin (bounds.getWidth(), bounds.getHeight()) * 0.5f;
const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
{
auto shadow = bounds.translated (0.0f, radius * 0.10f);
auto grad = juce::ColourGradient (juce::Colour (0x80000000),
centre.withY (centre.getY() + radius * 0.45f),
juce::Colour (0x00000000),
centre.withY (centre.getY() + radius * 0.45f).translated (radius * 1.1f, 0.0f),
true);
grad.addColour (0.55f, juce::Colour (0x30000000));
g.setGradientFill (grad);
g.fillEllipse (shadow);
}
{
auto disc = bounds.reduced (radius * 0.05f);
auto grad = juce::ColourGradient (juce::Colour (0xFFA9BBC2),
centre.translated (-radius * 0.35f, -radius * 0.45f),
juce::Colour (0xFF171B1E),
centre.translated (-radius * 0.35f, -radius * 0.45f).translated (radius * 1.25f, 0.0f),
true);
grad.addColour (0.35f, juce::Colour (0xFF6E7C84));
grad.addColour (0.75f, juce::Colour (0xFF3A4247));
g.setGradientFill (grad);
g.fillEllipse (disc);
}
{
auto rim = bounds.reduced (radius * 0.03f);
g.setColour (charcoal);
g.drawEllipse (rim, jmax (1.0f, radius * 0.05f));
}
{
auto face = bounds.reduced (radius * 0.24f);
auto grad = juce::ColourGradient (juce::Colour (0xFF333C43),
centre.translated (0.0f, -radius * 0.10f),
juce::Colour (0xFF101316),
centre.translated (0.0f, -radius * 0.10f).translated (radius * 0.85f, 0.0f),
true);
grad.addColour (0.55f, juce::Colour (0xFF20262B));
g.setGradientFill (grad);
g.fillEllipse (face);
g.setColour (juce::Colour (0x383CE0C8));
g.drawEllipse (face, 1.0f);
}
{
const float tipDist = radius * 0.72f;
const float baseDist = radius * 0.34f;
const float halfWidth = radius * 0.085f;
const auto tip = centre.getPointOnCircumference (tipDist, angle);
const auto base = centre.getPointOnCircumference (baseDist, angle);
const float perp = angle + juce::MathConstants<float>::halfPi;
const auto b1 = base.translated (std::cos (perp) * halfWidth, std::sin (perp) * halfWidth);
const auto b2 = base.translated (-std::cos (perp) * halfWidth, -std::sin (perp) * halfWidth);
juce::Path notch;
notch.addTriangle (b1, b2, tip);
notch.closeSubPath();
g.setColour (tealAccent);
g.fillPath (notch);
g.setColour (tealAccent);
g.strokePath (notch, juce::PathStrokeType (1.0f));
}
{
auto hl = juce::Rectangle<float> (radius * 0.9f, radius * 0.5f)
.withCentre (centre.translated (-radius * 0.28f, -radius * 0.32f));
auto grad = juce::ColourGradient (juce::Colour (0x30FFFFFF), hl.getCentre(),
juce::Colour (0x00FFFFFF), hl.getCentre().translated (radius * 0.6f, 0.0f),
true);
g.setGradientFill (grad);
g.fillEllipse (hl);
}
{
auto dot = juce::Rectangle<float> (radius * 0.16f, radius * 0.16f).withCentre (centre);
auto grad = juce::ColourGradient (juce::Colour (0xFF5A666D),
centre.translated (-radius * 0.03f, -radius * 0.03f),
juce::Colour (0xFF171B1E),
centre.translated (-radius * 0.03f, -radius * 0.03f).translated (radius * 0.14f, 0.0f),
true);
g.setGradientFill (grad);
g.fillEllipse (dot);
}
}
void HorizontLookAndFeel::drawComboBox (juce::Graphics& g, int width, int height, bool,
int buttonX, int buttonY, int buttonW, int buttonH, juce::ComboBox&)
{
auto bounds = juce::Rectangle<float> (0, 0, (float) width, (float) height);
auto grad = juce::ColourGradient (juce::Colour (0xFF22292E), { 0.0f, 0.0f },
juce::Colour (0xFF0E1215), { 0.0f, (float) height },
false);
g.setGradientFill (grad);
g.fillRoundedRectangle (bounds, 4.0f);
g.setColour (juce::Colour (0xFF3A4A4D));
g.drawRoundedRectangle (bounds.reduced (0.5f), 4.0f, 1.0f);
auto arrowArea = juce::Rectangle<float> ((float) buttonX, (float) buttonY, (float) buttonW, (float) buttonH);
juce::Path arrow;
arrow.startNewSubPath (arrowArea.getX() + arrowArea.getWidth() * 0.35f, arrowArea.getCentreY() - 2.0f);
arrow.lineTo (arrowArea.getCentreX(), arrowArea.getCentreY() + 3.0f);
arrow.lineTo (arrowArea.getX() + arrowArea.getWidth() * 0.65f, arrowArea.getCentreY() - 2.0f);
g.setColour (tealAccent);
g.strokePath (arrow, juce::PathStrokeType (1.6f,
juce::PathStrokeType::JointStyle::beveled,
juce::PathStrokeType::EndCapStyle::rounded));
}
void HorizontLookAndFeel::drawPopupMenuBackground (juce::Graphics& g, int width, int height)
{
g.setColour (juce::Colour (0xF0141B1E));
g.fillRoundedRectangle (0.0f, 0.0f, (float) width, (float) height, 6.0f);
g.setColour (juce::Colour (0xFF3A4A4D));
g.drawRoundedRectangle (0.5f, 0.5f, (float) width - 1.0f, (float) height - 1.0f, 6.0f, 1.0f);
}
void HorizontLookAndFeel::drawPopupMenuItem (juce::Graphics& g, const juce::Rectangle<int>& area,
bool isSeparator, bool isActive, bool isHighlighted, bool isTicked,
bool, const juce::String& text, const juce::String&,
const juce::Drawable*, const juce::Colour* textColour)
{
if (isSeparator)
{
auto r = area.reduced (5, 0);
g.setColour (juce::Colour (0x334A5A5D));
g.fillRect (r.removeFromBottom (1));
return;
}
if (isHighlighted && isActive)
{
g.setColour (juce::Colour (0xFF1E3A3C));
g.fillRoundedRectangle (area.toFloat().reduced (2.0f), 4.0f);
}
auto textArea = area.reduced (12, 0);
if (isTicked)
textArea.removeFromLeft (12);
g.setColour (isActive ? (textColour != nullptr ? *textColour : textMain) : textDim);
g.setFont (juce::Font (juce::FontOptions (13.0f)));
g.drawText (text, textArea, juce::Justification::centredLeft, false);
if (isTicked)
{
auto dot = juce::Rectangle<float> (4.0f, 4.0f)
.withCentre (juce::Point<float> ((float) (area.getX() + 10), (float) area.getCentreY()));
g.setColour (tealAccent);
g.fillEllipse (dot);
}
}
void HorizontLookAndFeel::drawTooltip (juce::Graphics& g, const juce::String& text, int width, int height)
{
g.setColour (juce::Colour (0xF0122A2B));
g.fillRoundedRectangle (0.0f, 0.0f, (float) width, (float) height, 4.0f);
g.setColour (tealAccent);
g.drawRoundedRectangle (0.5f, 0.5f, (float) width - 1.0f, (float) height - 1.0f, 4.0f, 1.0f);
g.setColour (textMain);
g.setFont (juce::Font (juce::FontOptions (12.0f)));
g.drawText (text, juce::Rectangle<int> (6, 0, width - 12, height), juce::Justification::centred, true);
}