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.

juce_LookAndFeel_V3.cpp 26KB

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