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.

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