migrating to the latest JUCE version

This commit is contained in:
2022-11-04 23:11:33 +01:00
committed by Nikolai Rodionov
parent 4257a0f8ba
commit faf8f18333
2796 changed files with 888518 additions and 784244 deletions

View File

@ -1,284 +1,284 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
MarkerList::MarkerList()
{
}
MarkerList::MarkerList (const MarkerList& other)
{
operator= (other);
}
MarkerList& MarkerList::operator= (const MarkerList& other)
{
if (other != *this)
{
markers.clear();
markers.addCopiesOf (other.markers);
markersHaveChanged();
}
return *this;
}
MarkerList::~MarkerList()
{
listeners.call ([this] (Listener& l) { l.markerListBeingDeleted (this); });
}
bool MarkerList::operator== (const MarkerList& other) const noexcept
{
if (other.markers.size() != markers.size())
return false;
for (int i = markers.size(); --i >= 0;)
{
const Marker* const m1 = markers.getUnchecked(i);
jassert (m1 != nullptr);
const Marker* const m2 = other.getMarker (m1->name);
if (m2 == nullptr || *m1 != *m2)
return false;
}
return true;
}
bool MarkerList::operator!= (const MarkerList& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
int MarkerList::getNumMarkers() const noexcept
{
return markers.size();
}
const MarkerList::Marker* MarkerList::getMarker (const int index) const noexcept
{
return markers [index];
}
const MarkerList::Marker* MarkerList::getMarker (const String& name) const noexcept
{
return getMarkerByName (name);
}
MarkerList::Marker* MarkerList::getMarkerByName (const String& name) const noexcept
{
for (int i = 0; i < markers.size(); ++i)
{
Marker* const m = markers.getUnchecked(i);
if (m->name == name)
return m;
}
return nullptr;
}
void MarkerList::setMarker (const String& name, const RelativeCoordinate& position)
{
if (Marker* const m = getMarkerByName (name))
{
if (m->position != position)
{
m->position = position;
markersHaveChanged();
}
return;
}
markers.add (new Marker (name, position));
markersHaveChanged();
}
void MarkerList::removeMarker (const int index)
{
if (isPositiveAndBelow (index, markers.size()))
{
markers.remove (index);
markersHaveChanged();
}
}
void MarkerList::removeMarker (const String& name)
{
for (int i = 0; i < markers.size(); ++i)
{
const Marker* const m = markers.getUnchecked(i);
if (m->name == name)
{
markers.remove (i);
markersHaveChanged();
}
}
}
void MarkerList::markersHaveChanged()
{
listeners.call ([this] (Listener& l) { l.markersChanged (this); });
}
void MarkerList::Listener::markerListBeingDeleted (MarkerList*)
{
}
void MarkerList::addListener (Listener* listener)
{
listeners.add (listener);
}
void MarkerList::removeListener (Listener* listener)
{
listeners.remove (listener);
}
//==============================================================================
MarkerList::Marker::Marker (const Marker& other)
: name (other.name), position (other.position)
{
}
MarkerList::Marker::Marker (const String& name_, const RelativeCoordinate& position_)
: name (name_), position (position_)
{
}
bool MarkerList::Marker::operator== (const Marker& other) const noexcept
{
return name == other.name && position == other.position;
}
bool MarkerList::Marker::operator!= (const Marker& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
const Identifier MarkerList::ValueTreeWrapper::markerTag ("Marker");
const Identifier MarkerList::ValueTreeWrapper::nameProperty ("name");
const Identifier MarkerList::ValueTreeWrapper::posProperty ("position");
MarkerList::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
: state (state_)
{
}
int MarkerList::ValueTreeWrapper::getNumMarkers() const
{
return state.getNumChildren();
}
ValueTree MarkerList::ValueTreeWrapper::getMarkerState (int index) const
{
return state.getChild (index);
}
ValueTree MarkerList::ValueTreeWrapper::getMarkerState (const String& name) const
{
return state.getChildWithProperty (nameProperty, name);
}
bool MarkerList::ValueTreeWrapper::containsMarker (const ValueTree& marker) const
{
return marker.isAChildOf (state);
}
MarkerList::Marker MarkerList::ValueTreeWrapper::getMarker (const ValueTree& marker) const
{
jassert (containsMarker (marker));
return MarkerList::Marker (marker [nameProperty], RelativeCoordinate (marker [posProperty].toString()));
}
void MarkerList::ValueTreeWrapper::setMarker (const MarkerList::Marker& m, UndoManager* undoManager)
{
ValueTree marker (state.getChildWithProperty (nameProperty, m.name));
if (marker.isValid())
{
marker.setProperty (posProperty, m.position.toString(), undoManager);
}
else
{
marker = ValueTree (markerTag);
marker.setProperty (nameProperty, m.name, nullptr);
marker.setProperty (posProperty, m.position.toString(), nullptr);
state.appendChild (marker, undoManager);
}
}
void MarkerList::ValueTreeWrapper::removeMarker (const ValueTree& marker, UndoManager* undoManager)
{
state.removeChild (marker, undoManager);
}
double MarkerList::getMarkerPosition (const Marker& marker, Component* parentComponent) const
{
if (parentComponent == nullptr)
return marker.position.resolve (nullptr);
RelativeCoordinatePositionerBase::ComponentScope scope (*parentComponent);
return marker.position.resolve (&scope);
}
//==============================================================================
void MarkerList::ValueTreeWrapper::applyTo (MarkerList& markerList)
{
const int numMarkers = getNumMarkers();
StringArray updatedMarkers;
for (int i = 0; i < numMarkers; ++i)
{
const ValueTree marker (state.getChild (i));
const String name (marker [nameProperty].toString());
markerList.setMarker (name, RelativeCoordinate (marker [posProperty].toString()));
updatedMarkers.add (name);
}
for (int i = markerList.getNumMarkers(); --i >= 0;)
if (! updatedMarkers.contains (markerList.getMarker (i)->name))
markerList.removeMarker (i);
}
void MarkerList::ValueTreeWrapper::readFrom (const MarkerList& markerList, UndoManager* undoManager)
{
state.removeAllChildren (undoManager);
for (int i = 0; i < markerList.getNumMarkers(); ++i)
setMarker (*markerList.getMarker(i), undoManager);
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
MarkerList::MarkerList()
{
}
MarkerList::MarkerList (const MarkerList& other)
{
operator= (other);
}
MarkerList& MarkerList::operator= (const MarkerList& other)
{
if (other != *this)
{
markers.clear();
markers.addCopiesOf (other.markers);
markersHaveChanged();
}
return *this;
}
MarkerList::~MarkerList()
{
listeners.call ([this] (Listener& l) { l.markerListBeingDeleted (this); });
}
bool MarkerList::operator== (const MarkerList& other) const noexcept
{
if (other.markers.size() != markers.size())
return false;
for (int i = markers.size(); --i >= 0;)
{
const Marker* const m1 = markers.getUnchecked(i);
jassert (m1 != nullptr);
const Marker* const m2 = other.getMarker (m1->name);
if (m2 == nullptr || *m1 != *m2)
return false;
}
return true;
}
bool MarkerList::operator!= (const MarkerList& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
int MarkerList::getNumMarkers() const noexcept
{
return markers.size();
}
const MarkerList::Marker* MarkerList::getMarker (const int index) const noexcept
{
return markers [index];
}
const MarkerList::Marker* MarkerList::getMarker (const String& name) const noexcept
{
return getMarkerByName (name);
}
MarkerList::Marker* MarkerList::getMarkerByName (const String& name) const noexcept
{
for (int i = 0; i < markers.size(); ++i)
{
Marker* const m = markers.getUnchecked(i);
if (m->name == name)
return m;
}
return nullptr;
}
void MarkerList::setMarker (const String& name, const RelativeCoordinate& position)
{
if (Marker* const m = getMarkerByName (name))
{
if (m->position != position)
{
m->position = position;
markersHaveChanged();
}
return;
}
markers.add (new Marker (name, position));
markersHaveChanged();
}
void MarkerList::removeMarker (const int index)
{
if (isPositiveAndBelow (index, markers.size()))
{
markers.remove (index);
markersHaveChanged();
}
}
void MarkerList::removeMarker (const String& name)
{
for (int i = 0; i < markers.size(); ++i)
{
const Marker* const m = markers.getUnchecked(i);
if (m->name == name)
{
markers.remove (i);
markersHaveChanged();
}
}
}
void MarkerList::markersHaveChanged()
{
listeners.call ([this] (Listener& l) { l.markersChanged (this); });
}
void MarkerList::Listener::markerListBeingDeleted (MarkerList*)
{
}
void MarkerList::addListener (Listener* listener)
{
listeners.add (listener);
}
void MarkerList::removeListener (Listener* listener)
{
listeners.remove (listener);
}
//==============================================================================
MarkerList::Marker::Marker (const Marker& other)
: name (other.name), position (other.position)
{
}
MarkerList::Marker::Marker (const String& name_, const RelativeCoordinate& position_)
: name (name_), position (position_)
{
}
bool MarkerList::Marker::operator== (const Marker& other) const noexcept
{
return name == other.name && position == other.position;
}
bool MarkerList::Marker::operator!= (const Marker& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
const Identifier MarkerList::ValueTreeWrapper::markerTag ("Marker");
const Identifier MarkerList::ValueTreeWrapper::nameProperty ("name");
const Identifier MarkerList::ValueTreeWrapper::posProperty ("position");
MarkerList::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
: state (state_)
{
}
int MarkerList::ValueTreeWrapper::getNumMarkers() const
{
return state.getNumChildren();
}
ValueTree MarkerList::ValueTreeWrapper::getMarkerState (int index) const
{
return state.getChild (index);
}
ValueTree MarkerList::ValueTreeWrapper::getMarkerState (const String& name) const
{
return state.getChildWithProperty (nameProperty, name);
}
bool MarkerList::ValueTreeWrapper::containsMarker (const ValueTree& marker) const
{
return marker.isAChildOf (state);
}
MarkerList::Marker MarkerList::ValueTreeWrapper::getMarker (const ValueTree& marker) const
{
jassert (containsMarker (marker));
return MarkerList::Marker (marker [nameProperty], RelativeCoordinate (marker [posProperty].toString()));
}
void MarkerList::ValueTreeWrapper::setMarker (const MarkerList::Marker& m, UndoManager* undoManager)
{
ValueTree marker (state.getChildWithProperty (nameProperty, m.name));
if (marker.isValid())
{
marker.setProperty (posProperty, m.position.toString(), undoManager);
}
else
{
marker = ValueTree (markerTag);
marker.setProperty (nameProperty, m.name, nullptr);
marker.setProperty (posProperty, m.position.toString(), nullptr);
state.appendChild (marker, undoManager);
}
}
void MarkerList::ValueTreeWrapper::removeMarker (const ValueTree& marker, UndoManager* undoManager)
{
state.removeChild (marker, undoManager);
}
double MarkerList::getMarkerPosition (const Marker& marker, Component* parentComponent) const
{
if (parentComponent == nullptr)
return marker.position.resolve (nullptr);
RelativeCoordinatePositionerBase::ComponentScope scope (*parentComponent);
return marker.position.resolve (&scope);
}
//==============================================================================
void MarkerList::ValueTreeWrapper::applyTo (MarkerList& markerList)
{
const int numMarkers = getNumMarkers();
StringArray updatedMarkers;
for (int i = 0; i < numMarkers; ++i)
{
const ValueTree marker (state.getChild (i));
const String name (marker [nameProperty].toString());
markerList.setMarker (name, RelativeCoordinate (marker [posProperty].toString()));
updatedMarkers.add (name);
}
for (int i = markerList.getNumMarkers(); --i >= 0;)
if (! updatedMarkers.contains (markerList.getMarker (i)->name))
markerList.removeMarker (i);
}
void MarkerList::ValueTreeWrapper::readFrom (const MarkerList& markerList, UndoManager* undoManager)
{
state.removeAllChildren (undoManager);
for (int i = 0; i < markerList.getNumMarkers(); ++i)
setMarker (*markerList.getMarker(i), undoManager);
}
} // namespace juce

View File

@ -1,195 +1,195 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
Holds a set of named marker points along a one-dimensional axis.
This class is used to store sets of X and Y marker points in components.
@see Component::getMarkers().
@tags{GUI}
*/
class JUCE_API MarkerList
{
public:
//==============================================================================
/** Creates an empty marker list. */
MarkerList();
/** Creates a copy of another marker list. */
MarkerList (const MarkerList&);
/** Copies another marker list to this one. */
MarkerList& operator= (const MarkerList&);
/** Destructor. */
~MarkerList();
//==============================================================================
/** Represents a marker in a MarkerList. */
class JUCE_API Marker
{
public:
/** Creates a copy of another Marker. */
Marker (const Marker&);
/** Creates a Marker with a given name and position. */
Marker (const String& name, const RelativeCoordinate& position);
/** The marker's name. */
String name;
/** The marker's position.
The expression used to define the coordinate may use the names of other
markers, so that markers can be linked in arbitrary ways, but be careful
not to create recursive loops of markers whose positions are based on each
other! It can also refer to "parent.right" and "parent.bottom" so that you
can set markers which are relative to the size of the component that contains
them.
To resolve the coordinate, you can use the MarkerList::getMarkerPosition() method.
*/
RelativeCoordinate position;
/** Returns true if both the names and positions of these two markers match. */
bool operator== (const Marker&) const noexcept;
/** Returns true if either the name or position of these two markers differ. */
bool operator!= (const Marker&) const noexcept;
};
//==============================================================================
/** Returns the number of markers in the list. */
int getNumMarkers() const noexcept;
/** Returns one of the markers in the list, by its index. */
const Marker* getMarker (int index) const noexcept;
/** Returns a named marker, or nullptr if no such name is found.
Note that name comparisons are case-sensitive.
*/
const Marker* getMarker (const String& name) const noexcept;
/** Evaluates the given marker and returns its absolute position.
The parent component must be supplied in case the marker's expression refers to
the size of its parent component.
*/
double getMarkerPosition (const Marker& marker, Component* parentComponent) const;
/** Sets the position of a marker.
If the name already exists, then the existing marker is moved; if it doesn't exist, then a
new marker is added.
*/
void setMarker (const String& name, const RelativeCoordinate& position);
/** Deletes the marker at the given list index. */
void removeMarker (int index);
/** Deletes the marker with the given name. */
void removeMarker (const String& name);
/** Returns true if all the markers in these two lists match exactly. */
bool operator== (const MarkerList&) const noexcept;
/** Returns true if not all the markers in these two lists match exactly. */
bool operator!= (const MarkerList&) const noexcept;
//==============================================================================
/**
A class for receiving events when changes are made to a MarkerList.
You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener()
method, and it will be called when markers are moved, added, or deleted.
@see MarkerList::addListener, MarkerList::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() = default;
/** Called when something in the given marker list changes. */
virtual void markersChanged (MarkerList* markerList) = 0;
/** Called when the given marker list is being deleted. */
virtual void markerListBeingDeleted (MarkerList* markerList);
};
/** Registers a listener that will be called when the markers are changed. */
void addListener (Listener* listener);
/** Deregisters a previously-registered listener. */
void removeListener (Listener* listener);
/** Synchronously calls markersChanged() on all the registered listeners. */
void markersHaveChanged();
//==============================================================================
/** A base class for objects that want to provide a MarkerList. */
struct MarkerListHolder
{
virtual ~MarkerListHolder() = default;
/** Objects can implement this method to provide a MarkerList. */
virtual MarkerList* getMarkers (bool xAxis) = 0;
};
//==============================================================================
/** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */
class ValueTreeWrapper
{
public:
ValueTreeWrapper (const ValueTree& state);
ValueTree& getState() noexcept { return state; }
int getNumMarkers() const;
ValueTree getMarkerState (int index) const;
ValueTree getMarkerState (const String& name) const;
bool containsMarker (const ValueTree& state) const;
MarkerList::Marker getMarker (const ValueTree& state) const;
void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager);
void removeMarker (const ValueTree& state, UndoManager* undoManager);
void applyTo (MarkerList& markerList);
void readFrom (const MarkerList& markerList, UndoManager* undoManager);
static const Identifier markerTag, nameProperty, posProperty;
private:
ValueTree state;
};
private:
//==============================================================================
OwnedArray<Marker> markers;
ListenerList<Listener> listeners;
Marker* getMarkerByName (const String& name) const noexcept;
JUCE_LEAK_DETECTOR (MarkerList)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
Holds a set of named marker points along a one-dimensional axis.
This class is used to store sets of X and Y marker points in components.
@see Component::getMarkers().
@tags{GUI}
*/
class JUCE_API MarkerList
{
public:
//==============================================================================
/** Creates an empty marker list. */
MarkerList();
/** Creates a copy of another marker list. */
MarkerList (const MarkerList&);
/** Copies another marker list to this one. */
MarkerList& operator= (const MarkerList&);
/** Destructor. */
~MarkerList();
//==============================================================================
/** Represents a marker in a MarkerList. */
class JUCE_API Marker
{
public:
/** Creates a copy of another Marker. */
Marker (const Marker&);
/** Creates a Marker with a given name and position. */
Marker (const String& name, const RelativeCoordinate& position);
/** The marker's name. */
String name;
/** The marker's position.
The expression used to define the coordinate may use the names of other
markers, so that markers can be linked in arbitrary ways, but be careful
not to create recursive loops of markers whose positions are based on each
other! It can also refer to "parent.right" and "parent.bottom" so that you
can set markers which are relative to the size of the component that contains
them.
To resolve the coordinate, you can use the MarkerList::getMarkerPosition() method.
*/
RelativeCoordinate position;
/** Returns true if both the names and positions of these two markers match. */
bool operator== (const Marker&) const noexcept;
/** Returns true if either the name or position of these two markers differ. */
bool operator!= (const Marker&) const noexcept;
};
//==============================================================================
/** Returns the number of markers in the list. */
int getNumMarkers() const noexcept;
/** Returns one of the markers in the list, by its index. */
const Marker* getMarker (int index) const noexcept;
/** Returns a named marker, or nullptr if no such name is found.
Note that name comparisons are case-sensitive.
*/
const Marker* getMarker (const String& name) const noexcept;
/** Evaluates the given marker and returns its absolute position.
The parent component must be supplied in case the marker's expression refers to
the size of its parent component.
*/
double getMarkerPosition (const Marker& marker, Component* parentComponent) const;
/** Sets the position of a marker.
If the name already exists, then the existing marker is moved; if it doesn't exist, then a
new marker is added.
*/
void setMarker (const String& name, const RelativeCoordinate& position);
/** Deletes the marker at the given list index. */
void removeMarker (int index);
/** Deletes the marker with the given name. */
void removeMarker (const String& name);
/** Returns true if all the markers in these two lists match exactly. */
bool operator== (const MarkerList&) const noexcept;
/** Returns true if not all the markers in these two lists match exactly. */
bool operator!= (const MarkerList&) const noexcept;
//==============================================================================
/**
A class for receiving events when changes are made to a MarkerList.
You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener()
method, and it will be called when markers are moved, added, or deleted.
@see MarkerList::addListener, MarkerList::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() = default;
/** Called when something in the given marker list changes. */
virtual void markersChanged (MarkerList* markerList) = 0;
/** Called when the given marker list is being deleted. */
virtual void markerListBeingDeleted (MarkerList* markerList);
};
/** Registers a listener that will be called when the markers are changed. */
void addListener (Listener* listener);
/** Deregisters a previously-registered listener. */
void removeListener (Listener* listener);
/** Synchronously calls markersChanged() on all the registered listeners. */
void markersHaveChanged();
//==============================================================================
/** A base class for objects that want to provide a MarkerList. */
struct MarkerListHolder
{
virtual ~MarkerListHolder() = default;
/** Objects can implement this method to provide a MarkerList. */
virtual MarkerList* getMarkers (bool xAxis) = 0;
};
//==============================================================================
/** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */
class ValueTreeWrapper
{
public:
ValueTreeWrapper (const ValueTree& state);
ValueTree& getState() noexcept { return state; }
int getNumMarkers() const;
ValueTree getMarkerState (int index) const;
ValueTree getMarkerState (const String& name) const;
bool containsMarker (const ValueTree& state) const;
MarkerList::Marker getMarker (const ValueTree& state) const;
void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager);
void removeMarker (const ValueTree& state, UndoManager* undoManager);
void applyTo (MarkerList& markerList);
void readFrom (const MarkerList& markerList, UndoManager* undoManager);
static const Identifier markerTag, nameProperty, posProperty;
private:
ValueTree state;
};
private:
//==============================================================================
OwnedArray<Marker> markers;
ListenerList<Listener> listeners;
Marker* getMarkerByName (const String& name) const noexcept;
JUCE_LEAK_DETECTOR (MarkerList)
};
} // namespace juce

