mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Added a MultiChoicePropertyComponent class to juce_gui_basics and updated the PropertiesDemo example to use it
This commit is contained in:
parent
9916aa6870
commit
404838a99f
5 changed files with 378 additions and 40 deletions
|
|
@ -141,58 +141,27 @@ static Array<PropertyComponent*> createChoices (int howMany)
|
|||
StringArray choices;
|
||||
Array<var> choiceVars;
|
||||
|
||||
for (int i = 0; i < howMany; ++i)
|
||||
for (int i = 0; i < 12; ++i)
|
||||
{
|
||||
choices.add ("Item " + String (i));
|
||||
choiceVars.add (i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < howMany; ++i)
|
||||
comps.add (new ChoicePropertyComponent (Value (Random::getSystemRandom().nextInt (6)), "Choice Property " + String (i + 1), choices, choiceVars));
|
||||
comps.add (new ChoicePropertyComponent (Value (Random::getSystemRandom().nextInt (12)), "Choice Property " + String (i + 1), choices, choiceVars));
|
||||
|
||||
for (int i = 0; i < howMany; ++i)
|
||||
comps.add (new MultiChoicePropertyComponent (Value (Array<var>()), "Multi-Choice Property " + String (i + 1), choices, choiceVars));
|
||||
|
||||
return comps;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class PropertiesDemo : public Component
|
||||
{
|
||||
public:
|
||||
PropertiesDemo()
|
||||
{
|
||||
setOpaque (true);
|
||||
addAndMakeVisible (propertyPanel);
|
||||
|
||||
propertyPanel.addSection ("Text Editors", createTextEditors());
|
||||
propertyPanel.addSection ("Sliders", createSliders (3));
|
||||
propertyPanel.addSection ("Choice Properties", createChoices (6));
|
||||
propertyPanel.addSection ("Buttons & Toggles", createButtons (3));
|
||||
|
||||
setSize (750, 650);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground,
|
||||
Colour::greyLevel (0.8f)));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
propertyPanel.setBounds (getLocalBounds().reduced (4));
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyPanel propertyPanel;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertiesDemo)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ConcertinaDemo : public Component,
|
||||
class PropertiesDemo : public Component,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
ConcertinaDemo()
|
||||
PropertiesDemo()
|
||||
{
|
||||
setOpaque (true);
|
||||
addAndMakeVisible (concertinaPanel);
|
||||
|
|
@ -212,7 +181,7 @@ public:
|
|||
|
||||
{
|
||||
auto* panel = new PropertyPanel ("Choice Properties");
|
||||
panel->addProperties (createChoices (12));
|
||||
panel->addProperties (createChoices (3));
|
||||
addPanel (panel);
|
||||
}
|
||||
|
||||
|
|
@ -222,6 +191,8 @@ public:
|
|||
addPanel (panel);
|
||||
}
|
||||
|
||||
|
||||
setSize (750, 650);
|
||||
startTimer (300);
|
||||
}
|
||||
|
||||
|
|
@ -251,5 +222,5 @@ private:
|
|||
concertinaPanel.setMaximumPanelSize (panel, panel->getTotalContentHeight());
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConcertinaDemo)
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertiesDemo)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ namespace juce
|
|||
#include "properties/juce_PropertyPanel.cpp"
|
||||
#include "properties/juce_SliderPropertyComponent.cpp"
|
||||
#include "properties/juce_TextPropertyComponent.cpp"
|
||||
#include "properties/juce_MultiChoicePropertyComponent.cpp"
|
||||
#include "widgets/juce_ComboBox.cpp"
|
||||
#include "widgets/juce_ImageComponent.cpp"
|
||||
#include "widgets/juce_Label.cpp"
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ namespace juce
|
|||
#include "properties/juce_PropertyPanel.h"
|
||||
#include "properties/juce_SliderPropertyComponent.h"
|
||||
#include "properties/juce_TextPropertyComponent.h"
|
||||
#include "properties/juce_MultiChoicePropertyComponent.h"
|
||||
#include "application/juce_Application.h"
|
||||
#include "misc/juce_BubbleComponent.h"
|
||||
#include "lookandfeel/juce_LookAndFeel.h"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
class MultiChoicePropertyComponent::MultiChoiceRemapperSource : public Value::ValueSource,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
MultiChoiceRemapperSource (const Value& source, var v)
|
||||
: sourceValue (source),
|
||||
varToControl (v)
|
||||
{
|
||||
sourceValue.addListener (this);
|
||||
}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
if (auto* arr = sourceValue.getValue().getArray())
|
||||
if (arr->contains (varToControl))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
if (auto* arr = sourceValue.getValue().getArray())
|
||||
{
|
||||
auto newValueInt = static_cast<int> (newValue);
|
||||
|
||||
if (newValueInt == 1)
|
||||
arr->addIfNotAlreadyThere (varToControl);
|
||||
else
|
||||
arr->remove (arr->indexOf (varToControl));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Value sourceValue;
|
||||
var varToControl;
|
||||
|
||||
void valueChanged (Value&) override { sendChangeMessage (true); }
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiChoiceRemapperSource)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class MultiChoicePropertyComponent::MultiChoiceRemapperSourceWithDefault : public Value::ValueSource,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
MultiChoiceRemapperSourceWithDefault (const ValueWithDefault& vwd, var v)
|
||||
: valueWithDefault (vwd),
|
||||
sourceValue (valueWithDefault.getPropertyAsValue()),
|
||||
varToControl (v)
|
||||
{
|
||||
sourceValue.addListener (this);
|
||||
}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
if (auto* arr = valueWithDefault.get().getArray())
|
||||
if (arr->contains (varToControl))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
if (auto* arr = valueWithDefault.get().getArray())
|
||||
{
|
||||
auto newValueInt = static_cast<int> (newValue);
|
||||
|
||||
if (newValueInt == 1)
|
||||
arr->addIfNotAlreadyThere (varToControl);
|
||||
else
|
||||
arr->remove (arr->indexOf (varToControl));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ValueWithDefault valueWithDefault;
|
||||
Value sourceValue;
|
||||
var varToControl;
|
||||
|
||||
void valueChanged (Value&) override { sendChangeMessage (true); }
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiChoiceRemapperSourceWithDefault)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
MultiChoicePropertyComponent::MultiChoicePropertyComponent (const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues)
|
||||
: PropertyComponent (propertyName, 70)
|
||||
{
|
||||
// The array of corresponding values must contain one value for each of the items in
|
||||
// the choices array!
|
||||
jassert (choices.size() == correspondingValues.size());
|
||||
|
||||
ignoreUnused (correspondingValues);
|
||||
|
||||
for (auto choice : choices)
|
||||
addAndMakeVisible (choiceButtons.add (new ToggleButton (choice)));
|
||||
|
||||
maxHeight = (choiceButtons.size() * 25) + 20;
|
||||
|
||||
{
|
||||
Path expandShape;
|
||||
expandShape.addTriangle ({ 0, 0 }, { 5, 10 }, { 10, 0});
|
||||
expandButton.setShape (expandShape, true, true, false);
|
||||
}
|
||||
|
||||
expandButton.onClick = [this] { setExpanded (! expanded); };
|
||||
addAndMakeVisible (expandButton);
|
||||
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
MultiChoicePropertyComponent::MultiChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues)
|
||||
: MultiChoicePropertyComponent (propertyName, choices, correspondingValues)
|
||||
{
|
||||
// The value to control must be an array!
|
||||
jassert (valueToControl.getValue().isArray());
|
||||
|
||||
for (int i = 0; i < choiceButtons.size(); ++i)
|
||||
choiceButtons[i]->getToggleStateValue().referTo (Value (new MultiChoiceRemapperSource (valueToControl,
|
||||
correspondingValues[i])));
|
||||
}
|
||||
|
||||
MultiChoicePropertyComponent::MultiChoicePropertyComponent (const ValueWithDefault& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues)
|
||||
: MultiChoicePropertyComponent (propertyName, choices, correspondingValues)
|
||||
{
|
||||
// The value to control must be an array!
|
||||
jassert (valueToControl.get().isArray());
|
||||
|
||||
for (int i = 0; i < choiceButtons.size(); ++i)
|
||||
choiceButtons[i]->getToggleStateValue().referTo (Value (new MultiChoiceRemapperSourceWithDefault (valueToControl,
|
||||
correspondingValues[i])));
|
||||
}
|
||||
|
||||
void MultiChoicePropertyComponent::paint (Graphics& g)
|
||||
{
|
||||
g.setColour (findColour (TextEditor::backgroundColourId));
|
||||
g.fillRect (getLookAndFeel().getPropertyComponentContentPosition (*this));
|
||||
|
||||
if (! expanded)
|
||||
{
|
||||
g.setColour (findColour (PropertyComponent::labelTextColourId).withAlpha (0.4f));
|
||||
g.drawFittedText ("+ " + String (numHidden) + " more", getLookAndFeel().getPropertyComponentContentPosition (*this)
|
||||
.removeFromBottom (20).withTrimmedLeft (10),
|
||||
Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
PropertyComponent::paint (g);
|
||||
}
|
||||
|
||||
void MultiChoicePropertyComponent::resized()
|
||||
{
|
||||
auto bounds = getLookAndFeel().getPropertyComponentContentPosition (*this);
|
||||
|
||||
bounds.removeFromBottom (5);
|
||||
expandButton.setBounds (bounds.removeFromBottom (10));
|
||||
|
||||
numHidden = 0;
|
||||
|
||||
for (auto* b : choiceButtons)
|
||||
{
|
||||
if (bounds.getHeight() >= 25)
|
||||
{
|
||||
b->setVisible (true);
|
||||
b->setBounds (bounds.removeFromTop (25).reduced (5, 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
b->setVisible (false);
|
||||
++numHidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiChoicePropertyComponent::setExpanded (bool isExpanded) noexcept
|
||||
{
|
||||
if (expanded == isExpanded)
|
||||
return;
|
||||
|
||||
expanded = isExpanded;
|
||||
preferredHeight = expanded ? maxHeight : 70;
|
||||
|
||||
if (auto* propertyPanel = findParentComponentOfClass<PropertyPanel>())
|
||||
propertyPanel->resized();
|
||||
|
||||
if (onHeightChange != nullptr)
|
||||
onHeightChange();
|
||||
|
||||
expandButton.setTransform (AffineTransform::rotation (expanded ? MathConstants<float>::pi : MathConstants<float>::twoPi,
|
||||
(float) expandButton.getBounds().getCentreX(),
|
||||
(float) expandButton.getBounds().getCentreY()));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MultiChoicePropertyComponent::lookAndFeelChanged()
|
||||
{
|
||||
auto iconColour = findColour (PropertyComponent::labelTextColourId);
|
||||
expandButton.setColours (iconColour, iconColour.darker(), iconColour.darker());
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A PropertyComponent that shows its value as an expandable list of ToggleButtons.
|
||||
|
||||
This type of property component contains a list of options where multiple options
|
||||
can be selected at once.
|
||||
|
||||
@see PropertyComponent, PropertyPanel
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class MultiChoicePropertyComponent : public PropertyComponent
|
||||
{
|
||||
public:
|
||||
/** Creates the component. Note that the underlying var object that the Value refers to must be an array.
|
||||
|
||||
@param valueToControl the value that the ToggleButtons will read and control
|
||||
@param propertyName the name of the property
|
||||
@param choices the list of possible values that will be represented
|
||||
@param correspondingValues a list of values corresponding to each item in the 'choices' StringArray.
|
||||
These are the values that will be read and written to the
|
||||
valueToControl value. This array must contain the same number of items
|
||||
as the choices array
|
||||
*/
|
||||
MultiChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues);
|
||||
|
||||
/** Creates the component using a ValueWithDefault object. This will select the default options.
|
||||
|
||||
@param valueToControl the ValueWithDefault object that contains the Value object that the ToggleButtons will read and control
|
||||
@param propertyName the name of the property
|
||||
@param choices the list of possible values that will be represented
|
||||
@param correspondingValues a list of values corresponding to each item in the 'choices' StringArray.
|
||||
These are the values that will be read and written to the
|
||||
valueToControl value. This array must contain the same number of items
|
||||
as the choices array
|
||||
*/
|
||||
MultiChoicePropertyComponent (const ValueWithDefault& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the list of options is expanded. */
|
||||
bool isExpanded() const noexcept { return expanded; }
|
||||
|
||||
/** Expands or shrinks the list of options.
|
||||
|
||||
N.B. This will just set the preferredHeight value of the PropertyComponent and attempt to
|
||||
call PropertyPanel::resized(), so if you are not displaying this object in a PropertyPanel
|
||||
then you should use the onHeightChange callback to resize it when the height changes.
|
||||
|
||||
@see onHeightChange
|
||||
*/
|
||||
void setExpanded (bool expanded) noexcept;
|
||||
|
||||
/** You can assign a lambda to this callback object to have it called when the MultiChoicePropertyComponent height changes. */
|
||||
std::function<void()> onHeightChange;
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics& g) override;
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
/** @internal */
|
||||
void refresh() override {}
|
||||
|
||||
private:
|
||||
MultiChoicePropertyComponent (const String&, const StringArray&, const Array<var>&);
|
||||
|
||||
class MultiChoiceRemapperSource;
|
||||
class MultiChoiceRemapperSourceWithDefault;
|
||||
|
||||
//==============================================================================
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
//==============================================================================
|
||||
int maxHeight = 0;
|
||||
int numHidden = 0;
|
||||
bool expanded = false;
|
||||
|
||||
OwnedArray<ToggleButton> choiceButtons;
|
||||
ShapeButton expandButton { "Expand", Colours::transparentBlack, Colours::transparentBlack, Colours::transparentBlack };
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiChoicePropertyComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Loading…
Add table
Add a link
Reference in a new issue