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.

261 lines
8.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. 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 (const 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. }
  134. ChoicePropertyComponent::ChoicePropertyComponent (ValueWithDefault valueToControl,
  135. const String& name)
  136. : PropertyComponent (name),
  137. choices ({ "Enabled", "Disabled" })
  138. {
  139. createComboBoxWithDefault (valueToControl.getDefault() ? "Enabled" : "Disabled");
  140. comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSourceWithDefault (valueToControl,
  141. { true, false })));
  142. }
  143. ChoicePropertyComponent::~ChoicePropertyComponent()
  144. {
  145. }
  146. //==============================================================================
  147. void ChoicePropertyComponent::createComboBox()
  148. {
  149. addAndMakeVisible (comboBox);
  150. for (auto choice : choices)
  151. {
  152. if (choice.isNotEmpty())
  153. comboBox.addItem (choice, choices.indexOf (choice) + 1);
  154. else
  155. comboBox.addSeparator();
  156. }
  157. comboBox.setEditableText (false);
  158. }
  159. void ChoicePropertyComponent::createComboBoxWithDefault (const String& defaultString)
  160. {
  161. addAndMakeVisible (comboBox);
  162. comboBox.addItem ("Default" + (defaultString.isNotEmpty() ? " (" + defaultString + ")" : ""), -1);
  163. for (auto choice : choices)
  164. {
  165. if (choice.isNotEmpty())
  166. comboBox.addItem (choice, choices.indexOf (choice) + 1);
  167. else
  168. comboBox.addSeparator();
  169. }
  170. comboBox.setEditableText (false);
  171. }
  172. void ChoicePropertyComponent::setIndex (const int /*newIndex*/)
  173. {
  174. jassertfalse; // you need to override this method in your subclass!
  175. }
  176. int ChoicePropertyComponent::getIndex() const
  177. {
  178. jassertfalse; // you need to override this method in your subclass!
  179. return -1;
  180. }
  181. const StringArray& ChoicePropertyComponent::getChoices() const
  182. {
  183. return choices;
  184. }
  185. //==============================================================================
  186. void ChoicePropertyComponent::refresh()
  187. {
  188. if (isCustomClass)
  189. {
  190. if (! comboBox.isVisible())
  191. {
  192. createComboBox();
  193. comboBox.onChange = [this] { changeIndex(); };
  194. }
  195. comboBox.setSelectedId (getIndex() + 1, dontSendNotification);
  196. }
  197. }
  198. void ChoicePropertyComponent::changeIndex()
  199. {
  200. if (isCustomClass)
  201. {
  202. auto newIndex = comboBox.getSelectedId() - 1;
  203. if (newIndex != getIndex())
  204. setIndex (newIndex);
  205. }
  206. }
  207. } // namespace juce