View File

@ -1,153 +1,153 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
const String RelativeCoordinate::Strings::parent ("parent");
const String RelativeCoordinate::Strings::left ("left");
const String RelativeCoordinate::Strings::right ("right");
const String RelativeCoordinate::Strings::top ("top");
const String RelativeCoordinate::Strings::bottom ("bottom");
const String RelativeCoordinate::Strings::x ("x");
const String RelativeCoordinate::Strings::y ("y");
const String RelativeCoordinate::Strings::width ("width");
const String RelativeCoordinate::Strings::height ("height");
RelativeCoordinate::StandardStrings::Type RelativeCoordinate::StandardStrings::getTypeOf (const String& s) noexcept
{
if (s == Strings::left) return left;
if (s == Strings::right) return right;
if (s == Strings::top) return top;
if (s == Strings::bottom) return bottom;
if (s == Strings::x) return x;
if (s == Strings::y) return y;
if (s == Strings::width) return width;
if (s == Strings::height) return height;
if (s == Strings::parent) return parent;
return unknown;
}
//==============================================================================
RelativeCoordinate::RelativeCoordinate()
{
}
RelativeCoordinate::RelativeCoordinate (const Expression& term_)
: term (term_)
{
}
RelativeCoordinate::RelativeCoordinate (const RelativeCoordinate& other)
: term (other.term)
{
}
RelativeCoordinate& RelativeCoordinate::operator= (const RelativeCoordinate& other)
{
term = other.term;
return *this;
}
RelativeCoordinate::RelativeCoordinate (RelativeCoordinate&& other) noexcept
: term (std::move (other.term))
{
}
RelativeCoordinate& RelativeCoordinate::operator= (RelativeCoordinate&& other) noexcept
{
term = std::move (other.term);
return *this;
}
RelativeCoordinate::RelativeCoordinate (const double absoluteDistanceFromOrigin)
: term (absoluteDistanceFromOrigin)
{
}
RelativeCoordinate::RelativeCoordinate (const String& s)
{
String error;
term = Expression (s, error);
}
RelativeCoordinate::~RelativeCoordinate()
{
}
bool RelativeCoordinate::operator== (const RelativeCoordinate& other) const noexcept
{
return term.toString() == other.term.toString();
}
bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const noexcept
{
return ! operator== (other);
}
double RelativeCoordinate::resolve (const Expression::Scope* scope) const
{
if (scope != nullptr)
return term.evaluate (*scope);
return term.evaluate();
}
bool RelativeCoordinate::isRecursive (const Expression::Scope* scope) const
{
String error;
if (scope != nullptr)
term.evaluate (*scope, error);
else
term.evaluate (Expression::Scope(), error);
return error.isNotEmpty();
}
void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::Scope* scope)
{
if (scope != nullptr)
{
term = term.adjustedToGiveNewResult (newPos, *scope);
}
else
{
Expression::Scope defaultScope;
term = term.adjustedToGiveNewResult (newPos, defaultScope);
}
}
bool RelativeCoordinate::isDynamic() const
{
return term.usesAnySymbols();
}
String RelativeCoordinate::toString() const
{
return term.toString();
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
const String RelativeCoordinate::Strings::parent ("parent");
const String RelativeCoordinate::Strings::left ("left");
const String RelativeCoordinate::Strings::right ("right");
const String RelativeCoordinate::Strings::top ("top");
const String RelativeCoordinate::Strings::bottom ("bottom");
const String RelativeCoordinate::Strings::x ("x");
const String RelativeCoordinate::Strings::y ("y");
const String RelativeCoordinate::Strings::width ("width");
const String RelativeCoordinate::Strings::height ("height");
RelativeCoordinate::StandardStrings::Type RelativeCoordinate::StandardStrings::getTypeOf (const String& s) noexcept
{
if (s == Strings::left) return left;
if (s == Strings::right) return right;
if (s == Strings::top) return top;
if (s == Strings::bottom) return bottom;
if (s == Strings::x) return x;
if (s == Strings::y) return y;
if (s == Strings::width) return width;
if (s == Strings::height) return height;
if (s == Strings::parent) return parent;
return unknown;
}
//==============================================================================
RelativeCoordinate::RelativeCoordinate()
{
}
RelativeCoordinate::RelativeCoordinate (const Expression& term_)
: term (term_)
{
}
RelativeCoordinate::RelativeCoordinate (const RelativeCoordinate& other)
: term (other.term)
{
}
RelativeCoordinate& RelativeCoordinate::operator= (const RelativeCoordinate& other)
{
term = other.term;
return *this;
}
RelativeCoordinate::RelativeCoordinate (RelativeCoordinate&& other) noexcept
: term (std::move (other.term))
{
}
RelativeCoordinate& RelativeCoordinate::operator= (RelativeCoordinate&& other) noexcept
{
term = std::move (other.term);
return *this;
}
RelativeCoordinate::RelativeCoordinate (const double absoluteDistanceFromOrigin)
: term (absoluteDistanceFromOrigin)
{
}
RelativeCoordinate::RelativeCoordinate (const String& s)
{
String error;
term = Expression (s, error);
}
RelativeCoordinate::~RelativeCoordinate()
{
}
bool RelativeCoordinate::operator== (const RelativeCoordinate& other) const noexcept
{
return term.toString() == other.term.toString();
}
bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const noexcept
{
return ! operator== (other);
}
double RelativeCoordinate::resolve (const Expression::Scope* scope) const
{
if (scope != nullptr)
return term.evaluate (*scope);
return term.evaluate();
}
bool RelativeCoordinate::isRecursive (const Expression::Scope* scope) const
{
String error;
if (scope != nullptr)
term.evaluate (*scope, error);
else
term.evaluate (Expression::Scope(), error);
return error.isNotEmpty();
}
void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::Scope* scope)
{
if (scope != nullptr)
{
term = term.adjustedToGiveNewResult (newPos, *scope);
}
else
{
Expression::Scope defaultScope;
term = term.adjustedToGiveNewResult (newPos, defaultScope);
}
}
bool RelativeCoordinate::isDynamic() const
{
return term.usesAnySymbols();
}
String RelativeCoordinate::toString() const
{
return term.toString();
}
} // namespace juce

View File

