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.

702 lines
25KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "jucedemo_headers.h"
  18. #include "MainDemoWindow.h"
  19. //==============================================================================
  20. class ContentComp : public Component,
  21. public MenuBarModel,
  22. public ApplicationCommandTarget
  23. {
  24. public:
  25. //==============================================================================
  26. ContentComp (MainDemoWindow& mainWindow_)
  27. : mainWindow (mainWindow_),
  28. currentDemoId (0)
  29. {
  30. setOpaque (true);
  31. invokeDirectly (showRendering, true);
  32. }
  33. ~ContentComp()
  34. {
  35. #if JUCE_OPENGL
  36. openGLContext.detach();
  37. #endif
  38. }
  39. void paint (Graphics& g)
  40. {
  41. g.fillAll (Colours::white);
  42. }
  43. void resized()
  44. {
  45. if (currentDemo != nullptr)
  46. currentDemo->setBounds (getLocalBounds());
  47. }
  48. //==============================================================================
  49. void showDemo (Component* demoComp)
  50. {
  51. currentDemo = demoComp;
  52. addAndMakeVisible (currentDemo);
  53. resized();
  54. }
  55. //==============================================================================
  56. StringArray getMenuBarNames()
  57. {
  58. const char* const names[] = { "Demo", "Look-and-feel", nullptr };
  59. return StringArray (names);
  60. }
  61. PopupMenu getMenuForIndex (int menuIndex, const String& /*menuName*/)
  62. {
  63. ApplicationCommandManager* commandManager = &(mainWindow.commandManager);
  64. PopupMenu menu;
  65. if (menuIndex == 0)
  66. {
  67. menu.addCommandItem (commandManager, showRendering);
  68. menu.addCommandItem (commandManager, showFontsAndText);
  69. menu.addCommandItem (commandManager, showWidgets);
  70. menu.addCommandItem (commandManager, showThreading);
  71. menu.addCommandItem (commandManager, showTreeView);
  72. menu.addCommandItem (commandManager, showTable);
  73. menu.addCommandItem (commandManager, showAudio);
  74. menu.addCommandItem (commandManager, showDragAndDrop);
  75. menu.addCommandItem (commandManager, showOpenGL);
  76. menu.addCommandItem (commandManager, showQuicktime);
  77. menu.addCommandItem (commandManager, showDirectShow);
  78. menu.addCommandItem (commandManager, showInterprocessComms);
  79. menu.addCommandItem (commandManager, showCamera);
  80. menu.addCommandItem (commandManager, showWebBrowser);
  81. menu.addCommandItem (commandManager, showCodeEditor);
  82. menu.addSeparator();
  83. menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
  84. }
  85. else if (menuIndex == 1)
  86. {
  87. menu.addCommandItem (commandManager, useLookAndFeelV1);
  88. menu.addCommandItem (commandManager, useLookAndFeelV2);
  89. menu.addCommandItem (commandManager, useLookAndFeelV3);
  90. menu.addSeparator();
  91. menu.addCommandItem (commandManager, useNativeTitleBar);
  92. #if JUCE_MAC
  93. menu.addCommandItem (commandManager, useNativeMenus);
  94. #endif
  95. #if ! JUCE_LINUX
  96. menu.addCommandItem (commandManager, goToKioskMode);
  97. #endif
  98. StringArray engines (getRenderingEngines());
  99. if (engines.size() > 1)
  100. {
  101. menu.addSeparator();
  102. int currentEngine = getPeer()->getCurrentRenderingEngine();
  103. #if JUCE_OPENGL
  104. if (openGLContext.isAttached())
  105. currentEngine = engines.size() - 1;
  106. #endif
  107. for (int i = 0; i < engines.size(); ++i)
  108. menu.addItem (5001 + i, "Use " + engines[i], true, i == currentEngine);
  109. }
  110. }
  111. return menu;
  112. }
  113. void menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/)
  114. {
  115. // most of our menu items are invoked automatically as commands, but we can handle the
  116. // other special cases here..
  117. if (menuItemID >= 5001 && menuItemID < 5010)
  118. {
  119. const int engineIndex = menuItemID - 5001;
  120. #if JUCE_OPENGL
  121. if (engineIndex >= getPeer()->getAvailableRenderingEngines().size())
  122. {
  123. setUsingOpenGLRenderer (true);
  124. return;
  125. }
  126. #endif
  127. setUsingOpenGLRenderer (false);
  128. getPeer()->setCurrentRenderingEngine (engineIndex);
  129. }
  130. }
  131. void setUsingOpenGLRenderer (bool shouldUseOpenGL)
  132. {
  133. #if JUCE_OPENGL
  134. if (shouldUseOpenGL && currentDemoId != showOpenGL)
  135. openGLContext.attachTo (*getTopLevelComponent());
  136. else
  137. openGLContext.detach();
  138. #endif
  139. }
  140. //==============================================================================
  141. // The following methods implement the ApplicationCommandTarget interface, allowing
  142. // this window to publish a set of actions it can perform, and which can be mapped
  143. // onto menus, keypresses, etc.
  144. ApplicationCommandTarget* getNextCommandTarget()
  145. {
  146. // this will return the next parent component that is an ApplicationCommandTarget (in this
  147. // case, there probably isn't one, but it's best to use this method in your own apps).
  148. return findFirstTargetParentComponent();
  149. }
  150. void getAllCommands (Array <CommandID>& commands)
  151. {
  152. // this returns the set of all commands that this target can perform..
  153. const CommandID ids[] = { showRendering,
  154. showFontsAndText,
  155. showWidgets,
  156. showThreading,
  157. showTreeView,
  158. showTable,
  159. showAudio,
  160. showDragAndDrop,
  161. showOpenGL,
  162. showQuicktime,
  163. showDirectShow,
  164. showCamera,
  165. showWebBrowser,
  166. showCodeEditor,
  167. showInterprocessComms,
  168. useLookAndFeelV1,
  169. useLookAndFeelV2,
  170. useLookAndFeelV3,
  171. useNativeTitleBar
  172. #if JUCE_MAC
  173. , useNativeMenus
  174. #endif
  175. #if ! JUCE_LINUX
  176. , goToKioskMode
  177. #endif
  178. };
  179. commands.addArray (ids, numElementsInArray (ids));
  180. }
  181. // This method is used when something needs to find out the details about one of the commands
  182. // that this object can perform..
  183. void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result)
  184. {
  185. const String generalCategory ("General");
  186. const String demosCategory ("Demos");
  187. switch (commandID)
  188. {
  189. case showRendering:
  190. result.setInfo ("Graphics Rendering", "Shows the graphics demo", demosCategory, 0);
  191. result.setTicked (currentDemoId == showRendering);
  192. result.addDefaultKeypress ('1', ModifierKeys::commandModifier);
  193. break;
  194. case showFontsAndText:
  195. result.setInfo ("Fonts and Text", "Shows the fonts & text demo", demosCategory, 0);
  196. result.setTicked (currentDemoId == showFontsAndText);
  197. result.addDefaultKeypress ('2', ModifierKeys::commandModifier);
  198. break;
  199. case showWidgets:
  200. result.setInfo ("Widgets", "Shows the widgets demo", demosCategory, 0);
  201. result.setTicked (currentDemoId == showWidgets);
  202. result.addDefaultKeypress ('3', ModifierKeys::commandModifier);
  203. break;
  204. case showThreading:
  205. result.setInfo ("Multithreading", "Shows the threading demo", demosCategory, 0);
  206. result.setTicked (currentDemoId == showThreading);
  207. result.addDefaultKeypress ('4', ModifierKeys::commandModifier);
  208. break;
  209. case showTreeView:
  210. result.setInfo ("Treeviews", "Shows the treeviews demo", demosCategory, 0);
  211. result.setTicked (currentDemoId == showTreeView);
  212. result.addDefaultKeypress ('5', ModifierKeys::commandModifier);
  213. break;
  214. case showTable:
  215. result.setInfo ("Table Components", "Shows the table component demo", demosCategory, 0);
  216. result.setTicked (currentDemoId == showTable);
  217. result.addDefaultKeypress ('6', ModifierKeys::commandModifier);
  218. break;
  219. case showAudio:
  220. result.setInfo ("Audio", "Shows the audio demo", demosCategory, 0);
  221. result.setTicked (currentDemoId == showAudio);
  222. result.addDefaultKeypress ('7', ModifierKeys::commandModifier);
  223. break;
  224. case showDragAndDrop:
  225. result.setInfo ("Drag-and-drop", "Shows the drag & drop demo", demosCategory, 0);
  226. result.setTicked (currentDemoId == showDragAndDrop);
  227. result.addDefaultKeypress ('8', ModifierKeys::commandModifier);
  228. break;
  229. case showOpenGL:
  230. result.setInfo ("OpenGL", "Shows the OpenGL demo", demosCategory, 0);
  231. result.addDefaultKeypress ('9', ModifierKeys::commandModifier);
  232. result.setTicked (currentDemoId == showOpenGL);
  233. #if ! JUCE_OPENGL
  234. result.setActive (false);
  235. #endif
  236. break;
  237. case showQuicktime:
  238. result.setInfo ("Quicktime", "Shows the Quicktime demo", demosCategory, 0);
  239. result.addDefaultKeypress ('b', ModifierKeys::commandModifier);
  240. result.setTicked (currentDemoId == showQuicktime);
  241. #if ! (JUCE_QUICKTIME && ! JUCE_LINUX)
  242. result.setActive (false);
  243. #endif
  244. break;
  245. case showDirectShow:
  246. result.setInfo ("DirectShow", "Shows the DirectShow demo", demosCategory, 0);
  247. result.addDefaultKeypress ('b', ModifierKeys::commandModifier);
  248. result.setTicked (currentDemoId == showDirectShow);
  249. #if ! JUCE_DIRECTSHOW
  250. result.setActive (false);
  251. #endif
  252. break;
  253. case showCamera:
  254. result.setInfo ("Camera Capture", "Shows the camera demo", demosCategory, 0);
  255. result.addDefaultKeypress ('c', ModifierKeys::commandModifier);
  256. result.setTicked (currentDemoId == showCamera);
  257. #if ! JUCE_USE_CAMERA
  258. result.setActive (false);
  259. #endif
  260. break;
  261. case showWebBrowser:
  262. result.setInfo ("Web Browser", "Shows the web browser demo", demosCategory, 0);
  263. result.addDefaultKeypress ('i', ModifierKeys::commandModifier);
  264. result.setTicked (currentDemoId == showWebBrowser);
  265. #if (! JUCE_WEB_BROWSER) || JUCE_LINUX
  266. result.setActive (false);
  267. #endif
  268. break;
  269. case showCodeEditor:
  270. result.setInfo ("Code Editor", "Shows the code editor demo", demosCategory, 0);
  271. result.addDefaultKeypress ('e', ModifierKeys::commandModifier);
  272. result.setTicked (currentDemoId == showCodeEditor);
  273. break;
  274. case showInterprocessComms:
  275. result.setInfo ("Interprocess Comms", "Shows the interprocess communications demo", demosCategory, 0);
  276. result.addDefaultKeypress ('0', ModifierKeys::commandModifier);
  277. result.setTicked (currentDemoId == showInterprocessComms);
  278. break;
  279. case useLookAndFeelV1:
  280. result.setInfo ("Use LookAndFeel_V1", String::empty, generalCategory, 0);
  281. result.setTicked (typeid (LookAndFeel_V1) == typeid (getLookAndFeel()));
  282. break;
  283. case useLookAndFeelV2:
  284. result.setInfo ("Use LookAndFeel_V2", String::empty, generalCategory, 0);
  285. result.setTicked (typeid (LookAndFeel_V2) == typeid (getLookAndFeel()));
  286. break;
  287. case useLookAndFeelV3:
  288. result.setInfo ("Use LookAndFeel_V3", String::empty, generalCategory, 0);
  289. result.setTicked (typeid (LookAndFeel_V3) == typeid (getLookAndFeel()));
  290. break;
  291. case useNativeTitleBar:
  292. result.setInfo ("Use native window title bar", String::empty, generalCategory, 0);
  293. result.setTicked (mainWindow.isUsingNativeTitleBar());
  294. break;
  295. #if JUCE_MAC
  296. case useNativeMenus:
  297. result.setInfo ("Use the native OSX menu bar", String::empty, generalCategory, 0);
  298. result.setTicked (MenuBarModel::getMacMainMenu() != 0);
  299. break;
  300. #endif
  301. #if ! JUCE_LINUX
  302. case goToKioskMode:
  303. result.setInfo ("Show full-screen kiosk mode", String::empty, generalCategory, 0);
  304. result.setTicked (Desktop::getInstance().getKioskModeComponent() != 0);
  305. break;
  306. #endif
  307. default:
  308. break;
  309. };
  310. }
  311. // this is the ApplicationCommandTarget method that is used to actually perform one of our commands..
  312. bool perform (const InvocationInfo& info)
  313. {
  314. switch (info.commandID)
  315. {
  316. case showRendering:
  317. showDemo (createRenderingDemo());
  318. currentDemoId = showRendering;
  319. break;
  320. case showFontsAndText:
  321. showDemo (createFontsAndTextDemo());
  322. currentDemoId = showFontsAndText;
  323. break;
  324. case showWidgets:
  325. showDemo (createWidgetsDemo());
  326. currentDemoId = showWidgets;
  327. break;
  328. case showThreading:
  329. showDemo (createThreadingDemo());
  330. currentDemoId = showThreading;
  331. break;
  332. case showTreeView:
  333. showDemo (createTreeViewDemo());
  334. currentDemoId = showTreeView;
  335. break;
  336. case showTable:
  337. showDemo (createTableDemo());
  338. currentDemoId = showTable;
  339. break;
  340. case showAudio:
  341. showDemo (createAudioDemo());
  342. currentDemoId = showAudio;
  343. break;
  344. case showDragAndDrop:
  345. showDemo (createDragAndDropDemo());
  346. currentDemoId = showDragAndDrop;
  347. break;
  348. case showOpenGL:
  349. #if JUCE_OPENGL
  350. setUsingOpenGLRenderer (false);
  351. showDemo (createOpenGLDemo());
  352. currentDemoId = showOpenGL;
  353. #endif
  354. break;
  355. case showQuicktime:
  356. #if JUCE_QUICKTIME && ! JUCE_LINUX
  357. setUsingOpenGLRenderer (false);
  358. showDemo (createQuickTimeDemo());
  359. currentDemoId = showQuicktime;
  360. #endif
  361. break;
  362. case showDirectShow:
  363. #if JUCE_DIRECTSHOW
  364. setUsingOpenGLRenderer (false);
  365. showDemo (createDirectShowDemo());
  366. currentDemoId = showDirectShow;
  367. #endif
  368. break;
  369. case showCamera:
  370. #if JUCE_USE_CAMERA
  371. setUsingOpenGLRenderer (false);
  372. showDemo (createCameraDemo());
  373. currentDemoId = showCamera;
  374. #endif
  375. break;
  376. case showWebBrowser:
  377. #if JUCE_WEB_BROWSER
  378. setUsingOpenGLRenderer (false);
  379. showDemo (createWebBrowserDemo());
  380. currentDemoId = showWebBrowser;
  381. #endif
  382. break;
  383. case showCodeEditor:
  384. showDemo (createCodeEditorDemo());
  385. currentDemoId = showCodeEditor;
  386. break;
  387. case showInterprocessComms:
  388. showDemo (createInterprocessCommsDemo());
  389. currentDemoId = showInterprocessComms;
  390. break;
  391. case useLookAndFeelV1: LookAndFeel::setDefaultLookAndFeel (&lookAndFeelV1); break;
  392. case useLookAndFeelV2: LookAndFeel::setDefaultLookAndFeel (&lookAndFeelV2); break;
  393. case useLookAndFeelV3: LookAndFeel::setDefaultLookAndFeel (&lookAndFeelV3); break;
  394. case useNativeTitleBar:
  395. mainWindow.setUsingNativeTitleBar (! mainWindow.isUsingNativeTitleBar());
  396. break;
  397. #if JUCE_MAC
  398. case useNativeMenus:
  399. if (MenuBarModel::getMacMainMenu() != 0)
  400. {
  401. MenuBarModel::setMacMainMenu (0);
  402. mainWindow.setMenuBar ((ContentComp*) mainWindow.getContentComponent());
  403. }
  404. else
  405. {
  406. MenuBarModel::setMacMainMenu ((ContentComp*) mainWindow.getContentComponent());
  407. mainWindow.setMenuBar (0);
  408. }
  409. break;
  410. #endif
  411. #if ! JUCE_LINUX
  412. case goToKioskMode:
  413. {
  414. Desktop& desktop = Desktop::getInstance();
  415. if (desktop.getKioskModeComponent() == nullptr)
  416. desktop.setKioskModeComponent (getTopLevelComponent());
  417. else
  418. desktop.setKioskModeComponent (nullptr);
  419. break;
  420. }
  421. #endif
  422. default:
  423. return false;
  424. };
  425. return true;
  426. }
  427. private:
  428. //==============================================================================
  429. MainDemoWindow& mainWindow;
  430. LookAndFeel_V1 lookAndFeelV1;
  431. LookAndFeel_V2 lookAndFeelV2;
  432. LookAndFeel_V3 lookAndFeelV3;
  433. ScopedPointer<Component> currentDemo;
  434. int currentDemoId;
  435. #if JUCE_OPENGL
  436. OpenGLContext openGLContext;
  437. #endif
  438. TooltipWindow tooltipWindow; // to add tooltips to an application, you
  439. // just need to create one of these and leave it
  440. // there to do its work..
  441. //==============================================================================
  442. StringArray getRenderingEngines()
  443. {
  444. StringArray renderingEngines (getPeer()->getAvailableRenderingEngines());
  445. #if JUCE_OPENGL
  446. renderingEngines.add ("Use OpenGL Renderer");
  447. #endif
  448. return renderingEngines;
  449. }
  450. //==============================================================================
  451. enum CommandIDs
  452. {
  453. showRendering = 0x2000,
  454. showFontsAndText = 0x2001,
  455. showWidgets = 0x2002,
  456. showThreading = 0x2003,
  457. showTreeView = 0x2004,
  458. showAudio = 0x2005,
  459. showDragAndDrop = 0x2006,
  460. showOpenGL = 0x2007,
  461. showQuicktime = 0x2008,
  462. showInterprocessComms = 0x2009,
  463. showTable = 0x2010,
  464. showCamera = 0x2011,
  465. showWebBrowser = 0x2012,
  466. showCodeEditor = 0x2013,
  467. showDirectShow = 0x2014,
  468. useLookAndFeelV1 = 0x2020,
  469. useLookAndFeelV2 = 0x2021,
  470. useLookAndFeelV3 = 0x2022,
  471. useNativeTitleBar = 0x2023,
  472. useNativeMenus = 0x2024,
  473. goToKioskMode = 0x2025
  474. };
  475. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentComp)
  476. };
  477. //==============================================================================
  478. #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC
  479. // Just add a simple icon to the Window system tray area..
  480. class DemoTaskbarComponent : public SystemTrayIconComponent,
  481. private Timer
  482. {
  483. public:
  484. DemoTaskbarComponent()
  485. {
  486. setIconImage (createImageForIcon());
  487. setIconTooltip ("Juce Demo App!");
  488. }
  489. Image createImageForIcon()
  490. {
  491. Image icon (Image::RGB, 32, 32, true);
  492. Graphics g (icon);
  493. // This draws an icon which is just a square with a "j" in it..
  494. g.fillAll (Colours::lightblue);
  495. g.setColour (Colours::black);
  496. g.setFont (Font ((float) icon.getHeight(), Font::bold));
  497. g.drawText ("j", 0, 0, icon.getWidth(), icon.getHeight(), Justification::centred, false);
  498. return icon;
  499. }
  500. void mouseDown (const MouseEvent&) override
  501. {
  502. // On OSX, there can be problems launching a menu when we're not the foreground
  503. // process, so just in case, we'll first make our process active, and then use a
  504. // timer to wait a moment before opening our menu, which gives the OS some time to
  505. // get its act together and bring our windows to the front.
  506. Process::makeForegroundProcess();
  507. startTimer (50);
  508. }
  509. void timerCallback() override
  510. {
  511. stopTimer();
  512. PopupMenu m;
  513. m.addItem (1, "Quit the Juce demo");
  514. // It's always better to open menus asynchronously when possible.
  515. m.showMenuAsync (PopupMenu::Options(),
  516. ModalCallbackFunction::forComponent (menuInvocationCallback, this));
  517. }
  518. // This is invoked when the menu is clicked or dismissed
  519. static void menuInvocationCallback (int chosenItemID, DemoTaskbarComponent*)
  520. {
  521. if (chosenItemID == 1)
  522. JUCEApplication::getInstance()->systemRequestedQuit();
  523. }
  524. };
  525. #endif
  526. //==============================================================================
  527. MainDemoWindow::MainDemoWindow()
  528. : DocumentWindow ("JUCE Demo!",
  529. Colours::azure,
  530. DocumentWindow::allButtons,
  531. true)
  532. {
  533. setResizable (true, false); // resizability is a property of ResizableWindow
  534. setResizeLimits (400, 300, 8192, 8192);
  535. ContentComp* contentComp = new ContentComp (*this);
  536. commandManager.registerAllCommandsForTarget (contentComp);
  537. commandManager.registerAllCommandsForTarget (JUCEApplication::getInstance());
  538. // this lets the command manager use keypresses that arrive in our window to send
  539. // out commands
  540. addKeyListener (commandManager.getKeyMappings());
  541. // sets the main content component for the window to be this tabbed
  542. // panel. This will be deleted when the window is deleted.
  543. setContentOwned (contentComp, false);
  544. // this tells the DocumentWindow to automatically create and manage a MenuBarComponent
  545. // which uses our contentComp as its MenuBarModel
  546. setMenuBar (contentComp);
  547. // tells our menu bar model that it should watch this command manager for
  548. // changes, and send change messages accordingly.
  549. contentComp->setApplicationCommandManagerToWatch (&commandManager);
  550. setVisible (true);
  551. #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC
  552. taskbarIcon = new DemoTaskbarComponent();
  553. #endif
  554. }
  555. MainDemoWindow::~MainDemoWindow()
  556. {
  557. // because we've set the content comp to be used as our menu bar model, we
  558. // have to switch this off before deleting the content comp..
  559. setMenuBar (nullptr);
  560. #if JUCE_MAC // ..and also the main bar if we're using that on a Mac...
  561. MenuBarModel::setMacMainMenu (nullptr);
  562. #endif
  563. // clearing the content component will delete the current one, and
  564. // that will in turn delete all its child components. You don't always
  565. // have to do this explicitly, because the base class's destructor will
  566. // also delete the content component, but in this case we need to
  567. // make sure our content comp has gone away before deleting our command
  568. // manager.
  569. clearContentComponent();
  570. }
  571. void MainDemoWindow::closeButtonPressed()
  572. {
  573. // The correct thing to do when you want the app to quit is to call the
  574. // JUCEApplication::systemRequestedQuit() method.
  575. // That means that requests to quit that come from your own UI, or from other
  576. // OS-specific sources (e.g. the dock menu on the mac) all get handled in the
  577. // same way.
  578. JUCEApplication::getInstance()->systemRequestedQuit();
  579. }