Audio plugin host https://kx.studio/carla
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.

646 lines
26KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. LookAndFeel_V3::LookAndFeel_V3()
  21. {
  22. setColour (TreeView::selectedItemBackgroundColourId, Colour (0x301111ee));
  23. const Colour textButtonColour (0xffeeeeff);
  24. setColour (TextButton::buttonColourId, textButtonColour);
  25. setColour (TextButton::buttonOnColourId, Colour (0xff888888));
  26. setColour (ComboBox::buttonColourId, textButtonColour);
  27. setColour (ComboBox::focusedOutlineColourId, textButtonColour);
  28. setColour (TextEditor::outlineColourId, Colours::transparentBlack);
  29. setColour (TabbedButtonBar::tabOutlineColourId, Colour (0x66000000));
  30. setColour (TabbedComponent::outlineColourId, Colour (0x66000000));
  31. setColour (Slider::trackColourId, Colour (0xbbffffff));
  32. setColour (Slider::thumbColourId, Colour (0xffddddff));
  33. setColour (BubbleComponent::backgroundColourId, Colour (0xeeeeeedd));
  34. setColour (ScrollBar::thumbColourId, Colour::greyLevel (0.8f).contrasting().withAlpha (0.13f));
  35. setColour (TableHeaderComponent::backgroundColourId, Colours::white.withAlpha (0.6f));
  36. setColour (TableHeaderComponent::outlineColourId, Colours::black.withAlpha (0.5f));
  37. }
  38. LookAndFeel_V3::~LookAndFeel_V3() {}
  39. bool LookAndFeel_V3::areScrollbarButtonsVisible() { return false; }
  40. void LookAndFeel_V3::drawStretchableLayoutResizerBar (Graphics& g, int /*w*/, int /*h*/, bool /*isVerticalBar*/,
  41. bool isMouseOver, bool isMouseDragging)
  42. {
  43. if (isMouseOver || isMouseDragging)
  44. g.fillAll (Colours::yellow.withAlpha (0.4f));
  45. }
  46. void LookAndFeel_V3::drawScrollbar (Graphics& g, ScrollBar& scrollbar, int x, int y, int width, int height,
  47. bool isScrollbarVertical, int thumbStartPosition, int thumbSize, bool isMouseOver, bool isMouseDown)
  48. {
  49. Path thumbPath;
  50. if (thumbSize > 0)
  51. {
  52. const float thumbIndent = (float) (isScrollbarVertical ? width : height) * 0.25f;
  53. const float thumbIndentx2 = thumbIndent * 2.0f;
  54. if (isScrollbarVertical)
  55. thumbPath.addRoundedRectangle ((float) x + thumbIndent, (float) thumbStartPosition + thumbIndent,
  56. (float) width - thumbIndentx2, (float) thumbSize - thumbIndentx2, ((float) width - thumbIndentx2) * 0.5f);
  57. else
  58. thumbPath.addRoundedRectangle ((float) thumbStartPosition + thumbIndent, (float) y + thumbIndent,
  59. (float) thumbSize - thumbIndentx2, (float) height - thumbIndentx2, ((float) height - thumbIndentx2) * 0.5f);
  60. }
  61. Colour thumbCol (scrollbar.findColour (ScrollBar::thumbColourId, true));
  62. if (isMouseOver || isMouseDown)
  63. thumbCol = thumbCol.withMultipliedAlpha (2.0f);
  64. g.setColour (thumbCol);
  65. g.fillPath (thumbPath);
  66. g.setColour (thumbCol.contrasting ((isMouseOver || isMouseDown) ? 0.2f : 0.1f));
  67. g.strokePath (thumbPath, PathStrokeType (1.0f));
  68. }
  69. void LookAndFeel_V3::drawConcertinaPanelHeader (Graphics& g, const Rectangle<int>& area,
  70. bool isMouseOver, bool /*isMouseDown*/,
  71. ConcertinaPanel&, Component& panel)
  72. {
  73. const Colour bkg (Colours::grey);
  74. g.setGradientFill (ColourGradient::vertical (Colours::white.withAlpha (isMouseOver ? 0.4f : 0.2f), (float) area.getY(),
  75. Colours::darkgrey.withAlpha (0.1f), (float) area.getBottom()));
  76. g.fillAll();
  77. g.setColour (bkg.contrasting().withAlpha (0.1f));
  78. g.fillRect (area.withHeight (1));
  79. g.fillRect (area.withTop (area.getBottom() - 1));
  80. g.setColour (bkg.contrasting());
  81. g.setFont (Font ((float) area.getHeight() * 0.6f).boldened());
  82. g.drawFittedText (panel.getName(), 4, 0, area.getWidth() - 6, area.getHeight(), Justification::centredLeft, 1);
  83. }
  84. static void drawButtonShape (Graphics& g, const Path& outline, Colour baseColour, float height)
  85. {
  86. const float mainBrightness = baseColour.getBrightness();
  87. const float mainAlpha = baseColour.getFloatAlpha();
  88. g.setGradientFill (ColourGradient::vertical (baseColour.brighter (0.2f), 0.0f,
  89. baseColour.darker (0.25f), height));
  90. g.fillPath (outline);
  91. g.setColour (Colours::white.withAlpha (0.4f * mainAlpha * mainBrightness * mainBrightness));
  92. g.strokePath (outline, PathStrokeType (1.0f), AffineTransform::translation (0.0f, 1.0f)
  93. .scaled (1.0f, (height - 1.6f) / height));
  94. g.setColour (Colours::black.withAlpha (0.4f * mainAlpha));
  95. g.strokePath (outline, PathStrokeType (1.0f));
  96. }
  97. void LookAndFeel_V3::drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour,
  98. bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown)
  99. {
  100. Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f)
  101. .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f));
  102. if (shouldDrawButtonAsDown || shouldDrawButtonAsHighlighted)
  103. baseColour = baseColour.contrasting (shouldDrawButtonAsDown ? 0.2f : 0.1f);
  104. const bool flatOnLeft = button.isConnectedOnLeft();
  105. const bool flatOnRight = button.isConnectedOnRight();
  106. const bool flatOnTop = button.isConnectedOnTop();
  107. const bool flatOnBottom = button.isConnectedOnBottom();
  108. const float width = (float) button.getWidth() - 1.0f;
  109. const float height = (float) button.getHeight() - 1.0f;
  110. if (width > 0 && height > 0)
  111. {
  112. const float cornerSize = 4.0f;
  113. Path outline;
  114. outline.addRoundedRectangle (0.5f, 0.5f, width, height, cornerSize, cornerSize,
  115. ! (flatOnLeft || flatOnTop),
  116. ! (flatOnRight || flatOnTop),
  117. ! (flatOnLeft || flatOnBottom),
  118. ! (flatOnRight || flatOnBottom));
  119. drawButtonShape (g, outline, baseColour, height);
  120. }
  121. }
  122. void LookAndFeel_V3::drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header)
  123. {
  124. auto r = header.getLocalBounds();
  125. auto outlineColour = header.findColour (TableHeaderComponent::outlineColourId);
  126. g.setColour (outlineColour);
  127. g.fillRect (r.removeFromBottom (1));
  128. g.setColour (header.findColour (TableHeaderComponent::backgroundColourId));
  129. g.fillRect (r);
  130. g.setColour (outlineColour);
  131. for (int i = header.getNumColumns (true); --i >= 0;)
  132. g.fillRect (header.getColumnPosition (i).removeFromRight (1));
  133. }
  134. int LookAndFeel_V3::getTabButtonOverlap (int /*tabDepth*/) { return -1; }
  135. int LookAndFeel_V3::getTabButtonSpaceAroundImage() { return 0; }
  136. void LookAndFeel_V3::createTabTextLayout (const TabBarButton& button, float length, float depth,
  137. Colour colour, TextLayout& textLayout)
  138. {
  139. Font font (depth * 0.5f);
  140. font.setUnderline (button.hasKeyboardFocus (false));
  141. AttributedString s;
  142. s.setJustification (Justification::centred);
  143. s.append (button.getButtonText().trim(), font, colour);
  144. textLayout.createLayout (s, length);
  145. }
  146. void LookAndFeel_V3::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
  147. {
  148. const Rectangle<int> activeArea (button.getActiveArea());
  149. const TabbedButtonBar::Orientation o = button.getTabbedButtonBar().getOrientation();
  150. const Colour bkg (button.getTabBackgroundColour());
  151. if (button.getToggleState())
  152. {
  153. g.setColour (bkg);
  154. }
  155. else
  156. {
  157. Point<int> p1, p2;
  158. switch (o)
  159. {
  160. case TabbedButtonBar::TabsAtBottom: p1 = activeArea.getBottomLeft(); p2 = activeArea.getTopLeft(); break;
  161. case TabbedButtonBar::TabsAtTop: p1 = activeArea.getTopLeft(); p2 = activeArea.getBottomLeft(); break;
  162. case TabbedButtonBar::TabsAtRight: p1 = activeArea.getTopRight(); p2 = activeArea.getTopLeft(); break;
  163. case TabbedButtonBar::TabsAtLeft: p1 = activeArea.getTopLeft(); p2 = activeArea.getTopRight(); break;
  164. default: jassertfalse; break;
  165. }
  166. g.setGradientFill (ColourGradient (bkg.brighter (0.2f), p1.toFloat(),
  167. bkg.darker (0.1f), p2.toFloat(), false));
  168. }
  169. g.fillRect (activeArea);
  170. g.setColour (button.findColour (TabbedButtonBar::tabOutlineColourId));
  171. Rectangle<int> r (activeArea);
  172. if (o != TabbedButtonBar::TabsAtBottom) g.fillRect (r.removeFromTop (1));
  173. if (o != TabbedButtonBar::TabsAtTop) g.fillRect (r.removeFromBottom (1));
  174. if (o != TabbedButtonBar::TabsAtRight) g.fillRect (r.removeFromLeft (1));
  175. if (o != TabbedButtonBar::TabsAtLeft) g.fillRect (r.removeFromRight (1));
  176. const float alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f;
  177. Colour col (bkg.contrasting().withMultipliedAlpha (alpha));
  178. if (TabbedButtonBar* bar = button.findParentComponentOfClass<TabbedButtonBar>())
  179. {
  180. TabbedButtonBar::ColourIds colID = button.isFrontTab() ? TabbedButtonBar::frontTextColourId
  181. : TabbedButtonBar::tabTextColourId;
  182. if (bar->isColourSpecified (colID))
  183. col = bar->findColour (colID);
  184. else if (isColourSpecified (colID))
  185. col = findColour (colID);
  186. }
  187. const Rectangle<float> area (button.getTextArea().toFloat());
  188. float length = area.getWidth();
  189. float depth = area.getHeight();
  190. if (button.getTabbedButtonBar().isVertical())
  191. std::swap (length, depth);
  192. TextLayout textLayout;
  193. createTabTextLayout (button, length, depth, col, textLayout);
  194. AffineTransform t;
  195. switch (o)
  196. {
  197. case TabbedButtonBar::TabsAtLeft: t = t.rotated (MathConstants<float>::pi * -0.5f).translated (area.getX(), area.getBottom()); break;
  198. case TabbedButtonBar::TabsAtRight: t = t.rotated (MathConstants<float>::pi * 0.5f).translated (area.getRight(), area.getY()); break;
  199. case TabbedButtonBar::TabsAtTop:
  200. case TabbedButtonBar::TabsAtBottom: t = t.translated (area.getX(), area.getY()); break;
  201. default: jassertfalse; break;
  202. }
  203. g.addTransform (t);
  204. textLayout.draw (g, Rectangle<float> (length, depth));
  205. }
  206. void LookAndFeel_V3::drawTabAreaBehindFrontButton (TabbedButtonBar& bar, Graphics& g, const int w, const int h)
  207. {
  208. const float shadowSize = 0.15f;
  209. Rectangle<int> shadowRect, line;
  210. ColourGradient gradient (Colours::black.withAlpha (bar.isEnabled() ? 0.08f : 0.04f), 0, 0,
  211. Colours::transparentBlack, 0, 0, false);
  212. switch (bar.getOrientation())
  213. {
  214. case TabbedButtonBar::TabsAtLeft:
  215. gradient.point1.x = (float) w;
  216. gradient.point2.x = (float) w * (1.0f - shadowSize);
  217. shadowRect.setBounds ((int) gradient.point2.x, 0, w - (int) gradient.point2.x, h);
  218. line.setBounds (w - 1, 0, 1, h);
  219. break;
  220. case TabbedButtonBar::TabsAtRight:
  221. gradient.point2.x = (float) w * shadowSize;
  222. shadowRect.setBounds (0, 0, (int) gradient.point2.x, h);
  223. line.setBounds (0, 0, 1, h);
  224. break;
  225. case TabbedButtonBar::TabsAtTop:
  226. gradient.point1.y = (float) h;
  227. gradient.point2.y = (float) h * (1.0f - shadowSize);
  228. shadowRect.setBounds (0, (int) gradient.point2.y, w, h - (int) gradient.point2.y);
  229. line.setBounds (0, h - 1, w, 1);
  230. break;
  231. case TabbedButtonBar::TabsAtBottom:
  232. gradient.point2.y = (float) h * shadowSize;
  233. shadowRect.setBounds (0, 0, w, (int) gradient.point2.y);
  234. line.setBounds (0, 0, w, 1);
  235. break;
  236. default: break;
  237. }
  238. g.setGradientFill (gradient);
  239. g.fillRect (shadowRect.expanded (2, 2));
  240. g.setColour (bar.findColour (TabbedButtonBar::tabOutlineColourId));
  241. g.fillRect (line);
  242. }
  243. void LookAndFeel_V3::drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor)
  244. {
  245. if (textEditor.isEnabled())
  246. {
  247. if (textEditor.hasKeyboardFocus (true) && ! textEditor.isReadOnly())
  248. {
  249. g.setColour (textEditor.findColour (TextEditor::focusedOutlineColourId));
  250. g.drawRect (0, 0, width, height, 2);
  251. }
  252. else
  253. {
  254. g.setColour (textEditor.findColour (TextEditor::outlineColourId));
  255. g.drawRect (0, 0, width, height);
  256. }
  257. }
  258. }
  259. void LookAndFeel_V3::drawTreeviewPlusMinusBox (Graphics& g, const Rectangle<float>& area,
  260. Colour backgroundColour, bool isOpen, bool isMouseOver)
  261. {
  262. Path p;
  263. p.addTriangle (0.0f, 0.0f, 1.0f, isOpen ? 0.0f : 0.5f, isOpen ? 0.5f : 0.0f, 1.0f);
  264. g.setColour (backgroundColour.contrasting().withAlpha (isMouseOver ? 0.5f : 0.3f));
  265. g.fillPath (p, p.getTransformToScaleToFit (area.reduced (2, area.getHeight() / 4), true));
  266. }
  267. bool LookAndFeel_V3::areLinesDrawnForTreeView (TreeView&)
  268. {
  269. return false;
  270. }
  271. int LookAndFeel_V3::getTreeViewIndentSize (TreeView&)
  272. {
  273. return 20;
  274. }
  275. void LookAndFeel_V3::drawComboBox (Graphics& g, int width, int height, const bool /*isMouseButtonDown*/,
  276. int buttonX, int buttonY, int buttonW, int buttonH, ComboBox& box)
  277. {
  278. g.fillAll (box.findColour (ComboBox::backgroundColourId));
  279. if (box.isEnabled() && box.hasKeyboardFocus (false))
  280. {
  281. g.setColour (box.findColour (ComboBox::focusedOutlineColourId));
  282. g.drawRect (0, 0, width, height, 2);
  283. }
  284. else
  285. {
  286. g.setColour (box.findColour (ComboBox::outlineColourId));
  287. g.drawRect (0, 0, width, height);
  288. }
  289. const float arrowX = 0.3f;
  290. const float arrowH = 0.2f;
  291. const auto x = (float) buttonX;
  292. const auto y = (float) buttonY;
  293. const auto w = (float) buttonW;
  294. const auto h = (float) buttonH;
  295. Path p;
  296. p.addTriangle (x + w * 0.5f, y + h * (0.45f - arrowH),
  297. x + w * (1.0f - arrowX), y + h * 0.45f,
  298. x + w * arrowX, y + h * 0.45f);
  299. p.addTriangle (x + w * 0.5f, y + h * (0.55f + arrowH),
  300. x + w * (1.0f - arrowX), y + h * 0.55f,
  301. x + w * arrowX, y + h * 0.55f);
  302. g.setColour (box.findColour (ComboBox::arrowColourId).withMultipliedAlpha (box.isEnabled() ? 1.0f : 0.3f));
  303. g.fillPath (p);
  304. }
  305. void LookAndFeel_V3::drawLinearSlider (Graphics& g, int x, int y, int width, int height,
  306. float sliderPos, float minSliderPos, float maxSliderPos,
  307. const Slider::SliderStyle style, Slider& slider)
  308. {
  309. g.fillAll (slider.findColour (Slider::backgroundColourId));
  310. if (style == Slider::LinearBar || style == Slider::LinearBarVertical)
  311. {
  312. const float fx = (float) x, fy = (float) y, fw = (float) width, fh = (float) height;
  313. Path p;
  314. if (style == Slider::LinearBarVertical)
  315. p.addRectangle (fx, sliderPos, fw, 1.0f + fh - sliderPos);
  316. else
  317. p.addRectangle (fx, fy, sliderPos - fx, fh);
  318. auto baseColour = slider.findColour (Slider::thumbColourId)
  319. .withMultipliedSaturation (slider.isEnabled() ? 1.0f : 0.5f)
  320. .withMultipliedAlpha (0.8f);
  321. g.setGradientFill (ColourGradient::vertical (baseColour.brighter (0.08f), 0.0f,
  322. baseColour.darker (0.08f), (float) height));
  323. g.fillPath (p);
  324. g.setColour (baseColour.darker (0.2f));
  325. if (style == Slider::LinearBarVertical)
  326. g.fillRect (fx, sliderPos, fw, 1.0f);
  327. else
  328. g.fillRect (sliderPos, fy, 1.0f, fh);
  329. }
  330. else
  331. {
  332. drawLinearSliderBackground (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  333. drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  334. }
  335. }
  336. void LookAndFeel_V3::drawLinearSliderBackground (Graphics& g, int x, int y, int width, int height,
  337. float /*sliderPos*/,
  338. float /*minSliderPos*/,
  339. float /*maxSliderPos*/,
  340. const Slider::SliderStyle /*style*/, Slider& slider)
  341. {
  342. const float sliderRadius = (float) (getSliderThumbRadius (slider) - 2);
  343. const Colour trackColour (slider.findColour (Slider::trackColourId));
  344. const Colour gradCol1 (trackColour.overlaidWith (Colour (slider.isEnabled() ? 0x13000000 : 0x09000000)));
  345. const Colour gradCol2 (trackColour.overlaidWith (Colour (0x06000000)));
  346. Path indent;
  347. if (slider.isHorizontal())
  348. {
  349. auto iy = (float) y + (float) height * 0.5f - sliderRadius * 0.5f;
  350. g.setGradientFill (ColourGradient::vertical (gradCol1, iy, gradCol2, iy + sliderRadius));
  351. indent.addRoundedRectangle ((float) x - sliderRadius * 0.5f, iy, (float) width + sliderRadius, sliderRadius, 5.0f);
  352. }
  353. else
  354. {
  355. auto ix = (float) x + (float) width * 0.5f - sliderRadius * 0.5f;
  356. g.setGradientFill (ColourGradient::horizontal (gradCol1, ix, gradCol2, ix + sliderRadius));
  357. indent.addRoundedRectangle (ix, (float) y - sliderRadius * 0.5f, sliderRadius, (float) height + sliderRadius, 5.0f);
  358. }
  359. g.fillPath (indent);
  360. g.setColour (trackColour.contrasting (0.5f));
  361. g.strokePath (indent, PathStrokeType (0.5f));
  362. }
  363. void LookAndFeel_V3::drawPopupMenuBackground (Graphics& g, int width, int height)
  364. {
  365. g.fillAll (findColour (PopupMenu::backgroundColourId));
  366. ignoreUnused (width, height);
  367. #if ! JUCE_MAC
  368. g.setColour (findColour (PopupMenu::textColourId).withAlpha (0.6f));
  369. g.drawRect (0, 0, width, height);
  370. #endif
  371. }
  372. void LookAndFeel_V3::drawMenuBarBackground (Graphics& g, int width, int height,
  373. bool, MenuBarComponent& menuBar)
  374. {
  375. auto colour = menuBar.findColour (PopupMenu::backgroundColourId);
  376. Rectangle<int> r (width, height);
  377. g.setColour (colour.contrasting (0.15f));
  378. g.fillRect (r.removeFromTop (1));
  379. g.fillRect (r.removeFromBottom (1));
  380. g.setGradientFill (ColourGradient::vertical (colour, 0, colour.darker (0.08f), (float) height));
  381. g.fillRect (r);
  382. }
  383. void LookAndFeel_V3::drawKeymapChangeButton (Graphics& g, int width, int height,
  384. Button& button, const String& keyDescription)
  385. {
  386. const Colour textColour (button.findColour (0x100ad01 /*KeyMappingEditorComponent::textColourId*/, true));
  387. if (keyDescription.isNotEmpty())
  388. {
  389. if (button.isEnabled())
  390. {
  391. g.setColour (textColour.withAlpha (button.isDown() ? 0.4f : (button.isOver() ? 0.2f : 0.1f)));
  392. g.fillRoundedRectangle (button.getLocalBounds().toFloat(), 4.0f);
  393. g.drawRoundedRectangle (button.getLocalBounds().toFloat(), 4.0f, 1.0f);
  394. }
  395. g.setColour (textColour);
  396. g.setFont ((float) height * 0.6f);
  397. g.drawFittedText (keyDescription, 4, 0, width - 8, height, Justification::centred, 1);
  398. }
  399. else
  400. {
  401. const float thickness = 7.0f;
  402. const float indent = 22.0f;
  403. Path p;
  404. p.addEllipse (0.0f, 0.0f, 100.0f, 100.0f);
  405. p.addRectangle (indent, 50.0f - thickness, 100.0f - indent * 2.0f, thickness * 2.0f);
  406. p.addRectangle (50.0f - thickness, indent, thickness * 2.0f, 50.0f - indent - thickness);
  407. p.addRectangle (50.0f - thickness, 50.0f + thickness, thickness * 2.0f, 50.0f - indent - thickness);
  408. p.setUsingNonZeroWinding (false);
  409. g.setColour (textColour.darker(0.1f).withAlpha (button.isDown() ? 0.7f : (button.isOver() ? 0.5f : 0.3f)));
  410. g.fillPath (p, p.getTransformToScaleToFit (2.0f, 2.0f, (float) width - 4.0f, (float) height - 4.0f, true));
  411. }
  412. if (button.hasKeyboardFocus (false))
  413. {
  414. g.setColour (textColour.withAlpha (0.4f));
  415. g.drawRect (0, 0, width, height);
  416. }
  417. }
  418. class LookAndFeel_V3_DocumentWindowButton : public Button
  419. {
  420. public:
  421. LookAndFeel_V3_DocumentWindowButton (const String& name, Colour c, const Path& normal, const Path& toggled)
  422. : Button (name), colour (c), normalShape (normal), toggledShape (toggled)
  423. {
  424. }
  425. void paintButton (Graphics& g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override
  426. {
  427. Colour background (Colours::grey);
  428. if (ResizableWindow* rw = findParentComponentOfClass<ResizableWindow>())
  429. background = rw->getBackgroundColour();
  430. const float cx = (float) getWidth() * 0.5f, cy = (float) getHeight() * 0.5f;
  431. const float diam = jmin (cx, cy) * (shouldDrawButtonAsDown ? 0.60f : 0.65f);
  432. g.setColour (background);
  433. g.fillEllipse (cx - diam, cy - diam, diam * 2.0f, diam * 2.0f);
  434. Colour c (background.contrasting (colour, 0.6f));
  435. if (! isEnabled())
  436. c = c.withAlpha (0.6f);
  437. else if (shouldDrawButtonAsHighlighted)
  438. c = c.brighter();
  439. g.setColour (c);
  440. g.drawEllipse (cx - diam, cy - diam, diam * 2.0f, diam * 2.0f, diam * 0.2f);
  441. Path& p = getToggleState() ? toggledShape : normalShape;
  442. float scale = 0.55f;
  443. g.fillPath (p, p.getTransformToScaleToFit (cx - diam * scale, cy - diam * scale,
  444. diam * 2.0f * scale, diam * 2.0f * scale, true));
  445. }
  446. private:
  447. Colour colour;
  448. Path normalShape, toggledShape;
  449. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel_V3_DocumentWindowButton)
  450. };
  451. Button* LookAndFeel_V3::createDocumentWindowButton (int buttonType)
  452. {
  453. Path shape;
  454. const float crossThickness = 0.25f;
  455. if (buttonType == DocumentWindow::closeButton)
  456. {
  457. shape.addLineSegment (Line<float> (0.0f, 0.0f, 1.0f, 1.0f), crossThickness * 1.4f);
  458. shape.addLineSegment (Line<float> (1.0f, 0.0f, 0.0f, 1.0f), crossThickness * 1.4f);
  459. return new LookAndFeel_V3_DocumentWindowButton ("close", Colour (0xffdd1100), shape, shape);
  460. }
  461. if (buttonType == DocumentWindow::minimiseButton)
  462. {
  463. shape.addLineSegment (Line<float> (0.0f, 0.5f, 1.0f, 0.5f), crossThickness);
  464. return new LookAndFeel_V3_DocumentWindowButton ("minimise", Colour (0xffaa8811), shape, shape);
  465. }
  466. if (buttonType == DocumentWindow::maximiseButton)
  467. {
  468. shape.addLineSegment (Line<float> (0.5f, 0.0f, 0.5f, 1.0f), crossThickness);
  469. shape.addLineSegment (Line<float> (0.0f, 0.5f, 1.0f, 0.5f), crossThickness);
  470. Path fullscreenShape;
  471. fullscreenShape.startNewSubPath (45.0f, 100.0f);
  472. fullscreenShape.lineTo (0.0f, 100.0f);
  473. fullscreenShape.lineTo (0.0f, 0.0f);
  474. fullscreenShape.lineTo (100.0f, 0.0f);
  475. fullscreenShape.lineTo (100.0f, 45.0f);
  476. fullscreenShape.addRectangle (45.0f, 45.0f, 100.0f, 100.0f);
  477. PathStrokeType (30.0f).createStrokedPath (fullscreenShape, fullscreenShape);
  478. return new LookAndFeel_V3_DocumentWindowButton ("maximise", Colour (0xff119911), shape, fullscreenShape);
  479. }
  480. jassertfalse;
  481. return nullptr;
  482. }
  483. Path LookAndFeel_V3::getTickShape (const float height)
  484. {
  485. static const unsigned char pathData[]
  486. = { 110,109,32,210,202,64,126,183,148,64,108,39,244,247,64,245,76,124,64,108,178,131,27,65,246,76,252,64,108,175,242,4,65,246,76,252,
  487. 64,108,236,5,68,65,0,0,160,180,108,240,150,90,65,21,136,52,63,108,48,59,16,65,0,0,32,65,108,32,210,202,64,126,183,148,64, 99,101,0,0 };
  488. Path p;
  489. p.loadPathFromData (pathData, sizeof (pathData));
  490. p.scaleToFit (0, 0, height * 2.0f, height, true);
  491. return p;
  492. }
  493. Path LookAndFeel_V3::getCrossShape (const float height)
  494. {
  495. static const unsigned char pathData[]
  496. = { 110,109,88,57,198,65,29,90,171,65,108,63,53,154,65,8,172,126,65,108,76,55,198,65,215,163,38,65,108,141,151,175,65,82,184,242,64,108,117,147,131,65,90,100,81,65,108,184,30,47,65,82,184,242,64,108,59,223,1,65,215,163,38,65,108,84,227,89,65,8,172,126,65,
  497. 108,35,219,1,65,29,90,171,65,108,209,34,47,65,231,251,193,65,108,117,147,131,65,207,247,149,65,108,129,149,175,65,231,251,193,65,99,101,0,0 };
  498. Path p;
  499. p.loadPathFromData (pathData, sizeof (pathData));
  500. p.scaleToFit (0, 0, height * 2.0f, height, true);
  501. return p;
  502. }
  503. } // namespace juce