@ -1,181 +1,181 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
Expresses a coordinate as a dynamically evaluated expression.
When using relative coordinates to position components, the following symbols are available:
- "left", "right", "top", "bottom" refer to the position of those edges in this component, so
e.g. for a component whose width is always 100, you might set the right edge to the "left + 100".
- "[id].left", "[id].right", "[id].top", "[id].bottom", "[id].width", "[id].height", where [id] is
the identifier of one of this component's siblings. A component's identifier is set with
Component::setComponentID(). So for example if you want your component to always be 50 pixels to the
right of the one called "xyz", you could set your left edge to be "xyz.right + 50".
- Instead of an [id], you can use the name "parent" to refer to this component's parent. Like
any other component, these values are relative to their component's parent, so "parent.right" won't be
very useful for positioning a component because it refers to a position with the parent's parent.. but
"parent.width" can be used for setting positions relative to the parent's size. E.g. to make a 10x10
component which remains 1 pixel away from its parent's bottom-right, you could use
"right - 10, bottom - 10, parent.width - 1, parent.height - 1".
- The name of one of the parent component's markers can also be used as a symbol. For markers to be
used, the parent component must implement its Component::getMarkers() method, and return at least one
valid MarkerList. So if you want your component's top edge to be 10 pixels below the
marker called "foobar", you'd set it to "foobar + 10".
See the Expression class for details about the operators that are supported, but for example
if you wanted to make your component remains centred within its parent with a size of 100, 100,
you could express it as:
@code myComp.setBounds (RelativeBounds ("parent.width / 2 - 50, parent.height / 2 - 50, left + 100, top + 100"));
@endcode
..or an alternative way to achieve the same thing:
@code myComp.setBounds (RelativeBounds ("right - 100, bottom - 100, parent.width / 2 + 50, parent.height / 2 + 50"));
@endcode
Or if you wanted a 100x100 component whose top edge is lined up to a marker called "topMarker" and
which is positioned 50 pixels to the right of another component called "otherComp", you could write:
@code myComp.setBounds (RelativeBounds ("otherComp.right + 50, topMarker, left + 100, top + 100"));
@endcode
Be careful not to make your coordinate expressions recursive, though, or exceptions and assertions will
be thrown!
@see RelativePoint, RelativeRectangle
@tags{GUI}
*/
class JUCE_API RelativeCoordinate
{
public:
//==============================================================================
/** Creates a zero coordinate. */
RelativeCoordinate();
RelativeCoordinate (const Expression& expression);
RelativeCoordinate (const RelativeCoordinate&);
RelativeCoordinate& operator= (const RelativeCoordinate&);
RelativeCoordinate (RelativeCoordinate&&) noexcept;
RelativeCoordinate& operator= (RelativeCoordinate&&) noexcept;
/** Creates an absolute position from the parent origin on either the X or Y axis.
@param absoluteDistanceFromOrigin the distance from the origin
*/
RelativeCoordinate (double absoluteDistanceFromOrigin);
/** Recreates a coordinate from a string description.
The string will be parsed by ExpressionParser::parse().
@param stringVersion the expression to use
@see toString
*/
RelativeCoordinate (const String& stringVersion);
/** Destructor. */
~RelativeCoordinate();
bool operator== (const RelativeCoordinate&) const noexcept;
bool operator!= (const RelativeCoordinate&) const noexcept;
//==============================================================================
/** Calculates the absolute position of this coordinate.
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
double resolve (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate uses the specified coord name at any level in its evaluation.
This will recursively check any coordinates upon which this one depends.
*/
bool references (const String& coordName, const Expression::Scope* evaluationScope) const;
/** Returns true if there's a recursive loop when trying to resolve this coordinate's position. */
bool isRecursive (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate depends on any other coordinates for its position. */
bool isDynamic() const;
//==============================================================================
/** Changes the value of this coord to make it resolve to the specified position.
Calling this will leave the anchor points unchanged, but will set this coordinate's absolute
or relative position to whatever value is necessary to make its resultant position
match the position that is provided.
*/
void moveToAbsolute (double absoluteTargetPosition, const Expression::Scope* evaluationScope);
/** Returns the expression that defines this coordinate. */
const Expression& getExpression() const { return term; }
//==============================================================================
/** Returns a string which represents this coordinate.
For details of the string syntax, see the constructor notes.
*/
String toString() const;
//==============================================================================
/** A set of static strings that are commonly used by the RelativeCoordinate class.
As well as avoiding using string literals in your code, using these preset values
has the advantage that all instances of the same string will share the same, reference-counted
String object, so if you have thousands of points which all refer to the same
anchor points, this can save a significant amount of memory allocation.
*/
struct Strings
{
static const String parent; /**< "parent" */
static const String left; /**< "left" */
static const String right; /**< "right" */
static const String top; /**< "top" */
static const String bottom; /**< "bottom" */
static const String x; /**< "x" */
static const String y; /**< "y" */
static const String width; /**< "width" */
static const String height; /**< "height" */
};
/** @internal */
struct StandardStrings
{
enum Type
{
left, right, top, bottom,
x, y, width, height,
parent,
unknown
};
static Type getTypeOf (const String& s) noexcept;
};
private:
//==============================================================================
Expression term;
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
Expresses a coordinate as a dynamically evaluated expression.
When using relative coordinates to position components, the following symbols are available:
- "left", "right", "top", "bottom" refer to the position of those edges in this component, so
e.g. for a component whose width is always 100, you might set the right edge to the "left + 100".
- "[id].left", "[id].right", "[id].top", "[id].bottom", "[id].width", "[id].height", where [id] is
the identifier of one of this component's siblings. A component's identifier is set with
Component::setComponentID(). So for example if you want your component to always be 50 pixels to the
right of the one called "xyz", you could set your left edge to be "xyz.right + 50".
- Instead of an [id], you can use the name "parent" to refer to this component's parent. Like
any other component, these values are relative to their component's parent, so "parent.right" won't be
very useful for positioning a component because it refers to a position with the parent's parent.. but
"parent.width" can be used for setting positions relative to the parent's size. E.g. to make a 10x10
component which remains 1 pixel away from its parent's bottom-right, you could use
"right - 10, bottom - 10, parent.width - 1, parent.height - 1".
- The name of one of the parent component's markers can also be used as a symbol. For markers to be
used, the parent component must implement its Component::getMarkers() method, and return at least one
valid MarkerList. So if you want your component's top edge to be 10 pixels below the
marker called "foobar", you'd set it to "foobar + 10".
See the Expression class for details about the operators that are supported, but for example
if you wanted to make your component remains centred within its parent with a size of 100, 100,
you could express it as:
@code myComp.setBounds (RelativeBounds ("parent.width / 2 - 50, parent.height / 2 - 50, left + 100, top + 100"));
@endcode
..or an alternative way to achieve the same thing:
@code myComp.setBounds (RelativeBounds ("right - 100, bottom - 100, parent.width / 2 + 50, parent.height / 2 + 50"));
@endcode
Or if you wanted a 100x100 component whose top edge is lined up to a marker called "topMarker" and
which is positioned 50 pixels to the right of another component called "otherComp", you could write:
@code myComp.setBounds (RelativeBounds ("otherComp.right + 50, topMarker, left + 100, top + 100"));
@endcode
Be careful not to make your coordinate expressions recursive, though, or exceptions and assertions will
be thrown!
@see RelativePoint, RelativeRectangle
@tags{GUI}
*/
class JUCE_API RelativeCoordinate
{
public:
//==============================================================================
/** Creates a zero coordinate. */
RelativeCoordinate();
RelativeCoordinate (const Expression& expression);
RelativeCoordinate (const RelativeCoordinate&);
RelativeCoordinate& operator= (const RelativeCoordinate&);
RelativeCoordinate (RelativeCoordinate&&) noexcept;
RelativeCoordinate& operator= (RelativeCoordinate&&) noexcept;
/** Creates an absolute position from the parent origin on either the X or Y axis.
@param absoluteDistanceFromOrigin the distance from the origin
*/
RelativeCoordinate (double absoluteDistanceFromOrigin);
/** Recreates a coordinate from a string description.
The string will be parsed by ExpressionParser::parse().
@param stringVersion the expression to use
@see toString
*/
RelativeCoordinate (const String& stringVersion);
/** Destructor. */
~RelativeCoordinate();
bool operator== (const RelativeCoordinate&) const noexcept;
bool operator!= (const RelativeCoordinate&) const noexcept;
//==============================================================================
/** Calculates the absolute position of this coordinate.
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
double resolve (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate uses the specified coord name at any level in its evaluation.
This will recursively check any coordinates upon which this one depends.
*/
bool references (const String& coordName, const Expression::Scope* evaluationScope) const;
/** Returns true if there's a recursive loop when trying to resolve this coordinate's position. */
bool isRecursive (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate depends on any other coordinates for its position. */
bool isDynamic() const;
//==============================================================================
/** Changes the value of this coord to make it resolve to the specified position.
Calling this will leave the anchor points unchanged, but will set this coordinate's absolute
or relative position to whatever value is necessary to make its resultant position
match the position that is provided.
*/
void moveToAbsolute (double absoluteTargetPosition, const Expression::Scope* evaluationScope);
/** Returns the expression that defines this coordinate. */
const Expression& getExpression() const { return term; }
//==============================================================================
/** Returns a string which represents this coordinate.
For details of the string syntax, see the constructor notes.
*/
String toString() const;
//==============================================================================
/** A set of static strings that are commonly used by the RelativeCoordinate class.
As well as avoiding using string literals in your code, using these preset values
has the advantage that all instances of the same string will share the same, reference-counted
String object, so if you have thousands of points which all refer to the same
anchor points, this can save a significant amount of memory allocation.
*/
struct Strings
{
static const String parent; /**< "parent" */
static const String left; /**< "left" */
static const String right; /**< "right" */
static const String top; /**< "top" */
static const String bottom; /**< "bottom" */
static const String x; /**< "x" */
static const String y; /**< "y" */
static const String width; /**< "width" */
static const String height; /**< "height" */
};
/** @internal */
struct StandardStrings
{
enum Type
{
left, right, top, bottom,
x, y, width, height,
parent,
unknown
};
static Type getTypeOf (const String& s) noexcept;
};
private:
//==============================================================================
Expression term;
};
} // namespace juce

View File

@ -1,335 +1,335 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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 MarkerListScope : public Expression::Scope
{
MarkerListScope (Component& comp) : component (comp) {}
Expression getSymbolValue (const String& symbol) const override
{
auto type = RelativeCoordinate::StandardStrings::getTypeOf (symbol);
if (type == RelativeCoordinate::StandardStrings::width) return Expression ((double) component.getWidth());
if (type == RelativeCoordinate::StandardStrings::height) return Expression ((double) component.getHeight());
MarkerList* list;
if (auto* marker = findMarker (component, symbol, list))
return Expression (marker->position.getExpression().evaluate (*this));
return Expression::Scope::getSymbolValue (symbol);
}
void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
{
if (scopeName == RelativeCoordinate::Strings::parent)
{
if (auto* parent = component.getParentComponent())
{
visitor.visit (MarkerListScope (*parent));
return;
}
}
Expression::Scope::visitRelativeScope (scopeName, visitor);
}
String getScopeUID() const override
{
return String::toHexString ((pointer_sized_int) (void*) &component) + "m";
}
static const MarkerList::Marker* findMarker (Component& component, const String& name, MarkerList*& list)
{
const MarkerList::Marker* marker = nullptr;
auto* mlh = dynamic_cast<MarkerList::MarkerListHolder*> (&component);
if (mlh != nullptr)
{
list = mlh->getMarkers (true);
if (list != nullptr)
marker = list->getMarker (name);
}
if (marker == nullptr)
{
if (mlh != nullptr)
{
list = mlh->getMarkers (false);
if (list != nullptr)
marker = list->getMarker (name);
}
}
return marker;
}
Component& component;
};
//==============================================================================
RelativeCoordinatePositionerBase::ComponentScope::ComponentScope (Component& comp)
: component (comp)
{
}
Expression RelativeCoordinatePositionerBase::ComponentScope::getSymbolValue (const String& symbol) const
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::left: return Expression ((double) component.getX());
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::top: return Expression ((double) component.getY());
case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
case RelativeCoordinate::StandardStrings::right: return Expression ((double) component.getRight());
case RelativeCoordinate::StandardStrings::bottom: return Expression ((double) component.getBottom());
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default: break;
}
if (Component* const parent = component.getParentComponent())
{
MarkerList* list;
if (auto* marker = MarkerListScope::findMarker (*parent, symbol, list))
{
MarkerListScope scope (*parent);
return Expression (marker->position.getExpression().evaluate (scope));
}
}
return Expression::Scope::getSymbolValue (symbol);
}
void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const String& scopeName, Visitor& visitor) const
{
if (auto* targetComp = (scopeName == RelativeCoordinate::Strings::parent)
? component.getParentComponent()
: findSiblingComponent (scopeName))
visitor.visit (ComponentScope (*targetComp));
else
Expression::Scope::visitRelativeScope (scopeName, visitor);
}
String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const
{
return String::toHexString ((pointer_sized_int) (void*) &component);
}
Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponent (const String& componentID) const
{
if (Component* const parent = component.getParentComponent())
return parent->findChildWithID (componentID);
return nullptr;
}
//==============================================================================
class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope
{
public:
DependencyFinderScope (Component& comp, RelativeCoordinatePositionerBase& p, bool& result)
: ComponentScope (comp), positioner (p), ok (result)
{
}
Expression getSymbolValue (const String& symbol) const override
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::left:
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::top:
case RelativeCoordinate::StandardStrings::width:
case RelativeCoordinate::StandardStrings::height:
case RelativeCoordinate::StandardStrings::right:
case RelativeCoordinate::StandardStrings::bottom:
positioner.registerComponentListener (component);
break;
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default:
if (auto* parent = component.getParentComponent())
{
MarkerList* list;
if (MarkerListScope::findMarker (*parent, symbol, list) != nullptr)
{
positioner.registerMarkerListListener (list);
}
else
{
// The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
if (auto* mlh = dynamic_cast<MarkerList::MarkerListHolder*> (parent))
{
positioner.registerMarkerListListener (mlh->getMarkers (true));
positioner.registerMarkerListListener (mlh->getMarkers (false));
}
ok = false;
}
}
break;
}
return ComponentScope::getSymbolValue (symbol);
}
void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
{
if (Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent)
? component.getParentComponent()
: findSiblingComponent (scopeName))
{
visitor.visit (DependencyFinderScope (*targetComp, positioner, ok));
}
else
{
// The named component doesn't exist, so we'll watch the parent for changes in case it appears later..
if (Component* const parent = component.getParentComponent())
positioner.registerComponentListener (*parent);
positioner.registerComponentListener (component);
ok = false;
}
}
private:
RelativeCoordinatePositionerBase& positioner;
bool& ok;
};
//==============================================================================
RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& comp)
: Component::Positioner (comp), registeredOk (false)
{
}
RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
{
unregisterListeners();
}
void RelativeCoordinatePositionerBase::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
{
apply();
}
void RelativeCoordinatePositionerBase::componentParentHierarchyChanged (Component&)
{
apply();
}
void RelativeCoordinatePositionerBase::componentChildrenChanged (Component& changed)
{
if (getComponent().getParentComponent() == &changed && ! registeredOk)
apply();
}
void RelativeCoordinatePositionerBase::componentBeingDeleted (Component& comp)
{
jassert (sourceComponents.contains (&comp));
sourceComponents.removeFirstMatchingValue (&comp);
registeredOk = false;
}
void RelativeCoordinatePositionerBase::markersChanged (MarkerList*)
{
apply();
}
void RelativeCoordinatePositionerBase::markerListBeingDeleted (MarkerList* markerList)
{
jassert (sourceMarkerLists.contains (markerList));
sourceMarkerLists.removeFirstMatchingValue (markerList);
}
void RelativeCoordinatePositionerBase::apply()
{
if (! registeredOk)
{
unregisterListeners();
registeredOk = registerCoordinates();
}
applyToComponentBounds();
}
bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& coord)
{
bool ok = true;
DependencyFinderScope finderScope (getComponent(), *this, ok);
coord.getExpression().evaluate (finderScope);
return ok;
}
bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
{
const bool ok = addCoordinate (point.x);
return addCoordinate (point.y) && ok;
}
void RelativeCoordinatePositionerBase::registerComponentListener (Component& comp)
{
if (! sourceComponents.contains (&comp))
{
comp.addComponentListener (this);
sourceComponents.add (&comp);
}
}
void RelativeCoordinatePositionerBase::registerMarkerListListener (MarkerList* const list)
{
if (list != nullptr && ! sourceMarkerLists.contains (list))
{
list->addListener (this);
sourceMarkerLists.add (list);
}
}
void RelativeCoordinatePositionerBase::unregisterListeners()
{
for (int i = sourceComponents.size(); --i >= 0;)
sourceComponents.getUnchecked(i)->removeComponentListener (this);
for (int i = sourceMarkerLists.size(); --i >= 0;)
sourceMarkerLists.getUnchecked(i)->removeListener (this);
sourceComponents.clear();
sourceMarkerLists.clear();
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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 MarkerListScope : public Expression::Scope
{
MarkerListScope (Component& comp) : component (comp) {}
Expression getSymbolValue (const String& symbol) const override
{
auto type = RelativeCoordinate::StandardStrings::getTypeOf (symbol);
if (type == RelativeCoordinate::StandardStrings::width) return Expression ((double) component.getWidth());
if (type == RelativeCoordinate::StandardStrings::height) return Expression ((double) component.getHeight());
MarkerList* list;
if (auto* marker = findMarker (component, symbol, list))
return Expression (marker->position.getExpression().evaluate (*this));
return Expression::Scope::getSymbolValue (symbol);
}
void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
{
if (scopeName == RelativeCoordinate::Strings::parent)
{
if (auto* parent = component.getParentComponent())
{
visitor.visit (MarkerListScope (*parent));
return;
}
}
Expression::Scope::visitRelativeScope (scopeName, visitor);
}
String getScopeUID() const override
{
return String::toHexString ((pointer_sized_int) (void*) &component) + "m";
}
static const MarkerList::Marker* findMarker (Component& component, const String& name, MarkerList*& list)
{
const MarkerList::Marker* marker = nullptr;
auto* mlh = dynamic_cast<MarkerList::MarkerListHolder*> (&component);
if (mlh != nullptr)
{
list = mlh->getMarkers (true);
if (list != nullptr)
marker = list->getMarker (name);
}
if (marker == nullptr)
{
if (mlh != nullptr)
{
list = mlh->getMarkers (false);
if (list != nullptr)
marker = list->getMarker (name);
}
}
return marker;
}
Component& component;
};
//==============================================================================
RelativeCoordinatePositionerBase::ComponentScope::ComponentScope (Component& comp)
: component (comp)
{
}
Expression RelativeCoordinatePositionerBase::ComponentScope::getSymbolValue (const String& symbol) const
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::left: return Expression ((double) component.getX());
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::top: return Expression ((double) component.getY());
case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
case RelativeCoordinate::StandardStrings::right: return Expression ((double) component.getRight());
case RelativeCoordinate::StandardStrings::bottom: return Expression ((double) component.getBottom());
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default: break;
}
if (Component* const parent = component.getParentComponent())
{
MarkerList* list;
if (auto* marker = MarkerListScope::findMarker (*parent, symbol, list))
{
MarkerListScope scope (*parent);
return Expression (marker->position.getExpression().evaluate (scope));
}
}
return Expression::Scope::getSymbolValue (symbol);
}
void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const String& scopeName, Visitor& visitor) const
{
if (auto* targetComp = (scopeName == RelativeCoordinate::Strings::parent)
? component.getParentComponent()
: findSiblingComponent (scopeName))
visitor.visit (ComponentScope (*targetComp));
else
Expression::Scope::visitRelativeScope (scopeName, visitor);
}
String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const
{
return String::toHexString ((pointer_sized_int) (void*) &component);
}
Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponent (const String& componentID) const
{
if (Component* const parent = component.getParentComponent())
return parent->findChildWithID (componentID);
return nullptr;
}
//==============================================================================
class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope
{
public:
DependencyFinderScope (Component& comp, RelativeCoordinatePositionerBase& p, bool& result)
: ComponentScope (comp), positioner (p), ok (result)
{
}
Expression getSymbolValue (const String& symbol) const override
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::left:
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::top:
case RelativeCoordinate::StandardStrings::width:
case RelativeCoordinate::StandardStrings::height:
case RelativeCoordinate::StandardStrings::right:
case RelativeCoordinate::StandardStrings::bottom:
positioner.registerComponentListener (component);
break;
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default:
if (auto* parent = component.getParentComponent())
{
MarkerList* list;
if (MarkerListScope::findMarker (*parent, symbol, list) != nullptr)
{
positioner.registerMarkerListListener (list);
}
else
{
// The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
if (auto* mlh = dynamic_cast<MarkerList::MarkerListHolder*> (parent))
{
positioner.registerMarkerListListener (mlh->getMarkers (true));
positioner.registerMarkerListListener (mlh->getMarkers (false));
}
ok = false;
}
}
break;
}
return ComponentScope::getSymbolValue (symbol);
}
void visitRelativeScope (const String& scopeName, Visitor& visitor) const override
{
if (Component* const targetComp = (scopeName == RelativeCoordinate::Strings::parent)
? component.getParentComponent()
: findSiblingComponent (scopeName))
{
visitor.visit (DependencyFinderScope (*targetComp, positioner, ok));
}
else
{
// The named component doesn't exist, so we'll watch the parent for changes in case it appears later..
if (Component* const parent = component.getParentComponent())
positioner.registerComponentListener (*parent);
positioner.registerComponentListener (component);
ok = false;
}
}
private:
RelativeCoordinatePositionerBase& positioner;
bool& ok;
};
//==============================================================================
RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& comp)
: Component::Positioner (comp), registeredOk (false)
{
}
RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
{
unregisterListeners();
}
void RelativeCoordinatePositionerBase::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
{
apply();
}
void RelativeCoordinatePositionerBase::componentParentHierarchyChanged (Component&)
{
apply();
}
void RelativeCoordinatePositionerBase::componentChildrenChanged (Component& changed)
{
if (getComponent().getParentComponent() == &changed && ! registeredOk)
apply();
}
void RelativeCoordinatePositionerBase::componentBeingDeleted (Component& comp)
{
jassert (sourceComponents.contains (&comp));
sourceComponents.removeFirstMatchingValue (&comp);
registeredOk = false;
}
void RelativeCoordinatePositionerBase::markersChanged (MarkerList*)
{
apply();
}
void RelativeCoordinatePositionerBase::markerListBeingDeleted (MarkerList* markerList)
{
jassert (sourceMarkerLists.contains (markerList));
sourceMarkerLists.removeFirstMatchingValue (markerList);
}
void RelativeCoordinatePositionerBase::apply()
{
if (! registeredOk)
{
unregisterListeners();
registeredOk = registerCoordinates();
}
applyToComponentBounds();
}
bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& coord)
{
bool ok = true;
DependencyFinderScope finderScope (getComponent(), *this, ok);
coord.getExpression().evaluate (finderScope);
return ok;
}
bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
{
const bool ok = addCoordinate (point.x);
return addCoordinate (point.y) && ok;
}
void RelativeCoordinatePositionerBase::registerComponentListener (Component& comp)
{
if (! sourceComponents.contains (&comp))
{
comp.addComponentListener (this);
sourceComponents.add (&comp);
}
}
void RelativeCoordinatePositionerBase::registerMarkerListListener (MarkerList* const list)
{
if (list != nullptr && ! sourceMarkerLists.contains (list))
{
list->addListener (this);
sourceMarkerLists.add (list);
}
}
void RelativeCoordinatePositionerBase::unregisterListeners()
{
for (int i = sourceComponents.size(); --i >= 0;)
sourceComponents.getUnchecked(i)->removeComponentListener (this);
for (int i = sourceMarkerLists.size(); --i >= 0;)
sourceMarkerLists.getUnchecked(i)->removeListener (this);
sourceComponents.clear();
sourceMarkerLists.clear();
}
} // namespace juce

