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.

2974 lines
120KB

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