Skip to content
Snippets Groups Projects
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);
    }


}