View File

@ -1,90 +1,90 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
Base class for Component::Positioners that are based upon relative coordinates.
@tags{GUI}
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
public MarkerList::Listener
{
public:
RelativeCoordinatePositionerBase (Component&);
~RelativeCoordinatePositionerBase() override;
void componentMovedOrResized (Component&, bool, bool) override;
void componentParentHierarchyChanged (Component&) override;
void componentChildrenChanged (Component&) override;
void componentBeingDeleted (Component&) override;
void markersChanged (MarkerList*) override;
void markerListBeingDeleted (MarkerList*) override;
void apply();
bool addCoordinate (const RelativeCoordinate&);
bool addPoint (const RelativePoint&);
//==============================================================================
/** Used for resolving a RelativeCoordinate expression in the context of a component. */
class ComponentScope : public Expression::Scope
{
public:
ComponentScope (Component&);
Expression getSymbolValue (const String& symbol) const override;
void visitRelativeScope (const String& scopeName, Visitor&) const override;
String getScopeUID() const override;
protected:
Component& component;
Component* findSiblingComponent (const String& componentID) const;
};
protected:
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;
private:
class DependencyFinderScope;
friend class DependencyFinderScope;
Array<Component*> sourceComponents;
Array<MarkerList*> sourceMarkerLists;
bool registeredOk;
void registerComponentListener (Component&);
void registerMarkerListListener (MarkerList*);
void unregisterListeners();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
Base class for Component::Positioners that are based upon relative coordinates.
@tags{GUI}
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
public MarkerList::Listener
{
public:
RelativeCoordinatePositionerBase (Component&);
~RelativeCoordinatePositionerBase() override;
void componentMovedOrResized (Component&, bool, bool) override;
void componentParentHierarchyChanged (Component&) override;
void componentChildrenChanged (Component&) override;
void componentBeingDeleted (Component&) override;
void markersChanged (MarkerList*) override;
void markerListBeingDeleted (MarkerList*) override;
void apply();
bool addCoordinate (const RelativeCoordinate&);
bool addPoint (const RelativePoint&);
//==============================================================================
/** Used for resolving a RelativeCoordinate expression in the context of a component. */
class ComponentScope : public Expression::Scope
{
public:
ComponentScope (Component&);
Expression getSymbolValue (const String& symbol) const override;
void visitRelativeScope (const String& scopeName, Visitor&) const override;
String getScopeUID() const override;
protected:
Component& component;
Component* findSiblingComponent (const String& componentID) const;
};
protected:
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;
private:
class DependencyFinderScope;
friend class DependencyFinderScope;
Array<Component*> sourceComponents;
Array<MarkerList*> sourceMarkerLists;
bool registeredOk;
void registerComponentListener (Component&);
void registerMarkerListListener (MarkerList*);
void unregisterListeners();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase)
};
} // namespace juce

View File

