CustomLookAndFeel.cpp 22.25 KiB
/*
------------------------------------------------------------------
This file is part of the Open Ephys GUI
Copyright (C) 2012 Open Ephys
------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CustomLookAndFeel.h"
CustomLookAndFeel::CustomLookAndFeel()
{
MemoryInputStream mis(BinaryData::misoserialized, BinaryData::misoserializedSize, false);
Miso = new CustomTypeface(mis);
enum {
PROCESSOR_COLOR = 0x801,
FILTER_COLOR = 0x802,
SINK_COLOR = 0x803,
SOURCE_COLOR = 0x804,
UTILITY_COLOR = 0x805,
};
setColour(PROCESSOR_COLOR, Colour(59, 59, 59));
setColour(FILTER_COLOR, Colour(255, 89, 0));
setColour(SINK_COLOR, Colour(255, 149, 0));
setColour(SOURCE_COLOR, Colour(255, 0, 0));
setColour(UTILITY_COLOR, Colour(90, 80, 80));
setColour(PopupMenu::backgroundColourId, Colours::darkgrey);
setColour(PopupMenu::textColourId, Colours::white);
setColour(PopupMenu::highlightedBackgroundColourId, Colours::grey);
setColour(PopupMenu::highlightedTextColourId, Colours::yellow);
}
CustomLookAndFeel::~CustomLookAndFeel() {}
// ===============
const Typeface::Ptr CustomLookAndFeel::getTypefaceForFont (const Font& font)
{
return Miso;
}
//==============================================================================
int CustomLookAndFeel::getTabButtonOverlap (int tabDepth)
{
return 0; //1 + tabDepth / 4;
}
int CustomLookAndFeel::getTabButtonSpaceAroundImage()
{
return 6;
}
void CustomLookAndFeel::drawTabButton (Graphics& g,
int w, int h,
const Colour& preferredColour,
int tabIndex,
const String& text,
Button& button,
TabbedButtonBar::Orientation orientation,
const bool isMouseOver,
const bool isMouseDown,
const bool isFrontTab)
{
int length = w;
int depth = h;
if (orientation == TabbedButtonBar::TabsAtLeft
|| orientation == TabbedButtonBar::TabsAtRight)
{
swapVariables (length, depth);
}
int borderSize = 3; // border between adjacent tabs
int innerBorderSize = 3;
int gapSize = 6; // gap between tab and tabbedComponent
float cornerSize = 5.0f; // how rounded should the corners be?
g.setColour(Colour(48,48,48));
if (orientation == TabbedButtonBar::TabsAtRight)
{
g.fillRoundedRectangle(gapSize, borderSize, w-gapSize, h-2*borderSize, cornerSize-2.0);
if (isFrontTab) {
g.setColour(Colour(48,48,48));
g.fillRect(0,borderSize,gapSize*2,h-2*borderSize);
g.fillRect(0,0,gapSize,h);
//g.setColour(Colour(170,178,183));
//g.fillRect(borderSize+innerBorderSize,innerBorderSize
// ,w-2*borderSize-2*innerBorderSize,h-gapSize-2*innerBorderSize);
g.setColour(Colour(0, 0, 0));
g.fillRoundedRectangle(0,h-borderSize,w,2*borderSize,cornerSize);
g.fillRoundedRectangle(0,-borderSize,w,2*borderSize,cornerSize);
}
}
else if (orientation == TabbedButtonBar::TabsAtTop)
{
g.fillRoundedRectangle(borderSize,0,w-2*borderSize,h-gapSize,cornerSize-2.0);
//g.setColour(Colour(170,178,183));
//g.fillRect(borderSize+innerBorderSize,innerBorderSize
// ,w-2*borderSize-2*innerBorderSize,h-gapSize-2*innerBorderSize);
if (isFrontTab) {
g.setColour(Colour(103,116,140));
g.fillRect(borderSize,h-2*gapSize,w-2*borderSize,2*gapSize);
g.fillRect(0,h-gapSize,w,gapSize);
//g.setColour(Colour(170,178,183));
//g.fillRect(borderSize+innerBorderSize,innerBorderSize
// ,w-2*borderSize-2*innerBorderSize,h-gapSize-2*innerBorderSize);
g.setColour(Colour(0,0,0));
g.fillRoundedRectangle(-borderSize,0,2*borderSize,h,cornerSize);
g.fillRoundedRectangle(w-borderSize,0,2*borderSize,h,cornerSize);
}
}
else if (orientation == TabbedButtonBar::TabsAtBottom)
{
g.fillRoundedRectangle(5,5,w-5,h-5,5);
if (isFrontTab)
g.fillRect(5,10,w-5,20);
}
else if (orientation == TabbedButtonBar::TabsAtLeft)
{
g.fillRoundedRectangle(5,5,w-5,h-5,5);
if (isFrontTab)
g.fillRect(5,10,w-5,20);
}
const int indent = getTabButtonOverlap (depth);
int x = 0, y = 0;
if (orientation == TabbedButtonBar::TabsAtLeft
|| orientation == TabbedButtonBar::TabsAtRight)
{
y += indent;
h -= indent * 2;
}
else
{
x += indent;
w -= indent * 2;
}
drawTabButtonText (g, x, y, w, h, preferredColour,
tabIndex, text, button, orientation,
isMouseOver, isMouseDown, isFrontTab);
}
void CustomLookAndFeel::drawTabButtonText (Graphics& g,
int x, int y, int w, int h,
const Colour& preferredBackgroundColour,
int /*tabIndex*/,
const String& text,
Button& button,
TabbedButtonBar::Orientation orientation,
const bool isMouseOver,
const bool isMouseDown,
const bool isFrontTab)
{
int length = w;
int depth = h;
if (orientation == TabbedButtonBar::TabsAtLeft
|| orientation == TabbedButtonBar::TabsAtRight)
{
swapVariables (length, depth);
}
Font font (depth * 0.6f);
font.setUnderline (button.hasKeyboardFocus (false));
GlyphArrangement textLayout;
textLayout.addFittedText (font, text.trim(),
0.0f, 0.0f, (float) length, (float) depth,
Justification::centred,
jmax (1, depth / 12));
AffineTransform transform;
if (orientation == TabbedButtonBar::TabsAtLeft)
{
transform = transform.rotated (float_Pi * -0.5f)
.translated ((float) x, (float) (y + h));
}
else if (orientation == TabbedButtonBar::TabsAtRight)
{
transform = transform.rotated (float_Pi * 0.5f)
.translated ((float) (x + w*1.1), (float) y);
}
else if (orientation == TabbedButtonBar::TabsAtTop)
{
transform = transform.translated ((float) x, (float) y - 3.0f);
}
else
{
transform = transform.translated ((float) x, (float) y + 3.0f);
}
// if (isFrontTab && (button.isColourSpecified (TabbedButtonBar::frontTextColourId) || isColourSpecified (TabbedButtonBar::frontTextColourId)))
// g.setColour (findColour (TabbedButtonBar::frontTextColourId));
// else if (button.isColourSpecified (TabbedButtonBar::tabTextColourId) || isColourSpecified (TabbedButtonBar::tabTextColourId))
// g.setColour (findColour (TabbedButtonBar::tabTextColourId));
// else
// g.setColour (preferredBackgroundColour.contrasting());
g.setColour(Colour(255,255,255));
if (! (isMouseOver || isMouseDown))
g.setOpacity (0.8f);
if (! button.isEnabled())
g.setOpacity (0.3f);
textLayout.draw (g, transform);
}
int CustomLookAndFeel::getTabButtonBestWidth (int /*tabIndex*/,
const String& text,
int tabDepth,
Button&)
{
Font f (tabDepth * 0.6f);
return f.getStringWidth (text.trim()) + getTabButtonOverlap (tabDepth) * 2 + 40;
}
void CustomLookAndFeel::drawTabAreaBehindFrontButton (Graphics& g,
int w, int h,
TabbedButtonBar& tabBar,
TabbedButtonBar::Orientation orientation)
{
}
//==================================================================
// SCROLL BAR METHODS :
//==================================================================
void CustomLookAndFeel::drawScrollbarButton (Graphics& g,
ScrollBar& scrollbar,
int width, int height,
int buttonDirection,
bool isScrollBarVertical,
bool isMouseOverButton,
bool isButtonDown)
{
Path p;
float w1 = 0.25f;
float w2 = 0.75f;
if (buttonDirection == 0)
p.addTriangle (width * 0.5f, height * 0.2f,
width * w1, height * 0.7f,
width * w2, height * 0.7f);
else if (buttonDirection == 1)
p.addTriangle (width * 0.8f, height * 0.5f,
width * 0.3f, height * w1,
width * 0.3f, height * w2);
else if (buttonDirection == 2)
p.addTriangle (width * 0.5f, height * 0.8f,
width * w1, height * 0.3f,
width * w2, height * 0.3f);
else if (buttonDirection == 3)
p.addTriangle (width * 0.2f, height * 0.5f,
width * 0.7f, height * w1,
width * 0.7f, height * w2);
if (isButtonDown)
g.setColour (Colours::white);
else
g.setColour (Colours::darkgrey);
g.fillPath (p);
if (isMouseOverButton)
g.strokePath (p, PathStrokeType (1.0f));
}
void CustomLookAndFeel::drawScrollbar (Graphics& g,
ScrollBar& scrollbar,
int x, int y,
int width, int height,
bool isScrollbarVertical,
int thumbStartPosition,
int thumbSize,
bool isMouseOver,
bool isMouseDown)
{
Path thumbPath;
const float slotIndent = jmin (width, height) > 15 ? 1.0f : 0.0f;
const float thumbIndent = slotIndent + 4.0f;
const float thumbIndentx2 = thumbIndent * 2.0f;
if (isScrollbarVertical)
{
if (thumbSize > 0)
thumbPath.addRoundedRectangle (x + thumbIndent,
thumbStartPosition + thumbIndent,
width - thumbIndentx2,
thumbSize - thumbIndentx2,
(width - thumbIndentx2) * 0.3f);
}
else
{
if (thumbSize > 0)
thumbPath.addRoundedRectangle (thumbStartPosition + thumbIndent,
y + thumbIndent,
thumbSize - thumbIndentx2,
height - thumbIndentx2,
(height - thumbIndentx2) * 0.3f);
}
g.setColour (Colours::darkgrey);
g.fillPath (thumbPath);
}
//==================================================================
// SLIDER METHODS :
//==================================================================
void CustomLookAndFeel::drawLinearSliderThumb (Graphics& g,
int x, int y,
int width, int height,
float sliderPos,
float minSliderPos,
float maxSliderPos,
const Slider::SliderStyle style,
Slider& slider)
{
const float sliderRadius = (float) (getSliderThumbRadius (slider) - 2);
Colour knobColour (Colours::darkgrey);//LookAndFeelHelpers::createBaseColour (slider.findColour (Slider::thumbColourId),
// slider.hasKeyboardFocus (false) && slider.isEnabled(),
// slider.isMouseOverOrDragging() && slider.isEnabled(),
// slider.isMouseButtonDown() && slider.isEnabled()));
const float outlineThickness = slider.isEnabled() ? 2.0f : 0.5f;
if (style == Slider::LinearHorizontal || style == Slider::LinearVertical)
{
float kx, ky;
if (style == Slider::LinearVertical)
{
kx = x + width * 0.5f;
ky = sliderPos;
}
else
{
kx = sliderPos;
ky = y + height * 0.5f;
}
drawSliderKnob (g,
kx - sliderRadius,
ky - sliderRadius,
sliderRadius * 2.0f,
knobColour, outlineThickness);
}
else
{
if (style == Slider::ThreeValueVertical)
{
drawSliderKnob (g, x + width * 0.5f - sliderRadius,
sliderPos - sliderRadius,
sliderRadius * 2.0f,
knobColour, outlineThickness);
}
else if (style == Slider::ThreeValueHorizontal)
{
drawSliderKnob (g,sliderPos - sliderRadius,
y + height * 0.5f - sliderRadius,
sliderRadius * 2.0f,
knobColour, outlineThickness);
}
if (style == Slider::TwoValueVertical || style == Slider::ThreeValueVertical)
{
const float sr = jmin (sliderRadius, width * 0.4f);
drawGlassPointer (g, jmax (0.0f, x + width * 0.5f - sliderRadius * 2.0f),
minSliderPos - sliderRadius,
sliderRadius * 2.0f, knobColour, outlineThickness, 1);
drawGlassPointer (g, jmin (x + width - sliderRadius * 2.0f, x + width * 0.5f), maxSliderPos - sr,
sliderRadius * 2.0f, knobColour, outlineThickness, 3);
}
else if (style == Slider::TwoValueHorizontal || style == Slider::ThreeValueHorizontal)
{
const float sr = jmin (sliderRadius, height * 0.4f);
drawGlassPointer (g, minSliderPos - sr,
jmax (0.0f, y + height * 0.5f - sliderRadius * 2.0f),
sliderRadius * 2.0f, knobColour, outlineThickness, 2);
drawGlassPointer (g, maxSliderPos - sliderRadius,
jmin (y + height - sliderRadius * 2.0f, y + height * 0.5f),
sliderRadius * 2.0f, knobColour, outlineThickness, 4);
}
}
}
void CustomLookAndFeel::drawLinearSliderBackground (Graphics& g,
int x, int y,
int width, int height,
float sliderPos,
float minSliderPos,
float maxSliderPos,
const Slider::SliderStyle /*style*/,
Slider& slider)
{
const float sliderRadius = (float) (getSliderThumbRadius (slider) - 2);
Path indent;
// Path backgroundPath;
if (slider.isHorizontal())
{
const float iy = y + height * 0.5f - sliderRadius * 0.5f;
const float ih = sliderRadius;
indent.addRoundedRectangle (x - sliderRadius * 0.5f, iy,
width + sliderRadius, ih,
5.0f);
// backgroundPath.addRoundedRectangle (x - sliderRadius * 0.5f, iy,
// (width + sliderRadius)*minSliderPos, ih,
// 5.0f);
// g.setColour(Colours::orange);
// g.fillPath (backgroundPath);
}
else
{
const float ix = x + width * 0.5f - sliderRadius * 0.5f;
const float iw = sliderRadius;
indent.addRoundedRectangle (ix, y - sliderRadius * 0.5f,
iw, height + sliderRadius,
5.0f);
// backgroundPath.addRoundedRectangle (ix, y - sliderRadius * 0.5f,
// iw, (height + sliderRadius)*sliderPos,
// 5.0f);
// g.setColour(Colours::orange);
// g.fillPath (backgroundPath);
//g.fillPath (indent);
}
g.setColour (Colours::darkgrey);
g.strokePath (indent, PathStrokeType (0.5f));
}
int CustomLookAndFeel::getSliderThumbRadius (Slider& slider)
{
return jmin (7,
slider.getHeight() / 2,
slider.getWidth() / 2) + 2;
}
void CustomLookAndFeel::drawSliderKnob (Graphics& g,
const float x, const float y,
const float diameter,
const Colour& colour,
const float outlineThickness) throw()
{
if (diameter <= outlineThickness)
return;
g.setColour(Colours::darkgrey);
g.fillEllipse (x, y, diameter, diameter);
g.setColour(Colours::black);
g.drawEllipse (x, y, diameter, diameter, outlineThickness);
}
void CustomLookAndFeel::drawGlassPointer (Graphics& g,
const float x, const float y,
const float diameter,
const Colour& colour, const float outlineThickness,
const int direction) throw()
{
if (diameter <= outlineThickness)
return;
Path p;
p.startNewSubPath (x + diameter * 0.5f, y);
p.lineTo (x + diameter, y + diameter * 0.6f);
p.lineTo (x + diameter, y + diameter);
p.lineTo (x, y + diameter);
p.lineTo (x, y + diameter * 0.6f);
p.closeSubPath();
p.applyTransform (AffineTransform::rotation (direction * (float_Pi * 0.5f), x + diameter * 0.5f, y + diameter * 0.5f));
{
ColourGradient cg (Colours::white.overlaidWith (colour.withMultipliedAlpha (0.3f)), 0, y,
Colours::white.overlaidWith (colour.withMultipliedAlpha (0.3f)), 0, y + diameter, false);
cg.addColour (0.4, Colours::white.overlaidWith (colour));
g.setGradientFill (cg);
g.fillPath (p);
}
ColourGradient cg (Colours::transparentBlack,
x + diameter * 0.5f, y + diameter * 0.5f,
Colours::black.withAlpha (0.5f * outlineThickness * colour.getFloatAlpha()),
x - diameter * 0.2f, y + diameter * 0.5f, true);
cg.addColour (0.5, Colours::transparentBlack);
cg.addColour (0.7, Colours::black.withAlpha (0.07f * outlineThickness));
g.setGradientFill (cg);
g.fillPath (p);
g.setColour (Colours::black.withAlpha (0.5f * colour.getFloatAlpha()));
g.strokePath (p, PathStrokeType (outlineThickness));
}
/// ------ combo box ---------------///
void CustomLookAndFeel::drawComboBox (Graphics& g, int width, int height,
const bool isButtonDown,
int buttonX, int buttonY,
int buttonW, int buttonH,
ComboBox& box)
{
g.fillAll (Colours::lightgrey);//box.findColour (ComboBox::backgroundColourId));
if (box.isEnabled() && box.hasKeyboardFocus (false))
{
g.setColour (Colours::lightgrey);//box.findColour (TextButton::buttonColourId));
g.drawRect (0, 0, width, height, 2);
}
else
{
g.setColour (box.findColour (ComboBox::outlineColourId));
g.drawRect (0, 0, width, height);
}
const float outlineThickness = box.isEnabled() ? (isButtonDown ? 1.2f : 0.5f) : 0.3f;
const Colour baseColour (Colours::orange);/*LookAndFeelHelpers::createBaseColour (box.findColour (ComboBox::buttonColourId),
box.hasKeyboardFocus (true),
false, isButtonDown)
.withMultipliedAlpha (box.isEnabled() ? 1.0f : 0.5f));*/
drawGlassLozenge (g,
buttonX + outlineThickness, buttonY + outlineThickness,
buttonW - outlineThickness * 2.0f, buttonH - outlineThickness * 2.0f,
baseColour, outlineThickness, -1.0f,
true, true, true, true);
if (box.isEnabled())
{
const float arrowX = 0.3f;
const float arrowH = 0.2f;
Path p;
p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.45f - arrowH),
buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.45f,
buttonX + buttonW * arrowX, buttonY + buttonH * 0.45f);
p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.55f + arrowH),
buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.55f,
buttonX + buttonW * arrowX, buttonY + buttonH * 0.55f);
g.setColour (box.findColour (ComboBox::arrowColourId));
g.fillPath (p);
}
}