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.

485 lines
16KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../jucer_Headers.h"
  24. #include "jucer_MainWindow.h"
  25. #include "jucer_ComponentLayoutEditor.h"
  26. #include "jucer_JucerDocumentHolder.h"
  27. #include "jucer_PrefsPanel.h"
  28. #include "jucer_TestComponent.h"
  29. #include "../model/jucer_ObjectTypes.h"
  30. #include "../properties/jucer_FontPropertyComponent.h"
  31. static OldSchoolLookAndFeel* oldLook = 0;
  32. static const int snapSizes[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32 };
  33. //==============================================================================
  34. class MultiDocHolder : public MultiDocumentPanel
  35. {
  36. public:
  37. MultiDocHolder()
  38. {
  39. setBackgroundColour (Colour (0xffe6f0ff));
  40. }
  41. ~MultiDocHolder()
  42. {
  43. }
  44. bool tryToCloseDocument (Component* component)
  45. {
  46. JucerDocumentHolder* const holder = dynamic_cast <JucerDocumentHolder*> (component);
  47. return holder == 0
  48. || holder->getDocument() == 0
  49. || holder->getDocument()->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk;
  50. }
  51. };
  52. //==============================================================================
  53. MainWindow::MainWindow()
  54. : DocumentWindow (T("The Jucer"),
  55. Colours::azure,
  56. DocumentWindow::allButtons)
  57. {
  58. if (oldLook == 0)
  59. oldLook = new OldSchoolLookAndFeel();
  60. setContentComponent (multiDocHolder = new MultiDocHolder());
  61. setApplicationCommandManagerToWatch (commandManager);
  62. #if JUCE_MAC
  63. setMacMainMenu (this);
  64. #else
  65. setMenuBar (this);
  66. #endif
  67. setResizable (true, false);
  68. centreWithSize (700, 600);
  69. // restore the last size and position from our settings file..
  70. restoreWindowStateFromString (StoredSettings::getInstance()->getProps()
  71. .getValue (T("lastMainWindowPos")));
  72. // Register all the app commands..
  73. {
  74. commandManager->registerAllCommandsForTarget (JUCEApplication::getInstance());
  75. commandManager->registerAllCommandsForTarget (this);
  76. // use a temporary one of these to harvest its commands..
  77. JucerDocumentHolder tempDesignHolder (ObjectTypes::createNewDocument (0));
  78. commandManager->registerAllCommandsForTarget (&tempDesignHolder);
  79. }
  80. commandManager->getKeyMappings()->resetToDefaultMappings();
  81. XmlElement* const keys = StoredSettings::getInstance()->getProps().getXmlValue (T("keyMappings"));
  82. if (keys != 0)
  83. {
  84. commandManager->getKeyMappings()->restoreFromXml (*keys);
  85. delete keys;
  86. }
  87. addKeyListener (commandManager->getKeyMappings());
  88. // don't want the window to take focus when the title-bar is clicked..
  89. setWantsKeyboardFocus (false);
  90. #ifndef JUCE_DEBUG
  91. // scan for fonts before the app gets started rather than glitching later
  92. FontPropertyComponent::preloadAllFonts();
  93. #endif
  94. }
  95. MainWindow::~MainWindow()
  96. {
  97. #if JUCE_MAC
  98. setMacMainMenu (0);
  99. #else
  100. setMenuBar (0);
  101. #endif
  102. removeKeyListener (commandManager->getKeyMappings());
  103. // save the current size and position to our settings file..
  104. StoredSettings::getInstance()->getProps()
  105. .setValue (T("lastMainWindowPos"), getWindowStateAsString());
  106. setContentComponent (0);
  107. LookAndFeel::setDefaultLookAndFeel (0);
  108. deleteAndZero (oldLook);
  109. }
  110. void MainWindow::closeButtonPressed()
  111. {
  112. JUCEApplication::getInstance()->systemRequestedQuit();
  113. }
  114. JucerDocument* MainWindow::getActiveDocument() const throw()
  115. {
  116. JucerDocumentHolder* holder = dynamic_cast <JucerDocumentHolder*> (multiDocHolder->getActiveDocument());
  117. if (holder == 0)
  118. return 0;
  119. return holder->getDocument();
  120. }
  121. bool MainWindow::closeAllDocuments()
  122. {
  123. return multiDocHolder->closeAllDocuments (true);
  124. }
  125. bool MainWindow::closeDocument (JucerDocumentHolder* designHolder)
  126. {
  127. return multiDocHolder->closeDocument (designHolder, true);
  128. }
  129. void MainWindow::openDocument (JucerDocument* const newDoc)
  130. {
  131. const File f (newDoc->getFile());
  132. // check it's not already open..
  133. if (f != File::nonexistent)
  134. {
  135. for (int i = multiDocHolder->getNumDocuments(); --i >= 0;)
  136. {
  137. JucerDocumentHolder* holder = dynamic_cast <JucerDocumentHolder*> (multiDocHolder->getDocument (i));
  138. if (holder != 0 && holder->getDocument()->getFile() == f)
  139. {
  140. multiDocHolder->setActiveDocument (holder);
  141. delete newDoc;
  142. return;
  143. }
  144. }
  145. }
  146. multiDocHolder->addDocument (new JucerDocumentHolder (newDoc), Colour (0xffc4cdcd), true);
  147. }
  148. bool MainWindow::openFile (const File& file)
  149. {
  150. JucerDocument* newDoc = ObjectTypes::loadDocumentFromFile (file, true);
  151. if (newDoc != 0)
  152. openDocument (newDoc);
  153. return newDoc != 0;
  154. }
  155. bool MainWindow::filesDropped (const StringArray& filenames, int mouseX, int mouseY)
  156. {
  157. for (int i = filenames.size(); --i >= 0;)
  158. {
  159. const File f (filenames[i]);
  160. if (f.hasFileExtension (T(".cpp")))
  161. if (openFile (f))
  162. return true;
  163. }
  164. return false;
  165. }
  166. void MainWindow::activeWindowStatusChanged()
  167. {
  168. DocumentWindow::activeWindowStatusChanged();
  169. if (isActiveWindow())
  170. TestComponent::reloadAll();
  171. }
  172. //==============================================================================
  173. const StringArray MainWindow::getMenuBarNames()
  174. {
  175. const tchar* const names[] = { T("File"), T("Edit"), T("View"), 0 };
  176. return StringArray ((const tchar**) names);
  177. }
  178. const PopupMenu MainWindow::getMenuForIndex (int topLevelMenuIndex,
  179. const String& menuName)
  180. {
  181. PopupMenu menu;
  182. if (topLevelMenuIndex == 0)
  183. {
  184. // "File" menu
  185. for (int i = 0; i < ObjectTypes::numDocumentTypes; ++i)
  186. menu.addCommandItem (commandManager, CommandIDs::newDocumentBase + i);
  187. menu.addSeparator();
  188. menu.addCommandItem (commandManager, CommandIDs::open);
  189. PopupMenu recentFiles;
  190. StoredSettings::getInstance()->recentFiles.createPopupMenuItems (recentFiles, 100, true, true);
  191. menu.addSubMenu (T("Open recent file"), recentFiles);
  192. menu.addSeparator();
  193. menu.addCommandItem (commandManager, CommandIDs::close);
  194. menu.addSeparator();
  195. menu.addCommandItem (commandManager, CommandIDs::save);
  196. menu.addCommandItem (commandManager, CommandIDs::saveAs);
  197. menu.addSeparator();
  198. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  199. }
  200. else if (topLevelMenuIndex == 1)
  201. {
  202. // "Edit" menu
  203. menu.addCommandItem (commandManager, CommandIDs::undo);
  204. menu.addCommandItem (commandManager, CommandIDs::redo);
  205. menu.addSeparator();
  206. menu.addCommandItem (commandManager, CommandIDs::editCompLayout);
  207. menu.addCommandItem (commandManager, CommandIDs::editCompGraphics);
  208. menu.addSeparator();
  209. PopupMenu newComps;
  210. int i;
  211. for (i = 0; i < ObjectTypes::numComponentTypes; ++i)
  212. newComps.addCommandItem (commandManager, CommandIDs::newComponentBase + i);
  213. menu.addSubMenu (T("Add new component"), newComps);
  214. PopupMenu newElements;
  215. for (i = 0; i < ObjectTypes::numElementTypes; ++i)
  216. newElements.addCommandItem (commandManager, CommandIDs::newElementBase + i);
  217. menu.addSubMenu (T("Add new graphic element"), newElements);
  218. menu.addSeparator();
  219. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
  220. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
  221. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
  222. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
  223. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::selectAll);
  224. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::deselectAll);
  225. menu.addSeparator();
  226. menu.addCommandItem (commandManager, CommandIDs::toFront);
  227. menu.addCommandItem (commandManager, CommandIDs::toBack);
  228. menu.addSeparator();
  229. menu.addCommandItem (commandManager, CommandIDs::group);
  230. menu.addCommandItem (commandManager, CommandIDs::ungroup);
  231. menu.addSeparator();
  232. menu.addCommandItem (commandManager, CommandIDs::bringBackLostItems);
  233. }
  234. else if (topLevelMenuIndex == 2)
  235. {
  236. // "View" menu
  237. menu.addCommandItem (commandManager, CommandIDs::test);
  238. PopupMenu lookAndFeels;
  239. lookAndFeels.addItem (201, T("Default"), true, (typeid (LookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel())) != 0);
  240. lookAndFeels.addItem (200, T("Old School"), true, (typeid (OldSchoolLookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel())) != 0);
  241. menu.addSeparator();
  242. menu.addSubMenu (T("Look and Feel"), lookAndFeels);
  243. menu.addSeparator();
  244. menu.addCommandItem (commandManager, CommandIDs::showGrid);
  245. menu.addCommandItem (commandManager, CommandIDs::enableSnapToGrid);
  246. const int currentSnapSize = getActiveDocument() != 0 ? getActiveDocument()->getSnappingGridSize() : 0;
  247. PopupMenu m;
  248. for (int i = 0; i < numElementsInArray (snapSizes); ++i)
  249. m.addItem (300 + i, String (snapSizes[i]) + T(" pixels"), true, snapSizes[i] == currentSnapSize);
  250. menu.addSubMenu (T("Grid size"), m, getActiveDocument() != 0);
  251. menu.addSeparator();
  252. menu.addCommandItem (commandManager, CommandIDs::zoomIn);
  253. menu.addCommandItem (commandManager, CommandIDs::zoomOut);
  254. menu.addCommandItem (commandManager, CommandIDs::zoomNormal);
  255. menu.addSeparator();
  256. PopupMenu overlays;
  257. overlays.addCommandItem (commandManager, CommandIDs::compOverlay0);
  258. overlays.addCommandItem (commandManager, CommandIDs::compOverlay33);
  259. overlays.addCommandItem (commandManager, CommandIDs::compOverlay66);
  260. overlays.addCommandItem (commandManager, CommandIDs::compOverlay100);
  261. menu.addSubMenu (T("Component Overlay"), overlays,
  262. getActiveDocument() != 0 && getActiveDocument()->getComponentLayout() != 0);
  263. menu.addSeparator();
  264. menu.addCommandItem (commandManager, CommandIDs::useTabbedWindows);
  265. menu.addSeparator();
  266. menu.addCommandItem (commandManager, CommandIDs::showPrefs);
  267. }
  268. return menu;
  269. }
  270. void MainWindow::menuItemSelected (int menuItemID,
  271. int topLevelMenuIndex)
  272. {
  273. if (menuItemID >= 100 && menuItemID < 200)
  274. {
  275. // open a file from the "recent files" menu
  276. JucerDocument* const newDoc
  277. = ObjectTypes::loadDocumentFromFile (StoredSettings::getInstance()->recentFiles.getFile (menuItemID - 100),
  278. true);
  279. if (newDoc != 0)
  280. openDocument (newDoc);
  281. }
  282. else if (menuItemID == 200)
  283. {
  284. LookAndFeel::setDefaultLookAndFeel (oldLook);
  285. }
  286. else if (menuItemID == 201)
  287. {
  288. LookAndFeel::setDefaultLookAndFeel (0);
  289. }
  290. else if (menuItemID >= 300 && menuItemID < 400)
  291. {
  292. if (getActiveDocument() != 0)
  293. {
  294. getActiveDocument()->setSnappingGrid (snapSizes [menuItemID - 300],
  295. getActiveDocument()->isSnapActive (false),
  296. getActiveDocument()->isSnapShown());
  297. }
  298. }
  299. }
  300. //==============================================================================
  301. ApplicationCommandTarget* MainWindow::getNextCommandTarget()
  302. {
  303. return 0;
  304. }
  305. void MainWindow::getAllCommands (Array <CommandID>& commands)
  306. {
  307. for (int i = 0; i < ObjectTypes::numDocumentTypes; ++i)
  308. commands.add (CommandIDs::newDocumentBase + i);
  309. const CommandID ids[] = { CommandIDs::open,
  310. CommandIDs::showPrefs,
  311. CommandIDs::useTabbedWindows };
  312. commands.addArray (ids, numElementsInArray (ids));
  313. }
  314. void MainWindow::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
  315. {
  316. if (commandID >= CommandIDs::newDocumentBase
  317. && commandID < CommandIDs::newDocumentBase + ObjectTypes::numDocumentTypes)
  318. {
  319. const int index = commandID - CommandIDs::newDocumentBase;
  320. result.setInfo (T("New ") + String (ObjectTypes::documentTypeNames [index]),
  321. T("Creates a new ") + String (ObjectTypes::documentTypeNames[index]),
  322. CommandCategories::general, 0);
  323. return;
  324. }
  325. const int cmd = ModifierKeys::commandModifier;
  326. switch (commandID)
  327. {
  328. case CommandIDs::open:
  329. result.setInfo (T("Open..."),
  330. T("Opens a Jucer .cpp component file for editing."),
  331. CommandCategories::general, 0);
  332. result.defaultKeypresses.add (KeyPress (T('o'), cmd, 0));
  333. break;
  334. case CommandIDs::showPrefs:
  335. result.setInfo (T("Preferences..."),
  336. T("Shows the preferences panel."),
  337. CommandCategories::general, 0);
  338. result.defaultKeypresses.add (KeyPress (T(','), cmd, 0));
  339. break;
  340. case CommandIDs::useTabbedWindows:
  341. result.setInfo (T("Use tabs to show windows"),
  342. T("Flips between a tabbed component and separate windows"),
  343. CommandCategories::general, 0);
  344. result.setTicked (multiDocHolder->getLayoutMode() == MultiDocumentPanel::MaximisedWindowsWithTabs);
  345. break;
  346. default:
  347. break;
  348. }
  349. }
  350. bool MainWindow::isCommandActive (const CommandID commandID)
  351. {
  352. return true;
  353. }
  354. bool MainWindow::perform (const InvocationInfo& info)
  355. {
  356. if (info.commandID >= CommandIDs::newDocumentBase
  357. && info.commandID < CommandIDs::newDocumentBase + ObjectTypes::numDocumentTypes)
  358. {
  359. const int index = info.commandID - CommandIDs::newDocumentBase;
  360. openDocument (ObjectTypes::createNewDocument (index));
  361. return true;
  362. }
  363. switch (info.commandID)
  364. {
  365. case CommandIDs::open:
  366. openFile (File::nonexistent);
  367. break;
  368. case CommandIDs::showPrefs:
  369. PrefsPanel::show();
  370. break;
  371. case CommandIDs::useTabbedWindows:
  372. if (multiDocHolder->getLayoutMode() == MultiDocumentPanel::MaximisedWindowsWithTabs)
  373. multiDocHolder->setLayoutMode (MultiDocumentPanel::FloatingWindows);
  374. else
  375. multiDocHolder->setLayoutMode (MultiDocumentPanel::MaximisedWindowsWithTabs);
  376. break;
  377. default:
  378. return false;
  379. }
  380. return true;
  381. }