@ -1,140 +1,140 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
RelativeParallelogram::RelativeParallelogram()
{
}
RelativeParallelogram::RelativeParallelogram (const Rectangle<float>& r)
: topLeft (r.getTopLeft()), topRight (r.getTopRight()), bottomLeft (r.getBottomLeft())
{
}
RelativeParallelogram::RelativeParallelogram (const RelativePoint& topLeft_, const RelativePoint& topRight_, const RelativePoint& bottomLeft_)
: topLeft (topLeft_), topRight (topRight_), bottomLeft (bottomLeft_)
{
}
RelativeParallelogram::RelativeParallelogram (const String& topLeft_, const String& topRight_, const String& bottomLeft_)
: topLeft (topLeft_), topRight (topRight_), bottomLeft (bottomLeft_)
{
}
RelativeParallelogram::~RelativeParallelogram()
{
}
void RelativeParallelogram::resolveThreePoints (Point<float>* points, Expression::Scope* const scope) const
{
points[0] = topLeft.resolve (scope);
points[1] = topRight.resolve (scope);
points[2] = bottomLeft.resolve (scope);
}
void RelativeParallelogram::resolveFourCorners (Point<float>* points, Expression::Scope* const scope) const
{
resolveThreePoints (points, scope);
points[3] = points[1] + (points[2] - points[0]);
}
const Rectangle<float> RelativeParallelogram::getBounds (Expression::Scope* const scope) const
{
Point<float> points[4];
resolveFourCorners (points, scope);
return Rectangle<float>::findAreaContainingPoints (points, 4);
}
void RelativeParallelogram::getPath (Path& path, Expression::Scope* const scope) const
{
Point<float> points[4];
resolveFourCorners (points, scope);
path.startNewSubPath (points[0]);
path.lineTo (points[1]);
path.lineTo (points[3]);
path.lineTo (points[2]);
path.closeSubPath();
}
AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::Scope* const scope)
{
Point<float> corners[3];
resolveThreePoints (corners, scope);
const Line<float> top (corners[0], corners[1]);
const Line<float> left (corners[0], corners[2]);
const Point<float> newTopRight (corners[0] + Point<float> (top.getLength(), 0.0f));
const Point<float> newBottomLeft (corners[0] + Point<float> (0.0f, left.getLength()));
topRight.moveToAbsolute (newTopRight, scope);
bottomLeft.moveToAbsolute (newBottomLeft, scope);
return AffineTransform::fromTargetPoints (corners[0], corners[0],
corners[1], newTopRight,
corners[2], newBottomLeft);
}
bool RelativeParallelogram::isDynamic() const
{
return topLeft.isDynamic() || topRight.isDynamic() || bottomLeft.isDynamic();
}
bool RelativeParallelogram::operator== (const RelativeParallelogram& other) const noexcept
{
return topLeft == other.topLeft && topRight == other.topRight && bottomLeft == other.bottomLeft;
}
bool RelativeParallelogram::operator!= (const RelativeParallelogram& other) const noexcept
{
return ! operator== (other);
}
Point<float> RelativeParallelogram::getInternalCoordForPoint (const Point<float>* const corners, Point<float> target) noexcept
{
const Point<float> tr (corners[1] - corners[0]);
const Point<float> bl (corners[2] - corners[0]);
target -= corners[0];
return Point<float> (Line<float> (Point<float>(), tr).getIntersection (Line<float> (target, target - bl)).getDistanceFromOrigin(),
Line<float> (Point<float>(), bl).getIntersection (Line<float> (target, target - tr)).getDistanceFromOrigin());
}
Point<float> RelativeParallelogram::getPointForInternalCoord (const Point<float>* const corners, const Point<float> point) noexcept
{
return corners[0]
+ Line<float> (Point<float>(), corners[1] - corners[0]).getPointAlongLine (point.x)
+ Line<float> (Point<float>(), corners[2] - corners[0]).getPointAlongLine (point.y);
}
Rectangle<float> RelativeParallelogram::getBoundingBox (const Point<float>* const p) noexcept
{
const Point<float> points[] = { p[0], p[1], p[2], p[1] + (p[2] - p[0]) };
return Rectangle<float>::findAreaContainingPoints (points, 4);
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
RelativeParallelogram::RelativeParallelogram()
{
}
RelativeParallelogram::RelativeParallelogram (const Rectangle<float>& r)
: topLeft (r.getTopLeft()), topRight (r.getTopRight()), bottomLeft (r.getBottomLeft())
{
}
RelativeParallelogram::RelativeParallelogram (const RelativePoint& topLeft_, const RelativePoint& topRight_, const RelativePoint& bottomLeft_)
: topLeft (topLeft_), topRight (topRight_), bottomLeft (bottomLeft_)
{
}
RelativeParallelogram::RelativeParallelogram (const String& topLeft_, const String& topRight_, const String& bottomLeft_)
: topLeft (topLeft_), topRight (topRight_), bottomLeft (bottomLeft_)
{
}
RelativeParallelogram::~RelativeParallelogram()
{
}
void RelativeParallelogram::resolveThreePoints (Point<float>* points, Expression::Scope* const scope) const
{
points[0] = topLeft.resolve (scope);
points[1] = topRight.resolve (scope);
points[2] = bottomLeft.resolve (scope);
}
void RelativeParallelogram::resolveFourCorners (Point<float>* points, Expression::Scope* const scope) const
{
resolveThreePoints (points, scope);
points[3] = points[1] + (points[2] - points[0]);
}
const Rectangle<float> RelativeParallelogram::getBounds (Expression::Scope* const scope) const
{
Point<float> points[4];
resolveFourCorners (points, scope);
return Rectangle<float>::findAreaContainingPoints (points, 4);
}
void RelativeParallelogram::getPath (Path& path, Expression::Scope* const scope) const
{
Point<float> points[4];
resolveFourCorners (points, scope);
path.startNewSubPath (points[0]);
path.lineTo (points[1]);
path.lineTo (points[3]);
path.lineTo (points[2]);
path.closeSubPath();
}
AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::Scope* const scope)
{
Point<float> corners[3];
resolveThreePoints (corners, scope);
const Line<float> top (corners[0], corners[1]);
const Line<float> left (corners[0], corners[2]);
const Point<float> newTopRight (corners[0] + Point<float> (top.getLength(), 0.0f));
const Point<float> newBottomLeft (corners[0] + Point<float> (0.0f, left.getLength()));
topRight.moveToAbsolute (newTopRight, scope);
bottomLeft.moveToAbsolute (newBottomLeft, scope);
return AffineTransform::fromTargetPoints (corners[0], corners[0],
corners[1], newTopRight,
corners[2], newBottomLeft);
}
bool RelativeParallelogram::isDynamic() const
{
return topLeft.isDynamic() || topRight.isDynamic() || bottomLeft.isDynamic();
}
bool RelativeParallelogram::operator== (const RelativeParallelogram& other) const noexcept
{
return topLeft == other.topLeft && topRight == other.topRight && bottomLeft == other.bottomLeft;
}
bool RelativeParallelogram::operator!= (const RelativeParallelogram& other) const noexcept
{
return ! operator== (other);
}
Point<float> RelativeParallelogram::getInternalCoordForPoint (const Point<float>* const corners, Point<float> target) noexcept
{
const Point<float> tr (corners[1] - corners[0]);
const Point<float> bl (corners[2] - corners[0]);
target -= corners[0];
return Point<float> (Line<float> (Point<float>(), tr).getIntersection (Line<float> (target, target - bl)).getDistanceFromOrigin(),
Line<float> (Point<float>(), bl).getIntersection (Line<float> (target, target - tr)).getDistanceFromOrigin());
}
Point<float> RelativeParallelogram::getPointForInternalCoord (const Point<float>* const corners, const Point<float> point) noexcept
{
return corners[0]
+ Line<float> (Point<float>(), corners[1] - corners[0]).getPointAlongLine (point.x)
+ Line<float> (Point<float>(), corners[2] - corners[0]).getPointAlongLine (point.y);
}
Rectangle<float> RelativeParallelogram::getBoundingBox (const Point<float>* const p) noexcept
{
const Point<float> points[] = { p[0], p[1], p[2], p[1] + (p[2] - p[0]) };
return Rectangle<float>::findAreaContainingPoints (points, 4);
}
} // namespace juce

View File

@ -1,66 +1,66 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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 parallelogram defined by three RelativePoint positions.
@see RelativePoint, RelativeCoordinate
@tags{GUI}
*/
class JUCE_API RelativeParallelogram
{
public:
//==============================================================================
RelativeParallelogram();
RelativeParallelogram (const Rectangle<float>& simpleRectangle);
RelativeParallelogram (const RelativePoint& topLeft, const RelativePoint& topRight, const RelativePoint& bottomLeft);
RelativeParallelogram (const String& topLeft, const String& topRight, const String& bottomLeft);
~RelativeParallelogram();
//==============================================================================
void resolveThreePoints (Point<float>* points, Expression::Scope* scope) const;
void resolveFourCorners (Point<float>* points, Expression::Scope* scope) const;
const Rectangle<float> getBounds (Expression::Scope* scope) const;
void getPath (Path& path, Expression::Scope* scope) const;
AffineTransform resetToPerpendicular (Expression::Scope* scope);
bool isDynamic() const;
bool operator== (const RelativeParallelogram&) const noexcept;
bool operator!= (const RelativeParallelogram&) const noexcept;
static Point<float> getInternalCoordForPoint (const Point<float>* parallelogramCorners, Point<float> point) noexcept;
static Point<float> getPointForInternalCoord (const Point<float>* parallelogramCorners, Point<float> internalPoint) noexcept;
static Rectangle<float> getBoundingBox (const Point<float>* parallelogramCorners) noexcept;
//==============================================================================
RelativePoint topLeft, topRight, bottomLeft;
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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 parallelogram defined by three RelativePoint positions.
@see RelativePoint, RelativeCoordinate
@tags{GUI}
*/
class JUCE_API RelativeParallelogram
{
public:
//==============================================================================
RelativeParallelogram();
RelativeParallelogram (const Rectangle<float>& simpleRectangle);
RelativeParallelogram (const RelativePoint& topLeft, const RelativePoint& topRight, const RelativePoint& bottomLeft);
RelativeParallelogram (const String& topLeft, const String& topRight, const String& bottomLeft);
~RelativeParallelogram();
//==============================================================================
void resolveThreePoints (Point<float>* points, Expression::Scope* scope) const;
void resolveFourCorners (Point<float>* points, Expression::Scope* scope) const;
const Rectangle<float> getBounds (Expression::Scope* scope) const;
void getPath (Path& path, Expression::Scope* scope) const;
AffineTransform resetToPerpendicular (Expression::Scope* scope);
bool isDynamic() const;
bool operator== (const RelativeParallelogram&) const noexcept;
bool operator!= (const RelativeParallelogram&) const noexcept;
static Point<float> getInternalCoordForPoint (const Point<float>* parallelogramCorners, Point<float> point) noexcept;
static Point<float> getPointForInternalCoord (const Point<float>* parallelogramCorners, Point<float> internalPoint) noexcept;
static Rectangle<float> getBoundingBox (const Point<float>* parallelogramCorners) noexcept;
//==============================================================================
RelativePoint topLeft, topRight, bottomLeft;
};
} // namespace juce

View File

@ -1,101 +1,101 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
namespace RelativePointHelpers
{
inline void skipComma (String::CharPointerType& s)
{
s.incrementToEndOfWhitespace();
if (*s == ',')
++s;
}
}
//==============================================================================
RelativePoint::RelativePoint()
{
}
RelativePoint::RelativePoint (Point<float> absolutePoint)
: x (absolutePoint.x), y (absolutePoint.y)
{
}
RelativePoint::RelativePoint (const float x_, const float y_)
: x (x_), y (y_)
{
}
RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordinate& y_)
: x (x_), y (y_)
{
}
RelativePoint::RelativePoint (const String& s)
{
String error;
String::CharPointerType text (s.getCharPointer());
x = RelativeCoordinate (Expression::parse (text, error));
RelativePointHelpers::skipComma (text);
y = RelativeCoordinate (Expression::parse (text, error));
}
bool RelativePoint::operator== (const RelativePoint& other) const noexcept
{
return x == other.x && y == other.y;
}
bool RelativePoint::operator!= (const RelativePoint& other) const noexcept
{
return ! operator== (other);
}
Point<float> RelativePoint::resolve (const Expression::Scope* scope) const
{
return Point<float> ((float) x.resolve (scope),
(float) y.resolve (scope));
}
void RelativePoint::moveToAbsolute (Point<float> newPos, const Expression::Scope* scope)
{
x.moveToAbsolute (newPos.x, scope);
y.moveToAbsolute (newPos.y, scope);
}
String RelativePoint::toString() const
{
return x.toString() + ", " + y.toString();
}
bool RelativePoint::isDynamic() const
{
return x.isDynamic() || y.isDynamic();
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
namespace RelativePointHelpers
{
inline void skipComma (String::CharPointerType& s)
{
s.incrementToEndOfWhitespace();
if (*s == ',')
++s;
}
}
//==============================================================================
RelativePoint::RelativePoint()
{
}
RelativePoint::RelativePoint (Point<float> absolutePoint)
: x (absolutePoint.x), y (absolutePoint.y)
{
}
RelativePoint::RelativePoint (const float x_, const float y_)
: x (x_), y (y_)
{
}
RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordinate& y_)
: x (x_), y (y_)
{
}
RelativePoint::RelativePoint (const String& s)
{
String error;
String::CharPointerType text (s.getCharPointer());
x = RelativeCoordinate (Expression::parse (text, error));
RelativePointHelpers::skipComma (text);
y = RelativeCoordinate (Expression::parse (text, error));
}
bool RelativePoint::operator== (const RelativePoint& other) const noexcept
{
return x == other.x && y == other.y;
}
bool RelativePoint::operator!= (const RelativePoint& other) const noexcept
{
return ! operator== (other);
}
Point<float> RelativePoint::resolve (const Expression::Scope* scope) const
{
return Point<float> ((float) x.resolve (scope),
(float) y.resolve (scope));
}
void RelativePoint::moveToAbsolute (Point<float> newPos, const Expression::Scope* scope)
{
x.moveToAbsolute (newPos.x, scope);
y.moveToAbsolute (newPos.y, scope);
}
String RelativePoint::toString() const
{
return x.toString() + ", " + y.toString();
}
bool RelativePoint::isDynamic() const
{
return x.isDynamic() || y.isDynamic();
}
} // namespace juce

