The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

2789 lines
113KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../../juce_core/basics/juce_StandardHeader.h"
  24. BEGIN_JUCE_NAMESPACE
  25. #include "juce_LookAndFeel.h"
  26. #include "../buttons/juce_TextButton.h"
  27. #include "../buttons/juce_ToggleButton.h"
  28. #include "../buttons/juce_ShapeButton.h"
  29. #include "../buttons/juce_ArrowButton.h"
  30. #include "../buttons/juce_DrawableButton.h"
  31. #include "../buttons/juce_HyperlinkButton.h"
  32. #include "../windows/juce_AlertWindow.h"
  33. #include "../windows/juce_DocumentWindow.h"
  34. #include "../windows/juce_ResizableWindow.h"
  35. #include "../menus/juce_MenuBarComponent.h"
  36. #include "../menus/juce_PopupMenu.h"
  37. #include "../layout/juce_ScrollBar.h"
  38. #include "../mouse/juce_LassoComponent.h"
  39. #include "../controls/juce_Slider.h"
  40. #include "../controls/juce_ListBox.h"
  41. #include "../controls/juce_TableHeaderComponent.h"
  42. #include "../controls/juce_Toolbar.h"
  43. #include "../controls/juce_ToolbarItemComponent.h"
  44. #include "../controls/juce_ProgressBar.h"
  45. #include "../controls/juce_TreeView.h"
  46. #include "../filebrowser/juce_FilenameComponent.h"
  47. #include "../filebrowser/juce_DirectoryContentsDisplayComponent.h"
  48. #include "../filebrowser/juce_FileSearchPathListComponent.h"
  49. #include "../filebrowser/juce_FileBrowserComponent.h"
  50. #include "../layout/juce_GroupComponent.h"
  51. #include "../properties/juce_PropertyComponent.h"
  52. #include "../juce_Desktop.h"
  53. #include "../../graphics/imaging/juce_ImageCache.h"
  54. #include "../../graphics/brushes/juce_GradientBrush.h"
  55. #include "../../graphics/fonts/juce_GlyphArrangement.h"
  56. #include "../../graphics/drawables/juce_DrawableComposite.h"
  57. #include "../../graphics/drawables/juce_DrawablePath.h"
  58. #include "../../../../juce_core/text/juce_LocalisedStrings.h"
  59. #include "../special/juce_MidiKeyboardComponent.h"
  60. #include "../special/juce_ColourSelector.h"
  61. #include "../../../../juce_core/misc/juce_PlatformUtilities.h"
  62. //==============================================================================
  63. static const Colour createBaseColour (const Colour& buttonColour,
  64. const bool hasKeyboardFocus,
  65. const bool isMouseOverButton,
  66. const bool isButtonDown) throw()
  67. {
  68. const float sat = hasKeyboardFocus ? 1.3f : 0.9f;
  69. const Colour baseColour (buttonColour.withMultipliedSaturation (sat));
  70. if (isButtonDown)
  71. return baseColour.contrasting (0.2f);
  72. else if (isMouseOverButton)
  73. return baseColour.contrasting (0.1f);
  74. return baseColour;
  75. }
  76. //==============================================================================
  77. LookAndFeel::LookAndFeel()
  78. {
  79. /* if this fails it means you're trying to create a LookAndFeel object before
  80. the static Colours have been initialised. That ain't gonna work. It probably
  81. means that you're using a static LookAndFeel object and that your compiler has
  82. decided to intialise it before the Colours class.
  83. */
  84. jassert (Colours::white == Colour (0xffffffff));
  85. // set up the standard set of colours..
  86. #define textButtonColour 0xffbbbbff
  87. #define textHighlightColour 0x401111ee
  88. #define standardOutlineColour 0xb2808080
  89. static const int standardColours[] =
  90. {
  91. TextButton::buttonColourId, textButtonColour,
  92. TextButton::buttonOnColourId, 0xff4444ff,
  93. TextButton::textColourId, 0xff000000,
  94. ComboBox::buttonColourId, 0xffbbbbff,
  95. ComboBox::outlineColourId, standardOutlineColour,
  96. ToggleButton::textColourId, 0xff000000,
  97. TextEditor::backgroundColourId, 0xffffffff,
  98. TextEditor::textColourId, 0xff000000,
  99. TextEditor::highlightColourId, textHighlightColour,
  100. TextEditor::highlightedTextColourId, 0xff000000,
  101. TextEditor::caretColourId, 0xff000000,
  102. TextEditor::outlineColourId, 0x00000000,
  103. TextEditor::focusedOutlineColourId, textButtonColour,
  104. TextEditor::shadowColourId, 0x38000000,
  105. Label::backgroundColourId, 0x00000000,
  106. Label::textColourId, 0xff000000,
  107. Label::outlineColourId, 0x00000000,
  108. ScrollBar::backgroundColourId, 0x00000000,
  109. ScrollBar::thumbColourId, 0xffffffff,
  110. TreeView::linesColourId, 0x4c000000,
  111. TreeView::backgroundColourId, 0x00000000,
  112. PopupMenu::backgroundColourId, 0xffffffff,
  113. PopupMenu::textColourId, 0xff000000,
  114. PopupMenu::headerTextColourId, 0xff000000,
  115. PopupMenu::highlightedTextColourId, 0xffffffff,
  116. PopupMenu::highlightedBackgroundColourId, 0x991111aa,
  117. ComboBox::textColourId, 0xff000000,
  118. ComboBox::backgroundColourId, 0xffffffff,
  119. ListBox::backgroundColourId, 0xffffffff,
  120. ListBox::outlineColourId, standardOutlineColour,
  121. ListBox::textColourId, 0xff000000,
  122. Slider::backgroundColourId, 0x00000000,
  123. Slider::thumbColourId, textButtonColour,
  124. Slider::trackColourId, 0x7fffffff,
  125. Slider::rotarySliderFillColourId, 0x7f0000ff,
  126. Slider::rotarySliderOutlineColourId, 0x66000000,
  127. Slider::textBoxTextColourId, 0xff000000,
  128. Slider::textBoxBackgroundColourId, 0xffffffff,
  129. Slider::textBoxHighlightColourId, textHighlightColour,
  130. Slider::textBoxOutlineColourId, standardOutlineColour,
  131. AlertWindow::backgroundColourId, 0xffededed,
  132. AlertWindow::textColourId, 0xff000000,
  133. AlertWindow::outlineColourId, 0xff666666,
  134. ProgressBar::backgroundColourId, 0xffffffff,
  135. ProgressBar::foregroundColourId, 0xffaaaaee,
  136. TooltipWindow::backgroundColourId, 0xffeeeebb,
  137. TooltipWindow::textColourId, 0xff000000,
  138. TooltipWindow::outlineColourId, 0x4c000000,
  139. Toolbar::backgroundColourId, 0xfff6f8f9,
  140. Toolbar::separatorColourId, 0x4c000000,
  141. Toolbar::buttonMouseOverBackgroundColourId, 0x4c0000ff,
  142. Toolbar::buttonMouseDownBackgroundColourId, 0x800000ff,
  143. Toolbar::labelTextColourId, 0xff000000,
  144. Toolbar::editingModeOutlineColourId, 0xffff0000,
  145. HyperlinkButton::textColourId, 0xcc1111ee,
  146. GroupComponent::outlineColourId, 0x66000000,
  147. GroupComponent::textColourId, 0xff000000,
  148. DirectoryContentsDisplayComponent::highlightColourId, textHighlightColour,
  149. DirectoryContentsDisplayComponent::textColourId, 0xff000000,
  150. 0x1000440, /*LassoComponent::lassoFillColourId*/ 0x66dddddd,
  151. 0x1000441, /*LassoComponent::lassoOutlineColourId*/ 0x99111111,
  152. MidiKeyboardComponent::whiteNoteColourId, 0xffffffff,
  153. MidiKeyboardComponent::blackNoteColourId, 0xff000000,
  154. MidiKeyboardComponent::keySeparatorLineColourId, 0x66000000,
  155. MidiKeyboardComponent::mouseOverKeyOverlayColourId, 0x80ffff00,
  156. MidiKeyboardComponent::keyDownOverlayColourId, 0xffb6b600,
  157. MidiKeyboardComponent::textLabelColourId, 0xff000000,
  158. MidiKeyboardComponent::upDownButtonBackgroundColourId, 0xffd3d3d3,
  159. MidiKeyboardComponent::upDownButtonArrowColourId, 0xff000000,
  160. ColourSelector::backgroundColourId, 0xffe5e5e5,
  161. ColourSelector::labelTextColourId, 0xff000000,
  162. FileSearchPathListComponent::backgroundColourId, 0xffffffff,
  163. };
  164. for (int i = 0; i < numElementsInArray (standardColours); i += 2)
  165. setColour (standardColours [i], Colour (standardColours [i + 1]));
  166. }
  167. LookAndFeel::~LookAndFeel()
  168. {
  169. }
  170. //==============================================================================
  171. const Colour LookAndFeel::findColour (const int colourId) const throw()
  172. {
  173. const int index = colourIds.indexOf (colourId);
  174. if (index >= 0)
  175. return colours [index];
  176. jassertfalse
  177. return Colours::black;
  178. }
  179. void LookAndFeel::setColour (const int colourId, const Colour& colour) throw()
  180. {
  181. const int index = colourIds.indexOf (colourId);
  182. if (index >= 0)
  183. colours.set (index, colour);
  184. colourIds.add (colourId);
  185. colours.add (colour);
  186. }
  187. //==============================================================================
  188. static LookAndFeel* defaultLF = 0;
  189. static LookAndFeel* currentDefaultLF = 0;
  190. LookAndFeel& LookAndFeel::getDefaultLookAndFeel() throw()
  191. {
  192. // if this happens, your app hasn't initialised itself properly.. if you're
  193. // trying to hack your own main() function, have a look at
  194. // JUCEApplication::initialiseForGUI()
  195. jassert (currentDefaultLF != 0);
  196. return *currentDefaultLF;
  197. }
  198. void LookAndFeel::setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel) throw()
  199. {
  200. if (newDefaultLookAndFeel == 0)
  201. {
  202. if (defaultLF == 0)
  203. defaultLF = new LookAndFeel();
  204. newDefaultLookAndFeel = defaultLF;
  205. }
  206. currentDefaultLF = newDefaultLookAndFeel;
  207. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  208. {
  209. Component* const c = Desktop::getInstance().getComponent (i);
  210. if (c != 0)
  211. c->sendLookAndFeelChange();
  212. }
  213. }
  214. void LookAndFeel::clearDefaultLookAndFeel() throw()
  215. {
  216. if (currentDefaultLF == defaultLF)
  217. currentDefaultLF = 0;
  218. deleteAndZero (defaultLF);
  219. }
  220. //==============================================================================
  221. void LookAndFeel::drawButtonBackground (Graphics& g,
  222. Button& button,
  223. const Colour& backgroundColour,
  224. bool isMouseOverButton,
  225. bool isButtonDown)
  226. {
  227. const int width = button.getWidth();
  228. const int height = button.getHeight();
  229. const float outlineThickness = button.isEnabled() ? ((isButtonDown || isMouseOverButton) ? 1.2f : 0.7f) : 0.4f;
  230. const float halfThickness = outlineThickness * 0.5f;
  231. const float indentL = button.isConnectedOnLeft() ? 0.1f : halfThickness;
  232. const float indentR = button.isConnectedOnRight() ? 0.1f : halfThickness;
  233. const float indentT = button.isConnectedOnTop() ? 0.1f : halfThickness;
  234. const float indentB = button.isConnectedOnBottom() ? 0.1f : halfThickness;
  235. const Colour baseColour (createBaseColour (backgroundColour,
  236. button.hasKeyboardFocus (true),
  237. isMouseOverButton, isButtonDown)
  238. .withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f));
  239. drawGlassLozenge (g,
  240. indentL,
  241. indentT,
  242. width - indentL - indentR,
  243. height - indentT - indentB,
  244. baseColour, outlineThickness, -1.0f,
  245. button.isConnectedOnLeft(),
  246. button.isConnectedOnRight(),
  247. button.isConnectedOnTop(),
  248. button.isConnectedOnBottom());
  249. }
  250. void LookAndFeel::drawButtonText (Graphics& g, TextButton& button,
  251. bool /*isMouseOverButton*/, bool /*isButtonDown*/)
  252. {
  253. g.setFont (button.getFont());
  254. g.setColour (button.findColour (TextButton::textColourId)
  255. .withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f));
  256. const int yIndent = jmin (4, button.proportionOfHeight (0.3f));
  257. const int cornerSize = jmin (button.getHeight(), button.getWidth()) / 2;
  258. const int fontHeight = roundFloatToInt (g.getCurrentFont().getHeight() * 0.6f);
  259. const int leftIndent = jmin (fontHeight, 2 + cornerSize / (button.isConnectedOnLeft() ? 4 : 2));
  260. const int rightIndent = jmin (fontHeight, 2 + cornerSize / (button.isConnectedOnRight() ? 4 : 2));
  261. g.drawFittedText (button.getButtonText(),
  262. leftIndent,
  263. yIndent,
  264. button.getWidth() - leftIndent - rightIndent,
  265. button.getHeight() - yIndent * 2,
  266. Justification::centred, 2);
  267. }
  268. void LookAndFeel::drawTickBox (Graphics& g,
  269. Component& component,
  270. int x, int y, int w, int h,
  271. const bool ticked,
  272. const bool isEnabled,
  273. const bool isMouseOverButton,
  274. const bool isButtonDown)
  275. {
  276. const float boxSize = w * 0.7f;
  277. drawGlassSphere (g, (float) x, y + (h - boxSize) * 0.5f, boxSize,
  278. createBaseColour (component.findColour (TextButton::buttonColourId)
  279. .withMultipliedAlpha (isEnabled ? 1.0f : 0.5f),
  280. true,
  281. isMouseOverButton,
  282. isButtonDown),
  283. isEnabled ? ((isButtonDown || isMouseOverButton) ? 1.1f : 0.5f) : 0.3f);
  284. if (ticked)
  285. {
  286. Path tick;
  287. tick.startNewSubPath (1.5f, 3.0f);
  288. tick.lineTo (3.0f, 6.0f);
  289. tick.lineTo (6.0f, 0.0f);
  290. g.setColour (isEnabled ? Colours::black : Colours::grey);
  291. const AffineTransform trans (AffineTransform::scale (w / 9.0f, h / 9.0f)
  292. .translated ((float) x, (float) y));
  293. g.strokePath (tick, PathStrokeType (2.5f), trans);
  294. }
  295. }
  296. void LookAndFeel::drawToggleButton (Graphics& g,
  297. ToggleButton& button,
  298. bool isMouseOverButton,
  299. bool isButtonDown)
  300. {
  301. if (button.hasKeyboardFocus (true))
  302. {
  303. g.setColour (button.findColour (TextEditor::focusedOutlineColourId));
  304. g.drawRect (0, 0, button.getWidth(), button.getHeight());
  305. }
  306. const int tickWidth = jmin (20, button.getHeight() - 4);
  307. drawTickBox (g, button, 4, (button.getHeight() - tickWidth) / 2,
  308. tickWidth, tickWidth,
  309. button.getToggleState(),
  310. button.isEnabled(),
  311. isMouseOverButton,
  312. isButtonDown);
  313. g.setColour (button.findColour (ToggleButton::textColourId));
  314. g.setFont (jmin (15.0f, button.getHeight() * 0.6f));
  315. if (! button.isEnabled())
  316. g.setOpacity (0.5f);
  317. const int textX = tickWidth + 5;
  318. g.drawFittedText (button.getButtonText(),
  319. textX, 4,
  320. button.getWidth() - textX - 2, button.getHeight() - 8,
  321. Justification::centredLeft, 10);
  322. }
  323. void LookAndFeel::changeToggleButtonWidthToFitText (ToggleButton& button)
  324. {
  325. Font font (jmin (15.0f, button.getHeight() * 0.6f));
  326. const int tickWidth = jmin (24, button.getHeight());
  327. button.setSize (font.getStringWidth (button.getButtonText()) + tickWidth + 8,
  328. button.getHeight());
  329. }
  330. void LookAndFeel::drawAlertBox (Graphics& g,
  331. AlertWindow& alert,
  332. const Rectangle& textArea,
  333. TextLayout& textLayout)
  334. {
  335. const int iconWidth = 80;
  336. const Colour background (alert.findColour (AlertWindow::backgroundColourId));
  337. g.fillAll (background);
  338. int iconSpaceUsed = 0;
  339. Justification alignment (Justification::horizontallyCentred);
  340. int iconSize = jmin (iconWidth + 50, alert.getHeight() + 20);
  341. if (alert.containsAnyExtraComponents() || alert.getNumButtons() > 2)
  342. iconSize = jmin (iconSize, textArea.getHeight() + 50);
  343. const Rectangle iconRect (iconSize / -10,
  344. iconSize / -10,
  345. iconSize,
  346. iconSize);
  347. if (alert.getAlertType() == AlertWindow::QuestionIcon
  348. || alert.getAlertType() == AlertWindow::InfoIcon)
  349. {
  350. if (alert.getAlertType() == AlertWindow::InfoIcon)
  351. g.setColour (background.overlaidWith (Colour (0x280000ff)));
  352. else
  353. g.setColour (background.overlaidWith (Colours::gold.darker().withAlpha (0.25f)));
  354. g.fillEllipse ((float) iconRect.getX(),
  355. (float) iconRect.getY(),
  356. (float) iconRect.getWidth(),
  357. (float) iconRect.getHeight());
  358. g.setColour (background);
  359. g.setFont (iconRect.getHeight() * 0.9f, Font::bold);
  360. g.drawText ((alert.getAlertType() == AlertWindow::InfoIcon) ? "i"
  361. : "?",
  362. iconRect.getX(),
  363. iconRect.getY(),
  364. iconRect.getWidth(),
  365. iconRect.getHeight(),
  366. Justification::centred, false);
  367. iconSpaceUsed = iconWidth;
  368. alignment = Justification::left;
  369. }
  370. else if (alert.getAlertType() == AlertWindow::WarningIcon)
  371. {
  372. Path p;
  373. p.addTriangle (iconRect.getX() + iconRect.getWidth() * 0.5f,
  374. (float) iconRect.getY(),
  375. (float) iconRect.getRight(),
  376. (float) iconRect.getBottom(),
  377. (float) iconRect.getX(),
  378. (float) iconRect.getBottom());
  379. g.setColour (background.overlaidWith (Colour (0x33ff0000)));
  380. g.fillPath (p.createPathWithRoundedCorners (5.0f));
  381. g.setColour (background);
  382. g.setFont (iconRect.getHeight() * 0.9f, Font::bold);
  383. g.drawText (T("!"),
  384. iconRect.getX(),
  385. iconRect.getY(),
  386. iconRect.getWidth(),
  387. iconRect.getHeight() + iconRect.getHeight() / 8,
  388. Justification::centred, false);
  389. iconSpaceUsed = iconWidth;
  390. alignment = Justification::left;
  391. }
  392. g.setColour (alert.findColour (AlertWindow::textColourId));
  393. textLayout.drawWithin (g,
  394. textArea.getX() + iconSpaceUsed,
  395. textArea.getY(),
  396. textArea.getWidth() - iconSpaceUsed,
  397. textArea.getHeight(),
  398. alignment.getFlags() | Justification::top);
  399. g.setColour (alert.findColour (AlertWindow::outlineColourId));
  400. g.drawRect (0, 0, alert.getWidth(), alert.getHeight());
  401. }
  402. int LookAndFeel::getAlertBoxWindowFlags()
  403. {
  404. return ComponentPeer::windowAppearsOnTaskbar
  405. | ComponentPeer::windowHasDropShadow;
  406. }
  407. void LookAndFeel::drawProgressBar (Graphics& g, ProgressBar& progressBar,
  408. int x, int y, int w, int h,
  409. float progress)
  410. {
  411. const Colour background (progressBar.findColour (ProgressBar::backgroundColourId));
  412. g.fillAll (background);
  413. g.setColour (background.contrasting (0.2f));
  414. g.drawRect (x, y, w, h);
  415. drawGlassLozenge (g,
  416. (float) (x + 1),
  417. (float) (y + 1),
  418. jlimit (0.0f, w - 2.0f, progress * (w - 2.0f)),
  419. (float) (h - 2),
  420. progressBar.findColour (ProgressBar::foregroundColourId),
  421. 0.5f,
  422. 0.0f,
  423. true, true, true, true);
  424. }
  425. void LookAndFeel::drawScrollbarButton (Graphics& g,
  426. ScrollBar& scrollbar,
  427. int width, int height,
  428. int buttonDirection,
  429. bool /*isScrollbarVertical*/,
  430. bool /*isMouseOverButton*/,
  431. bool isButtonDown)
  432. {
  433. Path p;
  434. if (buttonDirection == 0)
  435. p.addTriangle (width * 0.5f, height * 0.2f,
  436. width * 0.1f, height * 0.7f,
  437. width * 0.9f, height * 0.7f);
  438. else if (buttonDirection == 1)
  439. p.addTriangle (width * 0.8f, height * 0.5f,
  440. width * 0.3f, height * 0.1f,
  441. width * 0.3f, height * 0.9f);
  442. else if (buttonDirection == 2)
  443. p.addTriangle (width * 0.5f, height * 0.8f,
  444. width * 0.1f, height * 0.3f,
  445. width * 0.9f, height * 0.3f);
  446. else if (buttonDirection == 3)
  447. p.addTriangle (width * 0.2f, height * 0.5f,
  448. width * 0.7f, height * 0.1f,
  449. width * 0.7f, height * 0.9f);
  450. if (isButtonDown)
  451. g.setColour (scrollbar.findColour (ScrollBar::thumbColourId).contrasting (0.2f));
  452. else
  453. g.setColour (scrollbar.findColour (ScrollBar::thumbColourId));
  454. g.fillPath (p);
  455. g.setColour (Colour (0x80000000));
  456. g.strokePath (p, PathStrokeType (0.5f));
  457. }
  458. void LookAndFeel::drawScrollbar (Graphics& g,
  459. ScrollBar& scrollbar,
  460. int x, int y,
  461. int width, int height,
  462. bool isScrollbarVertical,
  463. int thumbStartPosition,
  464. int thumbSize,
  465. bool /*isMouseOver*/,
  466. bool /*isMouseDown*/)
  467. {
  468. g.fillAll (scrollbar.findColour (ScrollBar::backgroundColourId));
  469. Path slotPath, thumbPath;
  470. const float slotIndent = jmin (width, height) > 15 ? 1.0f : 0.0f;
  471. const float slotIndentx2 = slotIndent * 2.0f;
  472. const float thumbIndent = slotIndent + 1.0f;
  473. const float thumbIndentx2 = thumbIndent * 2.0f;
  474. float gx1 = 0.0f, gy1 = 0.0f, gx2 = 0.0f, gy2 = 0.0f;
  475. if (isScrollbarVertical)
  476. {
  477. slotPath.addRoundedRectangle (x + slotIndent,
  478. y + slotIndent,
  479. width - slotIndentx2,
  480. height - slotIndentx2,
  481. (width - slotIndentx2) * 0.5f);
  482. if (thumbSize > 0)
  483. thumbPath.addRoundedRectangle (x + thumbIndent,
  484. thumbStartPosition + thumbIndent,
  485. width - thumbIndentx2,
  486. thumbSize - thumbIndentx2,
  487. (width - thumbIndentx2) * 0.5f);
  488. gx1 = (float) x;
  489. gx2 = x + width * 0.7f;
  490. }
  491. else
  492. {
  493. slotPath.addRoundedRectangle (x + slotIndent,
  494. y + slotIndent,
  495. width - slotIndentx2,
  496. height - slotIndentx2,
  497. (height - slotIndentx2) * 0.5f);
  498. if (thumbSize > 0)
  499. thumbPath.addRoundedRectangle (thumbStartPosition + thumbIndent,
  500. y + thumbIndent,
  501. thumbSize - thumbIndentx2,
  502. height - thumbIndentx2,
  503. (height - thumbIndentx2) * 0.5f);
  504. gy1 = (float) y;
  505. gy2 = y + height * 0.7f;
  506. }
  507. const Colour thumbColour (scrollbar.findColour (ScrollBar::thumbColourId));
  508. GradientBrush gb (thumbColour.overlaidWith (Colour (0x44000000)),
  509. gx1, gy1,
  510. thumbColour.overlaidWith (Colour (0x19000000)),
  511. gx2, gy2, false);
  512. g.setBrush (&gb);
  513. g.fillPath (slotPath);
  514. if (isScrollbarVertical)
  515. {
  516. gx1 = x + width * 0.6f;
  517. gx2 = (float) x + width;
  518. }
  519. else
  520. {
  521. gy1 = y + height * 0.6f;
  522. gy2 = (float) y + height;
  523. }
  524. GradientBrush gb2 (Colours::transparentBlack,
  525. gx1, gy1,
  526. Colour (0x19000000),
  527. gx2, gy2, false);
  528. g.setBrush (&gb2);
  529. g.fillPath (slotPath);
  530. g.setColour (thumbColour);
  531. g.fillPath (thumbPath);
  532. GradientBrush gb3 (Colour (0x10000000),
  533. gx1, gy1,
  534. Colours::transparentBlack,
  535. gx2, gy2, false);
  536. g.saveState();
  537. g.setBrush (&gb3);
  538. if (isScrollbarVertical)
  539. g.reduceClipRegion (x + width / 2, y, width, height);
  540. else
  541. g.reduceClipRegion (x, y + height / 2, width, height);
  542. g.fillPath (thumbPath);
  543. g.restoreState();
  544. g.setColour (Colour (0x4c000000));
  545. g.strokePath (thumbPath, PathStrokeType (0.4f));
  546. }
  547. ImageEffectFilter* LookAndFeel::getScrollbarEffect()
  548. {
  549. return 0;
  550. }
  551. int LookAndFeel::getMinimumScrollbarThumbSize (ScrollBar& scrollbar)
  552. {
  553. return jmin (scrollbar.getWidth(), scrollbar.getHeight()) * 2;
  554. }
  555. int LookAndFeel::getDefaultScrollbarWidth()
  556. {
  557. return 18;
  558. }
  559. int LookAndFeel::getScrollbarButtonSize (ScrollBar& scrollbar)
  560. {
  561. return 2 + (scrollbar.isVertical() ? scrollbar.getWidth()
  562. : scrollbar.getHeight());
  563. }
  564. //==============================================================================
  565. const Path LookAndFeel::getTickShape (const float height)
  566. {
  567. static const unsigned char tickShapeData[] =
  568. {
  569. 109,0,224,168,68,0,0,119,67,108,0,224,172,68,0,128,146,67,113,0,192,148,68,0,0,219,67,0,96,110,68,0,224,56,68,113,0,64,51,68,0,32,130,68,0,64,20,68,0,224,
  570. 162,68,108,0,128,3,68,0,128,168,68,113,0,128,221,67,0,192,175,68,0,0,207,67,0,32,179,68,113,0,0,201,67,0,224,173,68,0,0,181,67,0,224,161,68,108,0,128,168,67,
  571. 0,128,154,68,113,0,128,141,67,0,192,138,68,0,128,108,67,0,64,131,68,113,0,0,62,67,0,128,119,68,0,0,5,67,0,128,114,68,113,0,0,102,67,0,192,88,68,0,128,155,
  572. 67,0,192,88,68,113,0,0,190,67,0,192,88,68,0,128,232,67,0,224,131,68,108,0,128,246,67,0,192,139,68,113,0,64,33,68,0,128,87,68,0,0,93,68,0,224,26,68,113,0,
  573. 96,140,68,0,128,188,67,0,224,168,68,0,0,119,67,99,101
  574. };
  575. Path p;
  576. p.loadPathFromData (tickShapeData, sizeof (tickShapeData));
  577. p.scaleToFit (0, 0, height * 2.0f, height, true);
  578. return p;
  579. }
  580. const Path LookAndFeel::getCrossShape (const float height)
  581. {
  582. static const unsigned char crossShapeData[] =
  583. {
  584. 109,0,0,17,68,0,96,145,68,108,0,192,13,68,0,192,147,68,113,0,0,213,67,0,64,174,68,0,0,168,67,0,64,174,68,113,0,0,104,67,0,64,174,68,0,0,5,67,0,64,
  585. 153,68,113,0,0,18,67,0,64,153,68,0,0,24,67,0,64,153,68,113,0,0,135,67,0,64,153,68,0,128,207,67,0,224,130,68,108,0,0,220,67,0,0,126,68,108,0,0,204,67,
  586. 0,128,117,68,113,0,0,138,67,0,64,82,68,0,0,138,67,0,192,57,68,113,0,0,138,67,0,192,37,68,0,128,210,67,0,64,10,68,113,0,128,220,67,0,64,45,68,0,0,8,
  587. 68,0,128,78,68,108,0,192,14,68,0,0,87,68,108,0,64,20,68,0,0,80,68,113,0,192,57,68,0,0,32,68,0,128,88,68,0,0,32,68,113,0,64,112,68,0,0,32,68,0,
  588. 128,124,68,0,64,68,68,113,0,0,121,68,0,192,67,68,0,128,119,68,0,192,67,68,113,0,192,108,68,0,192,67,68,0,32,89,68,0,96,82,68,113,0,128,69,68,0,0,97,68,
  589. 0,0,56,68,0,64,115,68,108,0,64,49,68,0,128,124,68,108,0,192,55,68,0,96,129,68,113,0,0,92,68,0,224,146,68,0,192,129,68,0,224,146,68,113,0,64,110,68,0,64,
  590. 168,68,0,64,87,68,0,64,168,68,113,0,128,66,68,0,64,168,68,0,64,27,68,0,32,150,68,99,101
  591. };
  592. Path p;
  593. p.loadPathFromData (crossShapeData, sizeof (crossShapeData));
  594. p.scaleToFit (0, 0, height * 2.0f, height, true);
  595. return p;
  596. }
  597. //==============================================================================
  598. void LookAndFeel::drawTreeviewPlusMinusBox (Graphics& g, int x, int y, int w, int h, bool isPlus)
  599. {
  600. const int boxSize = ((jmin (16, w, h) << 1) / 3) | 1;
  601. x += (w - boxSize) >> 1;
  602. y += (h - boxSize) >> 1;
  603. w = boxSize;
  604. h = boxSize;
  605. g.setColour (Colour (0xe5ffffff));
  606. g.fillRect (x, y, w, h);
  607. g.setColour (Colour (0x80000000));
  608. g.drawRect (x, y, w, h);
  609. const float size = boxSize / 2 + 1.0f;
  610. const float centre = (float) (boxSize / 2);
  611. g.fillRect (x + (w - size) * 0.5f, y + centre, size, 1.0f);
  612. if (isPlus)
  613. g.fillRect (x + centre, y + (h - size) * 0.5f, 1.0f, size);
  614. }
  615. //==============================================================================
  616. void LookAndFeel::drawBubble (Graphics& g,
  617. float tipX, float tipY,
  618. float boxX, float boxY,
  619. float boxW, float boxH)
  620. {
  621. int side = 0;
  622. if (tipX < boxX)
  623. side = 1;
  624. else if (tipX > boxX + boxW)
  625. side = 3;
  626. else if (tipY > boxY + boxH)
  627. side = 2;
  628. const float indent = 2.0f;
  629. Path p;
  630. p.addBubble (boxX + indent,
  631. boxY + indent,
  632. boxW - indent * 2.0f,
  633. boxH - indent * 2.0f,
  634. 5.0f,
  635. tipX, tipY,
  636. side,
  637. 0.5f,
  638. jmin (15.0f, boxW * 0.3f, boxH * 0.3f));
  639. //xxx need to take comp as param for colour
  640. g.setColour (findColour (TooltipWindow::backgroundColourId).withAlpha (0.9f));
  641. g.fillPath (p);
  642. //xxx as above
  643. g.setColour (findColour (TooltipWindow::textColourId).withAlpha (0.4f));
  644. g.strokePath (p, PathStrokeType (1.33f));
  645. }
  646. //==============================================================================
  647. const Font LookAndFeel::getPopupMenuFont()
  648. {
  649. return Font (17.0f);
  650. }
  651. void LookAndFeel::getIdealPopupMenuItemSize (const String& text,
  652. const bool isSeparator,
  653. int standardMenuItemHeight,
  654. int& idealWidth,
  655. int& idealHeight)
  656. {
  657. if (isSeparator)
  658. {
  659. idealWidth = 50;
  660. idealHeight = standardMenuItemHeight > 0 ? standardMenuItemHeight / 2 : 10;
  661. }
  662. else
  663. {
  664. Font font (getPopupMenuFont());
  665. if (standardMenuItemHeight > 0 && font.getHeight() > standardMenuItemHeight / 1.3f)
  666. font.setHeight (standardMenuItemHeight / 1.3f);
  667. idealHeight = standardMenuItemHeight > 0 ? standardMenuItemHeight : roundFloatToInt (font.getHeight() * 1.3f);
  668. idealWidth = font.getStringWidth (text) + idealHeight * 2;
  669. }
  670. }
  671. void LookAndFeel::drawPopupMenuBackground (Graphics& g, int width, int height)
  672. {
  673. const Colour background (findColour (PopupMenu::backgroundColourId));
  674. g.fillAll (background);
  675. g.setColour (background.overlaidWith (Colour (0x2badd8e6)));
  676. for (int i = 0; i < height; i += 3)
  677. g.fillRect (0, i, width, 1);
  678. g.setColour (findColour (PopupMenu::textColourId).withAlpha (0.6f));
  679. g.drawRect (0, 0, width, height);
  680. }
  681. void LookAndFeel::drawPopupMenuUpDownArrow (Graphics& g,
  682. int width, int height,
  683. bool isScrollUpArrow)
  684. {
  685. const Colour background (findColour (PopupMenu::backgroundColourId));
  686. GradientBrush gb (background,
  687. 0.0f, height * 0.5f,
  688. background.withAlpha (0.0f),
  689. 0.0f, isScrollUpArrow ? ((float) height) : 0.0f,
  690. false);
  691. g.setBrush (&gb);
  692. g.fillRect (1, 1, width - 2, height - 2);
  693. const float hw = width * 0.5f;
  694. const float arrowW = height * 0.3f;
  695. const float y1 = height * (isScrollUpArrow ? 0.6f : 0.3f);
  696. const float y2 = height * (isScrollUpArrow ? 0.3f : 0.6f);
  697. Path p;
  698. p.addTriangle (hw - arrowW, y1,
  699. hw + arrowW, y1,
  700. hw, y2);
  701. g.setColour (findColour (PopupMenu::textColourId).withAlpha (0.5f));
  702. g.fillPath (p);
  703. }
  704. void LookAndFeel::drawPopupMenuItem (Graphics& g,
  705. int width, int height,
  706. const bool isSeparator,
  707. const bool isActive,
  708. const bool isHighlighted,
  709. const bool isTicked,
  710. const bool hasSubMenu,
  711. const String& text,
  712. const String& shortcutKeyText,
  713. Image* image,
  714. const Colour* const textColourToUse)
  715. {
  716. const float halfH = height * 0.5f;
  717. if (isSeparator)
  718. {
  719. const float separatorIndent = 5.5f;
  720. g.setColour (Colour (0x33000000));
  721. g.drawLine (separatorIndent, halfH, width - separatorIndent, halfH);
  722. g.setColour (Colour (0x66ffffff));
  723. g.drawLine (separatorIndent, halfH + 1.0f, width - separatorIndent, halfH + 1.0f);
  724. }
  725. else
  726. {
  727. Colour textColour (findColour (PopupMenu::textColourId));
  728. if (textColourToUse != 0)
  729. textColour = *textColourToUse;
  730. if (isHighlighted)
  731. {
  732. g.setColour (findColour (PopupMenu::highlightedBackgroundColourId));
  733. g.fillRect (1, 1, width - 2, height - 2);
  734. g.setColour (findColour (PopupMenu::highlightedTextColourId));
  735. }
  736. else
  737. {
  738. g.setColour (textColour);
  739. }
  740. if (! isActive)
  741. g.setOpacity (0.3f);
  742. Font font (getPopupMenuFont());
  743. if (font.getHeight() > height / 1.3f)
  744. font.setHeight (height / 1.3f);
  745. g.setFont (font);
  746. const int leftBorder = (height * 5) / 4;
  747. const int rightBorder = 4;
  748. if (image != 0)
  749. {
  750. g.drawImageWithin (image,
  751. 2, 1, leftBorder - 4, height - 2,
  752. RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false);
  753. }
  754. else if (isTicked)
  755. {
  756. const Path tick (getTickShape (1.0f));
  757. const float th = font.getAscent();
  758. const float ty = halfH - th * 0.5f;
  759. g.fillPath (tick, tick.getTransformToScaleToFit (2.0f, ty, (float) (leftBorder - 4),
  760. th, true));
  761. }
  762. g.drawFittedText (text,
  763. leftBorder, 0,
  764. width - (leftBorder + rightBorder), height,
  765. Justification::centredLeft, 1);
  766. if (shortcutKeyText.isNotEmpty())
  767. {
  768. Font f2 (g.getCurrentFont());
  769. f2.setHeight (f2.getHeight() * 0.75f);
  770. f2.setHorizontalScale (0.95f);
  771. g.setFont (f2);
  772. g.drawText (shortcutKeyText,
  773. leftBorder,
  774. 0,
  775. width - (leftBorder + rightBorder + 4),
  776. height,
  777. Justification::centredRight,
  778. true);
  779. }
  780. if (hasSubMenu)
  781. {
  782. const float arrowH = 0.6f * getPopupMenuFont().getAscent();
  783. const float x = width - height * 0.6f;
  784. Path p;
  785. p.addTriangle (x, halfH - arrowH * 0.5f,
  786. x, halfH + arrowH * 0.5f,
  787. x + arrowH * 0.6f, halfH);
  788. g.fillPath (p);
  789. }
  790. }
  791. }
  792. //==============================================================================
  793. int LookAndFeel::getMenuWindowFlags()
  794. {
  795. return ComponentPeer::windowHasDropShadow;
  796. }
  797. void LookAndFeel::drawMenuBarBackground (Graphics& g, int width, int height,
  798. bool, MenuBarComponent& menuBar)
  799. {
  800. const Colour baseColour (createBaseColour (menuBar.findColour (PopupMenu::backgroundColourId), false, false, false));
  801. if (menuBar.isEnabled())
  802. {
  803. drawShinyButtonShape (g,
  804. -4.0f, 0.0f,
  805. width + 8.0f, (float) height,
  806. 0.0f,
  807. baseColour,
  808. 0.4f,
  809. true, true, true, true);
  810. }
  811. else
  812. {
  813. g.fillAll (baseColour);
  814. }
  815. }
  816. const Font LookAndFeel::getMenuBarFont (MenuBarComponent& menuBar, int /*itemIndex*/, const String& /*itemText*/)
  817. {
  818. return Font (menuBar.getHeight() * 0.7f);
  819. }
  820. int LookAndFeel::getMenuBarItemWidth (MenuBarComponent& menuBar, int itemIndex, const String& itemText)
  821. {
  822. return getMenuBarFont (menuBar, itemIndex, itemText)
  823. .getStringWidth (itemText) + menuBar.getHeight();
  824. }
  825. void LookAndFeel::drawMenuBarItem (Graphics& g,
  826. int width, int height,
  827. int itemIndex,
  828. const String& itemText,
  829. bool isMouseOverItem,
  830. bool isMenuOpen,
  831. bool /*isMouseOverBar*/,
  832. MenuBarComponent& menuBar)
  833. {
  834. if (! menuBar.isEnabled())
  835. {
  836. g.setColour (menuBar.findColour (PopupMenu::textColourId)
  837. .withMultipliedAlpha (0.5f));
  838. }
  839. else if (isMenuOpen || isMouseOverItem)
  840. {
  841. g.fillAll (menuBar.findColour (PopupMenu::highlightedBackgroundColourId));
  842. g.setColour (menuBar.findColour (PopupMenu::highlightedTextColourId));
  843. }
  844. else
  845. {
  846. g.setColour (menuBar.findColour (PopupMenu::textColourId));
  847. }
  848. g.setFont (getMenuBarFont (menuBar, itemIndex, itemText));
  849. g.drawFittedText (itemText, 0, 0, width, height, Justification::centred, 1);
  850. }
  851. //==============================================================================
  852. void LookAndFeel::drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor)
  853. {
  854. if (textEditor.isEnabled())
  855. {
  856. if (textEditor.hasKeyboardFocus (true) && ! textEditor.isReadOnly())
  857. {
  858. const int border = 2;
  859. g.setColour (textEditor.findColour (TextEditor::focusedOutlineColourId));
  860. g.drawRect (0, 0, width, height, border);
  861. g.setOpacity (1.0f);
  862. const Colour shadowColour (textEditor.findColour (TextEditor::shadowColourId).withMultipliedAlpha (0.75f));
  863. g.drawBevel (0, 0, width, height + 2, border + 2, shadowColour, shadowColour);
  864. }
  865. else
  866. {
  867. g.setColour (textEditor.findColour (TextEditor::outlineColourId));
  868. g.drawRect (0, 0, width, height);
  869. g.setOpacity (1.0f);
  870. const Colour shadowColour (textEditor.findColour (TextEditor::shadowColourId));
  871. g.drawBevel (0, 0, width, height + 2, 3, shadowColour, shadowColour);
  872. }
  873. }
  874. }
  875. //==============================================================================
  876. void LookAndFeel::drawComboBox (Graphics& g, int width, int height,
  877. const bool isButtonDown,
  878. int buttonX, int buttonY,
  879. int buttonW, int buttonH,
  880. ComboBox& box)
  881. {
  882. g.fillAll (box.findColour (ComboBox::backgroundColourId));
  883. if (box.isEnabled() && box.hasKeyboardFocus (false))
  884. {
  885. g.setColour (box.findColour (TextButton::buttonColourId));
  886. g.drawRect (0, 0, width, height, 2);
  887. }
  888. else
  889. {
  890. g.setColour (box.findColour (ComboBox::outlineColourId));
  891. g.drawRect (0, 0, width, height);
  892. }
  893. const float outlineThickness = box.isEnabled() ? (isButtonDown ? 1.2f : 0.5f) : 0.3f;
  894. const Colour baseColour (createBaseColour (box.findColour (ComboBox::buttonColourId),
  895. box.hasKeyboardFocus (true),
  896. false, isButtonDown)
  897. .withMultipliedAlpha (box.isEnabled() ? 1.0f : 0.5f));
  898. drawGlassLozenge (g,
  899. buttonX + outlineThickness, buttonY + outlineThickness,
  900. buttonW - outlineThickness * 2.0f, buttonH - outlineThickness * 2.0f,
  901. baseColour, outlineThickness, -1.0f,
  902. true, true, true, true);
  903. if (box.isEnabled())
  904. {
  905. const float arrowX = 0.3f;
  906. const float arrowH = 0.2f;
  907. Path p;
  908. p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.45f - arrowH),
  909. buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.45f,
  910. buttonX + buttonW * arrowX, buttonY + buttonH * 0.45f);
  911. p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.55f + arrowH),
  912. buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.55f,
  913. buttonX + buttonW * arrowX, buttonY + buttonH * 0.55f);
  914. g.setColour (Colour (0x99000000));
  915. g.fillPath (p);
  916. }
  917. }
  918. const Font LookAndFeel::getComboBoxFont (ComboBox& box)
  919. {
  920. const Font f (jmin (15.0f, box.getHeight() * 0.85f));
  921. return f;
  922. }
  923. Label* LookAndFeel::createComboBoxTextBox (ComboBox&)
  924. {
  925. return new Label (String::empty, String::empty);
  926. }
  927. //==============================================================================
  928. void LookAndFeel::drawLinearSliderBackground (Graphics& g,
  929. int x, int y,
  930. int width, int height,
  931. float /*sliderPos*/,
  932. float /*minSliderPos*/,
  933. float /*maxSliderPos*/,
  934. const Slider::SliderStyle /*style*/,
  935. Slider& slider)
  936. {
  937. const float sliderRadius = (float) (getSliderThumbRadius (slider) - 2);
  938. const Colour trackColour (slider.findColour (Slider::trackColourId));
  939. const Colour gradCol1 (trackColour.overlaidWith (Colours::black.withAlpha (slider.isEnabled() ? 0.25f : 0.13f)));
  940. const Colour gradCol2 (trackColour.overlaidWith (Colour (0x14000000)));
  941. Path indent;
  942. if (slider.isHorizontal())
  943. {
  944. const float iy = y + height * 0.5f - sliderRadius * 0.5f;
  945. const float ih = sliderRadius;
  946. GradientBrush gb (gradCol1, 0.0f, iy,
  947. gradCol2, 0.0f, iy + ih, false);
  948. g.setBrush (&gb);
  949. indent.addRoundedRectangle (x - sliderRadius * 0.5f, iy,
  950. width + sliderRadius, ih,
  951. 5.0f);
  952. g.fillPath (indent);
  953. }
  954. else
  955. {
  956. const float ix = x + width * 0.5f - sliderRadius * 0.5f;
  957. const float iw = sliderRadius;
  958. GradientBrush gb (gradCol1, ix, 0.0f,
  959. gradCol2, ix + iw, 0.0f, false);
  960. g.setBrush (&gb);
  961. indent.addRoundedRectangle (ix, y - sliderRadius * 0.5f,
  962. iw, height + sliderRadius,
  963. 5.0f);
  964. g.fillPath (indent);
  965. }
  966. g.setColour (Colour (0x4c000000));
  967. g.strokePath (indent, PathStrokeType (0.5f));
  968. }
  969. void LookAndFeel::drawLinearSliderThumb (Graphics& g,
  970. int x, int y,
  971. int width, int height,
  972. float sliderPos,
  973. float minSliderPos,
  974. float maxSliderPos,
  975. const Slider::SliderStyle style,
  976. Slider& slider)
  977. {
  978. const float sliderRadius = (float) (getSliderThumbRadius (slider) - 2);
  979. Colour knobColour (createBaseColour (slider.findColour (Slider::thumbColourId),
  980. slider.hasKeyboardFocus (false) && slider.isEnabled(),
  981. slider.isMouseOverOrDragging() && slider.isEnabled(),
  982. slider.isMouseButtonDown() && slider.isEnabled()));
  983. const float outlineThickness = slider.isEnabled() ? 0.8f : 0.3f;
  984. if (style == Slider::LinearHorizontal || style == Slider::LinearVertical)
  985. {
  986. float kx, ky;
  987. if (style == Slider::LinearVertical)
  988. {
  989. kx = x + width * 0.5f;
  990. ky = sliderPos;
  991. }
  992. else
  993. {
  994. kx = sliderPos;
  995. ky = y + height * 0.5f;
  996. }
  997. drawGlassSphere (g,
  998. kx - sliderRadius,
  999. ky - sliderRadius,
  1000. sliderRadius * 2.0f,
  1001. knobColour, outlineThickness);
  1002. }
  1003. else
  1004. {
  1005. if (style == Slider::ThreeValueVertical)
  1006. {
  1007. drawGlassSphere (g, x + width * 0.5f - sliderRadius,
  1008. sliderPos - sliderRadius,
  1009. sliderRadius * 2.0f,
  1010. knobColour, outlineThickness);
  1011. }
  1012. else if (style == Slider::ThreeValueHorizontal)
  1013. {
  1014. drawGlassSphere (g,sliderPos - sliderRadius,
  1015. y + height * 0.5f - sliderRadius,
  1016. sliderRadius * 2.0f,
  1017. knobColour, outlineThickness);
  1018. }
  1019. if (style == Slider::TwoValueVertical || style == Slider::ThreeValueVertical)
  1020. {
  1021. const float sr = jmin (sliderRadius, width * 0.4f);
  1022. drawGlassPointer (g, jmax (0.0f, x + width * 0.5f - sliderRadius * 2.0f),
  1023. minSliderPos - sliderRadius,
  1024. sliderRadius * 2.0f, knobColour, outlineThickness, 1);
  1025. drawGlassPointer (g, jmin (x + width - sliderRadius * 2.0f, x + width * 0.5f), maxSliderPos - sr,
  1026. sliderRadius * 2.0f, knobColour, outlineThickness, 3);
  1027. }
  1028. else if (style == Slider::TwoValueHorizontal || style == Slider::ThreeValueHorizontal)
  1029. {
  1030. const float sr = jmin (sliderRadius, height * 0.4f);
  1031. drawGlassPointer (g, minSliderPos - sr,
  1032. jmax (0.0f, y + height * 0.5f - sliderRadius * 2.0f),
  1033. sliderRadius * 2.0f, knobColour, outlineThickness, 2);
  1034. drawGlassPointer (g, maxSliderPos - sliderRadius,
  1035. jmin (y + height - sliderRadius * 2.0f, y + height * 0.5f),
  1036. sliderRadius * 2.0f, knobColour, outlineThickness, 4);
  1037. }
  1038. }
  1039. }
  1040. void LookAndFeel::drawLinearSlider (Graphics& g,
  1041. int x, int y,
  1042. int width, int height,
  1043. float sliderPos,
  1044. float minSliderPos,
  1045. float maxSliderPos,
  1046. const Slider::SliderStyle style,
  1047. Slider& slider)
  1048. {
  1049. g.fillAll (slider.findColour (Slider::backgroundColourId));
  1050. if (style == Slider::LinearBar)
  1051. {
  1052. const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
  1053. Colour baseColour (createBaseColour (slider.findColour (Slider::thumbColourId)
  1054. .withMultipliedSaturation (slider.isEnabled() ? 1.0f : 0.5f),
  1055. false,
  1056. isMouseOver,
  1057. isMouseOver || slider.isMouseButtonDown()));
  1058. drawShinyButtonShape (g,
  1059. (float) x, (float) y, sliderPos - (float) x, (float) height, 0.0f,
  1060. baseColour,
  1061. slider.isEnabled() ? 0.9f : 0.3f,
  1062. true, true, true, true);
  1063. }
  1064. else
  1065. {
  1066. drawLinearSliderBackground (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  1067. drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
  1068. }
  1069. }
  1070. int LookAndFeel::getSliderThumbRadius (Slider& slider)
  1071. {
  1072. return jmin (7,
  1073. slider.getHeight() / 2,
  1074. slider.getWidth() / 2) + 2;
  1075. }
  1076. void LookAndFeel::drawRotarySlider (Graphics& g,
  1077. int x, int y,
  1078. int width, int height,
  1079. float sliderPos,
  1080. const float rotaryStartAngle,
  1081. const float rotaryEndAngle,
  1082. Slider& slider)
  1083. {
  1084. const float radius = jmin (width / 2, height / 2) - 2.0f;
  1085. const float centreX = x + width * 0.5f;
  1086. const float centreY = y + height * 0.5f;
  1087. const float rx = centreX - radius;
  1088. const float ry = centreY - radius;
  1089. const float rw = radius * 2.0f;
  1090. const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
  1091. const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
  1092. if (radius > 12.0f)
  1093. {
  1094. if (slider.isEnabled())
  1095. g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 1.0f : 0.7f));
  1096. else
  1097. g.setColour (Colour (0x80808080));
  1098. const float thickness = 0.7f;
  1099. {
  1100. Path filledArc;
  1101. filledArc.addPieSegment (rx, ry, rw, rw,
  1102. rotaryStartAngle,
  1103. angle,
  1104. thickness);
  1105. g.fillPath (filledArc);
  1106. }
  1107. if (thickness > 0)
  1108. {
  1109. const float innerRadius = radius * 0.2f;
  1110. Path p;
  1111. p.addTriangle (-innerRadius, 0.0f,
  1112. 0.0f, -radius * thickness * 1.1f,
  1113. innerRadius, 0.0f);
  1114. p.addEllipse (-innerRadius, -innerRadius, innerRadius * 2.0f, innerRadius * 2.0f);
  1115. g.fillPath (p, AffineTransform::rotation (angle).translated (centreX, centreY));
  1116. }
  1117. if (slider.isEnabled())
  1118. {
  1119. g.setColour (slider.findColour (Slider::rotarySliderOutlineColourId));
  1120. Path outlineArc;
  1121. outlineArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, rotaryEndAngle, thickness);
  1122. outlineArc.closeSubPath();
  1123. g.strokePath (outlineArc, PathStrokeType (slider.isEnabled() ? (isMouseOver ? 2.0f : 1.2f) : 0.3f));
  1124. }
  1125. }
  1126. else
  1127. {
  1128. if (slider.isEnabled())
  1129. g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 1.0f : 0.7f));
  1130. else
  1131. g.setColour (Colour (0x80808080));
  1132. Path p;
  1133. p.addEllipse (-0.4f * rw, -0.4f * rw, rw * 0.8f, rw * 0.8f);
  1134. PathStrokeType (rw * 0.1f).createStrokedPath (p, p);
  1135. p.addLineSegment (0.0f, 0.0f, 0.0f, -radius, rw * 0.2f);
  1136. g.fillPath (p, AffineTransform::rotation (angle).translated (centreX, centreY));
  1137. }
  1138. }
  1139. Button* LookAndFeel::createSliderButton (const bool isIncrement)
  1140. {
  1141. return new TextButton (isIncrement ? "+" : "-", String::empty);
  1142. }
  1143. Label* LookAndFeel::createSliderTextBox (Slider& slider)
  1144. {
  1145. Label* const l = new Label (T("n"), String::empty);
  1146. l->setJustificationType (Justification::centred);
  1147. l->setColour (Label::textColourId, slider.findColour (Slider::textBoxTextColourId));
  1148. l->setColour (Label::backgroundColourId,
  1149. (slider.getSliderStyle() == Slider::LinearBar) ? Colours::transparentBlack
  1150. : slider.findColour (Slider::textBoxBackgroundColourId));
  1151. l->setColour (Label::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId));
  1152. l->setColour (TextEditor::textColourId, slider.findColour (Slider::textBoxTextColourId));
  1153. l->setColour (TextEditor::backgroundColourId,
  1154. slider.findColour (Slider::textBoxBackgroundColourId)
  1155. .withAlpha (slider.getSliderStyle() == Slider::LinearBar ? 0.7f : 1.0f));
  1156. l->setColour (TextEditor::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId));
  1157. return l;
  1158. }
  1159. ImageEffectFilter* LookAndFeel::getSliderEffect()
  1160. {
  1161. return 0;
  1162. }
  1163. //==============================================================================
  1164. static const TextLayout layoutTooltipText (const String& text) throw()
  1165. {
  1166. const float tooltipFontSize = 15.0f;
  1167. const int maxToolTipWidth = 400;
  1168. const Font f (tooltipFontSize, Font::bold);
  1169. TextLayout tl (text, f);
  1170. tl.layout (maxToolTipWidth, Justification::left, true);
  1171. return tl;
  1172. }
  1173. void LookAndFeel::getTooltipSize (const String& tipText, int& width, int& height)
  1174. {
  1175. const TextLayout tl (layoutTooltipText (tipText));
  1176. width = tl.getWidth() + 14;
  1177. height = tl.getHeight() + 10;
  1178. }
  1179. void LookAndFeel::drawTooltip (Graphics& g, const String& text, int width, int height)
  1180. {
  1181. g.fillAll (findColour (TooltipWindow::backgroundColourId));
  1182. const Colour textCol (findColour (TooltipWindow::textColourId));
  1183. g.setColour (findColour (TooltipWindow::outlineColourId));
  1184. g.drawRect (0, 0, width, height);
  1185. const TextLayout tl (layoutTooltipText (text));
  1186. g.setColour (findColour (TooltipWindow::textColourId));
  1187. tl.drawWithin (g, 0, 0, width, height, Justification::centred);
  1188. }
  1189. //==============================================================================
  1190. Button* LookAndFeel::createFilenameComponentBrowseButton (const String& text)
  1191. {
  1192. return new TextButton (text, TRANS("click to browse for a different file"));
  1193. }
  1194. void LookAndFeel::layoutFilenameComponent (FilenameComponent& filenameComp,
  1195. ComboBox* filenameBox,
  1196. Button* browseButton)
  1197. {
  1198. browseButton->setSize (80, filenameComp.getHeight());
  1199. TextButton* const tb = dynamic_cast <TextButton*> (browseButton);
  1200. if (tb != 0)
  1201. tb->changeWidthToFitText();
  1202. browseButton->setTopRightPosition (filenameComp.getWidth(), 0);
  1203. filenameBox->setBounds (0, 0, browseButton->getX(), filenameComp.getHeight());
  1204. }
  1205. //==============================================================================
  1206. void LookAndFeel::drawCornerResizer (Graphics& g,
  1207. int w, int h,
  1208. bool /*isMouseOver*/,
  1209. bool /*isMouseDragging*/)
  1210. {
  1211. const float lineThickness = jmin (w, h) * 0.075f;
  1212. for (float i = 0.0f; i < 1.0f; i += 0.3f)
  1213. {
  1214. g.setColour (Colours::lightgrey);
  1215. g.drawLine (w * i,
  1216. h + 1.0f,
  1217. w + 1.0f,
  1218. h * i,
  1219. lineThickness);
  1220. g.setColour (Colours::darkgrey);
  1221. g.drawLine (w * i + lineThickness,
  1222. h + 1.0f,
  1223. w + 1.0f,
  1224. h * i + lineThickness,
  1225. lineThickness);
  1226. }
  1227. }
  1228. void LookAndFeel::drawResizableFrame (Graphics&, int /*w*/, int /*h*/,
  1229. const BorderSize& /*borders*/)
  1230. {
  1231. }
  1232. //==============================================================================
  1233. void LookAndFeel::drawResizableWindowBorder (Graphics& g, int w, int h,
  1234. const BorderSize& border, ResizableWindow&)
  1235. {
  1236. g.setColour (Colour (0x80000000));
  1237. g.drawRect (0, 0, w, h);
  1238. g.setColour (Colour (0x19000000));
  1239. g.drawRect (border.getLeft() - 1,
  1240. border.getTop() - 1,
  1241. w + 2 - border.getLeftAndRight(),
  1242. h + 2 - border.getTopAndBottom());
  1243. }
  1244. void LookAndFeel::drawDocumentWindowTitleBar (DocumentWindow& window,
  1245. Graphics& g, int w, int h,
  1246. int titleSpaceX, int titleSpaceW,
  1247. const Image* icon,
  1248. bool drawTitleTextOnLeft)
  1249. {
  1250. const bool isActive = window.isActiveWindow();
  1251. GradientBrush gb (window.getBackgroundColour(),
  1252. 0.0f, 0.0f,
  1253. window.getBackgroundColour().contrasting (isActive ? 0.15f : 0.05f),
  1254. 0.0f, (float) h, false);
  1255. g.setBrush (&gb);
  1256. g.fillAll();
  1257. g.setFont (h * 0.65f, Font::bold);
  1258. int textW = g.getCurrentFont().getStringWidth (window.getName());
  1259. int iconW = 0;
  1260. int iconH = 0;
  1261. if (icon != 0)
  1262. {
  1263. iconH = (int) g.getCurrentFont().getHeight();
  1264. iconW = icon->getWidth() * iconH / icon->getHeight() + 4;
  1265. }
  1266. textW = jmin (titleSpaceW, textW + iconW);
  1267. int textX = drawTitleTextOnLeft ? titleSpaceX
  1268. : jmax (titleSpaceX, (w - textW) / 2);
  1269. if (textX + textW > titleSpaceX + titleSpaceW)
  1270. textX = titleSpaceX + titleSpaceW - textW;
  1271. if (icon != 0)
  1272. {
  1273. g.setOpacity (isActive ? 1.0f : 0.6f);
  1274. g.drawImageWithin (icon, textX, (h - iconH) / 2, iconW, iconH,
  1275. RectanglePlacement::centred, false);
  1276. textX += iconW;
  1277. textW -= iconW;
  1278. }
  1279. g.setColour (window.getBackgroundColour().contrasting (isActive ? 0.7f : 0.4f));
  1280. g.drawText (window.getName(), textX, 0, textW, h, Justification::centredLeft, true);
  1281. }
  1282. //==============================================================================
  1283. class GlassWindowButton : public Button
  1284. {
  1285. public:
  1286. //==============================================================================
  1287. GlassWindowButton (const String& name, const Colour& col,
  1288. const Path& normalShape_,
  1289. const Path& toggledShape_) throw()
  1290. : Button (name),
  1291. colour (col),
  1292. normalShape (normalShape_),
  1293. toggledShape (toggledShape_)
  1294. {
  1295. }
  1296. ~GlassWindowButton()
  1297. {
  1298. }
  1299. //==============================================================================
  1300. void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown)
  1301. {
  1302. float alpha = isMouseOverButton ? (isButtonDown ? 1.0f : 0.8f) : 0.55f;
  1303. if (! isEnabled())
  1304. alpha *= 0.5f;
  1305. float x = 0, y = 0, diam;
  1306. if (getWidth() < getHeight())
  1307. {
  1308. diam = (float) getWidth();
  1309. y = (getHeight() - getWidth()) * 0.5f;
  1310. }
  1311. else
  1312. {
  1313. diam = (float) getHeight();
  1314. y = (getWidth() - getHeight()) * 0.5f;
  1315. }
  1316. x += diam * 0.05f;
  1317. y += diam * 0.05f;
  1318. diam *= 0.9f;
  1319. GradientBrush gb1 (Colour::greyLevel (0.9f).withAlpha (alpha), 0, y + diam,
  1320. Colour::greyLevel (0.6f).withAlpha (alpha), 0, y, false);
  1321. g.setBrush (&gb1);
  1322. g.fillEllipse (x, y, diam, diam);
  1323. x += 2.0f;
  1324. y += 2.0f;
  1325. diam -= 4.0f;
  1326. LookAndFeel::drawGlassSphere (g, x, y, diam, colour.withAlpha (alpha), 1.0f);
  1327. Path& p = getToggleState() ? toggledShape : normalShape;
  1328. const AffineTransform t (p.getTransformToScaleToFit (x + diam * 0.3f, y + diam * 0.3f,
  1329. diam * 0.4f, diam * 0.4f, true));
  1330. g.setColour (Colours::black.withAlpha (alpha * 0.6f));
  1331. g.fillPath (p, t);
  1332. }
  1333. //==============================================================================
  1334. juce_UseDebuggingNewOperator
  1335. private:
  1336. Colour colour;
  1337. Path normalShape, toggledShape;
  1338. GlassWindowButton (const GlassWindowButton&);
  1339. const GlassWindowButton& operator= (const GlassWindowButton&);
  1340. };
  1341. Button* LookAndFeel::createDocumentWindowButton (int buttonType)
  1342. {
  1343. Path shape;
  1344. const float crossThickness = 0.25f;
  1345. if (buttonType == DocumentWindow::closeButton)
  1346. {
  1347. shape.addLineSegment (0.0f, 0.0f, 1.0f, 1.0f, crossThickness * 1.4f);
  1348. shape.addLineSegment (1.0f, 0.0f, 0.0f, 1.0f, crossThickness * 1.4f);
  1349. return new GlassWindowButton ("close", Colour (0xffdd1100), shape, shape);
  1350. }
  1351. else if (buttonType == DocumentWindow::minimiseButton)
  1352. {
  1353. shape.addLineSegment (0.0f, 0.5f, 1.0f, 0.5f, crossThickness);
  1354. return new GlassWindowButton ("minimise", Colour (0xffaa8811), shape, shape);
  1355. }
  1356. else if (buttonType == DocumentWindow::maximiseButton)
  1357. {
  1358. shape.addLineSegment (0.5f, 0.0f, 0.5f, 1.0f, crossThickness);
  1359. shape.addLineSegment (0.0f, 0.5f, 1.0f, 0.5f, crossThickness);
  1360. Path fullscreenShape;
  1361. fullscreenShape.startNewSubPath (45.0f, 100.0f);
  1362. fullscreenShape.lineTo (0.0f, 100.0f);
  1363. fullscreenShape.lineTo (0.0f, 0.0f);
  1364. fullscreenShape.lineTo (100.0f, 0.0f);
  1365. fullscreenShape.lineTo (100.0f, 45.0f);
  1366. fullscreenShape.addRectangle (45.0f, 45.0f, 100.0f, 100.0f);
  1367. PathStrokeType (30.0f).createStrokedPath (fullscreenShape, fullscreenShape);
  1368. return new GlassWindowButton ("maximise", Colour (0xff119911), shape, fullscreenShape);
  1369. }
  1370. jassertfalse
  1371. return 0;
  1372. }
  1373. void LookAndFeel::positionDocumentWindowButtons (DocumentWindow&,
  1374. int titleBarX,
  1375. int titleBarY,
  1376. int titleBarW,
  1377. int titleBarH,
  1378. Button* minimiseButton,
  1379. Button* maximiseButton,
  1380. Button* closeButton,
  1381. bool positionTitleBarButtonsOnLeft)
  1382. {
  1383. const int buttonW = titleBarH - titleBarH / 8;
  1384. int x = positionTitleBarButtonsOnLeft ? titleBarX + 4
  1385. : titleBarX + titleBarW - buttonW - buttonW / 4;
  1386. if (closeButton != 0)
  1387. {
  1388. closeButton->setBounds (x, titleBarY, buttonW, titleBarH);
  1389. x += positionTitleBarButtonsOnLeft ? buttonW : -(buttonW + buttonW / 4);
  1390. }
  1391. if (positionTitleBarButtonsOnLeft)
  1392. swapVariables (minimiseButton, maximiseButton);
  1393. if (maximiseButton != 0)
  1394. {
  1395. maximiseButton->setBounds (x, titleBarY, buttonW, titleBarH);
  1396. x += positionTitleBarButtonsOnLeft ? buttonW : -buttonW;
  1397. }
  1398. if (minimiseButton != 0)
  1399. minimiseButton->setBounds (x, titleBarY, buttonW, titleBarH);
  1400. }
  1401. int LookAndFeel::getDefaultMenuBarHeight()
  1402. {
  1403. return 24;
  1404. }
  1405. //==============================================================================
  1406. DropShadower* LookAndFeel::createDropShadowerForComponent (Component*)
  1407. {
  1408. return new DropShadower (0.4f, 1, 5, 10);
  1409. }
  1410. //==============================================================================
  1411. void LookAndFeel::drawStretchableLayoutResizerBar (Graphics& g,
  1412. int w, int h,
  1413. bool /*isVerticalBar*/,
  1414. bool isMouseOver,
  1415. bool isMouseDragging)
  1416. {
  1417. float alpha = 0.5f;
  1418. if (isMouseOver || isMouseDragging)
  1419. {
  1420. g.fillAll (Colour (0x190000ff));
  1421. alpha = 1.0f;
  1422. }
  1423. const float cx = w * 0.5f;
  1424. const float cy = h * 0.5f;
  1425. const float cr = jmin (w, h) * 0.4f;
  1426. GradientBrush gb (Colours::white.withAlpha (alpha), cx + cr * 0.1f, cy + cr,
  1427. Colours::black.withAlpha (alpha), cx, cy - cr * 4.0f,
  1428. true);
  1429. g.setBrush (&gb);
  1430. g.fillEllipse (cx - cr, cy - cr, cr * 2.0f, cr * 2.0f);
  1431. }
  1432. //==============================================================================
  1433. void LookAndFeel::drawGroupComponentOutline (Graphics& g, int width, int height,
  1434. const String& text,
  1435. const Justification& position,
  1436. GroupComponent& group)
  1437. {
  1438. const float textH = 15.0f;
  1439. const float indent = 3.0f;
  1440. const float textEdgeGap = 4.0f;
  1441. float cs = 5.0f;
  1442. Font f (textH);
  1443. Path p;
  1444. float x = indent;
  1445. float y = f.getAscent() - 3.0f;
  1446. float w = jmax (0.0f, width - x * 2.0f);
  1447. float h = jmax (0.0f, height - y - indent);
  1448. cs = jmin (cs, w * 0.5f, h * 0.5f);
  1449. const float cs2 = 2.0f * cs;
  1450. float textW = text.isEmpty() ? 0 : jlimit (0.0f, jmax (0.0f, w - cs2 - textEdgeGap * 2), f.getStringWidth (text) + textEdgeGap * 2.0f);
  1451. float textX = cs + textEdgeGap;
  1452. if (position.testFlags (Justification::horizontallyCentred))
  1453. textX = cs + (w - cs2 - textW) * 0.5f;
  1454. else if (position.testFlags (Justification::right))
  1455. textX = w - cs - textW - textEdgeGap;
  1456. p.startNewSubPath (x + textX + textW, y);
  1457. p.lineTo (x + w - cs, y);
  1458. p.addArc (x + w - cs2, y, cs2, cs2, 0, float_Pi * 0.5f);
  1459. p.lineTo (x + w, y + h - cs);
  1460. p.addArc (x + w - cs2, y + h - cs2, cs2, cs2, float_Pi * 0.5f, float_Pi);
  1461. p.lineTo (x + cs, y + h);
  1462. p.addArc (x, y + h - cs2, cs2, cs2, float_Pi, float_Pi * 1.5f);
  1463. p.lineTo (x, y + cs);
  1464. p.addArc (x, y, cs2, cs2, float_Pi * 1.5f, float_Pi * 2.0f);
  1465. p.lineTo (x + textX, y);
  1466. const float alpha = group.isEnabled() ? 1.0f : 0.5f;
  1467. g.setColour (group.findColour (GroupComponent::outlineColourId)
  1468. .withMultipliedAlpha (alpha));
  1469. g.strokePath (p, PathStrokeType (2.0f));
  1470. g.setColour (group.findColour (GroupComponent::textColourId)
  1471. .withMultipliedAlpha (alpha));
  1472. g.setFont (f);
  1473. g.drawText (text,
  1474. roundFloatToInt (x + textX), 0,
  1475. roundFloatToInt (textW),
  1476. roundFloatToInt (textH),
  1477. Justification::centred, true);
  1478. }
  1479. //==============================================================================
  1480. int LookAndFeel::getTabButtonOverlap (int tabDepth)
  1481. {
  1482. return 1 + tabDepth / 3;
  1483. }
  1484. int LookAndFeel::getTabButtonSpaceAroundImage()
  1485. {
  1486. return 4;
  1487. }
  1488. void LookAndFeel::createTabButtonShape (Path& p,
  1489. int width, int height,
  1490. int /*tabIndex*/,
  1491. const String& /*text*/,
  1492. Button& /*button*/,
  1493. TabbedButtonBar::Orientation orientation,
  1494. const bool /*isMouseOver*/,
  1495. const bool /*isMouseDown*/,
  1496. const bool /*isFrontTab*/)
  1497. {
  1498. const float w = (float) width;
  1499. const float h = (float) height;
  1500. float length = w;
  1501. float depth = h;
  1502. if (orientation == TabbedButtonBar::TabsAtLeft
  1503. || orientation == TabbedButtonBar::TabsAtRight)
  1504. {
  1505. swapVariables (length, depth);
  1506. }
  1507. const float indent = (float) getTabButtonOverlap ((int) depth);
  1508. const float overhang = 4.0f;
  1509. if (orientation == TabbedButtonBar::TabsAtLeft)
  1510. {
  1511. p.startNewSubPath (w, 0.0f);
  1512. p.lineTo (0.0f, indent);
  1513. p.lineTo (0.0f, h - indent);
  1514. p.lineTo (w, h);
  1515. p.lineTo (w + overhang, h + overhang);
  1516. p.lineTo (w + overhang, -overhang);
  1517. }
  1518. else if (orientation == TabbedButtonBar::TabsAtRight)
  1519. {
  1520. p.startNewSubPath (0.0f, 0.0f);
  1521. p.lineTo (w, indent);
  1522. p.lineTo (w, h - indent);
  1523. p.lineTo (0.0f, h);
  1524. p.lineTo (-overhang, h + overhang);
  1525. p.lineTo (-overhang, -overhang);
  1526. }
  1527. else if (orientation == TabbedButtonBar::TabsAtBottom)
  1528. {
  1529. p.startNewSubPath (0.0f, 0.0f);
  1530. p.lineTo (indent, h);
  1531. p.lineTo (w - indent, h);
  1532. p.lineTo (w, 0.0f);
  1533. p.lineTo (w + overhang, -overhang);
  1534. p.lineTo (-overhang, -overhang);
  1535. }
  1536. else
  1537. {
  1538. p.startNewSubPath (0.0f, h);
  1539. p.lineTo (indent, 0.0f);
  1540. p.lineTo (w - indent, 0.0f);
  1541. p.lineTo (w, h);
  1542. p.lineTo (w + overhang, h + overhang);
  1543. p.lineTo (-overhang, h + overhang);
  1544. }
  1545. p.closeSubPath();
  1546. p = p.createPathWithRoundedCorners (3.0f);
  1547. }
  1548. void LookAndFeel::fillTabButtonShape (Graphics& g,
  1549. const Path& path,
  1550. const Colour& preferredColour,
  1551. int /*tabIndex*/,
  1552. const String& /*text*/,
  1553. Button& button,
  1554. TabbedButtonBar::Orientation /*orientation*/,
  1555. const bool /*isMouseOver*/,
  1556. const bool /*isMouseDown*/,
  1557. const bool isFrontTab)
  1558. {
  1559. g.setColour (isFrontTab ? preferredColour
  1560. : preferredColour.withMultipliedAlpha (0.9f));
  1561. g.fillPath (path);
  1562. g.setColour (Colours::black.withAlpha (button.isEnabled() ? 0.5f : 0.25f));
  1563. g.strokePath (path, PathStrokeType (isFrontTab ? 1.0f : 0.5f));
  1564. }
  1565. void LookAndFeel::drawTabButtonText (Graphics& g,
  1566. int x, int y, int w, int h,
  1567. const Colour& preferredBackgroundColour,
  1568. int /*tabIndex*/,
  1569. const String& text,
  1570. Button& button,
  1571. TabbedButtonBar::Orientation orientation,
  1572. const bool isMouseOver,
  1573. const bool isMouseDown,
  1574. const bool /*isFrontTab*/)
  1575. {
  1576. int length = w;
  1577. int depth = h;
  1578. if (orientation == TabbedButtonBar::TabsAtLeft
  1579. || orientation == TabbedButtonBar::TabsAtRight)
  1580. {
  1581. swapVariables (length, depth);
  1582. }
  1583. Font font (depth * 0.6f);
  1584. font.setUnderline (button.hasKeyboardFocus (false));
  1585. GlyphArrangement textLayout;
  1586. textLayout.addFittedText (font, text.trim(),
  1587. 0.0f, 0.0f, (float) length, (float) depth,
  1588. Justification::centred,
  1589. jmax (1, depth / 12));
  1590. AffineTransform transform;
  1591. if (orientation == TabbedButtonBar::TabsAtLeft)
  1592. {
  1593. transform = transform.rotated (float_Pi * -0.5f)
  1594. .translated ((float) x, (float) (y + h));
  1595. }
  1596. else if (orientation == TabbedButtonBar::TabsAtRight)
  1597. {
  1598. transform = transform.rotated (float_Pi * 0.5f)
  1599. .translated ((float) (x + w), (float) y);
  1600. }
  1601. else
  1602. {
  1603. transform = transform.translated ((float) x, (float) y);
  1604. }
  1605. g.setColour (preferredBackgroundColour.contrasting());
  1606. if (! (isMouseOver || isMouseDown))
  1607. g.setOpacity (0.8f);
  1608. if (! button.isEnabled())
  1609. g.setOpacity (0.3f);
  1610. textLayout.draw (g, transform);
  1611. }
  1612. int LookAndFeel::getTabButtonBestWidth (int /*tabIndex*/,
  1613. const String& text,
  1614. int tabDepth,
  1615. Button&)
  1616. {
  1617. Font f (tabDepth * 0.6f);
  1618. return f.getStringWidth (text.trim()) + getTabButtonOverlap (tabDepth) * 2;
  1619. }
  1620. void LookAndFeel::drawTabButton (Graphics& g,
  1621. int w, int h,
  1622. const Colour& preferredColour,
  1623. int tabIndex,
  1624. const String& text,
  1625. Button& button,
  1626. TabbedButtonBar::Orientation orientation,
  1627. const bool isMouseOver,
  1628. const bool isMouseDown,
  1629. const bool isFrontTab)
  1630. {
  1631. int length = w;
  1632. int depth = h;
  1633. if (orientation == TabbedButtonBar::TabsAtLeft
  1634. || orientation == TabbedButtonBar::TabsAtRight)
  1635. {
  1636. swapVariables (length, depth);
  1637. }
  1638. Path tabShape;
  1639. createTabButtonShape (tabShape, w, h,
  1640. tabIndex, text, button, orientation,
  1641. isMouseOver, isMouseDown, isFrontTab);
  1642. fillTabButtonShape (g, tabShape, preferredColour,
  1643. tabIndex, text, button, orientation,
  1644. isMouseOver, isMouseDown, isFrontTab);
  1645. const int indent = getTabButtonOverlap (depth);
  1646. int x = 0, y = 0;
  1647. if (orientation == TabbedButtonBar::TabsAtLeft
  1648. || orientation == TabbedButtonBar::TabsAtRight)
  1649. {
  1650. y += indent;
  1651. h -= indent * 2;
  1652. }
  1653. else
  1654. {
  1655. x += indent;
  1656. w -= indent * 2;
  1657. }
  1658. drawTabButtonText (g, x, y, w, h, preferredColour,
  1659. tabIndex, text, button, orientation,
  1660. isMouseOver, isMouseDown, isFrontTab);
  1661. }
  1662. void LookAndFeel::drawTabAreaBehindFrontButton (Graphics& g,
  1663. int w, int h,
  1664. TabbedButtonBar& tabBar,
  1665. TabbedButtonBar::Orientation orientation)
  1666. {
  1667. const float shadowSize = 0.2f;
  1668. float x1 = 0.0f, y1 = 0.0f, x2 = 0.0f, y2 = 0.0f;
  1669. Rectangle shadowRect;
  1670. if (orientation == TabbedButtonBar::TabsAtLeft)
  1671. {
  1672. x1 = (float) w;
  1673. x2 = w * (1.0f - shadowSize);
  1674. shadowRect.setBounds ((int) x2, 0, w - (int) x2, h);
  1675. }
  1676. else if (orientation == TabbedButtonBar::TabsAtRight)
  1677. {
  1678. x2 = w * shadowSize;
  1679. shadowRect.setBounds (0, 0, (int) x2, h);
  1680. }
  1681. else if (orientation == TabbedButtonBar::TabsAtBottom)
  1682. {
  1683. y2 = h * shadowSize;
  1684. shadowRect.setBounds (0, 0, w, (int) y2);
  1685. }
  1686. else
  1687. {
  1688. y1 = (float) h;
  1689. y2 = h * (1.0f - shadowSize);
  1690. shadowRect.setBounds (0, (int) y2, w, h - (int) y2);
  1691. }
  1692. GradientBrush gb (Colours::black.withAlpha (tabBar.isEnabled() ? 0.3f : 0.15f), x1, y1,
  1693. Colours::transparentBlack, x2, y2,
  1694. false);
  1695. g.setBrush (&gb);
  1696. shadowRect.expand (2, 2);
  1697. g.fillRect (shadowRect);
  1698. g.setColour (Colour (0x80000000));
  1699. if (orientation == TabbedButtonBar::TabsAtLeft)
  1700. {
  1701. g.fillRect (w - 1, 0, 1, h);
  1702. }
  1703. else if (orientation == TabbedButtonBar::TabsAtRight)
  1704. {
  1705. g.fillRect (0, 0, 1, h);
  1706. }
  1707. else if (orientation == TabbedButtonBar::TabsAtBottom)
  1708. {
  1709. g.fillRect (0, 0, w, 1);
  1710. }
  1711. else
  1712. {
  1713. g.fillRect (0, h - 1, w, 1);
  1714. }
  1715. }
  1716. Button* LookAndFeel::createTabBarExtrasButton()
  1717. {
  1718. const float thickness = 7.0f;
  1719. const float indent = 22.0f;
  1720. Path p;
  1721. p.addEllipse (-10.0f, -10.0f, 120.0f, 120.0f);
  1722. DrawablePath ellipse;
  1723. ellipse.setPath (p);
  1724. ellipse.setSolidFill (Colour (0x99ffffff));
  1725. p.clear();
  1726. p.addEllipse (0.0f, 0.0f, 100.0f, 100.0f);
  1727. p.addRectangle (indent, 50.0f - thickness, 100.0f - indent * 2.0f, thickness * 2.0f);
  1728. p.addRectangle (50.0f - thickness, indent, thickness * 2.0f, 50.0f - indent - thickness);
  1729. p.addRectangle (50.0f - thickness, 50.0f + thickness, thickness * 2.0f, 50.0f - indent - thickness);
  1730. p.setUsingNonZeroWinding (false);
  1731. DrawablePath dp;
  1732. dp.setPath (p);
  1733. dp.setSolidFill (Colour (0x59000000));
  1734. DrawableComposite normalImage;
  1735. normalImage.insertDrawable (ellipse);
  1736. normalImage.insertDrawable (dp);
  1737. dp.setSolidFill (Colour (0xcc000000));
  1738. DrawableComposite overImage;
  1739. overImage.insertDrawable (ellipse);
  1740. overImage.insertDrawable (dp);
  1741. DrawableButton* db = new DrawableButton (T("tabs"), DrawableButton::ImageFitted);
  1742. db->setImages (&normalImage, &overImage, 0);
  1743. return db;
  1744. }
  1745. //==============================================================================
  1746. void LookAndFeel::drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header)
  1747. {
  1748. g.fillAll (Colours::white);
  1749. const int w = header.getWidth();
  1750. const int h = header.getHeight();
  1751. GradientBrush gb (Colour (0xffe8ebf9), 0.0f, h * 0.5f,
  1752. Colour (0xfff6f8f9), 0.0f, h - 1.0f,
  1753. false);
  1754. g.setBrush (&gb);
  1755. g.fillRect (0, h / 2, w, h);
  1756. g.setColour (Colour (0x33000000));
  1757. g.fillRect (0, h - 1, w, 1);
  1758. for (int i = header.getNumColumns (true); --i >= 0;)
  1759. g.fillRect (header.getColumnPosition (i).getRight() - 1, 0, 1, h - 1);
  1760. }
  1761. void LookAndFeel::drawTableHeaderColumn (Graphics& g, const String& columnName, int /*columnId*/,
  1762. int width, int height,
  1763. bool isMouseOver, bool isMouseDown,
  1764. int columnFlags)
  1765. {
  1766. if (isMouseDown)
  1767. g.fillAll (Colour (0x8899aadd));
  1768. else if (isMouseOver)
  1769. g.fillAll (Colour (0x5599aadd));
  1770. int rightOfText = width - 4;
  1771. if ((columnFlags & (TableHeaderComponent::sortedForwards | TableHeaderComponent::sortedBackwards)) != 0)
  1772. {
  1773. const float top = height * ((columnFlags & TableHeaderComponent::sortedForwards) != 0 ? 0.35f : (1.0f - 0.35f));
  1774. const float bottom = height - top;
  1775. const float w = height * 0.5f;
  1776. const float x = rightOfText - (w * 1.25f);
  1777. rightOfText = (int) x;
  1778. Path sortArrow;
  1779. sortArrow.addTriangle (x, bottom, x + w * 0.5f, top, x + w, bottom);
  1780. g.setColour (Colour (0x99000000));
  1781. g.fillPath (sortArrow);
  1782. }
  1783. g.setColour (Colours::black);
  1784. g.setFont (height * 0.5f, Font::bold);
  1785. const int textX = 4;
  1786. g.drawFittedText (columnName, textX, 0, rightOfText - textX, height, Justification::centredLeft, 1);
  1787. }
  1788. //==============================================================================
  1789. void LookAndFeel::paintToolbarBackground (Graphics& g, int w, int h, Toolbar& toolbar)
  1790. {
  1791. const Colour background (toolbar.findColour (Toolbar::backgroundColourId));
  1792. GradientBrush gb (background, 0.0f, 0.0f,
  1793. background.darker (0.1f),
  1794. toolbar.isVertical() ? w - 1.0f : 0.0f,
  1795. toolbar.isVertical() ? 0.0f : h - 1.0f,
  1796. false);
  1797. g.setBrush (&gb);
  1798. g.fillAll();
  1799. }
  1800. Button* LookAndFeel::createToolbarMissingItemsButton (Toolbar& /*toolbar*/)
  1801. {
  1802. return createTabBarExtrasButton();
  1803. }
  1804. void LookAndFeel::paintToolbarButtonBackground (Graphics& g, int /*width*/, int /*height*/,
  1805. bool isMouseOver, bool isMouseDown,
  1806. ToolbarItemComponent& component)
  1807. {
  1808. if (isMouseDown)
  1809. g.fillAll (component.findColour (Toolbar::buttonMouseDownBackgroundColourId, true));
  1810. else if (isMouseOver)
  1811. g.fillAll (component.findColour (Toolbar::buttonMouseOverBackgroundColourId, true));
  1812. }
  1813. void LookAndFeel::paintToolbarButtonLabel (Graphics& g, int x, int y, int width, int height,
  1814. const String& text, ToolbarItemComponent& component)
  1815. {
  1816. g.setColour (component.findColour (Toolbar::labelTextColourId, true)
  1817. .withAlpha (component.isEnabled() ? 1.0f : 0.25f));
  1818. const float fontHeight = jmin (14.0f, height * 0.85f);
  1819. g.setFont (fontHeight);
  1820. g.drawFittedText (text,
  1821. x, y, width, height,
  1822. Justification::centred,
  1823. jmax (1, height / (int) fontHeight));
  1824. }
  1825. //==============================================================================
  1826. void LookAndFeel::drawPropertyPanelSectionHeader (Graphics& g, const String& name,
  1827. bool isOpen, int width, int height)
  1828. {
  1829. const int buttonSize = (height * 3) / 4;
  1830. const int buttonIndent = (height - buttonSize) / 2;
  1831. drawTreeviewPlusMinusBox (g, buttonIndent, buttonIndent, buttonSize, buttonSize, ! isOpen);
  1832. const int textX = buttonIndent * 2 + buttonSize + 2;
  1833. g.setColour (Colours::black);
  1834. g.setFont (height * 0.7f, Font::bold);
  1835. g.drawText (name, textX, 0, width - textX - 4, height, Justification::centredLeft, true);
  1836. }
  1837. void LookAndFeel::drawPropertyComponentBackground (Graphics& g, int width, int height,
  1838. PropertyComponent&)
  1839. {
  1840. g.setColour (Colour (0x66ffffff));
  1841. g.fillRect (0, 0, width, height - 1);
  1842. }
  1843. void LookAndFeel::drawPropertyComponentLabel (Graphics& g, int, int height,
  1844. PropertyComponent& component)
  1845. {
  1846. g.setColour (Colours::black);
  1847. if (! component.isEnabled())
  1848. g.setOpacity (g.getCurrentColour().getAlpha() * 0.6f);
  1849. g.setFont (jmin (height, 24) * 0.65f);
  1850. const Rectangle r (getPropertyComponentContentPosition (component));
  1851. g.drawFittedText (component.getName(),
  1852. 3, r.getY(), r.getX() - 5, r.getHeight(),
  1853. Justification::centredLeft, 2);
  1854. }
  1855. const Rectangle LookAndFeel::getPropertyComponentContentPosition (PropertyComponent& component)
  1856. {
  1857. return Rectangle (component.getWidth() / 3, 1,
  1858. component.getWidth() - component.getWidth() / 3 - 1, component.getHeight() - 3);
  1859. }
  1860. //==============================================================================
  1861. void LookAndFeel::createFileChooserHeaderText (const String& title,
  1862. const String& instructions,
  1863. GlyphArrangement& text,
  1864. int width)
  1865. {
  1866. text.clear();
  1867. text.addJustifiedText (Font (17.0f, Font::bold), title,
  1868. 8.0f, 22.0f, width - 16.0f,
  1869. Justification::centred);
  1870. text.addJustifiedText (Font (14.0f), instructions,
  1871. 8.0f, 24.0f + 16.0f, width - 16.0f,
  1872. Justification::centred);
  1873. }
  1874. void LookAndFeel::drawFileBrowserRow (Graphics& g, int width, int height,
  1875. const String& filename, Image* icon,
  1876. const String& fileSizeDescription,
  1877. const String& fileTimeDescription,
  1878. const bool isDirectory,
  1879. const bool isItemSelected)
  1880. {
  1881. if (isItemSelected)
  1882. g.fillAll (findColour (DirectoryContentsDisplayComponent::highlightColourId));
  1883. g.setColour (findColour (DirectoryContentsDisplayComponent::textColourId));
  1884. g.setFont (height * 0.7f);
  1885. Image* im = icon;
  1886. Image* toRelease = 0;
  1887. if (im == 0)
  1888. {
  1889. toRelease = im = (isDirectory ? getDefaultFolderImage()
  1890. : getDefaultDocumentFileImage());
  1891. }
  1892. const int x = 32;
  1893. if (im != 0)
  1894. {
  1895. g.drawImageWithin (im, 2, 2, x - 4, height - 4,
  1896. RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize,
  1897. false);
  1898. ImageCache::release (toRelease);
  1899. }
  1900. if (width > 450 && ! isDirectory)
  1901. {
  1902. const int sizeX = roundFloatToInt (width * 0.7f);
  1903. const int dateX = roundFloatToInt (width * 0.8f);
  1904. g.drawFittedText (filename,
  1905. x, 0, sizeX - x, height,
  1906. Justification::centredLeft, 1);
  1907. g.setFont (height * 0.5f);
  1908. g.setColour (Colours::darkgrey);
  1909. if (! isDirectory)
  1910. {
  1911. g.drawFittedText (fileSizeDescription,
  1912. sizeX, 0, dateX - sizeX - 8, height,
  1913. Justification::centredRight, 1);
  1914. g.drawFittedText (fileTimeDescription,
  1915. dateX, 0, width - 8 - dateX, height,
  1916. Justification::centredRight, 1);
  1917. }
  1918. }
  1919. else
  1920. {
  1921. g.drawFittedText (filename,
  1922. x, 0, width - x, height,
  1923. Justification::centredLeft, 1);
  1924. }
  1925. }
  1926. Button* LookAndFeel::createFileBrowserGoUpButton()
  1927. {
  1928. DrawableButton* goUpButton = new DrawableButton ("up", DrawableButton::ImageOnButtonBackground);
  1929. Path arrowPath;
  1930. arrowPath.addArrow (50.0f, 100.0f, 50.0f, 0.0, 40.0f, 100.0f, 50.0f);
  1931. DrawablePath arrowImage;
  1932. arrowImage.setSolidFill (Colours::black.withAlpha (0.4f));
  1933. arrowImage.setPath (arrowPath);
  1934. goUpButton->setImages (&arrowImage);
  1935. return goUpButton;
  1936. }
  1937. void LookAndFeel::layoutFileBrowserComponent (FileBrowserComponent& browserComp,
  1938. DirectoryContentsDisplayComponent* fileListComponent,
  1939. FilePreviewComponent* previewComp,
  1940. ComboBox* currentPathBox,
  1941. TextEditor* filenameBox,
  1942. Button* goUpButton)
  1943. {
  1944. const int x = 8;
  1945. int w = browserComp.getWidth() - x - x;
  1946. if (previewComp != 0)
  1947. {
  1948. const int previewWidth = w / 3;
  1949. previewComp->setBounds (x + w - previewWidth, 0, previewWidth, browserComp.getHeight());
  1950. w -= previewWidth + 4;
  1951. }
  1952. int y = 4;
  1953. const int controlsHeight = 22;
  1954. const int bottomSectionHeight = controlsHeight + 8;
  1955. const int upButtonWidth = 50;
  1956. currentPathBox->setBounds (x, y, w - upButtonWidth - 6, controlsHeight);
  1957. goUpButton->setBounds (x + w - upButtonWidth, y, upButtonWidth, controlsHeight);
  1958. y += controlsHeight + 4;
  1959. Component* const listAsComp = dynamic_cast <Component*> (fileListComponent);
  1960. listAsComp->setBounds (x, y, w, browserComp.getHeight() - y - bottomSectionHeight);
  1961. y = listAsComp->getBottom() + 4;
  1962. filenameBox->setBounds (x + 50, y, w - 50, controlsHeight);
  1963. }
  1964. Image* LookAndFeel::getDefaultFolderImage()
  1965. {
  1966. static const unsigned char foldericon_png[] = { 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,28,8,6,0,0,0,0,194,189,34,0,0,0,4,103,65,77,65,0,0,175,200,55,5,
  1967. 138,233,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60,0,0,9,46,73,68,65,84,120,218,98,252,255,255,63,3,50,240,41,95,192,
  1968. 197,205,198,32,202,204,202,33,241,254,235,47,133,47,191,24,180,213,164,133,152,69,24,222,44,234,42,77,188,245,31,170,129,145,145,145,1,29,128,164,226,91,86,113,252,248,207,200,171,37,39,204,239,170,43,
  1969. 254,206,218,88,231,61,62,61,0,1,196,2,149,96,116,200,158,102,194,202,201,227,197,193,206,166,194,204,193,33,195,202,204,38,42,197,197,42,196,193,202,33,240,241,231,15,134,151,95,127,9,2,149,22,0,241,47,
  1970. 152,230,128,134,245,204,63,191,188,103,83,144,16,16,228,229,102,151,76,239,217,32,199,204,198,169,205,254,159,65,245,203,79,6,169,131,151,30,47,1,42,91,10,196,127,208,236,101,76,235,90,43,101,160,40,242,
  1971. 19,32,128,64,78,98,52,12,41,149,145,215,52,89,162,38,35,107,39,196,203,203,192,206,194,206,192,197,198,202,192,203,197,198,192,205,193,206,240,252,227,103,134,139,55,175,191,127,243,242,78,219,187,207,
  1972. 63,215,255,98,23,48,228,227,96,83,98,102,102,85,225,224,228,80,20,224,230,86,226,225,228,150,103,101,97,101,230,227,228,96,224,0,234,191,243,252,5,195,222,19,199,38,191,127,112,161,83,66,199,86,141,131,
  1973. 149,69,146,133,153,69,137,149,133,89,157,141,131,77,83,140,143,243,219,255,31,159,123,0,2,136,69,90,207,129,157,71,68,42,66,71,73,209,210,81,91,27,24,142,140,12,127,255,253,103,0,185,236,31,3,144,6,50,
  1974. 148,68,216,25,216,24,117,4,239,11,243,214,49,50,51,84,178,48,114,240,112,177,114,177,240,115,113,49,241,112,112,48,176,179,178,51,176,48,49,3,85,255,99,248,253,247,15,195,247,159,191,25,30,191,126,253,
  1975. 71,74,76,200,66,75,197,119,138,168,144,160,150,168,0,183,160,152,32,15,175,188,184,32,199,175,191,127,25,214,31,184,120,247,236,209,253,159,0,2,136,133,95,70,93,74,88,80,196,83,69,66,130,149,9,104,219,
  1976. 151,31,191,193,150,194,146,6,136,102,102,98,100,16,227,231,103,16,23,210,230,101,101,102,100,248,255,143,137,225,223,63,6,6,22,102,38,134,239,191,126,49,220,123,241,134,225,227,247,175,64,7,252,101,96,
  1977. 97,249,207,192,193,198,200,160,171,34,192,108,165,235,104,42,204,207,101,42,194,199,197,192,199,201,198,192,197,193,202,192,198,202,194,176,247,194,3,134,155,183,110,61,188,127,124,221,19,128,0,92,146,
  1978. 49,14,64,64,16,69,63,153,85,16,52,18,74,71,112,6,87,119,0,165,160,86,138,32,172,216,29,49,182,84,253,169,94,94,230,127,17,87,133,34,146,174,3,88,126,240,219,164,147,113,31,145,244,152,112,179,211,130,
  1979. 34,31,203,113,162,233,6,36,49,163,174,74,124,140,60,141,144,165,161,220,228,25,3,24,105,255,17,168,101,1,139,245,188,93,104,251,73,239,235,50,90,189,111,175,0,98,249,254,254,249,175,239,223,190,126,6,
  1980. 5,27,19,47,90,170,102,0,249,158,129,129,141,133,25,228,20,6,38,38,72,74,7,185,243,243,247,239,12,23,31,60,98,228,231,253,207,144,227,107,206,32,202,199,193,240,249,251,127,134,95,191,255,49,124,249,250,
  1981. 159,225,237,239,95,12,63,127,1,35,229,31,194,71,32,71,63,123,251,245,223,197,27,183,159,189,187,178,103,61,80,232,59,64,0,177,48,252,5,134,225,255,191,223,126,254,250,13,182,132,1,41,167,176,3,53,128,
  1982. 188,254,226,253,103,96,212,252,96,120,247,249,203,255,79,223,191,254,255,250,235,199,191,239,63,191,255,87,145,17,100,73,116,181,100,252,249,243,63,195,149,123,223,193,14,132,101,55,96,52,3,125,255,15,
  1983. 204,254,15,132,160,232,253,13,20,124,248,226,227,223,23,207,30,221,120,119,255,226,109,160,210,31,0,1,196,242,231,219,135,175,140,255,126,190,7,197,37,35,19,34,216,65,248,211,143,111,255,79,223,121,240,
  1984. 255,211,183,79,76,220,156,172,12,236,204,140,140,252,124,28,140,250,226,82,140,106,82,34,140,124,156,156,12,175,222,253,1,90,4,137,162,63,127,33,161,6,178,242,215,239,255,224,160,255,15,198,12,64,7,48,
  1985. 128,211,200,253,151,111,254,254,248,240,236,44,80,217,71,80,246,4,8,32,160,31,255,255,100,102,248,243,238,199,159,63,16,221,16,19,128,248,31,195,181,199,207,254,255,253,247,133,49,212,78,27,104,8,11,40,
  1986. 94,25,184,216,89,129,108,38,70,144,242,183,31,17,105,230,63,148,248,15,97,49,252,248,249,15,20,85,72,105,9,148,187,254,49,220,127,254,242,207,243,75,135,14,128,130,31,84,64,1,4,16,203,247,143,175,127,
  1987. 48,253,254,246,234,7,48,206,96,137,13,4,64,65,248,234,195,7,6,7,3,57,70,33,46,97,134,111,63,254,50,252,5,250,244,51,216,103,255,192,185,0,150,91,80,44,135,242,127,253,129,164,23,24,96,102,250,207,112,
  1988. 255,213,219,255,247,31,63,188,251,246,201,173,199,176,2,13,32,128,88,62,188,121,241,243,211,231,207,31,126,2,147,236,63,168,6,144,193,223,190,255,254,207,198,198,192,40,35,44,206,240,252,205,79,6,132,
  1989. 223,24,224,150,32,251,28,25,128,211,29,19,170,24,51,48,88,111,61,127,206,248,254,245,179,139,192,18,247,219,239,239,95,192,249,9,32,128,88,126,124,249,248,231,203,183,111,159,128,33,240,15,24,68,160,180,
  1990. 2,204,223,140,12,111,63,127,102,16,228,229,4,6,53,35,195,31,176,119,25,112,3,70,84,55,0,203,50,112,33,134,108,249,103,160,7,159,189,126,253,235,235,227,203,7,255,255,251,247,13,86,63,0,4,16,168,46,248,
  1991. 199,250,231,243,235,159,191,126,254,248,245,251,47,23,11,51,51,48,184,152,24,94,127,250,248,95,68,136,151,241,243,55,96,208,51,160,218,255,31,139,27,144,197,254,98,201,202,79,223,124,96,120,245,232,250,
  1992. 185,119,143,174,95,250,243,243,219,119,152,60,64,0,129,2,234,223,183,215,15,95,48,254,255,253,3,146,109,192,229,5,195,135,47,159,25,248,184,121,24,126,0,227,29,88,240,49,252,101,36,14,255,1,90,249,7,156,
  1993. 222,17,24,24,164,12,207,223,189,99,248,250,252,230,97,96,229,245,2,104,231,111,152,3,0,2,8,228,128,191,15,239,220,120,255,255,223,159,47,160,116,0,42,44,222,124,250,244,239,207,255,63,12,236,108,236,64,
  1994. 67,65,81,0,52,244,63,113,248,47,52,10,96,14,98,2,230,191,119,223,127,48,60,121,254,248,235,151,55,207,46,1,163,252,35,114,128,1,4,16,40,10,254,191,121,249,252,199,175,159,63,191,254,2,230,45,118,22,22,
  1995. 134,219,207,94,252,231,224,100,103,250,247,15,148,32,64,85,12,34,14,254,227,72,6,255,225,9,240,63,138,26,46,96,214,189,249,244,37,195,139,167,143,30,124,253,246,253,9,40,245,255,71,202,30,0,1,196,2,226,
  1996. 0,243,232,159,239,63,127,124,253,11,202,94,64,169,23,31,62,50,138,137,242,49,50,0,211,195,223,255,80,7,252,199,159,6,224,137,145,9,146,231,153,160,165,218,23,96,29,240,244,237,59,134,111,175,31,95,250,
  1997. 252,230,241,83,244,182,1,64,0,177,192,28,14,76,132,31,128,169,19,88,220,126,253,207,206,198,196,32,38,36,0,244,61,11,176,148,251,139,145,3,208,29,0,178,16,82,228,66,42,174,223,192,26,8,152,162,25,222,
  1998. 125,248,200,240,242,253,39,134,151,79,238,126,254,242,242,238,177,15,47,30,190,5,215,242,72,0,32,128,224,14,96,254,255,231,61,168,92,123,241,254,253,127,1,62,78,6,78,110,78,134,223,64,195,254,50,98,183,
  1999. 24,36,12,202,179,224,202,9,88,228,253,132,90,250,246,211,71,134,55,175,94,254,122,255,250,249,247,15,175,159,126,249,251,237,195,135,95,175,110,31,122,117,251,244,49,160,150,111,255,209,218,128,0,1,152,
  2000. 44,183,21,0,65,32,136,110,247,254,255,243,122,9,187,64,105,174,74,22,138,25,173,80,208,194,188,238,156,151,217,217,15,32,182,197,37,83,201,4,31,243,178,169,232,242,214,224,223,252,103,175,35,85,1,41,129,
  2001. 228,148,142,8,214,30,32,149,6,161,204,109,182,53,236,184,156,78,142,147,195,153,89,35,198,3,87,166,249,220,227,198,59,218,48,252,223,185,111,30,1,132,228,128,127,31,222,124,248,248,27,24,152,28,60,220,
  2002. 220,12,44,172,172,224,224,103,5,102,98,144,133,160,236,244,229,231,47,134,239,223,127,49,188,121,251,158,225,241,179,103,12,31,223,189,254,251,227,221,139,55,191,62,188,120,246,235,205,189,59,207,238,
  2003. 94,58,241,228,254,109,144,101,159,128,248,51,40,9,32,97,80,217,255,15,221,1,0,1,4,143,130,207,159,191,126,252,246,234,213,111,94,126,94,118,73,94,9,198,127,64,223,126,252,246,147,225,243,215,239,12,223,
  2004. 128,229,198,251,15,239,24,62,189,126,249,227,203,171,135,47,63,189,122,252,228,235,155,199,247,95,63,188,118,227,197,227,123,247,127,255,250,249,30,104,198,7,32,126,11,181,252,7,212,183,160,4,247,7,155,
  2005. 197,48,0,16,64,112,7,60,121,241,238,189,16,207,15,134,63,63,216,25,95,125,248,198,112,227,241,27,134,15,239,223,50,124,126,245,228,253,143,55,143,158,191,123,116,237,226,171,135,55,175,126,253,252,225,
  2006. 229,183,47,159,95,254,253,245,227,253,175,159,223,223,193,124,7,181,20,84,105,252,70,143,103,124,0,32,128,224,14,224,102,253,251,81,144,253,223,235,167,207,30,254,124,127,231,252,155,143,175,159,188,250,
  2007. 246,254,249,125,96,60,62,248,250,233,253,147,119,207,238,221,6,150,214,175,129,106,191,130,18,19,146,133,120,125,72,8,0,4,16,34,27,190,121,112,251,3,211,159,69,143,110,223,229,120,255,232,230,221,215,
  2008. 79,239,62,4,102,203,207,72,241,9,11,218,63,72,89,137,20,207,98,100,93,16,0,8,32,70,144,1,64,14,168,209,199,7,196,194,160,166,27,212,135,95,96,65,10,173,95,254,34,219,6,51,128,88,7,96,235,21,129,0,64,0,
  2009. 193,28,192,8,174,53,33,152,1,155,133,184,12,196,165,4,151,133,232,0,32,192,0,151,97,210,163,246,134,208,52,0,0,0,0,73,69,78,68,174,66,96,130,0,0};
  2010. return ImageCache::getFromMemory (foldericon_png, sizeof (foldericon_png));
  2011. }
  2012. Image* LookAndFeel::getDefaultDocumentFileImage()
  2013. {
  2014. static const unsigned char fileicon_png[] = { 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,244,0,0,0,4,103,65,77,65,0,0,175,200,55,5,
  2015. 138,233,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60,0,0,4,99,73,68,65,84,120,218,98,252,255,255,63,3,12,48,50,50,50,1,
  2016. 169,127,200,98,148,2,160,153,204,64,243,254,226,146,7,8,32,22,52,203,255,107,233,233,91,76,93,176,184,232,239,239,95,127,24,40,112,8,19,51,203,255,179,23,175,108,1,90,190,28,104,54,43,80,232,207,127,44,
  2017. 62,3,8,32,6,144,24,84,156,25,132,189,252,3,146,255,83,9,220,127,254,242,134,162,138,170,10,208,92,144,3,152,97,118,33,99,128,0,98,66,114,11,200,1,92,255,254,252,225,32,215,215,32,127,64,240,127,80,60,
  2018. 50,40,72,136,169,47,95,179,118,130,136,148,140,0,40,80,128,33,193,136,174,7,32,128,144,29,192,8,117,41,59,209,22,66,241,191,255,16,12,244,19,195,63,48,134,240,255,0,9,115,125,93,239,252,130,130,108,168,
  2019. 249,44,232,102,0,4,16,19,22,62,51,33,11,255,195,44,4,211,255,25,96,16,33,6,117,24,56,226,25,24,202,139,10,75,226,51,115,66,160,105,13,197,17,0,1,196,68,172,79,255,33,91,206,192,192,128,176,22,17,10,200,
  2020. 234,32,161,240,31,24,10,255,24,152,153,153,184,39,244,247,117,107,234,234,105,131,66,1,154,224,193,0,32,128,240,58,0,22,180,255,144,18,13,40,136,33,113,140,36,255,15,17,26,48,12,81,15,145,255,254,251,
  2021. 31,131,0,59,171,84,81,73,105,33,208,216,191,200,161,12,16,64,44,248,131,251,63,10,31,198,253,143,38,6,83,7,11,33,228,232,2,123,4,202,226,228,96,151,132,166,49,144,35,126,131,196,0,2,136,5,103,60,51,252,
  2022. 71,49,12,213,130,255,168,226,232,150,254,255,15,143,6,80,202,3,133,16,200,198,63,127,193,229,17,39,16,127,135,217,7,16,64,88,67,0,28,143,255,25,225,46,135,249,18,155,133,240,178,4,205,145,8,62,52,186,
  2023. 32,234,152,160,118,194,179,35,64,0,177,96,11,123,144,236,95,104,92,162,228,113,36,11,81,125,140,112,56,186,131,96,226,176,172,137,148,229,193,0,32,128,88,112,167,248,255,112,223,48,34,165,110,6,124,190,
  2024. 253,143,61,106,192,9,19,73,28,25,0,4,16,206,40,248,251,15,45,104,209,130,21,51,222,145,18,238,127,180,68,8,244,250,95,164,16,66,6,0,1,196,130,45,253,195,12,250,135,53,206,255,195,131,18,213,98,236,81,
  2025. 243,31,154,11,144,115,8,50,0,8,32,156,81,0,203,227,12,80,223,98,230,4,68,72,96,38,78,84,11,65,9,250,47,146,3,145,1,64,0,97,117,192,95,112,34,68,138,130,255,176,224,251,143,226,51,6,6,68,29,192,136,20,
  2026. 77,200,69,54,35,3,36,49,255,69,77,132,112,0,16,64,44,56,139,94,36,7,96,102,59,164,108,249,31,181,82,98,64,203,174,255,144,234,142,127,88,146,33,64,0,97,205,134,240,120,67,75,76,136,224,198,140,22,6,44,
  2027. 142,66,201,41,255,177,231,2,128,0,194,25,5,255,254,161,134,192,127,6,28,229,0,129,242,1,150,56,33,81,138,209,28,96,0,8,32,172,81,0,78,3,104,190,68,182,224,31,146,197,224,56,6,146,140,176,202,135,17,169,
  2028. 96,130,40,64,56,0,139,93,0,1,132,61,10,64,248,31,106,156,162,199,55,204,65,255,144,178,38,74,84,252,71,51,239,63,246,68,8,16,64,44,216,74,1,88,217,13,203,191,32,1,80,58,7,133,224,127,6,68,114,6,241,65,
  2029. 81,197,8,101,255,71,114,33,92,237,127,228,52,128,233,2,128,0,98,193,149,3,64,117,193,255,127,255,81,75,191,127,168,5,18,136,255,31,45,161,49,32,151,134,72,252,127,12,216,203,98,128,0,98,193,210,144,135,
  2030. 248,30,201,242,127,208,252,140,145,27,160,113,206,136,148,197,192,121,159,17,53,184,225,149,17,22,23,0,4,16,11,182,150,237,63,168,207,96,142,248,143,163,72,6,203,253,67,13,61,6,104,14,66,46,17,254,65,
  2031. 19,40,182,16,0,8,32,22,108,109,235,255,176,234,24,35,79,255,199,222,30,64,81,135,90,35,194,211,4,142,92,0,16,64,88,29,0,107,7,254,251,247,31,53,78,241,54,207,80,29,135,209,96,249,143,189,46,0,8,32,116,
  2032. 7,252,101,102,103,103,228,103,99,96,248,193,198,137,53,248,49,125,204,128,225,227,255,88,18,54,47,176,25,202,205,195,205,6,109,11,194,149,0,4,16,35,204,85,208,254,27,159,128,176,176,142,166,182,142,21,
  2033. 48,4,248,129,41,143,13,217,16,70,52,95,147,0,254,0,187,69,95,223,188,122,125,235,206,141,107,7,129,252,247,64,123,193,237,66,128,0,66,118,0,168,189,198,3,196,252,32,135,64,105,54,228,230,19,185,29,100,
  2034. 168,175,191,0,241,7,32,254,4,196,159,129,246,254,2,73,2,4,16,11,90,72,125,135,210,63,161,138,153,169,212,75,255,15,117,196,15,40,134,119,215,1,2,12,0,187,0,132,247,216,161,197,124,0,0,0,0,73,69,78,68,
  2035. 174,66,96,130,0,0};
  2036. return ImageCache::getFromMemory (fileicon_png, sizeof (fileicon_png));
  2037. }
  2038. //==============================================================================
  2039. void LookAndFeel::playAlertSound()
  2040. {
  2041. PlatformUtilities::beep();
  2042. }
  2043. //==============================================================================
  2044. static void createRoundedPath (Path& p,
  2045. const float x, const float y,
  2046. const float w, const float h,
  2047. const float cs,
  2048. const bool curveTopLeft, const bool curveTopRight,
  2049. const bool curveBottomLeft, const bool curveBottomRight) throw()
  2050. {
  2051. const float cs2 = 2.0f * cs;
  2052. if (curveTopLeft)
  2053. {
  2054. p.startNewSubPath (x, y + cs);
  2055. p.addArc (x, y, cs2, cs2, float_Pi * 1.5f, float_Pi * 2.0f);
  2056. }
  2057. else
  2058. {
  2059. p.startNewSubPath (x, y);
  2060. }
  2061. if (curveTopRight)
  2062. {
  2063. p.lineTo (x + w - cs, y);
  2064. p.addArc (x + w - cs2, y, cs2, cs2, 0.0f, float_Pi * 0.5f);
  2065. }
  2066. else
  2067. {
  2068. p.lineTo (x + w, y);
  2069. }
  2070. if (curveBottomRight)
  2071. {
  2072. p.lineTo (x + w, y + h - cs);
  2073. p.addArc (x + w - cs2, y + h - cs2, cs2, cs2, float_Pi * 0.5f, float_Pi);
  2074. }
  2075. else
  2076. {
  2077. p.lineTo (x + w, y + h);
  2078. }
  2079. if (curveBottomLeft)
  2080. {
  2081. p.lineTo (x + cs, y + h);
  2082. p.addArc (x, y + h - cs2, cs2, cs2, float_Pi, float_Pi * 1.5f);
  2083. }
  2084. else
  2085. {
  2086. p.lineTo (x, y + h);
  2087. }
  2088. p.closeSubPath();
  2089. }
  2090. //==============================================================================
  2091. void LookAndFeel::drawShinyButtonShape (Graphics& g,
  2092. float x, float y, float w, float h,
  2093. float maxCornerSize,
  2094. const Colour& baseColour,
  2095. const float strokeWidth,
  2096. const bool flatOnLeft,
  2097. const bool flatOnRight,
  2098. const bool flatOnTop,
  2099. const bool flatOnBottom) throw()
  2100. {
  2101. if (w <= strokeWidth * 1.1f || h <= strokeWidth * 1.1f)
  2102. return;
  2103. const float cs = jmin (maxCornerSize, w * 0.5f, h * 0.5f);
  2104. Path outline;
  2105. createRoundedPath (outline, x, y, w, h, cs,
  2106. ! (flatOnLeft || flatOnTop),
  2107. ! (flatOnRight || flatOnTop),
  2108. ! (flatOnLeft || flatOnBottom),
  2109. ! (flatOnRight || flatOnBottom));
  2110. ColourGradient cg (baseColour, 0.0f, y,
  2111. baseColour.overlaidWith (Colour (0x070000ff)), 0.0f, y + h,
  2112. false);
  2113. cg.addColour (0.5, baseColour.overlaidWith (Colour (0x33ffffff)));
  2114. cg.addColour (0.51, baseColour.overlaidWith (Colour (0x110000ff)));
  2115. GradientBrush gb (cg);
  2116. g.setBrush (&gb);
  2117. g.fillPath (outline);
  2118. g.setColour (Colour (0x80000000));
  2119. g.strokePath (outline, PathStrokeType (strokeWidth));
  2120. }
  2121. //==============================================================================
  2122. void LookAndFeel::drawGlassSphere (Graphics& g,
  2123. const float x, const float y,
  2124. const float diameter,
  2125. const Colour& colour,
  2126. const float outlineThickness) throw()
  2127. {
  2128. if (diameter <= outlineThickness)
  2129. return;
  2130. Path p;
  2131. p.addEllipse (x, y, diameter, diameter);
  2132. {
  2133. ColourGradient cg (Colours::white.overlaidWith (colour.withMultipliedAlpha (0.3f)), 0, y,
  2134. Colours::white.overlaidWith (colour.withMultipliedAlpha (0.3f)), 0, y + diameter, false);
  2135. cg.addColour (0.4, Colours::white.overlaidWith (colour));
  2136. GradientBrush gb (cg);
  2137. g.setBrush (&gb);
  2138. g.fillPath (p);
  2139. }
  2140. {
  2141. GradientBrush gb (Colours::white, 0, y + diameter * 0.06f,
  2142. Colours::transparentWhite, 0, y + diameter * 0.3f, false);
  2143. g.setBrush (&gb);
  2144. g.fillEllipse (x + diameter * 0.2f, y + diameter * 0.05f, diameter * 0.6f, diameter * 0.4f);
  2145. }
  2146. {
  2147. ColourGradient cg (Colours::transparentBlack,
  2148. x + diameter * 0.5f, y + diameter * 0.5f,
  2149. Colours::black.withAlpha (0.5f * outlineThickness * colour.getFloatAlpha()),
  2150. x, y + diameter * 0.5f, true);
  2151. cg.addColour (0.7, Colours::transparentBlack);
  2152. cg.addColour (0.8, Colours::black.withAlpha (0.1f * outlineThickness));
  2153. GradientBrush gb (cg);
  2154. g.setBrush (&gb);
  2155. g.fillPath (p);
  2156. }
  2157. g.setColour (Colours::black.withAlpha (0.5f * colour.getFloatAlpha()));
  2158. g.drawEllipse (x, y, diameter, diameter, outlineThickness);
  2159. }
  2160. //==============================================================================
  2161. void LookAndFeel::drawGlassPointer (Graphics& g,
  2162. const float x, const float y,
  2163. const float diameter,
  2164. const Colour& colour, const float outlineThickness,
  2165. const int direction) throw()
  2166. {
  2167. if (diameter <= outlineThickness)
  2168. return;
  2169. Path p;
  2170. p.startNewSubPath (x + diameter * 0.5f, y);
  2171. p.lineTo (x + diameter, y + diameter * 0.6f);
  2172. p.lineTo (x + diameter, y + diameter);
  2173. p.lineTo (x, y + diameter);
  2174. p.lineTo (x, y + diameter * 0.6f);
  2175. p.closeSubPath();
  2176. p.applyTransform (AffineTransform::rotation (direction * (float_Pi * 0.5f), x + diameter * 0.5f, y + diameter * 0.5f));
  2177. {
  2178. ColourGradient cg (Colours::white.overlaidWith (colour.withMultipliedAlpha (0.3f)), 0, y,
  2179. Colours::white.overlaidWith (colour.withMultipliedAlpha (0.3f)), 0, y + diameter, false);
  2180. cg.addColour (0.4, Colours::white.overlaidWith (colour));
  2181. GradientBrush gb (cg);
  2182. g.setBrush (&gb);
  2183. g.fillPath (p);
  2184. }
  2185. {
  2186. ColourGradient cg (Colours::transparentBlack,
  2187. x + diameter * 0.5f, y + diameter * 0.5f,
  2188. Colours::black.withAlpha (0.5f * outlineThickness * colour.getFloatAlpha()),
  2189. x - diameter * 0.2f, y + diameter * 0.5f, true);
  2190. cg.addColour (0.5, Colours::transparentBlack);
  2191. cg.addColour (0.7, Colours::black.withAlpha (0.07f * outlineThickness));
  2192. GradientBrush gb (cg);
  2193. g.setBrush (&gb);
  2194. g.fillPath (p);
  2195. }
  2196. g.setColour (Colours::black.withAlpha (0.5f * colour.getFloatAlpha()));
  2197. g.strokePath (p, PathStrokeType (outlineThickness));
  2198. }
  2199. //==============================================================================
  2200. void LookAndFeel::drawGlassLozenge (Graphics& g,
  2201. const float x, const float y,
  2202. const float width, const float height,
  2203. const Colour& colour,
  2204. const float outlineThickness,
  2205. const float cornerSize,
  2206. const bool flatOnLeft,
  2207. const bool flatOnRight,
  2208. const bool flatOnTop,
  2209. const bool flatOnBottom) throw()
  2210. {
  2211. if (width <= outlineThickness || height <= outlineThickness)
  2212. return;
  2213. const int intX = (int) x;
  2214. const int intY = (int) y;
  2215. const int intW = (int) width;
  2216. const int intH = (int) height;
  2217. const float cs = cornerSize < 0 ? jmin (width * 0.5f, height * 0.5f) : cornerSize;
  2218. const float edgeBlurRadius = height * 0.75f + (height - cs * 2.0f);
  2219. const int intEdge = (int) edgeBlurRadius;
  2220. Path outline;
  2221. createRoundedPath (outline, x, y, width, height, cs,
  2222. ! (flatOnLeft || flatOnTop),
  2223. ! (flatOnRight || flatOnTop),
  2224. ! (flatOnLeft || flatOnBottom),
  2225. ! (flatOnRight || flatOnBottom));
  2226. {
  2227. ColourGradient cg (colour.darker (0.2f), 0, y,
  2228. colour.darker (0.2f), 0, y + height, false);
  2229. cg.addColour (0.03, colour.withMultipliedAlpha (0.3f));
  2230. cg.addColour (0.4, colour);
  2231. cg.addColour (0.97, colour.withMultipliedAlpha (0.3f));
  2232. GradientBrush gb (cg);
  2233. g.setBrush (&gb);
  2234. g.fillPath (outline);
  2235. }
  2236. ColourGradient cg (Colours::transparentBlack, x + edgeBlurRadius, y + height * 0.5f,
  2237. colour.darker (0.2f), x, y + height * 0.5f, true);
  2238. cg.addColour (jlimit (0.0, 1.0, 1.0 - (cs * 0.5f) / edgeBlurRadius), Colours::transparentBlack);
  2239. cg.addColour (jlimit (0.0, 1.0, 1.0 - (cs * 0.25f) / edgeBlurRadius), colour.darker (0.2f).withMultipliedAlpha (0.3f));
  2240. if (! (flatOnLeft || flatOnTop || flatOnBottom))
  2241. {
  2242. GradientBrush gb (cg);
  2243. g.saveState();
  2244. g.setBrush (&gb);
  2245. g.reduceClipRegion (intX, intY, intEdge, intH);
  2246. g.fillPath (outline);
  2247. g.restoreState();
  2248. }
  2249. if (! (flatOnRight || flatOnTop || flatOnBottom))
  2250. {
  2251. cg.x1 = x + width - edgeBlurRadius;
  2252. cg.x2 = x + width;
  2253. GradientBrush gb (cg);
  2254. g.saveState();
  2255. g.setBrush (&gb);
  2256. g.reduceClipRegion (intX + intW - intEdge, intY, 2 + intEdge, intH);
  2257. g.fillPath (outline);
  2258. g.restoreState();
  2259. }
  2260. {
  2261. const float leftIndent = flatOnLeft ? 0.0f : cs * 0.4f;
  2262. const float rightIndent = flatOnRight ? 0.0f : cs * 0.4f;
  2263. Path highlight;
  2264. createRoundedPath (highlight,
  2265. x + leftIndent,
  2266. y + cs * 0.1f,
  2267. width - (leftIndent + rightIndent),
  2268. height * 0.4f, cs * 0.4f,
  2269. ! (flatOnLeft || flatOnTop),
  2270. ! (flatOnRight || flatOnTop),
  2271. ! (flatOnLeft || flatOnBottom),
  2272. ! (flatOnRight || flatOnBottom));
  2273. GradientBrush gb (colour.brighter (10.0f), 0, y + height * 0.06f,
  2274. Colours::transparentWhite, 0, y + height * 0.4f, false);
  2275. g.setBrush (&gb);
  2276. g.fillPath (highlight);
  2277. }
  2278. g.setColour (colour.darker().withMultipliedAlpha (1.5f));
  2279. g.strokePath (outline, PathStrokeType (outlineThickness));
  2280. }
  2281. END_JUCE_NAMESPACE