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.

292 lines
9.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - 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 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-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 ChoicePropertyComponent::RemapperValueSource : public Value::ValueSource,
  22. private Value::Listener
  23. {
  24. public:
  25. RemapperValueSource (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 (RemapperValueSource)
  51. };
  52. //==============================================================================
  53. class ChoicePropertyComponent::RemapperValueSourceWithDefault : public Value::ValueSource,
  54. private Value::Listener
  55. {
  56. public:
  57. RemapperValueSourceWithDefault (ValueWithDefault* vwd, const Array<var>& map)
  58. : valueWithDefault (vwd),
  59. sourceValue (valueWithDefault->getPropertyAsValue()),
  60. mappings (map)
  61. {
  62. sourceValue.addListener (this);
  63. }
  64. var getValue() const override
  65. {
  66. if (valueWithDefault == nullptr)
  67. return {};
  68. if (valueWithDefault->isUsingDefault())
  69. return -1;
  70. auto targetValue = sourceValue.getValue();
  71. for (auto map : mappings)
  72. if (map.equalsWithSameType (targetValue))
  73. return mappings.indexOf (map) + 1;
  74. return mappings.indexOf (targetValue) + 1;
  75. }
  76. void setValue (const var& newValue) override
  77. {
  78. if (valueWithDefault == nullptr)
  79. return;
  80. auto newValueInt = static_cast<int> (newValue);
  81. if (newValueInt == -1)
  82. {
  83. valueWithDefault->resetToDefault();
  84. }
  85. else
  86. {
  87. auto remappedVal = mappings [newValueInt - 1];
  88. if (! remappedVal.equalsWithSameType (sourceValue))
  89. *valueWithDefault = remappedVal;
  90. }
  91. }
  92. private:
  93. void valueChanged (Value&) override { sendChangeMessage (true); }
  94. WeakReference<ValueWithDefault> valueWithDefault;
  95. Value sourceValue;
  96. Array<var> mappings;
  97. //==============================================================================
  98. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSourceWithDefault)
  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. jassert (correspondingValues.size() == choices.size());
  115. ignoreUnused (correspondingValues);
  116. }
  117. ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
  118. const String& name,
  119. const StringArray& choiceList,
  120. const Array<var>& correspondingValues)
  121. : ChoicePropertyComponent (name, choiceList, correspondingValues)
  122. {
  123. createComboBox();
  124. comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSource (valueToControl,
  125. correspondingValues)));
  126. }
  127. ChoicePropertyComponent::ChoicePropertyComponent (ValueWithDefault& valueToControl,
  128. const String& name,
  129. const StringArray& choiceList,
  130. const Array<var>& correspondingValues)
  131. : ChoicePropertyComponent (name, choiceList, correspondingValues)
  132. {
  133. valueWithDefault = &valueToControl;
  134. createComboBoxWithDefault (choiceList [correspondingValues.indexOf (valueWithDefault->getDefault())]);
  135. comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSourceWithDefault (valueWithDefault,
  136. correspondingValues)));
  137. valueWithDefault->onDefaultChange = [this, choiceList, correspondingValues]
  138. {
  139. auto selectedId = comboBox.getSelectedId();
  140. comboBox.clear();
  141. createComboBoxWithDefault (choiceList [correspondingValues.indexOf (valueWithDefault->getDefault())]);
  142. comboBox.setSelectedId (selectedId);
  143. };
  144. }
  145. ChoicePropertyComponent::ChoicePropertyComponent (ValueWithDefault& valueToControl,
  146. const String& name)
  147. : PropertyComponent (name),
  148. choices ({ "Enabled", "Disabled" })
  149. {
  150. valueWithDefault = &valueToControl;
  151. createComboBoxWithDefault (valueWithDefault->getDefault() ? "Enabled" : "Disabled");
  152. comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSourceWithDefault (valueWithDefault,
  153. { true, false })));
  154. valueWithDefault->onDefaultChange = [this]
  155. {
  156. auto selectedId = comboBox.getSelectedId();
  157. comboBox.clear();
  158. createComboBoxWithDefault (valueWithDefault->getDefault() ? "Enabled" : "Disabled");
  159. comboBox.setSelectedId (selectedId);
  160. };
  161. }
  162. ChoicePropertyComponent::~ChoicePropertyComponent()
  163. {
  164. if (valueWithDefault != nullptr)
  165. valueWithDefault->onDefaultChange = nullptr;
  166. }
  167. //==============================================================================
  168. void ChoicePropertyComponent::createComboBox()
  169. {
  170. addAndMakeVisible (comboBox);
  171. for (auto choice : choices)
  172. {
  173. if (choice.isNotEmpty())
  174. comboBox.addItem (choice, choices.indexOf (choice) + 1);
  175. else
  176. comboBox.addSeparator();
  177. }
  178. comboBox.setEditableText (false);
  179. }
  180. void ChoicePropertyComponent::createComboBoxWithDefault (const String& defaultString)
  181. {
  182. addAndMakeVisible (comboBox);
  183. comboBox.addItem ("Default" + (defaultString.isNotEmpty() ? " (" + defaultString + ")" : ""), -1);
  184. for (auto choice : choices)
  185. {
  186. if (choice.isNotEmpty())
  187. comboBox.addItem (choice, choices.indexOf (choice) + 1);
  188. else
  189. comboBox.addSeparator();
  190. }
  191. comboBox.setEditableText (false);
  192. }
  193. void ChoicePropertyComponent::setIndex (const int /*newIndex*/)
  194. {
  195. jassertfalse; // you need to override this method in your subclass!
  196. }
  197. int ChoicePropertyComponent::getIndex() const
  198. {
  199. jassertfalse; // you need to override this method in your subclass!
  200. return -1;
  201. }
  202. const StringArray& ChoicePropertyComponent::getChoices() const
  203. {
  204. return choices;
  205. }
  206. //==============================================================================
  207. void ChoicePropertyComponent::refresh()
  208. {
  209. if (isCustomClass)
  210. {
  211. if (! comboBox.isVisible())
  212. {
  213. createComboBox();
  214. comboBox.onChange = [this] { changeIndex(); };
  215. }
  216. comboBox.setSelectedId (getIndex() + 1, dontSendNotification);
  217. }
  218. }
  219. void ChoicePropertyComponent::changeIndex()
  220. {
  221. if (isCustomClass)
  222. {
  223. auto newIndex = comboBox.getSelectedId() - 1;
  224. if (newIndex != getIndex())
  225. setIndex (newIndex);
  226. }
  227. }
  228. } // namespace juce