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.

545 lines
17KB

  1. #ifndef __MAINCOMPONENT_H_615ECE56__
  2. #define __MAINCOMPONENT_H_615ECE56__
  3. /*
  4. Copyright (C) 2012 Rory Walsh
  5. Cabbage is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. Cabbage 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 Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with Csound; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  16. 02111-1307 USA
  17. */
  18. #include "CodeEditor.h"
  19. #include "KeyboardShortcuts.h"
  20. #include "../Plugin/CabbagePluginProcessor.h"
  21. //class LiveCsound;
  22. class PythonEditor;
  23. class PopupDisplay;
  24. //==============================================================================
  25. //Main window. This window holds a 2 textEditors. One for the code, and the other for
  26. //displaying Csound output messages
  27. //==============================================================================
  28. class CodeWindow : public DocumentWindow,
  29. public ApplicationCommandTarget,
  30. public MenuBarModel,
  31. public ActionListener,
  32. public ActionBroadcaster,
  33. public CodeDocument::Listener,
  34. public Timer
  35. {
  36. public:
  37. CodeWindow(String name);
  38. ~CodeWindow();
  39. CodeDocument csoundDoc;
  40. //==============================================================================
  41. StringArray getMenuBarNames()
  42. {
  43. const char* const names[] = { "File", "Edit", "Help", 0 };
  44. return StringArray (names);
  45. }
  46. //==============================================================================
  47. void getAllCommands (Array <CommandID>& commands)
  48. {
  49. const CommandID ids[] = {
  50. CommandIDs::fileNew,
  51. CommandIDs::fileOpen,
  52. CommandIDs::fileSave,
  53. CommandIDs::fileSaveAs,
  54. CommandIDs::fileQuit,
  55. CommandIDs::fileKeyboardShorts,
  56. CommandIDs::editUndo,
  57. CommandIDs::editCopy,
  58. CommandIDs::editCut,
  59. CommandIDs::editPaste,
  60. CommandIDs::editRedo,
  61. CommandIDs::editToggleComments,
  62. CommandIDs::editZoomIn,
  63. CommandIDs::editZoomOut,
  64. CommandIDs::whiteBackground,
  65. CommandIDs::blackBackground,
  66. CommandIDs::startSession,
  67. CommandIDs::insertFromRepo,
  68. CommandIDs::AudioSettings,
  69. CommandIDs::addFromRepo,
  70. CommandIDs::insertRecentEvent,
  71. CommandIDs::openPythonEditor,
  72. CommandIDs::commOrchUpdateInstrument,
  73. CommandIDs::commOrchUpdateMultiLine,
  74. CommandIDs::commOrchUpdateSingleLine,
  75. CommandIDs::commScoUpdateMultiLine,
  76. CommandIDs::commScoUpdateSingleLine,
  77. CommandIDs::commOrcUpdateChannel,
  78. CommandIDs::viewCsoundHelp,
  79. CommandIDs::viewCabbageHelp
  80. };
  81. commands.addArray (ids, sizeof (ids) / sizeof (ids [0]));
  82. }
  83. //==============================================================================
  84. void menuItemSelected (int menuItemID, int topLevelMenuIndex){
  85. if (menuItemID >= 100 && menuItemID < 200)
  86. {
  87. RecentlyOpenedFilesList recentFiles;
  88. recentFiles.restoreFromString (appProperties->getUserSettings()
  89. ->getValue ("recentlyOpenedFiles"));
  90. csdFile = recentFiles.getFile (menuItemID - 100);
  91. textEditor->getDocument().replaceAllContent(csdFile.loadFileAsString());
  92. setName(csdFile.getFullPathName());
  93. }
  94. }
  95. //==============================================================================
  96. void setFontSize(String zoom)
  97. {
  98. if(zoom==String("in"))
  99. textEditor->setFont(Font(String("Courier New"), ++fontSize, 1));
  100. else
  101. textEditor->setFont(Font(String("Courier New"), --fontSize, 1));
  102. }
  103. //================= command methods ====================
  104. ApplicationCommandTarget* getNextCommandTarget(){
  105. return findFirstTargetParentComponent();
  106. }
  107. void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result);
  108. PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName);
  109. bool perform (const InvocationInfo& info);
  110. void toggleManuals(String manual);
  111. void setEditorColourScheme(String theme);
  112. void actionListenerCallback(const String &message);
  113. void timerCallback();
  114. void toggleTextWindows();
  115. Rectangle<int> getCaretScreenPosition(){
  116. Rectangle<int> rect(textEditor->getCaretPoisition());
  117. rect.setLeft(rect.getX()+this->getTopLevelComponent()->getX()+100);
  118. rect.setTop(rect.getY()+this->getTopLevelComponent()->getY()+45);
  119. return rect;
  120. }
  121. void closeButtonPressed(){
  122. //JUCEApplication::getInstance()->systemRequestedQuit();
  123. this->setVisible(false);
  124. }
  125. void codeDocumentTextDeleted(int,int){}
  126. void codeDocumentTextInserted(const juce::String &,int){}
  127. void codeDocumentChanged (const CodeDocument::Position &affectedTextStart, const CodeDocument::Position &affectedTextEnd);
  128. void insertFromRepo();
  129. void setText(String file){
  130. csoundDoc.replaceAllContent(file);
  131. }
  132. String getText(){
  133. return csoundDoc.getAllContent();
  134. }
  135. void setColourScheme(String theme){
  136. if(theme=="white"){
  137. textEditor->setColourScheme(csoundToker.getDefaultColourScheme());
  138. textEditor->setColour(CodeEditorComponent::backgroundColourId, Colours::white);
  139. textEditor->setColour(CaretComponent::caretColourId, Colours::black);
  140. textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::cornflowerblue);
  141. appProperties->getUserSettings()->setValue("EditorColourScheme", 0);
  142. }
  143. else if(theme=="dark"){
  144. textEditor->setColourScheme(csoundToker.getDarkColourScheme());
  145. textEditor->setColour(CaretComponent::caretColourId, Colours::white);
  146. textEditor->setColour(CodeEditorComponent::backgroundColourId, Colour::fromRGB(20, 20, 20));
  147. textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::green.withAlpha(.6f));
  148. appProperties->getUserSettings()->setValue("EditorColourScheme", 1);
  149. }
  150. }
  151. void newFile(String type);
  152. bool unSaved;
  153. StringArray recentEvents;
  154. //ScopedPointer<CabbageLookAndFeel> lookAndFeel;
  155. String csoundOutputText;
  156. bool firstTime;
  157. String debugMessage;
  158. bool showOutput;
  159. CommandManager commandManager;
  160. File csdFile;
  161. int fontSize;
  162. String ASCIICabbage;
  163. StringArray opcodeStrings;
  164. ScopedPointer<PopupDisplay> popupDisplay;
  165. CsoundCodeEditor* textEditor;
  166. CsoundTokeniser csoundToker;
  167. Font font;
  168. ScopedPointer<WebBrowserComponent> htmlHelp;
  169. bool showingHelp;
  170. };
  171. //============================================================
  172. // window for Python editor
  173. //============================================================
  174. class PythonEditor: public DocumentWindow,
  175. public ActionListener,
  176. public ActionBroadcaster
  177. {
  178. public:
  179. PythonEditor(String name):DocumentWindow (name, Colours::black,
  180. DocumentWindow::closeButton)
  181. {
  182. textEditor = new CsoundCodeEditor("python", csoundDocu, &csoundToker);
  183. textEditor->setColour(TextEditor::textColourId, Colours::white);
  184. textEditor->setFont(Font(String("Courier New"), 15, 1));
  185. textEditor->addActionListener(this);
  186. textEditor->setSize(600, 400);
  187. if(!appProperties->getUserSettings()->getValue("EditorColourScheme", var(0)).getIntValue())
  188. setEditorColourScheme("white");
  189. else if(appProperties->getUserSettings()->getValue("EditorColourScheme", var(0)).getIntValue())
  190. setEditorColourScheme("dark");
  191. centreWithSize(600, 400);
  192. setContentNonOwned(textEditor, true);
  193. setResizable(true, false);
  194. }
  195. ~PythonEditor()
  196. {
  197. delete textEditor;
  198. }
  199. void codeDocumentChanged (const CodeDocument::Position &affectedTextStart, const CodeDocument::Position &affectedTextEnd)
  200. {
  201. }
  202. void actionListenerCallback(const String &message)
  203. {
  204. if(message=="make invisible"){
  205. //this->setVisible(false);
  206. sendActionMessage("sendPythonEvent");
  207. //if(textEditor->getm)
  208. }
  209. }
  210. void closeButtonPressed(){
  211. setVisible(false);
  212. }
  213. void setEditorColourScheme(String theme){
  214. if(theme=="white"){
  215. textEditor->setColourScheme(csoundToker.getDefaultColourScheme());
  216. textEditor->setColour(CodeEditorComponent::backgroundColourId, Colours::white);
  217. textEditor->setColour(CaretComponent::caretColourId, Colours::black);
  218. textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::cornflowerblue);
  219. appProperties->getUserSettings()->setValue("EditorColourScheme", 0);
  220. }
  221. else if(theme=="dark"){
  222. textEditor->setColourScheme(csoundToker.getDarkColourScheme());
  223. textEditor->setColour(CaretComponent::caretColourId, Colours::white);
  224. textEditor->setColour(CodeEditorComponent::backgroundColourId, Colour::fromRGB(20, 20, 20));
  225. textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::green.withAlpha(.6f));
  226. appProperties->getUserSettings()->setValue("EditorColourScheme", 1);
  227. }
  228. }
  229. void codeDocumentTextDeleted(int,int){}
  230. void codeDocumentTextInserted(const juce::String &,int){}
  231. CsoundCodeEditor* textEditor;
  232. CodeDocument csoundDocu;
  233. PythonTokeniser csoundToker;
  234. };
  235. //============================================================
  236. // audio settings class (not currently used...)
  237. //============================================================
  238. class AudioSettings: public Component,
  239. public ActionListener,
  240. public ActionBroadcaster
  241. {
  242. public:
  243. AudioSettings(StringArray deviceStrings)
  244. {
  245. addAndMakeVisible (label = new Label ("new label",
  246. "Sampling Rate"));
  247. label->setFont (Font (15.00f, Font::bold));
  248. label->setJustificationType (Justification::centredLeft);
  249. label->setEditable (false, false, false);
  250. label->setColour (TextEditor::textColourId, Colours::lime);
  251. label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
  252. addAndMakeVisible (samplingRate = new ComboBox ("new combo box"));
  253. samplingRate->addItem("44100", 1);
  254. samplingRate->addItem("48000", 2);
  255. samplingRate->setSelectedId(1, dontSendNotification );
  256. samplingRate->setEditableText (false);
  257. samplingRate->setJustificationType (Justification::centredLeft);
  258. samplingRate->setTextWhenNothingSelected (String::empty);
  259. samplingRate->setTextWhenNoChoicesAvailable ("(no choices)");
  260. //samplingRate->addListener (this);
  261. addAndMakeVisible (label2 = new Label ("new label",
  262. "Ksmps"));
  263. label2->setFont (Font (20.00f, Font::bold));
  264. label2->setJustificationType (Justification::centredLeft);
  265. label2->setEditable (false, false, false);
  266. label2->setColour (TextEditor::textColourId, Colours::lime);
  267. label2->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
  268. addAndMakeVisible (ksmps = new ComboBox ("new combo box"));
  269. ksmps->addItem("32", 1);
  270. ksmps->addItem("64", 2);
  271. ksmps->addItem("128", 3);
  272. ksmps->addItem("512", 4);
  273. ksmps->addItem("1024", 5);
  274. ksmps->addItem("2048", 6);
  275. ksmps->addItem("4096", 7);
  276. ksmps->setSelectedId(2, dontSendNotification );
  277. ksmps->setEditableText (false);
  278. ksmps->setJustificationType (Justification::centredLeft);
  279. ksmps->setTextWhenNothingSelected (String::empty);
  280. ksmps->setTextWhenNoChoicesAvailable ("(no choices)");
  281. // ksmps->addListener (this);
  282. addAndMakeVisible (label3 = new Label ("new label",
  283. "Audio Device"));
  284. label3->setFont (Font (15.00f, Font::bold));
  285. label3->setJustificationType (Justification::centredLeft);
  286. label3->setEditable (false, false, false);
  287. label3->setColour (TextEditor::textColourId, Colours::lime);
  288. label3->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
  289. addAndMakeVisible (audioDevice = new ComboBox ("new combo box"));
  290. audioDevice->setEditableText (false);
  291. for(int i=0;i<deviceStrings.size();i++)
  292. audioDevice->addItem(deviceStrings[i], i+1);
  293. audioDevice->setSelectedId(deviceStrings.size(), dontSendNotification );
  294. audioDevice->setJustificationType (Justification::centredLeft);
  295. audioDevice->setTextWhenNothingSelected (String::empty);
  296. audioDevice->setTextWhenNoChoicesAvailable ("(no choices)");
  297. //audioDevice->addListener (this);
  298. addAndMakeVisible (label4 = new Label ("new label",
  299. "MIDI Device"));
  300. label4->setFont (Font (15.00f, Font::bold));
  301. label4->setJustificationType (Justification::centredLeft);
  302. label4->setEditable (false, false, false);
  303. label4->setColour (TextEditor::textColourId, Colours::lime);
  304. label4->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
  305. addAndMakeVisible (midiDevice = new ComboBox ("new combo box"));
  306. midiDevice->setEditableText (false);
  307. midiDevice->setJustificationType (Justification::centredLeft);
  308. midiDevice->setTextWhenNothingSelected (String::empty);
  309. midiDevice->setTextWhenNoChoicesAvailable ("(no choices)");
  310. //midiDevice->addListener (this);
  311. setSize(300, 200);
  312. }
  313. void actionListenerCallback(const String &message)
  314. {
  315. if(message=="make invisible"){
  316. //this->setVisible(false);
  317. sendActionMessage("sendPythonEvent");
  318. }
  319. }
  320. void resized(){
  321. label->setBounds (28, 16, 96, 24);
  322. samplingRate->setBounds (130, 16, 118, 24);
  323. label2->setBounds (58, 52, 80, 24);
  324. ksmps->setBounds (130, 52, 117, 24);
  325. label3->setBounds (41, 87, 80, 24);
  326. audioDevice->setBounds (130, 88, 117, 24);
  327. label4->setBounds (42, 122, 80, 24);
  328. midiDevice->setBounds (130, 121, 118, 24);
  329. }
  330. void paint(Graphics& g){
  331. g.fillAll(Colours::black);
  332. }
  333. ~AudioSettings(){
  334. label = nullptr;
  335. samplingRate = nullptr;
  336. label2 = nullptr;
  337. ksmps = nullptr;
  338. label3 = nullptr;
  339. audioDevice = nullptr;
  340. label4 = nullptr;
  341. midiDevice = nullptr;
  342. }
  343. private:
  344. ScopedPointer<Label> label;
  345. ScopedPointer<ComboBox> samplingRate;
  346. ScopedPointer<Label> label2;
  347. ScopedPointer<ComboBox> ksmps;
  348. ScopedPointer<Label> label3;
  349. ScopedPointer<ComboBox> audioDevice;
  350. ScopedPointer<Label> label4;
  351. ScopedPointer<ComboBox> midiDevice;
  352. };
  353. //============================================================
  354. // class for displaying popup text
  355. //============================================================
  356. class PopupDisplay : public DialogWindow,
  357. public Timer,
  358. public ActionBroadcaster
  359. {
  360. class Box : public Component
  361. {
  362. public:
  363. Box():firstTime(true)
  364. {
  365. this->setInterceptsMouseClicks(false, false);
  366. setSize(10, 50);
  367. }
  368. ~Box(){};
  369. void setText(String _info, String _syntax){
  370. syntax=_syntax;
  371. info=_info;
  372. repaint();
  373. }
  374. void paint(Graphics& g)
  375. {
  376. #ifdef LINUX
  377. g.fillAll(Colour::fromRGB(40,40,40));
  378. g.setColour(Colours::yellow);
  379. g.drawRect(0, 0, getWidth()-1, getHeight()-1, 1);
  380. g.setFont(Font(String("Arial"), 16, 0));
  381. g.setColour(Colours::whitesmoke);
  382. g.drawFittedText(syntax, 10, 10, getWidth(), getHeight(), Justification::topLeft, 100, 1);
  383. g.setFont(Font(String("Arial"), 15, 0));
  384. g.setColour(Colours::cornflowerblue);
  385. g.drawFittedText(info, 10, 25, getWidth(), getHeight(), Justification::topLeft, 100, 1);
  386. #else
  387. g.fillAll(Colour::fromRGB(20, 20, 20));
  388. g.setColour(Colours::whitesmoke);
  389. g.drawRect(0, 0, getWidth()-1, getHeight()-1, 1);
  390. g.setFont(Font(String("Arial"), 16, 0));
  391. g.setColour(Colours::yellow);
  392. g.drawFittedText(syntax, 10, 10, getWidth(), getHeight(), Justification::topLeft, 100, 1);
  393. g.setFont(Font(String("Arial"), 15, 0));
  394. g.setColour(Colours::lime);
  395. g.drawFittedText(info, 10, 25, getWidth(), getHeight(), Justification::topLeft, 100, 1);
  396. #endif
  397. }
  398. void resized(){
  399. setSize(getWidth(), getHeight());
  400. }
  401. bool firstTime;
  402. private:
  403. String syntax, info;
  404. };
  405. public:
  406. PopupDisplay(String name): DialogWindow(name, Colours::black, true, true),
  407. time(0), seconds(0)
  408. {
  409. box = new Box();
  410. this->setContentNonOwned(box, true);
  411. #ifndef LINUX
  412. this->setAlpha(.9f);
  413. #endif
  414. }
  415. ~PopupDisplay(){}
  416. void resized(){
  417. setSize(getWidth(), 50);
  418. // box->repaint();
  419. }
  420. void setText(String opcodeName, String opcodeDescrptor){
  421. box->setText(opcodeName, opcodeDescrptor);
  422. }
  423. int getDesktopWindowStyleFlags() const{
  424. int styleFlags = ComponentPeer::windowAppearsOnTaskbar;
  425. //if (useDropShadow) styleFlags |= ComponentPeer::windowHasDropShadow;
  426. //if (useNativeTitleBar) styleFlags |= ComponentPeer::windowHasTitleBar;
  427. return 0;
  428. }
  429. void timerCallback(){
  430. if(time<seconds){
  431. time++;
  432. stopTimer();
  433. setVisible(true);
  434. sendActionMessage("");
  435. }
  436. }
  437. void killSplash(){
  438. box->firstTime=false;
  439. box->repaint();
  440. }
  441. bool triggerToAppear(int _seconds)
  442. {
  443. time=0;
  444. seconds = _seconds;
  445. startTimer(1000);
  446. }
  447. void closeButtonPressed(){
  448. setVisible(false);
  449. }
  450. ScopedPointer<Box> box;
  451. int time;
  452. int seconds;
  453. };
  454. #endif // __MAINCOMPONENT_H_615ECE56__