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.

668 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. #pragma once
  20. //==============================================================================
  21. class ViewportHandler : public ComponentTypeHandler
  22. {
  23. public:
  24. ViewportHandler()
  25. : ComponentTypeHandler ("Viewport", "Viewport", typeid (UpdatingViewport), 150, 150)
  26. {}
  27. Component* createNewComponent (JucerDocument*) override
  28. {
  29. Viewport* const v = new UpdatingViewport ("new viewport");
  30. v->setViewedComponent (new ViewportDemoContentComp());
  31. return v;
  32. }
  33. XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
  34. {
  35. Viewport* const v = dynamic_cast<Viewport*> (comp);
  36. XmlElement* const e = ComponentTypeHandler::createXmlFor (comp, layout);
  37. e->setAttribute ("vscroll", v->isVerticalScrollBarShown());
  38. e->setAttribute ("hscroll", v->isHorizontalScrollBarShown());
  39. e->setAttribute ("scrollbarThickness", v->getScrollBarThickness());
  40. e->setAttribute ("contentType", getViewportContentType (v));
  41. e->setAttribute ("jucerFile", getViewportJucerComponentFile (v));
  42. e->setAttribute ("contentClass", getViewportGenericComponentClass (v));
  43. e->setAttribute ("constructorParams", getViewportConstructorParams (v));
  44. return e;
  45. }
  46. bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
  47. {
  48. if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
  49. return false;
  50. Viewport defaultViewport;
  51. Viewport* const v = dynamic_cast<Viewport*> (comp);
  52. v->setScrollBarsShown (xml.getBoolAttribute ("vscroll", defaultViewport.isVerticalScrollBarShown()),
  53. xml.getBoolAttribute ("hscroll", defaultViewport.isHorizontalScrollBarShown()));
  54. v->setScrollBarThickness (xml.getIntAttribute ("scrollbarThickness", defaultViewport.getScrollBarThickness()));
  55. setViewportJucerComponentFile (v, xml.getStringAttribute ("jucerFile", String()));
  56. setViewportGenericComponentClass (v, xml.getStringAttribute ("contentClass"));
  57. setViewportContentType (v, xml.getIntAttribute ("contentType", 0));
  58. setViewportConstructorParams (v, xml.getStringAttribute ("constructorParams"));
  59. return true;
  60. }
  61. void getEditableProperties (Component* component, JucerDocument& document,
  62. Array<PropertyComponent*>& props, bool multipleSelected) override
  63. {
  64. ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
  65. if (multipleSelected)
  66. return;
  67. auto* v = dynamic_cast<Viewport*> (component);
  68. props.add (new ViewportScrollbarShownProperty (v, document, true));
  69. props.add (new ViewportScrollbarShownProperty (v, document, false));
  70. props.add (new ViewportScrollbarSizeProperty (v, document));
  71. props.add (new ViewportContentTypeProperty (v, document));
  72. if (getViewportContentType (v) == 1)
  73. {
  74. props.add (new ViewportJucerFileProperty (v, document));
  75. props.add (new ConstructorParamsProperty (v, document));
  76. }
  77. else if (getViewportContentType (v) == 2)
  78. {
  79. props.add (new ViewportContentClassProperty (v, document));
  80. props.add (new ConstructorParamsProperty (v, document));
  81. }
  82. }
  83. String getCreationParameters (GeneratedCode&, Component* comp) override
  84. {
  85. return quotedString (comp->getName(), false);
  86. }
  87. void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
  88. {
  89. Viewport defaultViewport;
  90. Viewport* const v = dynamic_cast<Viewport*> (component);
  91. ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
  92. if (defaultViewport.isVerticalScrollBarShown() != v->isVerticalScrollBarShown()
  93. || defaultViewport.isHorizontalScrollBarShown() != v->isHorizontalScrollBarShown())
  94. {
  95. code.constructorCode
  96. << memberVariableName << "->setScrollBarsShown ("
  97. << CodeHelpers::boolLiteral (v->isVerticalScrollBarShown()) << ", "
  98. << CodeHelpers::boolLiteral (v->isHorizontalScrollBarShown()) << ");\n";
  99. }
  100. if (defaultViewport.getScrollBarThickness() != v->getScrollBarThickness())
  101. {
  102. code.constructorCode
  103. << memberVariableName << "->setScrollBarThickness ("
  104. << v->getScrollBarThickness() << ");\n";
  105. }
  106. if (getViewportContentType (v) != 0)
  107. {
  108. String classNm (getViewportGenericComponentClass (v));
  109. if (getViewportContentType (v) == 1)
  110. {
  111. File file;
  112. const String filename (getViewportJucerComponentFile (v));
  113. if (filename.isNotEmpty())
  114. file = code.document->getCppFile().getSiblingFile (filename);
  115. ScopedPointer<JucerDocument> doc (JucerDocument::createForCppFile (nullptr, file));
  116. if (doc != nullptr)
  117. {
  118. code.includeFilesCPP.add (doc->getHeaderFile()
  119. .getRelativePathFrom (code.document->getCppFile().getParentDirectory())
  120. .replaceCharacter ('\\', '/'));
  121. classNm = doc->getClassName();
  122. }
  123. else
  124. {
  125. classNm = String();
  126. }
  127. }
  128. if (classNm.isNotEmpty())
  129. {
  130. code.constructorCode
  131. << memberVariableName << "->setViewedComponent (new "
  132. << classNm;
  133. if (getViewportConstructorParams (v).trim().isNotEmpty())
  134. {
  135. code.constructorCode << " (" << getViewportConstructorParams (v).trim() << "));\n";
  136. }
  137. else
  138. {
  139. code.constructorCode << "());\n";
  140. }
  141. }
  142. }
  143. code.constructorCode << "\n";
  144. }
  145. static void updateViewportContentComp (Viewport* vp)
  146. {
  147. if (getViewportContentType (vp) == 1)
  148. {
  149. JucerDocument* doc = findParentDocument (vp);
  150. TestComponent* tc = new TestComponent (doc, 0, false);
  151. tc->setFilename (getViewportJucerComponentFile (vp));
  152. tc->setToInitialSize();
  153. vp->setViewedComponent (tc);
  154. }
  155. else
  156. {
  157. vp->setViewedComponent (new ViewportDemoContentComp());
  158. }
  159. }
  160. static int getViewportContentType (Viewport* vp)
  161. {
  162. return vp->getProperties() ["contentType"];
  163. }
  164. static void setViewportContentType (Viewport* vp, int newValue)
  165. {
  166. if (newValue != getViewportContentType (vp))
  167. {
  168. vp->getProperties().set ("contentType", newValue);
  169. updateViewportContentComp (vp);
  170. }
  171. }
  172. static String getViewportJucerComponentFile (Viewport* vp)
  173. {
  174. return vp->getProperties() ["jucerFile"].toString();
  175. }
  176. static void setViewportJucerComponentFile (Viewport* vp, const String& file)
  177. {
  178. if (file != getViewportJucerComponentFile (vp))
  179. {
  180. vp->getProperties().set ("jucerFile", file);
  181. updateViewportContentComp (vp);
  182. }
  183. }
  184. static String getViewportGenericComponentClass (Viewport* vp)
  185. {
  186. return vp->getProperties() ["contentClass"].toString();
  187. }
  188. static void setViewportGenericComponentClass (Viewport* vp, const String& className)
  189. {
  190. if (className != getViewportGenericComponentClass (vp))
  191. {
  192. vp->getProperties().set ("contentClass", className);
  193. updateViewportContentComp (vp);
  194. }
  195. }
  196. static String getViewportConstructorParams (Viewport* vp)
  197. {
  198. return vp->getProperties() ["constructorParams"].toString();
  199. }
  200. static void setViewportConstructorParams (Viewport* vp, const String& newParams)
  201. {
  202. if (newParams != getViewportConstructorParams (vp))
  203. {
  204. vp->getProperties().set ("constructorParams", newParams);
  205. updateViewportContentComp (vp);
  206. }
  207. }
  208. private:
  209. //==============================================================================
  210. class UpdatingViewport : public Viewport
  211. {
  212. public:
  213. UpdatingViewport (const String& name)
  214. : Viewport (name)
  215. {
  216. }
  217. void parentHierarchyChanged()
  218. {
  219. Viewport::parentHierarchyChanged();
  220. updateViewportContentComp (this);
  221. }
  222. };
  223. //==============================================================================
  224. struct ViewportDemoContentComp : public Component
  225. {
  226. ViewportDemoContentComp()
  227. {
  228. setSize (2048, 2048);
  229. }
  230. void paint (Graphics& g) override
  231. {
  232. g.fillCheckerBoard (getLocalBounds().toFloat(), 50.0f, 50.0f,
  233. Colours::lightgrey.withAlpha (0.5f),
  234. Colours::darkgrey.withAlpha (0.5f));
  235. }
  236. };
  237. //==============================================================================
  238. class ViewportScrollbarShownProperty : public ComponentBooleanProperty <Viewport>
  239. {
  240. public:
  241. ViewportScrollbarShownProperty (Viewport* comp, JucerDocument& doc, const bool vertical_)
  242. : ComponentBooleanProperty <Viewport> (vertical_ ? "V scrollbar" : "H scrollbar",
  243. "enabled", "enabled",
  244. comp, doc),
  245. vertical (vertical_)
  246. {
  247. }
  248. void setState (bool newState)
  249. {
  250. document.perform (new ViewportScrollbarChangeAction (component, *document.getComponentLayout(), vertical, newState),
  251. "Change Viewport scrollbar");
  252. }
  253. bool getState() const
  254. {
  255. return vertical ? component->isVerticalScrollBarShown()
  256. : component->isHorizontalScrollBarShown();
  257. }
  258. const bool vertical;
  259. private:
  260. class ViewportScrollbarChangeAction : public ComponentUndoableAction <Viewport>
  261. {
  262. public:
  263. ViewportScrollbarChangeAction (Viewport* const comp, ComponentLayout& l, const bool vertical_, const bool newState_)
  264. : ComponentUndoableAction <Viewport> (comp, l),
  265. vertical (vertical_),
  266. newState (newState_)
  267. {
  268. oldState = vertical ? comp->isVerticalScrollBarShown()
  269. : comp->isHorizontalScrollBarShown();
  270. }
  271. bool perform()
  272. {
  273. showCorrectTab();
  274. if (vertical)
  275. getComponent()->setScrollBarsShown (newState, getComponent()->isHorizontalScrollBarShown());
  276. else
  277. getComponent()->setScrollBarsShown (getComponent()->isVerticalScrollBarShown(), newState);
  278. changed();
  279. return true;
  280. }
  281. bool undo()
  282. {
  283. showCorrectTab();
  284. if (vertical)
  285. getComponent()->setScrollBarsShown (oldState, getComponent()->isHorizontalScrollBarShown());
  286. else
  287. getComponent()->setScrollBarsShown (getComponent()->isVerticalScrollBarShown(), oldState);
  288. changed();
  289. return true;
  290. }
  291. bool vertical, newState, oldState;
  292. };
  293. };
  294. //==============================================================================
  295. class ViewportScrollbarSizeProperty : public SliderPropertyComponent,
  296. public ChangeListener
  297. {
  298. public:
  299. ViewportScrollbarSizeProperty (Viewport* comp, JucerDocument& doc)
  300. : SliderPropertyComponent ("scrollbar size", 3.0, 30.0, 1.0, 1.0),
  301. component (comp),
  302. document (doc)
  303. {
  304. document.addChangeListener (this);
  305. }
  306. ~ViewportScrollbarSizeProperty()
  307. {
  308. document.removeChangeListener (this);
  309. }
  310. void setValue (double newValue)
  311. {
  312. document.getUndoManager().undoCurrentTransactionOnly();
  313. document.perform (new ViewportScrollbarSizeChangeAction (component, *document.getComponentLayout(), roundToInt (newValue)),
  314. "Change Viewport scrollbar size");
  315. }
  316. double getValue() const
  317. {
  318. return component->getScrollBarThickness();
  319. }
  320. void changeListenerCallback (ChangeBroadcaster*)
  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. public 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()
  415. {
  416. document.removeChangeListener (this);
  417. }
  418. void setFile (const File& newFile)
  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
  426. {
  427. auto filename = getViewportJucerComponentFile (component);
  428. if (filename.isEmpty())
  429. return {};
  430. return document.getCppFile().getSiblingFile (filename);
  431. }
  432. void changeListenerCallback (ChangeBroadcaster*)
  433. {
  434. refresh();
  435. }
  436. private:
  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. };