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.

703 lines
27KB

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