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.

264 lines
8.1KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE examples.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. The code included in this file is provided under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  7. To use, copy, modify, and/or distribute this software for any purpose with or
  8. without fee is hereby granted provided that the above copyright notice and
  9. this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
  11. WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
  12. PURPOSE, ARE DISCLAIMED.
  13. ==============================================================================
  14. */
  15. /*******************************************************************************
  16. The block below describes the properties of this PIP. A PIP is a short snippet
  17. of code that can be read by the Projucer and used to generate a JUCE project.
  18. BEGIN_JUCE_PIP_METADATA
  19. name: MDIDemo
  20. version: 1.0.0
  21. vendor: JUCE
  22. website: http://juce.com
  23. description: Displays and edits MDI files.
  24. dependencies: juce_core, juce_data_structures, juce_events, juce_graphics,
  25. juce_gui_basics, juce_gui_extra
  26. exporters: xcode_mac, vs2017, linux_make, androidstudio, xcode_iphone
  27. type: Component
  28. mainClass: MDIDemo
  29. useLocalCopy: 1
  30. END_JUCE_PIP_METADATA
  31. *******************************************************************************/
  32. #pragma once
  33. #include "../Assets/DemoUtilities.h"
  34. //==============================================================================
  35. /** The Note class contains text editor used to display and edit the note's contents and will
  36. also listen to changes in the text and mark the FileBasedDocument as 'dirty'. This 'dirty'
  37. flag is used to promt the user to save the note when it is closed.
  38. */
  39. class Note : public Component,
  40. public FileBasedDocument
  41. {
  42. public:
  43. Note (const String& name, const String& contents)
  44. : FileBasedDocument (".jnote", "*.jnote",
  45. "Browse for note to load",
  46. "Choose file to save note to"),
  47. textValueObject (contents)
  48. {
  49. // we need to use an separate Value object as our text source so it doesn't get marked
  50. // as changed immediately
  51. setName (name);
  52. editor.setMultiLine (true);
  53. editor.setReturnKeyStartsNewLine (true);
  54. editor.getTextValue().referTo (textValueObject);
  55. addAndMakeVisible (editor);
  56. editor.onTextChange = [this] { changed(); };
  57. }
  58. void resized() override
  59. {
  60. editor.setBounds (getLocalBounds());
  61. }
  62. String getDocumentTitle() override
  63. {
  64. return getName();
  65. }
  66. Result loadDocument (const File& file) override
  67. {
  68. editor.setText (file.loadFileAsString());
  69. return Result::ok();
  70. }
  71. Result saveDocument (const File& file) override
  72. {
  73. // attempt to save the contents into the given file
  74. FileOutputStream os (file);
  75. if (os.openedOk())
  76. os.writeText (editor.getText(), false, false);
  77. return Result::ok();
  78. }
  79. File getLastDocumentOpened() override
  80. {
  81. // not interested in this for now
  82. return {};
  83. }
  84. void setLastDocumentOpened (const File& /*file*/) override
  85. {
  86. // not interested in this for now
  87. }
  88. #if JUCE_MODAL_LOOPS_PERMITTED
  89. File getSuggestedSaveAsFile (const File&) override
  90. {
  91. return File::getSpecialLocation (File::userDesktopDirectory).getChildFile (getName()).withFileExtension ("jnote");
  92. }
  93. #endif
  94. private:
  95. Value textValueObject;
  96. TextEditor editor;
  97. void lookAndFeelChanged() override
  98. {
  99. editor.applyFontToAllText (editor.getFont());
  100. }
  101. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Note)
  102. };
  103. //==============================================================================
  104. /** Simple MultiDocumentPanel that just tries to save our notes when they are closed.
  105. */
  106. class DemoMultiDocumentPanel : public MultiDocumentPanel
  107. {
  108. public:
  109. DemoMultiDocumentPanel() {}
  110. ~DemoMultiDocumentPanel()
  111. {
  112. closeAllDocuments (true);
  113. }
  114. bool tryToCloseDocument (Component* component) override
  115. {
  116. #if JUCE_MODAL_LOOPS_PERMITTED
  117. if (auto* note = dynamic_cast<Note*> (component))
  118. return note->saveIfNeededAndUserAgrees() != FileBasedDocument::failedToWriteToFile;
  119. #else
  120. ignoreUnused (component);
  121. #endif
  122. return true;
  123. }
  124. private:
  125. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DemoMultiDocumentPanel)
  126. };
  127. //==============================================================================
  128. /** Simple multi-document panel that manages a number of notes that you can store to files.
  129. By default this will look for notes saved to the desktop and load them up.
  130. */
  131. class MDIDemo : public Component,
  132. public FileDragAndDropTarget
  133. {
  134. public:
  135. MDIDemo()
  136. {
  137. setOpaque (true);
  138. showInTabsButton.setToggleState (false, dontSendNotification);
  139. showInTabsButton.onClick = [this] { updateLayoutMode(); };
  140. addAndMakeVisible (showInTabsButton);
  141. addNoteButton.onClick = [this] { addNote ("Note " + String (multiDocumentPanel.getNumDocuments() + 1), "Hello World!"); };
  142. addAndMakeVisible (addNoteButton);
  143. addAndMakeVisible (multiDocumentPanel);
  144. multiDocumentPanel.setBackgroundColour (Colours::transparentBlack);
  145. updateLayoutMode();
  146. addNote ("Notes Demo", "You can drag-and-drop text files onto this page to open them as notes..");
  147. addExistingNotes();
  148. setSize (500, 500);
  149. }
  150. void paint (Graphics& g) override
  151. {
  152. g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground));
  153. }
  154. void resized() override
  155. {
  156. auto area = getLocalBounds();
  157. auto buttonArea = area.removeFromTop (28).reduced (2);
  158. addNoteButton .setBounds (buttonArea.removeFromRight (150));
  159. showInTabsButton.setBounds (buttonArea);
  160. multiDocumentPanel.setBounds (area);
  161. }
  162. bool isInterestedInFileDrag (const StringArray&) override
  163. {
  164. return true;
  165. }
  166. void filesDropped (const StringArray& filenames, int /*x*/, int /*y*/) override
  167. {
  168. Array<File> files;
  169. for (auto& f : filenames)
  170. files.add ({ f });
  171. createNotesForFiles (files);
  172. }
  173. void createNotesForFiles (const Array<File>& files)
  174. {
  175. for (auto& file : files)
  176. {
  177. auto content = file.loadFileAsString();
  178. if (content.length() > 20000)
  179. content = "Too long!";
  180. addNote (file.getFileName(), content);
  181. }
  182. }
  183. private:
  184. ToggleButton showInTabsButton { "Show with tabs" };
  185. TextButton addNoteButton { "Create a new note" };
  186. DemoMultiDocumentPanel multiDocumentPanel;
  187. void updateLayoutMode()
  188. {
  189. multiDocumentPanel.setLayoutMode (showInTabsButton.getToggleState() ? MultiDocumentPanel::MaximisedWindowsWithTabs
  190. : MultiDocumentPanel::FloatingWindows);
  191. }
  192. void addNote (const String& name, const String& content)
  193. {
  194. auto* newNote = new Note (name, content);
  195. newNote->setSize (200, 200);
  196. multiDocumentPanel.addDocument (newNote, Colours::lightblue.withAlpha (0.6f), true);
  197. }
  198. void addExistingNotes()
  199. {
  200. Array<File> files;
  201. File::getSpecialLocation (File::userDesktopDirectory).findChildFiles (files, File::findFiles, false, "*.jnote");
  202. createNotesForFiles (files);
  203. }
  204. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MDIDemo)
  205. };