fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).
This commit is contained in:
@ -0,0 +1,87 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
BooleanPropertyComponent::BooleanPropertyComponent (const String& name,
|
||||
const String& buttonTextWhenTrue,
|
||||
const String& buttonTextWhenFalse)
|
||||
: PropertyComponent (name),
|
||||
onText (buttonTextWhenTrue),
|
||||
offText (buttonTextWhenFalse)
|
||||
{
|
||||
addAndMakeVisible (button);
|
||||
button.setClickingTogglesState (false);
|
||||
button.onClick = [this] { setState (! getState()); };
|
||||
}
|
||||
|
||||
BooleanPropertyComponent::BooleanPropertyComponent (const Value& valueToControl,
|
||||
const String& name,
|
||||
const String& buttonText)
|
||||
: PropertyComponent (name),
|
||||
onText (buttonText),
|
||||
offText (buttonText)
|
||||
{
|
||||
addAndMakeVisible (button);
|
||||
button.setClickingTogglesState (false);
|
||||
button.setButtonText (buttonText);
|
||||
button.getToggleStateValue().referTo (valueToControl);
|
||||
button.setClickingTogglesState (true);
|
||||
}
|
||||
|
||||
BooleanPropertyComponent::~BooleanPropertyComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void BooleanPropertyComponent::setState (const bool newState)
|
||||
{
|
||||
button.setToggleState (newState, sendNotification);
|
||||
}
|
||||
|
||||
bool BooleanPropertyComponent::getState() const
|
||||
{
|
||||
return button.getToggleState();
|
||||
}
|
||||
|
||||
void BooleanPropertyComponent::paint (Graphics& g)
|
||||
{
|
||||
PropertyComponent::paint (g);
|
||||
|
||||
g.setColour (findColour (backgroundColourId));
|
||||
g.fillRect (button.getBounds());
|
||||
|
||||
g.setColour (findColour (outlineColourId));
|
||||
g.drawRect (button.getBounds());
|
||||
}
|
||||
|
||||
void BooleanPropertyComponent::refresh()
|
||||
{
|
||||
button.setToggleState (getState(), dontSendNotification);
|
||||
button.setButtonText (button.getToggleState() ? onText : offText);
|
||||
}
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 contains an on/off toggle button.
|
||||
|
||||
This type of property component can be used if you have a boolean value to
|
||||
toggle on/off.
|
||||
|
||||
@see PropertyComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API BooleanPropertyComponent : public PropertyComponent
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates a button component.
|
||||
|
||||
If you use this constructor, you must override the getState() and setState()
|
||||
methods.
|
||||
|
||||
@param propertyName the property name to be passed to the PropertyComponent
|
||||
@param buttonTextWhenTrue the text shown in the button when the value is true
|
||||
@param buttonTextWhenFalse the text shown in the button when the value is false
|
||||
*/
|
||||
BooleanPropertyComponent (const String& propertyName,
|
||||
const String& buttonTextWhenTrue,
|
||||
const String& buttonTextWhenFalse);
|
||||
|
||||
public:
|
||||
/** Creates a button component.
|
||||
|
||||
Note that if you call this constructor then you must use the Value to interact with the
|
||||
button state, and you can't override the class with your own setState or getState methods.
|
||||
If you want to use getState and setState, call the other constructor instead.
|
||||
|
||||
@param valueToControl a Value object that this property should refer to.
|
||||
@param propertyName the property name to be passed to the PropertyComponent
|
||||
@param buttonText the text shown in the ToggleButton component
|
||||
*/
|
||||
BooleanPropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
const String& buttonText);
|
||||
|
||||
/** Destructor. */
|
||||
~BooleanPropertyComponent();
|
||||
|
||||
//==============================================================================
|
||||
/** Called to change the state of the boolean value. */
|
||||
virtual void setState (bool newState);
|
||||
|
||||
/** Must return the current value of the property. */
|
||||
virtual bool getState() const;
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the component.
|
||||
|
||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
|
||||
methods.
|
||||
|
||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
||||
*/
|
||||
enum ColourIds
|
||||
{
|
||||
backgroundColourId = 0x100e801, /**< The colour to fill the background of the button area. */
|
||||
outlineColourId = 0x100e803, /**< The colour to use to draw an outline around the text area. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
/** @internal */
|
||||
void refresh() override;
|
||||
|
||||
private:
|
||||
ToggleButton button;
|
||||
String onText, offText;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BooleanPropertyComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
ButtonPropertyComponent::ButtonPropertyComponent (const String& name, bool triggerOnMouseDown)
|
||||
: PropertyComponent (name)
|
||||
{
|
||||
addAndMakeVisible (button);
|
||||
button.setTriggeredOnMouseDown (triggerOnMouseDown);
|
||||
button.onClick = [this] { buttonClicked(); };
|
||||
}
|
||||
|
||||
ButtonPropertyComponent::~ButtonPropertyComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void ButtonPropertyComponent::refresh()
|
||||
{
|
||||
button.setButtonText (getButtonText());
|
||||
}
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 contains a button.
|
||||
|
||||
This type of property component can be used if you need a button to trigger some
|
||||
kind of action.
|
||||
|
||||
@see PropertyComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API ButtonPropertyComponent : public PropertyComponent
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a button component.
|
||||
|
||||
@param propertyName the property name to be passed to the PropertyComponent
|
||||
@param triggerOnMouseDown this is passed to the Button::setTriggeredOnMouseDown() method
|
||||
*/
|
||||
ButtonPropertyComponent (const String& propertyName,
|
||||
bool triggerOnMouseDown);
|
||||
|
||||
/** Destructor. */
|
||||
~ButtonPropertyComponent();
|
||||
|
||||
//==============================================================================
|
||||
/** Called when the user clicks the button.
|
||||
*/
|
||||
virtual void buttonClicked() = 0;
|
||||
|
||||
/** Returns the string that should be displayed in the button.
|
||||
|
||||
If you need to change this string, call refresh() to update the component.
|
||||
*/
|
||||
virtual String getButtonText() const = 0;
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
TextButton button;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonPropertyComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,280 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ChoicePropertyComponent::RemapperValueSource : public Value::ValueSource,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
RemapperValueSource (const Value& source, const Array<var>& map)
|
||||
: sourceValue (source),
|
||||
mappings (map)
|
||||
{
|
||||
sourceValue.addListener (this);
|
||||
}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
auto targetValue = sourceValue.getValue();
|
||||
|
||||
for (auto& map : mappings)
|
||||
if (map.equalsWithSameType (targetValue))
|
||||
return mappings.indexOf (map) + 1;
|
||||
|
||||
return mappings.indexOf (targetValue) + 1;
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
auto remappedVal = mappings [static_cast<int> (newValue) - 1];
|
||||
|
||||
if (! remappedVal.equalsWithSameType (sourceValue))
|
||||
sourceValue = remappedVal;
|
||||
}
|
||||
|
||||
protected:
|
||||
Value sourceValue;
|
||||
Array<var> mappings;
|
||||
|
||||
void valueChanged (Value&) override { sendChangeMessage (true); }
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSource)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ChoicePropertyComponent::RemapperValueSourceWithDefault : public Value::ValueSource,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
RemapperValueSourceWithDefault (ValueWithDefault& vwd, const Array<var>& map)
|
||||
: valueWithDefault (vwd),
|
||||
sourceValue (valueWithDefault.getPropertyAsValue()),
|
||||
mappings (map)
|
||||
{
|
||||
sourceValue.addListener (this);
|
||||
}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
if (valueWithDefault.isUsingDefault())
|
||||
return -1;
|
||||
|
||||
auto targetValue = sourceValue.getValue();
|
||||
|
||||
for (auto map : mappings)
|
||||
if (map.equalsWithSameType (targetValue))
|
||||
return mappings.indexOf (map) + 1;
|
||||
|
||||
return mappings.indexOf (targetValue) + 1;
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
auto newValueInt = static_cast<int> (newValue);
|
||||
|
||||
if (newValueInt == -1)
|
||||
{
|
||||
valueWithDefault.resetToDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto remappedVal = mappings [newValueInt - 1];
|
||||
|
||||
if (! remappedVal.equalsWithSameType (sourceValue))
|
||||
valueWithDefault = remappedVal;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ValueWithDefault& valueWithDefault;
|
||||
Value sourceValue;
|
||||
Array<var> mappings;
|
||||
|
||||
void valueChanged (Value&) override { sendChangeMessage (true); }
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSourceWithDefault)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
ChoicePropertyComponent::ChoicePropertyComponent (const String& name)
|
||||
: PropertyComponent (name),
|
||||
isCustomClass (true)
|
||||
{
|
||||
}
|
||||
|
||||
ChoicePropertyComponent::ChoicePropertyComponent (const String& name,
|
||||
const StringArray& choiceList,
|
||||
const Array<var>& correspondingValues)
|
||||
: PropertyComponent (name),
|
||||
choices (choiceList)
|
||||
{
|
||||
// The array of corresponding values must contain one value for each of the items in
|
||||
// the choices array!
|
||||
jassert (correspondingValues.size() == choices.size());
|
||||
|
||||
ignoreUnused (correspondingValues);
|
||||
}
|
||||
|
||||
ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& name,
|
||||
const StringArray& choiceList,
|
||||
const Array<var>& correspondingValues)
|
||||
: ChoicePropertyComponent (name, choiceList, correspondingValues)
|
||||
{
|
||||
createComboBox();
|
||||
|
||||
comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSource (valueToControl,
|
||||
correspondingValues)));
|
||||
}
|
||||
|
||||
ChoicePropertyComponent::ChoicePropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& name,
|
||||
const StringArray& choiceList,
|
||||
const Array<var>& correspondingValues)
|
||||
: ChoicePropertyComponent (name, choiceList, correspondingValues)
|
||||
{
|
||||
createComboBoxWithDefault (choiceList [correspondingValues.indexOf (valueToControl.getDefault())]);
|
||||
|
||||
comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSourceWithDefault (valueToControl,
|
||||
correspondingValues)));
|
||||
|
||||
valueToControl.onDefaultChange = [this, &valueToControl, choiceList, correspondingValues]
|
||||
{
|
||||
auto selectedId = comboBox.getSelectedId();
|
||||
|
||||
comboBox.clear();
|
||||
createComboBoxWithDefault (choiceList [correspondingValues.indexOf (valueToControl.getDefault())]);
|
||||
|
||||
comboBox.setSelectedId (selectedId);
|
||||
};
|
||||
}
|
||||
|
||||
ChoicePropertyComponent::ChoicePropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& name)
|
||||
: PropertyComponent (name),
|
||||
choices ({ "Enabled", "Disabled" })
|
||||
{
|
||||
createComboBoxWithDefault (valueToControl.getDefault() ? "Enabled" : "Disabled");
|
||||
|
||||
comboBox.getSelectedIdAsValue().referTo (Value (new RemapperValueSourceWithDefault (valueToControl,
|
||||
{ true, false })));
|
||||
|
||||
valueToControl.onDefaultChange = [this, &valueToControl]
|
||||
{
|
||||
auto selectedId = comboBox.getSelectedId();
|
||||
|
||||
comboBox.clear();
|
||||
createComboBoxWithDefault (valueToControl.getDefault() ? "Enabled" : "Disabled");
|
||||
|
||||
comboBox.setSelectedId (selectedId);
|
||||
};
|
||||
}
|
||||
|
||||
ChoicePropertyComponent::~ChoicePropertyComponent()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ChoicePropertyComponent::createComboBox()
|
||||
{
|
||||
addAndMakeVisible (comboBox);
|
||||
|
||||
for (auto choice : choices)
|
||||
{
|
||||
if (choice.isNotEmpty())
|
||||
comboBox.addItem (choice, choices.indexOf (choice) + 1);
|
||||
else
|
||||
comboBox.addSeparator();
|
||||
}
|
||||
|
||||
comboBox.setEditableText (false);
|
||||
}
|
||||
|
||||
void ChoicePropertyComponent::createComboBoxWithDefault (const String& defaultString)
|
||||
{
|
||||
addAndMakeVisible (comboBox);
|
||||
|
||||
comboBox.addItem ("Default" + (defaultString.isNotEmpty() ? " (" + defaultString + ")" : ""), -1);
|
||||
|
||||
for (auto choice : choices)
|
||||
{
|
||||
if (choice.isNotEmpty())
|
||||
comboBox.addItem (choice, choices.indexOf (choice) + 1);
|
||||
else
|
||||
comboBox.addSeparator();
|
||||
}
|
||||
|
||||
comboBox.setEditableText (false);
|
||||
}
|
||||
|
||||
void ChoicePropertyComponent::setIndex (const int /*newIndex*/)
|
||||
{
|
||||
jassertfalse; // you need to override this method in your subclass!
|
||||
}
|
||||
|
||||
int ChoicePropertyComponent::getIndex() const
|
||||
{
|
||||
jassertfalse; // you need to override this method in your subclass!
|
||||
return -1;
|
||||
}
|
||||
|
||||
const StringArray& ChoicePropertyComponent::getChoices() const
|
||||
{
|
||||
return choices;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ChoicePropertyComponent::refresh()
|
||||
{
|
||||
if (isCustomClass)
|
||||
{
|
||||
if (! comboBox.isVisible())
|
||||
{
|
||||
createComboBox();
|
||||
comboBox.onChange = [this] { changeIndex(); };
|
||||
}
|
||||
|
||||
comboBox.setSelectedId (getIndex() + 1, dontSendNotification);
|
||||
}
|
||||
}
|
||||
|
||||
void ChoicePropertyComponent::changeIndex()
|
||||
{
|
||||
if (isCustomClass)
|
||||
{
|
||||
auto newIndex = comboBox.getSelectedId() - 1;
|
||||
|
||||
if (newIndex != getIndex())
|
||||
setIndex (newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 a combo box.
|
||||
|
||||
This type of property component contains a list of options and has a
|
||||
combo box to choose one.
|
||||
|
||||
Your subclass's constructor must add some strings to the choices StringArray
|
||||
and these are shown in the list.
|
||||
|
||||
The getIndex() method will be called to find out which option is the currently
|
||||
selected one. If you call refresh() it will call getIndex() to check whether
|
||||
the value has changed, and will update the combo box if needed.
|
||||
|
||||
If the user selects a different item from the list, setIndex() will be
|
||||
called to let your class process this.
|
||||
|
||||
@see PropertyComponent, PropertyPanel
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API ChoicePropertyComponent : public PropertyComponent
|
||||
{
|
||||
protected:
|
||||
/** Creates the component.
|
||||
Your subclass's constructor must add a list of options to the choices member variable.
|
||||
*/
|
||||
ChoicePropertyComponent (const String& propertyName);
|
||||
|
||||
public:
|
||||
/** Creates the component.
|
||||
|
||||
Note that if you call this constructor then you must use the Value to interact with the
|
||||
index, and you can't override the class with your own setIndex or getIndex methods.
|
||||
If you want to use those methods, call the other constructor instead.
|
||||
|
||||
@param valueToControl the value that the combo box will read and control
|
||||
@param propertyName the name of the property
|
||||
@param choices the list of possible values that the drop-down list will contain
|
||||
@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
|
||||
*/
|
||||
ChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues);
|
||||
|
||||
/** Creates the component using a ValueWithDefault object. This will add an item to the ComboBox for the
|
||||
default value with an ID of -1.
|
||||
|
||||
@param valueToControl the ValueWithDefault object that contains the Value object that the combo box will read and control
|
||||
@param propertyName the name of the property
|
||||
@param choices the list of possible values that the drop-down list will contain
|
||||
@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
|
||||
|
||||
*/
|
||||
ChoicePropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues);
|
||||
|
||||
/** Creates the component using a ValueWithDefault object, adding an item to the ComboBox for the
|
||||
default value with an ID of -1 as well as adding separate "Enabled" and "Disabled" options.
|
||||
|
||||
This is useful for simple on/off choices that also need a default value.
|
||||
*/
|
||||
ChoicePropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& propertyName);
|
||||
|
||||
/** Destructor. */
|
||||
~ChoicePropertyComponent();
|
||||
|
||||
//==============================================================================
|
||||
/** Called when the user selects an item from the combo box.
|
||||
|
||||
Your subclass must use this callback to update the value that this component
|
||||
represents. The index is the index of the chosen item in the choices
|
||||
StringArray.
|
||||
*/
|
||||
virtual void setIndex (int newIndex);
|
||||
|
||||
/** Returns the index of the item that should currently be shown.
|
||||
This is the index of the item in the choices StringArray that will be shown.
|
||||
*/
|
||||
virtual int getIndex() const;
|
||||
|
||||
/** Returns the list of options. */
|
||||
const StringArray& getChoices() const;
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void refresh() override;
|
||||
|
||||
protected:
|
||||
/** The list of options that will be shown in the combo box.
|
||||
|
||||
Your subclass must populate this array in its constructor. If any empty
|
||||
strings are added, these will be replaced with horizontal separators (see
|
||||
ComboBox::addSeparator() for more info).
|
||||
*/
|
||||
StringArray choices;
|
||||
|
||||
private:
|
||||
/** Delegating constructor. */
|
||||
ChoicePropertyComponent (const String&, const StringArray&, const Array<var>&);
|
||||
|
||||
ComboBox comboBox;
|
||||
bool isCustomClass = false;
|
||||
|
||||
class RemapperValueSource;
|
||||
class RemapperValueSourceWithDefault;
|
||||
|
||||
void createComboBox();
|
||||
void createComboBoxWithDefault (const String&);
|
||||
|
||||
void changeIndex();
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChoicePropertyComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,340 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 StringComparator
|
||||
{
|
||||
public:
|
||||
static int compareElements (var first, var second)
|
||||
{
|
||||
if (first.toString() > second.toString())
|
||||
return 1;
|
||||
else if (first.toString() < second.toString())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class MultiChoicePropertyComponent::MultiChoiceRemapperSource : public Value::ValueSource,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
MultiChoiceRemapperSource (const Value& source, var v, int c)
|
||||
: sourceValue (source),
|
||||
varToControl (v),
|
||||
maxChoices (c)
|
||||
{
|
||||
sourceValue.addListener (this);
|
||||
}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
if (auto* arr = sourceValue.getValue().getArray())
|
||||
if (arr->contains (varToControl))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
if (auto* arr = sourceValue.getValue().getArray())
|
||||
{
|
||||
auto temp = *arr;
|
||||
|
||||
if (static_cast<bool> (newValue))
|
||||
{
|
||||
if (temp.addIfNotAlreadyThere (varToControl) && (maxChoices != -1) && (temp.size() > maxChoices))
|
||||
temp.remove (temp.size() - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.remove (arr->indexOf (varToControl));
|
||||
}
|
||||
|
||||
StringComparator c;
|
||||
temp.sort (c);
|
||||
|
||||
sourceValue = temp;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Value sourceValue;
|
||||
var varToControl;
|
||||
|
||||
int maxChoices;
|
||||
|
||||
//==============================================================================
|
||||
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 (ValueWithDefault& vwd, var v, int c, ToggleButton* b)
|
||||
: valueWithDefault (vwd),
|
||||
varToControl (v),
|
||||
sourceValue (valueWithDefault.getPropertyAsValue()),
|
||||
maxChoices (c),
|
||||
buttonToControl (b)
|
||||
{
|
||||
sourceValue.addListener (this);
|
||||
}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
auto v = valueWithDefault.get();
|
||||
|
||||
if (auto* arr = v.getArray())
|
||||
{
|
||||
if (arr->contains (varToControl))
|
||||
{
|
||||
updateButtonTickColour();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
auto v = valueWithDefault.get();
|
||||
|
||||
OptionalScopedPointer<Array<var>> arrayToControl;
|
||||
|
||||
if (valueWithDefault.isUsingDefault())
|
||||
arrayToControl.set (new Array<var>(), true); // use an empty array so the default values are overwritten
|
||||
else
|
||||
arrayToControl.set (v.getArray(), false);
|
||||
|
||||
if (arrayToControl != nullptr)
|
||||
{
|
||||
auto temp = *arrayToControl;
|
||||
|
||||
bool newState = newValue;
|
||||
|
||||
if (valueWithDefault.isUsingDefault())
|
||||
{
|
||||
if (auto* defaultArray = v.getArray())
|
||||
{
|
||||
if (defaultArray->contains (varToControl))
|
||||
newState = true; // force the state as the user is setting it explicitly
|
||||
}
|
||||
}
|
||||
|
||||
if (newState)
|
||||
{
|
||||
if (temp.addIfNotAlreadyThere (varToControl) && (maxChoices != -1) && (temp.size() > maxChoices))
|
||||
temp.remove (temp.size() - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.remove (temp.indexOf (varToControl));
|
||||
}
|
||||
|
||||
StringComparator c;
|
||||
temp.sort (c);
|
||||
|
||||
valueWithDefault = temp;
|
||||
|
||||
if (temp.size() == 0)
|
||||
valueWithDefault.resetToDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ValueWithDefault& valueWithDefault;
|
||||
var varToControl;
|
||||
Value sourceValue;
|
||||
|
||||
int maxChoices;
|
||||
|
||||
ToggleButton* buttonToControl;
|
||||
|
||||
//==============================================================================
|
||||
void valueChanged (Value&) override { sendChangeMessage (true); }
|
||||
|
||||
void updateButtonTickColour() const noexcept
|
||||
{
|
||||
auto alpha = valueWithDefault.isUsingDefault() ? 0.4f : 1.0f;
|
||||
auto baseColour = buttonToControl->findColour (ToggleButton::tickColourId);
|
||||
|
||||
buttonToControl->setColour (ToggleButton::tickColourId, baseColour.withAlpha (alpha));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
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,
|
||||
int maxChoices)
|
||||
: 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],
|
||||
maxChoices)));
|
||||
}
|
||||
|
||||
MultiChoicePropertyComponent::MultiChoicePropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues,
|
||||
int maxChoices)
|
||||
: 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],
|
||||
maxChoices,
|
||||
choiceButtons[i])));
|
||||
|
||||
valueToControl.onDefaultChange = [this] { repaint(); };
|
||||
}
|
||||
|
||||
void MultiChoicePropertyComponent::paint (Graphics& g)
|
||||
{
|
||||
g.setColour (findColour (TextEditor::backgroundColourId));
|
||||
g.fillRect (getLookAndFeel().getPropertyComponentContentPosition (*this));
|
||||
|
||||
if (! expanded)
|
||||
{
|
||||
g.setColour (findColour (TextEditor::backgroundColourId).contrasting().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);
|
||||
|
||||
auto buttonSlice = bounds.removeFromBottom (10);
|
||||
expandButton.setSize (10, 10);
|
||||
expandButton.setCentrePosition (buttonSlice.getCentre());
|
||||
|
||||
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()));
|
||||
|
||||
resized();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MultiChoicePropertyComponent::lookAndFeelChanged()
|
||||
{
|
||||
auto iconColour = findColour (TextEditor::backgroundColourId).contrasting();
|
||||
expandButton.setColours (iconColour, iconColour.darker(), iconColour.darker());
|
||||
}
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
@param maxChoices the maxmimum number of values which can be selected at once. The default of
|
||||
-1 will not limit the number that can be selected
|
||||
*/
|
||||
MultiChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues,
|
||||
int maxChoices = -1);
|
||||
|
||||
/** 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
|
||||
@param maxChoices the maxmimum number of values which can be selected at once. The default of
|
||||
-1 will not limit the number that can be selected
|
||||
*/
|
||||
MultiChoicePropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues,
|
||||
int maxChoices = -1);
|
||||
|
||||
//==============================================================================
|
||||
/** 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
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
PropertyComponent::PropertyComponent (const String& name, const int preferredHeight_)
|
||||
: Component (name), preferredHeight (preferredHeight_)
|
||||
{
|
||||
jassert (name.isNotEmpty());
|
||||
}
|
||||
|
||||
PropertyComponent::~PropertyComponent() {}
|
||||
|
||||
void PropertyComponent::paint (Graphics& g)
|
||||
{
|
||||
LookAndFeel& lf = getLookAndFeel();
|
||||
|
||||
lf.drawPropertyComponentBackground (g, getWidth(), getHeight(), *this);
|
||||
lf.drawPropertyComponentLabel (g, getWidth(), getHeight(), *this);
|
||||
}
|
||||
|
||||
void PropertyComponent::resized()
|
||||
{
|
||||
if (Component* const c = getChildComponent(0))
|
||||
c->setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
|
||||
}
|
||||
|
||||
void PropertyComponent::enablementChanged()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
} // namespace juce
|
146
modules/juce_gui_basics/properties/juce_PropertyComponent.h
Normal file
146
modules/juce_gui_basics/properties/juce_PropertyComponent.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 base class for a component that goes in a PropertyPanel and displays one of
|
||||
an item's properties.
|
||||
|
||||
Subclasses of this are used to display a property in various forms, e.g. a
|
||||
ChoicePropertyComponent shows its value as a combo box; a SliderPropertyComponent
|
||||
shows its value as a slider; a TextPropertyComponent as a text box, etc.
|
||||
|
||||
A subclass must implement the refresh() method which will be called to tell the
|
||||
component to update itself, and is also responsible for calling this it when the
|
||||
item that it refers to is changed.
|
||||
|
||||
@see PropertyPanel, TextPropertyComponent, SliderPropertyComponent,
|
||||
ChoicePropertyComponent, ButtonPropertyComponent, BooleanPropertyComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API PropertyComponent : public Component,
|
||||
public SettableTooltipClient
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a PropertyComponent.
|
||||
|
||||
@param propertyName the name is stored as this component's name, and is
|
||||
used as the name displayed next to this component in
|
||||
a property panel
|
||||
@param preferredHeight the height that the component should be given - some
|
||||
items may need to be larger than a normal row height.
|
||||
This value can also be set if a subclass changes the
|
||||
preferredHeight member variable.
|
||||
*/
|
||||
PropertyComponent (const String& propertyName,
|
||||
int preferredHeight = 25);
|
||||
|
||||
/** Destructor. */
|
||||
~PropertyComponent();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns this item's preferred height.
|
||||
|
||||
This value is specified either in the constructor or by a subclass changing the
|
||||
preferredHeight member variable.
|
||||
*/
|
||||
int getPreferredHeight() const noexcept { return preferredHeight; }
|
||||
|
||||
void setPreferredHeight (int newHeight) noexcept { preferredHeight = newHeight; }
|
||||
|
||||
//==============================================================================
|
||||
/** Updates the property component if the item it refers to has changed.
|
||||
|
||||
A subclass must implement this method, and other objects may call it to
|
||||
force it to refresh itself.
|
||||
|
||||
The subclass should be economical in the amount of work is done, so for
|
||||
example it should check whether it really needs to do a repaint rather than
|
||||
just doing one every time this method is called, as it may be called when
|
||||
the value being displayed hasn't actually changed.
|
||||
*/
|
||||
virtual void refresh() = 0;
|
||||
|
||||
|
||||
/** The default paint method fills the background and draws a label for the
|
||||
item's name.
|
||||
|
||||
@see LookAndFeel::drawPropertyComponentBackground(), LookAndFeel::drawPropertyComponentLabel()
|
||||
*/
|
||||
void paint (Graphics&) override;
|
||||
|
||||
/** The default resize method positions any child component to the right of this
|
||||
one, based on the look and feel's default label size.
|
||||
*/
|
||||
void resized() override;
|
||||
|
||||
/** By default, this just repaints the component. */
|
||||
void enablementChanged() override;
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the combo box.
|
||||
|
||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
|
||||
methods.
|
||||
|
||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
||||
*/
|
||||
enum ColourIds
|
||||
{
|
||||
backgroundColourId = 0x1008300, /**< The background colour to fill the component with. */
|
||||
labelTextColourId = 0x1008301, /**< The colour for the property's label text. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** This abstract base class is implemented by LookAndFeel classes. */
|
||||
struct JUCE_API LookAndFeelMethods
|
||||
{
|
||||
virtual ~LookAndFeelMethods() {}
|
||||
|
||||
virtual void drawPropertyPanelSectionHeader (Graphics&, const String& name, bool isOpen, int width, int height) = 0;
|
||||
virtual void drawPropertyComponentBackground (Graphics&, int width, int height, PropertyComponent&) = 0;
|
||||
virtual void drawPropertyComponentLabel (Graphics&, int width, int height, PropertyComponent&) = 0;
|
||||
virtual Rectangle<int> getPropertyComponentContentPosition (PropertyComponent&) = 0;
|
||||
virtual int getPropertyPanelSectionHeaderHeight (const String& sectionTitle) = 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
/** Used by the PropertyPanel to determine how high this component needs to be.
|
||||
A subclass can update this value in its constructor but shouldn't alter it later
|
||||
as changes won't necessarily be picked up.
|
||||
*/
|
||||
int preferredHeight;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
374
modules/juce_gui_basics/properties/juce_PropertyPanel.cpp
Normal file
374
modules/juce_gui_basics/properties/juce_PropertyPanel.cpp
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
struct PropertyPanel::SectionComponent : public Component
|
||||
{
|
||||
SectionComponent (const String& sectionTitle,
|
||||
const Array<PropertyComponent*>& newProperties,
|
||||
bool sectionIsOpen)
|
||||
: Component (sectionTitle),
|
||||
titleHeight (getLookAndFeel().getPropertyPanelSectionHeaderHeight (sectionTitle)),
|
||||
isOpen (sectionIsOpen)
|
||||
{
|
||||
propertyComps.addArray (newProperties);
|
||||
|
||||
for (auto* propertyComponent : propertyComps)
|
||||
{
|
||||
addAndMakeVisible (propertyComponent);
|
||||
propertyComponent->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
~SectionComponent()
|
||||
{
|
||||
propertyComps.clear();
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (titleHeight > 0)
|
||||
getLookAndFeel().drawPropertyPanelSectionHeader (g, getName(), isOpen, getWidth(), titleHeight);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto y = titleHeight;
|
||||
|
||||
for (auto* propertyComponent : propertyComps)
|
||||
{
|
||||
propertyComponent->setBounds (1, y, getWidth() - 2, propertyComponent->getPreferredHeight());
|
||||
y = propertyComponent->getBottom();
|
||||
}
|
||||
}
|
||||
|
||||
int getPreferredHeight() const
|
||||
{
|
||||
auto y = titleHeight;
|
||||
|
||||
if (isOpen)
|
||||
for (auto* propertyComponent : propertyComps)
|
||||
y += propertyComponent->getPreferredHeight();
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
void setOpen (bool open)
|
||||
{
|
||||
if (isOpen != open)
|
||||
{
|
||||
isOpen = open;
|
||||
|
||||
for (auto* propertyComponent : propertyComps)
|
||||
propertyComponent->setVisible (open);
|
||||
|
||||
if (auto* propertyPanel = findParentComponentOfClass<PropertyPanel>())
|
||||
propertyPanel->resized();
|
||||
}
|
||||
}
|
||||
|
||||
void refreshAll() const
|
||||
{
|
||||
for (auto* propertyComponent : propertyComps)
|
||||
propertyComponent->refresh();
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent& e) override
|
||||
{
|
||||
if (e.getMouseDownX() < titleHeight
|
||||
&& e.x < titleHeight
|
||||
&& e.getNumberOfClicks() != 2)
|
||||
mouseDoubleClick (e);
|
||||
}
|
||||
|
||||
void mouseDoubleClick (const MouseEvent& e) override
|
||||
{
|
||||
if (e.y < titleHeight)
|
||||
setOpen (! isOpen);
|
||||
}
|
||||
|
||||
OwnedArray<PropertyComponent> propertyComps;
|
||||
int titleHeight;
|
||||
bool isOpen;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (SectionComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct PropertyPanel::PropertyHolderComponent : public Component
|
||||
{
|
||||
PropertyHolderComponent() {}
|
||||
|
||||
void paint (Graphics&) override {}
|
||||
|
||||
void updateLayout (int width)
|
||||
{
|
||||
auto y = 0;
|
||||
|
||||
for (auto* section : sections)
|
||||
{
|
||||
section->setBounds (0, y, width, section->getPreferredHeight());
|
||||
y = section->getBottom();
|
||||
}
|
||||
|
||||
setSize (width, y);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void refreshAll() const
|
||||
{
|
||||
for (auto* section : sections)
|
||||
section->refreshAll();
|
||||
}
|
||||
|
||||
void insertSection (int indexToInsertAt, SectionComponent* newSection)
|
||||
{
|
||||
sections.insert (indexToInsertAt, newSection);
|
||||
addAndMakeVisible (newSection, 0);
|
||||
}
|
||||
|
||||
SectionComponent* getSectionWithNonEmptyName (int targetIndex) const noexcept
|
||||
{
|
||||
auto index = 0;
|
||||
for (auto* section : sections)
|
||||
{
|
||||
if (section->getName().isNotEmpty())
|
||||
if (index++ == targetIndex)
|
||||
return section;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OwnedArray<SectionComponent> sections;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (PropertyHolderComponent)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
PropertyPanel::PropertyPanel()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
PropertyPanel::PropertyPanel (const String& name) : Component (name)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void PropertyPanel::init()
|
||||
{
|
||||
messageWhenEmpty = TRANS("(nothing selected)");
|
||||
|
||||
addAndMakeVisible (viewport);
|
||||
viewport.setViewedComponent (propertyHolderComponent = new PropertyHolderComponent());
|
||||
viewport.setFocusContainer (true);
|
||||
}
|
||||
|
||||
PropertyPanel::~PropertyPanel()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::paint (Graphics& g)
|
||||
{
|
||||
if (isEmpty())
|
||||
{
|
||||
g.setColour (Colours::black.withAlpha (0.5f));
|
||||
g.setFont (14.0f);
|
||||
g.drawText (messageWhenEmpty, getLocalBounds().withHeight (30),
|
||||
Justification::centred, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::resized()
|
||||
{
|
||||
viewport.setBounds (getLocalBounds());
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::clear()
|
||||
{
|
||||
if (! isEmpty())
|
||||
{
|
||||
propertyHolderComponent->sections.clear();
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyPanel::isEmpty() const
|
||||
{
|
||||
return propertyHolderComponent->sections.size() == 0;
|
||||
}
|
||||
|
||||
int PropertyPanel::getTotalContentHeight() const
|
||||
{
|
||||
return propertyHolderComponent->getHeight();
|
||||
}
|
||||
|
||||
void PropertyPanel::addProperties (const Array<PropertyComponent*>& newProperties)
|
||||
{
|
||||
if (isEmpty())
|
||||
repaint();
|
||||
|
||||
propertyHolderComponent->insertSection (-1, new SectionComponent (String(), newProperties, true));
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
void PropertyPanel::addSection (const String& sectionTitle,
|
||||
const Array<PropertyComponent*>& newProperties,
|
||||
bool shouldBeOpen,
|
||||
int indexToInsertAt)
|
||||
{
|
||||
jassert (sectionTitle.isNotEmpty());
|
||||
|
||||
if (isEmpty())
|
||||
repaint();
|
||||
|
||||
propertyHolderComponent->insertSection (indexToInsertAt, new SectionComponent (sectionTitle, newProperties, shouldBeOpen));
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
void PropertyPanel::updatePropHolderLayout() const
|
||||
{
|
||||
auto maxWidth = viewport.getMaximumVisibleWidth();
|
||||
propertyHolderComponent->updateLayout (maxWidth);
|
||||
|
||||
auto newMaxWidth = viewport.getMaximumVisibleWidth();
|
||||
if (maxWidth != newMaxWidth)
|
||||
{
|
||||
// need to do this twice because of scrollbars changing the size, etc.
|
||||
propertyHolderComponent->updateLayout (newMaxWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::refreshAll() const
|
||||
{
|
||||
propertyHolderComponent->refreshAll();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
StringArray PropertyPanel::getSectionNames() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (auto* section : propertyHolderComponent->sections)
|
||||
{
|
||||
if (section->getName().isNotEmpty())
|
||||
s.add (section->getName());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool PropertyPanel::isSectionOpen (int sectionIndex) const
|
||||
{
|
||||
if (auto* s = propertyHolderComponent->getSectionWithNonEmptyName (sectionIndex))
|
||||
return s->isOpen;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PropertyPanel::setSectionOpen (int sectionIndex, bool shouldBeOpen)
|
||||
{
|
||||
if (auto* s = propertyHolderComponent->getSectionWithNonEmptyName (sectionIndex))
|
||||
s->setOpen (shouldBeOpen);
|
||||
}
|
||||
|
||||
void PropertyPanel::setSectionEnabled (int sectionIndex, bool shouldBeEnabled)
|
||||
{
|
||||
if (auto* s = propertyHolderComponent->getSectionWithNonEmptyName (sectionIndex))
|
||||
s->setEnabled (shouldBeEnabled);
|
||||
}
|
||||
|
||||
void PropertyPanel::removeSection (int sectionIndex)
|
||||
{
|
||||
if (auto* s = propertyHolderComponent->getSectionWithNonEmptyName (sectionIndex))
|
||||
{
|
||||
propertyHolderComponent->sections.removeObject (s);
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
XmlElement* PropertyPanel::getOpennessState() const
|
||||
{
|
||||
auto* xml = new XmlElement ("PROPERTYPANELSTATE");
|
||||
|
||||
xml->setAttribute ("scrollPos", viewport.getViewPositionY());
|
||||
|
||||
auto sections = getSectionNames();
|
||||
for (auto s : sections)
|
||||
{
|
||||
if (s.isNotEmpty())
|
||||
{
|
||||
auto* e = xml->createNewChildElement ("SECTION");
|
||||
e->setAttribute ("name", s);
|
||||
e->setAttribute ("open", isSectionOpen (sections.indexOf (s)) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
void PropertyPanel::restoreOpennessState (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName ("PROPERTYPANELSTATE"))
|
||||
{
|
||||
auto sections = getSectionNames();
|
||||
|
||||
forEachXmlChildElementWithTagName (xml, e, "SECTION")
|
||||
{
|
||||
setSectionOpen (sections.indexOf (e->getStringAttribute ("name")),
|
||||
e->getBoolAttribute ("open"));
|
||||
}
|
||||
|
||||
viewport.setViewPosition (viewport.getViewPositionX(),
|
||||
xml.getIntAttribute ("scrollPos", viewport.getViewPositionY()));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::setMessageWhenEmpty (const String& newMessage)
|
||||
{
|
||||
if (messageWhenEmpty != newMessage)
|
||||
{
|
||||
messageWhenEmpty = newMessage;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
const String& PropertyPanel::getMessageWhenEmpty() const noexcept
|
||||
{
|
||||
return messageWhenEmpty;
|
||||
}
|
||||
|
||||
} // namespace juce
|
179
modules/juce_gui_basics/properties/juce_PropertyPanel.h
Normal file
179
modules/juce_gui_basics/properties/juce_PropertyPanel.h
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 panel that holds a list of PropertyComponent objects.
|
||||
|
||||
This panel displays a list of PropertyComponents, and allows them to be organised
|
||||
into collapsible sections.
|
||||
|
||||
To use, simply create one of these and add your properties to it with addProperties()
|
||||
or addSection().
|
||||
|
||||
@see PropertyComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API PropertyPanel : public Component
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty property panel. */
|
||||
PropertyPanel();
|
||||
|
||||
/** Creates an empty property panel. */
|
||||
PropertyPanel (const String& name);
|
||||
|
||||
/** Destructor. */
|
||||
~PropertyPanel();
|
||||
|
||||
//==============================================================================
|
||||
/** Deletes all property components from the panel. */
|
||||
void clear();
|
||||
|
||||
/** Adds a set of properties to the panel.
|
||||
|
||||
The components in the list will be owned by this object and will be automatically
|
||||
deleted later on when no longer needed.
|
||||
|
||||
These properties are added without them being inside a named section. If you
|
||||
want them to be kept together in a collapsible section, use addSection() instead.
|
||||
*/
|
||||
void addProperties (const Array<PropertyComponent*>& newPropertyComponents);
|
||||
|
||||
/** Adds a set of properties to the panel.
|
||||
|
||||
These properties are added under a section heading with a plus/minus button that
|
||||
allows it to be opened and closed. If indexToInsertAt is < 0 then it will be added
|
||||
at the end of the list, or before the given index if the index is non-zero.
|
||||
|
||||
The components in the list will be owned by this object and will be automatically
|
||||
deleted later on when no longer needed.
|
||||
|
||||
To add properies without them being in a section, use addProperties().
|
||||
*/
|
||||
void addSection (const String& sectionTitle,
|
||||
const Array<PropertyComponent*>& newPropertyComponents,
|
||||
bool shouldSectionInitiallyBeOpen = true,
|
||||
int indexToInsertAt = -1);
|
||||
|
||||
/** Calls the refresh() method of all PropertyComponents in the panel */
|
||||
void refreshAll() const;
|
||||
|
||||
/** Returns true if the panel contains no properties. */
|
||||
bool isEmpty() const;
|
||||
|
||||
/** Returns the height that the panel needs in order to display all of its content
|
||||
without scrolling.
|
||||
*/
|
||||
int getTotalContentHeight() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a list of all the names of sections in the panel.
|
||||
These are the sections that have been added with addSection().
|
||||
*/
|
||||
StringArray getSectionNames() const;
|
||||
|
||||
/** Returns true if the section at this index is currently open.
|
||||
The index is from 0 up to the number of items returned by getSectionNames().
|
||||
*/
|
||||
bool isSectionOpen (int sectionIndex) const;
|
||||
|
||||
/** Opens or closes one of the sections.
|
||||
The index is from 0 up to the number of items returned by getSectionNames().
|
||||
*/
|
||||
void setSectionOpen (int sectionIndex, bool shouldBeOpen);
|
||||
|
||||
/** Enables or disables one of the sections.
|
||||
The index is from 0 up to the number of items returned by getSectionNames().
|
||||
*/
|
||||
void setSectionEnabled (int sectionIndex, bool shouldBeEnabled);
|
||||
|
||||
/** Remove one of the sections using the section index.
|
||||
The index is from 0 up to the number of items returned by getSectionNames().
|
||||
*/
|
||||
void removeSection (int sectionIndex);
|
||||
|
||||
//==============================================================================
|
||||
/** Saves the current state of open/closed sections so it can be restored later.
|
||||
|
||||
The caller is responsible for deleting the object that is returned.
|
||||
To restore this state, use restoreOpennessState().
|
||||
|
||||
@see restoreOpennessState
|
||||
*/
|
||||
XmlElement* getOpennessState() const;
|
||||
|
||||
/** Restores a previously saved arrangement of open/closed sections.
|
||||
|
||||
This will try to restore a snapshot of the panel's state that was created by
|
||||
the getOpennessState() method. If any of the sections named in the original
|
||||
XML aren't present, they will be ignored.
|
||||
|
||||
@see getOpennessState
|
||||
*/
|
||||
void restoreOpennessState (const XmlElement& newState);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets a message to be displayed when there are no properties in the panel.
|
||||
The default message is "nothing selected".
|
||||
*/
|
||||
void setMessageWhenEmpty (const String& newMessage);
|
||||
|
||||
/** Returns the message that is displayed when there are no properties.
|
||||
@see setMessageWhenEmpty
|
||||
*/
|
||||
const String& getMessageWhenEmpty() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the PropertyPanel's internal Viewport. */
|
||||
Viewport& getViewport() noexcept { return viewport; }
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
Viewport viewport;
|
||||
struct SectionComponent;
|
||||
struct PropertyHolderComponent;
|
||||
PropertyHolderComponent* propertyHolderComponent;
|
||||
String messageWhenEmpty;
|
||||
|
||||
void init();
|
||||
void updatePropHolderLayout() const;
|
||||
void updatePropHolderLayout (int width) const;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyPanel)
|
||||
};
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
SliderPropertyComponent::SliderPropertyComponent (const String& name,
|
||||
const double rangeMin,
|
||||
const double rangeMax,
|
||||
const double interval,
|
||||
const double skewFactor,
|
||||
bool symmetricSkew)
|
||||
: PropertyComponent (name)
|
||||
{
|
||||
addAndMakeVisible (slider);
|
||||
|
||||
slider.setRange (rangeMin, rangeMax, interval);
|
||||
slider.setSkewFactor (skewFactor, symmetricSkew);
|
||||
slider.setSliderStyle (Slider::LinearBar);
|
||||
|
||||
slider.onValueChange = [this]
|
||||
{
|
||||
if (getValue() != slider.getValue())
|
||||
setValue (slider.getValue());
|
||||
};
|
||||
}
|
||||
|
||||
SliderPropertyComponent::SliderPropertyComponent (const Value& valueToControl,
|
||||
const String& name,
|
||||
const double rangeMin,
|
||||
const double rangeMax,
|
||||
const double interval,
|
||||
const double skewFactor,
|
||||
bool symmetricSkew)
|
||||
: PropertyComponent (name)
|
||||
{
|
||||
addAndMakeVisible (slider);
|
||||
|
||||
slider.setRange (rangeMin, rangeMax, interval);
|
||||
slider.setSkewFactor (skewFactor, symmetricSkew);
|
||||
slider.setSliderStyle (Slider::LinearBar);
|
||||
|
||||
slider.getValueObject().referTo (valueToControl);
|
||||
}
|
||||
|
||||
SliderPropertyComponent::~SliderPropertyComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void SliderPropertyComponent::setValue (const double /*newValue*/)
|
||||
{
|
||||
}
|
||||
|
||||
double SliderPropertyComponent::getValue() const
|
||||
{
|
||||
return slider.getValue();
|
||||
}
|
||||
|
||||
void SliderPropertyComponent::refresh()
|
||||
{
|
||||
slider.setValue (getValue(), dontSendNotification);
|
||||
}
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 a slider.
|
||||
|
||||
@see PropertyComponent, Slider
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API SliderPropertyComponent : public PropertyComponent
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates the property component.
|
||||
|
||||
The ranges, interval and skew factor are passed to the Slider component.
|
||||
|
||||
If you need to customise the slider in other ways, your constructor can
|
||||
access the slider member variable and change it directly.
|
||||
*/
|
||||
SliderPropertyComponent (const String& propertyName,
|
||||
double rangeMin,
|
||||
double rangeMax,
|
||||
double interval,
|
||||
double skewFactor = 1.0,
|
||||
bool symmetricSkew = false);
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates the property component.
|
||||
|
||||
The ranges, interval and skew factor are passed to the Slider component.
|
||||
|
||||
If you need to customise the slider in other ways, your constructor can
|
||||
access the slider member variable and change it directly.
|
||||
|
||||
Note that if you call this constructor then you must use the Value to interact with
|
||||
the value, and you can't override the class with your own setValue or getValue methods.
|
||||
If you want to use those methods, call the other constructor instead.
|
||||
*/
|
||||
SliderPropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
double rangeMin,
|
||||
double rangeMax,
|
||||
double interval,
|
||||
double skewFactor = 1.0,
|
||||
bool symmetricSkew = false);
|
||||
|
||||
/** Destructor. */
|
||||
~SliderPropertyComponent();
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Called when the user moves the slider to change its value.
|
||||
|
||||
Your subclass must use this method to update whatever item this property
|
||||
represents.
|
||||
*/
|
||||
virtual void setValue (double newValue);
|
||||
|
||||
/** Returns the value that the slider should show. */
|
||||
virtual double getValue() const;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void refresh();
|
||||
|
||||
protected:
|
||||
/** The slider component being used in this component.
|
||||
Your subclass has access to this in case it needs to customise it in some way.
|
||||
*/
|
||||
Slider slider;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderPropertyComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
@ -0,0 +1,262 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 TextPropertyComponent::LabelComp : public Label,
|
||||
public FileDragAndDropTarget
|
||||
{
|
||||
public:
|
||||
LabelComp (TextPropertyComponent& tpc, int charLimit, bool multiline, bool editable)
|
||||
: Label ({}, {}),
|
||||
owner (tpc),
|
||||
maxChars (charLimit),
|
||||
isMultiline (multiline)
|
||||
{
|
||||
setEditable (editable, editable);
|
||||
|
||||
updateColours();
|
||||
}
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray&) override
|
||||
{
|
||||
return interestedInFileDrag;
|
||||
}
|
||||
|
||||
void filesDropped (const StringArray& files, int, int) override
|
||||
{
|
||||
setText (getText() + files.joinIntoString (isMultiline ? "\n" : ", "), sendNotificationSync);
|
||||
showEditor();
|
||||
}
|
||||
|
||||
TextEditor* createEditorComponent() override
|
||||
{
|
||||
auto* ed = Label::createEditorComponent();
|
||||
ed->setInputRestrictions (maxChars);
|
||||
|
||||
if (isMultiline)
|
||||
{
|
||||
ed->setMultiLine (true, true);
|
||||
ed->setReturnKeyStartsNewLine (true);
|
||||
}
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
void textWasEdited() override
|
||||
{
|
||||
owner.textWasEdited();
|
||||
}
|
||||
|
||||
void updateColours()
|
||||
{
|
||||
setColour (backgroundColourId, owner.findColour (TextPropertyComponent::backgroundColourId));
|
||||
setColour (outlineColourId, owner.findColour (TextPropertyComponent::outlineColourId));
|
||||
setColour (textColourId, owner.findColour (TextPropertyComponent::textColourId));
|
||||
repaint();
|
||||
}
|
||||
|
||||
void setInterestedInFileDrag (bool isInterested)
|
||||
{
|
||||
interestedInFileDrag = isInterested;
|
||||
}
|
||||
|
||||
void setTextToDisplayWhenEmpty (const String& text, float alpha)
|
||||
{
|
||||
textToDisplayWhenEmpty = text;
|
||||
alphaToUseForEmptyText = alpha;
|
||||
}
|
||||
|
||||
void paintOverChildren (Graphics& g) override
|
||||
{
|
||||
if (getText().isEmpty() && ! isBeingEdited())
|
||||
{
|
||||
auto textArea = getBorderSize().subtractedFrom (getLocalBounds());
|
||||
auto labelFont = owner.getLookAndFeel().getLabelFont (*this);
|
||||
|
||||
g.setColour (owner.findColour (TextPropertyComponent::textColourId).withAlpha (alphaToUseForEmptyText));
|
||||
g.setFont (labelFont);
|
||||
|
||||
g.drawFittedText (textToDisplayWhenEmpty, textArea, getJustificationType(),
|
||||
jmax (1, (int) (textArea.getHeight() / labelFont.getHeight())),
|
||||
getMinimumHorizontalScale());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TextPropertyComponent& owner;
|
||||
|
||||
int maxChars;
|
||||
bool isMultiline;
|
||||
bool interestedInFileDrag = true;
|
||||
|
||||
String textToDisplayWhenEmpty;
|
||||
float alphaToUseForEmptyText = 0.0f;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextPropertyComponent::RemapperValueSourceWithDefault : public Value::ValueSource
|
||||
{
|
||||
public:
|
||||
RemapperValueSourceWithDefault (const ValueWithDefault& vwd)
|
||||
: valueWithDefault (vwd)
|
||||
{
|
||||
}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
return valueWithDefault.isUsingDefault() ? var() : valueWithDefault.get();
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
if (newValue.toString().isEmpty())
|
||||
valueWithDefault.resetToDefault();
|
||||
else
|
||||
valueWithDefault = newValue;
|
||||
}
|
||||
|
||||
private:
|
||||
ValueWithDefault valueWithDefault;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSourceWithDefault)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
TextPropertyComponent::TextPropertyComponent (const String& name,
|
||||
int maxNumChars,
|
||||
bool multiLine,
|
||||
bool isEditable)
|
||||
: PropertyComponent (name),
|
||||
isMultiLine (multiLine)
|
||||
{
|
||||
createEditor (maxNumChars, isEditable);
|
||||
}
|
||||
|
||||
TextPropertyComponent::TextPropertyComponent (const Value& valueToControl,
|
||||
const String& name,
|
||||
int maxNumChars,
|
||||
bool isMultiLine,
|
||||
bool isEditable)
|
||||
: TextPropertyComponent (name, maxNumChars, isMultiLine, isEditable)
|
||||
{
|
||||
textEditor->getTextValue().referTo (valueToControl);
|
||||
}
|
||||
|
||||
TextPropertyComponent::TextPropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& name,
|
||||
int maxNumChars,
|
||||
bool isMultiLine,
|
||||
bool isEditable)
|
||||
: TextPropertyComponent (name, maxNumChars, isMultiLine, isEditable)
|
||||
{
|
||||
textEditor->getTextValue().referTo (Value (new RemapperValueSourceWithDefault (valueToControl)));
|
||||
textEditor->setTextToDisplayWhenEmpty (valueToControl.getDefault(), 0.5f);
|
||||
|
||||
valueToControl.onDefaultChange = [this, &valueToControl]
|
||||
{
|
||||
textEditor->setTextToDisplayWhenEmpty (valueToControl.getDefault(), 0.5f);
|
||||
repaint();
|
||||
};
|
||||
}
|
||||
|
||||
TextPropertyComponent::~TextPropertyComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void TextPropertyComponent::setText (const String& newText)
|
||||
{
|
||||
textEditor->setText (newText, sendNotificationSync);
|
||||
}
|
||||
|
||||
String TextPropertyComponent::getText() const
|
||||
{
|
||||
return textEditor->getText();
|
||||
}
|
||||
|
||||
Value& TextPropertyComponent::getValue() const
|
||||
{
|
||||
return textEditor->getTextValue();
|
||||
}
|
||||
|
||||
void TextPropertyComponent::createEditor (int maxNumChars, bool isEditable)
|
||||
{
|
||||
textEditor.reset (new LabelComp (*this, maxNumChars, isMultiLine, isEditable));
|
||||
addAndMakeVisible (textEditor.get());
|
||||
|
||||
if (isMultiLine)
|
||||
{
|
||||
textEditor->setJustificationType (Justification::topLeft);
|
||||
preferredHeight = 100;
|
||||
}
|
||||
}
|
||||
|
||||
void TextPropertyComponent::refresh()
|
||||
{
|
||||
textEditor->setText (getText(), dontSendNotification);
|
||||
}
|
||||
|
||||
void TextPropertyComponent::textWasEdited()
|
||||
{
|
||||
auto newText = textEditor->getText();
|
||||
|
||||
if (getText() != newText)
|
||||
setText (newText);
|
||||
|
||||
callListeners();
|
||||
}
|
||||
|
||||
void TextPropertyComponent::addListener (TextPropertyComponent::Listener* l) { listenerList.add (l); }
|
||||
void TextPropertyComponent::removeListener (TextPropertyComponent::Listener* l) { listenerList.remove (l); }
|
||||
|
||||
void TextPropertyComponent::callListeners()
|
||||
{
|
||||
Component::BailOutChecker checker (this);
|
||||
listenerList.callChecked (checker, [this] (Listener& l) { l.textPropertyComponentChanged (this); });
|
||||
}
|
||||
|
||||
void TextPropertyComponent::colourChanged()
|
||||
{
|
||||
PropertyComponent::colourChanged();
|
||||
textEditor->updateColours();
|
||||
}
|
||||
|
||||
void TextPropertyComponent::setInterestedInFileDrag (bool isInterested)
|
||||
{
|
||||
if (textEditor != nullptr)
|
||||
textEditor->setInterestedInFileDrag (isInterested);
|
||||
}
|
||||
|
||||
void TextPropertyComponent::setEditable (bool isEditable)
|
||||
{
|
||||
if (textEditor != nullptr)
|
||||
textEditor->setEditable (isEditable, isEditable);
|
||||
}
|
||||
|
||||
} // namespace juce
|
188
modules/juce_gui_basics/properties/juce_TextPropertyComponent.h
Normal file
188
modules/juce_gui_basics/properties/juce_TextPropertyComponent.h
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 editable text.
|
||||
|
||||
@see PropertyComponent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API TextPropertyComponent : public PropertyComponent
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates a text property component.
|
||||
|
||||
@param propertyName The name of the property
|
||||
@param maxNumChars If not zero, then this specifies the maximum allowable length of
|
||||
the string. If zero, then the string will have no length limit.
|
||||
@param isMultiLine Sets whether the text editor allows carriage returns.
|
||||
@param isEditable Sets whether the text editor is editable. The default is true.
|
||||
|
||||
@see TextEditor, setEditable
|
||||
*/
|
||||
TextPropertyComponent (const String& propertyName,
|
||||
int maxNumChars,
|
||||
bool isMultiLine,
|
||||
bool isEditable = true);
|
||||
|
||||
public:
|
||||
/** Creates a text property component.
|
||||
|
||||
@param valueToControl The Value that is controlled by the TextPropertyComponent
|
||||
@param propertyName The name of the property
|
||||
@param maxNumChars If not zero, then this specifies the maximum allowable length of
|
||||
the string. If zero, then the string will have no length limit.
|
||||
@param isMultiLine Sets whether the text editor allows carriage returns.
|
||||
@param isEditable Sets whether the text editor is editable. The default is true.
|
||||
|
||||
@see TextEditor, setEditable
|
||||
*/
|
||||
TextPropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
int maxNumChars,
|
||||
bool isMultiLine,
|
||||
bool isEditable = true);
|
||||
|
||||
/** Creates a text property component with a default value.
|
||||
|
||||
@param valueToControl The ValueWithDefault that is controlled by the TextPropertyComponent
|
||||
@param propertyName The name of the property
|
||||
@param maxNumChars If not zero, then this specifies the maximum allowable length of
|
||||
the string. If zero, then the string will have no length limit.
|
||||
@param isMultiLine Sets whether the text editor allows carriage returns.
|
||||
@param isEditable Sets whether the text editor is editable. The default is true.
|
||||
|
||||
@see TextEditor, setEditable
|
||||
*/
|
||||
TextPropertyComponent (ValueWithDefault& valueToControl,
|
||||
const String& propertyName,
|
||||
int maxNumChars,
|
||||
bool isMultiLine,
|
||||
bool isEditable = true);
|
||||
|
||||
/** Destructor. */
|
||||
~TextPropertyComponent();
|
||||
|
||||
//==============================================================================
|
||||
/** Called when the user edits the text.
|
||||
|
||||
Your subclass must use this callback to change the value of whatever item
|
||||
this property component represents.
|
||||
*/
|
||||
virtual void setText (const String& newText);
|
||||
|
||||
/** Returns the text that should be shown in the text editor. */
|
||||
virtual String getText() const;
|
||||
|
||||
/** Returns the text that should be shown in the text editor as a Value object. */
|
||||
Value& getValue() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the text editor allows carriage returns. */
|
||||
bool isTextEditorMultiLine() const noexcept { return isMultiLine; }
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the component.
|
||||
|
||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
|
||||
methods.
|
||||
|
||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
||||
*/
|
||||
enum ColourIds
|
||||
{
|
||||
backgroundColourId = 0x100e401, /**< The colour to fill the background of the text area. */
|
||||
textColourId = 0x100e402, /**< The colour to use for the editable text. */
|
||||
outlineColourId = 0x100e403, /**< The colour to use to draw an outline around the text area. */
|
||||
};
|
||||
|
||||
void colourChanged() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Used to receive callbacks for text changes */
|
||||
class JUCE_API Listener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~Listener() {}
|
||||
|
||||
/** Called when text has finished being entered (i.e. not per keypress) has changed. */
|
||||
virtual void textPropertyComponentChanged (TextPropertyComponent*) = 0;
|
||||
};
|
||||
|
||||
/** Registers a listener to receive events when this button's state changes.
|
||||
If the listener is already registered, this will not register it again.
|
||||
@see removeListener
|
||||
*/
|
||||
void addListener (Listener* newListener);
|
||||
|
||||
/** Removes a previously-registered button listener
|
||||
@see addListener
|
||||
*/
|
||||
void removeListener (Listener* listener);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets whether the text property component can have files dropped onto it by an external application.
|
||||
|
||||
The default setting for this is true but you may want to disable this behaviour if you derive
|
||||
from this class and want your subclass to respond to the file drag.
|
||||
*/
|
||||
void setInterestedInFileDrag (bool isInterested);
|
||||
|
||||
/** Sets whether the text editor is editable. The default setting for this is true. */
|
||||
void setEditable (bool isEditable);
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void refresh() override;
|
||||
/** @internal */
|
||||
virtual void textWasEdited();
|
||||
|
||||
private:
|
||||
bool isMultiLine;
|
||||
|
||||
class RemapperValueSourceWithDefault;
|
||||
|
||||
class LabelComp;
|
||||
friend class LabelComp;
|
||||
|
||||
std::unique_ptr<LabelComp> textEditor;
|
||||
ListenerList<Listener> listenerList;
|
||||
|
||||
void callListeners();
|
||||
void createEditor (int maxNumChars, bool isEditable);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextPropertyComponent)
|
||||
};
|
||||
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user