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.

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