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.

411 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 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. #include "../../jucer_Headers.h"
  19. #include "../../model/Component/jucer_ComponentDocument.h"
  20. #include "../jucer_JucerTreeViewBase.h"
  21. #include "../Editor Base/jucer_EditorPanel.h"
  22. #include "../Editor Base/jucer_EditorDragOperation.h"
  23. #include "jucer_ComponentEditor.h"
  24. #include "jucer_ComponentEditorCanvas.h"
  25. #include "jucer_ComponentEditorTreeView.h"
  26. #include "jucer_ComponentEditorCodeView.h"
  27. #include "jucer_ComponentEditorToolbar.h"
  28. //==============================================================================
  29. class ComponentEditor::ClassInfoHolder : public Component
  30. {
  31. public:
  32. ClassInfoHolder (ComponentEditor& editor_)
  33. : editor (editor_)
  34. {
  35. addAndMakeVisible (panel = new PropertyPanelWithTooltips());
  36. Array <PropertyComponent*> props;
  37. editor.getDocument().createClassProperties (props);
  38. panel->getPanel()->addSection ("Component Properties", props, true);
  39. }
  40. ~ClassInfoHolder()
  41. {
  42. deleteAllChildren();
  43. }
  44. void resized()
  45. {
  46. panel->setBounds (getLocalBounds());
  47. }
  48. private:
  49. ComponentEditor& editor;
  50. PropertyPanelWithTooltips* panel;
  51. };
  52. //==============================================================================
  53. class ComponentEditor::LayoutEditorHolder : public EditorPanelBase
  54. {
  55. public:
  56. LayoutEditorHolder (ComponentEditor& editor_)
  57. : toolbarFactory (editor_),
  58. editor (editor_)
  59. {
  60. }
  61. ~LayoutEditorHolder()
  62. {
  63. shutdown();
  64. }
  65. void createCanvas()
  66. {
  67. initialise (new ComponentEditorCanvas (editor), toolbarFactory,
  68. new ComponentEditorTreeView::Root (editor));
  69. }
  70. SelectedItemSet<String>& getSelection()
  71. {
  72. return editor.getSelection();
  73. }
  74. void getSelectedItemProperties (Array<PropertyComponent*>& props)
  75. {
  76. editor.getDocument().createItemProperties (props, editor.getSelectedIds());
  77. }
  78. private:
  79. ComponentEditorToolbarFactory toolbarFactory;
  80. ComponentEditor& editor;
  81. };
  82. //==============================================================================
  83. class ComponentEditor::BackgroundEditorHolder : public Component
  84. {
  85. public:
  86. BackgroundEditorHolder (ComponentEditor& editor_)
  87. : editor (editor_)
  88. {
  89. }
  90. ~BackgroundEditorHolder()
  91. {
  92. }
  93. private:
  94. ComponentEditor& editor;
  95. };
  96. //==============================================================================
  97. ComponentEditor::ComponentEditor (OpenDocumentManager::Document* document_,
  98. Project* project_, ComponentDocument* componentDocument_)
  99. : DocumentEditorComponent (document_),
  100. project (project_),
  101. componentDocument (componentDocument_),
  102. classInfoHolder (0),
  103. layoutEditorHolder (0),
  104. backgroundEditorHolder (0),
  105. codeEditorHolder (0)
  106. {
  107. setOpaque (true);
  108. if (componentDocument != 0)
  109. {
  110. classInfoHolder = new ClassInfoHolder (*this);
  111. layoutEditorHolder = new LayoutEditorHolder (*this);
  112. backgroundEditorHolder = new BackgroundEditorHolder (*this);
  113. codeEditorHolder = new CodeEditorHolder (*this);
  114. layoutEditorHolder->createCanvas();
  115. }
  116. addAndMakeVisible (tabs = new TabbedComponent (TabbedButtonBar::TabsAtRight));
  117. tabs->setTabBarDepth (22);
  118. tabs->setOutline (0);
  119. tabs->addTab ("Class Settings", Colour::greyLevel (0.88f), classInfoHolder, true);
  120. tabs->addTab ("Components", Colours::white, layoutEditorHolder, true);
  121. tabs->addTab ("Background", Colours::white, backgroundEditorHolder, true);
  122. tabs->addTab ("Source Code", Colours::white, codeEditorHolder, true);
  123. tabs->setCurrentTabIndex (1);
  124. }
  125. ComponentEditor::~ComponentEditor()
  126. {
  127. deleteAllChildren();
  128. }
  129. void ComponentEditor::paint (Graphics& g)
  130. {
  131. g.fillAll (Colours::white);
  132. }
  133. void ComponentEditor::resized()
  134. {
  135. tabs->setBounds (getLocalBounds());
  136. }
  137. const StringArray ComponentEditor::getSelectedIds() const
  138. {
  139. StringArray ids;
  140. const int num = selection.getNumSelected();
  141. for (int i = 0; i < num; ++i)
  142. ids.add (selection.getSelectedItem(i));
  143. return ids;
  144. }
  145. void ComponentEditor::deleteSelection()
  146. {
  147. const StringArray ids (getSelectedIds());
  148. getSelection().deselectAll();
  149. getDocument().beginNewTransaction();
  150. for (int i = ids.size(); --i >= 0;)
  151. {
  152. const ValueTree comp (getDocument().getComponentWithID (ids[i]));
  153. if (comp.isValid())
  154. getDocument().removeComponent (comp);
  155. }
  156. getDocument().beginNewTransaction();
  157. }
  158. void ComponentEditor::deselectNonComponents()
  159. {
  160. EditorCanvasBase::SelectedItems& sel = getSelection();
  161. for (int i = sel.getNumSelected(); --i >= 0;)
  162. if (! getDocument().getComponentWithID (sel.getSelectedItem (i)).isValid())
  163. sel.deselect (sel.getSelectedItem (i));
  164. }
  165. void ComponentEditor::selectionToFront()
  166. {
  167. getDocument().beginNewTransaction();
  168. int index = 0;
  169. for (int i = getDocument().getNumComponents(); --i >= 0;)
  170. {
  171. const ValueTree comp (getDocument().getComponent (index));
  172. if (comp.isValid() && getSelection().isSelected (comp [ComponentDocument::idProperty]))
  173. {
  174. ValueTree parent (comp.getParent());
  175. parent.moveChild (parent.indexOf (comp), -1, getDocument().getUndoManager());
  176. }
  177. else
  178. {
  179. ++index;
  180. }
  181. }
  182. getDocument().beginNewTransaction();
  183. }
  184. void ComponentEditor::selectionToBack()
  185. {
  186. getDocument().beginNewTransaction();
  187. int index = getDocument().getNumComponents() - 1;
  188. for (int i = getDocument().getNumComponents(); --i >= 0;)
  189. {
  190. const ValueTree comp (getDocument().getComponent (index));
  191. if (comp.isValid() && getSelection().isSelected (comp [ComponentDocument::idProperty]))
  192. {
  193. ValueTree parent (comp.getParent());
  194. parent.moveChild (parent.indexOf (comp), 0, getDocument().getUndoManager());
  195. }
  196. else
  197. {
  198. --index;
  199. }
  200. }
  201. getDocument().beginNewTransaction();
  202. }
  203. //==============================================================================
  204. void ComponentEditor::showNewComponentMenu (Component* componentToAttachTo)
  205. {
  206. PopupMenu m;
  207. getDocument().addNewComponentMenuItems (m);
  208. const int r = m.showAt (componentToAttachTo);
  209. const ValueTree newComp (getDocument().performNewComponentMenuItem (r));
  210. if (newComp.isValid())
  211. getSelection().selectOnly (newComp [ComponentDocument::idProperty]);
  212. }
  213. //==============================================================================
  214. void ComponentEditor::test()
  215. {
  216. ScopedPointer<Component> testComp (document->createViewer());
  217. TooltipWindow tooltipWindow;
  218. DialogWindow::showModalDialog ("Testing: " + getDocument().getClassName().toString(),
  219. testComp, this, Colours::lightgrey, true, true);
  220. }
  221. //==============================================================================
  222. void ComponentEditor::getAllCommands (Array <CommandID>& commands)
  223. {
  224. DocumentEditorComponent::getAllCommands (commands);
  225. const CommandID ids[] = { CommandIDs::undo,
  226. CommandIDs::redo,
  227. CommandIDs::toFront,
  228. CommandIDs::toBack,
  229. CommandIDs::test,
  230. CommandIDs::showOrHideProperties,
  231. CommandIDs::showOrHideTree,
  232. CommandIDs::showOrHideMarkers,
  233. CommandIDs::toggleSnapping,
  234. StandardApplicationCommandIDs::del };
  235. commands.addArray (ids, numElementsInArray (ids));
  236. }
  237. void ComponentEditor::getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  238. {
  239. result.setActive (document != 0);
  240. switch (commandID)
  241. {
  242. case CommandIDs::undo:
  243. result.setInfo ("Undo", "Undoes the last change", CommandCategories::general, 0);
  244. result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::commandModifier, 0));
  245. break;
  246. case CommandIDs::redo:
  247. result.setInfo ("Redo", "Redoes the last change", CommandCategories::general, 0);
  248. result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::shiftModifier | ModifierKeys::commandModifier, 0));
  249. result.defaultKeypresses.add (KeyPress ('y', ModifierKeys::commandModifier, 0));
  250. break;
  251. case CommandIDs::toFront:
  252. result.setInfo ("Bring to Front", "Brings the selected items to the front", CommandCategories::editing, 0);
  253. break;
  254. case CommandIDs::toBack:
  255. result.setInfo ("Send to Back", "Moves the selected items to the back", CommandCategories::editing, 0);
  256. break;
  257. case CommandIDs::test:
  258. result.setInfo ("Test", "Test the current component", CommandCategories::editing, 0);
  259. result.defaultKeypresses.add (KeyPress ('t', ModifierKeys::commandModifier, 0));
  260. break;
  261. case CommandIDs::showOrHideProperties:
  262. result.setInfo ("Show/Hide Tree", "Shows or hides the component tree view", CommandCategories::editing, 0);
  263. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->arePropertiesVisible());
  264. break;
  265. case CommandIDs::showOrHideTree:
  266. result.setInfo ("Show/Hide Properties", "Shows or hides the component properties panel", CommandCategories::editing, 0);
  267. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->isTreeVisible());
  268. break;
  269. case CommandIDs::showOrHideMarkers:
  270. result.setInfo ("Show/Hide Markers", "Shows or hides the markers", CommandCategories::editing, 0);
  271. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->areMarkersVisible());
  272. break;
  273. case CommandIDs::toggleSnapping:
  274. result.setInfo ("Toggle snapping", "Turns object snapping on or off", CommandCategories::editing, 0);
  275. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->isSnappingEnabled());
  276. break;
  277. case StandardApplicationCommandIDs::del:
  278. result.setInfo ("Delete", String::empty, CommandCategories::general, 0);
  279. result.defaultKeypresses.add (KeyPress (KeyPress::deleteKey, 0, 0));
  280. result.defaultKeypresses.add (KeyPress (KeyPress::backspaceKey, 0, 0));
  281. break;
  282. default:
  283. DocumentEditorComponent::getCommandInfo (commandID, result);
  284. break;
  285. }
  286. }
  287. bool ComponentEditor::perform (const InvocationInfo& info)
  288. {
  289. switch (info.commandID)
  290. {
  291. case CommandIDs::undo:
  292. getDocument().getUndoManager()->beginNewTransaction();
  293. getDocument().getUndoManager()->undo();
  294. return true;
  295. case CommandIDs::redo:
  296. getDocument().getUndoManager()->beginNewTransaction();
  297. getDocument().getUndoManager()->redo();
  298. return true;
  299. case CommandIDs::toFront:
  300. selectionToFront();
  301. return true;
  302. case CommandIDs::toBack:
  303. selectionToBack();
  304. return true;
  305. case CommandIDs::test:
  306. test();
  307. return true;
  308. case CommandIDs::showOrHideProperties:
  309. layoutEditorHolder->showOrHideProperties();
  310. return true;
  311. case CommandIDs::showOrHideTree:
  312. layoutEditorHolder->showOrHideTree();
  313. return true;
  314. case CommandIDs::showOrHideMarkers:
  315. layoutEditorHolder->showOrHideMarkers();
  316. return true;
  317. case CommandIDs::toggleSnapping:
  318. layoutEditorHolder->toggleSnapping();
  319. return true;
  320. case StandardApplicationCommandIDs::del:
  321. deleteSelection();
  322. return true;
  323. default:
  324. break;
  325. }
  326. return DocumentEditorComponent::perform (info);
  327. }