View File

@ -1,91 +1,91 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
An X-Y position stored as a pair of RelativeCoordinate values.
@see RelativeCoordinate, RelativeRectangle
@tags{GUI}
*/
class JUCE_API RelativePoint
{
public:
/** Creates a point at the origin. */
RelativePoint();
/** Creates an absolute point, relative to the origin. */
RelativePoint (Point<float> absolutePoint);
/** Creates an absolute point, relative to the origin. */
RelativePoint (float absoluteX, float absoluteY);
/** Creates an absolute point from two coordinates. */
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y);
/** Creates a point from a stringified representation.
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate
strings is explained in the RelativeCoordinate class.
@see toString
*/
RelativePoint (const String& stringVersion);
bool operator== (const RelativePoint&) const noexcept;
bool operator!= (const RelativePoint&) const noexcept;
/** Calculates the absolute position of this point.
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
Point<float> resolve (const Expression::Scope* evaluationContext) const;
/** Changes the values of this point's coordinates to make it resolve to the specified position.
Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (Point<float> newPos, const Expression::Scope* evaluationContext);
/** Returns a string which represents this point.
This returns a comma-separated pair of coordinates. For details of the string syntax used by the
coordinates, see the RelativeCoordinate constructor notes.
The string that is returned can be passed to the RelativePoint constructor to recreate the point.
*/
String toString() const;
/** Returns true if this point depends on any other coordinates for its position. */
bool isDynamic() const;
// The actual X and Y coords...
RelativeCoordinate x, y;
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
//==============================================================================
/**
An X-Y position stored as a pair of RelativeCoordinate values.
@see RelativeCoordinate, RelativeRectangle
@tags{GUI}
*/
class JUCE_API RelativePoint
{
public:
/** Creates a point at the origin. */
RelativePoint();
/** Creates an absolute point, relative to the origin. */
RelativePoint (Point<float> absolutePoint);
/** Creates an absolute point, relative to the origin. */
RelativePoint (float absoluteX, float absoluteY);
/** Creates an absolute point from two coordinates. */
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y);
/** Creates a point from a stringified representation.
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate
strings is explained in the RelativeCoordinate class.
@see toString
*/
RelativePoint (const String& stringVersion);
bool operator== (const RelativePoint&) const noexcept;
bool operator!= (const RelativePoint&) const noexcept;
/** Calculates the absolute position of this point.
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
Point<float> resolve (const Expression::Scope* evaluationContext) const;
/** Changes the values of this point's coordinates to make it resolve to the specified position.
Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (Point<float> newPos, const Expression::Scope* evaluationContext);
/** Returns a string which represents this point.
This returns a comma-separated pair of coordinates. For details of the string syntax used by the
coordinates, see the RelativeCoordinate constructor notes.
The string that is returned can be passed to the RelativePoint constructor to recreate the point.
*/
String toString() const;
/** Returns true if this point depends on any other coordinates for its position. */
bool isDynamic() const;
// The actual X and Y coords...
RelativeCoordinate x, y;
};
} // namespace juce

View File

@ -1,262 +1,262 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
RelativePointPath::RelativePointPath()
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
}
RelativePointPath::RelativePointPath (const RelativePointPath& other)
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
for (int i = 0; i < other.elements.size(); ++i)
elements.add (other.elements.getUnchecked(i)->clone());
}
RelativePointPath::RelativePointPath (const Path& path)
: usesNonZeroWinding (path.isUsingNonZeroWinding()),
containsDynamicPoints (false)
{
for (Path::Iterator i (path); i.next();)
{
switch (i.elementType)
{
case Path::Iterator::startNewSubPath: elements.add (new StartSubPath (RelativePoint (i.x1, i.y1))); break;
case Path::Iterator::lineTo: elements.add (new LineTo (RelativePoint (i.x1, i.y1))); break;
case Path::Iterator::quadraticTo: elements.add (new QuadraticTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2))); break;
case Path::Iterator::cubicTo: elements.add (new CubicTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2), RelativePoint (i.x3, i.y3))); break;
case Path::Iterator::closePath: elements.add (new CloseSubPath()); break;
default: jassertfalse; break;
}
}
}
RelativePointPath::~RelativePointPath()
{
}
bool RelativePointPath::operator== (const RelativePointPath& other) const noexcept
{
if (elements.size() != other.elements.size()
|| usesNonZeroWinding != other.usesNonZeroWinding
|| containsDynamicPoints != other.containsDynamicPoints)
return false;
for (int i = 0; i < elements.size(); ++i)
{
ElementBase* const e1 = elements.getUnchecked(i);
ElementBase* const e2 = other.elements.getUnchecked(i);
if (e1->type != e2->type)
return false;
int numPoints1, numPoints2;
const RelativePoint* const points1 = e1->getControlPoints (numPoints1);
const RelativePoint* const points2 = e2->getControlPoints (numPoints2);
jassert (numPoints1 == numPoints2);
for (int j = numPoints1; --j >= 0;)
if (points1[j] != points2[j])
return false;
}
return true;
}
bool RelativePointPath::operator!= (const RelativePointPath& other) const noexcept
{
return ! operator== (other);
}
void RelativePointPath::swapWith (RelativePointPath& other) noexcept
{
elements.swapWith (other.elements);
std::swap (usesNonZeroWinding, other.usesNonZeroWinding);
std::swap (containsDynamicPoints, other.containsDynamicPoints);
}
void RelativePointPath::createPath (Path& path, Expression::Scope* scope) const
{
for (int i = 0; i < elements.size(); ++i)
elements.getUnchecked(i)->addToPath (path, scope);
}
bool RelativePointPath::containsAnyDynamicPoints() const
{
return containsDynamicPoints;
}
void RelativePointPath::addElement (ElementBase* newElement)
{
if (newElement != nullptr)
{
elements.add (newElement);
containsDynamicPoints = containsDynamicPoints || newElement->isDynamic();
}
}
//==============================================================================
RelativePointPath::ElementBase::ElementBase (const ElementType type_) : type (type_)
{
}
bool RelativePointPath::ElementBase::isDynamic()
{
int numPoints;
const RelativePoint* const points = getControlPoints (numPoints);
for (int i = numPoints; --i >= 0;)
if (points[i].isDynamic())
return true;
return false;
}
//==============================================================================
RelativePointPath::StartSubPath::StartSubPath (const RelativePoint& pos)
: ElementBase (startSubPathElement), startPos (pos)
{
}
void RelativePointPath::StartSubPath::addToPath (Path& path, Expression::Scope* scope) const
{
path.startNewSubPath (startPos.resolve (scope));
}
RelativePoint* RelativePointPath::StartSubPath::getControlPoints (int& numPoints)
{
numPoints = 1;
return &startPos;
}
RelativePointPath::ElementBase* RelativePointPath::StartSubPath::clone() const
{
return new StartSubPath (startPos);
}
//==============================================================================
RelativePointPath::CloseSubPath::CloseSubPath()
: ElementBase (closeSubPathElement)
{
}
void RelativePointPath::CloseSubPath::addToPath (Path& path, Expression::Scope*) const
{
path.closeSubPath();
}
RelativePoint* RelativePointPath::CloseSubPath::getControlPoints (int& numPoints)
{
numPoints = 0;
return nullptr;
}
RelativePointPath::ElementBase* RelativePointPath::CloseSubPath::clone() const
{
return new CloseSubPath();
}
//==============================================================================
RelativePointPath::LineTo::LineTo (const RelativePoint& endPoint_)
: ElementBase (lineToElement), endPoint (endPoint_)
{
}
void RelativePointPath::LineTo::addToPath (Path& path, Expression::Scope* scope) const
{
path.lineTo (endPoint.resolve (scope));
}
RelativePoint* RelativePointPath::LineTo::getControlPoints (int& numPoints)
{
numPoints = 1;
return &endPoint;
}
RelativePointPath::ElementBase* RelativePointPath::LineTo::clone() const
{
return new LineTo (endPoint);
}
//==============================================================================
RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint)
: ElementBase (quadraticToElement)
{
controlPoints[0] = controlPoint;
controlPoints[1] = endPoint;
}
void RelativePointPath::QuadraticTo::addToPath (Path& path, Expression::Scope* scope) const
{
path.quadraticTo (controlPoints[0].resolve (scope),
controlPoints[1].resolve (scope));
}
RelativePoint* RelativePointPath::QuadraticTo::getControlPoints (int& numPoints)
{
numPoints = 2;
return controlPoints;
}
RelativePointPath::ElementBase* RelativePointPath::QuadraticTo::clone() const
{
return new QuadraticTo (controlPoints[0], controlPoints[1]);
}
//==============================================================================
RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint)
: ElementBase (cubicToElement)
{
controlPoints[0] = controlPoint1;
controlPoints[1] = controlPoint2;
controlPoints[2] = endPoint;
}
void RelativePointPath::CubicTo::addToPath (Path& path, Expression::Scope* scope) const
{
path.cubicTo (controlPoints[0].resolve (scope),
controlPoints[1].resolve (scope),
controlPoints[2].resolve (scope));
}
RelativePoint* RelativePointPath::CubicTo::getControlPoints (int& numPoints)
{
numPoints = 3;
return controlPoints;
}
RelativePointPath::ElementBase* RelativePointPath::CubicTo::clone() const
{
return new CubicTo (controlPoints[0], controlPoints[1], controlPoints[2]);
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
RelativePointPath::RelativePointPath()
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
}
RelativePointPath::RelativePointPath (const RelativePointPath& other)
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
for (int i = 0; i < other.elements.size(); ++i)
elements.add (other.elements.getUnchecked(i)->clone());
}
RelativePointPath::RelativePointPath (const Path& path)
: usesNonZeroWinding (path.isUsingNonZeroWinding()),
containsDynamicPoints (false)
{
for (Path::Iterator i (path); i.next();)
{
switch (i.elementType)
{
case Path::Iterator::startNewSubPath: elements.add (new StartSubPath (RelativePoint (i.x1, i.y1))); break;
case Path::Iterator::lineTo: elements.add (new LineTo (RelativePoint (i.x1, i.y1))); break;
case Path::Iterator::quadraticTo: elements.add (new QuadraticTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2))); break;
case Path::Iterator::cubicTo: elements.add (new CubicTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2), RelativePoint (i.x3, i.y3))); break;
case Path::Iterator::closePath: elements.add (new CloseSubPath()); break;
default: jassertfalse; break;
}
}
}
RelativePointPath::~RelativePointPath()
{
}
bool RelativePointPath::operator== (const RelativePointPath& other) const noexcept
{
if (elements.size() != other.elements.size()
|| usesNonZeroWinding != other.usesNonZeroWinding
|| containsDynamicPoints != other.containsDynamicPoints)
return false;
for (int i = 0; i < elements.size(); ++i)
{
ElementBase* const e1 = elements.getUnchecked(i);
ElementBase* const e2 = other.elements.getUnchecked(i);
if (e1->type != e2->type)
return false;
int numPoints1, numPoints2;
const RelativePoint* const points1 = e1->getControlPoints (numPoints1);
const RelativePoint* const points2 = e2->getControlPoints (numPoints2);
jassert (numPoints1 == numPoints2);
for (int j = numPoints1; --j >= 0;)
if (points1[j] != points2[j])
return false;
}
return true;
}
bool RelativePointPath::operator!= (const RelativePointPath& other) const noexcept
{
return ! operator== (other);
}
void RelativePointPath::swapWith (RelativePointPath& other) noexcept
{
elements.swapWith (other.elements);
std::swap (usesNonZeroWinding, other.usesNonZeroWinding);
std::swap (containsDynamicPoints, other.containsDynamicPoints);
}
void RelativePointPath::createPath (Path& path, Expression::Scope* scope) const
{
for (int i = 0; i < elements.size(); ++i)
elements.getUnchecked(i)->addToPath (path, scope);
}
bool RelativePointPath::containsAnyDynamicPoints() const
{
return containsDynamicPoints;
}
void RelativePointPath::addElement (ElementBase* newElement)
{
if (newElement != nullptr)
{
elements.add (newElement);
containsDynamicPoints = containsDynamicPoints || newElement->isDynamic();
}
}
//==============================================================================
RelativePointPath::ElementBase::ElementBase (const ElementType type_) : type (type_)
{
}
bool RelativePointPath::ElementBase::isDynamic()
{
int numPoints;
const RelativePoint* const points = getControlPoints (numPoints);
for (int i = numPoints; --i >= 0;)
if (points[i].isDynamic())
return true;
return false;
}
//==============================================================================
RelativePointPath::StartSubPath::StartSubPath (const RelativePoint& pos)
: ElementBase (startSubPathElement), startPos (pos)
{
}
void RelativePointPath::StartSubPath::addToPath (Path& path, Expression::Scope* scope) const
{
path.startNewSubPath (startPos.resolve (scope));
}
RelativePoint* RelativePointPath::StartSubPath::getControlPoints (int& numPoints)
{
numPoints = 1;
return &startPos;
}
RelativePointPath::ElementBase* RelativePointPath::StartSubPath::clone() const
{
return new StartSubPath (startPos);
}
//==============================================================================
RelativePointPath::CloseSubPath::CloseSubPath()
: ElementBase (closeSubPathElement)
{
}
void RelativePointPath::CloseSubPath::addToPath (Path& path, Expression::Scope*) const
{
path.closeSubPath();
}
RelativePoint* RelativePointPath::CloseSubPath::getControlPoints (int& numPoints)
{
numPoints = 0;
return nullptr;
}
RelativePointPath::ElementBase* RelativePointPath::CloseSubPath::clone() const
{
return new CloseSubPath();
}
//==============================================================================
RelativePointPath::LineTo::LineTo (const RelativePoint& endPoint_)
: ElementBase (lineToElement), endPoint (endPoint_)
{
}
void RelativePointPath::LineTo::addToPath (Path& path, Expression::Scope* scope) const
{
path.lineTo (endPoint.resolve (scope));
}
RelativePoint* RelativePointPath::LineTo::getControlPoints (int& numPoints)
{
numPoints = 1;
return &endPoint;
}
RelativePointPath::ElementBase* RelativePointPath::LineTo::clone() const
{
return new LineTo (endPoint);
}
//==============================================================================
RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint)
: ElementBase (quadraticToElement)
{
controlPoints[0] = controlPoint;
controlPoints[1] = endPoint;
}
void RelativePointPath::QuadraticTo::addToPath (Path& path, Expression::Scope* scope) const
{
path.quadraticTo (controlPoints[0].resolve (scope),
controlPoints[1].resolve (scope));
}
RelativePoint* RelativePointPath::QuadraticTo::getControlPoints (int& numPoints)
{
numPoints = 2;
return controlPoints;
}
RelativePointPath::ElementBase* RelativePointPath::QuadraticTo::clone() const
{
return new QuadraticTo (controlPoints[0], controlPoints[1]);
}
//==============================================================================
RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint)
: ElementBase (cubicToElement)
{
controlPoints[0] = controlPoint1;
controlPoints[1] = controlPoint2;
controlPoints[2] = endPoint;
}
void RelativePointPath::CubicTo::addToPath (Path& path, Expression::Scope* scope) const
{
path.cubicTo (controlPoints[0].resolve (scope),
controlPoints[1].resolve (scope),
controlPoints[2].resolve (scope));
}
RelativePoint* RelativePointPath::CubicTo::getControlPoints (int& numPoints)
{
numPoints = 3;
return controlPoints;
}
RelativePointPath::ElementBase* RelativePointPath::CubicTo::clone() const
{
return new CubicTo (controlPoints[0], controlPoints[1], controlPoints[2]);
}
} // namespace juce

