The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
6.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. class ChannelClickListener
  20. {
  21. public:
  22. virtual ~ChannelClickListener() {}
  23. virtual void channelButtonClicked (int channelIndex) = 0;
  24. virtual bool isChannelActive (int channelIndex) = 0;
  25. };
  26. class SurroundEditor : public AudioProcessorEditor,
  27. public ButtonListener,
  28. private Timer
  29. {
  30. public:
  31. SurroundEditor (AudioProcessor& parent)
  32. : AudioProcessorEditor (parent),
  33. currentChannelLayout (AudioChannelSet::disabled()),
  34. noChannelsLabel ("noChannelsLabel", "Input disabled"),
  35. layoutTitle ("LayoutTitleLabel", getLayoutName())
  36. {
  37. layoutTitle.setJustificationType (Justification::centred);
  38. addAndMakeVisible (layoutTitle);
  39. addAndMakeVisible (noChannelsLabel);
  40. setSize (640, 64);
  41. lastSuspended = ! getAudioProcessor()->isSuspended();
  42. timerCallback();
  43. startTimer (500);
  44. }
  45. ~SurroundEditor()
  46. {
  47. }
  48. void resized() override
  49. {
  50. Rectangle<int> r = getLocalBounds();
  51. layoutTitle.setBounds (r.removeFromBottom (16));
  52. noChannelsLabel.setBounds (r);
  53. if (channelButtons.size() > 0)
  54. {
  55. const int buttonWidth = r.getWidth() / channelButtons.size();
  56. for (int i = 0; i < channelButtons.size(); ++i)
  57. channelButtons[i]->setBounds (r.removeFromLeft (buttonWidth));
  58. }
  59. }
  60. void paint (Graphics& g) override
  61. {
  62. g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
  63. }
  64. void buttonClicked (Button* btn) override
  65. {
  66. if (TextButton* textButton = dynamic_cast<TextButton*> (btn))
  67. {
  68. const int channelIndex = channelButtons.indexOf (textButton);
  69. if (ChannelClickListener* listener = dynamic_cast<ChannelClickListener*> (getAudioProcessor()))
  70. listener->channelButtonClicked (channelIndex);
  71. }
  72. }
  73. void updateGUI()
  74. {
  75. const AudioChannelSet& channelSet = getAudioProcessor()->getChannelLayoutOfBus (false, 0);
  76. if (channelSet != currentChannelLayout)
  77. {
  78. currentChannelLayout = channelSet;
  79. layoutTitle.setText (currentChannelLayout.getDescription(), NotificationType::dontSendNotification);
  80. channelButtons.clear();
  81. activeChannels.resize (currentChannelLayout.size());
  82. if (currentChannelLayout == AudioChannelSet::disabled())
  83. {
  84. noChannelsLabel.setVisible (true);
  85. }
  86. else
  87. {
  88. const int numChannels = currentChannelLayout.size();
  89. for (int i = 0; i < numChannels; ++i)
  90. {
  91. const String channelName =
  92. AudioChannelSet::getAbbreviatedChannelTypeName (currentChannelLayout.getTypeOfChannel (i));
  93. TextButton* newButton;
  94. channelButtons.add (newButton = new TextButton (channelName, channelName));
  95. newButton->addListener (this);
  96. addAndMakeVisible (newButton);
  97. }
  98. noChannelsLabel.setVisible (false);
  99. resized();
  100. }
  101. if (ChannelClickListener* listener = dynamic_cast<ChannelClickListener*> (getAudioProcessor()))
  102. {
  103. const auto activeColour = getLookAndFeel().findColour (Slider::thumbColourId);
  104. const auto inactiveColour = getLookAndFeel().findColour (Slider::trackColourId);
  105. for (int i = 0; i < activeChannels.size(); ++i)
  106. {
  107. bool isActive = listener->isChannelActive (i);
  108. activeChannels.getReference (i) = isActive;
  109. channelButtons [i]->setColour (TextButton::buttonColourId, isActive ? activeColour : inactiveColour);
  110. channelButtons [i]->repaint();
  111. }
  112. }
  113. }
  114. }
  115. private:
  116. String getLayoutName() const
  117. {
  118. if (AudioProcessor* p = getAudioProcessor())
  119. return p->getChannelLayoutOfBus (false, 0).getDescription();
  120. return "Unknown";
  121. }
  122. void timerCallback() override
  123. {
  124. if (getAudioProcessor()->isSuspended() != lastSuspended)
  125. {
  126. lastSuspended = getAudioProcessor()->isSuspended();
  127. updateGUI();
  128. }
  129. if (! lastSuspended)
  130. {
  131. if (ChannelClickListener* listener = dynamic_cast<ChannelClickListener*> (getAudioProcessor()))
  132. {
  133. const auto activeColour = getLookAndFeel().findColour (Slider::thumbColourId);
  134. const auto inactiveColour = getLookAndFeel().findColour (Slider::trackColourId);
  135. for (int i = 0; i < activeChannels.size(); ++i)
  136. {
  137. bool isActive = listener->isChannelActive (i);
  138. if (activeChannels.getReference (i) != isActive)
  139. {
  140. activeChannels.getReference (i) = isActive;
  141. channelButtons [i]->setColour (TextButton::buttonColourId, isActive ? activeColour : inactiveColour);
  142. channelButtons [i]->repaint();
  143. }
  144. }
  145. }
  146. }
  147. }
  148. AudioChannelSet currentChannelLayout;
  149. Label noChannelsLabel, layoutTitle;
  150. OwnedArray<TextButton> channelButtons;
  151. Array<bool> activeChannels;
  152. bool lastSuspended;
  153. };