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.

382 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. class ButtonHandler : public ComponentTypeHandler
  19. {
  20. public:
  21. ButtonHandler (const String& typeDescription_,
  22. const String& className_,
  23. const std::type_info& componentClass,
  24. const int defaultWidth_,
  25. const int defaultHeight_)
  26. : ComponentTypeHandler (typeDescription_, className_, componentClass,
  27. defaultWidth_, defaultHeight_)
  28. {}
  29. void getEditableProperties (Component* component, JucerDocument& document, Array <PropertyComponent*>& properties)
  30. {
  31. ComponentTypeHandler::getEditableProperties (component, document, properties);
  32. Button* const b = dynamic_cast <Button*> (component);
  33. properties.add (new ButtonTextProperty (b, document));
  34. properties.add (new ButtonCallbackProperty (b, document));
  35. properties.add (new ButtonRadioGroupProperty (b, document));
  36. properties.add (new ButtonConnectedEdgeProperty ("connected left", Button::ConnectedOnLeft, b, document));
  37. properties.add (new ButtonConnectedEdgeProperty ("connected right", Button::ConnectedOnRight, b, document));
  38. properties.add (new ButtonConnectedEdgeProperty ("connected top", Button::ConnectedOnTop, b, document));
  39. properties.add (new ButtonConnectedEdgeProperty ("connected bottom", Button::ConnectedOnBottom, b, document));
  40. }
  41. XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
  42. {
  43. Button* const b = dynamic_cast <Button*> (comp);
  44. XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
  45. e->setAttribute ("buttonText", b->getButtonText());
  46. e->setAttribute ("connectedEdges", b->getConnectedEdgeFlags());
  47. e->setAttribute ("needsCallback", needsButtonListener (b));
  48. e->setAttribute ("radioGroupId", b->getRadioGroupId());
  49. return e;
  50. }
  51. bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
  52. {
  53. Button* const b = dynamic_cast <Button*> (comp);
  54. if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
  55. return false;
  56. b->setButtonText (xml.getStringAttribute ("buttonText", b->getButtonText()));
  57. b->setConnectedEdges (xml.getIntAttribute ("connectedEdges", 0));
  58. setNeedsButtonListener (b, xml.getBoolAttribute ("needsCallback", true));
  59. b->setRadioGroupId (xml.getIntAttribute ("radioGroupId", 0));
  60. return true;
  61. }
  62. String getCreationParameters (Component* component)
  63. {
  64. return quotedString (component->getName());
  65. }
  66. void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
  67. {
  68. ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
  69. Button* const b = dynamic_cast <Button*> (component);
  70. if (b->getButtonText() != b->getName())
  71. {
  72. code.constructorCode
  73. << memberVariableName << "->setButtonText ("
  74. << quotedString (b->getButtonText()) << ");\n";
  75. }
  76. if (b->getConnectedEdgeFlags() != 0)
  77. {
  78. StringArray flags;
  79. if (b->isConnectedOnLeft())
  80. flags.add ("Button::ConnectedOnLeft");
  81. if (b->isConnectedOnRight())
  82. flags.add ("Button::ConnectedOnRight");
  83. if (b->isConnectedOnTop())
  84. flags.add ("Button::ConnectedOnTop");
  85. if (b->isConnectedOnBottom())
  86. flags.add ("Button::ConnectedOnBottom");
  87. String s;
  88. s << memberVariableName << "->setConnectedEdges ("
  89. << flags.joinIntoString (" | ") << ");\n";
  90. code.constructorCode += s;
  91. }
  92. if (b->getRadioGroupId() != 0)
  93. code.constructorCode << memberVariableName << "->setRadioGroupId ("
  94. << b->getRadioGroupId() << ");\n";
  95. if (needsButtonListener (component))
  96. code.constructorCode << memberVariableName << "->addListener (this);\n";
  97. }
  98. void fillInGeneratedCode (Component* component, GeneratedCode& code)
  99. {
  100. ComponentTypeHandler::fillInGeneratedCode (component, code);
  101. if (needsButtonListener (component))
  102. {
  103. String& callback = code.getCallbackCode ("public ButtonListener",
  104. "void",
  105. "buttonClicked (Button* buttonThatWasClicked)",
  106. true);
  107. if (callback.isNotEmpty())
  108. callback << "else ";
  109. const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
  110. const String userCodeComment ("UserButtonCode_" + memberVariableName);
  111. callback
  112. << "if (buttonThatWasClicked == " << memberVariableName
  113. << ")\n{\n //[" << userCodeComment << "] -- add your button handler code here..\n //[/" << userCodeComment << "]\n}\n";
  114. }
  115. }
  116. static bool needsButtonListener (Component* button)
  117. {
  118. return button->getProperties().getWithDefault ("generateListenerCallback", true);
  119. }
  120. static void setNeedsButtonListener (Component* button, const bool shouldDoCallback)
  121. {
  122. button->getProperties().set ("generateListenerCallback", shouldDoCallback);
  123. }
  124. private:
  125. //==============================================================================
  126. class ButtonTextProperty : public ComponentTextProperty <Button>
  127. {
  128. public:
  129. ButtonTextProperty (Button* button_, JucerDocument& doc)
  130. : ComponentTextProperty <Button> ("text", 100, false, button_, doc)
  131. {
  132. }
  133. void setText (const String& newText)
  134. {
  135. document.perform (new ButtonTextChangeAction (component, *document.getComponentLayout(), newText),
  136. "Change button text");
  137. }
  138. String getText() const
  139. {
  140. return component->getButtonText();
  141. }
  142. private:
  143. class ButtonTextChangeAction : public ComponentUndoableAction <Button>
  144. {
  145. public:
  146. ButtonTextChangeAction (Button* const comp, ComponentLayout& layout, const String& newName_)
  147. : ComponentUndoableAction <Button> (comp, layout),
  148. newName (newName_)
  149. {
  150. oldName = comp->getButtonText();
  151. }
  152. bool perform()
  153. {
  154. showCorrectTab();
  155. getComponent()->setButtonText (newName);
  156. changed();
  157. return true;
  158. }
  159. bool undo()
  160. {
  161. showCorrectTab();
  162. getComponent()->setButtonText (oldName);
  163. changed();
  164. return true;
  165. }
  166. String newName, oldName;
  167. };
  168. };
  169. class ButtonCallbackProperty : public ComponentBooleanProperty <Button>
  170. {
  171. public:
  172. ButtonCallbackProperty (Button* button, JucerDocument& document)
  173. : ComponentBooleanProperty <Button> ("callback", "Generate ButtonListener", "Generate ButtonListener", button, document)
  174. {
  175. }
  176. void setState (bool newState)
  177. {
  178. document.perform (new ButtonCallbackChangeAction (component, *document.getComponentLayout(), newState),
  179. "Change button callback");
  180. }
  181. bool getState() const { return needsButtonListener (component); }
  182. private:
  183. class ButtonCallbackChangeAction : public ComponentUndoableAction <Button>
  184. {
  185. public:
  186. ButtonCallbackChangeAction (Button* const comp, ComponentLayout& layout, const bool newState_)
  187. : ComponentUndoableAction <Button> (comp, layout),
  188. newState (newState_)
  189. {
  190. oldState = needsButtonListener (comp);
  191. }
  192. bool perform()
  193. {
  194. showCorrectTab();
  195. setNeedsButtonListener (getComponent(), newState);
  196. changed();
  197. return true;
  198. }
  199. bool undo()
  200. {
  201. showCorrectTab();
  202. setNeedsButtonListener (getComponent(), oldState);
  203. changed();
  204. return true;
  205. }
  206. bool newState, oldState;
  207. };
  208. };
  209. class ButtonRadioGroupProperty : public ComponentTextProperty <Button>
  210. {
  211. public:
  212. ButtonRadioGroupProperty (Button* const button_, JucerDocument& doc)
  213. : ComponentTextProperty <Button> ("radio group", 10, false, button_, doc)
  214. {
  215. }
  216. void setText (const String& newText)
  217. {
  218. document.perform (new ButtonRadioGroupChangeAction (component, *document.getComponentLayout(), newText.getIntValue()),
  219. "Change radio group ID");
  220. }
  221. String getText() const
  222. {
  223. return String (component->getRadioGroupId());
  224. }
  225. private:
  226. class ButtonRadioGroupChangeAction : public ComponentUndoableAction <Button>
  227. {
  228. public:
  229. ButtonRadioGroupChangeAction (Button* const comp, ComponentLayout& layout, const int newId_)
  230. : ComponentUndoableAction <Button> (comp, layout),
  231. newId (newId_)
  232. {
  233. oldId = comp->getRadioGroupId();
  234. }
  235. bool perform()
  236. {
  237. showCorrectTab();
  238. getComponent()->setRadioGroupId (newId);
  239. changed();
  240. return true;
  241. }
  242. bool undo()
  243. {
  244. showCorrectTab();
  245. getComponent()->setRadioGroupId (oldId);
  246. changed();
  247. return true;
  248. }
  249. int newId, oldId;
  250. };
  251. };
  252. class ButtonConnectedEdgeProperty : public ComponentBooleanProperty <Button>
  253. {
  254. public:
  255. ButtonConnectedEdgeProperty (const String& name, const int flag_,
  256. Button* button, JucerDocument& document)
  257. : ComponentBooleanProperty <Button> (name, "Connected", "Connected", button, document),
  258. flag (flag_)
  259. {
  260. }
  261. void setState (bool newState)
  262. {
  263. document.perform (new ButtonConnectedChangeAction (component, *document.getComponentLayout(), flag, newState),
  264. "Change button connected edges");
  265. }
  266. bool getState() const
  267. {
  268. return (component->getConnectedEdgeFlags() & flag) != 0;
  269. }
  270. private:
  271. const int flag;
  272. class ButtonConnectedChangeAction : public ComponentUndoableAction <Button>
  273. {
  274. public:
  275. ButtonConnectedChangeAction (Button* const comp, ComponentLayout& layout, const int flag_, const bool newState_)
  276. : ComponentUndoableAction <Button> (comp, layout),
  277. flag (flag_),
  278. newState (newState_)
  279. {
  280. oldState = ((comp->getConnectedEdgeFlags() & flag) != 0);
  281. }
  282. bool perform()
  283. {
  284. showCorrectTab();
  285. if (newState)
  286. getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() | flag);
  287. else
  288. getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() & ~flag);
  289. changed();
  290. return true;
  291. }
  292. bool undo()
  293. {
  294. showCorrectTab();
  295. if (oldState)
  296. getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() | flag);
  297. else
  298. getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() & ~flag);
  299. changed();
  300. return true;
  301. }
  302. const int flag;
  303. bool newState, oldState;
  304. };
  305. };
  306. };