juce_LookAndFeel_V1.cpp 21 KB

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