c89c1558e3
- fixed passthrough when capturing - added declicking fades when bypassing input passthrough, playback, and recording - layout tweaks for extra small windows - waveform scrollbar improvements, visible edge drag handles, and allows dragging from anywhere - minor visual tweaks - license header mods, and LICENSE file consolidation
1315 lines
52 KiB
C++
1315 lines
52 KiB
C++
// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception
|
|
// Copyright (C) 2020 Jesse Chappell
|
|
|
|
|
|
#include "CustomLookAndFeel.h"
|
|
|
|
//==============================================================================
|
|
CustomLookAndFeel::CustomLookAndFeel()
|
|
{
|
|
// setColour (mainBackgroundColourId, Colour::greyLevel (0.8f));
|
|
//DBG("Sonolook and feel");
|
|
|
|
setUsingNativeAlertWindows(true);
|
|
|
|
fontScale = 1.0;
|
|
|
|
|
|
setColourScheme(getDarkColourScheme());
|
|
|
|
getCurrentColourScheme().setUIColour(ColourScheme::UIColour::windowBackground, Colour::fromFloatRGBA(0.0, 0.0, 0.0, 1.0));
|
|
getCurrentColourScheme().setUIColour(ColourScheme::UIColour::widgetBackground, Colour::fromFloatRGBA(0.1, 0.1, 0.1, 1.0));
|
|
getCurrentColourScheme().setUIColour(ColourScheme::UIColour::outline, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.5));
|
|
|
|
setColour (Label::textColourId, Colour (0xffcccccc));
|
|
setColour (Label::textWhenEditingColourId, Colour (0xffe9e9e9));
|
|
|
|
setColour(ResizableWindow::backgroundColourId, Colour(0xff111111));
|
|
|
|
//setColour (TextButton::buttonColourId, Colour (0xff363636));
|
|
setColour (TextButton::buttonColourId, Colour::fromFloatRGBA(0.15, 0.15, 0.15, 0.7)); // old one
|
|
//setColour (TextButton::buttonColourId, Colour::fromFloatRGBA(0.15, 0.15, 0.15, 0.0));
|
|
//setColour (TextButton::buttonOnColourId, Colour (0xff3d70c8));
|
|
setColour (TextButton::buttonOnColourId, Colour::fromFloatRGBA(0.5, 0.4, 0.6, 0.8));
|
|
setColour (TextButton::textColourOnId, Colour (0xddcccccc));
|
|
setColour (TextButton::textColourOffId, Colour (0xdde9e9e9));
|
|
|
|
setColour (ToggleButton::textColourId, Colour (0xddcccccc));
|
|
|
|
|
|
setColour (ScrollBar::ColourIds::thumbColourId, Colour::fromFloatRGBA(0.7, 0.7, 0.7, 0.7));
|
|
|
|
//setColour (ComboBox::backgroundColourId, Colour (0xff161616));
|
|
setColour (ComboBox::backgroundColourId, Colour::fromFloatRGBA(0.15, 0.15, 0.15, 0.7));
|
|
setColour (ComboBox::textColourId, Colour (0xffe9e9e9));
|
|
setColour (ComboBox::outlineColourId, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.5));
|
|
|
|
setColour (TextEditor::backgroundColourId, Colour (0xff050505));
|
|
setColour (TextEditor::textColourId, Colour (0xffe9e9e9));
|
|
setColour (TextEditor::highlightColourId, Colour (0xff5959f9));
|
|
setColour (TextEditor::outlineColourId, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.5));
|
|
setColour (TextEditor::focusedOutlineColourId, Colour::fromFloatRGBA(0.5, 0.5, 0.5, 0.7));
|
|
|
|
setColour (Slider::backgroundColourId, Colour::fromFloatRGBA(0.2, 0.2, 0.2, 1.0));
|
|
setColour (Slider::rotarySliderOutlineColourId, Colour::fromFloatRGBA(0.2, 0.2, 0.2, 1.0));
|
|
setColour (Slider::textBoxTextColourId, Colour(0xddcccccc));
|
|
setColour (Slider::textBoxBackgroundColourId, Colour::fromFloatRGBA(0.05, 0.05, 0.05, 1.0));
|
|
setColour (Slider::textBoxHighlightColourId, Colour (0xaa555555));
|
|
setColour (Slider::textBoxOutlineColourId, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.5));
|
|
|
|
setColour (Slider::trackColourId, Colour::fromFloatRGBA(0.1, 0.4, 0.6, 0.8));
|
|
setColour (Slider::thumbColourId, Colour::fromFloatRGBA(0.5, 0.4, 0.6, 0.9));
|
|
//setColour (Slider::thumbColourId, Colour::fromFloatRGBA(0.2, 0.5, 0.7, 1.0));
|
|
setColour (Slider::rotarySliderFillColourId, Colour::fromFloatRGBA(0.5, 0.4, 0.6, 0.9));
|
|
|
|
setColour (TabbedButtonBar::tabOutlineColourId, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.6));
|
|
setColour (TabbedComponent::outlineColourId, Colour::fromFloatRGBA(0.2, 0.2, 0.2, 0.5));
|
|
|
|
|
|
|
|
setColour (ListBox::backgroundColourId, Colour::fromFloatRGBA(0.15, 0.15, 0.15, 0.7));
|
|
setColour (ListBox::outlineColourId, Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.5));
|
|
|
|
setColour (BubbleComponent::backgroundColourId, Colour::fromFloatRGBA(0.25, 0.25, 0.25, 1.0));
|
|
setColour (BubbleComponent::outlineColourId, Colour::fromFloatRGBA(0.4, 0.4, 0.4, 0.5));
|
|
//setColour (TooltipWindow::textColourId, Colour(0xeecccccc));
|
|
setColour (TooltipWindow::textColourId, Colour(0xee222222));
|
|
setColour (TooltipWindow::backgroundColourId, Colour(0xeeffff99));
|
|
|
|
setColour (PopupMenu::backgroundColourId, Colour::fromFloatRGBA(0.2, 0.2, 0.2, 1.0));
|
|
setColour (PopupMenu::highlightedBackgroundColourId, Colour::fromFloatRGBA(0.35, 0.35, 0.4, 1.0));
|
|
|
|
setColour (SidePanel::backgroundColour, Colour::fromFloatRGBA(0.17, 0.17, 0.17, 1.0));
|
|
|
|
|
|
//setColour (SonoDrawableButton::overOverlayColourId, Colour::fromFloatRGBA(0.8, 0.8, 0.8, 0.08));
|
|
//setColour (SonoDrawableButton::downOverlayColourId, Colour::fromFloatRGBA(0.8, 0.8, 0.8, 0.3));
|
|
|
|
setColour (DrawableButton::textColourId, Colour (0xffb9b9b9));
|
|
setColour (DrawableButton::textColourOnId, Colour (0xffe9e9e9));
|
|
|
|
//setColour (DrawableButton::backgroundColourId, Colour (0xffb9b9b9));
|
|
setColour (DrawableButton::backgroundOnColourId, Colour::fromFloatRGBA(0.5, 0.4, 0.6, 0.8));
|
|
|
|
//setColour (ConfigurationRowView::backgroundColourId, Colour::fromFloatRGBA(0.05, 0.05, 0.05, 1.0));
|
|
//setColour (ConfigurationRowView::selectedBackgroundColourId, Colour::fromFloatRGBA(0.15, 0.15, 0.15, 1.0));
|
|
|
|
setColour(ToggleButton::tickColourId, Colour::fromFloatRGBA(0.4, 0.8, 1.0, 1.0));
|
|
|
|
setColour (DirectoryContentsDisplayComponent::highlightColourId, Colour::fromFloatRGBA(0.1, 0.4, 0.6, 0.9));
|
|
setColour (DirectoryContentsDisplayComponent::textColourId, Colour (0xffe9e9e9));
|
|
// setColour (Label::textColourId, Colour (0xffe9e9e9));
|
|
|
|
//myFont = Typeface::createSystemTypefaceFor (BinaryData::DejaVuSans_ttf, BinaryData::DejaVuSans_ttfSize);
|
|
//setDefaultSansSerifTypefaceName("Gill Sans");
|
|
//setDefaultSansSerifTypefaceName("Arial Unicode MS");
|
|
//setDefaultSansSerifTypefaceName(myFont.getTypefaceName());
|
|
|
|
//myFont = Typeface::createSystemTypefaceFor (BinaryData::GillSans_ttc, BinaryData::GillSans_ttcSize);
|
|
myFont = Font(16 * fontScale);
|
|
|
|
|
|
if (auto * deflnf = dynamic_cast<CustomLookAndFeel*>(&LookAndFeel::getDefaultLookAndFeel())) {
|
|
setLanguageCode(deflnf->languageCode);
|
|
}
|
|
|
|
//DBG("Myfont name " << myFont.getTypefaceName());
|
|
}
|
|
|
|
void CustomLookAndFeel::setLanguageCode(const String & lang)
|
|
{
|
|
languageCode = lang;
|
|
|
|
if (lang.startsWith("zh")) {
|
|
fontScale = 1.0f;
|
|
}
|
|
else if (lang.startsWith("ko")) {
|
|
fontScale = 1.15f;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Font CustomLookAndFeel::getMenuBarFont (MenuBarComponent& menuBar, int /*itemIndex*/, const String& /*itemText*/)
|
|
{
|
|
return Font (menuBar.getHeight() * 0.7f);
|
|
}
|
|
|
|
//==============================================================================
|
|
void CustomLookAndFeel::drawCallOutBoxBackground (CallOutBox& box, Graphics& g,
|
|
const Path& path, Image& cachedImage)
|
|
{
|
|
if (cachedImage.isNull())
|
|
{
|
|
cachedImage = Image (Image::ARGB, box.getWidth(), box.getHeight(), true);
|
|
Graphics g2 (cachedImage);
|
|
|
|
DropShadow (Colours::black.withAlpha (0.7f), 8, Point<int> (0, 2)).drawForPath (g2, path);
|
|
}
|
|
|
|
g.setColour (Colours::black);
|
|
g.drawImageAt (cachedImage, 0, 0);
|
|
|
|
//g.setColour (getCurrentColourScheme().getUIColour (ColourScheme::UIColour::widgetBackground).withAlpha (0.8f));
|
|
g.setColour (getCurrentColourScheme().getUIColour (ColourScheme::UIColour::widgetBackground));
|
|
g.fillPath (path);
|
|
|
|
g.setColour (getCurrentColourScheme().getUIColour (ColourScheme::UIColour::outline).withAlpha (0.8f));
|
|
g.strokePath (path, PathStrokeType (1.0f));
|
|
}
|
|
|
|
|
|
|
|
int CustomLookAndFeel::getTabButtonBestWidth (TabBarButton& button, int depth)
|
|
{
|
|
return 250; // 120;
|
|
}
|
|
|
|
int CustomLookAndFeel::getTabButtonSpaceAroundImage() {
|
|
return 0;
|
|
}
|
|
|
|
static Colour getTabBackgroundColour (TabBarButton& button)
|
|
{
|
|
|
|
const Colour bkg (button.findColour (TabbedComponent::backgroundColourId).contrasting (0.15f));
|
|
|
|
if (button.isFrontTab())
|
|
return bkg.overlaidWith (Colours::yellow.withAlpha (0.8f));
|
|
|
|
return bkg;
|
|
}
|
|
|
|
Rectangle<int> CustomLookAndFeel::getTabButtonExtraComponentBounds (const TabBarButton& button, Rectangle<int>& textArea, Component& comp)
|
|
{
|
|
Rectangle<int> extraComp;
|
|
|
|
auto orientation = button.getTabbedButtonBar().getOrientation();
|
|
|
|
if (button.getExtraComponentPlacement() == TabBarButton::beforeText)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case TabbedButtonBar::TabsAtBottom:
|
|
case TabbedButtonBar::TabsAtTop: extraComp = textArea.removeFromLeft (comp.getWidth()); break;
|
|
case TabbedButtonBar::TabsAtLeft: extraComp = textArea.removeFromBottom (comp.getHeight()); break;
|
|
case TabbedButtonBar::TabsAtRight: extraComp = textArea.removeFromTop (comp.getHeight()); break;
|
|
default: jassertfalse; break;
|
|
}
|
|
}
|
|
else if (button.getExtraComponentPlacement() == TabBarButton::afterText)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case TabbedButtonBar::TabsAtBottom:
|
|
case TabbedButtonBar::TabsAtTop: extraComp = textArea.removeFromRight (comp.getWidth()); break;
|
|
case TabbedButtonBar::TabsAtLeft: extraComp = textArea.removeFromTop (comp.getHeight()); break;
|
|
case TabbedButtonBar::TabsAtRight: extraComp = textArea.removeFromBottom (comp.getHeight()); break;
|
|
default: jassertfalse; break;
|
|
}
|
|
}
|
|
else if (button.getExtraComponentPlacement() == TabBarButton::aboveText)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case TabbedButtonBar::TabsAtBottom:
|
|
case TabbedButtonBar::TabsAtTop: extraComp = textArea.removeFromTop (comp.getHeight()); break;
|
|
case TabbedButtonBar::TabsAtLeft: extraComp = textArea.removeFromTop (comp.getHeight()); break;
|
|
case TabbedButtonBar::TabsAtRight: extraComp = textArea.removeFromTop (comp.getHeight()); break;
|
|
default: jassertfalse; break;
|
|
}
|
|
|
|
// DBG("Extra comp bounds: " << extraComp.toString())
|
|
extraComp.translate(0, 3);
|
|
//DBG("After Extra comp bounds: " << extraComp.toString())
|
|
|
|
}
|
|
else if (button.getExtraComponentPlacement() == TabBarButton::belowText)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case TabbedButtonBar::TabsAtBottom:
|
|
case TabbedButtonBar::TabsAtTop: extraComp = textArea.removeFromBottom (comp.getHeight()); break;
|
|
case TabbedButtonBar::TabsAtLeft: extraComp = textArea.removeFromBottom (comp.getHeight()); break;
|
|
case TabbedButtonBar::TabsAtRight: extraComp = textArea.removeFromBottom (comp.getHeight()); break;
|
|
default: jassertfalse; break;
|
|
}
|
|
}
|
|
|
|
return extraComp;
|
|
}
|
|
|
|
void CustomLookAndFeel::createTabTextLayout (const TabBarButton& button, float length, float depth,
|
|
Colour colour, TextLayout& textLayout)
|
|
{
|
|
float hscale = 0.6f;
|
|
#if JUCE_IOS
|
|
hscale = 0.5f;
|
|
#endif
|
|
float fontsize = button.getExtraComponent() != nullptr ? jmin(depth, 32.0f) * hscale : jmin(depth, 32.0f) * hscale;
|
|
Font font = myFont.withHeight(fontsize * fontScale);
|
|
font.setUnderline (button.hasKeyboardFocus (false));
|
|
|
|
AttributedString s;
|
|
s.setWordWrap(AttributedString::byWord);
|
|
s.setJustification (Justification::centred);
|
|
s.append (button.getButtonText().trim(), font, colour);
|
|
|
|
textLayout.createLayout (s, length);
|
|
}
|
|
|
|
void CustomLookAndFeel::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
|
|
{
|
|
const Rectangle<int> activeArea (button.getActiveArea());
|
|
|
|
const TabbedButtonBar::Orientation o = button.getTabbedButtonBar().getOrientation();
|
|
|
|
const Colour bkg (button.getTabBackgroundColour());
|
|
const Colour selcol = Colour::fromFloatRGBA(0.0f, 0.2f, 0.4f, 1.0f);
|
|
|
|
// DBG("Sono draw tab button");
|
|
|
|
|
|
if (button.getToggleState() && bkg != Colours::black)
|
|
{
|
|
//g.setColour (bkg);
|
|
g.setColour (selcol);
|
|
}
|
|
else
|
|
{
|
|
|
|
Point<int> p1, p2;
|
|
|
|
switch (o)
|
|
{
|
|
case TabbedButtonBar::TabsAtBottom: p1 = activeArea.getBottomLeft(); p2 = activeArea.getTopLeft(); break;
|
|
case TabbedButtonBar::TabsAtTop: p1 = activeArea.getTopLeft(); p2 = activeArea.getBottomLeft(); break;
|
|
case TabbedButtonBar::TabsAtRight: p1 = activeArea.getTopRight(); p2 = activeArea.getTopLeft(); break;
|
|
case TabbedButtonBar::TabsAtLeft: p1 = activeArea.getTopLeft(); p2 = activeArea.getTopRight(); break;
|
|
default: jassertfalse; break;
|
|
}
|
|
|
|
g.setColour(isMouseDown ? bkg.brighter(0.1) : bkg);
|
|
|
|
//g.setGradientFill (ColourGradient (bkg.darker (0.1f), (float) p1.x, (float) p1.y,
|
|
// bkg.darker (0.5f), (float) p2.x, (float) p2.y, false));
|
|
}
|
|
|
|
Rectangle<int> p (activeArea.reduced(1));
|
|
|
|
g.fillRect (p);
|
|
|
|
//g.fillRect (activeArea);
|
|
|
|
#if 0
|
|
g.setColour (button.findColour (TabbedButtonBar::tabOutlineColourId));
|
|
|
|
Rectangle<int> r (activeArea);
|
|
|
|
if (o != TabbedButtonBar::TabsAtBottom) g.fillRect (r.removeFromTop (1));
|
|
if (o != TabbedButtonBar::TabsAtTop) g.fillRect (r.removeFromBottom (1));
|
|
if (o != TabbedButtonBar::TabsAtRight) g.fillRect (r.removeFromLeft (1));
|
|
if (o != TabbedButtonBar::TabsAtLeft) g.fillRect (r.removeFromRight (1));
|
|
#endif
|
|
|
|
|
|
const float alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f;
|
|
|
|
Colour col (bkg.contrasting().withMultipliedAlpha (alpha));
|
|
|
|
if (TabbedButtonBar* bar = button.findParentComponentOfClass<TabbedButtonBar>())
|
|
{
|
|
TabbedButtonBar::ColourIds colID = button.isFrontTab() ? TabbedButtonBar::frontTextColourId
|
|
: TabbedButtonBar::tabTextColourId;
|
|
|
|
if (bar->isColourSpecified (colID))
|
|
col = bar->findColour (colID);
|
|
else if (isColourSpecified (colID))
|
|
col = findColour (colID);
|
|
}
|
|
|
|
const Rectangle<float> area (button.getTextArea().toFloat());
|
|
|
|
float length = area.getWidth();
|
|
float depth = area.getHeight();
|
|
|
|
if (button.getTabbedButtonBar().isVertical())
|
|
std::swap (length, depth);
|
|
|
|
TextLayout textLayout;
|
|
createTabTextLayout (button, length, depth, col, textLayout);
|
|
|
|
AffineTransform t;
|
|
|
|
switch (o)
|
|
{
|
|
case TabbedButtonBar::TabsAtLeft: t = t.rotated (float_Pi * -0.5f).translated (area.getX(), area.getBottom()); break;
|
|
case TabbedButtonBar::TabsAtRight: t = t.rotated (float_Pi * 0.5f).translated (area.getRight(), area.getY()); break;
|
|
case TabbedButtonBar::TabsAtTop:
|
|
case TabbedButtonBar::TabsAtBottom: t = t.translated (area.getX(), area.getY()); break;
|
|
default: jassertfalse; break;
|
|
}
|
|
|
|
g.addTransform (t);
|
|
textLayout.draw (g, Rectangle<float> (length, depth));
|
|
}
|
|
|
|
/*
|
|
void CustomLookAndFeel::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
|
|
{
|
|
const Rectangle<int> activeArea (button.getActiveArea());
|
|
|
|
const Colour bkg (getTabBackgroundColour (button));
|
|
|
|
g.setGradientFill (ColourGradient (bkg.brighter (0.1f), 0, (float) activeArea.getY(),
|
|
bkg.darker (0.1f), 0, (float) activeArea.getBottom(), false));
|
|
g.fillRect (activeArea);
|
|
|
|
g.setColour (button.findColour (TabbedComponent::backgroundColourId).darker (0.3f));
|
|
g.drawRect (activeArea);
|
|
|
|
const float alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f;
|
|
const Colour col (bkg.contrasting().withMultipliedAlpha (alpha));
|
|
|
|
TextLayout textLayout;
|
|
LookAndFeel_V3::createTabTextLayout (button, (float) activeArea.getWidth(), (float) activeArea.getHeight(), col, textLayout);
|
|
|
|
textLayout.draw (g, button.getTextArea().toFloat());
|
|
}
|
|
*/
|
|
|
|
void CustomLookAndFeel::drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) {}
|
|
|
|
void CustomLookAndFeel::drawTabAreaBehindFrontButton (TabbedButtonBar& bar, Graphics& g, const int w, const int h)
|
|
{
|
|
const float shadowSize = 0.15f;
|
|
|
|
Rectangle<int> shadowRect, line;
|
|
ColourGradient gradient (Colours::black.withAlpha (bar.isEnabled() ? 0.08f : 0.04f), 0, 0,
|
|
Colours::transparentBlack, 0, 0, false);
|
|
|
|
switch (bar.getOrientation())
|
|
{
|
|
case TabbedButtonBar::TabsAtLeft:
|
|
gradient.point1.x = (float) w;
|
|
gradient.point2.x = w * (1.0f - shadowSize);
|
|
shadowRect.setBounds ((int) gradient.point2.x, 0, w - (int) gradient.point2.x, h);
|
|
line.setBounds (w - 1, 0, 1, h);
|
|
break;
|
|
|
|
case TabbedButtonBar::TabsAtRight:
|
|
gradient.point2.x = w * shadowSize;
|
|
shadowRect.setBounds (0, 0, (int) gradient.point2.x, h);
|
|
line.setBounds (0, 0, 1, h);
|
|
break;
|
|
|
|
case TabbedButtonBar::TabsAtTop:
|
|
gradient.point1.y = (float) h;
|
|
gradient.point2.y = h * (1.0f - shadowSize);
|
|
shadowRect.setBounds (0, (int) gradient.point2.y, w, h - (int) gradient.point2.y);
|
|
line.setBounds (0, h - 1, w, 1);
|
|
break;
|
|
|
|
case TabbedButtonBar::TabsAtBottom:
|
|
gradient.point2.y = h * shadowSize;
|
|
shadowRect.setBounds (0, 0, w, (int) gradient.point2.y);
|
|
line.setBounds (0, 0, w, 1);
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
|
|
g.setGradientFill (gradient);
|
|
g.fillRect (shadowRect.expanded (2, 2));
|
|
|
|
g.setColour (bar.findColour (TabbedButtonBar::tabOutlineColourId));
|
|
g.fillRect (line);
|
|
}
|
|
|
|
void CustomLookAndFeel::drawTabButtonText (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
|
|
{
|
|
const Rectangle<float> area (button.getTextArea().toFloat());
|
|
|
|
//DBG("Sono look and feel drawtabbutton text: " << button.getButtonText());
|
|
|
|
float length = area.getWidth();
|
|
float depth = area.getHeight();
|
|
|
|
if (button.getTabbedButtonBar().isVertical())
|
|
std::swap (length, depth);
|
|
|
|
Font font = myFont.withHeight(jmin(depth,30.0f) * 0.6f * fontScale);
|
|
font.setUnderline (button.hasKeyboardFocus (false));
|
|
|
|
AffineTransform t;
|
|
|
|
switch (button.getTabbedButtonBar().getOrientation())
|
|
{
|
|
case TabbedButtonBar::TabsAtLeft: t = t.rotated (float_Pi * -0.5f).translated (area.getX(), area.getBottom()); break;
|
|
case TabbedButtonBar::TabsAtRight: t = t.rotated (float_Pi * 0.5f).translated (area.getRight(), area.getY()); break;
|
|
case TabbedButtonBar::TabsAtTop:
|
|
case TabbedButtonBar::TabsAtBottom: t = t.translated (area.getX(), area.getY()); break;
|
|
default: jassertfalse; break;
|
|
}
|
|
|
|
Colour col;
|
|
|
|
if (button.isFrontTab() && (button.isColourSpecified (TabbedButtonBar::frontTextColourId)
|
|
|| isColourSpecified (TabbedButtonBar::frontTextColourId)))
|
|
col = findColour (TabbedButtonBar::frontTextColourId);
|
|
else if (button.isColourSpecified (TabbedButtonBar::tabTextColourId)
|
|
|| isColourSpecified (TabbedButtonBar::tabTextColourId))
|
|
col = findColour (TabbedButtonBar::tabTextColourId);
|
|
else
|
|
col = button.getTabBackgroundColour().contrasting();
|
|
|
|
const float alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f;
|
|
|
|
g.setColour (col.withMultipliedAlpha (alpha));
|
|
g.setFont (font);
|
|
g.addTransform (t);
|
|
|
|
g.drawFittedText (button.getButtonText().trim(),
|
|
0, 0, (int) length, (int) depth,
|
|
Justification::centred,
|
|
//jmax (1, ((int) depth) / 12), 0.5f);
|
|
1, 0.5f);
|
|
}
|
|
|
|
static Range<float> getBrightnessRange (const Image& im)
|
|
{
|
|
float minB = 1.0f, maxB = 0;
|
|
const int w = im.getWidth();
|
|
const int h = im.getHeight();
|
|
|
|
for (int y = 0; y < h; ++y)
|
|
{
|
|
for (int x = 0; x < w; ++x)
|
|
{
|
|
const float b = im.getPixelAt (x, y).getBrightness();
|
|
minB = jmin (minB, b);
|
|
maxB = jmax (maxB, b);
|
|
}
|
|
}
|
|
|
|
return Range<float> (minB, maxB);
|
|
}
|
|
|
|
Font CustomLookAndFeel::getLabelFont (Label& label)
|
|
{
|
|
if (fontScale == 1.0f) {
|
|
return label.getFont();
|
|
}
|
|
else {
|
|
return label.getFont().withHeight(label.getFont().getHeight() * fontScale);
|
|
}
|
|
}
|
|
|
|
void CustomLookAndFeel::drawLabel (Graphics& g, Label& label)
|
|
{
|
|
Colour olcolor = label.findColour (Label::backgroundColourId);
|
|
|
|
g.setColour(olcolor);
|
|
if (!olcolor.isTransparent()) {
|
|
if (labelCornerRadius > 0.0f) {
|
|
g.fillRoundedRectangle(label.getLocalBounds().reduced(1).toFloat(), labelCornerRadius);
|
|
} else {
|
|
g.fillAll (olcolor);
|
|
}
|
|
}
|
|
|
|
|
|
if (! label.isBeingEdited())
|
|
{
|
|
auto alpha = label.isEnabled() ? 1.0f : 0.5f;
|
|
const Font font (getLabelFont (label));
|
|
|
|
g.setColour (label.findColour (Label::textColourId).withMultipliedAlpha (alpha));
|
|
g.setFont (font);
|
|
|
|
auto textArea = getLabelBorderSize (label).subtractedFrom (label.getLocalBounds());
|
|
|
|
g.drawFittedText (label.getText(), textArea, label.getJustificationType(),
|
|
jmax (1, (int) (textArea.getHeight() / font.getHeight())),
|
|
label.getMinimumHorizontalScale());
|
|
|
|
olcolor = label.findColour (Label::outlineColourId).withMultipliedAlpha (alpha);
|
|
}
|
|
else if (label.isEnabled())
|
|
{
|
|
olcolor = label.findColour (Label::outlineColourId);
|
|
}
|
|
|
|
if (!olcolor.isTransparent()) {
|
|
g.setColour (olcolor);
|
|
if (labelCornerRadius > 0.0f) {
|
|
g.drawRoundedRectangle(label.getLocalBounds().reduced(1).toFloat(), labelCornerRadius, 1.0f);
|
|
} else {
|
|
g.drawRect (label.getLocalBounds());
|
|
}
|
|
}
|
|
}
|
|
|
|
Font CustomLookAndFeel::getTextButtonFont (TextButton& button, int buttonHeight)
|
|
{
|
|
// DBG("GetTextButton font with height: " << buttonHeight);
|
|
float textRatio = 0.5f;
|
|
//if (SonoTextButton* const textbutt = dynamic_cast<SonoTextButton*> (&button)) {
|
|
// textRatio = textbutt->getTextHeightRatio();
|
|
//}
|
|
|
|
return myFont.withHeight(jmin (16.0f, buttonHeight * textRatio) * fontScale);
|
|
}
|
|
|
|
Button* CustomLookAndFeel::createSliderButton (Slider&, const bool isIncrement)
|
|
{
|
|
TextButton * butt = new TextButton (isIncrement ? "+" : "-", {});
|
|
return butt;
|
|
}
|
|
|
|
Label* CustomLookAndFeel::createSliderTextBox (Slider& slider)
|
|
{
|
|
Label * lab = LookAndFeel_V4::createSliderTextBox(slider);
|
|
lab->setKeyboardType(TextInputTarget::decimalKeyboard);
|
|
lab->setFont(myFont.withHeight(16.0* fontScale));
|
|
lab->setMinimumHorizontalScale(0.5);
|
|
lab->setJustificationType(Justification::centredRight);
|
|
return lab;
|
|
}
|
|
|
|
Font CustomLookAndFeel::getSliderPopupFont (Slider&)
|
|
{
|
|
return Font (18.0f, Font::bold);
|
|
}
|
|
|
|
int CustomLookAndFeel::getSliderPopupPlacement (Slider&)
|
|
{
|
|
return BubbleComponent::above
|
|
//| BubbleComponent::below
|
|
| BubbleComponent::left
|
|
| BubbleComponent::right
|
|
;
|
|
}
|
|
|
|
void CustomLookAndFeel::drawButtonTextWithAlignment (Graphics& g, TextButton& button, bool /*isMouseOverButton*/, bool /*isButtonDown*/, Justification textjust)
|
|
{
|
|
Font font (getTextButtonFont (button, button.getHeight()));
|
|
g.setFont (font);
|
|
g.setColour (button.findColour (button.getToggleState() ? TextButton::textColourOnId
|
|
: TextButton::textColourOffId)
|
|
.withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f));
|
|
|
|
float textRatio = 0.7f;
|
|
//if (SonoTextButton* const textbutt = dynamic_cast<SonoTextButton*> (&button)) {
|
|
// textRatio = textbutt->getTextHeightRatio();
|
|
//}
|
|
|
|
const int yIndent = jmin (2, button.proportionOfHeight ((1.0 - textRatio) * 0.5));
|
|
const int cornerSize = jmin (button.getHeight(), button.getWidth()) / 2;
|
|
|
|
const int fontHeight = roundToInt (font.getHeight() * 0.3);
|
|
const int leftIndent = jmin (fontHeight, 2 + cornerSize / (button.isConnectedOnLeft() ? 4 : 2));
|
|
const int rightIndent = jmin (fontHeight, 2 + cornerSize / (button.isConnectedOnRight() ? 4 : 2));
|
|
|
|
g.drawFittedText (button.getButtonText(),
|
|
leftIndent,
|
|
yIndent,
|
|
button.getWidth() - leftIndent - rightIndent,
|
|
button.getHeight() - yIndent * 2,
|
|
textjust, 2, 0.7f);
|
|
}
|
|
|
|
|
|
void CustomLookAndFeel::drawButtonText (Graphics& g, TextButton& button, bool isMouseOverButton, bool isButtonDown)
|
|
{
|
|
drawButtonTextWithAlignment(g, button, isMouseOverButton, isButtonDown);
|
|
}
|
|
|
|
|
|
void CustomLookAndFeel::drawFileBrowserRow (Graphics& g, int width, int height,
|
|
const File& file, const String& filename, Image* icon,
|
|
const String& fileSizeDescription,
|
|
const String& fileTimeDescription,
|
|
bool isDirectory, bool isItemSelected,
|
|
int itemIndex, DirectoryContentsDisplayComponent& dcc)
|
|
{
|
|
Component* const fileListComp = dynamic_cast<Component*> (&dcc);
|
|
|
|
if (isItemSelected)
|
|
g.fillAll (fileListComp != nullptr ? fileListComp->findColour (DirectoryContentsDisplayComponent::highlightColourId)
|
|
: findColour (DirectoryContentsDisplayComponent::highlightColourId));
|
|
|
|
int x = 32;
|
|
g.setColour (Colours::black);
|
|
|
|
if (isDirectory) {
|
|
if (icon != nullptr && icon->isValid())
|
|
{
|
|
g.drawImageWithin (*icon, 2, 2, x - 4, height - 4,
|
|
RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize,
|
|
false);
|
|
}
|
|
else
|
|
{
|
|
if (const Drawable* d = isDirectory ? getDefaultFolderImage()
|
|
: getDefaultDocumentFileImage())
|
|
d->drawWithin (g, Rectangle<float> (2.0f, 2.0f, x - 4.0f, height - 4.0f),
|
|
RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, 1.0f);
|
|
}
|
|
}
|
|
else {
|
|
x = 4;
|
|
}
|
|
|
|
g.setColour (fileListComp != nullptr ? fileListComp->findColour (DirectoryContentsDisplayComponent::textColourId)
|
|
: findColour (DirectoryContentsDisplayComponent::textColourId));
|
|
g.setFont (myFont.withHeight(height * 0.6f));
|
|
|
|
if (width > 450 && ! isDirectory)
|
|
{
|
|
const int sizeX = roundToInt (width * 0.7f);
|
|
const int dateX = roundToInt (width * 0.8f);
|
|
|
|
g.drawFittedText (filename,
|
|
x, 0, sizeX - x, height,
|
|
Justification::centredLeft, 1);
|
|
|
|
g.setFont (myFont.withHeight(height * 0.6f));
|
|
g.setColour (Colours::darkgrey);
|
|
|
|
if (! isDirectory)
|
|
{
|
|
g.drawFittedText (fileSizeDescription,
|
|
sizeX, 0, dateX - sizeX - 8, height,
|
|
Justification::centredRight, 1);
|
|
|
|
g.drawFittedText (fileTimeDescription,
|
|
dateX, 0, width - 8 - dateX, height,
|
|
Justification::centredRight, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g.drawFittedText (filename,
|
|
x, 0, width - x, height,
|
|
Justification::centredLeft, 1);
|
|
|
|
}
|
|
}
|
|
|
|
Button* CustomLookAndFeel::createFileBrowserGoUpButton()
|
|
{
|
|
DrawableButton* goUpButton = new DrawableButton ("up", DrawableButton::ImageOnButtonBackground);
|
|
|
|
Path arrowPath;
|
|
arrowPath.addArrow (Line<float> (50.0f, 100.0f, 50.0f, 0.0f), 40.0f, 100.0f, 50.0f);
|
|
|
|
DrawablePath arrowImage;
|
|
arrowImage.setFill (Colours::white.withAlpha (0.4f));
|
|
arrowImage.setPath (arrowPath);
|
|
|
|
goUpButton->setImages (&arrowImage);
|
|
|
|
return goUpButton;
|
|
}
|
|
|
|
void CustomLookAndFeel::layoutFileBrowserComponent (FileBrowserComponent& browserComp,
|
|
DirectoryContentsDisplayComponent* fileListComponent,
|
|
FilePreviewComponent* previewComp,
|
|
ComboBox* currentPathBox,
|
|
TextEditor* filenameBox,
|
|
Button* goUpButton)
|
|
{
|
|
const int x = 8;
|
|
int w = browserComp.getWidth() - x - x;
|
|
|
|
if (previewComp != nullptr)
|
|
{
|
|
const int previewWidth = w / 3;
|
|
previewComp->setBounds (x + w - previewWidth, 0, previewWidth, browserComp.getHeight());
|
|
|
|
w -= previewWidth + 4;
|
|
}
|
|
|
|
int y = 4;
|
|
|
|
const int controlsHeight = 22;
|
|
const int bottomSectionHeight = controlsHeight + 8;
|
|
const int upButtonWidth = 50;
|
|
|
|
currentPathBox->setBounds (x, y, w - upButtonWidth - 6, controlsHeight);
|
|
goUpButton->setBounds (x + w - upButtonWidth, y, upButtonWidth, controlsHeight);
|
|
|
|
y += controlsHeight + 4;
|
|
|
|
if (Component* const listAsComp = dynamic_cast <Component*> (fileListComponent))
|
|
{
|
|
listAsComp->setBounds (x, y, w, browserComp.getHeight() - y - bottomSectionHeight);
|
|
y = listAsComp->getBottom() + 4;
|
|
}
|
|
|
|
filenameBox->setBounds (x + 50, y, w - 50, controlsHeight);
|
|
}
|
|
|
|
|
|
PopupMenu::Options CustomLookAndFeel::getOptionsForComboBoxPopupMenu (ComboBox& box, Label& label)
|
|
{
|
|
auto options = PopupMenu::Options().withTargetComponent (&box)
|
|
.withItemThatMustBeVisible (box.getSelectedId())
|
|
.withMinimumWidth (box.getWidth())
|
|
.withMaximumNumColumns (1)
|
|
.withStandardItemHeight (label.getHeight());
|
|
|
|
#if JUCE_IOS || JUCE_ANDROID
|
|
auto * dw = box.findParentComponentOfClass<AudioProcessorEditor>();
|
|
if (dw) {
|
|
options = options.withParentComponent(dw);
|
|
}
|
|
#endif
|
|
|
|
return options;
|
|
}
|
|
|
|
void CustomLookAndFeel::drawTreeviewPlusMinusBox (Graphics& g, const Rectangle<float>& area,
|
|
Colour backgroundColour, bool isOpen, bool isMouseOver)
|
|
{
|
|
Path p;
|
|
p.addTriangle (0.0f, 0.0f, 1.0f, isOpen ? 0.0f : 0.5f, isOpen ? 0.5f : 0.0f, 1.0f);
|
|
|
|
DBG("draw plus minus ours");
|
|
|
|
//g.setColour (backgroundColour.contrasting().withAlpha (isMouseOver ? 0.5f : 0.3f));
|
|
g.setColour (Colours::white.withAlpha (isMouseOver ? 0.5f : 0.3f));
|
|
g.fillPath (p, p.getTransformToScaleToFit (area.reduced (2, area.getHeight() / 4), true));
|
|
}
|
|
|
|
|
|
void CustomLookAndFeel::drawToggleButton (Graphics& g, ToggleButton& button,
|
|
bool isMouseOverButton, bool isButtonDown)
|
|
{
|
|
/*
|
|
if (button.hasKeyboardFocus (true))
|
|
{
|
|
g.setColour (button.findColour (TextEditor::focusedOutlineColourId));
|
|
g.drawRect (0, 0, button.getWidth(), button.getHeight());
|
|
}
|
|
*/
|
|
|
|
float fontSize = jmin (15.0f, button.getHeight() * 0.75f) * fontScale;
|
|
const float tickWidth = fontSize * 1.1f;
|
|
|
|
drawTickBox (g, button, 4.0f, (button.getHeight() - tickWidth) * 0.5f,
|
|
tickWidth, tickWidth,
|
|
button.getToggleState(),
|
|
button.isEnabled(),
|
|
isMouseOverButton,
|
|
isButtonDown);
|
|
|
|
g.setColour (button.findColour (ToggleButton::textColourId));
|
|
g.setFont (myFont.withHeight(fontSize));
|
|
|
|
if (! button.isEnabled())
|
|
g.setOpacity (0.5f);
|
|
|
|
const int textX = (int) tickWidth + 10;
|
|
|
|
g.drawFittedText (button.getButtonText(),
|
|
textX, 0,
|
|
button.getWidth() - textX - 2, button.getHeight(),
|
|
Justification::centredLeft, 10);
|
|
}
|
|
|
|
void CustomLookAndFeel::drawTickBox (Graphics& g, Component& component,
|
|
float x, float y, float w, float h,
|
|
const bool ticked,
|
|
const bool isEnabled,
|
|
const bool isMouseOverButton,
|
|
const bool isButtonDown)
|
|
{
|
|
const float boxSize = w * 1.0f;
|
|
|
|
|
|
g.setColour (component.findColour (TextEditor::focusedOutlineColourId));
|
|
g.drawRect (x, y + (h - boxSize) * 0.5f, boxSize, boxSize);
|
|
|
|
if (ticked)
|
|
{
|
|
Path tick;
|
|
tick.startNewSubPath (1.5f, 3.0f);
|
|
tick.lineTo (3.0f, 6.0f);
|
|
tick.lineTo (6.0f, 0.0f);
|
|
|
|
|
|
g.setColour (isEnabled ? component.findColour(ToggleButton::tickColourId) : Colours::grey);
|
|
|
|
const AffineTransform trans (AffineTransform::scale (w / 9.0f, h / 9.0f)
|
|
.translated (x+2, y+1));
|
|
|
|
g.strokePath (tick, PathStrokeType (2.5f), trans);
|
|
}
|
|
}
|
|
|
|
void CustomLookAndFeel::drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
|
|
const float rotaryStartAngle, const float rotaryEndAngle, Slider& slider)
|
|
{
|
|
const auto outline = findColour (Slider::rotarySliderOutlineColourId);
|
|
const auto fill = findColour (Slider::rotarySliderFillColourId);
|
|
|
|
const auto bounds = Rectangle<int> (x, y, width, height).toFloat().reduced (3);
|
|
|
|
|
|
auto radius = jmin (bounds.getWidth(), bounds.getHeight()) / 2.0f;
|
|
const auto toAngle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
|
|
auto lineW = jmin (8.0f, radius * 0.3f);
|
|
auto arcRadius = radius - lineW * 0.5f;
|
|
|
|
Path backgroundArc;
|
|
backgroundArc.addCentredArc (bounds.getCentreX(),
|
|
bounds.getCentreY(),
|
|
arcRadius,
|
|
arcRadius,
|
|
0.0f,
|
|
rotaryStartAngle,
|
|
rotaryEndAngle,
|
|
true);
|
|
|
|
g.setColour (outline);
|
|
g.strokePath (backgroundArc, PathStrokeType (lineW, PathStrokeType::curved, PathStrokeType::rounded));
|
|
|
|
auto rotStartAngle = rotaryStartAngle;
|
|
|
|
if (slider.getProperties().contains ("fromCentre"))
|
|
{
|
|
rotStartAngle = (rotStartAngle + rotaryEndAngle) / 2;
|
|
}
|
|
|
|
|
|
if (slider.isEnabled())
|
|
{
|
|
Path valueArc;
|
|
valueArc.addCentredArc (bounds.getCentreX(),
|
|
bounds.getCentreY(),
|
|
arcRadius,
|
|
arcRadius,
|
|
0.0f,
|
|
rotStartAngle,
|
|
toAngle,
|
|
true);
|
|
|
|
g.setColour (fill);
|
|
g.strokePath (valueArc, PathStrokeType (lineW, PathStrokeType::curved, PathStrokeType::rounded));
|
|
}
|
|
|
|
const auto thumbWidth = lineW ; // * 1.5f;
|
|
const Point<float> thumbPoint (bounds.getCentreX() + arcRadius * std::cos (toAngle - float_Pi * 0.5f),
|
|
bounds.getCentreY() + arcRadius * std::sin (toAngle - float_Pi * 0.5f));
|
|
|
|
g.setColour (findColour (Slider::thumbColourId));
|
|
g.fillEllipse (Rectangle<float> (thumbWidth, thumbWidth).withCentre (thumbPoint));
|
|
}
|
|
|
|
//==============================================================================
|
|
int CustomLookAndFeel::getSliderThumbRadius (Slider& slider)
|
|
{
|
|
if (slider.isTwoValue() || slider.isThreeValue()) {
|
|
return jmin (14, slider.isHorizontal() ? static_cast<int> (slider.getHeight() * 0.25f)
|
|
: static_cast<int> (slider.getWidth() * 0.5f));
|
|
}
|
|
return jmin (16, slider.isHorizontal() ? static_cast<int> (slider.getHeight() * 0.5f)
|
|
: static_cast<int> (slider.getWidth() * 0.5f));
|
|
}
|
|
|
|
|
|
Slider::SliderLayout CustomLookAndFeel::getSliderLayout (Slider& slider)
|
|
{
|
|
// 1. compute the actually visible textBox size from the slider textBox size and some additional constraints
|
|
|
|
int minXSpace = 0;
|
|
int minYSpace = 0;
|
|
|
|
auto textBoxPos = slider.getTextBoxPosition();
|
|
|
|
if (textBoxPos == Slider::TextBoxLeft || textBoxPos == Slider::TextBoxRight)
|
|
minXSpace = 30;
|
|
else
|
|
minYSpace = 15;
|
|
|
|
auto localBounds = slider.getLocalBounds();
|
|
|
|
auto textBoxWidth = jmax (0, jmin (slider.getTextBoxWidth(), localBounds.getWidth() - minXSpace));
|
|
auto textBoxHeight = jmax (0, jmin (slider.getTextBoxHeight(), localBounds.getHeight() - minYSpace));
|
|
|
|
Slider::SliderLayout layout;
|
|
|
|
// 2. set the textBox bounds
|
|
|
|
if (textBoxPos != Slider::NoTextBox)
|
|
{
|
|
if (slider.isBar())
|
|
{
|
|
layout.textBoxBounds = localBounds;
|
|
}
|
|
else
|
|
{
|
|
layout.textBoxBounds.setWidth (textBoxWidth);
|
|
layout.textBoxBounds.setHeight (textBoxHeight);
|
|
|
|
const int thumbIndent = getSliderThumbRadius (slider);
|
|
|
|
if (textBoxPos == Slider::TextBoxLeft) layout.textBoxBounds.setX (0);
|
|
else if (textBoxPos == Slider::TextBoxRight) layout.textBoxBounds.setX (localBounds.getWidth() - textBoxWidth);
|
|
else if (sliderTextJustification.testFlags(Justification::right))/* above or below -> right */ layout.textBoxBounds.setX ((localBounds.getWidth() - textBoxWidth - 1));
|
|
else if (sliderTextJustification.testFlags(Justification::left))/* above or below -> left */ layout.textBoxBounds.setX (1);
|
|
else /* above or below -> centre horizontally */ layout.textBoxBounds.setX ((localBounds.getWidth() - textBoxWidth) / 2);
|
|
|
|
if (textBoxPos == Slider::TextBoxAbove) layout.textBoxBounds.setY (0);
|
|
else if (textBoxPos == Slider::TextBoxBelow) layout.textBoxBounds.setY (localBounds.getHeight() - textBoxHeight);
|
|
else if (sliderTextJustification.testFlags(Justification::top))/* left or right -> top */ layout.textBoxBounds.setY (0);
|
|
else if (sliderTextJustification.testFlags(Justification::bottom))/* left or right -> bottom */ layout.textBoxBounds.setY (localBounds.getHeight() - textBoxHeight);
|
|
else /* left or right -> centre vertically */ layout.textBoxBounds.setY ((localBounds.getHeight() - textBoxHeight) / 2);
|
|
}
|
|
}
|
|
|
|
// 3. set the slider bounds
|
|
|
|
layout.sliderBounds = localBounds;
|
|
|
|
if (slider.isBar())
|
|
{
|
|
layout.sliderBounds.reduce (1, 1); // bar border
|
|
}
|
|
else
|
|
{
|
|
if (textBoxPos == Slider::TextBoxLeft) layout.sliderBounds.removeFromLeft (textBoxWidth);
|
|
else if (textBoxPos == Slider::TextBoxRight) layout.sliderBounds.removeFromRight (textBoxWidth);
|
|
else if (textBoxPos == Slider::TextBoxAbove) layout.sliderBounds.removeFromTop (textBoxHeight);
|
|
else if (textBoxPos == Slider::TextBoxBelow) layout.sliderBounds.removeFromBottom (textBoxHeight);
|
|
|
|
const int thumbIndent = getSliderThumbRadius (slider);
|
|
|
|
if (slider.isHorizontal()) layout.sliderBounds.reduce (thumbIndent, 0);
|
|
else if (slider.isVertical()) layout.sliderBounds.reduce (0, thumbIndent);
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
|
|
|
|
void CustomLookAndFeel::drawLinearSlider (Graphics& g, int x, int y, int width, int height,
|
|
float sliderPos,
|
|
float minSliderPos,
|
|
float maxSliderPos,
|
|
const Slider::SliderStyle style, Slider& slider)
|
|
{
|
|
if (slider.isBar())
|
|
{
|
|
if (slider.getProperties().contains ("fromCentre")) {
|
|
auto centrex = x + width*0.5f;
|
|
auto centrey = y + height*0.5f;
|
|
|
|
if (!slider.getProperties().contains ("noFill")) {
|
|
g.setColour (slider.findColour (Slider::trackColourId));
|
|
|
|
g.fillRect (slider.isHorizontal() ? Rectangle<float> (sliderPos > centrex ? centrex : sliderPos, y + 0.5f, sliderPos > centrex ? sliderPos - centrex : centrex - sliderPos, height - 1.0f)
|
|
: Rectangle<float> (x + 0.5f, sliderPos < centrey ? sliderPos : centrey, width - 1.0f, sliderPos < centrey ? centrey - sliderPos : sliderPos - centrey));
|
|
}
|
|
|
|
// draw line
|
|
g.setColour (slider.findColour (Slider::thumbColourId));
|
|
|
|
g.fillRect (slider.isHorizontal() ? Rectangle<float> (sliderPos - 1, y + 0.5f, 2, height - 1.0f)
|
|
: Rectangle<float> (x + 0.5f, sliderPos - 1, width - 1.0f, 2));
|
|
}
|
|
else {
|
|
|
|
if (!slider.getProperties().contains ("noFill")) {
|
|
|
|
g.setColour (slider.findColour (Slider::trackColourId));
|
|
|
|
g.fillRect (slider.isHorizontal() ? Rectangle<float> (static_cast<float> (x), y + 0.5f, sliderPos - x, height - 1.0f)
|
|
: Rectangle<float> (x + 0.5f, sliderPos, width - 1.0f, y + (height - sliderPos)));
|
|
}
|
|
//else
|
|
|
|
g.setColour (slider.findColour (Slider::thumbColourId));
|
|
|
|
{
|
|
// draw line
|
|
g.fillRect (slider.isHorizontal() ? Rectangle<float> (sliderPos - 1, y + 0.5f, 3, height - 1.0f)
|
|
: Rectangle<float> (x + 0.5f, sliderPos - 1, width - 1.0f, 3));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto isTwoVal = (style == Slider::SliderStyle::TwoValueVertical || style == Slider::SliderStyle::TwoValueHorizontal);
|
|
auto isThreeVal = (style == Slider::SliderStyle::ThreeValueVertical || style == Slider::SliderStyle::ThreeValueHorizontal);
|
|
|
|
auto trackWidth = jmin (10.0f, slider.isHorizontal() ? height * 0.25f : width * 0.25f);
|
|
|
|
Point<float> startPoint (slider.isHorizontal() ? x : x + width * 0.5f,
|
|
slider.isHorizontal() ? y + height * 0.5f : height + y);
|
|
|
|
Point<float> endPoint (slider.isHorizontal() ? width + x : startPoint.x,
|
|
slider.isHorizontal() ? startPoint.y : y);
|
|
|
|
Path backgroundTrack;
|
|
backgroundTrack.startNewSubPath (startPoint);
|
|
backgroundTrack.lineTo (endPoint);
|
|
g.setColour (slider.findColour (Slider::backgroundColourId));
|
|
g.strokePath (backgroundTrack, { trackWidth, PathStrokeType::curved, PathStrokeType::rounded });
|
|
|
|
Path valueTrack;
|
|
Point<float> minPoint, maxPoint, thumbPoint;
|
|
|
|
if (isTwoVal || isThreeVal)
|
|
{
|
|
minPoint = { slider.isHorizontal() ? minSliderPos : width * 0.5f,
|
|
slider.isHorizontal() ? height * 0.5f : minSliderPos };
|
|
|
|
if (isThreeVal)
|
|
thumbPoint = { slider.isHorizontal() ? sliderPos : width * 0.5f,
|
|
slider.isHorizontal() ? height * 0.5f : sliderPos };
|
|
|
|
maxPoint = { slider.isHorizontal() ? maxSliderPos : width * 0.5f,
|
|
slider.isHorizontal() ? height * 0.5f : maxSliderPos };
|
|
}
|
|
else
|
|
{
|
|
auto kx = slider.isHorizontal() ? sliderPos : (x + width * 0.5f);
|
|
auto ky = slider.isHorizontal() ? (y + height * 0.5f) : sliderPos;
|
|
|
|
minPoint = startPoint;
|
|
maxPoint = { kx, ky };
|
|
}
|
|
|
|
auto thumbWidth = getSliderThumbRadius (slider);
|
|
|
|
valueTrack.startNewSubPath (minPoint);
|
|
valueTrack.lineTo (isThreeVal ? thumbPoint : maxPoint);
|
|
g.setColour (slider.findColour (Slider::trackColourId));
|
|
g.strokePath (valueTrack, { trackWidth, PathStrokeType::curved, PathStrokeType::rounded });
|
|
|
|
if (! isTwoVal)
|
|
{
|
|
g.setColour (slider.findColour (Slider::thumbColourId));
|
|
g.fillEllipse (Rectangle<float> (static_cast<float> (thumbWidth), static_cast<float> (thumbWidth)).withCentre (isThreeVal ? thumbPoint : maxPoint));
|
|
}
|
|
|
|
if (isTwoVal || isThreeVal)
|
|
{
|
|
auto sr = jmin (trackWidth, (slider.isHorizontal() ? height : width) * 0.4f);
|
|
auto pointerColour = slider.findColour (Slider::thumbColourId);
|
|
|
|
auto wscale = 1.5f;
|
|
|
|
if (slider.isHorizontal())
|
|
{
|
|
/*
|
|
drawPointer (g, minSliderPos - sr,
|
|
height * 0.5f - trackWidth*wscale*0.5, //jmax (0.0f, y + height * 0.5f - trackWidth * 0.5f),
|
|
trackWidth * wscale, pointerColour, 1); // 2
|
|
|
|
drawPointer (g, maxSliderPos - trackWidth,
|
|
height * 0.5f - trackWidth*wscale*0.5, //jmin (y + height - trackWidth * 2.0f, (float)y + height * 0.5f),
|
|
trackWidth * wscale, pointerColour, 3); // 4
|
|
*/
|
|
|
|
drawPointer (g, minSliderPos - sr,
|
|
jmax (0.0f, y + height * 0.5f - trackWidth * wscale),
|
|
trackWidth * wscale, pointerColour, 2); // 2
|
|
|
|
drawPointer (g, maxSliderPos - trackWidth*0.5*wscale,
|
|
jmin (y + height - trackWidth * wscale, (float)y + height * 0.5f),
|
|
trackWidth * wscale, pointerColour, 4); // 4
|
|
}
|
|
else
|
|
{
|
|
drawPointer (g, jmax (0.0f, x + width * 0.5f - trackWidth * 2.0f),
|
|
minSliderPos - trackWidth,
|
|
trackWidth * wscale, pointerColour, 1);
|
|
|
|
drawPointer (g, jmin (x + width - trackWidth * 2.0f, x + width * 0.5f), maxSliderPos - sr,
|
|
trackWidth * wscale, pointerColour, 3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CustomLookAndFeel::drawDrawableButton (Graphics& g, DrawableButton& button,
|
|
bool isMouseOverButton, bool isButtonDown)
|
|
{
|
|
const auto cornerSize = 6.0f;
|
|
bool toggleState = button.getToggleState();
|
|
|
|
;
|
|
|
|
//Rectangle<float> bounds = g.getClipBounds().toFloat();
|
|
Rectangle<float> bounds = button.getLocalBounds().toFloat();
|
|
|
|
g.setColour(button.findColour (toggleState ? DrawableButton::backgroundOnColourId
|
|
: DrawableButton::backgroundColourId));
|
|
//g.fillAll();
|
|
g.fillRoundedRectangle(bounds, cornerSize);
|
|
|
|
if (isButtonDown) {
|
|
//setColour (SonoDrawableButton::overOverlayColourId, Colour::fromFloatRGBA(0.8, 0.8, 0.8, 0.08));
|
|
//setColour (SonoDrawableButton::downOverlayColourId, Colour::fromFloatRGBA(0.8, 0.8, 0.8, 0.3));
|
|
g.setColour(Colour::fromFloatRGBA(0.8, 0.8, 0.8, 0.3));
|
|
|
|
//g.setColour(findColour(SonoDrawableButton::downOverlayColourId));
|
|
//g.fillAll();
|
|
g.fillRoundedRectangle(bounds, cornerSize);
|
|
}
|
|
else if (isMouseOverButton) {
|
|
//g.setColour(findColour(SonoDrawableButton::overOverlayColourId));
|
|
g.setColour(Colour::fromFloatRGBA(0.8, 0.8, 0.8, 0.08));
|
|
//g.fillAll();
|
|
g.fillRoundedRectangle(bounds, cornerSize);
|
|
}
|
|
|
|
//g.fillAll (button.findColour (toggleState ? DrawableButton::backgroundOnColourId
|
|
// : DrawableButton::backgroundColourId));
|
|
|
|
int textH = 0;
|
|
int textW = 0;
|
|
float imageratio = 0.75f;
|
|
|
|
//if (SonoDrawableButton* const sonobutt = dynamic_cast<SonoDrawableButton*> (&button)) {
|
|
// imageratio = sonobutt->getForegroundImageRatio();
|
|
//}
|
|
|
|
if (button.getStyle() == DrawableButton::ImageAboveTextLabel || button.getStyle() == DrawableButton::ImageBelowTextLabel) {
|
|
textH = jmin (14, button.proportionOfHeight (0.2f));
|
|
} else if (button.getStyle() == DrawableButton::ImageLeftOfTextLabel || button.getStyle() == DrawableButton::ImageRightOfTextLabel) {
|
|
textH = jmin (14, button.proportionOfHeight (0.8f));
|
|
textW = jmax (20, button.proportionOfWidth (1.0f - imageratio));
|
|
}
|
|
|
|
|
|
if (textH > 0)
|
|
{
|
|
g.setFont (myFont.withHeight((float) textH * fontScale));
|
|
|
|
g.setColour (button.findColour (toggleState ? DrawableButton::textColourOnId
|
|
: DrawableButton::textColourId)
|
|
.withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.4f));
|
|
|
|
if (button.getStyle() == DrawableButton::ImageAboveTextLabel) {
|
|
|
|
g.drawFittedText (button.getButtonText(),
|
|
2, button.getHeight() - textH - 1,
|
|
button.getWidth() - 4, textH,
|
|
Justification::centred, 1);
|
|
}
|
|
else if (button.getStyle() == DrawableButton::ImageBelowTextLabel) {
|
|
g.drawFittedText (button.getButtonText(),
|
|
2, 1,
|
|
button.getWidth() - 4, textH,
|
|
Justification::centred, 1);
|
|
}
|
|
else if (button.getStyle() == DrawableButton::ImageRightOfTextLabel) {
|
|
g.drawFittedText (button.getButtonText(),
|
|
2, 1,
|
|
textW , button.getHeight() - 2,
|
|
Justification::centred, 2, 0.6f);
|
|
}
|
|
else if (button.getStyle() == DrawableButton::ImageLeftOfTextLabel) {
|
|
g.drawFittedText (button.getButtonText(),
|
|
button.getWidth() - textW - 4 , 1,
|
|
textW , button.getHeight() - 2,
|
|
Justification::centred, 2, 0.6f);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CustomLookAndFeel::drawBubble (Graphics& g, BubbleComponent& comp,
|
|
const Point<float>& tip, const Rectangle<float>& body)
|
|
{
|
|
Path p;
|
|
p.addBubble (body.reduced (0.5f), body.getUnion (Rectangle<float> (tip.x, tip.y, 1.0f, 1.0f)),
|
|
tip, 5.0f, jmin (10.0f, body.getWidth() * 0.2f, body.getHeight() * 0.2f));
|
|
|
|
g.setColour (comp.findColour (BubbleComponent::backgroundColourId));
|
|
g.fillPath (p);
|
|
|
|
g.setColour (comp.findColour (BubbleComponent::outlineColourId));
|
|
g.strokePath (p, PathStrokeType (1.0f));
|
|
}
|
|
|
|
|
|
CustomBigTextLookAndFeel::CustomBigTextLookAndFeel(float maxTextSize)
|
|
: maxSize(maxTextSize)
|
|
{
|
|
|
|
}
|
|
|
|
Font CustomBigTextLookAndFeel::getTextButtonFont (TextButton& button, int buttonHeight)
|
|
{
|
|
// DBG("GetTextButton font with height: " << buttonHeight << " maxsize: " << maxSize);
|
|
float textRatio = 0.8f;
|
|
//if (SonoTextButton* const textbutt = dynamic_cast<SonoTextButton*> (&button)) {
|
|
// textRatio = textbutt->getTextHeightRatio();
|
|
//}
|
|
|
|
return myFont.withHeight(jmin (maxSize, buttonHeight * textRatio) * fontScale);
|
|
}
|
|
|
|
Label* CustomBigTextLookAndFeel::createSliderTextBox (Slider& slider)
|
|
{
|
|
Label * lab = LookAndFeel_V4::createSliderTextBox(slider);
|
|
lab->setKeyboardType(TextInputTarget::decimalKeyboard);
|
|
lab->setFont(myFont.withHeight(maxSize * fontScale));
|
|
lab->setJustificationType(textJustification);
|
|
lab->setMinimumHorizontalScale(0.5);
|
|
|
|
return lab;
|
|
}
|
|
|
|
Button* CustomBigTextLookAndFeel::createSliderButton (Slider&, const bool isIncrement)
|
|
{
|
|
TextButton * butt = new TextButton (isIncrement ? "+" : "-", {});
|
|
butt->setLookAndFeel(this);
|
|
return butt;
|
|
}
|
|
|
|
|
|
void CustomBigTextLookAndFeel::drawToggleButton (Graphics& g, ToggleButton& button,
|
|
bool isMouseOverButton, bool isButtonDown)
|
|
{
|
|
/*
|
|
if (button.hasKeyboardFocus (true))
|
|
{
|
|
g.setColour (button.findColour (TextEditor::focusedOutlineColourId));
|
|
g.drawRect (0, 0, button.getWidth(), button.getHeight());
|
|
}
|
|
*/
|
|
|
|
float fontSize = jmin (maxSize, button.getHeight() * 0.75f) * fontScale;
|
|
const float tickWidth = fontSize * 1.1f;
|
|
|
|
drawTickBox (g, button, 4.0f, (button.getHeight() - tickWidth) * 0.5f,
|
|
tickWidth, tickWidth,
|
|
button.getToggleState(),
|
|
button.isEnabled(),
|
|
isMouseOverButton,
|
|
isButtonDown);
|
|
|
|
g.setColour (button.findColour (ToggleButton::textColourId));
|
|
g.setFont (myFont.withHeight(fontSize));
|
|
|
|
if (! button.isEnabled())
|
|
g.setOpacity (0.5f);
|
|
|
|
const int textX = (int) tickWidth + 10;
|
|
|
|
g.drawFittedText (button.getButtonText(),
|
|
textX, 0,
|
|
button.getWidth() - textX - 2, button.getHeight(),
|
|
Justification::centredLeft, 10);
|
|
}
|
|
|
|
|