/* ------------------------------------------------------------------ This file is part of the Open Ephys GUI Copyright (C) 2013 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" #include "CustomArrowButton.h" CustomLookAndFeel::CustomLookAndFeel() : // third argument to MIS means don't copy the binary data to make a new stream cpmonoExtraLightStream(BinaryData::cpmonoextralightserialized, BinaryData::cpmonoextralightserializedSize, false), cpmonoLightStream(BinaryData::cpmonolightserialized, BinaryData::cpmonolightserializedSize, false), cpmonoPlainStream(BinaryData::cpmonoplainserialized, BinaryData::cpmonoplainserializedSize, false), cpmonoBoldStream(BinaryData::cpmonoboldserialized, BinaryData::cpmonoboldserializedSize, false), cpmonoBlackStream(BinaryData::cpmonoblackserialized, BinaryData::cpmonoblackserializedSize, false), misoRegularStream(BinaryData::misoserialized, BinaryData::misoserializedSize, false), silkscreenStream(BinaryData::silkscreenserialized, BinaryData::silkscreenserializedSize, false), // heap allocation is necessary here, because otherwise the typefaces are // deleted too soon (there's a singleton typefacecache that holds references // to them whenever they're used). cpmonoExtraLight(new CustomTypeface(cpmonoExtraLightStream)), cpmonoLight(new CustomTypeface(cpmonoLightStream)), cpmonoPlain(new CustomTypeface(cpmonoPlainStream)), cpmonoBold(new CustomTypeface(cpmonoBoldStream)), cpmonoBlack(new CustomTypeface(cpmonoBlackStream)), misoRegular(new CustomTypeface(misoRegularStream)), silkscreen(new CustomTypeface(silkscreenStream)) { // UNCOMMENT AFTER UPDATE // typefaceMap.set(String("Default Extra Light"), cpmonoExtraLight); // typefaceMap.set(String("Default Light"), cpmonoLight); // typefaceMap.set(String("Default"), cpmonoPlain); // typefaceMap.set(String("Default Bold"), cpmonoBold); // typefaceMap.set(String("Default Black"), cpmonoBlack); // typefaceMap.set(String("Paragraph"), misoRegular); // typefaceMap.set(String("Silkscreen"), silkscreen); 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() {} //============================================================================== // FONT/TYPEFACE METHODS : //============================================================================== Typeface::Ptr CustomLookAndFeel::getTypefaceForFont(const Font& font) { String typefaceName = font.getTypefaceName(); // some of these names might be unnecessary, and there may be good ones // missing. adjust as needed if (typefaceName.equalsIgnoreCase("Default Extra Light")) { return cpmonoExtraLight; } else if (typefaceName.equalsIgnoreCase("Default Light")) { return cpmonoLight; } else if (typefaceName.equalsIgnoreCase("Default")) { return cpmonoPlain; } else if (typefaceName.equalsIgnoreCase("Default Bold")) { return cpmonoBold; } else if (typefaceName.equalsIgnoreCase("Default Black")) { return cpmonoBlack; } else if (typefaceName.equalsIgnoreCase("Paragraph")) { return misoRegular; } else if (typefaceName.equalsIgnoreCase("Small Text")) { return silkscreen; } else // default { return LookAndFeel::getTypefaceForFont(font); } // UNCOMMENT AFTER UPDATE // if (typefaceMap.contains(typefaceName)) // return typefaceMap[typefaceName]; // else // return LookAndFeel::getTypefaceForFont(font); } //================================================================== // 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)); } Button* CustomLookAndFeel::createSliderButton(Slider& s, bool isIncrement) { return new CustomArrowButton(String::empty, isIncrement ? 0 : 0.5); } /// ------ 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));*/ juce::LookAndFeel_V1::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); } }