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.

575 lines
21KB

  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. namespace juce
  20. {
  21. LookAndFeel_V1::LookAndFeel_V1()
  22. {
  23. setColour (TextButton::buttonColourId, Colour (0xffbbbbff));
  24. setColour (ListBox::outlineColourId, findColour (ComboBox::outlineColourId));
  25. setColour (ScrollBar::thumbColourId, Colour (0xffbbbbdd));
  26. setColour (ScrollBar::backgroundColourId, Colours::transparentBlack);
  27. setColour (Slider::thumbColourId, Colours::white);
  28. setColour (Slider::trackColourId, Colour (0x7f000000));
  29. setColour (Slider::textBoxOutlineColourId, Colours::grey);
  30. setColour (ProgressBar::backgroundColourId, Colours::white.withAlpha (0.6f));
  31. setColour (ProgressBar::foregroundColourId, Colours::green.withAlpha (0.7f));
  32. setColour (PopupMenu::backgroundColourId, Colour (0xffeef5f8));
  33. setColour (PopupMenu::highlightedBackgroundColourId, Colour (0xbfa4c2ce));
  34. setColour (PopupMenu::highlightedTextColourId, Colours::black);
  35. setColour (TextEditor::focusedOutlineColourId, findColour (TextButton::buttonColourId));
  36. scrollbarShadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 2, Point<int>()));
  37. }
  38. LookAndFeel_V1::~LookAndFeel_V1()
  39. {
  40. }
  41. //==============================================================================
  42. void LookAndFeel_V1::drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour,
  43. bool isMouseOverButton, bool isButtonDown)
  44. {
  45. const int width = button.getWidth();
  46. const int height = button.getHeight();
  47. const float indent = 2.0f;
  48. const int cornerSize = jmin (roundToInt (width * 0.4f),
  49. roundToInt (height * 0.4f));
  50. Path p;
  51. p.addRoundedRectangle (indent, indent,
  52. width - indent * 2.0f,
  53. height - indent * 2.0f,
  54. (float) cornerSize);
  55. Colour bc (backgroundColour.withMultipliedSaturation (0.3f));
  56. if (isMouseOverButton)
  57. {
  58. if (isButtonDown)
  59. bc = bc.brighter();
  60. else if (bc.getBrightness() > 0.5f)
  61. bc = bc.darker (0.1f);
  62. else
  63. bc = bc.brighter (0.1f);
  64. }
  65. g.setColour (bc);
  66. g.fillPath (p);
  67. g.setColour (bc.contrasting().withAlpha ((isMouseOverButton) ? 0.6f : 0.4f));
  68. g.strokePath (p, PathStrokeType ((isMouseOverButton) ? 2.0f : 1.4f));
  69. }
  70. void LookAndFeel_V1::drawTickBox (Graphics& g, Component& /*component*/,
  71. float x, float y, float w, float h,
  72. const bool ticked,
  73. const bool isEnabled,
  74. const bool /*isMouseOverButton*/,
  75. const bool isButtonDown)
  76. {
  77. Path box;
  78. box.addRoundedRectangle (0.0f, 2.0f, 6.0f, 6.0f, 1.0f);
  79. g.setColour (isEnabled ? Colours::blue.withAlpha (isButtonDown ? 0.3f : 0.1f)
  80. : Colours::lightgrey.withAlpha (0.1f));
  81. AffineTransform trans (AffineTransform::scale (w / 9.0f, h / 9.0f).translated (x, y));
  82. g.fillPath (box, trans);
  83. g.setColour (Colours::black.withAlpha (0.6f));
  84. g.strokePath (box, PathStrokeType (0.9f), trans);
  85. if (ticked)
  86. {
  87. Path tick;
  88. tick.startNewSubPath (1.5f, 3.0f);
  89. tick.lineTo (3.0f, 6.0f);
  90. tick.lineTo (6.0f, 0.0f);
  91. g.setColour (isEnabled ? Colours::black : Colours::grey);
  92. g.strokePath (tick, PathStrokeType (2.5f), trans);
  93. }
  94. }
  95. void LookAndFeel_V1::drawToggleButton (Graphics& g, ToggleButton& button, bool isMouseOverButton, bool isButtonDown)
  96. {
  97. if (button.hasKeyboardFocus (true))
  98. {
  99. g.setColour (button.findColour (TextEditor::focusedOutlineColourId));
  100. g.drawRect (0, 0, button.getWidth(), button.getHeight());
  101. }
  102. const int tickWidth = jmin (20, button.getHeight() - 4);
  103. drawTickBox (g, button, 4.0f, (button.getHeight() - tickWidth) * 0.5f,
  104. (float) tickWidth, (float) tickWidth,
  105. button.getToggleState(),
  106. button.isEnabled(),
  107. isMouseOverButton,
  108. isButtonDown);
  109. g.setColour (button.findColour (ToggleButton::textColourId));
  110. g.setFont (jmin (15.0f, button.getHeight() * 0.6f));
  111. if (! button.isEnabled())
  112. g.setOpacity (0.5f);
  113. const int textX = tickWidth + 5;
  114. g.drawFittedText (button.getButtonText(),
  115. textX, 4,
  116. button.getWidth() - textX - 2, button.getHeight() - 8,
  117. Justification::centredLeft, 10);
  118. }
  119. void LookAndFeel_V1::drawProgressBar (Graphics& g, ProgressBar& progressBar,
  120. int width, int height,
  121. double progress, const String& textToShow)
  122. {
  123. if (progress < 0 || progress >= 1.0)
  124. {
  125. LookAndFeel_V2::drawProgressBar (g, progressBar, width, height, progress, textToShow);
  126. }
  127. else
  128. {
  129. const Colour background (progressBar.findColour (ProgressBar::backgroundColourId));
  130. const Colour foreground (progressBar.findColour (ProgressBar::foregroundColourId));
  131. g.fillAll (background);
  132. g.setColour (foreground);
  133. g.fillRect (1, 1,
  134. jlimit (0, width - 2, roundToInt (progress * (width - 2))),
  135. height - 2);
  136. if (textToShow.isNotEmpty())
  137. {
  138. g.setColour (Colour::contrasting (background, foreground));
  139. g.setFont (height * 0.6f);
  140. g.drawText (textToShow, 0, 0, width, height, Justification::centred, false);
  141. }
  142. }
  143. }
  144. void LookAndFeel_V1::drawScrollbarButton (Graphics& g, ScrollBar& bar,
  145. int width, int height, int buttonDirection,
  146. bool isScrollbarVertical,
  147. bool isMouseOverButton,
  148. bool isButtonDown)
  149. {
  150. if (isScrollbarVertical)
  151. width -= 2;
  152. else
  153. height -= 2;
  154. Path p;
  155. if (buttonDirection == 0)
  156. p.addTriangle (width * 0.5f, height * 0.2f,
  157. width * 0.1f, height * 0.7f,
  158. width * 0.9f, height * 0.7f);
  159. else if (buttonDirection == 1)
  160. p.addTriangle (width * 0.8f, height * 0.5f,
  161. width * 0.3f, height * 0.1f,
  162. width * 0.3f, height * 0.9f);
  163. else if (buttonDirection == 2)
  164. p.addTriangle (width * 0.5f, height * 0.8f,
  165. width * 0.1f, height * 0.3f,
  166. width * 0.9f, height * 0.3f);
  167. else if (buttonDirection == 3)
  168. p.addTriangle (width * 0.2f, height * 0.5f,
  169. width * 0.7f, height * 0.1f,
  170. width * 0.7f, height * 0.9f);
  171. if (isButtonDown)
  172. g.setColour (Colours::white);
  173. else if (isMouseOverButton)
  174. g.setColour (Colours::white.withAlpha (0.7f));
  175. else
  176. g.setColour (bar.findColour (ScrollBar::thumbColourId).withAlpha (0.5f));
  177. g.fillPath (p);
  178. g.setColour (Colours::black.withAlpha (0.5f));
  179. g.strokePath (p, PathStrokeType (0.5f));
  180. }
  181. void LookAndFeel_V1::drawScrollbar (Graphics& g, ScrollBar& bar,
  182. int x, int y, int width, int height,
  183. bool isScrollbarVertical, int thumbStartPosition, int thumbSize,
  184. bool isMouseOver, bool isMouseDown)
  185. {
  186. g.fillAll (bar.findColour (ScrollBar::backgroundColourId));
  187. g.setColour (bar.findColour (ScrollBar::thumbColourId)
  188. .withAlpha ((isMouseOver || isMouseDown) ? 0.4f : 0.15f));
  189. if (thumbSize > 0.0f)
  190. {
  191. Rectangle<int> thumb;
  192. if (isScrollbarVertical)
  193. {
  194. width -= 2;
  195. g.fillRect (x + roundToInt (width * 0.35f), y,
  196. roundToInt (width * 0.3f), height);
  197. thumb.setBounds (x + 1, thumbStartPosition,
  198. width - 2, thumbSize);
  199. }
  200. else
  201. {
  202. height -= 2;
  203. g.fillRect (x, y + roundToInt (height * 0.35f),
  204. width, roundToInt (height * 0.3f));
  205. thumb.setBounds (thumbStartPosition, y + 1,
  206. thumbSize, height - 2);
  207. }
  208. g.setColour (bar.findColour (ScrollBar::thumbColourId)
  209. .withAlpha ((isMouseOver || isMouseDown) ? 0.95f : 0.7f));
  210. g.fillRect (thumb);
  211. g.setColour (Colours::black.withAlpha ((isMouseOver || isMouseDown) ? 0.4f : 0.25f));
  212. g.drawRect (thumb.getX(), thumb.getY(), thumb.getWidth(), thumb.getHeight());
  213. if (thumbSize > 16)
  214. {
  215. for (int i = 3; --i >= 0;)
  216. {
  217. const float linePos = thumbStartPosition + thumbSize / 2 + (i - 1) * 4.0f;
  218. g.setColour (Colours::black.withAlpha (0.15f));
  219. if (isScrollbarVertical)
  220. {
  221. g.drawLine (x + width * 0.2f, linePos, width * 0.8f, linePos);
  222. g.setColour (Colours::white.withAlpha (0.15f));
  223. g.drawLine (width * 0.2f, linePos - 1, width * 0.8f, linePos - 1);
  224. }
  225. else
  226. {
  227. g.drawLine (linePos, height * 0.2f, linePos, height * 0.8f);
  228. g.setColour (Colours::white.withAlpha (0.15f));
  229. g.drawLine (linePos - 1, height * 0.2f, linePos - 1, height * 0.8f);
  230. }
  231. }
  232. }
  233. }
  234. }
  235. ImageEffectFilter* LookAndFeel_V1::getScrollbarEffect()
  236. {
  237. return &scrollbarShadow;
  238. }
  239. //==============================================================================
  240. void LookAndFeel_V1::drawPopupMenuBackground (Graphics& g, int width, int height)
  241. {
  242. g.fillAll (findColour (PopupMenu::backgroundColourId));
  243. g.setColour (Colours::black.withAlpha (0.6f));
  244. g.drawRect (0, 0, width, height);
  245. }
  246. void LookAndFeel_V1::drawMenuBarBackground (Graphics& g, int /*width*/, int /*height*/, bool, MenuBarComponent& menuBar)
  247. {
  248. g.fillAll (menuBar.findColour (PopupMenu::backgroundColourId));
  249. }
  250. //==============================================================================
  251. void LookAndFeel_V1::drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor)
  252. {
  253. if (textEditor.isEnabled())
  254. {
  255. g.setColour (textEditor.findColour (TextEditor::outlineColourId));
  256. g.drawRect (0, 0, width, height);
  257. }
  258. }
  259. //==============================================================================
  260. void LookAndFeel_V1::drawComboBox (Graphics& g, int width, int height,
  261. const bool isButtonDown,
  262. int buttonX, int buttonY, int buttonW, int buttonH,
  263. ComboBox& box)
  264. {
  265. g.fillAll (box.findColour (ComboBox::backgroundColourId));
  266. g.setColour (box.findColour ((isButtonDown) ? ComboBox::buttonColourId
  267. : ComboBox::backgroundColourId));
  268. g.fillRect (buttonX, buttonY, buttonW, buttonH);
  269. g.setColour (box.findColour (ComboBox::outlineColourId));
  270. g.drawRect (0, 0, width, height);
  271. const float arrowX = 0.2f;
  272. const float arrowH = 0.3f;
  273. if (box.isEnabled())
  274. {
  275. Path p;
  276. p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.45f - arrowH),
  277. buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.45f,
  278. buttonX + buttonW * arrowX, buttonY + buttonH * 0.45f);
  279. p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.55f + arrowH),
  280. buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.55f,
  281. buttonX + buttonW * arrowX, buttonY + buttonH * 0.55f);
  282. g.setColour (box.findColour ((isButtonDown) ? ComboBox::backgroundColourId
  283. : ComboBox::buttonColourId));
  284. g.fillPath (p);
  285. }
  286. }
  287. Font LookAndFeel_V1::getComboBoxFont (ComboBox& box)
  288. {
  289. Font f (jmin (15.0f, box.getHeight() * 0.85f));
  290. f.setHorizontalScale (0.9f);
  291. return f;
  292. }
  293. //==============================================================================
  294. static void drawTriangle (Graphics& g, float x1, float y1, float x2, float y2, float x3, float y3, Colour fill, Colour outline)
  295. {
  296. Path p;
  297. p.addTriangle (x1, y1, x2, y2, x3, y3);
  298. g.setColour (fill);
  299. g.fillPath (p);
  300. g.setColour (outline);
  301. g.strokePath (p, PathStrokeType (0.3f));
  302. }
  303. void LookAndFeel_V1::drawLinearSlider (Graphics& g,
  304. int x, int y, int w, int h,
  305. float sliderPos, float minSliderPos, float maxSliderPos,
  306. const Slider::SliderStyle style,
  307. Slider& slider)
  308. {
  309. g.fillAll (slider.findColour (Slider::backgroundColourId));
  310. if (style == Slider::LinearBar)
  311. {
  312. g.setColour (slider.findColour (Slider::thumbColourId));
  313. g.fillRect (x, y, (int) sliderPos - x, h);
  314. g.setColour (slider.findColour (Slider::textBoxTextColourId).withMultipliedAlpha (0.5f));
  315. g.drawRect (x, y, (int) sliderPos - x, h);
  316. }
  317. else
  318. {
  319. g.setColour (slider.findColour (Slider::trackColourId)
  320. .withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.3f));
  321. if (slider.isHorizontal())
  322. {
  323. g.fillRect (x, y + roundToInt (h * 0.6f),
  324. w, roundToInt (h * 0.2f));
  325. }
  326. else
  327. {
  328. g.fillRect (x + roundToInt (w * 0.5f - jmin (3.0f, w * 0.1f)), y,
  329. jmin (4, roundToInt (w * 0.2f)), h);
  330. }
  331. float alpha = 0.35f;
  332. if (slider.isEnabled())
  333. alpha = slider.isMouseOverOrDragging() ? 1.0f : 0.7f;
  334. const Colour fill (slider.findColour (Slider::thumbColourId).withAlpha (alpha));
  335. const Colour outline (Colours::black.withAlpha (slider.isEnabled() ? 0.7f : 0.35f));
  336. if (style == Slider::TwoValueVertical || style == Slider::ThreeValueVertical)
  337. {
  338. drawTriangle (g, x + w * 0.5f + jmin (4.0f, w * 0.3f), minSliderPos,
  339. x + w * 0.5f - jmin (8.0f, w * 0.4f), minSliderPos - 7.0f,
  340. x + w * 0.5f - jmin (8.0f, w * 0.4f), minSliderPos,
  341. fill, outline);
  342. drawTriangle (g, x + w * 0.5f + jmin (4.0f, w * 0.3f), maxSliderPos,
  343. x + w * 0.5f - jmin (8.0f, w * 0.4f), maxSliderPos,
  344. x + w * 0.5f - jmin (8.0f, w * 0.4f), maxSliderPos + 7.0f,
  345. fill, outline);
  346. }
  347. else if (style == Slider::TwoValueHorizontal || style == Slider::ThreeValueHorizontal)
  348. {
  349. drawTriangle (g, minSliderPos, y + h * 0.6f - jmin (4.0f, h * 0.3f),
  350. minSliderPos - 7.0f, y + h * 0.9f ,
  351. minSliderPos, y + h * 0.9f,
  352. fill, outline);
  353. drawTriangle (g, maxSliderPos, y + h * 0.6f - jmin (4.0f, h * 0.3f),
  354. maxSliderPos, y + h * 0.9f,
  355. maxSliderPos + 7.0f, y + h * 0.9f,
  356. fill, outline);
  357. }
  358. if (style == Slider::LinearHorizontal || style == Slider::ThreeValueHorizontal)
  359. {
  360. drawTriangle (g, sliderPos, y + h * 0.9f,
  361. sliderPos - 7.0f, y + h * 0.2f,
  362. sliderPos + 7.0f, y + h * 0.2f,
  363. fill, outline);
  364. }
  365. else if (style == Slider::LinearVertical || style == Slider::ThreeValueVertical)
  366. {
  367. drawTriangle (g, x + w * 0.5f - jmin (4.0f, w * 0.3f), sliderPos,
  368. x + w * 0.5f + jmin (8.0f, w * 0.4f), sliderPos - 7.0f,
  369. x + w * 0.5f + jmin (8.0f, w * 0.4f), sliderPos + 7.0f,
  370. fill, outline);
  371. }
  372. }
  373. }
  374. Button* LookAndFeel_V1::createSliderButton (Slider&, const bool isIncrement)
  375. {
  376. if (isIncrement)
  377. return new ArrowButton ("u", 0.75f, Colours::white.withAlpha (0.8f));
  378. return new ArrowButton ("d", 0.25f, Colours::white.withAlpha (0.8f));
  379. }
  380. ImageEffectFilter* LookAndFeel_V1::getSliderEffect (Slider&)
  381. {
  382. return &scrollbarShadow;
  383. }
  384. int LookAndFeel_V1::getSliderThumbRadius (Slider&)
  385. {
  386. return 8;
  387. }
  388. //==============================================================================
  389. void LookAndFeel_V1::drawCornerResizer (Graphics& g, int w, int h, bool isMouseOver, bool isMouseDragging)
  390. {
  391. g.setColour ((isMouseOver || isMouseDragging) ? Colours::lightgrey
  392. : Colours::darkgrey);
  393. const float lineThickness = jmin (w, h) * 0.1f;
  394. for (float i = 0.0f; i < 1.0f; i += 0.3f)
  395. {
  396. g.drawLine (w * i,
  397. h + 1.0f,
  398. w + 1.0f,
  399. h * i,
  400. lineThickness);
  401. }
  402. }
  403. //==============================================================================
  404. Button* LookAndFeel_V1::createDocumentWindowButton (int buttonType)
  405. {
  406. Path shape;
  407. if (buttonType == DocumentWindow::closeButton)
  408. {
  409. shape.addLineSegment (Line<float> (0.0f, 0.0f, 1.0f, 1.0f), 0.35f);
  410. shape.addLineSegment (Line<float> (1.0f, 0.0f, 0.0f, 1.0f), 0.35f);
  411. ShapeButton* const b = new ShapeButton ("close",
  412. Colour (0x7fff3333),
  413. Colour (0xd7ff3333),
  414. Colour (0xf7ff3333));
  415. b->setShape (shape, true, true, true);
  416. return b;
  417. }
  418. else if (buttonType == DocumentWindow::minimiseButton)
  419. {
  420. shape.addLineSegment (Line<float> (0.0f, 0.5f, 1.0f, 0.5f), 0.25f);
  421. DrawableButton* b = new DrawableButton ("minimise", DrawableButton::ImageFitted);
  422. DrawablePath dp;
  423. dp.setPath (shape);
  424. dp.setFill (Colours::black.withAlpha (0.3f));
  425. b->setImages (&dp);
  426. return b;
  427. }
  428. else if (buttonType == DocumentWindow::maximiseButton)
  429. {
  430. shape.addLineSegment (Line<float> (0.5f, 0.0f, 0.5f, 1.0f), 0.25f);
  431. shape.addLineSegment (Line<float> (0.0f, 0.5f, 1.0f, 0.5f), 0.25f);
  432. DrawableButton* b = new DrawableButton ("maximise", DrawableButton::ImageFitted);
  433. DrawablePath dp;
  434. dp.setPath (shape);
  435. dp.setFill (Colours::black.withAlpha (0.3f));
  436. b->setImages (&dp);
  437. return b;
  438. }
  439. jassertfalse;
  440. return nullptr;
  441. }
  442. void LookAndFeel_V1::positionDocumentWindowButtons (DocumentWindow&,
  443. int titleBarX, int titleBarY, int titleBarW, int titleBarH,
  444. Button* minimiseButton,
  445. Button* maximiseButton,
  446. Button* closeButton,
  447. bool positionTitleBarButtonsOnLeft)
  448. {
  449. titleBarY += titleBarH / 8;
  450. titleBarH -= titleBarH / 4;
  451. const int buttonW = titleBarH;
  452. int x = positionTitleBarButtonsOnLeft ? titleBarX + 4
  453. : titleBarX + titleBarW - buttonW - 4;
  454. if (closeButton != nullptr)
  455. {
  456. closeButton->setBounds (x, titleBarY, buttonW, titleBarH);
  457. x += positionTitleBarButtonsOnLeft ? buttonW + buttonW / 5
  458. : -(buttonW + buttonW / 5);
  459. }
  460. if (positionTitleBarButtonsOnLeft)
  461. std::swap (minimiseButton, maximiseButton);
  462. if (maximiseButton != nullptr)
  463. {
  464. maximiseButton->setBounds (x, titleBarY - 2, buttonW, titleBarH);
  465. x += positionTitleBarButtonsOnLeft ? buttonW : -buttonW;
  466. }
  467. if (minimiseButton != nullptr)
  468. minimiseButton->setBounds (x, titleBarY - 2, buttonW, titleBarH);
  469. }
  470. } // namespace juce