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.

667 lines
23KB

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