JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_MultiChoicePropertyComponent.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26
27namespace juce
28{
29
30//==============================================================================
32{
33public:
34 static int compareElements (var first, var second)
35 {
36 if (first.toString() > second.toString())
37 return 1;
38 else if (first.toString() < second.toString())
39 return -1;
40
41 return 0;
42 }
43};
44
45static void updateButtonTickColour (ToggleButton* button, bool usingDefault)
46{
47 button->setColour (ToggleButton::tickColourId, button->getLookAndFeel().findColour (ToggleButton::tickColourId)
48 .withAlpha (usingDefault ? 0.4f : 1.0f));
49}
50
51//==============================================================================
53 private Value::Listener
54{
55public:
56 MultiChoiceRemapperSource (const Value& source, var v, int c)
57 : sourceValue (source),
58 varToControl (v),
59 maxChoices (c)
60 {
61 sourceValue.addListener (this);
62 }
63
64 var getValue() const override
65 {
66 if (auto* arr = sourceValue.getValue().getArray())
67 if (arr->contains (varToControl))
68 return true;
69
70 return false;
71 }
72
73 void setValue (const var& newValue) override
74 {
75 if (auto* arr = sourceValue.getValue().getArray())
76 {
77 auto temp = *arr;
78
79 if (static_cast<bool> (newValue))
80 {
81 if (temp.addIfNotAlreadyThere (varToControl) && (maxChoices != -1) && (temp.size() > maxChoices))
82 temp.remove (temp.size() - 2);
83 }
84 else
85 {
86 temp.remove (arr->indexOf (varToControl));
87 }
88
90 temp.sort (c);
91
92 sourceValue = temp;
93 }
94 }
95
96private:
97 Value sourceValue;
98 var varToControl;
99
100 int maxChoices;
101
102 //==============================================================================
103 void valueChanged (Value&) override { sendChangeMessage (true); }
104
105 //==============================================================================
106 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiChoiceRemapperSource)
107};
108
109//==============================================================================
111 private Value::Listener
112{
113public:
115 var v, int c, ToggleButton* b)
116 : value (val),
117 varToControl (v),
118 sourceValue (value.getPropertyAsValue()),
119 maxChoices (c),
120 buttonToControl (b)
121 {
122 sourceValue.addListener (this);
123 }
124
125 var getValue() const override
126 {
127 auto v = value.get();
128
129 if (auto* arr = v.getArray())
130 {
131 if (arr->contains (varToControl))
132 {
133 updateButtonTickColour (buttonToControl, value.isUsingDefault());
134 return true;
135 }
136 }
137
138 return false;
139 }
140
141 void setValue (const var& newValue) override
142 {
143 auto v = value.get();
144
146
147 if (value.isUsingDefault())
148 arrayToControl.set (new Array<var>(), true); // use an empty array so the default values are overwritten
149 else
150 arrayToControl.set (v.getArray(), false);
151
152 if (arrayToControl != nullptr)
153 {
154 auto temp = *arrayToControl;
155
156 bool newState = newValue;
157
158 if (value.isUsingDefault())
159 {
160 if (auto* defaultArray = v.getArray())
161 {
162 if (defaultArray->contains (varToControl))
163 newState = true; // force the state as the user is setting it explicitly
164 }
165 }
166
167 if (newState)
168 {
169 if (temp.addIfNotAlreadyThere (varToControl) && (maxChoices != -1) && (temp.size() > maxChoices))
170 temp.remove (temp.size() - 2);
171 }
172 else
173 {
174 temp.remove (temp.indexOf (varToControl));
175 }
176
178 temp.sort (c);
179
180 value = temp;
181
182 if (temp.size() == 0)
183 value.resetToDefault();
184 }
185 }
186
187private:
188 //==============================================================================
189 void valueChanged (Value&) override { sendChangeMessage (true); }
190
191 //==============================================================================
193 var varToControl;
194 Value sourceValue;
195
196 int maxChoices;
197
198 ToggleButton* buttonToControl;
199
200 //==============================================================================
201 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiChoiceRemapperSourceWithDefault)
202};
203
204//==============================================================================
205int MultiChoicePropertyComponent::getTotalButtonsHeight (int numButtons)
206{
207 return numButtons * buttonHeight + 1;
208}
209
210MultiChoicePropertyComponent::MultiChoicePropertyComponent (const String& propertyName,
211 const StringArray& choices,
213 : PropertyComponent (propertyName, jmin (getTotalButtonsHeight (choices.size()), collapsedHeight))
214{
215 // The array of corresponding values must contain one value for each of the items in
216 // the choices array!
217 jassert (choices.size() == correspondingValues.size());
218
219 for (auto choice : choices)
220 addAndMakeVisible (choiceButtons.add (new ToggleButton (choice)));
221
222 if (preferredHeight >= collapsedHeight)
223 {
224 expandable = true;
225 maxHeight = getTotalButtonsHeight (choiceButtons.size()) + expandAreaHeight;
226 }
227
228 if (isExpandable())
229 {
230 {
231 Path expandShape;
232 expandShape.addTriangle ({ 0, 0 }, { 5, 10 }, { 10, 0});
233 expandButton.setShape (expandShape, true, true, false);
234 }
235
236 expandButton.onClick = [this] { setExpanded (! expanded); };
237 addAndMakeVisible (expandButton);
238
239 lookAndFeelChanged();
240 }
241}
242
243MultiChoicePropertyComponent::MultiChoicePropertyComponent (const Value& valueToControl,
244 const String& propertyName,
245 const StringArray& choices,
247 int maxChoices)
249{
250 // The value to control must be an array!
251 jassert (valueToControl.getValue().isArray());
252
253 for (int i = 0; i < choiceButtons.size(); ++i)
254 choiceButtons[i]->getToggleStateValue().referTo (Value (new MultiChoiceRemapperSource (valueToControl,
256 maxChoices)));
257}
258
259MultiChoicePropertyComponent::MultiChoicePropertyComponent (const ValueTreePropertyWithDefault& valueToControl,
260 const String& propertyName,
261 const StringArray& choices,
263 int maxChoices)
265{
266 value = valueToControl;
267
268 // The value to control must be an array!
269 jassert (value.get().isArray());
270
271 for (int i = 0; i < choiceButtons.size(); ++i)
272 choiceButtons[i]->getToggleStateValue().referTo (Value (new MultiChoiceRemapperSourceWithDefault (value,
274 maxChoices,
275 choiceButtons[i])));
276
277 value.onDefaultChange = [this] { repaint(); };
278}
279
281{
283 g.fillRect (getLookAndFeel().getPropertyComponentContentPosition (*this));
284
285 if (isExpandable() && ! isExpanded())
286 {
287 g.setColour (findColour (TextEditor::backgroundColourId).contrasting().withAlpha (0.4f));
288 g.drawFittedText ("+ " + String (numHidden) + " more", getLookAndFeel().getPropertyComponentContentPosition (*this)
289 .removeFromBottom (expandAreaHeight).withTrimmedLeft (10),
291 }
292
294}
295
297{
298 auto bounds = getLookAndFeel().getPropertyComponentContentPosition (*this);
299
300 if (isExpandable())
301 {
302 bounds.removeFromBottom (5);
303
304 auto buttonSlice = bounds.removeFromBottom (10);
305 expandButton.setSize (10, 10);
306 expandButton.setCentrePosition (buttonSlice.getCentre());
307 }
308
309 numHidden = 0;
310
311 for (auto* b : choiceButtons)
312 {
313 if (bounds.getHeight() >= buttonHeight)
314 {
315 b->setVisible (true);
316 b->setBounds (bounds.removeFromTop (buttonHeight).reduced (5, 2));
317 }
318 else
319 {
320 b->setVisible (false);
321 ++numHidden;
322 }
323 }
324}
325
327{
328 if (! isExpandable() || (isExpanded() == shouldBeExpanded))
329 return;
330
331 expanded = shouldBeExpanded;
332 preferredHeight = expanded ? maxHeight : collapsedHeight;
333
335 propertyPanel->resized();
336
337 NullCheckedInvocation::invoke (onHeightChange);
338
340 (float) expandButton.getBounds().getCentreX(),
341 (float) expandButton.getBounds().getCentreY()));
342
343 resized();
344}
345
346//==============================================================================
347void MultiChoicePropertyComponent::lookAndFeelChanged()
348{
350 expandButton.setColours (iconColour, iconColour.darker(), iconColour.darker());
351
352 const auto usingDefault = value.isUsingDefault();
353
354 for (auto* button : choiceButtons)
355 updateButtonTickColour (button, usingDefault);
356}
357
358} // namespace juce
static AffineTransform rotation(float angleInRadians) noexcept
Returns a new transform which is a rotation about (0, 0).
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
Colour contrasting(float amount=1.0f) const noexcept
Returns a colour that will be clearly visible against this colour.
void addAndMakeVisible(Component *child, int zOrder=-1)
Adds a child component to this one, and also makes the child visible if it isn't already.
void setCentrePosition(int x, int y)
Changes the position of the component's centre.
void repaint()
Marks the whole component as needing to be redrawn.
void setSize(int newWidth, int newHeight)
Changes the size of the component.
Colour findColour(int colourID, bool inheritFromParent=false) const
Looks for a colour that has been registered with the given colour ID number.
LookAndFeel & getLookAndFeel() const noexcept
Finds the appropriate look-and-feel to use for this component.
A graphics context, used for drawing a component or image.
void drawFittedText(const String &text, int x, int y, int width, int height, Justification justificationFlags, int maximumNumberOfLines, float minimumHorizontalScale=0.0f) const
Tries to draw a text string inside a given space.
void fillRect(Rectangle< int > rectangle) const
Fills a rectangle with the current colour or brush.
void setColour(Colour newColour)
Changes the current drawing colour.
@ centredLeft
Indicates that the item should be centred vertically but placed on the left hand side.
void setValue(const var &newValue) override
Changes the current value.
var getValue() const override
Returns the current value of this object.
A PropertyComponent that shows its value as an expandable list of ToggleButtons.
void resized() override
Called when this component's size has been changed.
void paint(Graphics &g) override
Components can override this method to draw their content.
bool isExpandable() const noexcept
Returns true if the list of options has been truncated and can be expanded.
bool isExpanded() const noexcept
Returns true if the list of options is expanded.
void setExpanded(bool expanded) noexcept
Expands or shrinks the list of options if they are not all visible.
Holds a pointer to an object which can optionally be deleted when this pointer goes out of scope.
void set(ObjectType *newObject, bool takeOwnership)
Makes this OptionalScopedPointer point at a new object, specifying whether the OptionalScopedPointer ...
int preferredHeight
Used by the PropertyPanel to determine how high this component needs to be.
void paint(Graphics &) override
The default paint method fills the background and draws a label for the item's name.
Rectangle removeFromBottom(ValueType amountToRemove) noexcept
Removes a strip from the bottom of this rectangle, reducing this rectangle by the specified amount an...
void setColours(Colour normalColour, Colour overColour, Colour downColour)
Set the colours to use for drawing the shape.
A special array for holding a list of strings.
The JUCE String class!
Definition juce_String.h:53
@ backgroundColourId
The colour to use for the text component's background - this can be transparent if necessary.
A button that can be toggled on/off.
@ tickColourId
The colour to use for the tick mark.
This class acts as a wrapper around a property inside a ValueTree.
bool isUsingDefault() const
Returns true if the property does not exist in the referenced ValueTree.
std::function< void()> onDefaultChange
You can assign a lambda to this callback and it will called when the default value is changed.
void resetToDefault() noexcept
Removes the property from the referenced ValueTree.
var get() const noexcept
Returns the current value of the property.
Receives callbacks when a Value object changes.
Definition juce_Value.h:139
Used internally by the Value class as the base class for its shared value objects.
Definition juce_Value.h:180
void sendChangeMessage(bool dispatchSynchronously)
Delivers a change message to all the listeners that are registered with this value.
Represents a shared variant value.
Definition juce_Value.h:51
void addListener(Listener *listener)
Adds a listener to receive callbacks when the value changes.
var getValue() const
Returns the current value.
A variant class, that can be used to hold a range of primitive values.
Array< var > * getArray() const noexcept
If this variant holds an array, this provides access to it.
void remove(int index)
If the var is an array, this removes one of its elements.
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
typedef float
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
@ valueChanged
Indicates that the UI element's value has changed.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
T size(T... args)
Commonly used mathematical constants.