The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

701 lines
27KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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. static const Slider::SliderStyle sliderStyleTypes[] =
  18. {
  19. Slider::LinearHorizontal,
  20. Slider::LinearVertical,
  21. Slider::LinearBar,
  22. Slider::LinearBarVertical,
  23. Slider::Rotary,
  24. Slider::RotaryHorizontalDrag,
  25. Slider::RotaryVerticalDrag,
  26. Slider::RotaryHorizontalVerticalDrag,
  27. Slider::IncDecButtons,
  28. Slider::TwoValueHorizontal,
  29. Slider::TwoValueVertical,
  30. Slider::ThreeValueHorizontal,
  31. Slider::ThreeValueVertical
  32. };
  33. static const Slider::TextEntryBoxPosition sliderTextBoxPositions[] =
  34. {
  35. Slider::NoTextBox,
  36. Slider::TextBoxLeft,
  37. Slider::TextBoxRight,
  38. Slider::TextBoxAbove,
  39. Slider::TextBoxBelow
  40. };
  41. struct SliderHandler : public ComponentTypeHandler
  42. {
  43. SliderHandler()
  44. : ComponentTypeHandler ("Slider", "Slider", typeid (Slider), 150, 24)
  45. {
  46. registerColour (Slider::backgroundColourId, "background", "bkgcol");
  47. registerColour (Slider::thumbColourId, "thumb", "thumbcol");
  48. registerColour (Slider::trackColourId, "track", "trackcol");
  49. registerColour (Slider::rotarySliderFillColourId, "rotary fill", "rotarysliderfill");
  50. registerColour (Slider::rotarySliderOutlineColourId, "rotary outln", "rotaryslideroutline");
  51. registerColour (Slider::textBoxTextColourId, "textbox text", "textboxtext");
  52. registerColour (Slider::textBoxBackgroundColourId, "textbox bkgd", "textboxbkgd");
  53. registerColour (Slider::textBoxHighlightColourId, "textbox highlt", "textboxhighlight");
  54. registerColour (Slider::textBoxOutlineColourId, "textbox outln", "textboxoutline");
  55. }
  56. Component* createNewComponent (JucerDocument*) override
  57. {
  58. return new Slider ("new slider");
  59. }
  60. XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
  61. {
  62. XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
  63. Slider* s = dynamic_cast<Slider*> (comp);
  64. e->setAttribute ("min", s->getMinimum());
  65. e->setAttribute ("max", s->getMaximum());
  66. e->setAttribute ("int", s->getInterval());
  67. e->setAttribute ("style", sliderStyleToString (s->getSliderStyle()));
  68. e->setAttribute ("textBoxPos", textBoxPosToString (s->getTextBoxPosition()));
  69. e->setAttribute ("textBoxEditable", s->isTextBoxEditable());
  70. e->setAttribute ("textBoxWidth", s->getTextBoxWidth());
  71. e->setAttribute ("textBoxHeight", s->getTextBoxHeight());
  72. e->setAttribute ("skewFactor", s->getSkewFactor());
  73. e->setAttribute ("needsCallback", needsSliderListener (s));
  74. return e;
  75. }
  76. bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
  77. {
  78. if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
  79. return false;
  80. Slider* const s = dynamic_cast<Slider*> (comp);
  81. s->setRange (xml.getDoubleAttribute ("min", 0.0),
  82. xml.getDoubleAttribute ("max", 10.0),
  83. xml.getDoubleAttribute ("int", 0.0));
  84. s->setSliderStyle (sliderStringToStyle (xml.getStringAttribute ("style", "LinearHorizontal")));
  85. s->setTextBoxStyle (stringToTextBoxPos (xml.getStringAttribute ("textBoxPos", "TextBoxLeft")),
  86. ! xml.getBoolAttribute ("textBoxEditable", true),
  87. xml.getIntAttribute ("textBoxWidth", 80),
  88. xml.getIntAttribute ("textBoxHeight", 20));
  89. s->setSkewFactor (xml.getDoubleAttribute ("skewFactor", 1.0));
  90. setNeedsSliderListener (s, xml.getBoolAttribute ("needsCallback", true));
  91. return true;
  92. }
  93. String getCreationParameters (GeneratedCode&, Component* component) override
  94. {
  95. return quotedString (component->getName(), false);
  96. }
  97. void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
  98. {
  99. ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
  100. Slider* const s = dynamic_cast<Slider*> (component);
  101. String r;
  102. r << memberVariableName << "->setRange ("
  103. << s->getMinimum() << ", " << s->getMaximum() << ", " << s->getInterval()
  104. << ");\n"
  105. << memberVariableName << "->setSliderStyle (Slider::"
  106. << sliderStyleToString (s->getSliderStyle()) << ");\n"
  107. << memberVariableName << "->setTextBoxStyle (Slider::"
  108. << textBoxPosToString (s->getTextBoxPosition())
  109. << ", " << CodeHelpers::boolLiteral (! s->isTextBoxEditable())
  110. << ", " << s->getTextBoxWidth() << ", " << s->getTextBoxHeight() << ");\n"
  111. << getColourIntialisationCode (component, memberVariableName);
  112. if (needsSliderListener (component))
  113. r << memberVariableName << "->addListener (this);\n";
  114. if (s->getSkewFactor() != 1.0)
  115. r << memberVariableName << "->setSkewFactor (" << s->getSkewFactor() << ");\n";
  116. r << '\n';
  117. code.constructorCode += r;
  118. }
  119. void fillInGeneratedCode (Component* component, GeneratedCode& code) override
  120. {
  121. ComponentTypeHandler::fillInGeneratedCode (component, code);
  122. if (needsSliderListener (component))
  123. {
  124. String& callback = code.getCallbackCode ("public SliderListener",
  125. "void",
  126. "sliderValueChanged (Slider* sliderThatWasMoved)",
  127. true);
  128. if (callback.isNotEmpty())
  129. callback << "else ";
  130. const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
  131. const String userCodeComment ("UserSliderCode_" + memberVariableName);
  132. callback
  133. << "if (sliderThatWasMoved == " << memberVariableName
  134. << ")\n{\n //[" << userCodeComment << "] -- add your slider handling code here..\n //[/" << userCodeComment << "]\n}\n";
  135. }
  136. }
  137. void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props) override
  138. {
  139. ComponentTypeHandler::getEditableProperties (component, document, props);
  140. Slider* s = dynamic_cast<Slider*> (component);
  141. jassert (s != 0);
  142. props.add (new SliderRangeProperty (s, document, "minimum", 0));
  143. props.add (new SliderRangeProperty (s, document, "maximum", 1));
  144. props.add (new SliderRangeProperty (s, document, "interval", 2));
  145. props.add (new SliderTypeProperty (s, document));
  146. props.add (new SliderTextboxProperty (s, document));
  147. props.add (new SliderTextboxEditableProperty (s, document));
  148. props.add (new SliderTextboxSizeProperty (s, document, true));
  149. props.add (new SliderTextboxSizeProperty (s, document, false));
  150. props.add (new SliderSkewProperty (s, document));
  151. props.add (new SliderCallbackProperty (s, document));
  152. addColourProperties (component, document, props);
  153. }
  154. static bool needsSliderListener (Component* slider)
  155. {
  156. return slider->getProperties().getWithDefault ("generateListenerCallback", true);
  157. }
  158. static void setNeedsSliderListener (Component* slider, bool shouldDoCallback)
  159. {
  160. slider->getProperties().set ("generateListenerCallback", shouldDoCallback);
  161. }
  162. private:
  163. //==============================================================================
  164. struct SliderTypeProperty : public ComponentChoiceProperty<Slider>
  165. {
  166. SliderTypeProperty (Slider* slider, JucerDocument& doc)
  167. : ComponentChoiceProperty<Slider> ("type", slider, doc)
  168. {
  169. choices.add ("Linear Horizontal");
  170. choices.add ("Linear Vertical");
  171. choices.add ("Linear Bar Horizontal");
  172. choices.add ("Linear Bar Vertical");
  173. choices.add ("Rotary");
  174. choices.add ("Rotary HorizontalDrag");
  175. choices.add ("Rotary VerticalDrag");
  176. choices.add ("Rotary HorizontalVerticalDrag");
  177. choices.add ("Inc/Dec Buttons");
  178. choices.add ("Two Value Horizontal");
  179. choices.add ("Two Value Vertical");
  180. choices.add ("Three Value Horizontal");
  181. choices.add ("Three Value Vertical");
  182. }
  183. void setIndex (int newIndex) override
  184. {
  185. if (newIndex >= 0 && newIndex < numElementsInArray (sliderStyleTypes))
  186. document.perform (new SliderTypeChangeAction (component, *document.getComponentLayout(),
  187. sliderStyleTypes[newIndex]),
  188. "Change Slider style");
  189. }
  190. int getIndex() const override
  191. {
  192. for (int i = 0; i < numElementsInArray (sliderStyleTypes); ++i)
  193. if (sliderStyleTypes[i] == dynamic_cast<Slider*> (component)->getSliderStyle())
  194. return i;
  195. return -1;
  196. }
  197. private:
  198. struct SliderTypeChangeAction : public ComponentUndoableAction<Slider>
  199. {
  200. SliderTypeChangeAction (Slider* comp, ComponentLayout& l, Slider::SliderStyle newState_)
  201. : ComponentUndoableAction<Slider> (comp, l),
  202. newState (newState_)
  203. {
  204. oldState = comp->getSliderStyle();
  205. }
  206. bool perform() override
  207. {
  208. showCorrectTab();
  209. getComponent()->setSliderStyle (newState);
  210. changed();
  211. return true;
  212. }
  213. bool undo() override
  214. {
  215. showCorrectTab();
  216. getComponent()->setSliderStyle (oldState);
  217. changed();
  218. return true;
  219. }
  220. Slider::SliderStyle newState, oldState;
  221. };
  222. };
  223. //==============================================================================
  224. struct SliderTextboxProperty : public ComponentChoiceProperty<Slider>
  225. {
  226. SliderTextboxProperty (Slider* slider, JucerDocument& doc)
  227. : ComponentChoiceProperty<Slider> ("text position", slider, doc)
  228. {
  229. choices.add ("No text box");
  230. choices.add ("Text box on left");
  231. choices.add ("Text box on right");
  232. choices.add ("Text box above");
  233. choices.add ("Text box below");
  234. }
  235. void setIndex (int newIndex) override
  236. {
  237. if (newIndex >= 0 && newIndex < numElementsInArray (sliderTextBoxPositions))
  238. document.perform (new SliderTextBoxChangeAction (component, *document.getComponentLayout(),
  239. sliderTextBoxPositions[newIndex]),
  240. "Change Slider textbox");
  241. }
  242. int getIndex() const override
  243. {
  244. for (int i = 0; i < numElementsInArray (sliderTextBoxPositions); ++i)
  245. if (sliderTextBoxPositions[i] == component->getTextBoxPosition())
  246. return i;
  247. return -1;
  248. }
  249. private:
  250. struct SliderTextBoxChangeAction : public ComponentUndoableAction<Slider>
  251. {
  252. SliderTextBoxChangeAction (Slider* comp, ComponentLayout& l, Slider::TextEntryBoxPosition newState_)
  253. : ComponentUndoableAction<Slider> (comp, l),
  254. newState (newState_)
  255. {
  256. oldState = comp->getTextBoxPosition();
  257. }
  258. bool perform() override
  259. {
  260. showCorrectTab();
  261. getComponent()->setTextBoxStyle (newState,
  262. ! getComponent()->isTextBoxEditable(),
  263. getComponent()->getTextBoxWidth(),
  264. getComponent()->getTextBoxHeight());
  265. changed();
  266. return true;
  267. }
  268. bool undo() override
  269. {
  270. showCorrectTab();
  271. getComponent()->setTextBoxStyle (oldState,
  272. ! getComponent()->isTextBoxEditable(),
  273. getComponent()->getTextBoxWidth(),
  274. getComponent()->getTextBoxHeight());
  275. changed();
  276. return true;
  277. }
  278. Slider::TextEntryBoxPosition newState, oldState;
  279. };
  280. };
  281. //==============================================================================
  282. struct SliderTextboxEditableProperty : public ComponentBooleanProperty<Slider>
  283. {
  284. SliderTextboxEditableProperty (Slider* slider, JucerDocument& doc)
  285. : ComponentBooleanProperty<Slider> ("text box mode", "Editable", "Editable", slider, doc)
  286. {
  287. }
  288. void setState (bool newState) override
  289. {
  290. document.perform (new SliderEditableChangeAction (component, *document.getComponentLayout(), newState),
  291. "Change Slider editability");
  292. }
  293. bool getState() const override
  294. {
  295. return component->isTextBoxEditable();
  296. }
  297. private:
  298. struct SliderEditableChangeAction : public ComponentUndoableAction<Slider>
  299. {
  300. SliderEditableChangeAction (Slider* const comp, ComponentLayout& l, bool newState_)
  301. : ComponentUndoableAction<Slider> (comp, l),
  302. newState (newState_)
  303. {
  304. oldState = comp->isTextBoxEditable();
  305. }
  306. bool perform() override
  307. {
  308. showCorrectTab();
  309. getComponent()->setTextBoxIsEditable (newState);
  310. changed();
  311. return true;
  312. }
  313. bool undo() override
  314. {
  315. showCorrectTab();
  316. getComponent()->setTextBoxIsEditable (oldState);
  317. changed();
  318. return true;
  319. }
  320. bool newState, oldState;
  321. };
  322. };
  323. //==============================================================================
  324. struct SliderCallbackProperty : public ComponentBooleanProperty<Slider>
  325. {
  326. SliderCallbackProperty (Slider* s, JucerDocument& doc)
  327. : ComponentBooleanProperty<Slider> ("callback", "Generate SliderListener",
  328. "Generate SliderListener", s, doc)
  329. {
  330. }
  331. void setState (bool newState) override
  332. {
  333. document.perform (new SliderCallbackChangeAction (component, *document.getComponentLayout(), newState),
  334. "Change button callback");
  335. }
  336. bool getState() const override { return needsSliderListener (component); }
  337. struct SliderCallbackChangeAction : public ComponentUndoableAction<Slider>
  338. {
  339. SliderCallbackChangeAction (Slider* comp, ComponentLayout& l, bool newState_)
  340. : ComponentUndoableAction<Slider> (comp, l),
  341. newState (newState_)
  342. {
  343. oldState = needsSliderListener (comp);
  344. }
  345. bool perform() override
  346. {
  347. showCorrectTab();
  348. setNeedsSliderListener (getComponent(), newState);
  349. changed();
  350. return true;
  351. }
  352. bool undo() override
  353. {
  354. showCorrectTab();
  355. setNeedsSliderListener (getComponent(), oldState);
  356. changed();
  357. return true;
  358. }
  359. bool newState, oldState;
  360. };
  361. };
  362. //==============================================================================
  363. struct SliderTextboxSizeProperty : public ComponentTextProperty<Slider>
  364. {
  365. SliderTextboxSizeProperty (Slider* slider, JucerDocument& doc, bool isWidth_)
  366. : ComponentTextProperty<Slider> (isWidth_ ? "text box width" : "text box height",
  367. 12, false, slider, doc),
  368. isWidth (isWidth_)
  369. {
  370. }
  371. void setText (const String& newText) override
  372. {
  373. document.perform (new SliderBoxSizeChangeAction (component, *document.getComponentLayout(), isWidth, newText.getIntValue()),
  374. "Change Slider textbox size");
  375. }
  376. String getText() const override
  377. {
  378. return String (isWidth ? component->getTextBoxWidth()
  379. : component->getTextBoxHeight());
  380. }
  381. private:
  382. const bool isWidth;
  383. struct SliderBoxSizeChangeAction : public ComponentUndoableAction<Slider>
  384. {
  385. SliderBoxSizeChangeAction (Slider* const comp, ComponentLayout& l, bool isWidth_, int newSize_)
  386. : ComponentUndoableAction<Slider> (comp, l),
  387. isWidth (isWidth_),
  388. newSize (newSize_)
  389. {
  390. oldSize = isWidth ? comp->getTextBoxWidth()
  391. : comp->getTextBoxHeight();
  392. }
  393. bool perform() override
  394. {
  395. showCorrectTab();
  396. Slider& c = *getComponent();
  397. if (isWidth)
  398. c.setTextBoxStyle (c.getTextBoxPosition(),
  399. ! c.isTextBoxEditable(),
  400. newSize,
  401. c.getTextBoxHeight());
  402. else
  403. c.setTextBoxStyle (c.getTextBoxPosition(),
  404. ! c.isTextBoxEditable(),
  405. c.getTextBoxWidth(),
  406. newSize);
  407. changed();
  408. return true;
  409. }
  410. bool undo() override
  411. {
  412. showCorrectTab();
  413. Slider& c = *getComponent();
  414. if (isWidth)
  415. c.setTextBoxStyle (c.getTextBoxPosition(),
  416. ! c.isTextBoxEditable(),
  417. oldSize,
  418. c.getTextBoxHeight());
  419. else
  420. c.setTextBoxStyle (c.getTextBoxPosition(),
  421. ! c.isTextBoxEditable(),
  422. c.getTextBoxWidth(),
  423. oldSize);
  424. changed();
  425. return true;
  426. }
  427. bool isWidth;
  428. int newSize, oldSize;
  429. };
  430. };
  431. //==============================================================================
  432. struct SliderRangeProperty : public ComponentTextProperty<Slider>
  433. {
  434. SliderRangeProperty (Slider* slider, JucerDocument& doc,
  435. const String& name, int rangeParam_)
  436. : ComponentTextProperty<Slider> (name, 15, false, slider, doc),
  437. rangeParam (rangeParam_)
  438. {
  439. }
  440. void setText (const String& newText) override
  441. {
  442. double state [3];
  443. state [0] = component->getMinimum();
  444. state [1] = component->getMaximum();
  445. state [2] = component->getInterval();
  446. state [rangeParam] = newText.getDoubleValue();
  447. document.perform (new SliderRangeChangeAction (component, *document.getComponentLayout(), state),
  448. "Change Slider range");
  449. }
  450. String getText() const override
  451. {
  452. Slider* s = dynamic_cast<Slider*> (component);
  453. jassert (s != nullptr);
  454. switch (rangeParam)
  455. {
  456. case 0: return String (s->getMinimum());
  457. case 1: return String (s->getMaximum());
  458. case 2: return String (s->getInterval());
  459. default: jassertfalse; break;
  460. }
  461. return {};
  462. }
  463. private:
  464. const int rangeParam;
  465. struct SliderRangeChangeAction : public ComponentUndoableAction<Slider>
  466. {
  467. SliderRangeChangeAction (Slider* comp, ComponentLayout& l, const double newState_[3])
  468. : ComponentUndoableAction<Slider> (comp, l)
  469. {
  470. newState[0] = newState_ [0];
  471. newState[1] = newState_ [1];
  472. newState[2] = newState_ [2];
  473. oldState[0] = comp->getMinimum();
  474. oldState[1] = comp->getMaximum();
  475. oldState[2] = comp->getInterval();
  476. }
  477. bool perform() override
  478. {
  479. showCorrectTab();
  480. getComponent()->setRange (newState[0], newState[1], newState[2]);
  481. changed();
  482. return true;
  483. }
  484. bool undo() override
  485. {
  486. showCorrectTab();
  487. getComponent()->setRange (oldState[0], oldState[1], oldState[2]);
  488. changed();
  489. return true;
  490. }
  491. double newState[3], oldState[3];
  492. };
  493. };
  494. //==============================================================================
  495. struct SliderSkewProperty : public ComponentTextProperty<Slider>
  496. {
  497. SliderSkewProperty (Slider* slider, JucerDocument& doc)
  498. : ComponentTextProperty<Slider> ("skew factor", 12, false, slider, doc)
  499. {
  500. }
  501. void setText (const String& newText) override
  502. {
  503. const double skew = jlimit (0.001, 1000.0, newText.getDoubleValue());
  504. document.perform (new SliderSkewChangeAction (component, *document.getComponentLayout(), skew),
  505. "Change Slider skew");
  506. }
  507. String getText() const override
  508. {
  509. Slider* s = dynamic_cast<Slider*> (component);
  510. jassert (s != 0);
  511. return String (s->getSkewFactor());
  512. }
  513. struct SliderSkewChangeAction : public ComponentUndoableAction<Slider>
  514. {
  515. SliderSkewChangeAction (Slider* comp, ComponentLayout& l, double newValue_)
  516. : ComponentUndoableAction<Slider> (comp, l)
  517. {
  518. newValue = newValue_;
  519. oldValue = comp->getSkewFactor();
  520. }
  521. bool perform() override
  522. {
  523. showCorrectTab();
  524. getComponent()->setSkewFactor (newValue);
  525. changed();
  526. return true;
  527. }
  528. bool undo() override
  529. {
  530. showCorrectTab();
  531. getComponent()->setSkewFactor (oldValue);
  532. changed();
  533. return true;
  534. }
  535. double newValue, oldValue;
  536. };
  537. };
  538. //==============================================================================
  539. static String sliderStyleToString (Slider::SliderStyle style)
  540. {
  541. switch (style)
  542. {
  543. case Slider::LinearHorizontal: return "LinearHorizontal";
  544. case Slider::LinearVertical: return "LinearVertical";
  545. case Slider::LinearBar: return "LinearBar";
  546. case Slider::LinearBarVertical: return "LinearBarVertical";
  547. case Slider::Rotary: return "Rotary";
  548. case Slider::RotaryHorizontalDrag: return "RotaryHorizontalDrag";
  549. case Slider::RotaryVerticalDrag: return "RotaryVerticalDrag";
  550. case Slider::RotaryHorizontalVerticalDrag: return "RotaryHorizontalVerticalDrag";
  551. case Slider::IncDecButtons: return "IncDecButtons";
  552. case Slider::TwoValueHorizontal: return "TwoValueHorizontal";
  553. case Slider::TwoValueVertical: return "TwoValueVertical";
  554. case Slider::ThreeValueHorizontal: return "ThreeValueHorizontal";
  555. case Slider::ThreeValueVertical: return "ThreeValueVertical";
  556. default: jassertfalse; break;
  557. }
  558. return {};
  559. }
  560. static Slider::SliderStyle sliderStringToStyle (const String& s)
  561. {
  562. for (int i = 0; i < numElementsInArray (sliderStyleTypes); ++i)
  563. if (s == sliderStyleToString (sliderStyleTypes[i]))
  564. return sliderStyleTypes[i];
  565. jassertfalse;
  566. return Slider::LinearHorizontal;
  567. }
  568. static String textBoxPosToString (const Slider::TextEntryBoxPosition pos)
  569. {
  570. switch (pos)
  571. {
  572. case Slider::NoTextBox: return "NoTextBox";
  573. case Slider::TextBoxLeft: return "TextBoxLeft";
  574. case Slider::TextBoxRight: return "TextBoxRight";
  575. case Slider::TextBoxAbove: return "TextBoxAbove";
  576. case Slider::TextBoxBelow: return "TextBoxBelow";
  577. default: jassertfalse; break;
  578. }
  579. return {};
  580. }
  581. static Slider::TextEntryBoxPosition stringToTextBoxPos (const String& s)
  582. {
  583. for (int i = 0; i < numElementsInArray (sliderTextBoxPositions); ++i)
  584. if (s == textBoxPosToString (sliderTextBoxPositions[i]))
  585. return sliderTextBoxPositions[i];
  586. jassertfalse;
  587. return Slider::TextBoxLeft;
  588. }
  589. };