View File

@ -1,193 +1,193 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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 path object that consists of RelativePoint coordinates rather than the normal fixed ones.
One of these paths can be converted into a Path object for drawing and manipulation, but
unlike a Path, its points can be dynamic instead of just fixed.
@see RelativePoint, RelativeCoordinate
@tags{GUI}
*/
class JUCE_API RelativePointPath
{
public:
//==============================================================================
RelativePointPath();
RelativePointPath (const RelativePointPath&);
explicit RelativePointPath (const Path& path);
~RelativePointPath();
bool operator== (const RelativePointPath&) const noexcept;
bool operator!= (const RelativePointPath&) const noexcept;
//==============================================================================
/** Resolves this points in this path and adds them to a normal Path object. */
void createPath (Path& path, Expression::Scope* scope) const;
/** Returns true if the path contains any non-fixed points. */
bool containsAnyDynamicPoints() const;
/** Quickly swaps the contents of this path with another. */
void swapWith (RelativePointPath&) noexcept;
//==============================================================================
/** The types of element that may be contained in this path.
@see RelativePointPath::ElementBase
*/
enum ElementType
{
nullElement,
startSubPathElement,
closeSubPathElement,
lineToElement,
quadraticToElement,
cubicToElement
};
//==============================================================================
/** Base class for the elements that make up a RelativePointPath.
*/
class JUCE_API ElementBase
{
public:
ElementBase (ElementType type);
virtual ~ElementBase() = default;
virtual void addToPath (Path& path, Expression::Scope*) const = 0;
virtual RelativePoint* getControlPoints (int& numPoints) = 0;
virtual ElementBase* clone() const = 0;
bool isDynamic();
const ElementType type;
private:
JUCE_DECLARE_NON_COPYABLE (ElementBase)
};
//==============================================================================
/** Class for the start sub path element */
class JUCE_API StartSubPath : public ElementBase
{
public:
StartSubPath (const RelativePoint& pos);
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint startPos;
private:
JUCE_DECLARE_NON_COPYABLE (StartSubPath)
};
//==============================================================================
/** Class for the close sub path element */
class JUCE_API CloseSubPath : public ElementBase
{
public:
CloseSubPath();
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
private:
JUCE_DECLARE_NON_COPYABLE (CloseSubPath)
};
//==============================================================================
/** Class for the line to element */
class JUCE_API LineTo : public ElementBase
{
public:
LineTo (const RelativePoint& endPoint);
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint endPoint;
private:
JUCE_DECLARE_NON_COPYABLE (LineTo)
};
//==============================================================================
/** Class for the quadratic to element */
class JUCE_API QuadraticTo : public ElementBase
{
public:
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint);
ValueTree createTree() const;
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint controlPoints[2];
private:
JUCE_DECLARE_NON_COPYABLE (QuadraticTo)
};
//==============================================================================
/** Class for the cubic to element */
class JUCE_API CubicTo : public ElementBase
{
public:
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint);
ValueTree createTree() const;
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint controlPoints[3];
private:
JUCE_DECLARE_NON_COPYABLE (CubicTo)
};
//==============================================================================
void addElement (ElementBase* newElement);
//==============================================================================
OwnedArray<ElementBase> elements;
bool usesNonZeroWinding;
private:
class Positioner;
friend class Positioner;
bool containsDynamicPoints;
void applyTo (DrawablePath& path) const;
RelativePointPath& operator= (const RelativePointPath&);
JUCE_LEAK_DETECTOR (RelativePointPath)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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 path object that consists of RelativePoint coordinates rather than the normal fixed ones.
One of these paths can be converted into a Path object for drawing and manipulation, but
unlike a Path, its points can be dynamic instead of just fixed.
@see RelativePoint, RelativeCoordinate
@tags{GUI}
*/
class JUCE_API RelativePointPath
{
public:
//==============================================================================
RelativePointPath();
RelativePointPath (const RelativePointPath&);
explicit RelativePointPath (const Path& path);
~RelativePointPath();
bool operator== (const RelativePointPath&) const noexcept;
bool operator!= (const RelativePointPath&) const noexcept;
//==============================================================================
/** Resolves this points in this path and adds them to a normal Path object. */
void createPath (Path& path, Expression::Scope* scope) const;
/** Returns true if the path contains any non-fixed points. */
bool containsAnyDynamicPoints() const;
/** Quickly swaps the contents of this path with another. */
void swapWith (RelativePointPath&) noexcept;
//==============================================================================
/** The types of element that may be contained in this path.
@see RelativePointPath::ElementBase
*/
enum ElementType
{
nullElement,
startSubPathElement,
closeSubPathElement,
lineToElement,
quadraticToElement,
cubicToElement
};
//==============================================================================
/** Base class for the elements that make up a RelativePointPath.
*/
class JUCE_API ElementBase
{
public:
ElementBase (ElementType type);
virtual ~ElementBase() = default;
virtual void addToPath (Path& path, Expression::Scope*) const = 0;
virtual RelativePoint* getControlPoints (int& numPoints) = 0;
virtual ElementBase* clone() const = 0;
bool isDynamic();
const ElementType type;
private:
JUCE_DECLARE_NON_COPYABLE (ElementBase)
};
//==============================================================================
/** Class for the start sub path element */
class JUCE_API StartSubPath : public ElementBase
{
public:
StartSubPath (const RelativePoint& pos);
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint startPos;
private:
JUCE_DECLARE_NON_COPYABLE (StartSubPath)
};
//==============================================================================
/** Class for the close sub path element */
class JUCE_API CloseSubPath : public ElementBase
{
public:
CloseSubPath();
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
private:
JUCE_DECLARE_NON_COPYABLE (CloseSubPath)
};
//==============================================================================
/** Class for the line to element */
class JUCE_API LineTo : public ElementBase
{
public:
LineTo (const RelativePoint& endPoint);
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint endPoint;
private:
JUCE_DECLARE_NON_COPYABLE (LineTo)
};
//==============================================================================
/** Class for the quadratic to element */
class JUCE_API QuadraticTo : public ElementBase
{
public:
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint);
ValueTree createTree() const;
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint controlPoints[2];
private:
JUCE_DECLARE_NON_COPYABLE (QuadraticTo)
};
//==============================================================================
/** Class for the cubic to element */
class JUCE_API CubicTo : public ElementBase
{
public:
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint);
ValueTree createTree() const;
void addToPath (Path& path, Expression::Scope*) const override;
RelativePoint* getControlPoints (int& numPoints) override;
ElementBase* clone() const override;
RelativePoint controlPoints[3];
private:
JUCE_DECLARE_NON_COPYABLE (CubicTo)
};
//==============================================================================
void addElement (ElementBase* newElement);
//==============================================================================
OwnedArray<ElementBase> elements;
bool usesNonZeroWinding;
private:
class Positioner;
friend class Positioner;
bool containsDynamicPoints;
void applyTo (DrawablePath& path) const;
RelativePointPath& operator= (const RelativePointPath&);
JUCE_LEAK_DETECTOR (RelativePointPath)
};
} // namespace juce

View File

