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.

281 lines
9.0KB

  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. namespace juce
  20. {
  21. //==============================================================================
  22. class ChoicePropertyComponent::RemapperValueSource : public Value::ValueSource,
  23. private Value::Listener
  24. {
  25. public:
  26. RemapperValueSource (const Value& source, const Array<var>& map)
  27. : sourceValue (source),
  28. mappings (map)
  29. {
  30. sourceValue.addListener (this);
  31. }
  32. var getValue() const override
  33. {
  34. auto targetValue = sourceValue.getValue();
  35. for (auto& map : mappings)
  36. if (map.equalsWithSameType (targetValue))
  37. return mappings.indexOf (map) + 1;
  38. return mappings.indexOf (targetValue) + 1;
  39. }
  40. void setValue (const var& newValue) override
  41. {
  42. auto remappedVal = mappings [static_cast<int> (newValue) - 1];
  43. if (! remappedVal.equalsWithSameType (sourceValue))
  44. sourceValue = remappedVal;
  45. }
  46. protected:
  47. Value sourceValue;
  48. Array<var> mappings;
  49. void valueChanged (Value&) override { sendChangeMessage (true); }
  50. //==============================================================================
  51. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSource)
  52. };
  53. //==============================================================================
  54. class ChoicePropertyComponent::RemapperValueSourceWithDefault : public Value::ValueSource,
  55. private Value::Listener
  56. {
  57. public:
  58. RemapperValueSourceWithDefault (ValueWithDefault& vwd, const Array<var>& map)
  59. : valueWithDefault (vwd),
  60. sourceValue (valueWithDefault.getPropertyAsValue()),
  61. mappings (map)
  62. {
  63. sourceValue.addListener (this);
  64. }
  65. var getValue() const override
  66. {
  67. if (valueWithDefault.isUsingDefault())
  68. return -1;
  69. auto targetValue = sourceValue.getValue();
  70. for (auto map : mappings)
  71. if (map.equalsWithSameType (targetValue))
  72. return mappings.indexOf (map) + 1;
  73. return mappings.indexOf (targetValue) + 1;
  74. }
  75. void setValue (const var& newValue) override
  76. {
  77. auto newValueInt = static_cast<int> (newValue);
  78. if (newValueInt == -1)
  79. {
  80. valueWithDefault.resetToDefault();
  81. }
  82. else
  83. {
  84. auto remappedVal = mappings [newValueInt - 1];
  85. if (! remappedVal.equalsWithSameType (sourceValue))
  86. valueWithDefault = remappedVal;
  87. }
  88. }
  89. private:
  90. ValueWithDefault& valueWithDefault;
  91. Value sourceValue;
  92. Array<var> mappings;
  93. void valueChanged (Value&) override { sendChangeMessage (true); }
  94. //==============================================================================
  95. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSourceWithDefault)
  96. };
  97. //==============================================================================
  98. ChoicePropertyComponent::ChoicePropertyComponent (const String& name)
  99. : PropertyComponent (name),
  100. isCustomClass (true)
  101. {
  102. }
  103. ChoicePropertyComponent::ChoicePropertyComponent (const String& name,
  104. const StringArray& choiceList,
  105. const Array<var>& correspondingValues)
  106. : PropertyComponent (name),
  107. choices (choiceList)
  108. {
  109. // The array of corresponding values must contain one value for each of the items in
  110. // the choices array!
  111. jassert (correspondingValues.size() == choices.size());
  112. ignoreUnused (correspondingValues);
  113. }
  114. ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
  115. const String& name,
  116. const StringArray& choiceList,
  117. const Array<var>& correspondingValues)
  118. : ChoicePropertyComponent (name, choiceList, correspondingValues)
  119. {
  120. createComboBox();
  121. comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSource (valueToControl,
  122. correspondingValues)));
  123. }
  124. ChoicePropertyComponent::ChoicePropertyComponent (ValueWithDefault& valueToControl,
  125. const String& name,
  126. const StringArray& choiceList,
  127. const Array<var>& correspondingValues)
  128. : ChoicePropertyComponent (name, choiceList, correspondingValues)
  129. {
  130. createComboBoxWithDefault (choiceList [correspondingValues.indexOf (valueToControl.getDefault())]);
  131. comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSourceWithDefault (valueToControl,
  132. correspondingValues)));
  133. valueToControl.onDefaultChange = [this, &valueToControl, choiceList, correspondingValues]
  134. {
  135. auto selectedId = comboBox.getSelectedId();
  136. comboBox.clear();
  137. createComboBoxWithDefault (choiceList [correspondingValues.indexOf (valueToControl.getDefault())]);
  138. comboBox.setSelectedId (selectedId);
  139. };
  140. }
  141. ChoicePropertyComponent::ChoicePropertyComponent (ValueWithDefault& valueToControl,
  142. const String& name)
  143. : PropertyComponent (name),
  144. choices ({ "Enabled", "Disabled" })
  145. {
  146. createComboBoxWithDefault (valueToControl.getDefault() ? "Enabled" : "Disabled");
  147. comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSourceWithDefault (valueToControl,
  148. { true, false })));
  149. valueToControl.onDefaultChange = [this, &valueToControl]
  150. {
  151. auto selectedId = comboBox.getSelectedId();
  152. comboBox.clear();
  153. createComboBoxWithDefault (valueToControl.getDefault() ? "Enabled" : "Disabled");
  154. comboBox.setSelectedId (selectedId);
  155. };
  156. }
  157. ChoicePropertyComponent::~ChoicePropertyComponent()
  158. {
  159. }
  160. //==============================================================================
  161. void ChoicePropertyComponent::createComboBox()
  162. {
  163. addAndMakeVisible (comboBox);
  164. for (auto choice : choices)
  165. {
  166. if (choice.isNotEmpty())
  167. comboBox.addItem (choice, choices.indexOf (choice) + 1);
  168. else
  169. comboBox.addSeparator();
  170. }
  171. comboBox.setEditableText (false);
  172. }
  173. void ChoicePropertyComponent::createComboBoxWithDefault (const String& defaultString)
  174. {
  175. addAndMakeVisible (comboBox);
  176. comboBox.addItem ("Default" + (defaultString.isNotEmpty() ? " (" + defaultString + ")" : ""), -1);
  177. for (auto choice : choices)
  178. {
  179. if (choice.isNotEmpty())
  180. comboBox.addItem (choice, choices.indexOf (choice) + 1);
  181. else
  182. comboBox.addSeparator();
  183. }
  184. comboBox.setEditableText (false);
  185. }
  186. void ChoicePropertyComponent::setIndex (const int /*newIndex*/)
  187. {
  188. jassertfalse; // you need to override this method in your subclass!
  189. }
  190. int ChoicePropertyComponent::getIndex() const
  191. {
  192. jassertfalse; // you need to override this method in your subclass!
  193. return -1;
  194. }
  195. const StringArray& ChoicePropertyComponent::getChoices() const
  196. {
  197. return choices;
  198. }
  199. //==============================================================================
  200. void ChoicePropertyComponent::refresh()
  201. {
  202. if (isCustomClass)
  203. {
  204. if (! comboBox.isVisible())
  205. {
  206. createComboBox();
  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