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.

682 lines
27KB

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