|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-9 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
- */
-
- #include "jucer_Coordinate.h"
-
-
- //==============================================================================
- const char* Coordinate::parentLeftMarkerName = "parent.left";
- const char* Coordinate::parentRightMarkerName = "parent.right";
- const char* Coordinate::parentTopMarkerName = "parent.top";
- const char* Coordinate::parentBottomMarkerName = "parent.bottom";
-
- Coordinate::Coordinate (bool isHorizontal_)
- : value (0), isProportion (false), isHorizontal (isHorizontal_)
- {
- }
-
- Coordinate::Coordinate (double absoluteDistanceFromOrigin, bool isHorizontal_)
- : value (absoluteDistanceFromOrigin), isProportion (false), isHorizontal (isHorizontal_)
- {
- }
-
- Coordinate::Coordinate (double absoluteDistance, const String& source, bool isHorizontal_)
- : anchor1 (source), value (absoluteDistance), isProportion (false), isHorizontal (isHorizontal_)
- {
- }
-
- Coordinate::Coordinate (double relativeProportion, const String& pos1, const String& pos2, bool isHorizontal_)
- : anchor1 (pos1), anchor2 (pos2), value (relativeProportion), isProportion (true), isHorizontal (isHorizontal_)
- {
- }
-
- Coordinate::~Coordinate()
- {
- }
-
- const Coordinate Coordinate::getAnchorPoint1() const
- {
- return Coordinate (0.0, anchor1, isHorizontal);
- }
-
- const Coordinate Coordinate::getAnchorPoint2() const
- {
- return Coordinate (0.0, anchor2, isHorizontal);
- }
-
- bool Coordinate::isOrigin (const String& name)
- {
- return name.isEmpty() || name == parentLeftMarkerName || name == parentTopMarkerName;
- }
-
- const String Coordinate::getOriginMarkerName() const
- {
- return isHorizontal ? parentLeftMarkerName : parentTopMarkerName;
- }
-
- const String Coordinate::getExtentMarkerName() const
- {
- return isHorizontal ? parentRightMarkerName : parentBottomMarkerName;
- }
-
- const String Coordinate::checkName (const String& name) const
- {
- return name.isEmpty() ? getOriginMarkerName() : name;
- }
-
- double Coordinate::getPosition (const String& name, MarkerResolver& markerResolver, int recursionCounter) const
- {
- if (isOrigin (name))
- return 0.0;
-
- return markerResolver.findMarker (name, isHorizontal)
- .resolve (markerResolver, recursionCounter + 1);
- }
-
- struct RecursivePositionException
- {
- };
-
- double Coordinate::resolve (MarkerResolver& markerResolver, int recursionCounter) const
- {
- if (recursionCounter > 100)
- {
- jassertfalse
- throw RecursivePositionException();
- }
-
- const double pos1 = getPosition (anchor1, markerResolver, recursionCounter);
-
- return isProportion ? pos1 + (getPosition (anchor2, markerResolver, recursionCounter) - pos1) * value
- : pos1 + value;
- }
-
- double Coordinate::resolve (MarkerResolver& markerResolver) const
- {
- try
- {
- return resolve (markerResolver, 0);
- }
- catch (RecursivePositionException&)
- {}
-
- return 0.0;
- }
-
- void Coordinate::moveToAbsolute (double newPos, MarkerResolver& markerResolver)
- {
- try
- {
- const double pos1 = getPosition (anchor1, markerResolver, 0);
-
- if (isProportion)
- {
- const double size = getPosition (anchor2, markerResolver, 0) - pos1;
-
- if (size != 0)
- value = (newPos - pos1) / size;
- }
- else
- {
- value = newPos - pos1;
- }
- }
- catch (RecursivePositionException&)
- {}
- }
-
- bool Coordinate::isRecursive (MarkerResolver& markerResolver) const
- {
- try
- {
- resolve (markerResolver, 0);
- }
- catch (RecursivePositionException&)
- {
- return true;
- }
-
- return false;
- }
-
- void Coordinate::skipWhitespace (const String& s, int& i)
- {
- while (CharacterFunctions::isWhitespace (s[i]))
- ++i;
- }
-
- const String Coordinate::readMarkerName (const String& s, int& i)
- {
- skipWhitespace (s, i);
-
- if (CharacterFunctions::isLetter (s[i]) || s[i] == '_')
- {
- int start = i;
-
- while (CharacterFunctions::isLetterOrDigit (s[i]) || s[i] == '_' || s[i] == '.')
- ++i;
-
- return s.substring (start, i);
- }
-
- return String::empty;
- }
-
- double Coordinate::readNumber (const String& s, int& i)
- {
- skipWhitespace (s, i);
-
- int start = i;
-
- if (CharacterFunctions::isDigit (s[i]) || s[i] == '.' || s[i] == '-')
- ++i;
-
- while (CharacterFunctions::isDigit (s[i]) || s[i] == '.')
- ++i;
-
- if ((s[i] == 'e' || s[i] == 'E')
- && (CharacterFunctions::isDigit (s[i + 1])
- || s[i + 1] == '-'
- || s[i + 1] == '+'))
- {
- i += 2;
-
- while (CharacterFunctions::isDigit (s[i]))
- ++i;
- }
-
- const double value = s.substring (start, i).getDoubleValue();
-
- while (CharacterFunctions::isWhitespace (s[i]) || s[i] == ',')
- ++i;
-
- return value;
- }
-
- Coordinate::Coordinate (const String& s, bool isHorizontal_)
- : value (0), isProportion (false), isHorizontal (isHorizontal_)
- {
- int i = 0;
-
- anchor1 = readMarkerName (s, i);
-
- if (anchor1.isNotEmpty())
- {
- skipWhitespace (s, i);
-
- if (s[i] == '+')
- value = readNumber (s, ++i);
- else if (s[i] == '-')
- value = -readNumber (s, ++i);
- }
- else
- {
- value = readNumber (s, i);
- skipWhitespace (s, i);
-
- if (s[i] == '%')
- {
- isProportion = true;
- value /= 100.0;
- skipWhitespace (s, ++i);
-
- if (s[i] == '*')
- {
- anchor1 = readMarkerName (s, ++i);
- skipWhitespace (s, i);
-
- if (s[i] == '-' && s[i + 1] == '>')
- {
- i += 2;
- anchor2 = readMarkerName (s, i);
- }
- else
- {
- anchor2 = anchor1;
- anchor1 = getOriginMarkerName();
- }
- }
- else
- {
- anchor1 = getOriginMarkerName();
- anchor2 = getExtentMarkerName();
- }
- }
- }
- }
-
- static const String limitedAccuracyString (const double n)
- {
- return String (n, 3).trimCharactersAtEnd ("0").trimCharactersAtEnd (".");
- }
-
- const String Coordinate::toString() const
- {
- if (isProportion)
- {
- const String percent (limitedAccuracyString (value * 100.0));
-
- if (isOrigin (anchor1))
- {
- if (anchor2 == parentRightMarkerName || anchor2 == parentBottomMarkerName)
- return percent + "%";
- else
- return percent + "% * " + checkName (anchor2);
- }
- else
- return percent + "% * " + checkName (anchor1) + " -> " + checkName (anchor2);
- }
- else
- {
- if (isOrigin (anchor1))
- return limitedAccuracyString (value);
- else if (value > 0)
- return checkName (anchor1) + " + " + limitedAccuracyString (value);
- else if (value < 0)
- return checkName (anchor1) + " - " + limitedAccuracyString (-value);
- else
- return checkName (anchor1);
- }
- }
-
- const double Coordinate::getEditableValue() const
- {
- return isProportion ? value * 100.0 : value;
- }
-
- void Coordinate::setEditableValue (const double newValue)
- {
- value = isProportion ? newValue / 100.0 : newValue;
- }
-
- void Coordinate::toggleProportionality (MarkerResolver& markerResolver)
- {
- const double oldValue = resolve (markerResolver);
-
- isProportion = ! isProportion;
- anchor1 = getOriginMarkerName();
- anchor2 = getExtentMarkerName();
-
- moveToAbsolute (oldValue, markerResolver);
- }
-
- void Coordinate::changeAnchor1 (const String& newMarkerName, MarkerResolver& markerResolver)
- {
- const double oldValue = resolve (markerResolver);
- anchor1 = newMarkerName;
- moveToAbsolute (oldValue, markerResolver);
- }
-
- void Coordinate::changeAnchor2 (const String& newMarkerName, MarkerResolver& markerResolver)
- {
- const double oldValue = resolve (markerResolver);
- anchor2 = newMarkerName;
- moveToAbsolute (oldValue, markerResolver);
- }
-
- //==============================================================================
- RectangleCoordinates::RectangleCoordinates()
- : left (true), right (true), top (false), bottom (false)
- {
- }
-
- RectangleCoordinates::RectangleCoordinates (const Rectangle<int>& rect)
- : left (rect.getX(), true),
- right (rect.getWidth(), "left", true),
- top (rect.getY(), false),
- bottom (rect.getHeight(), "top", false)
- {
- }
-
- RectangleCoordinates::RectangleCoordinates (const String& stringVersion)
- : left (true), right (true), top (false), bottom (false)
- {
- StringArray tokens;
- tokens.addTokens (stringVersion, ",", String::empty);
-
- left = Coordinate (tokens [0], true);
- top = Coordinate (tokens [1], false);
- right = Coordinate (tokens [2], true);
- bottom = Coordinate (tokens [3], false);
- }
-
- bool RectangleCoordinates::isRecursive (Coordinate::MarkerResolver& markerResolver) const
- {
- return left.isRecursive (markerResolver) || right.isRecursive (markerResolver)
- || top.isRecursive (markerResolver) || bottom.isRecursive (markerResolver);
- }
-
- const Rectangle<int> RectangleCoordinates::resolve (Coordinate::MarkerResolver& markerResolver) const
- {
- const int l = roundToInt (left.resolve (markerResolver));
- const int r = roundToInt (right.resolve (markerResolver));
- const int t = roundToInt (top.resolve (markerResolver));
- const int b = roundToInt (bottom.resolve (markerResolver));
-
- return Rectangle<int> (l, t, r - l, b - t);
- }
-
- void RectangleCoordinates::moveToAbsolute (const Rectangle<int>& newPos, Coordinate::MarkerResolver& markerResolver)
- {
- left.moveToAbsolute (newPos.getX(), markerResolver);
- right.moveToAbsolute (newPos.getRight(), markerResolver);
- top.moveToAbsolute (newPos.getY(), markerResolver);
- bottom.moveToAbsolute (newPos.getBottom(), markerResolver);
- }
-
- const String RectangleCoordinates::toString() const
- {
- return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString();
- }
|