@ -1,277 +1,277 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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
{
namespace RelativeRectangleHelpers
{
inline void skipComma (String::CharPointerType& s)
{
s.incrementToEndOfWhitespace();
if (*s == ',')
++s;
}
static bool dependsOnSymbolsOtherThanThis (const Expression& e)
{
if (e.getType() == Expression::operatorType && e.getSymbolOrFunction() == ".")
return true;
if (e.getType() == Expression::symbolType)
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (e.getSymbolOrFunction()))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::left:
case RelativeCoordinate::StandardStrings::right:
case RelativeCoordinate::StandardStrings::top:
case RelativeCoordinate::StandardStrings::bottom: return false;
case RelativeCoordinate::StandardStrings::width:
case RelativeCoordinate::StandardStrings::height:
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default: break;
}
return true;
}
else
{
for (int i = e.getNumInputs(); --i >= 0;)
if (dependsOnSymbolsOtherThanThis (e.getInput(i)))
return true;
}
return false;
}
}
//==============================================================================
RelativeRectangle::RelativeRectangle()
{
}
RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const RelativeCoordinate& right_,
const RelativeCoordinate& top_, const RelativeCoordinate& bottom_)
: left (left_), right (right_), top (top_), bottom (bottom_)
{
}
RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect)
: left (rect.getX()),
right (Expression::symbol (RelativeCoordinate::Strings::left) + Expression ((double) rect.getWidth())),
top (rect.getY()),
bottom (Expression::symbol (RelativeCoordinate::Strings::top) + Expression ((double) rect.getHeight()))
{
}
RelativeRectangle::RelativeRectangle (const String& s)
{
String error;
String::CharPointerType text (s.getCharPointer());
left = RelativeCoordinate (Expression::parse (text, error));
RelativeRectangleHelpers::skipComma (text);
top = RelativeCoordinate (Expression::parse (text, error));
RelativeRectangleHelpers::skipComma (text);
right = RelativeCoordinate (Expression::parse (text, error));
RelativeRectangleHelpers::skipComma (text);
bottom = RelativeCoordinate (Expression::parse (text, error));
}
bool RelativeRectangle::operator== (const RelativeRectangle& other) const noexcept
{
return left == other.left && top == other.top && right == other.right && bottom == other.bottom;
}
bool RelativeRectangle::operator!= (const RelativeRectangle& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
// An expression context that can evaluate expressions using "this"
class RelativeRectangleLocalScope : public Expression::Scope
{
public:
RelativeRectangleLocalScope (const RelativeRectangle& rect_) : rect (rect_) {}
Expression getSymbolValue (const String& symbol) const
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::left: return rect.left.getExpression();
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::top: return rect.top.getExpression();
case RelativeCoordinate::StandardStrings::right: return rect.right.getExpression();
case RelativeCoordinate::StandardStrings::bottom: return rect.bottom.getExpression();
case RelativeCoordinate::StandardStrings::width:
case RelativeCoordinate::StandardStrings::height:
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default: break;
}
return Expression::Scope::getSymbolValue (symbol);
}
private:
const RelativeRectangle& rect;
JUCE_DECLARE_NON_COPYABLE (RelativeRectangleLocalScope)
};
const Rectangle<float> RelativeRectangle::resolve (const Expression::Scope* scope) const
{
if (scope == nullptr)
{
RelativeRectangleLocalScope defaultScope (*this);
return resolve (&defaultScope);
}
else
{
const double l = left.resolve (scope);
const double r = right.resolve (scope);
const double t = top.resolve (scope);
const double b = bottom.resolve (scope);
return Rectangle<float> ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t));
}
}
void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::Scope* scope)
{
left.moveToAbsolute (newPos.getX(), scope);
right.moveToAbsolute (newPos.getRight(), scope);
top.moveToAbsolute (newPos.getY(), scope);
bottom.moveToAbsolute (newPos.getBottom(), scope);
}
bool RelativeRectangle::isDynamic() const
{
using namespace RelativeRectangleHelpers;
return dependsOnSymbolsOtherThanThis (left.getExpression())
|| dependsOnSymbolsOtherThanThis (right.getExpression())
|| dependsOnSymbolsOtherThanThis (top.getExpression())
|| dependsOnSymbolsOtherThanThis (bottom.getExpression());
}
String RelativeRectangle::toString() const
{
return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString();
}
void RelativeRectangle::renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope)
{
left = left.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
right = right.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
top = top.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
bottom = bottom.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
}
//==============================================================================
class RelativeRectangleComponentPositioner : public RelativeCoordinatePositionerBase
{
public:
RelativeRectangleComponentPositioner (Component& comp, const RelativeRectangle& r)
: RelativeCoordinatePositionerBase (comp),
rectangle (r)
{
}
bool registerCoordinates() override
{
bool ok = addCoordinate (rectangle.left);
ok = addCoordinate (rectangle.right) && ok;
ok = addCoordinate (rectangle.top) && ok;
ok = addCoordinate (rectangle.bottom) && ok;
return ok;
}
bool isUsingRectangle (const RelativeRectangle& other) const noexcept
{
return rectangle == other;
}
void applyToComponentBounds() override
{
for (int i = 32; --i >= 0;)
{
ComponentScope scope (getComponent());
const Rectangle<int> newBounds (rectangle.resolve (&scope).getSmallestIntegerContainer());
if (newBounds == getComponent().getBounds())
return;
getComponent().setBounds (newBounds);
}
jassertfalse; // Seems to be a recursive reference!
}
void applyNewBounds (const Rectangle<int>& newBounds) override
{
if (newBounds != getComponent().getBounds())
{
ComponentScope scope (getComponent());
rectangle.moveToAbsolute (newBounds.toFloat(), &scope);
applyToComponentBounds();
}
}
private:
RelativeRectangle rectangle;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner)
};
void RelativeRectangle::applyToComponent (Component& component) const
{
if (isDynamic())
{
RelativeRectangleComponentPositioner* current = dynamic_cast<RelativeRectangleComponentPositioner*> (component.getPositioner());
if (current == nullptr || ! current->isUsingRectangle (*this))
{
RelativeRectangleComponentPositioner* p = new RelativeRectangleComponentPositioner (component, *this);
component.setPositioner (p);
p->apply();
}
}
else
{
component.setPositioner (nullptr);
component.setBounds (resolve (nullptr).getSmallestIntegerContainer());
}
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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
{
namespace RelativeRectangleHelpers
{
inline void skipComma (String::CharPointerType& s)
{
s.incrementToEndOfWhitespace();
if (*s == ',')
++s;
}
static bool dependsOnSymbolsOtherThanThis (const Expression& e)
{
if (e.getType() == Expression::operatorType && e.getSymbolOrFunction() == ".")
return true;
if (e.getType() == Expression::symbolType)
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (e.getSymbolOrFunction()))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::left:
case RelativeCoordinate::StandardStrings::right:
case RelativeCoordinate::StandardStrings::top:
case RelativeCoordinate::StandardStrings::bottom: return false;
case RelativeCoordinate::StandardStrings::width:
case RelativeCoordinate::StandardStrings::height:
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default: break;
}
return true;
}
else
{
for (int i = e.getNumInputs(); --i >= 0;)
if (dependsOnSymbolsOtherThanThis (e.getInput(i)))
return true;
}
return false;
}
}
//==============================================================================
RelativeRectangle::RelativeRectangle()
{
}
RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const RelativeCoordinate& right_,
const RelativeCoordinate& top_, const RelativeCoordinate& bottom_)
: left (left_), right (right_), top (top_), bottom (bottom_)
{
}
RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect)
: left (rect.getX()),
right (Expression::symbol (RelativeCoordinate::Strings::left) + Expression ((double) rect.getWidth())),
top (rect.getY()),
bottom (Expression::symbol (RelativeCoordinate::Strings::top) + Expression ((double) rect.getHeight()))
{
}
RelativeRectangle::RelativeRectangle (const String& s)
{
String error;
String::CharPointerType text (s.getCharPointer());
left = RelativeCoordinate (Expression::parse (text, error));
RelativeRectangleHelpers::skipComma (text);
top = RelativeCoordinate (Expression::parse (text, error));
RelativeRectangleHelpers::skipComma (text);
right = RelativeCoordinate (Expression::parse (text, error));
RelativeRectangleHelpers::skipComma (text);
bottom = RelativeCoordinate (Expression::parse (text, error));
}
bool RelativeRectangle::operator== (const RelativeRectangle& other) const noexcept
{
return left == other.left && top == other.top && right == other.right && bottom == other.bottom;
}
bool RelativeRectangle::operator!= (const RelativeRectangle& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
// An expression context that can evaluate expressions using "this"
class RelativeRectangleLocalScope : public Expression::Scope
{
public:
RelativeRectangleLocalScope (const RelativeRectangle& rect_) : rect (rect_) {}
Expression getSymbolValue (const String& symbol) const
{
switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
{
case RelativeCoordinate::StandardStrings::x:
case RelativeCoordinate::StandardStrings::left: return rect.left.getExpression();
case RelativeCoordinate::StandardStrings::y:
case RelativeCoordinate::StandardStrings::top: return rect.top.getExpression();
case RelativeCoordinate::StandardStrings::right: return rect.right.getExpression();
case RelativeCoordinate::StandardStrings::bottom: return rect.bottom.getExpression();
case RelativeCoordinate::StandardStrings::width:
case RelativeCoordinate::StandardStrings::height:
case RelativeCoordinate::StandardStrings::parent:
case RelativeCoordinate::StandardStrings::unknown:
default: break;
}
return Expression::Scope::getSymbolValue (symbol);
}
private:
const RelativeRectangle& rect;
JUCE_DECLARE_NON_COPYABLE (RelativeRectangleLocalScope)
};
const Rectangle<float> RelativeRectangle::resolve (const Expression::Scope* scope) const
{
if (scope == nullptr)
{
RelativeRectangleLocalScope defaultScope (*this);
return resolve (&defaultScope);
}
else
{
const double l = left.resolve (scope);
const double r = right.resolve (scope);
const double t = top.resolve (scope);
const double b = bottom.resolve (scope);
return Rectangle<float> ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t));
}
}
void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::Scope* scope)
{
left.moveToAbsolute (newPos.getX(), scope);
right.moveToAbsolute (newPos.getRight(), scope);
top.moveToAbsolute (newPos.getY(), scope);
bottom.moveToAbsolute (newPos.getBottom(), scope);
}
bool RelativeRectangle::isDynamic() const
{
using namespace RelativeRectangleHelpers;
return dependsOnSymbolsOtherThanThis (left.getExpression())
|| dependsOnSymbolsOtherThanThis (right.getExpression())
|| dependsOnSymbolsOtherThanThis (top.getExpression())
|| dependsOnSymbolsOtherThanThis (bottom.getExpression());
}
String RelativeRectangle::toString() const
{
return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString();
}
void RelativeRectangle::renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope)
{
left = left.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
right = right.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
top = top.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
bottom = bottom.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
}
//==============================================================================
class RelativeRectangleComponentPositioner : public RelativeCoordinatePositionerBase
{
public:
RelativeRectangleComponentPositioner (Component& comp, const RelativeRectangle& r)
: RelativeCoordinatePositionerBase (comp),
rectangle (r)
{
}
bool registerCoordinates() override
{
bool ok = addCoordinate (rectangle.left);
ok = addCoordinate (rectangle.right) && ok;
ok = addCoordinate (rectangle.top) && ok;
ok = addCoordinate (rectangle.bottom) && ok;
return ok;
}
bool isUsingRectangle (const RelativeRectangle& other) const noexcept
{
return rectangle == other;
}
void applyToComponentBounds() override
{
for (int i = 32; --i >= 0;)
{
ComponentScope scope (getComponent());
const Rectangle<int> newBounds (rectangle.resolve (&scope).getSmallestIntegerContainer());
if (newBounds == getComponent().getBounds())
return;
getComponent().setBounds (newBounds);
}
jassertfalse; // Seems to be a recursive reference!
}
void applyNewBounds (const Rectangle<int>& newBounds) override
{
if (newBounds != getComponent().getBounds())
{
ComponentScope scope (getComponent());
rectangle.moveToAbsolute (newBounds.toFloat(), &scope);
applyToComponentBounds();
}
}
private:
RelativeRectangle rectangle;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner)
};
void RelativeRectangle::applyToComponent (Component& component) const
{
if (isDynamic())
{
RelativeRectangleComponentPositioner* current = dynamic_cast<RelativeRectangleComponentPositioner*> (component.getPositioner());
if (current == nullptr || ! current->isUsingRectangle (*this))
{
RelativeRectangleComponentPositioner* p = new RelativeRectangleComponentPositioner (component, *this);
component.setPositioner (p);
p->apply();
}
}
else
{
component.setPositioner (nullptr);
component.setBounds (resolve (nullptr).getSmallestIntegerContainer());
}
}
} // namespace juce

View File

@ -1,108 +1,108 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
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 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-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 rectangle stored as a set of RelativeCoordinate values.
The rectangle's top, left, bottom and right edge positions are each stored as a RelativeCoordinate.
@see RelativeCoordinate, RelativePoint
@tags{GUI}
*/
class JUCE_API RelativeRectangle
{
public:
//==============================================================================
/** Creates a zero-size rectangle at the origin. */
RelativeRectangle();
/** Creates an absolute rectangle, relative to the origin. */
explicit RelativeRectangle (const Rectangle<float>& rect);
/** Creates a rectangle from four coordinates. */
RelativeRectangle (const RelativeCoordinate& left, const RelativeCoordinate& right,
const RelativeCoordinate& top, const RelativeCoordinate& bottom);
/** Creates a rectangle from a stringified representation.
The string must contain a sequence of 4 coordinates, separated by commas, in the order
left, top, right, bottom. The syntax for the coordinate strings is explained in the
RelativeCoordinate class.
@see toString
*/
explicit RelativeRectangle (const String& stringVersion);
bool operator== (const RelativeRectangle&) const noexcept;
bool operator!= (const RelativeRectangle&) const noexcept;
//==============================================================================
/** Calculates the absolute position of this rectangle.
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
const Rectangle<float> resolve (const Expression::Scope* scope) const;
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position.
Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (const Rectangle<float>& newPos, const Expression::Scope* scope);
/** Returns true if this rectangle depends on any external symbols for its position.
Coordinates that refer to symbols based on "this" are assumed not to be dynamic.
*/
bool isDynamic() const;
/** Returns a string which represents this point.
This returns a comma-separated list of coordinates, in the order left, top, right, bottom.
If you're using this to position a Component, then see the notes for
Component::setBounds (const RelativeRectangle&) for details of the syntax used.
The string that is returned can be passed to the RelativeRectangle constructor to recreate the rectangle.
*/
String toString() const;
/** Renames a symbol if it is used by any of the coordinates.
This calls Expression::withRenamedSymbol() on the rectangle's coordinates.
*/
void renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope);
/** Creates and sets an appropriate Component::Positioner object for the given component, which will
keep it positioned with this rectangle.
*/
void applyToComponent (Component& component) const;
//==============================================================================
// The actual rectangle coords...
RelativeCoordinate left, right, top, bottom;
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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 rectangle stored as a set of RelativeCoordinate values.
The rectangle's top, left, bottom and right edge positions are each stored as a RelativeCoordinate.
@see RelativeCoordinate, RelativePoint
@tags{GUI}
*/
class JUCE_API RelativeRectangle
{
public:
//==============================================================================
/** Creates a zero-size rectangle at the origin. */
RelativeRectangle();
/** Creates an absolute rectangle, relative to the origin. */
explicit RelativeRectangle (const Rectangle<float>& rect);
/** Creates a rectangle from four coordinates. */
RelativeRectangle (const RelativeCoordinate& left, const RelativeCoordinate& right,
const RelativeCoordinate& top, const RelativeCoordinate& bottom);
/** Creates a rectangle from a stringified representation.
The string must contain a sequence of 4 coordinates, separated by commas, in the order
left, top, right, bottom. The syntax for the coordinate strings is explained in the
RelativeCoordinate class.
@see toString
*/
explicit RelativeRectangle (const String& stringVersion);
bool operator== (const RelativeRectangle&) const noexcept;
bool operator!= (const RelativeRectangle&) const noexcept;
//==============================================================================
/** Calculates the absolute position of this rectangle.
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
const Rectangle<float> resolve (const Expression::Scope* scope) const;
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position.
Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (const Rectangle<float>& newPos, const Expression::Scope* scope);
/** Returns true if this rectangle depends on any external symbols for its position.
Coordinates that refer to symbols based on "this" are assumed not to be dynamic.
*/
bool isDynamic() const;
/** Returns a string which represents this point.
This returns a comma-separated list of coordinates, in the order left, top, right, bottom.
If you're using this to position a Component, then see the notes for
Component::setBounds (const RelativeRectangle&) for details of the syntax used.
The string that is returned can be passed to the RelativeRectangle constructor to recreate the rectangle.
*/
String toString() const;
/** Renames a symbol if it is used by any of the coordinates.
This calls Expression::withRenamedSymbol() on the rectangle's coordinates.
*/
void renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope);
/** Creates and sets an appropriate Component::Positioner object for the given component, which will
keep it positioned with this rectangle.
*/
void applyToComponent (Component& component) const;
//==============================================================================
// The actual rectangle coords...
RelativeCoordinate left, right, top, bottom;
};
} // namespace juce