Extra "ports" of juce-based plugins using the distrho build system
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.

2256 lines
73KB

  1. /*
  2. Copyright (C) 2010 Rory Walsh, Damien Rennick
  3. Cabbage is free software; you can redistribute it
  4. and/or modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. Cabbage is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with Csound; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  14. 02111-1307 USA
  15. */
  16. #ifndef _CabbageWidgets_H__
  17. #define _CabbageWidgets_H__
  18. #include "JuceHeader.h"
  19. #include "CabbageLookAndFeel.h"
  20. #include "CabbageUtils.h"
  21. #include "CabbageTable.h"
  22. #include "XYPad.h"
  23. #include "Soundfiler.h"
  24. #include "DirectoryContentsComponent.h"
  25. class InfoWindow : public DocumentWindow
  26. {
  27. ScopedPointer<WebBrowserComponent> htmlInfo;
  28. public:
  29. //==============================================================================
  30. InfoWindow(LookAndFeel* look, String file) : DocumentWindow (String("Information"),
  31. Colours::black,
  32. DocumentWindow::allButtons)
  33. {
  34. setSize(600, 400);
  35. this->setTitleBarHeight(20);
  36. htmlInfo = new WebBrowserComponent(false);
  37. htmlInfo->setBounds(0, 0, 600, 400);
  38. setContentOwned(htmlInfo, true);
  39. htmlInfo->goToURL(file);
  40. }
  41. ~InfoWindow(){};
  42. void closeButtonPressed(){
  43. setVisible(false);
  44. };
  45. };
  46. //==============================================================================
  47. // custom button component with optional surrounding groupbox
  48. //==============================================================================
  49. class CabbageButton : public Component
  50. {
  51. int offX, offY, offWidth, offHeight;
  52. String buttonType;
  53. public:
  54. ScopedPointer<GroupComponent> groupbox;
  55. ScopedPointer<Button> button;
  56. //---- constructor -----
  57. CabbageButton(String name, String caption, String buttonText, String colour, String fontcolour)
  58. {
  59. setName(name);
  60. offX=offY=offWidth=offHeight=0;
  61. groupbox = new GroupComponent(String("groupbox_")+name);
  62. button = new TextButton(name);
  63. addAndMakeVisible(groupbox);
  64. addAndMakeVisible(button);
  65. groupbox->setVisible(false);
  66. groupbox->getProperties().set("groupLine", var(1));
  67. Logger::writeToLog(buttonText);
  68. button->setButtonText(buttonText);
  69. if(caption.length()>0){
  70. offX=10;
  71. offY=35;
  72. offWidth=-20;
  73. offHeight=-45;
  74. groupbox->setVisible(true);
  75. groupbox->setText(caption);
  76. }
  77. if(fontcolour.length()>0)
  78. button->getProperties().set("fontcolour", fontcolour);
  79. if(colour.length()>0)
  80. button->getProperties().set("colour", colour);
  81. }
  82. //---------------------------------------------
  83. ~CabbageButton(){
  84. }
  85. //---------------------------------------------
  86. void resized()
  87. {
  88. groupbox->setBounds(0, 0, getWidth(), getHeight());
  89. button->setBounds(offX, offY, getWidth()+offWidth, getHeight()+offHeight);
  90. this->setWantsKeyboardFocus(false);
  91. }
  92. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageButton);
  93. };
  94. //==============================================================================
  95. // custom slider component with optional surrounding groupbox
  96. //==============================================================================
  97. class CabbageSlider : public Component,
  98. public ChangeBroadcaster
  99. {
  100. int offX, offY, offWidth, offHeight, plantX, plantY;
  101. String sliderType, compName, cl;
  102. int resizeCount;
  103. String tracker;
  104. //subclass slider here to expose mouse listener method
  105. class cSlider : public Slider
  106. {
  107. public:
  108. cSlider(String text, CabbageSlider* _slider):Slider(text),
  109. slider(_slider){}
  110. ~cSlider(){};
  111. private:
  112. void mouseMove(const MouseEvent& event){
  113. slider->sendChangeMessage();
  114. }
  115. CabbageSlider* slider;
  116. };
  117. public:
  118. ScopedPointer<GroupComponent> groupbox;
  119. ScopedPointer<Slider> slider;
  120. //---- constructor -----
  121. CabbageSlider(String name, String text, String caption, String kind, String colour, String fontColour, int textBox, String trackerFill, int decPlaces)
  122. : plantX(-99), plantY(-99), sliderType(kind), compName(caption), cl(colour), tracker(trackerFill)
  123. {
  124. setName(name);
  125. offX=offY=offWidth=offHeight=0;
  126. groupbox = new GroupComponent(String("groupbox_")+name);
  127. slider = new Slider(text);
  128. slider->toFront(true);
  129. addAndMakeVisible(slider);
  130. addAndMakeVisible(groupbox);
  131. groupbox->setVisible(false);
  132. groupbox->getProperties().set("groupLine", var(1));
  133. if(tracker.length()>0)
  134. slider->getProperties().set("tracker", tracker);
  135. slider->getProperties().set("decimalPlaces", decPlaces);
  136. //Logger::writeToLog(fontColour);
  137. slider->getProperties().set("fontcolour", fontColour);
  138. //slider->getProperties().set("valueFontColour", Colour::fromString(cl).contrasting().toString());
  139. if(textBox<1)
  140. slider->setTextBoxStyle (Slider::NoTextBox, true, 0, 0);
  141. this->setWantsKeyboardFocus(false);
  142. resizeCount = 0;
  143. }//--- end of constructor ----
  144. //---------------------------------------------
  145. ~CabbageSlider()
  146. {
  147. }
  148. //---------------------------------------------
  149. void resized()
  150. {
  151. //if rotary
  152. if (sliderType.contains("rotary")) {
  153. if(cl.length() > 0)
  154. slider->setColour(0x1001200, Colour::fromString(cl));
  155. slider->setSliderStyle(Slider::Rotary);
  156. getProperties().set("type", var("rslider"));
  157. slider->setSliderStyle(Slider::RotaryVerticalDrag);
  158. slider->setRotaryParameters(float_Pi * 1.2f, float_Pi * 2.8f, false);
  159. //if using group caption
  160. if (compName.length() > 0) {
  161. groupbox->setBounds(0, 0, getWidth(), getHeight());
  162. int textHeight = 20;
  163. int availableHeight = getHeight()-textHeight;
  164. offY = textHeight + 5;
  165. int sliderHeight = availableHeight - 10;
  166. int sliderWidth = sliderHeight;
  167. offX = (getWidth()/2) - (sliderWidth/2);
  168. slider->setBounds(offX, offY, sliderWidth, sliderHeight);
  169. groupbox->setText (compName);
  170. groupbox->setVisible(true);
  171. slider->toFront(true);
  172. }
  173. //else if no group caption then the slider takes the whole area available
  174. else
  175. slider->setBounds(0, 0, getWidth(), getHeight());
  176. }
  177. //else if vertical
  178. else if (sliderType.contains("vertical")) {
  179. slider->setSliderStyle(Slider::LinearVertical);
  180. if(cl.length() > 0)
  181. slider->setColour(Slider::thumbColourId, Colour::fromString(cl));
  182. if (compName.length() > 0) {
  183. groupbox->setBounds(0, 0, getWidth(), getHeight());
  184. int textHeight = 20;
  185. int availableHeight = getHeight()-textHeight;
  186. offY = textHeight + 5;
  187. int sliderHeight = availableHeight - 10;
  188. int sliderWidth = getWidth() - 20;
  189. offX = (getWidth()/2) - (sliderWidth/2);
  190. slider->setBounds(offX, offY, sliderWidth, sliderHeight);
  191. groupbox->setVisible(true);
  192. groupbox->setText(compName);
  193. slider->toFront(true);
  194. }
  195. else
  196. slider->setBounds(0, 0, getWidth(), getHeight());
  197. }
  198. //else if horizontal
  199. else {
  200. slider->setSliderStyle(Slider::LinearHorizontal);
  201. if(cl.length() > 0)
  202. slider->setColour(Slider::thumbColourId, Colour::fromString(cl));
  203. if (compName.length() > 0) {
  204. groupbox->setBounds(0, 0, getWidth(), getHeight());
  205. int textHeight = 20;
  206. int availableHeight = getHeight()-textHeight;
  207. offY = textHeight + 5;
  208. int sliderHeight = availableHeight - 10;
  209. int sliderWidth = getWidth() - 20;
  210. offX = (getWidth()/2) - (sliderWidth/2);
  211. slider->setBounds(offX, offY, sliderWidth, sliderHeight);
  212. groupbox->setText(compName);
  213. groupbox->setVisible(true);
  214. slider->toFront(true);
  215. }
  216. else
  217. slider->setBounds(0, 0, getWidth(), getHeight());
  218. }
  219. //We only store the original dimensions the first time resized() is called.
  220. //Otherwise we would be passing incorrect values to the slider l+f methods...
  221. if (resizeCount == 0) {
  222. slider->getProperties().set(String("origHeight"), getHeight());
  223. slider->getProperties().set(String("origWidth"), getWidth());
  224. slider->getProperties().set(String("origX"), getX());
  225. slider->getProperties().set(String("origY"), getY());
  226. }
  227. resizeCount++;
  228. this->setWantsKeyboardFocus(false);
  229. }
  230. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageSlider);
  231. };
  232. //==============================================================================
  233. // custom checkbox component with optional surrounding groupbox
  234. //==============================================================================
  235. class CabbageCheckbox : public Component
  236. {
  237. int offX, offY, offWidth, offHeight;
  238. public:
  239. ScopedPointer<GroupComponent> groupbox;
  240. ScopedPointer<ToggleButton> button;
  241. //---- constructor -----
  242. CabbageCheckbox(String name, String caption, String buttonText, String colour, String fontcolour, bool isRect)
  243. {
  244. setName(name);
  245. offX=offY=offWidth=offHeight=0;
  246. groupbox = new GroupComponent(String("groupbox_")+name);
  247. button = new ToggleButton(name);
  248. addAndMakeVisible(groupbox);
  249. addAndMakeVisible(button);
  250. groupbox->setVisible(false);
  251. groupbox->getProperties().set("groupLine", var(1));
  252. //outline colour ID
  253. groupbox->setColour(0x1005400,
  254. Colour::fromString(colour));
  255. //text colour ID
  256. groupbox->setColour(0x1005410,
  257. Colour::fromString(colour));
  258. button->setButtonText(buttonText);
  259. if(caption.length()>0){
  260. offX=10;
  261. offY=20;
  262. offWidth=-20;
  263. offHeight=-30;
  264. groupbox->setVisible(true);
  265. groupbox->setText(caption);
  266. }
  267. button->getProperties().set("isRect", isRect);
  268. button->getProperties().set("colour", colour);
  269. button->getProperties().set("fontcolour", fontcolour);
  270. //text colour id
  271. button->setColour(0x1006501,
  272. Colour::fromString(colour));
  273. button->setButtonText(buttonText);
  274. this->setWantsKeyboardFocus(false);
  275. }
  276. //---------------------------------------------
  277. ~CabbageCheckbox(){
  278. }
  279. //---------------------------------------------
  280. void resized()
  281. {
  282. groupbox->setBounds(0, 0, getWidth(), getHeight());
  283. button->setBounds(offX, offY, getWidth()+offWidth, getHeight()+offHeight);
  284. this->setWantsKeyboardFocus(false);
  285. }
  286. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageCheckbox);
  287. };
  288. //==============================================================================
  289. // custom checkbox component with optional surrounding groupbox
  290. //==============================================================================
  291. class CabbageComboBox : public Component
  292. {
  293. //ScopedPointer<LookAndFeel> lookFeel;
  294. int offX, offY, offWidth, offHeight;
  295. public:
  296. ScopedPointer<GroupComponent> groupbox;
  297. ScopedPointer<ComboBox> combo;
  298. //---- constructor -----
  299. CabbageComboBox(String name, String caption, String text, String colour, String fontColour)
  300. {
  301. setName(name);
  302. offX=offY=offWidth=offHeight=0;
  303. groupbox = new GroupComponent(String("groupbox_")+name);
  304. combo = new ComboBox(name);
  305. addAndMakeVisible(groupbox);
  306. addAndMakeVisible(combo);
  307. groupbox->setVisible(false);
  308. groupbox->getProperties().set("groupLine", var(1));
  309. combo->setColour(ComboBox::textColourId, Colour::fromString(fontColour));
  310. combo->getProperties().set("colour", colour);
  311. combo->getProperties().set("fontcolour", fontColour);
  312. //combo->setColour(ComboBox::ColourIds::textColourId, Colour::fromString(fontColour));
  313. //outline colour IDE
  314. groupbox->setColour(0x1005400,
  315. Colour::fromString(colour));
  316. //text colour ID
  317. groupbox->setColour(0x1005410,
  318. Colour::fromString(colour));
  319. if(caption.length()>0){
  320. offX=10;
  321. offY=35;
  322. offWidth=-20;
  323. offHeight=-45;
  324. groupbox->setVisible(true);
  325. groupbox->setText(caption);
  326. }
  327. //text colour ID
  328. combo->setColour(0x1000a00,
  329. Colours::findColourForName("white", Colours::grey));
  330. combo->setEditableText (false);
  331. combo->setJustificationType (Justification::centredLeft);
  332. combo->setTextWhenNothingSelected(text);
  333. this->setWantsKeyboardFocus(false);
  334. }
  335. //---------------------------------------------
  336. ~CabbageComboBox(){
  337. }
  338. //---------------------------------------------
  339. void resized()
  340. {
  341. groupbox->setBounds(0, 0, getWidth(), getHeight());
  342. combo->setBounds(offX, offY, getWidth()+offWidth, getHeight()+offHeight);
  343. this->setWantsKeyboardFocus(false);
  344. }
  345. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageComboBox);
  346. };
  347. //==============================================================================
  348. // custom image component
  349. //==============================================================================
  350. class CabbageImage : public Component
  351. {
  352. public:
  353. CabbageImage(String name, String file, String outline, String fill, String shape, int line):
  354. Component(name), picFile(file), file(file), fill(fill), outline(outline), shape(shape), line(line){
  355. setName(name);
  356. //toBack();
  357. img = ImageCache::getFromFile (File (file));
  358. this->setWantsKeyboardFocus(false);
  359. //this->setInterceptsMouseClicks(false, true);
  360. }
  361. ~CabbageImage(){
  362. }
  363. private:
  364. Image img;
  365. int top, left, width, height, line;
  366. String fill, outline, shape, file;
  367. File picFile;
  368. void paint (Graphics& g){
  369. if(file.length()>5){
  370. g.drawImage(img, 0, 0, width, height, 0, 0, img.getWidth(), img.getHeight());
  371. }
  372. else{
  373. if(shape.contains("rounded")){
  374. g.setColour(Colour::fromString(outline));
  375. g.drawRoundedRectangle(0,0, width, height, width*.02, line);
  376. g.setColour(Colour::fromString(fill));
  377. g.fillRoundedRectangle(line,line, width-(line*2), height-(line*2), width*.02);
  378. }
  379. else if(shape.contains("ellipse")){
  380. g.setColour(Colour::fromString(outline));
  381. g.drawEllipse(0,0, width, height, line);
  382. g.setColour(Colour::fromString(fill));
  383. g.fillEllipse(line,line, width-(line*2), height-(line*2));
  384. }
  385. else if(shape.contains("sharp")){
  386. g.setColour(Colour::fromString(outline));
  387. g.drawRect(0,0, width, height, line);
  388. g.setColour(Colour::fromString(fill));
  389. g.fillRect(line,line, width-(line*2), height-(line*2));
  390. }
  391. }
  392. }
  393. void resized(){
  394. top = getY();
  395. left = getX();
  396. width = getWidth();
  397. height = getHeight();
  398. }
  399. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageImage);
  400. };
  401. //==============================================================================
  402. // custom groupbox component, this can act as a plant for other components
  403. //==============================================================================
  404. class CabbageGroupbox : public GroupComponent
  405. {
  406. OwnedArray<Component> comps;
  407. int offX, offY, offWidth, offHeight;
  408. public:
  409. //---- constructor -----
  410. CabbageGroupbox(String name, String caption, String text, String colour, String fontColour, int line):GroupComponent(name)
  411. {
  412. toBack();
  413. offX=offY=offWidth=offHeight=0;
  414. if(colour.length()>0){
  415. //outline colour iD
  416. setColour(0x1005400,
  417. Colour::fromString(colour));
  418. //text colour iD
  419. setColour(0x1005410,
  420. Colour::fromString(colour));
  421. }
  422. this->getProperties().set("colour", colour);
  423. this->getProperties().set("fontcolour", fontColour);
  424. this->setText(text);
  425. this->setWantsKeyboardFocus(false);
  426. if(line==0)
  427. this->getProperties().set("groupLine", var(0));
  428. else
  429. this->getProperties().set("groupLine", var(1));
  430. this->repaint();
  431. setName(name);
  432. }
  433. //---------------------------------------------
  434. ~CabbageGroupbox(){
  435. }
  436. //---------------------------------------------
  437. void resized()
  438. {
  439. this->setWantsKeyboardFocus(false);
  440. }
  441. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageGroupbox);
  442. };
  443. //==============================================================================
  444. // custom directorylist
  445. //==============================================================================
  446. class CabbageDirectoryList : public Component
  447. {
  448. public:
  449. ScopedPointer<DirectoryContentsComponent> directoryList;
  450. String name, channel, workingDir, fileType;
  451. //---- constructor -----
  452. public:
  453. CabbageDirectoryList (String _name, String _channel, String _workingDir, String _fileType):
  454. name(_name),
  455. channel(_channel),
  456. workingDir(_workingDir),
  457. fileType(_fileType)
  458. {
  459. setName(name);
  460. directoryList = new DirectoryContentsComponent(workingDir, fileType);
  461. addAndMakeVisible(directoryList);
  462. }
  463. ~CabbageDirectoryList(){}
  464. void resized()
  465. {
  466. directoryList->setBounds(0, 0, getWidth(), getHeight());
  467. }
  468. void paint(Graphics& g){}
  469. const StringArray getListContents(){
  470. StringArray test = directoryList->getFunctionTables();
  471. //Logger::writeToLog(test.joinIntoString("\n"));
  472. return directoryList->getFunctionTables();
  473. }
  474. private:
  475. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageDirectoryList);
  476. };
  477. //==============================================================================
  478. // custom multitab
  479. //==============================================================================
  480. class CabbageMultiTab : public Component
  481. {
  482. public:
  483. ScopedPointer<TabbedComponent> tabComp;
  484. String name, fontcolour, bgcolour;
  485. //---- constructor -----
  486. public:
  487. CabbageMultiTab (String _name, String _fontcolour, String _bgcolour):
  488. name(_name),
  489. fontcolour(_fontcolour),
  490. bgcolour(_bgcolour)
  491. {
  492. setName(name);
  493. tabComp = new TabbedComponent(TabbedButtonBar::TabsAtTop);
  494. tabComp->setOutline(0);
  495. addAndMakeVisible(tabComp);
  496. }
  497. ~CabbageMultiTab(){}
  498. void resized()
  499. {
  500. tabComp->setBounds(0, 0, getWidth(), getHeight());
  501. }
  502. void paint(Graphics& g){}
  503. private:
  504. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageMultiTab);
  505. };
  506. //==============================================================================
  507. // custom CabbageXYController
  508. //==============================================================================
  509. class CabbageXYController : public Component
  510. {
  511. //ScopedPointer<LookAndFeel> lookFeel;
  512. int offX, offY, offWidth, offHeight;
  513. public:
  514. ScopedPointer<GroupComponent> groupbox;
  515. ScopedPointer<XYPad> xypad;
  516. int XYAutoIndex;
  517. //---- constructor -----
  518. CabbageXYController(XYPadAutomation* xyAuto,
  519. String name,
  520. String text,
  521. String caption,
  522. int minX, int maxX, int minY, int maxY, int index, int dec,
  523. String colour,
  524. String fontcolour,
  525. float xValue,
  526. float yValue)
  527. {
  528. setName(name);
  529. XYAutoIndex = index;
  530. offX=offY=offWidth=offHeight=0;
  531. caption="";
  532. groupbox = new GroupComponent(String("groupbox_")+name);
  533. groupbox->setWantsKeyboardFocus(false);
  534. xypad = new XYPad(xyAuto, text, minX, maxX, minY, maxY, dec, Colour::fromString(colour), Colour::fromString(fontcolour), xValue, yValue);
  535. xypad->setWantsKeyboardFocus(false);
  536. addAndMakeVisible(xypad);
  537. addAndMakeVisible(groupbox);
  538. groupbox->setVisible(false);
  539. //outline colour ID
  540. groupbox->setColour(0x1005400,
  541. Colours::findColourForName("white", Colours::white));
  542. //outline text ID
  543. groupbox->setColour(0x1005410,
  544. Colours::findColourForName("white", Colours::white));
  545. if(caption.length()>0){
  546. offX=10;
  547. offY=15;
  548. offWidth=-20;
  549. offHeight=-25;
  550. groupbox->setVisible(true);
  551. groupbox->setText(caption);
  552. }
  553. this->setWantsKeyboardFocus(false);
  554. }
  555. //---------------------------------------------
  556. ~CabbageXYController(){
  557. }
  558. //---------------------------------------------
  559. void resized()
  560. {
  561. groupbox->setBounds(0, 0, getWidth(), getHeight());
  562. xypad->setBounds(offX, offY, getWidth()+offWidth, getHeight()+offHeight);
  563. this->setWantsKeyboardFocus(false);
  564. }
  565. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageXYController);
  566. };
  567. //==============================================================================
  568. // custom Csound message console
  569. //==============================================================================
  570. class CabbageMessageConsole : public Component
  571. {
  572. ScopedPointer<GroupComponent> groupbox;
  573. ScopedPointer<LookAndFeel_V1> lookAndFeel;
  574. String text;
  575. int offX, offY, offWidth, offHeight;
  576. public:
  577. ScopedPointer<TextEditor> editor;
  578. //---- constructor -----
  579. CabbageMessageConsole(String name, String caption, String text):
  580. editor(new TextEditor(String("editor_")+name)),
  581. groupbox(new GroupComponent(String("groupbox_")+name)),
  582. lookAndFeel(new LookAndFeel_V1()),
  583. offX(0),
  584. offY(0),
  585. offWidth(0),
  586. offHeight(0),
  587. text(text)
  588. {
  589. editor->setLookAndFeel(lookAndFeel);
  590. addAndMakeVisible(editor);
  591. editor->setMultiLine(true);
  592. editor->setScrollbarsShown(true);
  593. editor->setReturnKeyStartsNewLine(true);
  594. editor->setReadOnly(true);
  595. //background colour ID
  596. editor->setColour(0x1000200, Colours::black);
  597. //text colour ID
  598. editor->setColour(0x1000201, Colours::green);
  599. if(caption.length()>0){
  600. offX=10;
  601. offY=15;
  602. offWidth=-20;
  603. offHeight=-25;
  604. groupbox->setVisible(true);
  605. groupbox->setText(caption);
  606. }
  607. this->setWantsKeyboardFocus(false);
  608. }
  609. //---------------------------------------------
  610. ~CabbageMessageConsole(){
  611. }
  612. void paint(Graphics &g){
  613. //----- For drawing the border
  614. g.setColour(CabbageUtils::getComponentSkin());
  615. g.fillRoundedRectangle (0, -3, getWidth(), getHeight(), 8.f);
  616. g.setColour(Colours::black);
  617. g.fillRoundedRectangle (5, getHeight()-35, getWidth()-10, 20, 8.f);
  618. //----- For drawing the title
  619. g.setColour (Colours::whitesmoke);
  620. g.setOpacity (0.8);
  621. g.setFont (15);
  622. Justification just(1);
  623. g.drawText(text, 10, -5, getWidth()-20, 35, just, false);
  624. }
  625. //---------------------------------------------
  626. void resized()
  627. {
  628. groupbox->setBounds(0, 0, getWidth(), getHeight());
  629. editor->setBounds(offX+5, offY+20, (getWidth()+offWidth)-10, (getHeight()+offHeight)-45);
  630. this->setWantsKeyboardFocus(false);
  631. }
  632. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageMessageConsole);
  633. };
  634. //==============================================================================
  635. // custom VUComponent
  636. //==============================================================================
  637. class VUComponent : public Component
  638. {
  639. public:
  640. //=================================================================================
  641. // Nested class VU Meter
  642. //=================================================================================
  643. class VUMeter : public Component
  644. {
  645. public:
  646. //=============================================================================
  647. VUMeter(int input1, bool input2)
  648. {
  649. //-----1 = Mono, 2 = Left Ch., 3 = Right Ch.
  650. type = input1;
  651. //----- Horizontal or Vertical
  652. style = input2;
  653. clipFlag = 0; //0 is off, 1 is on
  654. //----- Declarations for each db value. The range will go logarithmically from -infinity to +3db.
  655. //A level of 0.9 is being assigned to 0db.
  656. plus3DB = 1;
  657. zeroDB = 0.9;
  658. minus3DB = 0.71 * zeroDB; //0.639
  659. minus10DB = 0.3162 * zeroDB; //0.285
  660. minus20DB = 0.1 * zeroDB; //0.09
  661. minus40DB = 0.01 * zeroDB; //0.009
  662. }
  663. //====================================================================================
  664. ~VUMeter(){}
  665. //========== Resizing method =========================================================
  666. void resized ()
  667. {
  668. //----- Declaring dimensional properties
  669. top = 5;
  670. clipZone = 2; //Leaving a gap for the clip marker at the top
  671. bottom = getHeight() - 5;
  672. if (type == 1)
  673. levelWidth = getWidth()/5; //width of mono level
  674. else if ((type == 2) || (type == 3))
  675. levelWidth = (getWidth()/1.25) / 5; //width of stereo level should be the same as if it were mono
  676. levelHeight = bottom - (top + clipZone); //height available to the VU part
  677. xOffset = getWidth()/5; //Mono and Left Ch. VU's will be drawn 1/5 of totalWidth from left
  678. yOffset = 0;
  679. prevLevel = bottom;
  680. currentLevel = bottom;
  681. //----- Setting the location of the db markers
  682. plus3Mark = bottom - levelHeight;
  683. zeroMark = bottom - (0.9 * levelHeight);
  684. minus3Mark = bottom - (0.8 * levelHeight);
  685. minus10Mark = bottom - (0.5 * levelHeight);
  686. minus20Mark = bottom - (0.25 * levelHeight);
  687. minus40Mark = bottom - (0.1 * levelHeight);
  688. //----- Setting up the gradient fill for the meter level
  689. cg = ColourGradient (Colours::transparentBlack, 0, bottom,
  690. Colours::transparentBlack, 0, top, false);
  691. cg.addColour (0.07, Colours::aqua);
  692. cg.addColour (0.2, Colours::lime);
  693. cg.addColour (0.5, Colours::lime);
  694. cg.addColour (0.6, Colours::yellow);
  695. cg.addColour (0.75, Colours::yellow);
  696. cg.addColour (0.85, Colours::orange);
  697. cg.addColour (0.999, Colours::orangered);
  698. clClip = (Colours::red);
  699. //----- Calling function to draw image background. This only applies if the VU is mono or the
  700. //left channel of a stereo meter. Right channel meters will not use a background as they can just
  701. //draw over the left channel background image.
  702. if ((type == 1) || (type == 2))
  703. verticalBackground();
  704. }
  705. //===== Vertical Background =======================================================================
  706. void verticalBackground ()
  707. {
  708. //----- This function draws the background onto a blank image and then loads it into cache. The
  709. //cached image is then reused in the paint() method. This is a more efficient way to redrawing something
  710. //that is static.
  711. // Creating a blank canvas
  712. img = Image(Image::ARGB, getWidth(), getHeight(), true);
  713. Graphics g (img);
  714. Colour bg = Colour::fromRGBA (10, 10, 15, 255);
  715. g.fillRoundedRectangle (0, 0, getWidth(), getHeight(), 2);
  716. //----- Painting the db level markers
  717. g.setColour (Colours::white);
  718. int fontSize = getHeight()*0.05;
  719. if (fontSize > 15)
  720. fontSize = 15;
  721. g.setFont (fontSize);
  722. int startText; //starting x value
  723. if (type == 1)
  724. startText = getWidth() * 0.4;
  725. else if (type == 2)
  726. startText = (getWidth() * 0.4) * 1.25; //stereo VU's are 1.25 times the size of a mono VU
  727. Justification just (4); //Centered
  728. g.drawText ("+3", startText, plus3Mark-5, getWidth()*.4, 10, just, false);
  729. g.drawText ("0", startText, zeroMark-5, getWidth()*.4, 10, just, false);
  730. g.drawText ("-3", startText, minus3Mark-5, getWidth()*.4, 10, just, false);
  731. g.drawText ("-10", startText, minus10Mark-5, getWidth()*.4, 10, just, false);
  732. g.drawText ("-20", startText, minus20Mark-5, getWidth()*.4, 10, just, false);
  733. g.drawText ("-40", startText, minus40Mark-5, getWidth()*.4, 10, just, false);
  734. //----- Painting the level background
  735. g.setGradientFill (cg);
  736. g.setOpacity (0.1);
  737. g.fillRect (xOffset, clipZone, levelWidth, levelHeight);
  738. if (type == 2) //if stereo we need another meter level
  739. g.fillRect (xOffset+levelWidth+1, clipZone, levelWidth, levelHeight);
  740. //---- For the clip zone
  741. g.setColour (clClip);
  742. g.setOpacity (0.2);
  743. g.fillRect (xOffset, top, levelWidth, clipZone);
  744. if (type == 2) //if stereo we need another clip zone
  745. g.fillRect (xOffset+levelWidth+1, top, levelWidth, clipZone);
  746. //----- Loading image into cache
  747. if (type == 1)
  748. ImageCache::addImageToCache (img, 11);
  749. else if (type == 2)
  750. ImageCache::addImageToCache (img, 12);
  751. }
  752. //========= Paint Method ====================================================================
  753. void paint (Graphics &g)
  754. {
  755. Image bg;
  756. //----- Drawing the background from the imagecache
  757. if (type == 1)
  758. bg = ImageCache::getFromHashCode(11);
  759. if (type == 2)
  760. bg = ImageCache::getFromHashCode(12);
  761. g.drawImage (bg, 0, 0, getWidth(), getHeight(), 0, 0, bg.getWidth(), bg.getHeight(), false);
  762. //----- Drawing the meter level. When paintFlag is 1 the meter level is to be increased. This
  763. //new bit of the level is painted using the gradient fill cg. If paintFlag is 0, the level is
  764. //to be decreased. Because there is no colour or drawing tool used for paintFlag=0, this bit of
  765. //the level is cleared.
  766. if (paintFlag == 1) {
  767. g.setGradientFill (cg);
  768. g.setOpacity (0.7);
  769. if ((type == 1) || (type == 2))
  770. g.fillRect (xOffset, currentLevel, levelWidth, diff);
  771. else
  772. g.fillRect ((xOffset+levelWidth+1), currentLevel, levelWidth, diff);
  773. }
  774. //----- Determining if the clipmarker should be shown. It is set back to 0 immediately as it
  775. //does not need to repainted over and over. If the clipFlag is 0, the marker will stay on if
  776. //the repaint() bounds are not inclusive of the clipZone. When the user clicks on the VU meter
  777. //the clipFlag will be 0 and the repaint() bounds will include the clipZone (see mouseDown()),
  778. //therefore turning off the clipmarker. This happens because there is no colour or draw function
  779. //used for clipFlag = 0, and therefore this zone is cleared exposing the background again.
  780. if (clipFlag == 1) {
  781. g.setColour (clClip);
  782. if (type == 1)
  783. g.fillRect (xOffset, top, levelWidth, clipZone);
  784. else
  785. g.fillRect(xOffset, top, (levelWidth*2) + 1, clipZone);
  786. clipFlag = 0;
  787. }
  788. }
  789. //========= Set Level =========================================================================
  790. void setLevel (float value)
  791. {
  792. level = value;
  793. // If level is 1 or more...
  794. if (level >= 1) {
  795. clipFlag = 1;
  796. level = 1;
  797. }
  798. //----- The following if statements determine the offset on the y axis. Each zone
  799. //itself has to be treated independently to the rest of the level range.
  800. if ((level >= 0) && (level < minus40DB)){
  801. currentLevel = (bottom - minus40Mark) * (level / minus40DB);
  802. currentLevel = bottom - currentLevel;
  803. }
  804. //----- If level is between 0.009 and 0.09
  805. else if ((level >= minus40DB) && (level < minus20DB)){
  806. currentLevel = (minus40Mark-minus20Mark) * ((level - minus40DB) / (minus20DB - minus40DB));
  807. currentLevel = minus40Mark - currentLevel;
  808. }
  809. //----- If level is between 0.285 and 0.09
  810. else if ((level >= minus20DB) && (level < minus10DB)){
  811. currentLevel = (minus20Mark-minus10Mark) * ((level - minus20DB) / (minus10DB - minus20DB));
  812. currentLevel = minus20Mark - currentLevel;
  813. }
  814. //----- If level is between 0.285 and 0.639
  815. else if ((level >= minus10DB) && (level < minus3DB)){
  816. currentLevel = (minus10Mark-minus3Mark) * ((level - minus10DB) / (minus3DB - minus10DB));
  817. currentLevel = minus10Mark - currentLevel;
  818. }
  819. //----- If level is between 0.639 and 0.9
  820. else if ((level >= minus3DB) && (level < zeroDB)){
  821. currentLevel = (minus3Mark-zeroMark) * ((level - minus3DB) / (zeroDB - minus3DB));
  822. currentLevel = minus3Mark - currentLevel;
  823. }
  824. //----- If level is 0.9 or over
  825. else if (level >= zeroDB) {
  826. currentLevel = (zeroMark-plus3Mark) * ((level*10)-9);
  827. currentLevel = zeroMark - currentLevel;
  828. }
  829. //----- We only need to repaint the level difference between this value and the previous.
  830. //This is much more efficient than repainting the entire component each time.
  831. diff = prevLevel - currentLevel;
  832. if (diff > 0) {
  833. paintFlag = 1; // to indicate that we are adding to the current meter level
  834. if ((type == 1) || (type == 2))
  835. repaint(xOffset, currentLevel, levelWidth, diff);
  836. else
  837. repaint((xOffset+levelWidth+1), currentLevel, levelWidth, diff);
  838. }
  839. else if (diff < 0) {
  840. diff *= -1;
  841. paintFlag = 0; //to indicate that we are subtracting from the current meter level
  842. if ((type == 1) || (type == 2))
  843. repaint(xOffset, prevLevel, levelWidth, diff);
  844. else
  845. repaint((xOffset+levelWidth+1), prevLevel, levelWidth, diff);
  846. }
  847. //else if diff = 0 then do nothing!
  848. //----- To see if clip marker should be shown.....
  849. if (clipFlag == 1) {
  850. if ((type == 1) || (type == 2))
  851. repaint (xOffset, top, levelWidth, clipZone);
  852. else
  853. repaint((xOffset+levelWidth+1), top, levelWidth, clipZone);
  854. }
  855. // Making the current level the previous level, for the next pass through....
  856. prevLevel = currentLevel;
  857. }
  858. //======== If mouse is clicked ================================================================
  859. void mouseDown (const MouseEvent& e)
  860. {
  861. //----- Getting (x,y) of the mouse click
  862. int x = e.getPosition().getX();
  863. int y = e.getPosition().getY();
  864. //----- If the mouse is clicked over the VU, then the clip marker will be
  865. //turned off.
  866. if ((x >= getWidth()/5) && (x <= getWidth()*0.8) &&
  867. (y >= 0) && (y <= getHeight())) {
  868. clipFlag = 0;
  869. // Only need to repaint the clipzone. Stereo VU's just repaint both
  870. //clip zones as it will not make much difference in terms of CPU usage.
  871. if (type == 1) //mono
  872. repaint (xOffset, top, levelWidth, clipZone);
  873. else //stereo
  874. repaint(xOffset, top, (levelWidth*2) + 1, clipZone);
  875. }
  876. }
  877. private:
  878. bool style;
  879. int type, widthMeter, heightMeter;
  880. float level;
  881. int clipFlag, clipZone;
  882. int top, bottom, xOffset, yOffset, levelWidth, levelHeight;
  883. float plus3DB, zeroDB, minus3DB, minus10DB, minus20DB, minus40DB;
  884. int plus3Mark, zeroMark, minus3Mark, minus10Mark, minus20Mark, minus40Mark;
  885. Colour clClip;
  886. ColourGradient cg;
  887. Image img;
  888. int paintFlag;
  889. int currentLevel, prevLevel;
  890. int diff;
  891. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VUMeter);
  892. };
  893. //====== End of VUMeter class ===========================================
  894. //===== VU Component Constructor ========================================
  895. VUComponent (Array<int> conArr, bool useVertical)
  896. {
  897. style = useVertical;
  898. numArrElements = 0;
  899. totalNumLevels = 0;
  900. numMeters = 0;
  901. for (int i=0; i<conArr.size(); i++) {
  902. //Ignoring anything that is not either 1 or 2...
  903. if ((conArr[i] == 1) || (conArr[i] == 2)) {
  904. config.add (conArr[i]);
  905. numArrElements++;
  906. totalNumLevels += conArr[i]; //needed for indexing
  907. //numMeters allows us to get the correct width of each meter, as stereo
  908. //meters are 1.25 times as wide as mono ones...
  909. if (conArr[i] == 1)
  910. numMeters += 1;
  911. else
  912. numMeters += 1.25;
  913. }
  914. }
  915. }
  916. //===== Destructor ====================================================
  917. ~VUComponent()
  918. {
  919. }
  920. //===== Resize ========================================================
  921. void resized()
  922. {
  923. float gap = getWidth() * 0.07; //gap between meters
  924. float totalGap = gap * (numArrElements-1); //all gaps added up
  925. float availableWidth = getWidth() - totalGap;
  926. float widthMonoMeter = availableWidth / numMeters;
  927. float widthStereoMeter;
  928. //If there is only 1 element in the array it should take up the whole width
  929. if ((numArrElements == 1) && (totalNumLevels ==2))
  930. widthStereoMeter = availableWidth;
  931. else
  932. widthStereoMeter = widthMonoMeter * 1.25;
  933. //----- The following for loop adds each level with a unique index. xOffset is the
  934. //x coordinate at which they are drawn.
  935. int arrElement = 0;
  936. float xOffset = 0;
  937. for (int i=0; i<totalNumLevels; i++) {
  938. //----- Adding a mono meter
  939. if (config[arrElement] == 1 ) {
  940. meters.add (new VUMeter(1, style));
  941. meters[i]->setBounds (xOffset, 0, widthMonoMeter, getHeight());
  942. addAndMakeVisible (meters[i]);
  943. xOffset += widthMonoMeter;
  944. if (arrElement != numArrElements) //if not the last element then add a gap
  945. xOffset += gap;
  946. arrElement++;
  947. }
  948. //----- Adding a stereo meter
  949. else if (config[arrElement] == 2 ) {
  950. //Left side
  951. meters.add (new VUMeter(2, style));
  952. meters[i]->setBounds (xOffset, 0, widthStereoMeter, getHeight());
  953. addAndMakeVisible (meters[i]);
  954. //Right side
  955. i++; //i needs to be incremented again to make sure that the index numbers are correct
  956. meters.add (new VUMeter(3, style));
  957. meters[i]->setBounds (xOffset, 0, widthStereoMeter, getHeight());
  958. addAndMakeVisible (meters[i]);
  959. xOffset += widthStereoMeter;
  960. if (arrElement != numArrElements) //if not the last element then add a gap
  961. xOffset += gap;
  962. arrElement++;
  963. }
  964. }
  965. }
  966. //===== Set VU Level Function =========================================
  967. void setVULevel (int VUIndex, float value)
  968. {
  969. meters[VUIndex]->setLevel (value);
  970. }
  971. private:
  972. OwnedArray<VUMeter> meters;
  973. bool style;
  974. int widthMeter, heightMeter;
  975. int totalNumLevels;
  976. float numMeters;
  977. Array<int> config;
  978. int numArrElements;
  979. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VUComponent);
  980. };
  981. //==============================================================================
  982. // custom CabbageVUMeter
  983. //==============================================================================
  984. class CabbageVUMeter : public Component
  985. {
  986. //ScopedPointer<LookAndFeel> lookFeel;
  987. int offX, offY, offWidth, offHeight, numMeters, width, height;
  988. String name;
  989. public:
  990. ScopedPointer<GroupComponent> groupbox;
  991. ScopedPointer<VUComponent> vuMeter;
  992. //---- constructor -----
  993. CabbageVUMeter(String name, String text, String caption, Array<int> config):
  994. numMeters(0)
  995. {
  996. setName(name);
  997. offX=offY=offWidth=offHeight=0;
  998. groupbox = new GroupComponent(String("groupbox_")+name);
  999. numMeters = 0;
  1000. for(int i =0;i<config.size();i++)
  1001. numMeters = numMeters+config[i];
  1002. vuMeter = new VUComponent(config, true);
  1003. addAndMakeVisible(vuMeter);
  1004. addAndMakeVisible(groupbox);
  1005. groupbox->setVisible(false);
  1006. //outline colour ID
  1007. groupbox->setColour(0x1005400,
  1008. Colours::findColourForName("white", Colours::white));
  1009. //text colour ID
  1010. groupbox->setColour(0x1005410,
  1011. Colours::findColourForName("white", Colours::white));
  1012. if(caption.length()>0){
  1013. offX=10;
  1014. offY=15;
  1015. offWidth=-20;
  1016. offHeight=-25;
  1017. groupbox->setVisible(true);
  1018. groupbox->setText(caption);
  1019. }
  1020. this->setWantsKeyboardFocus(false);
  1021. }
  1022. //---------------------------------------------
  1023. ~CabbageVUMeter(){
  1024. }
  1025. int getNoMeters(){
  1026. return numMeters;
  1027. }
  1028. //---------------------------------------------
  1029. void resized()
  1030. {
  1031. groupbox->setBounds(0, 0, getWidth(), getHeight());
  1032. vuMeter->setBounds(offX, offY, getWidth()+offWidth, getHeight()+offHeight);
  1033. this->setWantsKeyboardFocus(false);
  1034. }
  1035. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageVUMeter);
  1036. };
  1037. //==============================================================================
  1038. // custom CabbageTable, uses the Table class
  1039. //==============================================================================
  1040. class CabbageTable : public Component
  1041. {
  1042. //ScopedPointer<LookAndFeel> lookFeel;
  1043. int offX, offY, offWidth, offHeight, tableSize;
  1044. StringArray colours, channels;
  1045. Array<int> tableSizes, tableNumbers, drawingModes, resizingModes;
  1046. Array< Point<float> > minMax;
  1047. float alpha;
  1048. public:
  1049. bool readOnly;
  1050. ScopedPointer<GroupComponent> groupbox;
  1051. ScopedPointer<CabbageTableManager> table;
  1052. ScopedPointer<TextButton> button;
  1053. ScopedPointer<ChangeListener> listener;
  1054. //---- constructor -----
  1055. CabbageTable(String name, String text, String caption, StringArray chans,
  1056. Array<int> tblNumbers,
  1057. Array<int> tblSize,
  1058. Array<int> drawingModes,
  1059. Array<int> resizingModes,
  1060. Array<float> ampRanges,
  1061. StringArray Colours,
  1062. bool readOnly,
  1063. ChangeListener* listen)
  1064. : tableSizes(tblSize),
  1065. colours(Colours),
  1066. channels(chans),
  1067. readOnly(readOnly),
  1068. listener(listen),
  1069. tableNumbers(tblNumbers),
  1070. drawingModes(drawingModes),
  1071. resizingModes(resizingModes)
  1072. {
  1073. setName(name);
  1074. for(int i=0;i<ampRanges.size();i+=2){
  1075. minMax.add(Point<float>(ampRanges[i], ampRanges[i+1]));
  1076. }
  1077. offX=offY=offWidth=offHeight=0;
  1078. groupbox = new GroupComponent(String("groupbox_")+name);
  1079. groupbox->setWantsKeyboardFocus(false);
  1080. tableSize = tableSizes[0];
  1081. table = new CabbageTableManager(tableSize);
  1082. //add extra colours if user never specified them
  1083. //for(int i=colours.size();i<=tableSizes.size();i++)
  1084. //colours.add(Colour::fromString(colours[0]).withBrightness(1).toString());
  1085. // colours.add(Colours::lime.withBrightness(float(i)/tableSizes.size()).toString());
  1086. // set up drawing modes for each table
  1087. // 0: default mode, draws everything normally
  1088. // 1: drawHoriztonalSegments
  1089. // 2: make fixed point envelope
  1090. // 3: fixed points and horizontal
  1091. // 4: fixed points and horizontal and toggle max/min, editable from the onst
  1092. // ....varous fill variations...
  1093. for(int i=drawingModes.size();i<tableSizes.size();i++)
  1094. drawingModes.add(0);
  1095. addAndMakeVisible(table);
  1096. addAndMakeVisible(groupbox);
  1097. groupbox->setVisible(false);
  1098. //outline colour ID
  1099. groupbox->setColour(0x1005400,
  1100. Colours::findColourForName("white", Colours::white));
  1101. //text colour ID
  1102. groupbox->setColour(0x1005410,
  1103. Colours::findColourForName("white", Colours::white));
  1104. if(caption.length()>0){
  1105. offX=10;
  1106. offY=15;
  1107. offWidth=-20;
  1108. offHeight=-25;
  1109. groupbox->setVisible(true);
  1110. groupbox->setText(caption);
  1111. }
  1112. this->setWantsKeyboardFocus(false);
  1113. }
  1114. void setDrawingModeBooleans(bool &fixedEnv, bool &drawHorizontal, bool &toggleMaxMin, bool &drawOriginal, bool &drawFill, int mode)
  1115. {
  1116. if(mode==1){
  1117. drawHorizontal = true;
  1118. fixedEnv = false;
  1119. toggleMaxMin= false;
  1120. drawOriginal = true;
  1121. drawFill = false;
  1122. }
  1123. else if(mode==2){
  1124. drawHorizontal = false;
  1125. fixedEnv = true;
  1126. toggleMaxMin= false;
  1127. drawOriginal = true;
  1128. drawFill = false;
  1129. }
  1130. else if(mode==3){
  1131. drawHorizontal = true;
  1132. fixedEnv = true;
  1133. toggleMaxMin= false;
  1134. drawOriginal = true;
  1135. drawFill = false;
  1136. }
  1137. else if(mode==4){
  1138. drawHorizontal = true;
  1139. fixedEnv = true;
  1140. toggleMaxMin= true;
  1141. drawOriginal = false;
  1142. drawFill = true;
  1143. }
  1144. else{
  1145. drawHorizontal = false;
  1146. fixedEnv = false;
  1147. toggleMaxMin= false;
  1148. drawOriginal = true;
  1149. drawFill = false;
  1150. }
  1151. }
  1152. //---------------------------------------------
  1153. ~CabbageTable(){
  1154. listener.release();
  1155. }
  1156. void paint(Graphics& g){
  1157. //Logger::writeToLog("test");
  1158. }
  1159. void addTables(){
  1160. bool fixed, horizontal, toggleMaxMin, drawOriginal, drawFill;
  1161. if(table->getNumberOfTables()<tableNumbers.size())
  1162. if(tableNumbers.size()>1)
  1163. for(int i=0;i<tableNumbers.size();i++){
  1164. String name = "table"+String(tableNumbers[i]);
  1165. setDrawingModeBooleans(fixed, horizontal, toggleMaxMin, drawOriginal, drawFill, drawingModes[i]);
  1166. table->addTable(name, channels[i], tableNumbers[i], tableSizes[i], fixed,
  1167. horizontal, drawOriginal, toggleMaxMin, drawFill,
  1168. resizingModes[i], minMax[i], Colours::findColourForName(colours[i], Colours::white), readOnly, listener);
  1169. }
  1170. else{
  1171. setDrawingModeBooleans(fixed, horizontal, toggleMaxMin, drawOriginal, drawFill, drawingModes[0]);
  1172. String name = "table"+String(tableNumbers[0]);
  1173. Logger::writeToLog(name);
  1174. table->addTable("table0", channels[0], tableNumbers[0], tableSizes[0], fixed,
  1175. horizontal, drawOriginal, toggleMaxMin, drawFill,
  1176. resizingModes[0], minMax[0],
  1177. Colours::findColourForName(colours[0], Colours::white), readOnly, listener);
  1178. }
  1179. }
  1180. //---------------------------------------------
  1181. void fillTable(int ID, Array<double, CriticalSection> yValues){
  1182. if(yValues.size()>1)
  1183. table->fillTable(ID, yValues);
  1184. table->repaint();
  1185. }
  1186. void setScrubberPosition(int ID, float position){
  1187. //if(position>0)
  1188. //table->setScrubberPosition(ID, position);
  1189. }
  1190. //---------------------------------------------
  1191. void resized()
  1192. {
  1193. groupbox->setBounds(0, 0, getWidth(), getHeight());
  1194. table->setBounds(offX, offY, getWidth()+offWidth, getHeight()+offHeight);
  1195. //check that we have drawn enough tables
  1196. this->setWantsKeyboardFocus(false);
  1197. }
  1198. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageTable);
  1199. };
  1200. //==============================================================================
  1201. // custom PVSView, for viewing pvs
  1202. //==============================================================================
  1203. #ifndef Cabbage_No_Csound
  1204. class CabbagePVSTableData : public Component
  1205. {
  1206. public:
  1207. CabbagePVSTableData(int frameSize, int fftsize, int overlap, PVSDATEXT* inSpecData, int minFreq, int maxFreq) :
  1208. specData(inSpecData),
  1209. frameSize(frameSize),
  1210. minFreq(minFreq),
  1211. maxFreq(maxFreq)
  1212. {
  1213. freqRange = (maxFreq-minFreq);
  1214. }
  1215. ~CabbagePVSTableData()
  1216. {
  1217. }
  1218. void resized()
  1219. {
  1220. if (freqRange >= getWidth())
  1221. lineThickness = 1;
  1222. else
  1223. lineThickness = getWidth() / (float)freqRange;
  1224. cg = ColourGradient (Colours::transparentBlack, 0, getHeight(),
  1225. Colours::transparentBlack, 0, 0, false);
  1226. cg.addColour (0.07, Colours::aqua);
  1227. cg.addColour (0.2, Colours::lime);
  1228. cg.addColour (0.5, Colours::lime);
  1229. cg.addColour (0.6, Colours::yellow);
  1230. cg.addColour (0.75, Colours::yellow);
  1231. cg.addColour (0.85, Colours::orange);
  1232. cg.addColour (0.999, Colours::orangered);
  1233. cacheGridImage();
  1234. currPoint.setXY(0, getHeight());
  1235. frameSize = maxFreq/getWidth();
  1236. }
  1237. void cacheGridImage()
  1238. {
  1239. //----- This method stores the grid in cache
  1240. grid = Image(Image::ARGB, getWidth(), getHeight(), true);
  1241. Graphics g (grid);
  1242. g.setColour(CabbageUtils::getComponentFontColour());
  1243. for (float i=0.0; i<=1.0; i+=0.125) {
  1244. g.drawLine(getWidth()*i, 0, getWidth()*i, getHeight(), .1);
  1245. g.drawLine(0, getHeight()*i, getWidth(), getHeight()*i, .1);
  1246. }
  1247. ImageCache::addImageToCache(grid, 19);
  1248. }
  1249. void paint(Graphics& g)
  1250. {
  1251. Image bgGrid = ImageCache::getFromHashCode(19);
  1252. g.drawImage(bgGrid, 0, 0, getWidth(), getHeight(), 0, 0, bgGrid.getWidth(), bgGrid.getHeight(), false);
  1253. g.setGradientFill(cg);
  1254. //draw PVS data
  1255. for (int i=0; i<specData->N*2; i+=2) {
  1256. if (specData->frame[i]) {
  1257. amp = specData->frame[i];
  1258. freq = int(specData->frame[i+1]);
  1259. if ((amp > 0) && (amp <= 1) && (freq >= minFreq) && (freq <= maxFreq)) {
  1260. // g.fillEllipse ((((freq-minFreq)/(float)freqRange)*getWidth())-1,
  1261. // (getHeight()-(amp*getHeight()))-1, 2, 2);
  1262. g.drawLine(((freq-minFreq)/(float)freqRange)*getWidth(), getHeight()-(amp*getHeight()),
  1263. ((freq-minFreq)/(float)freqRange)*getWidth(), getHeight(), 1);
  1264. //prevPoint = currPoint;
  1265. //currPoint.setXY(((freq-minFreq)/(float)freqRange)*getWidth(), getHeight()-(amp*getHeight()));
  1266. //if (currPoint.getX() > prevPoint.getX())
  1267. // g.drawLine(prevPoint.getX(), prevPoint.getY(), currPoint.getX(), currPoint.getY(), 2);
  1268. }
  1269. }
  1270. }
  1271. }
  1272. private:
  1273. PVSDATEXT* specData;
  1274. Array<int> freqValues;
  1275. Array<MYFLT> ampValues;
  1276. int frameSize, minFreq, maxFreq, freqRange;
  1277. float lineThickness;
  1278. ColourGradient cg;
  1279. Image grid;
  1280. float amp, maxAmp, freq;
  1281. Point<float> currPoint, prevPoint;
  1282. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePVSTableData);
  1283. };
  1284. //---------------------------------------------------------------------
  1285. class CabbagePVSView : public Component
  1286. {
  1287. public:
  1288. CabbagePVSView(String name, String caption, String text, int frameSize, int fftsize, int overlap,
  1289. PVSDATEXT* inSpecData):
  1290. text(text)
  1291. {
  1292. setName(name);
  1293. maxFreq = 2000;
  1294. minFreq = 0;
  1295. maxAmp = 1.0;
  1296. pvsTableData = new CabbagePVSTableData (frameSize, fftsize, overlap, inSpecData, minFreq, maxFreq);
  1297. }
  1298. ~CabbagePVSView()
  1299. {
  1300. }
  1301. void resized()
  1302. {
  1303. this->setWantsKeyboardFocus(false);
  1304. pvsTableData->setBounds(getWidth()*0.2, getHeight()*0.1, getWidth()*0.7, getHeight()*0.7);
  1305. addAndMakeVisible(pvsTableData);
  1306. cacheBackground();
  1307. }
  1308. void updatePVSStruct()
  1309. {
  1310. pvsTableData->repaint();
  1311. }
  1312. void cacheBackground()
  1313. {
  1314. bg = Image(Image::ARGB, getWidth(), getHeight(), true);
  1315. Graphics g (bg);
  1316. //background
  1317. g.setColour(CabbageUtils::getDarkerBackgroundSkin());
  1318. g.fillRoundedRectangle (0, 0, getWidth(), getHeight(), 5);
  1319. //border
  1320. g.setColour (CabbageUtils::getComponentSkin());
  1321. g.drawRoundedRectangle (.5, .5, getWidth()-1, getHeight()-1, 5, 1);
  1322. //Markers etc...
  1323. g.setColour (Colours::lime);
  1324. Font font = CabbageUtils::getSmallerValueFont();
  1325. g.setFont(font);
  1326. String strX, strY;
  1327. float strWidth;
  1328. for (float i=0.0; i<=1.0; i+=0.25) {
  1329. //x-axis markers
  1330. strX = String(maxFreq*i);
  1331. strWidth = font.getStringWidthFloat(strX);
  1332. g.drawText(strX, pvsTableData->getX()+((pvsTableData->getWidth()*i)-(strWidth/2)), pvsTableData->getBottom()+10,
  1333. strWidth, font.getHeight(), 36, false);
  1334. //y-axis markers
  1335. strY = String(maxAmp*i);
  1336. strWidth = font.getStringWidthFloat(strY);
  1337. g.drawText(strY, pvsTableData->getX()-(strWidth+10),
  1338. (pvsTableData->getBottom()-(pvsTableData->getHeight()*i)) - (font.getHeight()/2),
  1339. strWidth, font.getHeight(), 36, false);
  1340. }
  1341. g.setColour (CabbageUtils::getComponentFontColour());
  1342. Font labelFont = CabbageUtils::getComponentFont();
  1343. String xLabel = "Frequency (Hz)";
  1344. strWidth = labelFont.getStringWidthFloat(xLabel);
  1345. g.setFont(labelFont);
  1346. g.drawText(xLabel, pvsTableData->getX()+((pvsTableData->getWidth()/2)-strWidth/2), getHeight()-(labelFont.getHeight()+10),
  1347. strWidth, labelFont.getHeight(), 36, false);
  1348. String yLabel = "Amplitude";
  1349. strWidth = labelFont.getStringWidthFloat(yLabel);
  1350. //g.drawTextAsPath(yLabel, AffineTransform::identity.rotated(4.7, 150, pvsTableData->getHeight()*0.66));
  1351. ImageCache::addImageToCache(bg, 20);
  1352. }
  1353. void paint(Graphics &g)
  1354. {
  1355. Image img = ImageCache::getFromHashCode(20);
  1356. g.drawImage(img, 0, 0, getWidth(), getHeight(), 0, 0, img.getWidth(), img.getHeight(), false);
  1357. }
  1358. private:
  1359. ScopedPointer<CabbagePVSTableData> pvsTableData;
  1360. String text;
  1361. int minFreq, maxFreq;
  1362. float maxAmp;
  1363. Image bg;
  1364. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePVSView);
  1365. };
  1366. #endif
  1367. //==============================================================================
  1368. // custom SnapshotControl, used for saving and recalling presets
  1369. //==============================================================================
  1370. class CabbageSnapshot : public Component,
  1371. public Button::Listener,
  1372. public ActionBroadcaster,
  1373. public ComboBox::Listener
  1374. {
  1375. ScopedPointer<TextButton> button;
  1376. ScopedPointer<GroupComponent> groupbox;
  1377. String name, preset, presetFileText;
  1378. int offX, offY, offWidth, offHeight;
  1379. bool masterSnapshot;
  1380. public:
  1381. ScopedPointer<ComboBox> combobox;
  1382. CabbageSnapshot(String compName, String caption, String presetName, bool master):masterSnapshot(master), name(compName), preset(presetName){
  1383. name << "|snapshot:";
  1384. preset << "|snapshot:";
  1385. setName(name);
  1386. offX=offY=offWidth=offHeight=0;
  1387. groupbox = new GroupComponent(String("groupbox_")+name);
  1388. combobox = new ComboBox(name);
  1389. combobox->addListener(this);
  1390. button = new TextButton("Snapshot");
  1391. button->addListener(this);
  1392. addAndMakeVisible(combobox);
  1393. addAndMakeVisible(groupbox);
  1394. addAndMakeVisible(button);
  1395. groupbox->setVisible(false);
  1396. //outline colour ID
  1397. groupbox->setColour(0x1005400,
  1398. Colours::findColourForName("white", Colours::white));
  1399. //text colour ID
  1400. groupbox->setColour(0x1005410,
  1401. Colours::findColourForName("white", Colours::white));
  1402. if(caption.length()>0){
  1403. offX=10;
  1404. offY=15;
  1405. offWidth=-20;
  1406. offHeight=-25;
  1407. groupbox->setVisible(true);
  1408. groupbox->setText(caption);
  1409. }
  1410. }
  1411. ~CabbageSnapshot(){}
  1412. void buttonClicked(Button* button){
  1413. //CabbageUtils::showMessage(name+"save;"+String(combobox->getText().trim()));
  1414. sendActionMessage(preset+"save;"+String(combobox->getText().trim())+String("?")+String(masterSnapshot));
  1415. }
  1416. void comboBoxChanged(ComboBox* combo){
  1417. sendActionMessage(preset+"load;"+String(combobox->getText().trim())+String("?")+String(masterSnapshot));
  1418. }
  1419. //---------------------------------------------
  1420. void resized()
  1421. {
  1422. groupbox->setBounds(0, 0, getWidth(), getHeight());
  1423. combobox->setBounds(offX, offY+2, (getWidth()+offWidth)*.60, (getHeight()+offHeight)*.8);
  1424. button->setBounds(offX+(getWidth()+offWidth)*.60+5, offY, (getWidth()+offWidth)*.35, getHeight()+offHeight);
  1425. }
  1426. };
  1427. //==============================================================================
  1428. // custom NumToggleButton
  1429. //==============================================================================
  1430. class CabbageNumToggle : public Component,
  1431. public ActionBroadcaster
  1432. {
  1433. String name;
  1434. Colour colour;
  1435. ScopedPointer<Label> label;
  1436. int width, height, value, lastValue;
  1437. bool buttonState, mouseButtonState;
  1438. public:
  1439. CabbageNumToggle(String name, int width, int height):
  1440. width(width),
  1441. height(height),
  1442. value(0),
  1443. lastValue(0),
  1444. buttonState(false),
  1445. mouseButtonState(false),
  1446. colour(Colours::lime)
  1447. {
  1448. setBounds(0, 0, width, height);
  1449. label = new Label();
  1450. label->setText("", dontSendNotification);
  1451. label->getProperties().set("textColour", "black");
  1452. label->setBounds(0, 0, width, height);
  1453. label->setEditable(false, true);
  1454. label->setInterceptsMouseClicks(false, true);
  1455. addAndMakeVisible(label);
  1456. label->toFront(true);
  1457. }
  1458. void mouseDrag (const MouseEvent &e){
  1459. if(e.mods.isRightButtonDown()&&buttonState)
  1460. if(e.getOffsetFromDragStart().getY()<0){
  1461. label->setText(String(value+(e.getDistanceFromDragStart()/2)), dontSendNotification);
  1462. lastValue = e.getDistanceFromDragStart()/2;
  1463. sendActionMessage(String("button:")+getName()+String("|state:")+String(buttonState)+String("|value:")+label->getText());
  1464. }
  1465. else{
  1466. label->setText(String(value-(e.getDistanceFromDragStart()/2)), dontSendNotification);
  1467. lastValue = value-(e.getDistanceFromDragStart()/2);
  1468. //send a message with the button number and its value
  1469. sendActionMessage(String("button:")+getName()+String("|state:")+String(buttonState)+String("|value:")+label->getText());
  1470. }
  1471. }
  1472. void mouseExit (const MouseEvent &e){
  1473. if(e.mods.isRightButtonDown())
  1474. value = lastValue;
  1475. }
  1476. void mouseDown(const MouseEvent &e){
  1477. if(e.mods.isLeftButtonDown())
  1478. if(getToggleState()){
  1479. buttonState=false;
  1480. repaint();
  1481. //send a message with the button number and its state
  1482. sendActionMessage(String("button:")+getName()+String("|state:")+String(buttonState)+String("|value:")+label->getText());
  1483. }
  1484. else{
  1485. buttonState=true;
  1486. repaint();
  1487. sendActionMessage(String("button:")+getName()+String("|state:")+String(buttonState)+String("|value:")+label->getText());
  1488. }
  1489. }
  1490. bool getToggleState(){
  1491. return buttonState;
  1492. }
  1493. void setToggleState(bool val){
  1494. buttonState = val;
  1495. }
  1496. int getCurrentValue(){
  1497. return label->getText().getIntValue();
  1498. }
  1499. void setActiveColour(String inColour){
  1500. colour = Colours::findColourForName(inColour, Colours::lime);
  1501. }
  1502. void paint(Graphics &g){
  1503. Image newButton = CabbageLookAndFeel::drawToggleImage (width, height, buttonState, colour, true);
  1504. g.drawImage(newButton, 0, 0, width, height, 0, 0, width, height);
  1505. }
  1506. };
  1507. //==============================================================================
  1508. // custom PatternMatrix
  1509. //==============================================================================
  1510. class PatternMatrix : public Component,
  1511. public Timer,
  1512. public ButtonListener,
  1513. public SliderListener,
  1514. public ActionListener
  1515. {
  1516. ScopedPointer<CabbageCheckbox> onoffButton;
  1517. ScopedPointer<Slider> bpm;
  1518. OwnedArray<Slider> pSliders;
  1519. float buttonIndex, updateVar, offX, offY, offWidth, offHeight,
  1520. noPatterns, noSteps, beat, currentStepButton, rCtrls;
  1521. bool timerActive;
  1522. public:
  1523. OwnedArray<CabbageNumToggle> stepButton;
  1524. CabbagePluginAudioProcessor* myFilter;
  1525. //---- constructor -----
  1526. PatternMatrix(String caption, int width, int height, StringArray patterns, int steps, int rctrls, CabbagePluginAudioProcessor* filter)
  1527. : timerActive(false), noSteps(steps),
  1528. noPatterns(patterns.size()), beat(0), myFilter(filter),
  1529. currentStepButton(0),
  1530. buttonIndex(0),
  1531. updateVar(0),
  1532. rCtrls(rctrls)
  1533. {
  1534. onoffButton = new CabbageCheckbox("Active", "", "", Colours::red.toString(), CabbageUtils::getComponentFontColour().toString(), true);
  1535. onoffButton->button->setButtonText("");
  1536. onoffButton->button->addListener(this);
  1537. //onoffButton->getProperties().set(Colours, "red");
  1538. onoffButton->setBounds(60, 25, 20, 20);
  1539. if(myFilter->patMatrixActive)
  1540. onoffButton->button->setToggleState(true, sendNotification);
  1541. addAndMakeVisible(onoffButton);
  1542. bpm = new Slider("bpm");
  1543. bpm->setSliderStyle(Slider::LinearBar);
  1544. bpm->setBounds(185, 27, 180, 15);
  1545. bpm->setRange(0, 1000, 1);
  1546. bpm->setValue(120);
  1547. bpm->addListener(this);
  1548. addAndMakeVisible(bpm);
  1549. myFilter->noSteps = noSteps;
  1550. myFilter->noPatterns = noPatterns;
  1551. myFilter->patternNames = patterns;
  1552. Rectangle<int> pattRect;
  1553. //set bounds for pattern rectangle
  1554. pattRect.setBounds(60, 50, width-(rCtrls*40)-60, (height-50)*.95);
  1555. //set bounds for slider rectangle
  1556. Rectangle<int> slidersRect;
  1557. slidersRect.setBounds(pattRect.getWidth()+60, 50, width-pattRect.getWidth()+60, (height-50)*.95);
  1558. //populate matrix with step buttons
  1559. if(myFilter->patStepMatrix.size()==0)
  1560. {
  1561. for(int pats=0;pats<patterns.size();pats++)
  1562. for(int beats=0;beats<steps;beats++){
  1563. stepButton.add(new CabbageNumToggle("", (pattRect.getWidth()/noSteps), (pattRect.getHeight()/patterns.size())));
  1564. stepButton[stepButton.size()-1]->addActionListener(this);
  1565. stepButton[stepButton.size()-1]->setName(String(stepButton.size()-1));
  1566. // stepButton[stepButton.size()-1]->setToggleState(myFilter->patStepMatrix[stepButton.size()-1].state);
  1567. CabbagePatternMatrixStepData patMat;
  1568. myFilter->patStepMatrix.add(patMat);
  1569. stepButton[stepButton.size()-1]->setTopLeftPosition(pattRect.getX()+(beats*(pattRect.getWidth()/noSteps)), pats*(pattRect.getHeight())/patterns.size()+pattRect.getY());
  1570. addAndMakeVisible(stepButton[stepButton.size()-1]);
  1571. }
  1572. }
  1573. else{
  1574. for(int pats=0;pats<patterns.size();pats++)
  1575. for(int beats=0;beats<steps;beats++){
  1576. stepButton.add(new CabbageNumToggle("", (pattRect.getWidth()/noSteps), (pattRect.getHeight()/patterns.size())));
  1577. stepButton[stepButton.size()-1]->addActionListener(this);
  1578. stepButton[stepButton.size()-1]->setName(String(stepButton.size()-1));
  1579. stepButton[stepButton.size()-1]->setToggleState(myFilter->patStepMatrix[stepButton.size()-1].state);
  1580. //CabbagePatternMatrixStepData patMat;
  1581. //myFilter->patStepMatrix.add(patMat);
  1582. stepButton[stepButton.size()-1]->setTopLeftPosition(pattRect.getX()+(beats*(pattRect.getWidth()/noSteps)), pats*(pattRect.getHeight())/patterns.size()+pattRect.getY());
  1583. addAndMakeVisible(stepButton[stepButton.size()-1]);
  1584. }
  1585. }
  1586. //add p-field controls if needed
  1587. for(int pats=0;pats<patterns.size();pats++){
  1588. for(int i=0;i<rCtrls;i++){
  1589. pSliders.add(new Slider());
  1590. pSliders[pSliders.size()-1]->setSliderStyle(Slider::RotaryVerticalDrag);
  1591. pSliders[pSliders.size()-1]->addListener(this);
  1592. pSliders[pSliders.size()-1]->setRange(0, 127, 1);
  1593. pSliders[pSliders.size()-1]->setTextBoxIsEditable(true);
  1594. pSliders[pSliders.size()-1]->showTextBox();
  1595. String sliderName("row:"+String(pats)+"|ctrl:"+String(i));
  1596. CabbagePatternMatrixPfieldData patMat;
  1597. myFilter->patPfieldMatrix.add(patMat);
  1598. pSliders[pSliders.size()-1]->getProperties().set("data", var(sliderName));
  1599. pSliders[pSliders.size()-1]->setBounds(slidersRect.getX()+(i*40), (((pats*(slidersRect.getHeight())/patterns.size())))+slidersRect.getY(), 40, 40);
  1600. addAndMakeVisible(pSliders[pSliders.size()-1]);
  1601. }
  1602. }
  1603. }
  1604. ~PatternMatrix(){
  1605. }
  1606. void actionListenerCallback(const juce::String &value)
  1607. {
  1608. //button:1|state:1|value:127
  1609. //sort out buttons first
  1610. if(value.contains("button")){
  1611. String buttonNum(value.substring(value.indexOf("button:")+7, value.indexOf("|st")));
  1612. String buttonState(value.substring(value.indexOf("|state:")+7, value.indexOf("|val")));
  1613. String buttonValue(value.substring(value.indexOf("|value:")+7, value.length()));
  1614. if(buttonState.getIntValue()==1){
  1615. myFilter->patStepMatrix.getReference(buttonNum.getIntValue()).state = buttonState.getIntValue();
  1616. myFilter->patStepMatrix.getReference(buttonNum.getIntValue()).p4 = buttonValue.getIntValue();
  1617. }
  1618. else
  1619. myFilter->patStepMatrix.getReference(buttonNum.getIntValue()).state = buttonState.getIntValue();
  1620. }
  1621. //and now sliders
  1622. }
  1623. void sliderValueChanged(juce::Slider *slider){
  1624. String data = slider->getProperties().getWithDefault("data", String("").contains("row"));
  1625. if(data.contains("row")){
  1626. String sliderRow(data.substring(data.indexOf("row:")+4, data.indexOf("|ctr")));
  1627. String sliderCtrl(data.substring(data.indexOf("|ctrl:")+6, data.length()));
  1628. if(sliderCtrl=="0")
  1629. myFilter->patPfieldMatrix.getReference(sliderRow.getIntValue()).p5 = slider->getValue();
  1630. else if(sliderCtrl=="1")
  1631. myFilter->patPfieldMatrix.getReference(sliderRow.getIntValue()).p6 = slider->getValue();
  1632. else if(sliderCtrl=="2")
  1633. myFilter->patPfieldMatrix.getReference(sliderRow.getIntValue()).p7 = slider->getValue();
  1634. else if(sliderCtrl=="3")
  1635. myFilter->patPfieldMatrix.getReference(sliderRow.getIntValue()).p8 = slider->getValue();
  1636. else if(sliderCtrl=="4")
  1637. myFilter->patPfieldMatrix.getReference(sliderRow.getIntValue()).p9 = slider->getValue();
  1638. }
  1639. }
  1640. void sliderDragEnded(Slider* slider)
  1641. {
  1642. if(slider->getName()=="bpm"){
  1643. myFilter->bpm = slider->getValue();
  1644. myFilter->timeCounter = 0;
  1645. this->startTimer(15);
  1646. }
  1647. }
  1648. void buttonClicked(Button *button)
  1649. {
  1650. if(button->getName()=="Active"){
  1651. if(button->getToggleState()){
  1652. this->startTimer(15);
  1653. myFilter->patMatrixActive=1;
  1654. }
  1655. else{
  1656. this->stopTimer();
  1657. timerActive = false;
  1658. myFilter->patMatrixActive=0;
  1659. }
  1660. }
  1661. }
  1662. void timerCallback(){
  1663. for(int u=0;u<stepButton.size();u++){
  1664. if(stepButton[u]->getToggleState()==1){
  1665. stepButton[u]->setActiveColour("lime");
  1666. stepButton[u]->repaint();
  1667. }
  1668. }
  1669. for(int y=0;y<noPatterns;y++){
  1670. //Logger::writeToLog(String(myFilter->beat+(y*noSteps)));
  1671. if(stepButton[myFilter->beat+(y*noSteps)]->getToggleState()==1){
  1672. stepButton[myFilter->beat+(y*noSteps)]->setActiveColour("yellow");
  1673. stepButton[myFilter->beat+(y*noSteps)]->repaint();
  1674. }
  1675. }
  1676. }
  1677. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PatternMatrix);
  1678. };
  1679. //==============================================================================
  1680. // CabbagePatternMatrix
  1681. //==============================================================================
  1682. class CabbagePatternMatrix : public Component
  1683. {
  1684. int offX, offY, offWidth, offHeight, tableSize, width, height, rCtrls;
  1685. String caption;
  1686. StringArray patterns;
  1687. public:
  1688. ScopedPointer<PatternMatrix> patternMatrix;
  1689. CabbagePluginAudioProcessor* myFilter;
  1690. //---- constructor -----
  1691. CabbagePatternMatrix(CabbagePluginAudioProcessor* filter, String name, int width, int height, String caption, StringArray patterns, int steps, int rctrls)
  1692. : myFilter(filter), height(height), width(width), caption(caption), patterns(patterns), rCtrls(rctrls)
  1693. {
  1694. setName(name);
  1695. offX=offY=offWidth=offHeight=0;
  1696. patternMatrix = new PatternMatrix(caption, width, height, patterns, steps, rCtrls, myFilter);
  1697. addAndMakeVisible(patternMatrix);
  1698. this->setWantsKeyboardFocus(false);
  1699. }
  1700. //---------------------------------------------
  1701. ~CabbagePatternMatrix(){
  1702. }
  1703. void paint(Graphics& g){
  1704. //----- Background
  1705. Colour bg = Colours::white;
  1706. g.setColour (bg);
  1707. g.fillRoundedRectangle (0, 0, width, height, 5);
  1708. //----- Outline
  1709. g.setColour (CabbageUtils::getComponentFontColour());
  1710. g.setOpacity (0.1);
  1711. g.drawRoundedRectangle (0.5, 0.5, width-1, height-1, 5, 1);
  1712. Font font (String("Impact"), 14, 0);
  1713. font.setFallbackFontName (String("Verdana")); //in case the user doesn't have the first font installed
  1714. g.setFont (font);
  1715. Justification just (4);
  1716. g.setColour (Colours::black);
  1717. String name = CabbageUtils::cabbageString (caption, font, width);
  1718. g.drawText (name, 0, 5, width, 13, just, false);
  1719. g.drawLine (10, 20, width-10, 20, 0.3);
  1720. for(int i=0;i<patterns.size();i++){
  1721. Justification just (4);
  1722. g.setColour (Colours::black);
  1723. String name = CabbageUtils::cabbageString (patterns[i], font, 60);
  1724. g.drawText(name, 0, (i*((height-50)/patterns.size()*.90))+50, 60, (height/patterns.size())*.90, just, false);
  1725. }
  1726. g.drawText("Active", 70, 25, 60, 20, just, false);
  1727. g.drawText("BPM", 140, 25, 60, 20, just, false);
  1728. }
  1729. //---------------------------------------------
  1730. void resized()
  1731. {
  1732. patternMatrix->setBounds(offX, offY, getWidth()+offWidth, getHeight()+offHeight);
  1733. this->setWantsKeyboardFocus(false);
  1734. }
  1735. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePatternMatrix);
  1736. };
  1737. //==============================================================================
  1738. // custom soundfiler
  1739. //==============================================================================
  1740. class CabbageSoundfiler : public Component
  1741. {
  1742. ScopedPointer<Soundfiler> soundFiler;
  1743. //---- constructor -----
  1744. public:
  1745. CabbageSoundfiler (String name, String file, String colour, String fontcolour, CabbageAudioSource &audioSource, int sr)
  1746. {
  1747. setName(name);
  1748. soundFiler = new Soundfiler(audioSource, file, sr, Colour::fromString(colour), Colour::fromString(fontcolour));
  1749. addAndMakeVisible(soundFiler);
  1750. }
  1751. ~CabbageSoundfiler()
  1752. {
  1753. }
  1754. void resized()
  1755. {
  1756. soundFiler->setBounds(0, 0, getWidth(), getHeight());
  1757. }
  1758. void paint(Graphics& g)
  1759. {
  1760. }
  1761. private:
  1762. String text, colour;
  1763. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageSoundfiler);
  1764. };
  1765. //==============================================================================
  1766. // custom CabbageLabel
  1767. //==============================================================================
  1768. class CabbageLabel : public Component
  1769. {
  1770. public:
  1771. CabbageLabel (String text, String colour)
  1772. : text(text), colour(colour)
  1773. {
  1774. }
  1775. ~CabbageLabel()
  1776. {
  1777. }
  1778. void resized()
  1779. {
  1780. }
  1781. void paint(Graphics& g)
  1782. {
  1783. g.setColour(Colour::fromString(colour));
  1784. g.setFont(CabbageUtils::getComponentFont());
  1785. g.setFont(getHeight());
  1786. g.drawFittedText(text, 0, 0, getWidth(), getHeight(), Justification::left, 1, 1);
  1787. }
  1788. private:
  1789. String text, colour;
  1790. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageLabel);
  1791. };
  1792. //==============================================================================
  1793. // custom CabbageTransportControl
  1794. //==============================================================================
  1795. /*
  1796. * this will need a fast forward, skip to start, play/pause and
  1797. */
  1798. class CabbageTransportControl : public Component
  1799. {
  1800. ScopedPointer<ImageButton> playButton;
  1801. ScopedPointer<ImageButton> skipToStartButton;
  1802. ScopedPointer<ImageButton> skipToEndButton;
  1803. public:
  1804. CabbageTransportControl(int width, int height){
  1805. playButton = new ImageButton("Play button");
  1806. addAndMakeVisible(playButton);
  1807. skipToStartButton = new ImageButton("Skip to start button");
  1808. addAndMakeVisible(skipToStartButton);
  1809. skipToEndButton = new ImageButton("Skip to end button");
  1810. addAndMakeVisible(skipToEndButton);
  1811. //playButton->setToggleState(false, true);
  1812. playButton->setClickingTogglesState(true);
  1813. //playButton->setState(Button::buttonDown);
  1814. /*
  1815. playButton->setImages(false, true, true,
  1816. CabbageUtils::drawSoundfilerButton("play_normal"), 1.0f, Colours::transparentBlack,
  1817. CabbageUtils::drawSoundfilerButton("play_hover"), 1.0f, Colours::transparentBlack,
  1818. CabbageUtils::drawSoundfilerButton("play_down"), 1.0f, Colours::transparentBlack);
  1819. skipToStartButton->setImages(false, true, true,
  1820. CabbageUtils::drawSoundfilerButton("skip_start_normal"), 1.0f, Colours::transparentBlack,
  1821. CabbageUtils::drawSoundfilerButton("skip_start_hover"), 1.0f, Colours::transparentBlack,
  1822. CabbageUtils::drawSoundfilerButton("skip_start_down"), 1.0f, Colours::transparentBlack);
  1823. skipToEndButton->setImages(false, true, true,
  1824. CabbageUtils::drawSoundfilerButton("skip_end_normal"), 1.0f, Colours::transparentBlack,
  1825. CabbageUtils::drawSoundfilerButton("skip_end_hover"), 1.0f, Colours::transparentBlack,
  1826. CabbageUtils::drawSoundfilerButton("skip_end_down"), 1.0f, Colours::transparentBlack);
  1827. */
  1828. }
  1829. ~CabbageTransportControl(){}
  1830. void resized()
  1831. {
  1832. int numOfButtons = 3;
  1833. float buttonWidth = getWidth() / (numOfButtons+1); //jmin(getHeight()*0.8f, (float)getWidth()/(numOfButtons+1));
  1834. float buttonGap = buttonWidth / (numOfButtons+1); //(getWidth()-(buttonWidth*numOfButtons)) / numOfButtons;
  1835. float buttonHeight = getHeight() - (buttonGap*2);
  1836. skipToStartButton->setBounds(buttonGap, buttonGap, buttonWidth, buttonHeight);
  1837. playButton->setBounds(buttonGap*2 + buttonWidth, buttonGap, buttonWidth, buttonHeight);
  1838. skipToEndButton->setBounds(buttonGap*3 + buttonWidth*2, buttonGap, buttonWidth, buttonHeight);
  1839. }
  1840. void paint(Graphics& g)
  1841. {
  1842. //g.setColour(CabbageUtils::getDarkerBackgroundSkin());
  1843. g.setColour(Colours::lightgrey);
  1844. g.fillAll();
  1845. }
  1846. };
  1847. //==============================================================================
  1848. // custom CabbageLine
  1849. //==============================================================================
  1850. class CabbageLine : public Component
  1851. {
  1852. Colour col;
  1853. public:
  1854. CabbageLine (bool isHorizontal, String colour)
  1855. : isHorizontal(isHorizontal)
  1856. {
  1857. col = Colour::fromString(colour);
  1858. }
  1859. ~CabbageLine()
  1860. {
  1861. }
  1862. void resized()
  1863. {
  1864. if (isHorizontal == true)
  1865. this->setBounds(getX(), getY(), getWidth(), getHeight());
  1866. else
  1867. this->setBounds(getX(), getY(), getWidth(), getHeight());
  1868. this->setAlpha(0.7);
  1869. }
  1870. void paint(Graphics& g)
  1871. {
  1872. g.setColour (col);
  1873. g.fillRoundedRectangle(0, 0, getWidth(), getHeight(), 1);
  1874. g.setColour (CabbageUtils::getBackgroundSkin());
  1875. g.fillRoundedRectangle (0, 0, getWidth()-1, getHeight()-1, 1);
  1876. }
  1877. private:
  1878. bool isHorizontal;
  1879. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageLine);
  1880. };
  1881. //==============================================================================
  1882. // custom Cabbage display widget
  1883. //==============================================================================
  1884. class CabbageDisplay : public Component
  1885. {
  1886. public:
  1887. CabbageDisplay ()
  1888. {
  1889. #ifndef Cabbage_No_Csound
  1890. winData = nullptr;
  1891. #endif
  1892. }
  1893. ~CabbageDisplay()
  1894. {
  1895. }
  1896. void resized()
  1897. {
  1898. }
  1899. #ifndef Cabbage_No_Csound
  1900. void updateData(WINDAT* windat)
  1901. {
  1902. winData = windat;
  1903. }
  1904. void paint(Graphics& g)
  1905. {
  1906. g.setColour (Colours::white);
  1907. //draw PVS data
  1908. if(winData!=nullptr)
  1909. for (int i=0; i<winData->npts; i++) {
  1910. if (winData->fdata[i]) {
  1911. int amp = winData->fdata[i];
  1912. g.drawLine((i/winData->npts)*getWidth(), getHeight()-(amp*getHeight()),
  1913. (i/winData->npts)*getWidth(), getHeight(), 1);
  1914. }
  1915. }
  1916. }
  1917. WINDAT* winData;
  1918. #endif
  1919. private:
  1920. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageDisplay);
  1921. };
  1922. #endif