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.

658 lines
23KB

  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. class ViewportHandler : public ComponentTypeHandler
  18. {
  19. public:
  20. ViewportHandler()
  21. : ComponentTypeHandler ("Viewport", "Viewport", typeid (UpdatingViewport), 150, 150)
  22. {}
  23. Component* createNewComponent (JucerDocument*)
  24. {
  25. Viewport* const v = new UpdatingViewport ("new viewport");
  26. v->setViewedComponent (new ViewportDemoContentComp());
  27. return v;
  28. }
  29. XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
  30. {
  31. Viewport* const v = dynamic_cast<Viewport*> (comp);
  32. XmlElement* const e = ComponentTypeHandler::createXmlFor (comp, layout);
  33. e->setAttribute ("vscroll", v->isVerticalScrollBarShown());
  34. e->setAttribute ("hscroll", v->isHorizontalScrollBarShown());
  35. e->setAttribute ("scrollbarThickness", v->getScrollBarThickness());
  36. e->setAttribute ("contentType", getViewportContentType (v));
  37. e->setAttribute ("jucerFile", getViewportJucerComponentFile (v));
  38. e->setAttribute ("contentClass", getViewportGenericComponentClass (v));
  39. e->setAttribute ("constructorParams", getViewportConstructorParams (v));
  40. return e;
  41. }
  42. bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
  43. {
  44. if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
  45. return false;
  46. Viewport defaultViewport;
  47. Viewport* const v = dynamic_cast<Viewport*> (comp);
  48. v->setScrollBarsShown (xml.getBoolAttribute ("vscroll", defaultViewport.isVerticalScrollBarShown()),
  49. xml.getBoolAttribute ("hscroll", defaultViewport.isHorizontalScrollBarShown()));
  50. v->setScrollBarThickness (xml.getIntAttribute ("scrollbarThickness", defaultViewport.getScrollBarThickness()));
  51. setViewportJucerComponentFile (v, xml.getStringAttribute ("jucerFile", String()));
  52. setViewportGenericComponentClass (v, xml.getStringAttribute ("contentClass"));
  53. setViewportContentType (v, xml.getIntAttribute ("contentType", 0));
  54. setViewportConstructorParams (v, xml.getStringAttribute ("constructorParams"));
  55. return true;
  56. }
  57. void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
  58. {
  59. ComponentTypeHandler::getEditableProperties (component, document, props);
  60. Viewport* const v = dynamic_cast<Viewport*> (component);
  61. props.add (new ViewportScrollbarShownProperty (v, document, true));
  62. props.add (new ViewportScrollbarShownProperty (v, document, false));
  63. props.add (new ViewportScrollbarSizeProperty (v, document));
  64. props.add (new ViewportContentTypeProperty (v, document));
  65. if (getViewportContentType (v) == 1)
  66. {
  67. props.add (new ViewportJucerFileProperty (v, document));
  68. props.add (new ConstructorParamsProperty (v, document));
  69. }
  70. else if (getViewportContentType (v) == 2)
  71. {
  72. props.add (new ViewportContentClassProperty (v, document));
  73. props.add (new ConstructorParamsProperty (v, document));
  74. }
  75. }
  76. String getCreationParameters (GeneratedCode&, Component* comp)
  77. {
  78. return quotedString (comp->getName(), false);
  79. }
  80. void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
  81. {
  82. Viewport defaultViewport;
  83. Viewport* const v = dynamic_cast<Viewport*> (component);
  84. ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
  85. if (defaultViewport.isVerticalScrollBarShown() != v->isVerticalScrollBarShown()
  86. || defaultViewport.isHorizontalScrollBarShown() != v->isHorizontalScrollBarShown())
  87. {
  88. code.constructorCode
  89. << memberVariableName << "->setScrollBarsShown ("
  90. << CodeHelpers::boolLiteral (v->isVerticalScrollBarShown()) << ", "
  91. << CodeHelpers::boolLiteral (v->isHorizontalScrollBarShown()) << ");\n";
  92. }
  93. if (defaultViewport.getScrollBarThickness() != v->getScrollBarThickness())
  94. {
  95. code.constructorCode
  96. << memberVariableName << "->setScrollBarThickness ("
  97. << v->getScrollBarThickness() << ");\n";
  98. }
  99. if (getViewportContentType (v) != 0)
  100. {
  101. String classNm (getViewportGenericComponentClass (v));
  102. if (getViewportContentType (v) == 1)
  103. {
  104. File file;
  105. const String filename (getViewportJucerComponentFile (v));
  106. if (filename.isNotEmpty())
  107. file = code.document->getCppFile().getSiblingFile (filename);
  108. ScopedPointer<JucerDocument> doc (JucerDocument::createForCppFile (nullptr, file));
  109. if (doc != nullptr)
  110. {
  111. code.includeFilesCPP.add (doc->getHeaderFile()
  112. .getRelativePathFrom (code.document->getCppFile().getParentDirectory())
  113. .replaceCharacter ('\\', '/'));
  114. classNm = doc->getClassName();
  115. }
  116. else
  117. {
  118. classNm = String();
  119. }
  120. }
  121. if (classNm.isNotEmpty())
  122. {
  123. code.constructorCode
  124. << memberVariableName << "->setViewedComponent (new "
  125. << classNm;
  126. if (getViewportConstructorParams (v).trim().isNotEmpty())
  127. {
  128. code.constructorCode << " (" << getViewportConstructorParams (v).trim() << "));\n";
  129. }
  130. else
  131. {
  132. code.constructorCode << "());\n";
  133. }
  134. }
  135. }
  136. code.constructorCode << "\n";
  137. }
  138. static void updateViewportContentComp (Viewport* vp)
  139. {
  140. if (getViewportContentType (vp) == 1)
  141. {
  142. JucerDocument* doc = findParentDocument (vp);
  143. TestComponent* tc = new TestComponent (doc, 0, false);
  144. tc->setFilename (getViewportJucerComponentFile (vp));
  145. tc->setToInitialSize();
  146. vp->setViewedComponent (tc);
  147. }
  148. else
  149. {
  150. vp->setViewedComponent (new ViewportDemoContentComp());
  151. }
  152. }
  153. static int getViewportContentType (Viewport* vp)
  154. {
  155. return vp->getProperties() ["contentType"];
  156. }
  157. static void setViewportContentType (Viewport* vp, int newValue)
  158. {
  159. if (newValue != getViewportContentType (vp))
  160. {
  161. vp->getProperties().set ("contentType", newValue);
  162. updateViewportContentComp (vp);
  163. }
  164. }
  165. static String getViewportJucerComponentFile (Viewport* vp)
  166. {
  167. return vp->getProperties() ["jucerFile"].toString();
  168. }
  169. static void setViewportJucerComponentFile (Viewport* vp, const String& file)
  170. {
  171. if (file != getViewportJucerComponentFile (vp))
  172. {
  173. vp->getProperties().set ("jucerFile", file);
  174. updateViewportContentComp (vp);
  175. }
  176. }
  177. static String getViewportGenericComponentClass (Viewport* vp)
  178. {
  179. return vp->getProperties() ["contentClass"].toString();
  180. }
  181. static void setViewportGenericComponentClass (Viewport* vp, const String& className)
  182. {
  183. if (className != getViewportGenericComponentClass (vp))
  184. {
  185. vp->getProperties().set ("contentClass", className);
  186. updateViewportContentComp (vp);
  187. }
  188. }
  189. static String getViewportConstructorParams (Viewport* vp)
  190. {
  191. return vp->getProperties() ["constructorParams"].toString();
  192. }
  193. static void setViewportConstructorParams (Viewport* vp, const String& newParams)
  194. {
  195. if (newParams != getViewportConstructorParams (vp))
  196. {
  197. vp->getProperties().set ("constructorParams", newParams);
  198. updateViewportContentComp (vp);
  199. }
  200. }
  201. private:
  202. //==============================================================================
  203. class UpdatingViewport : public Viewport
  204. {
  205. public:
  206. UpdatingViewport (const String& name)
  207. : Viewport (name)
  208. {
  209. }
  210. void parentHierarchyChanged()
  211. {
  212. Viewport::parentHierarchyChanged();
  213. updateViewportContentComp (this);
  214. }
  215. };
  216. //==============================================================================
  217. struct ViewportDemoContentComp : public Component
  218. {
  219. ViewportDemoContentComp()
  220. {
  221. setSize (2048, 2048);
  222. }
  223. void paint (Graphics& g) override
  224. {
  225. g.fillCheckerBoard (getLocalBounds(), 50, 50,
  226. Colours::lightgrey.withAlpha (0.5f),
  227. Colours::darkgrey.withAlpha (0.5f));
  228. }
  229. };
  230. //==============================================================================
  231. class ViewportScrollbarShownProperty : public ComponentBooleanProperty <Viewport>
  232. {
  233. public:
  234. ViewportScrollbarShownProperty (Viewport* comp, JucerDocument& doc, const bool vertical_)
  235. : ComponentBooleanProperty <Viewport> (vertical_ ? "V scrollbar" : "H scrollbar",
  236. "enabled", "enabled",
  237. comp, doc),
  238. vertical (vertical_)
  239. {
  240. }
  241. void setState (bool newState)
  242. {
  243. document.perform (new ViewportScrollbarChangeAction (component, *document.getComponentLayout(), vertical, newState),
  244. "Change Viewport scrollbar");
  245. }
  246. bool getState() const
  247. {
  248. return vertical ? component->isVerticalScrollBarShown()
  249. : component->isHorizontalScrollBarShown();
  250. }
  251. const bool vertical;
  252. private:
  253. class ViewportScrollbarChangeAction : public ComponentUndoableAction <Viewport>
  254. {
  255. public:
  256. ViewportScrollbarChangeAction (Viewport* const comp, ComponentLayout& l, const bool vertical_, const bool newState_)
  257. : ComponentUndoableAction <Viewport> (comp, l),
  258. vertical (vertical_),
  259. newState (newState_)
  260. {
  261. oldState = vertical ? comp->isVerticalScrollBarShown()
  262. : comp->isHorizontalScrollBarShown();
  263. }
  264. bool perform()
  265. {
  266. showCorrectTab();
  267. if (vertical)
  268. getComponent()->setScrollBarsShown (newState, getComponent()->isHorizontalScrollBarShown());
  269. else
  270. getComponent()->setScrollBarsShown (getComponent()->isVerticalScrollBarShown(), newState);
  271. changed();
  272. return true;
  273. }
  274. bool undo()
  275. {
  276. showCorrectTab();
  277. if (vertical)
  278. getComponent()->setScrollBarsShown (oldState, getComponent()->isHorizontalScrollBarShown());
  279. else
  280. getComponent()->setScrollBarsShown (getComponent()->isVerticalScrollBarShown(), oldState);
  281. changed();
  282. return true;
  283. }
  284. bool vertical, newState, oldState;
  285. };
  286. };
  287. //==============================================================================
  288. class ViewportScrollbarSizeProperty : public SliderPropertyComponent,
  289. public ChangeListener
  290. {
  291. public:
  292. ViewportScrollbarSizeProperty (Viewport* comp, JucerDocument& doc)
  293. : SliderPropertyComponent ("scrollbar size", 3.0, 30.0, 1.0, 1.0),
  294. component (comp),
  295. document (doc)
  296. {
  297. document.addChangeListener (this);
  298. }
  299. ~ViewportScrollbarSizeProperty()
  300. {
  301. document.removeChangeListener (this);
  302. }
  303. void setValue (double newValue)
  304. {
  305. document.getUndoManager().undoCurrentTransactionOnly();
  306. document.perform (new ViewportScrollbarSizeChangeAction (component, *document.getComponentLayout(), roundToInt (newValue)),
  307. "Change Viewport scrollbar size");
  308. }
  309. double getValue() const
  310. {
  311. return component->getScrollBarThickness();
  312. }
  313. void changeListenerCallback (ChangeBroadcaster*)
  314. {
  315. refresh();
  316. }
  317. Viewport* component;
  318. JucerDocument& document;
  319. private:
  320. class ViewportScrollbarSizeChangeAction : public ComponentUndoableAction <Viewport>
  321. {
  322. public:
  323. ViewportScrollbarSizeChangeAction (Viewport* const comp, ComponentLayout& l, const int newState_)
  324. : ComponentUndoableAction <Viewport> (comp, l),
  325. newState (newState_)
  326. {
  327. oldState = comp->getScrollBarThickness();
  328. }
  329. bool perform()
  330. {
  331. showCorrectTab();
  332. getComponent()->setScrollBarThickness (newState);
  333. changed();
  334. return true;
  335. }
  336. bool undo()
  337. {
  338. showCorrectTab();
  339. getComponent()->setScrollBarThickness (newState);
  340. changed();
  341. return true;
  342. }
  343. int newState, oldState;
  344. };
  345. };
  346. //==============================================================================
  347. class ViewportContentTypeProperty : public ComponentChoiceProperty <Viewport>
  348. {
  349. public:
  350. ViewportContentTypeProperty (Viewport* comp, JucerDocument& doc)
  351. : ComponentChoiceProperty <Viewport> ("content", comp, doc)
  352. {
  353. choices.add ("No content component");
  354. choices.add ("Jucer content component");
  355. choices.add ("Named content component");
  356. }
  357. void setIndex (int newIndex)
  358. {
  359. document.perform (new ViewportContentTypeChangeAction (component, *document.getComponentLayout(), newIndex),
  360. "Change Viewport content type");
  361. }
  362. int getIndex() const
  363. {
  364. return getViewportContentType (component);
  365. }
  366. private:
  367. class ViewportContentTypeChangeAction : public ComponentUndoableAction <Viewport>
  368. {
  369. public:
  370. ViewportContentTypeChangeAction (Viewport* const comp, ComponentLayout& l, const int newValue_)
  371. : ComponentUndoableAction <Viewport> (comp, l),
  372. newValue (newValue_)
  373. {
  374. oldValue = getViewportContentType (comp);
  375. }
  376. bool perform()
  377. {
  378. showCorrectTab();
  379. setViewportContentType (getComponent(), newValue);
  380. changed();
  381. layout.getDocument()->refreshAllPropertyComps();
  382. return true;
  383. }
  384. bool undo()
  385. {
  386. showCorrectTab();
  387. setViewportContentType (getComponent(), oldValue);
  388. changed();
  389. layout.getDocument()->refreshAllPropertyComps();
  390. return true;
  391. }
  392. int newValue, oldValue;
  393. };
  394. };
  395. //==============================================================================
  396. class ViewportJucerFileProperty : public FilePropertyComponent,
  397. public ChangeListener
  398. {
  399. public:
  400. ViewportJucerFileProperty (Viewport* const comp, JucerDocument& doc)
  401. : FilePropertyComponent ("Jucer file", false, true),
  402. component (comp),
  403. document (doc)
  404. {
  405. document.addChangeListener (this);
  406. }
  407. ~ViewportJucerFileProperty()
  408. {
  409. document.removeChangeListener (this);
  410. }
  411. void setFile (const File& newFile)
  412. {
  413. document.perform (new JucerCompFileChangeAction (component, *document.getComponentLayout(),
  414. newFile.getRelativePathFrom (document.getCppFile().getParentDirectory())
  415. .replaceCharacter ('\\', '/')),
  416. "Change Projucer component file");
  417. }
  418. File getFile() const
  419. {
  420. auto filename = getViewportJucerComponentFile (component);
  421. if (filename.isEmpty())
  422. return {};
  423. return document.getCppFile().getSiblingFile (filename);
  424. }
  425. void changeListenerCallback (ChangeBroadcaster*)
  426. {
  427. refresh();
  428. }
  429. private:
  430. Viewport* const component;
  431. JucerDocument& document;
  432. class JucerCompFileChangeAction : public ComponentUndoableAction <Viewport>
  433. {
  434. public:
  435. JucerCompFileChangeAction (Viewport* const comp, ComponentLayout& l, const String& newState_)
  436. : ComponentUndoableAction <Viewport> (comp, l),
  437. newState (newState_)
  438. {
  439. oldState = getViewportJucerComponentFile (comp);
  440. }
  441. bool perform()
  442. {
  443. showCorrectTab();
  444. setViewportJucerComponentFile (getComponent(), newState);
  445. changed();
  446. return true;
  447. }
  448. bool undo()
  449. {
  450. showCorrectTab();
  451. setViewportJucerComponentFile (getComponent(), oldState);
  452. changed();
  453. return true;
  454. }
  455. String newState, oldState;
  456. };
  457. };
  458. //==============================================================================
  459. class ViewportContentClassProperty : public ComponentTextProperty <Viewport>
  460. {
  461. public:
  462. ViewportContentClassProperty (Viewport* comp, JucerDocument& doc)
  463. : ComponentTextProperty <Viewport> ("content class", 256, false, comp, doc)
  464. {
  465. }
  466. void setText (const String& newText) override
  467. {
  468. document.perform (new ViewportClassNameChangeAction (component, *document.getComponentLayout(), newText),
  469. "Change Viewport content class");
  470. }
  471. String getText() const override
  472. {
  473. return getViewportGenericComponentClass (component);
  474. }
  475. private:
  476. class ViewportClassNameChangeAction : public ComponentUndoableAction <Viewport>
  477. {
  478. public:
  479. ViewportClassNameChangeAction (Viewport* const comp, ComponentLayout& l, const String& newValue_)
  480. : ComponentUndoableAction <Viewport> (comp, l),
  481. newValue (newValue_)
  482. {
  483. oldValue = getViewportGenericComponentClass (comp);
  484. }
  485. bool perform()
  486. {
  487. showCorrectTab();
  488. setViewportGenericComponentClass (getComponent(), newValue);
  489. changed();
  490. layout.getDocument()->refreshAllPropertyComps();
  491. return true;
  492. }
  493. bool undo()
  494. {
  495. showCorrectTab();
  496. setViewportGenericComponentClass (getComponent(), oldValue);
  497. changed();
  498. layout.getDocument()->refreshAllPropertyComps();
  499. return true;
  500. }
  501. String newValue, oldValue;
  502. };
  503. };
  504. //==============================================================================
  505. class ConstructorParamsProperty : public ComponentTextProperty <Viewport>
  506. {
  507. public:
  508. ConstructorParamsProperty (Viewport* comp, JucerDocument& doc)
  509. : ComponentTextProperty <Viewport> ("constructor params", 512, false, comp, doc)
  510. {
  511. }
  512. void setText (const String& newText) override
  513. {
  514. document.perform (new ConstructorParamChangeAction (component, *document.getComponentLayout(), newText),
  515. "Change Viewport content constructor params");
  516. }
  517. String getText() const override
  518. {
  519. return getViewportConstructorParams (component);
  520. }
  521. private:
  522. class ConstructorParamChangeAction : public ComponentUndoableAction <Viewport>
  523. {
  524. public:
  525. ConstructorParamChangeAction (Viewport* const comp, ComponentLayout& l, const String& newValue_)
  526. : ComponentUndoableAction <Viewport> (comp, l),
  527. newValue (newValue_)
  528. {
  529. oldValue = getViewportConstructorParams (comp);
  530. }
  531. bool perform()
  532. {
  533. showCorrectTab();
  534. setViewportConstructorParams (getComponent(), newValue);
  535. changed();
  536. layout.getDocument()->refreshAllPropertyComps();
  537. return true;
  538. }
  539. bool undo()
  540. {
  541. showCorrectTab();
  542. setViewportConstructorParams (getComponent(), oldValue);
  543. changed();
  544. layout.getDocument()->refreshAllPropertyComps();
  545. return true;
  546. }
  547. String newValue, oldValue;
  548. };
  549. };
  550. };