12 : deathMetalFont(juce::FontOptions(
13 juce::Typeface::createSystemTypefaceFor(BinaryData::ArtDystopia_ttf, BinaryData::ArtDystopia_ttfSize)))
20 juce::Font getLabelFont(juce::Label &label)
override
23 return deathMetalFont;
26 juce::Font getPopupMenuFont()
override
28 return deathMetalFont;
31 void drawButtonText(juce::Graphics &g, juce::TextButton &button,
bool isMouseOverButton,
bool isButtonDown)
override
33 std::ignore = isMouseOverButton;
34 std::ignore = isButtonDown;
35 auto font = deathMetalFont;
37 g.setColour(button.findColour(juce::TextButton::textColourOnId));
38 g.drawText(button.getButtonText(), button.getLocalBounds(), juce::Justification::centred,
true);
40 button.setColour(juce::TextButton::ColourIds::buttonColourId, juce::Colours::black);
41 button.setColour(juce::TextButton::ColourIds::buttonOnColourId, juce::Colours::black);
44 void drawLinearSlider(Graphics &g,
int x,
int y,
int width,
int height,
float sliderPos,
float minSliderPos,
45 float maxSliderPos, Slider::SliderStyle style, Slider &slider)
override
49 g.setColour(slider.findColour(Slider::trackColourId));
50 g.fillRect(slider.isHorizontal() ? Rectangle<float>(
static_cast<float>(x), (
float)y + 0.5f,
51 sliderPos - (
float)x, (
float)height - 1.0f)
52 : Rectangle<float>((
float)x + 0.5f, sliderPos, (
float)width - 1.0f,
53 (
float)y + ((
float)height - sliderPos)));
55 drawLinearSliderOutline(g, x, y, width, height, style, slider);
60 (style == Slider::SliderStyle::TwoValueVertical || style == Slider::SliderStyle::TwoValueHorizontal);
61 auto isThreeVal = (style == Slider::SliderStyle::ThreeValueVertical ||
62 style == Slider::SliderStyle::ThreeValueHorizontal);
64 auto trackWidth = jmin(6.0f, slider.isHorizontal() ? (
float)height * 0.25f : (
float)width * 0.25f);
66 Point<float> startPoint(slider.isHorizontal() ? (
float)x : (
float)x + (
float)width * 0.5f,
67 slider.isHorizontal() ? (
float)y + (
float)height * 0.5f : (
float)(height + y));
69 Point<float> endPoint(slider.isHorizontal() ? (
float)(width + x) : startPoint.x,
70 slider.isHorizontal() ? startPoint.y : (
float)y);
73 backgroundTrack.startNewSubPath(startPoint);
74 backgroundTrack.lineTo(endPoint);
75 g.setColour(slider.findColour(Slider::backgroundColourId));
76 g.strokePath(backgroundTrack, {trackWidth, PathStrokeType::curved, PathStrokeType::rounded});
79 Point<float> minPoint, maxPoint, thumbPoint;
81 if (isTwoVal || isThreeVal)
83 minPoint = {slider.isHorizontal() ? minSliderPos : (float)width * 0.5f,
84 slider.isHorizontal() ? (float)height * 0.5f : minSliderPos};
87 thumbPoint = {slider.isHorizontal() ? sliderPos : (float)width * 0.5f,
88 slider.isHorizontal() ? (float)height * 0.5f : sliderPos};
90 maxPoint = {slider.isHorizontal() ? maxSliderPos : (float)width * 0.5f,
91 slider.isHorizontal() ? (float)height * 0.5f : maxSliderPos};
95 auto kx = slider.isHorizontal() ? sliderPos : ((float)x + (float)width * 0.5f);
96 auto ky = slider.isHorizontal() ? ((float)y + (float)height * 0.5f) : sliderPos;
98 minPoint = startPoint;
102 auto thumbWidth = getSliderThumbRadius(slider) + 4;
104 valueTrack.startNewSubPath(minPoint);
105 valueTrack.lineTo(isThreeVal ? thumbPoint : maxPoint);
106 g.setColour(slider.findColour(Slider::trackColourId));
107 g.strokePath(valueTrack, {trackWidth, PathStrokeType::curved, PathStrokeType::rounded});
111 g.setColour(juce::Colours::black);
112 g.fillEllipse(Rectangle<float>(
static_cast<float>(thumbWidth),
static_cast<float>(thumbWidth))
113 .withCentre(isThreeVal ? thumbPoint : maxPoint));
115 g.setColour(juce::Colours::white);
117 juce::Point<float> point1(maxPoint.getX(), maxPoint.getY());
118 point1.setX(point1.getX() + (thumbWidth / 2) * ::sinf(0.f * std::numbers::pi / 180.f));
119 point1.setY(point1.getY() + (thumbWidth / 2) * ::cosf(0.f * std::numbers::pi / 180.f));
121 juce::Point<float> point2(maxPoint.getX(), maxPoint.getY());
122 point2.setX(point2.getX() +
123 (thumbWidth / 2) * ::sinf(144.f *
static_cast<float>(std::numbers::pi) / 180.f));
124 point2.setY(point2.getY() +
125 (thumbWidth / 2) * ::cosf(144.f *
static_cast<float>(std::numbers::pi) / 180.f));
127 juce::Point<float> point3(maxPoint.getX(), maxPoint.getY());
128 point3.setX(point3.getX() +
129 (thumbWidth / 2) * ::sinf(288.f *
static_cast<float>(std::numbers::pi) / 180.f));
130 point3.setY(point3.getY() +
131 (thumbWidth / 2) * ::cosf(288.f *
static_cast<float>(std::numbers::pi) / 180.f));
133 juce::Point<float> point4(maxPoint.getX(), maxPoint.getY());
134 point4.setX(point4.getX() +
135 (thumbWidth / 2) * ::sinf(72.f *
static_cast<float>(std::numbers::pi) / 180.f));
136 point4.setY(point4.getY() +
137 (thumbWidth / 2) * ::cosf(72.f *
static_cast<float>(std::numbers::pi) / 180.f));
139 juce::Point<float> point5(maxPoint.getX(), maxPoint.getY());
140 point5.setX(point5.getX() +
141 (thumbWidth / 2) * ::sinf(216.f *
static_cast<float>(std::numbers::pi) / 180.f));
142 point5.setY(point5.getY() +
143 (thumbWidth / 2) * ::cosf(216.f *
static_cast<float>(std::numbers::pi) / 180.f));
145 juce::Path pentagramPath;
146 pentagramPath.startNewSubPath(point1);
147 pentagramPath.lineTo(point2);
148 pentagramPath.lineTo(point3);
149 pentagramPath.lineTo(point4);
150 pentagramPath.lineTo(point5);
151 pentagramPath.closeSubPath();
152 g.strokePath(pentagramPath, juce::PathStrokeType(1));
154 g.drawEllipse(Rectangle<float>(
static_cast<float>(thumbWidth),
static_cast<float>(thumbWidth))
155 .withCentre(isThreeVal ? thumbPoint : maxPoint)
160 if (isTwoVal || isThreeVal)
162 auto sr = jmin(trackWidth, (slider.isHorizontal() ? (
float)height : (
float)width) * 0.4f);
163 auto pointerColour = slider.findColour(Slider::thumbColourId);
165 if (slider.isHorizontal())
167 drawPointer(g, minSliderPos - sr, jmax(0.0f, (
float)y + (
float)height * 0.5f - trackWidth * 2.0f),
168 trackWidth * 2.0f, pointerColour, 2);
170 drawPointer(g, maxSliderPos - trackWidth,
171 jmin((
float)(y + height) - trackWidth * 2.0f, (
float)y + (
float)height * 0.5f),
172 trackWidth * 2.0f, pointerColour, 4);
176 drawPointer(g, jmax(0.0f, (
float)x + (
float)width * 0.5f - trackWidth * 2.0f),
177 minSliderPos - trackWidth, trackWidth * 2.0f, pointerColour, 1);
179 drawPointer(g, jmin((
float)(x + width) - trackWidth * 2.0f, (
float)x + (
float)width * 0.5f),
180 maxSliderPos - sr, trackWidth * 2.0f, pointerColour, 3);
185 drawLinearSliderOutline(g, x, y, width, height, style, slider);
189 void drawRotarySlider(juce::Graphics &g,
int x,
int y,
int width,
int height,
float sliderPosProportional,
190 float rotaryStartAngle,
float rotaryEndAngle, juce::Slider &slider)
override
192 std::ignore = slider;
193 auto radius = (float)juce::jmin(width / 2, height / 2) - 4.0f;
194 auto centreX = (float)x + (
float)width * 0.5f;
195 auto centreY = (float)y + (
float)height * 0.5f;
196 auto rx = centreX - radius;
197 auto ry = centreY - radius;
198 auto rw = radius * 2.0f;
199 auto angle = rotaryStartAngle + sliderPosProportional * (rotaryEndAngle - rotaryStartAngle);
201 auto lineW = radius * 0.135f;
203 juce::Rectangle<float> bounds(rx, ry, rw, rw);
206 g.setColour(juce::Colours::black);
207 g.fillEllipse(bounds);
210 float adjustedRadius = radius - (lineW / 2.0f);
213 backgroundArc.addCentredArc(centreX, centreY, adjustedRadius, adjustedRadius, 0.0f, rotaryStartAngle,
214 rotaryEndAngle,
true);
216 g.setColour(juce::Colours::grey.darker(1.0));
217 g.strokePath(backgroundArc, PathStrokeType(lineW, PathStrokeType::curved, PathStrokeType::rounded));
221 arcPath.addCentredArc(centreX, centreY, adjustedRadius, adjustedRadius, 0.0f, rotaryStartAngle, angle,
true);
224 juce::Image offscreenImage(juce::Image::ARGB, width, height,
true);
226 juce::Graphics offscreenGraphics(offscreenImage);
229 offscreenGraphics.fillAll(juce::Colours::transparentBlack);
232 offscreenGraphics.setColour(juce::Colours::white);
234 offscreenGraphics.strokePath(
235 arcPath, juce::PathStrokeType(lineW, juce::PathStrokeType::curved, juce::PathStrokeType::rounded));
242 juce::Image unboundImage = offscreenImage.createCopy();
245 juce::Image glowImage(juce::Image::ARGB, width, height,
true);
247 juce::Graphics glowGraphics(glowImage);
248 juce::GlowEffect glowEffect;
249 glowEffect.setGlowProperties(5.0f, juce::Colours::yellow);
250 glowEffect.applyEffect(unboundImage, glowGraphics, 1.0f, 1.0f);
254 g.drawImageAt(glowImage, x, y);
256 g.setColour(juce::Colours::white);
258 juce::Point<float> point1(centreX, centreY);
259 point1.setX(point1.getX() + (radius - lineW * 1.5f) * ::sinf(0.f * std::numbers::pi / 180.f));
260 point1.setY(point1.getY() + (radius - lineW * 1.5f) * ::cosf(0.f * std::numbers::pi / 180.f));
262 juce::Point<float> point2(centreX, centreY);
263 point2.setX(point2.getX() +
264 (radius - lineW * 1.5f) * ::sinf(144.f *
static_cast<float>(std::numbers::pi) / 180.f));
265 point2.setY(point2.getY() +
266 (radius - lineW * 1.5f) * ::cosf(144.f *
static_cast<float>(std::numbers::pi) / 180.f));
268 juce::Point<float> point3(centreX, centreY);
269 point3.setX(point3.getX() +
270 (radius - lineW * 1.5f) * ::sinf(288.f *
static_cast<float>(std::numbers::pi) / 180.f));
271 point3.setY(point3.getY() +
272 (radius - lineW * 1.5f) * ::cosf(288.f *
static_cast<float>(std::numbers::pi) / 180.f));
274 juce::Point<float> point4(centreX, centreY);
275 point4.setX(point4.getX() +
276 (radius - lineW * 1.5f) * ::sinf(72.f *
static_cast<float>(std::numbers::pi) / 180.f));
277 point4.setY(point4.getY() +
278 (radius - lineW * 1.5f) * ::cosf(72.f *
static_cast<float>(std::numbers::pi) / 180.f));
280 juce::Point<float> point5(centreX, centreY);
281 point5.setX(point5.getX() +
282 (radius - lineW * 1.5f) * ::sinf(216.f *
static_cast<float>(std::numbers::pi) / 180.f));
283 point5.setY(point5.getY() +
284 (radius - lineW * 1.5f) * ::cosf(216.f *
static_cast<float>(std::numbers::pi) / 180.f));
286 juce::Path pentagramPath;
287 pentagramPath.startNewSubPath(point1);
288 pentagramPath.lineTo(point2);
289 pentagramPath.lineTo(point3);
290 pentagramPath.lineTo(point4);
291 pentagramPath.lineTo(point5);
292 pentagramPath.closeSubPath();
295 juce::AffineTransform transform =
296 juce::AffineTransform::translation(-centreX, -centreY).rotated(angle).translated(centreX, centreY);
297 pentagramPath.applyTransform(transform);
299 g.strokePath(pentagramPath, juce::PathStrokeType(2));
302 g.drawEllipse(bounds.reduced(lineW * 2.f), 2.f);
305 juce::Path crossPath;
308 crossPath.addRectangle(centreX - lineW / 2, centreY + radius / 6, lineW, -radius);
312 crossPath.addRectangle(centreX - (radius / 3 / 2), centreY - radius / 10, radius / 3, lineW);
316 crossPath.applyTransform(transform);
318 g.setColour(juce::Colours::white);
319 g.fillPath(crossPath);
322 void drawGroupComponentOutline(juce::Graphics &g,
int width,
int height,
const juce::String &text,
323 const juce::Justification &position, juce::GroupComponent &group)
override
325 const float textH = 15.0f;
326 const float indent = 3.0f;
327 const float textEdgeGap = 4.0f;
332 auto y = deathMetalFont.getAscent() - 3.0f;
333 auto w = jmax(0.0f, (
float)width - x * 2.0f);
334 auto h = jmax(0.0f, (
float)height - y - indent);
335 cs = jmin(cs, w * 0.5f, h * 0.5f);
336 auto cs2 = 2.0f * cs;
338 auto textW = text.isEmpty() ? 0 : jlimit(0.0f, jmax(0.0f, w - cs2 - textEdgeGap * 2), [&]() {
340 juce::TextLayout layout;
341 juce::AttributedString attributedText;
342 attributedText.append(text, deathMetalFont, juce::Colours::black);
344 layout.createLayout(attributedText, w - cs2 - textEdgeGap * 2);
345 return layout.getWidth() + textEdgeGap * 2.0f;
347 auto textX = cs + textEdgeGap;
349 if (position.testFlags(Justification::horizontallyCentred))
350 textX = cs + (w - cs2 - textW) * 0.5f;
351 else if (position.testFlags(Justification::right))
352 textX = w - cs - textW - textEdgeGap;
354 p.startNewSubPath(x + textX + textW, y);
355 p.lineTo(x + w - cs, y);
357 p.addArc(x + w - cs2, y, cs2, cs2, 0, MathConstants<float>::halfPi);
358 p.lineTo(x + w, y + h - cs);
360 p.addArc(x + w - cs2, y + h - cs2, cs2, cs2, MathConstants<float>::halfPi, MathConstants<float>::pi);
361 p.lineTo(x + cs, y + h);
363 p.addArc(x, y + h - cs2, cs2, cs2, MathConstants<float>::pi, MathConstants<float>::pi * 1.5f);
366 p.addArc(x, y, cs2, cs2, MathConstants<float>::pi * 1.5f, MathConstants<float>::twoPi);
367 p.lineTo(x + textX, y);
369 auto alpha = group.isEnabled() ? 1.0f : 0.5f;
371 g.setColour(group.findColour(GroupComponent::outlineColourId).withMultipliedAlpha(alpha));
373 g.strokePath(p, PathStrokeType(2.0f));
375 g.setColour(group.findColour(GroupComponent::textColourId).withMultipliedAlpha(alpha));
376 g.setFont(deathMetalFont);
377 g.drawText(text, roundToInt(x + textX), 0, roundToInt(textW), roundToInt(textH), Justification::centred,
true);
380 void drawPopupMenuBackground(juce::Graphics &g,
int width,
int height)
override
382 std::ignore = height;
384 g.fillAll(juce::Colours::black);
388 juce::Font deathMetalFont;
389 juce::ColourGradient mGradient;