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.

707 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 Slider::Listener",
  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,
  140. Array<PropertyComponent*>& props, bool multipleSelected) override
  141. {
  142. ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
  143. if (multipleSelected)
  144. return;
  145. if (auto* s = dynamic_cast<Slider*> (component))
  146. {
  147. props.add (new SliderRangeProperty (s, document, "minimum", 0));
  148. props.add (new SliderRangeProperty (s, document, "maximum", 1));
  149. props.add (new SliderRangeProperty (s, document, "interval", 2));
  150. props.add (new SliderTypeProperty (s, document));
  151. props.add (new SliderTextboxProperty (s, document));
  152. props.add (new SliderTextboxEditableProperty (s, document));
  153. props.add (new SliderTextboxSizeProperty (s, document, true));
  154. props.add (new SliderTextboxSizeProperty (s, document, false));
  155. props.add (new SliderSkewProperty (s, document));
  156. props.add (new SliderCallbackProperty (s, document));
  157. }
  158. addColourProperties (component, document, props);
  159. }
  160. static bool needsSliderListener (Component* slider)
  161. {
  162. return slider->getProperties().getWithDefault ("generateListenerCallback", true);
  163. }
  164. static void setNeedsSliderListener (Component* slider, bool shouldDoCallback)
  165. {
  166. slider->getProperties().set ("generateListenerCallback", shouldDoCallback);
  167. }
  168. private:
  169. //==============================================================================
  170. struct SliderTypeProperty : public ComponentChoiceProperty<Slider>
  171. {
  172. SliderTypeProperty (Slider* slider, JucerDocument& doc)
  173. : ComponentChoiceProperty<Slider> ("type", slider, doc)
  174. {
  175. choices.add ("Linear Horizontal");
  176. choices.add ("Linear Vertical");
  177. choices.add ("Linear Bar Horizontal");
  178. choices.add ("Linear Bar Vertical");
  179. choices.add ("Rotary");
  180. choices.add ("Rotary HorizontalDrag");
  181. choices.add ("Rotary VerticalDrag");
  182. choices.add ("Rotary HorizontalVerticalDrag");
  183. choices.add ("Inc/Dec Buttons");
  184. choices.add ("Two Value Horizontal");
  185. choices.add ("Two Value Vertical");
  186. choices.add ("Three Value Horizontal");
  187. choices.add ("Three Value Vertical");
  188. }
  189. void setIndex (int newIndex) override
  190. {
  191. if (newIndex >= 0 && newIndex < numElementsInArray (sliderStyleTypes))
  192. document.perform (new SliderTypeChangeAction (component, *document.getComponentLayout(),
  193. sliderStyleTypes[newIndex]),
  194. "Change Slider style");
  195. }
  196. int getIndex() const override
  197. {
  198. for (int i = 0; i < numElementsInArray (sliderStyleTypes); ++i)
  199. if (sliderStyleTypes[i] == dynamic_cast<Slider*> (component)->getSliderStyle())
  200. return i;
  201. return -1;
  202. }
  203. private:
  204. struct SliderTypeChangeAction : public ComponentUndoableAction<Slider>
  205. {
  206. SliderTypeChangeAction (Slider* comp, ComponentLayout& l, Slider::SliderStyle newState_)
  207. : ComponentUndoableAction<Slider> (comp, l),
  208. newState (newState_)
  209. {
  210. oldState = comp->getSliderStyle();
  211. }
  212. bool perform() override
  213. {
  214. showCorrectTab();
  215. getComponent()->setSliderStyle (newState);
  216. changed();
  217. return true;
  218. }
  219. bool undo() override
  220. {
  221. showCorrectTab();
  222. getComponent()->setSliderStyle (oldState);
  223. changed();
  224. return true;
  225. }
  226. Slider::SliderStyle newState, oldState;
  227. };
  228. };
  229. //==============================================================================
  230. struct SliderTextboxProperty : public ComponentChoiceProperty<Slider>
  231. {
  232. SliderTextboxProperty (Slider* slider, JucerDocument& doc)
  233. : ComponentChoiceProperty<Slider> ("text position", slider, doc)
  234. {
  235. choices.add ("No text box");
  236. choices.add ("Text box on left");
  237. choices.add ("Text box on right");
  238. choices.add ("Text box above");
  239. choices.add ("Text box below");
  240. }
  241. void setIndex (int newIndex) override
  242. {
  243. if (newIndex >= 0 && newIndex < numElementsInArray (sliderTextBoxPositions))
  244. document.perform (new SliderTextBoxChangeAction (component, *document.getComponentLayout(),
  245. sliderTextBoxPositions[newIndex]),
  246. "Change Slider textbox");
  247. }
  248. int getIndex() const override
  249. {
  250. for (int i = 0; i < numElementsInArray (sliderTextBoxPositions); ++i)
  251. if (sliderTextBoxPositions[i] == component->getTextBoxPosition())
  252. return i;
  253. return -1;
  254. }
  255. private:
  256. struct SliderTextBoxChangeAction : public ComponentUndoableAction<Slider>
  257. {
  258. SliderTextBoxChangeAction (Slider* comp, ComponentLayout& l, Slider::TextEntryBoxPosition newState_)
  259. : ComponentUndoableAction<Slider> (comp, l),
  260. newState (newState_)
  261. {
  262. oldState = comp->getTextBoxPosition();
  263. }
  264. bool perform() override
  265. {
  266. showCorrectTab();
  267. getComponent()->setTextBoxStyle (newState,
  268. ! getComponent()->isTextBoxEditable(),
  269. getComponent()->getTextBoxWidth(),
  270. getComponent()->getTextBoxHeight());
  271. changed();
  272. return true;
  273. }
  274. bool undo() override
  275. {
  276. showCorrectTab();
  277. getComponent()->setTextBoxStyle (oldState,
  278. ! getComponent()->isTextBoxEditable(),
  279. getComponent()->getTextBoxWidth(),
  280. getComponent()->getTextBoxHeight());
  281. changed();
  282. return true;
  283. }
  284. Slider::TextEntryBoxPosition newState, oldState;
  285. };
  286. };
  287. //==============================================================================
  288. struct SliderTextboxEditableProperty : public ComponentBooleanProperty<Slider>
  289. {
  290. SliderTextboxEditableProperty (Slider* slider, JucerDocument& doc)
  291. : ComponentBooleanProperty<Slider> ("text box mode", "Editable", "Editable", slider, doc)
  292. {
  293. }
  294. void setState (bool newState) override
  295. {
  296. document.perform (new SliderEditableChangeAction (component, *document.getComponentLayout(), newState),
  297. "Change Slider editability");
  298. }
  299. bool getState() const override
  300. {
  301. return component->isTextBoxEditable();
  302. }
  303. private:
  304. struct SliderEditableChangeAction : public ComponentUndoableAction<Slider>
  305. {
  306. SliderEditableChangeAction (Slider* const comp, ComponentLayout& l, bool newState_)
  307. : ComponentUndoableAction<Slider> (comp, l),
  308. newState (newState_)
  309. {
  310. oldState = comp->isTextBoxEditable();
  311. }
  312. bool perform() override
  313. {
  314. showCorrectTab();
  315. getComponent()->setTextBoxIsEditable (newState);
  316. changed();
  317. return true;
  318. }
  319. bool undo() override
  320. {
  321. showCorrectTab();
  322. getComponent()->setTextBoxIsEditable (oldState);
  323. changed();
  324. return true;
  325. }
  326. bool newState, oldState;
  327. };
  328. };
  329. //==============================================================================
  330. struct SliderCallbackProperty : public ComponentBooleanProperty<Slider>
  331. {
  332. SliderCallbackProperty (Slider* s, JucerDocument& doc)
  333. : ComponentBooleanProperty<Slider> ("callback", "Generate SliderListener",
  334. "Generate SliderListener", s, doc)
  335. {
  336. }
  337. void setState (bool newState) override
  338. {
  339. document.perform (new SliderCallbackChangeAction (component, *document.getComponentLayout(), newState),
  340. "Change button callback");
  341. }
  342. bool getState() const override { return needsSliderListener (component); }
  343. struct SliderCallbackChangeAction : public ComponentUndoableAction<Slider>
  344. {
  345. SliderCallbackChangeAction (Slider* comp, ComponentLayout& l, bool newState_)
  346. : ComponentUndoableAction<Slider> (comp, l),
  347. newState (newState_)
  348. {
  349. oldState = needsSliderListener (comp);
  350. }
  351. bool perform() override
  352. {
  353. showCorrectTab();
  354. setNeedsSliderListener (getComponent(), newState);
  355. changed();
  356. return true;
  357. }
  358. bool undo() override
  359. {
  360. showCorrectTab();
  361. setNeedsSliderListener (getComponent(), oldState);
  362. changed();
  363. return true;
  364. }
  365. bool newState, oldState;
  366. };
  367. };
  368. //==============================================================================
  369. struct SliderTextboxSizeProperty : public ComponentTextProperty<Slider>
  370. {
  371. SliderTextboxSizeProperty (Slider* slider, JucerDocument& doc, bool isWidth_)
  372. : ComponentTextProperty<Slider> (isWidth_ ? "text box width" : "text box height",
  373. 12, false, slider, doc),
  374. isWidth (isWidth_)
  375. {
  376. }
  377. void setText (const String& newText) override
  378. {
  379. document.perform (new SliderBoxSizeChangeAction (component, *document.getComponentLayout(), isWidth, newText.getIntValue()),
  380. "Change Slider textbox size");
  381. }
  382. String getText() const override
  383. {
  384. return String (isWidth ? component->getTextBoxWidth()
  385. : component->getTextBoxHeight());
  386. }
  387. private:
  388. const bool isWidth;
  389. struct SliderBoxSizeChangeAction : public ComponentUndoableAction<Slider>
  390. {
  391. SliderBoxSizeChangeAction (Slider* const comp, ComponentLayout& l, bool isWidth_, int newSize_)
  392. : ComponentUndoableAction<Slider> (comp, l),
  393. isWidth (isWidth_),
  394. newSize (newSize_)
  395. {
  396. oldSize = isWidth ? comp->getTextBoxWidth()
  397. : comp->getTextBoxHeight();
  398. }
  399. bool perform() override
  400. {
  401. showCorrectTab();
  402. Slider& c = *getComponent();
  403. if (isWidth)
  404. c.setTextBoxStyle (c.getTextBoxPosition(),
  405. ! c.isTextBoxEditable(),
  406. newSize,
  407. c.getTextBoxHeight());
  408. else
  409. c.setTextBoxStyle (c.getTextBoxPosition(),
  410. ! c.isTextBoxEditable(),
  411. c.getTextBoxWidth(),
  412. newSize);
  413. changed();
  414. return true;
  415. }
  416. bool undo() override
  417. {
  418. showCorrectTab();
  419. Slider& c = *getComponent();
  420. if (isWidth)
  421. c.setTextBoxStyle (c.getTextBoxPosition(),
  422. ! c.isTextBoxEditable(),
  423. oldSize,
  424. c.getTextBoxHeight());
  425. else
  426. c.setTextBoxStyle (c.getTextBoxPosition(),
  427. ! c.isTextBoxEditable(),
  428. c.getTextBoxWidth(),
  429. oldSize);
  430. changed();
  431. return true;
  432. }
  433. bool isWidth;
  434. int newSize, oldSize;
  435. };
  436. };
  437. //==============================================================================
  438. struct SliderRangeProperty : public ComponentTextProperty<Slider>
  439. {
  440. SliderRangeProperty (Slider* slider, JucerDocument& doc,
  441. const String& name, int rangeParam_)
  442. : ComponentTextProperty<Slider> (name, 15, false, slider, doc),
  443. rangeParam (rangeParam_)
  444. {
  445. }
  446. void setText (const String& newText) override
  447. {
  448. double state [3];
  449. state [0] = component->getMinimum();
  450. state [1] = component->getMaximum();
  451. state [2] = component->getInterval();
  452. state [rangeParam] = newText.getDoubleValue();
  453. document.perform (new SliderRangeChangeAction (component, *document.getComponentLayout(), state),
  454. "Change Slider range");
  455. }
  456. String getText() const override
  457. {
  458. Slider* s = dynamic_cast<Slider*> (component);
  459. jassert (s != nullptr);
  460. switch (rangeParam)
  461. {
  462. case 0: return String (s->getMinimum());
  463. case 1: return String (s->getMaximum());
  464. case 2: return String (s->getInterval());
  465. default: jassertfalse; break;
  466. }
  467. return {};
  468. }
  469. private:
  470. const int rangeParam;
  471. struct SliderRangeChangeAction : public ComponentUndoableAction<Slider>
  472. {
  473. SliderRangeChangeAction (Slider* comp, ComponentLayout& l, const double newState_[3])
  474. : ComponentUndoableAction<Slider> (comp, l)
  475. {
  476. newState[0] = newState_ [0];
  477. newState[1] = newState_ [1];
  478. newState[2] = newState_ [2];
  479. oldState[0] = comp->getMinimum();
  480. oldState[1] = comp->getMaximum();
  481. oldState[2] = comp->getInterval();
  482. }
  483. bool perform() override
  484. {
  485. showCorrectTab();
  486. getComponent()->setRange (newState[0], newState[1], newState[2]);
  487. changed();
  488. return true;
  489. }
  490. bool undo() override
  491. {
  492. showCorrectTab();
  493. getComponent()->setRange (oldState[0], oldState[1], oldState[2]);
  494. changed();
  495. return true;
  496. }
  497. double newState[3], oldState[3];
  498. };
  499. };
  500. //==============================================================================
  501. struct SliderSkewProperty : public ComponentTextProperty<Slider>
  502. {
  503. SliderSkewProperty (Slider* slider, JucerDocument& doc)
  504. : ComponentTextProperty<Slider> ("skew factor", 12, false, slider, doc)
  505. {
  506. }
  507. void setText (const String& newText) override
  508. {
  509. const double skew = jlimit (0.001, 1000.0, newText.getDoubleValue());
  510. document.perform (new SliderSkewChangeAction (component, *document.getComponentLayout(), skew),
  511. "Change Slider skew");
  512. }
  513. String getText() const override
  514. {
  515. Slider* s = dynamic_cast<Slider*> (component);
  516. jassert (s != 0);
  517. return String (s->getSkewFactor());
  518. }
  519. struct SliderSkewChangeAction : public ComponentUndoableAction<Slider>
  520. {
  521. SliderSkewChangeAction (Slider* comp, ComponentLayout& l, double newValue_)
  522. : ComponentUndoableAction<Slider> (comp, l)
  523. {
  524. newValue = newValue_;
  525. oldValue = comp->getSkewFactor();
  526. }
  527. bool perform() override
  528. {
  529. showCorrectTab();
  530. getComponent()->setSkewFactor (newValue);
  531. changed();
  532. return true;
  533. }
  534. bool undo() override
  535. {
  536. showCorrectTab();
  537. getComponent()->setSkewFactor (oldValue);
  538. changed();
  539. return true;
  540. }
  541. double newValue, oldValue;
  542. };
  543. };
  544. //==============================================================================
  545. static String sliderStyleToString (Slider::SliderStyle style)
  546. {
  547. switch (style)
  548. {
  549. case Slider::LinearHorizontal: return "LinearHorizontal";
  550. case Slider::LinearVertical: return "LinearVertical";
  551. case Slider::LinearBar: return "LinearBar";
  552. case Slider::LinearBarVertical: return "LinearBarVertical";
  553. case Slider::Rotary: return "Rotary";
  554. case Slider::RotaryHorizontalDrag: return "RotaryHorizontalDrag";
  555. case Slider::RotaryVerticalDrag: return "RotaryVerticalDrag";
  556. case Slider::RotaryHorizontalVerticalDrag: return "RotaryHorizontalVerticalDrag";
  557. case Slider::IncDecButtons: return "IncDecButtons";
  558. case Slider::TwoValueHorizontal: return "TwoValueHorizontal";
  559. case Slider::TwoValueVertical: return "TwoValueVertical";
  560. case Slider::ThreeValueHorizontal: return "ThreeValueHorizontal";
  561. case Slider::ThreeValueVertical: return "ThreeValueVertical";
  562. default: jassertfalse; break;
  563. }
  564. return {};
  565. }
  566. static Slider::SliderStyle sliderStringToStyle (const String& s)
  567. {
  568. for (int i = 0; i < numElementsInArray (sliderStyleTypes); ++i)
  569. if (s == sliderStyleToString (sliderStyleTypes[i]))
  570. return sliderStyleTypes[i];
  571. jassertfalse;
  572. return Slider::LinearHorizontal;
  573. }
  574. static String textBoxPosToString (const Slider::TextEntryBoxPosition pos)
  575. {
  576. switch (pos)
  577. {
  578. case Slider::NoTextBox: return "NoTextBox";
  579. case Slider::TextBoxLeft: return "TextBoxLeft";
  580. case Slider::TextBoxRight: return "TextBoxRight";
  581. case Slider::TextBoxAbove: return "TextBoxAbove";
  582. case Slider::TextBoxBelow: return "TextBoxBelow";
  583. default: jassertfalse; break;
  584. }
  585. return {};
  586. }
  587. static Slider::TextEntryBoxPosition stringToTextBoxPos (const String& s)
  588. {
  589. for (int i = 0; i < numElementsInArray (sliderTextBoxPositions); ++i)
  590. if (s == textBoxPosToString (sliderTextBoxPositions[i]))
  591. return sliderTextBoxPositions[i];
  592. jassertfalse;
  593. return Slider::TextBoxLeft;
  594. }
  595. };