Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_LookAndFeel_V2.cpp 121KB

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