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.

444 lines
14KB

  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*>& newComps)
  75. {
  76. editor.getSelectedItemProperties (newComps);
  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::getSelectedItemProperties (Array <PropertyComponent*>& props)
  146. {
  147. getDocument().createItemProperties (props, getSelectedIds());
  148. }
  149. void ComponentEditor::deleteSelection()
  150. {
  151. const StringArray ids (getSelectedIds());
  152. getSelection().deselectAll();
  153. getDocument().beginNewTransaction();
  154. for (int i = ids.size(); --i >= 0;)
  155. {
  156. const ValueTree comp (getDocument().getComponentWithID (ids[i]));
  157. if (comp.isValid())
  158. getDocument().removeComponent (comp);
  159. }
  160. getDocument().beginNewTransaction();
  161. }
  162. void ComponentEditor::deselectNonComponents()
  163. {
  164. EditorCanvasBase::SelectedItems& sel = getSelection();
  165. for (int i = sel.getNumSelected(); --i >= 0;)
  166. if (! getDocument().getComponentWithID (sel.getSelectedItem (i)).isValid())
  167. sel.deselect (sel.getSelectedItem (i));
  168. }
  169. void ComponentEditor::selectionToFront()
  170. {
  171. getDocument().beginNewTransaction();
  172. int index = 0;
  173. for (int i = getDocument().getNumComponents(); --i >= 0;)
  174. {
  175. const ValueTree comp (getDocument().getComponent (index));
  176. if (comp.isValid() && getSelection().isSelected (comp [ComponentDocument::idProperty]))
  177. {
  178. ValueTree parent (comp.getParent());
  179. parent.moveChild (parent.indexOf (comp), -1, getDocument().getUndoManager());
  180. }
  181. else
  182. {
  183. ++index;
  184. }
  185. }
  186. getDocument().beginNewTransaction();
  187. }
  188. void ComponentEditor::selectionToBack()
  189. {
  190. getDocument().beginNewTransaction();
  191. int index = getDocument().getNumComponents() - 1;
  192. for (int i = getDocument().getNumComponents(); --i >= 0;)
  193. {
  194. const ValueTree comp (getDocument().getComponent (index));
  195. if (comp.isValid() && getSelection().isSelected (comp [ComponentDocument::idProperty]))
  196. {
  197. ValueTree parent (comp.getParent());
  198. parent.moveChild (parent.indexOf (comp), 0, getDocument().getUndoManager());
  199. }
  200. else
  201. {
  202. --index;
  203. }
  204. }
  205. getDocument().beginNewTransaction();
  206. }
  207. //==============================================================================
  208. void ComponentEditor::showNewComponentMenu (Component* componentToAttachTo)
  209. {
  210. PopupMenu m;
  211. getDocument().addNewComponentMenuItems (m);
  212. const int r = m.showAt (componentToAttachTo);
  213. const ValueTree newComp (getDocument().performNewComponentMenuItem (r));
  214. if (newComp.isValid())
  215. getSelection().selectOnly (newComp [ComponentDocument::idProperty]);
  216. }
  217. //==============================================================================
  218. class TestComponent : public Component
  219. {
  220. public:
  221. TestComponent (ComponentDocument& document_)
  222. : document (document_)
  223. {
  224. setSize (document.getCanvasWidth().getValue(),
  225. document.getCanvasHeight().getValue());
  226. }
  227. ~TestComponent()
  228. {
  229. deleteAllChildren();
  230. }
  231. void resized()
  232. {
  233. document.getCanvasWidth() = getWidth();
  234. document.getCanvasHeight() = getHeight();
  235. ComponentEditorCanvas::updateComponentsIn (this, document, selected);
  236. }
  237. private:
  238. ComponentDocument document;
  239. ComponentEditorCanvas::SelectedItems selected;
  240. TooltipWindow tooltipWindow;
  241. };
  242. void ComponentEditor::test()
  243. {
  244. TestComponent testComp (getDocument());
  245. DialogWindow::showModalDialog ("Testing: " + getDocument().getClassName().toString(),
  246. &testComp, this, Colours::lightgrey, true, true);
  247. }
  248. //==============================================================================
  249. void ComponentEditor::getAllCommands (Array <CommandID>& commands)
  250. {
  251. DocumentEditorComponent::getAllCommands (commands);
  252. const CommandID ids[] = { CommandIDs::undo,
  253. CommandIDs::redo,
  254. CommandIDs::toFront,
  255. CommandIDs::toBack,
  256. CommandIDs::test,
  257. CommandIDs::showOrHideProperties,
  258. CommandIDs::showOrHideTree,
  259. CommandIDs::showOrHideMarkers,
  260. CommandIDs::toggleSnapping,
  261. StandardApplicationCommandIDs::del };
  262. commands.addArray (ids, numElementsInArray (ids));
  263. }
  264. void ComponentEditor::getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  265. {
  266. result.setActive (document != 0);
  267. switch (commandID)
  268. {
  269. case CommandIDs::undo:
  270. result.setInfo ("Undo", "Undoes the last change", CommandCategories::general, 0);
  271. result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::commandModifier, 0));
  272. break;
  273. case CommandIDs::redo:
  274. result.setInfo ("Redo", "Redoes the last change", CommandCategories::general, 0);
  275. result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::shiftModifier | ModifierKeys::commandModifier, 0));
  276. result.defaultKeypresses.add (KeyPress ('y', ModifierKeys::commandModifier, 0));
  277. break;
  278. case CommandIDs::toFront:
  279. result.setInfo ("Bring to Front", "Brings the selected items to the front", CommandCategories::editing, 0);
  280. break;
  281. case CommandIDs::toBack:
  282. result.setInfo ("Send to Back", "Moves the selected items to the back", CommandCategories::editing, 0);
  283. break;
  284. case CommandIDs::test:
  285. result.setInfo ("Test", "Test the current component", CommandCategories::editing, 0);
  286. result.defaultKeypresses.add (KeyPress ('t', ModifierKeys::commandModifier, 0));
  287. break;
  288. case CommandIDs::showOrHideProperties:
  289. result.setInfo ("Show/Hide Tree", "Shows or hides the component tree view", CommandCategories::editing, 0);
  290. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->arePropertiesVisible());
  291. break;
  292. case CommandIDs::showOrHideTree:
  293. result.setInfo ("Show/Hide Properties", "Shows or hides the component properties panel", CommandCategories::editing, 0);
  294. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->isTreeVisible());
  295. break;
  296. case CommandIDs::showOrHideMarkers:
  297. result.setInfo ("Show/Hide Markers", "Shows or hides the markers", CommandCategories::editing, 0);
  298. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->areMarkersVisible());
  299. break;
  300. case CommandIDs::toggleSnapping:
  301. result.setInfo ("Toggle snapping", "Turns object snapping on or off", CommandCategories::editing, 0);
  302. result.setTicked (layoutEditorHolder != 0 && layoutEditorHolder->isSnappingEnabled());
  303. break;
  304. case StandardApplicationCommandIDs::del:
  305. result.setInfo ("Delete", String::empty, CommandCategories::general, 0);
  306. result.defaultKeypresses.add (KeyPress (KeyPress::deleteKey, 0, 0));
  307. result.defaultKeypresses.add (KeyPress (KeyPress::backspaceKey, 0, 0));
  308. break;
  309. default:
  310. DocumentEditorComponent::getCommandInfo (commandID, result);
  311. break;
  312. }
  313. }
  314. bool ComponentEditor::perform (const InvocationInfo& info)
  315. {
  316. switch (info.commandID)
  317. {
  318. case CommandIDs::undo:
  319. getDocument().getUndoManager()->beginNewTransaction();
  320. getDocument().getUndoManager()->undo();
  321. return true;
  322. case CommandIDs::redo:
  323. getDocument().getUndoManager()->beginNewTransaction();
  324. getDocument().getUndoManager()->redo();
  325. return true;
  326. case CommandIDs::toFront:
  327. selectionToFront();
  328. return true;
  329. case CommandIDs::toBack:
  330. selectionToBack();
  331. return true;
  332. case CommandIDs::test:
  333. test();
  334. return true;
  335. case CommandIDs::showOrHideProperties:
  336. layoutEditorHolder->showOrHideProperties();
  337. return true;
  338. case CommandIDs::showOrHideTree:
  339. layoutEditorHolder->showOrHideTree();
  340. return true;
  341. case CommandIDs::showOrHideMarkers:
  342. layoutEditorHolder->showOrHideMarkers();
  343. return true;
  344. case CommandIDs::toggleSnapping:
  345. layoutEditorHolder->toggleSnapping();
  346. return true;
  347. case StandardApplicationCommandIDs::del:
  348. deleteSelection();
  349. return true;
  350. default:
  351. break;
  352. }
  353. return DocumentEditorComponent::perform (info);
  354. }