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.

588 lines
22KB

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