Audio plugin host https://kx.studio/carla
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.

276 lines
8.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. //==============================================================================
  21. class ChoiceRemapperValueSource : public Value::ValueSource,
  22. private Value::Listener
  23. {
  24. public:
  25. ChoiceRemapperValueSource (const Value& source, const Array<var>& map)
  26. : sourceValue (source),
  27. mappings (map)
  28. {
  29. sourceValue.addListener (this);
  30. }
  31. var getValue() const override
  32. {
  33. auto targetValue = sourceValue.getValue();
  34. for (auto& map : mappings)
  35. if (map.equalsWithSameType (targetValue))
  36. return mappings.indexOf (map) + 1;
  37. return mappings.indexOf (targetValue) + 1;
  38. }
  39. void setValue (const var& newValue) override
  40. {
  41. auto remappedVal = mappings [static_cast<int> (newValue) - 1];
  42. if (! remappedVal.equalsWithSameType (sourceValue))
  43. sourceValue = remappedVal;
  44. }
  45. protected:
  46. Value sourceValue;
  47. Array<var> mappings;
  48. void valueChanged (Value&) override { sendChangeMessage (true); }
  49. //==============================================================================
  50. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChoiceRemapperValueSource)
  51. };
  52. //==============================================================================
  53. class ChoiceRemapperValueSourceWithDefault : public Value::ValueSource,
  54. private Value::Listener
  55. {
  56. public:
  57. ChoiceRemapperValueSourceWithDefault (const ValueTreePropertyWithDefault& v, const Array<var>& map)
  58. : value (v),
  59. sourceValue (value.getPropertyAsValue()),
  60. mappings (map)
  61. {
  62. sourceValue.addListener (this);
  63. }
  64. var getValue() const override
  65. {
  66. if (! value.isUsingDefault())
  67. {
  68. const auto target = sourceValue.getValue();
  69. const auto equalsWithSameType = [&target] (const var& map) { return map.equalsWithSameType (target); };
  70. auto iter = std::find_if (mappings.begin(), mappings.end(), equalsWithSameType);
  71. if (iter == mappings.end())
  72. iter = std::find (mappings.begin(), mappings.end(), target);
  73. if (iter != mappings.end())
  74. return 1 + (int) std::distance (mappings.begin(), iter);
  75. }
  76. return -1;
  77. }
  78. void setValue (const var& newValue) override
  79. {
  80. auto newValueInt = static_cast<int> (newValue);
  81. if (newValueInt == -1)
  82. {
  83. value.resetToDefault();
  84. }
  85. else
  86. {
  87. auto remappedVal = mappings [newValueInt - 1];
  88. if (! remappedVal.equalsWithSameType (sourceValue))
  89. value = remappedVal;
  90. }
  91. }
  92. private:
  93. void valueChanged (Value&) override { sendChangeMessage (true); }
  94. ValueTreePropertyWithDefault value;
  95. Value sourceValue;
  96. Array<var> mappings;
  97. //==============================================================================
  98. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChoiceRemapperValueSourceWithDefault)
  99. };
  100. //==============================================================================
  101. ChoicePropertyComponent::ChoicePropertyComponent (const String& name)
  102. : PropertyComponent (name),
  103. isCustomClass (true)
  104. {
  105. }
  106. ChoicePropertyComponent::ChoicePropertyComponent (const String& name,
  107. const StringArray& choiceList,
  108. const Array<var>& correspondingValues)
  109. : PropertyComponent (name),
  110. choices (choiceList)
  111. {
  112. // The array of corresponding values must contain one value for each of the items in
  113. // the choices array!
  114. jassertquiet (correspondingValues.size() == choices.size());
  115. }
  116. ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
  117. const String& name,
  118. const StringArray& choiceList,
  119. const Array<var>& correspondingValues)
  120. : ChoicePropertyComponent (name, choiceList, correspondingValues)
  121. {
  122. refreshChoices();
  123. initialiseComboBox (Value (new ChoiceRemapperValueSource (valueToControl, correspondingValues)));
  124. }
  125. ChoicePropertyComponent::ChoicePropertyComponent (const ValueTreePropertyWithDefault& valueToControl,
  126. const String& name,
  127. const StringArray& choiceList,
  128. const Array<var>& correspondingValues)
  129. : ChoicePropertyComponent (name, choiceList, correspondingValues)
  130. {
  131. value = valueToControl;
  132. auto getDefaultString = [this, correspondingValues] { return choices [correspondingValues.indexOf (value.getDefault())]; };
  133. refreshChoices (getDefaultString());
  134. initialiseComboBox (Value (new ChoiceRemapperValueSourceWithDefault (value, correspondingValues)));
  135. value.onDefaultChange = [this, getDefaultString]
  136. {
  137. auto selectedId = comboBox.getSelectedId();
  138. refreshChoices (getDefaultString());
  139. comboBox.setSelectedId (selectedId);
  140. };
  141. }
  142. ChoicePropertyComponent::ChoicePropertyComponent (const ValueTreePropertyWithDefault& valueToControl,
  143. const String& name)
  144. : PropertyComponent (name),
  145. choices ({ "Enabled", "Disabled" })
  146. {
  147. value = valueToControl;
  148. auto getDefaultString = [this] { return value.getDefault() ? "Enabled" : "Disabled"; };
  149. refreshChoices (getDefaultString());
  150. initialiseComboBox (Value (new ChoiceRemapperValueSourceWithDefault (value, { true, false })));
  151. value.onDefaultChange = [this, getDefaultString]
  152. {
  153. auto selectedId = comboBox.getSelectedId();
  154. refreshChoices (getDefaultString());
  155. comboBox.setSelectedId (selectedId);
  156. };
  157. }
  158. //==============================================================================
  159. void ChoicePropertyComponent::initialiseComboBox (const Value& v)
  160. {
  161. if (v != Value())
  162. comboBox.setSelectedId (v.getValue(), dontSendNotification);
  163. comboBox.getSelectedIdAsValue().referTo (v);
  164. comboBox.setEditableText (false);
  165. addAndMakeVisible (comboBox);
  166. }
  167. void ChoicePropertyComponent::refreshChoices()
  168. {
  169. comboBox.clear();
  170. for (int i = 0; i < choices.size(); ++i)
  171. {
  172. const auto& choice = choices[i];
  173. if (choice.isNotEmpty())
  174. comboBox.addItem (choice, i + 1);
  175. else
  176. comboBox.addSeparator();
  177. }
  178. }
  179. void ChoicePropertyComponent::refreshChoices (const String& defaultString)
  180. {
  181. refreshChoices();
  182. comboBox.addItem ("Default" + (defaultString.isNotEmpty() ? " (" + defaultString + ")" : ""), -1);
  183. }
  184. //==============================================================================
  185. void ChoicePropertyComponent::setIndex (const int /*newIndex*/)
  186. {
  187. jassertfalse; // you need to override this method in your subclass!
  188. }
  189. int ChoicePropertyComponent::getIndex() const
  190. {
  191. jassertfalse; // you need to override this method in your subclass!
  192. return -1;
  193. }
  194. const StringArray& ChoicePropertyComponent::getChoices() const
  195. {
  196. return choices;
  197. }
  198. //==============================================================================
  199. void ChoicePropertyComponent::refresh()
  200. {
  201. if (isCustomClass)
  202. {
  203. if (! comboBox.isVisible())
  204. {
  205. refreshChoices();
  206. initialiseComboBox ({});
  207. comboBox.onChange = [this] { changeIndex(); };
  208. }
  209. comboBox.setSelectedId (getIndex() + 1, dontSendNotification);
  210. }
  211. }
  212. void ChoicePropertyComponent::changeIndex()
  213. {
  214. if (isCustomClass)
  215. {
  216. auto newIndex = comboBox.getSelectedId() - 1;
  217. if (newIndex != getIndex())
  218. setIndex (newIndex);
  219. }
  220. }
  221. } // namespace juce