2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
30 #include "juce_RelativeRectangle.h"
31 #include "juce_RelativeCoordinatePositioner.h"
34 //==============================================================================
35 namespace RelativeRectangleHelpers
37 inline void skipComma (String::CharPointerType
& s
)
39 s
= s
.findEndOfWhitespace();
45 bool dependsOnSymbolsOtherThanThis (const Expression
& e
)
47 if (e
.getType() == Expression::operatorType
&& e
.getSymbolOrFunction() == ".")
50 if (e
.getType() == Expression::symbolType
)
52 switch (RelativeCoordinate::StandardStrings::getTypeOf (e
.getSymbolOrFunction()))
54 case RelativeCoordinate::StandardStrings::x
:
55 case RelativeCoordinate::StandardStrings::y
:
56 case RelativeCoordinate::StandardStrings::left
:
57 case RelativeCoordinate::StandardStrings::right
:
58 case RelativeCoordinate::StandardStrings::top
:
59 case RelativeCoordinate::StandardStrings::bottom
: return false;
67 for (int i
= e
.getNumInputs(); --i
>= 0;)
68 if (dependsOnSymbolsOtherThanThis (e
.getInput(i
)))
76 //==============================================================================
77 RelativeRectangle::RelativeRectangle()
81 RelativeRectangle::RelativeRectangle (const RelativeCoordinate
& left_
, const RelativeCoordinate
& right_
,
82 const RelativeCoordinate
& top_
, const RelativeCoordinate
& bottom_
)
83 : left (left_
), right (right_
), top (top_
), bottom (bottom_
)
87 RelativeRectangle::RelativeRectangle (const Rectangle
<float>& rect
)
89 right (Expression::symbol (RelativeCoordinate::Strings::left
) + Expression ((double) rect
.getWidth())),
91 bottom (Expression::symbol (RelativeCoordinate::Strings::top
) + Expression ((double) rect
.getHeight()))
95 RelativeRectangle::RelativeRectangle (const String
& s
)
97 String::CharPointerType
text (s
.getCharPointer());
98 left
= RelativeCoordinate (Expression::parse (text
));
99 RelativeRectangleHelpers::skipComma (text
);
100 top
= RelativeCoordinate (Expression::parse (text
));
101 RelativeRectangleHelpers::skipComma (text
);
102 right
= RelativeCoordinate (Expression::parse (text
));
103 RelativeRectangleHelpers::skipComma (text
);
104 bottom
= RelativeCoordinate (Expression::parse (text
));
107 bool RelativeRectangle::operator== (const RelativeRectangle
& other
) const noexcept
109 return left
== other
.left
&& top
== other
.top
&& right
== other
.right
&& bottom
== other
.bottom
;
112 bool RelativeRectangle::operator!= (const RelativeRectangle
& other
) const noexcept
114 return ! operator== (other
);
117 //==============================================================================
118 // An expression context that can evaluate expressions using "this"
119 class RelativeRectangleLocalScope
: public Expression::Scope
122 RelativeRectangleLocalScope (const RelativeRectangle
& rect_
) : rect (rect_
) {}
124 Expression
getSymbolValue (const String
& symbol
) const
126 switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol
))
128 case RelativeCoordinate::StandardStrings::x
:
129 case RelativeCoordinate::StandardStrings::left
: return rect
.left
.getExpression();
130 case RelativeCoordinate::StandardStrings::y
:
131 case RelativeCoordinate::StandardStrings::top
: return rect
.top
.getExpression();
132 case RelativeCoordinate::StandardStrings::right
: return rect
.right
.getExpression();
133 case RelativeCoordinate::StandardStrings::bottom
: return rect
.bottom
.getExpression();
137 return Expression::Scope::getSymbolValue (symbol
);
141 const RelativeRectangle
& rect
;
143 JUCE_DECLARE_NON_COPYABLE (RelativeRectangleLocalScope
);
146 const Rectangle
<float> RelativeRectangle::resolve (const Expression::Scope
* scope
) const
148 if (scope
== nullptr)
150 RelativeRectangleLocalScope
defaultScope (*this);
151 return resolve (&defaultScope
);
155 const double l
= left
.resolve (scope
);
156 const double r
= right
.resolve (scope
);
157 const double t
= top
.resolve (scope
);
158 const double b
= bottom
.resolve (scope
);
160 return Rectangle
<float> ((float) l
, (float) t
, (float) jmax (0.0, r
- l
), (float) jmax (0.0, b
- t
));
164 void RelativeRectangle::moveToAbsolute (const Rectangle
<float>& newPos
, const Expression::Scope
* scope
)
166 left
.moveToAbsolute (newPos
.getX(), scope
);
167 right
.moveToAbsolute (newPos
.getRight(), scope
);
168 top
.moveToAbsolute (newPos
.getY(), scope
);
169 bottom
.moveToAbsolute (newPos
.getBottom(), scope
);
172 bool RelativeRectangle::isDynamic() const
174 using namespace RelativeRectangleHelpers
;
176 return dependsOnSymbolsOtherThanThis (left
.getExpression())
177 || dependsOnSymbolsOtherThanThis (right
.getExpression())
178 || dependsOnSymbolsOtherThanThis (top
.getExpression())
179 || dependsOnSymbolsOtherThanThis (bottom
.getExpression());
182 String
RelativeRectangle::toString() const
184 return left
.toString() + ", " + top
.toString() + ", " + right
.toString() + ", " + bottom
.toString();
187 void RelativeRectangle::renameSymbol (const Expression::Symbol
& oldSymbol
, const String
& newName
, const Expression::Scope
& scope
)
189 left
= left
.getExpression().withRenamedSymbol (oldSymbol
, newName
, scope
);
190 right
= right
.getExpression().withRenamedSymbol (oldSymbol
, newName
, scope
);
191 top
= top
.getExpression().withRenamedSymbol (oldSymbol
, newName
, scope
);
192 bottom
= bottom
.getExpression().withRenamedSymbol (oldSymbol
, newName
, scope
);
195 //==============================================================================
196 class RelativeRectangleComponentPositioner
: public RelativeCoordinatePositionerBase
199 RelativeRectangleComponentPositioner (Component
& component_
, const RelativeRectangle
& rectangle_
)
200 : RelativeCoordinatePositionerBase (component_
),
201 rectangle (rectangle_
)
205 bool registerCoordinates()
207 bool ok
= addCoordinate (rectangle
.left
);
208 ok
= addCoordinate (rectangle
.right
) && ok
;
209 ok
= addCoordinate (rectangle
.top
) && ok
;
210 ok
= addCoordinate (rectangle
.bottom
) && ok
;
214 bool isUsingRectangle (const RelativeRectangle
& other
) const noexcept
216 return rectangle
== other
;
219 void applyToComponentBounds()
221 for (int i
= 4; --i
>= 0;)
223 ComponentScope
scope (getComponent());
224 const Rectangle
<int> newBounds (rectangle
.resolve (&scope
).getSmallestIntegerContainer());
226 if (newBounds
== getComponent().getBounds())
229 getComponent().setBounds (newBounds
);
232 jassertfalse
; // must be a recursive reference!
235 void applyNewBounds (const Rectangle
<int>& newBounds
)
237 if (newBounds
!= getComponent().getBounds())
239 ComponentScope
scope (getComponent());
240 rectangle
.moveToAbsolute (newBounds
.toFloat(), &scope
);
242 applyToComponentBounds();
247 RelativeRectangle rectangle
;
249 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner
);
252 void RelativeRectangle::applyToComponent (Component
& component
) const
256 RelativeRectangleComponentPositioner
* current
= dynamic_cast <RelativeRectangleComponentPositioner
*> (component
.getPositioner());
258 if (current
== nullptr || ! current
->isUsingRectangle (*this))
260 RelativeRectangleComponentPositioner
* p
= new RelativeRectangleComponentPositioner (component
, *this);
262 component
.setPositioner (p
);
268 component
.setPositioner (nullptr);
269 component
.setBounds (resolve (nullptr).getSmallestIntegerContainer());