The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. LookAndFeel_V3::LookAndFeel_V3()
  18. {
  19. setColour (TreeView::selectedItemBackgroundColourId, Colour (0x301111ee));
  20. const Colour textButtonColour (0xffeeeeff);
  21. setColour (TextButton::buttonColourId, textButtonColour);
  22. setColour (ComboBox::buttonColourId, textButtonColour);
  23. setColour (TextEditor::outlineColourId, Colours::transparentBlack);
  24. setColour (ScrollBar::thumbColourId, Colour::greyLevel (0.8f).contrasting().withAlpha (0.13f));
  25. }
  26. LookAndFeel_V3::~LookAndFeel_V3() {}
  27. bool LookAndFeel_V3::areScrollbarButtonsVisible() { return false; }
  28. void LookAndFeel_V3::drawStretchableLayoutResizerBar (Graphics& g, int /*w*/, int /*h*/, bool /*isVerticalBar*/,
  29. bool isMouseOver, bool isMouseDragging)
  30. {
  31. if (isMouseOver || isMouseDragging)
  32. g.fillAll (Colours::yellow.withAlpha (0.4f));
  33. }
  34. void LookAndFeel_V3::drawScrollbar (Graphics& g, ScrollBar& scrollbar, int x, int y, int width, int height,
  35. bool isScrollbarVertical, int thumbStartPosition, int thumbSize, bool isMouseOver, bool isMouseDown)
  36. {
  37. Path thumbPath;
  38. if (thumbSize > 0)
  39. {
  40. const float thumbIndent = (isScrollbarVertical ? width : height) * 0.25f;
  41. const float thumbIndentx2 = thumbIndent * 2.0f;
  42. if (isScrollbarVertical)
  43. thumbPath.addRoundedRectangle (x + thumbIndent, thumbStartPosition + thumbIndent,
  44. width - thumbIndentx2, thumbSize - thumbIndentx2, (width - thumbIndentx2) * 0.5f);
  45. else
  46. thumbPath.addRoundedRectangle (thumbStartPosition + thumbIndent, y + thumbIndent,
  47. thumbSize - thumbIndentx2, height - thumbIndentx2, (height - thumbIndentx2) * 0.5f);
  48. }
  49. Colour thumbCol (scrollbar.findColour (ScrollBar::thumbColourId, true));
  50. if (isMouseOver || isMouseDown)
  51. thumbCol = thumbCol.withMultipliedAlpha (2.0f);
  52. g.setColour (thumbCol);
  53. g.fillPath (thumbPath);
  54. g.setColour (thumbCol.contrasting ((isMouseOver || isMouseDown) ? 0.2f : 0.1f));
  55. g.strokePath (thumbPath, PathStrokeType (1.0f));
  56. }
  57. void LookAndFeel_V3::drawConcertinaPanelHeader (Graphics& g, const Rectangle<int>& area,
  58. bool isMouseOver, bool /*isMouseDown*/,
  59. ConcertinaPanel&, Component& panel)
  60. {
  61. const Colour bkg (Colours::grey);
  62. g.setGradientFill (ColourGradient (Colours::white.withAlpha (isMouseOver ? 0.4f : 0.2f), 0, (float) area.getY(),
  63. Colours::darkgrey.withAlpha (0.2f), 0, (float) area.getBottom(), false));
  64. g.fillAll();
  65. g.setColour (bkg.contrasting().withAlpha (0.04f));
  66. g.fillRect (area.withHeight (1));
  67. g.fillRect (area.withTop (area.getBottom() - 1));
  68. g.setColour (bkg.contrasting());
  69. g.setFont (Font (area.getHeight() * 0.6f).boldened());
  70. g.drawFittedText (panel.getName(), 4, 0, area.getWidth() - 6, area.getHeight(), Justification::centredLeft, 1);
  71. }
  72. static void drawButtonShape (Graphics& g, const Path& outline, Colour baseColour, float height)
  73. {
  74. const float mainBrightness = baseColour.getBrightness();
  75. const float mainAlpha = baseColour.getFloatAlpha();
  76. g.setGradientFill (ColourGradient (baseColour.brighter (0.2f), 0.0f, 0.0f,
  77. baseColour.darker (0.25f), 0.0f, height, false));
  78. g.fillPath (outline);
  79. g.setColour (Colours::white.withAlpha (0.4f * mainAlpha * mainBrightness * mainBrightness));
  80. g.strokePath (outline, PathStrokeType (1.0f), AffineTransform::translation (0.0f, 1.0f)
  81. .scaled (1.0f, (height - 1.6f) / height));
  82. g.setColour (Colours::black.withAlpha (0.4f * mainAlpha));
  83. g.strokePath (outline, PathStrokeType (1.0f));
  84. }
  85. void LookAndFeel_V3::drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour,
  86. bool isMouseOverButton, bool isButtonDown)
  87. {
  88. Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f)
  89. .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f));
  90. if (isButtonDown || isMouseOverButton)
  91. baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f);
  92. const bool flatOnLeft = button.isConnectedOnLeft();
  93. const bool flatOnRight = button.isConnectedOnRight();
  94. const bool flatOnTop = button.isConnectedOnTop();
  95. const bool flatOnBottom = button.isConnectedOnBottom();
  96. const float width = button.getWidth() - 1.0f;
  97. const float height = button.getHeight() - 1.0f;
  98. if (width > 0 && height > 0)
  99. {
  100. const float cornerSize = 4.0f;
  101. Path outline;
  102. outline.addRoundedRectangle (0.5f, 0.5f, width, height, cornerSize, cornerSize,
  103. ! (flatOnLeft || flatOnTop),
  104. ! (flatOnRight || flatOnTop),
  105. ! (flatOnLeft || flatOnBottom),
  106. ! (flatOnRight || flatOnBottom));
  107. drawButtonShape (g, outline, baseColour, height);
  108. }
  109. }
  110. void LookAndFeel_V3::drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header)
  111. {
  112. Rectangle<int> r (header.getLocalBounds());
  113. g.setColour (Colours::black.withAlpha (0.5f));
  114. g.fillRect (r.removeFromBottom (1));
  115. g.setColour (Colours::white.withAlpha (0.6f));
  116. g.fillRect (r);
  117. g.setColour (Colours::black.withAlpha (0.5f));
  118. for (int i = header.getNumColumns (true); --i >= 0;)
  119. g.fillRect (header.getColumnPosition (i).removeFromRight (1));
  120. }
  121. int LookAndFeel_V3::getTabButtonOverlap (int /*tabDepth*/) { return -1; }
  122. int LookAndFeel_V3::getTabButtonSpaceAroundImage() { return 1; }
  123. void LookAndFeel_V3::createTabTextLayout (const TabBarButton& button, float length, float depth,
  124. Colour colour, TextLayout& textLayout)
  125. {
  126. Font font (depth * 0.5f);
  127. font.setUnderline (button.hasKeyboardFocus (false));
  128. AttributedString s;
  129. s.setJustification (Justification::centred);
  130. s.append (button.getButtonText().trim(), font, colour);
  131. textLayout.createLayout (s, length);
  132. }
  133. void LookAndFeel_V3::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
  134. {
  135. const Rectangle<int> activeArea (button.getActiveArea());
  136. const TabbedButtonBar::Orientation o = button.getTabbedButtonBar().getOrientation();
  137. const Colour bkg (button.getTabBackgroundColour());
  138. if (button.getToggleState())
  139. {
  140. g.setColour (bkg);
  141. g.fillRect (activeArea);
  142. }
  143. else
  144. {
  145. Point<int> p1, p2;
  146. switch (o)
  147. {
  148. case TabbedButtonBar::TabsAtBottom: p1 = activeArea.getBottomLeft(); p2 = activeArea.getTopLeft(); break;
  149. case TabbedButtonBar::TabsAtTop: p1 = activeArea.getTopLeft(); p2 = activeArea.getBottomLeft(); break;
  150. case TabbedButtonBar::TabsAtRight: p1 = activeArea.getTopRight(); p2 = activeArea.getTopLeft(); break;
  151. case TabbedButtonBar::TabsAtLeft: p1 = activeArea.getTopLeft(); p2 = activeArea.getTopRight(); break;
  152. default: jassertfalse; break;
  153. }
  154. g.setGradientFill (ColourGradient (bkg.brighter (0.2f), (float) p1.x, (float) p1.y,
  155. bkg.darker (0.1f), (float) p2.x, (float) p2.y, false));
  156. g.fillRect (activeArea);
  157. }
  158. g.setColour (bkg.contrasting (0.3f));
  159. Rectangle<int> r (activeArea);
  160. if (o != TabbedButtonBar::TabsAtBottom) g.fillRect (r.removeFromTop (1));
  161. if (o != TabbedButtonBar::TabsAtTop) g.fillRect (r.removeFromBottom (1));
  162. if (o != TabbedButtonBar::TabsAtRight) g.fillRect (r.removeFromLeft (1));
  163. if (o != TabbedButtonBar::TabsAtLeft) g.fillRect (r.removeFromRight (1));
  164. const float alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f;
  165. const Colour col (bkg.contrasting().withMultipliedAlpha (alpha));
  166. const Rectangle<float> area (button.getTextArea().toFloat());
  167. float length = area.getWidth();
  168. float depth = area.getHeight();
  169. if (button.getTabbedButtonBar().isVertical())
  170. std::swap (length, depth);
  171. TextLayout textLayout;
  172. createTabTextLayout (button, length, depth, col, textLayout);
  173. AffineTransform t;
  174. switch (o)
  175. {
  176. case TabbedButtonBar::TabsAtLeft: t = t.rotated (float_Pi * -0.5f).translated (area.getX(), area.getBottom()); break;
  177. case TabbedButtonBar::TabsAtRight: t = t.rotated (float_Pi * 0.5f).translated (area.getRight(), area.getY()); break;
  178. case TabbedButtonBar::TabsAtTop:
  179. case TabbedButtonBar::TabsAtBottom: t = t.translated (area.getX(), area.getY()); break;
  180. default: jassertfalse; break;
  181. }
  182. g.addTransform (t);
  183. textLayout.draw (g, Rectangle<float> (length, depth));
  184. }
  185. void LookAndFeel_V3::drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor)
  186. {
  187. if (textEditor.isEnabled())
  188. {
  189. if (textEditor.hasKeyboardFocus (true) && ! textEditor.isReadOnly())
  190. {
  191. g.setColour (textEditor.findColour (TextEditor::focusedOutlineColourId));
  192. g.drawRect (0, 0, width, height, 2);
  193. }
  194. else
  195. {
  196. g.setColour (textEditor.findColour (TextEditor::outlineColourId));
  197. g.drawRect (0, 0, width, height);
  198. }
  199. }
  200. }
  201. void LookAndFeel_V3::drawTreeviewPlusMinusBox (Graphics& g, const Rectangle<float>& area,
  202. Colour backgroundColour, bool isOpen, bool isMouseOver)
  203. {
  204. Path p;
  205. p.addTriangle (0.0f, 0.0f, 1.0f, isOpen ? 0.0f : 0.5f, isOpen ? 0.5f : 0.0f, 1.0f);
  206. g.setColour (backgroundColour.contrasting().withAlpha (isMouseOver ? 0.5f : 0.3f));
  207. g.fillPath (p, p.getTransformToScaleToFit (area.reduced (2, area.getHeight() / 4), true));
  208. }
  209. bool LookAndFeel_V3::areLinesDrawnForTreeView (TreeView&)
  210. {
  211. return false;
  212. }
  213. int LookAndFeel_V3::getTreeViewIndentSize (TreeView&)
  214. {
  215. return 20;
  216. }
  217. void LookAndFeel_V3::drawComboBox (Graphics& g, int width, int height, const bool isButtonDown,
  218. int buttonX, int buttonY, int buttonW, int buttonH, ComboBox& box)
  219. {
  220. g.fillAll (box.findColour (ComboBox::backgroundColourId));
  221. const Colour buttonColour (box.findColour (ComboBox::buttonColourId));
  222. if (box.isEnabled() && box.hasKeyboardFocus (false))
  223. {
  224. g.setColour (buttonColour);
  225. g.drawRect (0, 0, width, height, 2);
  226. }
  227. else
  228. {
  229. g.setColour (box.findColour (ComboBox::outlineColourId));
  230. g.drawRect (0, 0, width, height);
  231. }
  232. const float arrowX = 0.3f;
  233. const float arrowH = 0.2f;
  234. Path p;
  235. p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.45f - arrowH),
  236. buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.45f,
  237. buttonX + buttonW * arrowX, buttonY + buttonH * 0.45f);
  238. p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.55f + arrowH),
  239. buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.55f,
  240. buttonX + buttonW * arrowX, buttonY + buttonH * 0.55f);
  241. g.setColour (box.findColour (ComboBox::arrowColourId).withMultipliedAlpha (box.isEnabled() ? 1.0f : 0.3f));
  242. g.fillPath (p);
  243. }
  244. void LookAndFeel_V3::drawPopupMenuBackground (Graphics& g, int width, int height)
  245. {
  246. g.fillAll (findColour (PopupMenu::backgroundColourId));
  247. (void) width; (void) height;
  248. #if ! JUCE_MAC
  249. g.setColour (findColour (PopupMenu::textColourId).withAlpha (0.6f));
  250. g.drawRect (0, 0, width, height);
  251. #endif
  252. }
  253. void LookAndFeel_V3::drawMenuBarBackground (Graphics& g, int width, int height,
  254. bool, MenuBarComponent& menuBar)
  255. {
  256. const Colour colour (menuBar.findColour (PopupMenu::backgroundColourId));
  257. Rectangle<int> r (width, height);
  258. g.setColour (colour.contrasting (0.15f));
  259. g.fillRect (r.removeFromTop (1));
  260. g.fillRect (r.removeFromBottom (1));
  261. g.setGradientFill (ColourGradient (colour, 0, 0, colour.darker (0.08f), 0, height, false));
  262. g.fillRect (r);
  263. }
  264. void LookAndFeel_V3::drawKeymapChangeButton (Graphics& g, int width, int height,
  265. Button& button, const String& keyDescription)
  266. {
  267. const Colour textColour (button.findColour (0x100ad01 /*KeyMappingEditorComponent::textColourId*/, true));
  268. if (keyDescription.isNotEmpty())
  269. {
  270. if (button.isEnabled())
  271. {
  272. g.setColour (textColour.withAlpha (button.isDown() ? 0.4f : (button.isOver() ? 0.2f : 0.1f)));
  273. g.fillRoundedRectangle (button.getLocalBounds().toFloat(), 4.0f);
  274. g.drawRoundedRectangle (button.getLocalBounds().toFloat(), 4.0f, 1.0f);
  275. }
  276. g.setColour (textColour);
  277. g.setFont (height * 0.6f);
  278. g.drawFittedText (keyDescription, 4, 0, width - 8, height, Justification::centred, 1);
  279. }
  280. else
  281. {
  282. const float thickness = 7.0f;
  283. const float indent = 22.0f;
  284. Path p;
  285. p.addEllipse (0.0f, 0.0f, 100.0f, 100.0f);
  286. p.addRectangle (indent, 50.0f - thickness, 100.0f - indent * 2.0f, thickness * 2.0f);
  287. p.addRectangle (50.0f - thickness, indent, thickness * 2.0f, 50.0f - indent - thickness);
  288. p.addRectangle (50.0f - thickness, 50.0f + thickness, thickness * 2.0f, 50.0f - indent - thickness);
  289. p.setUsingNonZeroWinding (false);
  290. g.setColour (textColour.darker(0.1f).withAlpha (button.isDown() ? 0.7f : (button.isOver() ? 0.5f : 0.3f)));
  291. g.fillPath (p, p.getTransformToScaleToFit (2.0f, 2.0f, width - 4.0f, height - 4.0f, true));
  292. }
  293. if (button.hasKeyboardFocus (false))
  294. {
  295. g.setColour (textColour.withAlpha (0.4f));
  296. g.drawRect (0, 0, width, height);
  297. }
  298. }