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.

660 lines
23KB

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