|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2015 - ROLI Ltd.
-
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
-
- Details of these licenses can be found 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.juce.com for more information.
-
- ==============================================================================
- */
-
- #pragma once
-
- #include "../ui/jucer_PaintRoutineEditor.h"
- #include "../ui/jucer_ComponentLayoutEditor.h"
-
- //==============================================================================
- /**
- Base class for a property that edits the x, y, w, or h of a PositionedRectangle.
- */
- class PositionPropertyBase : public PropertyComponent,
- protected ChangeListener,
- private ButtonListener
- {
- public:
- enum ComponentPositionDimension
- {
- componentX = 0,
- componentY = 1,
- componentWidth = 2,
- componentHeight = 3
- };
-
- PositionPropertyBase (Component* comp,
- const String& name,
- ComponentPositionDimension dimension_,
- const bool includeAnchorOptions_,
- const bool allowRelativeOptions_,
- ComponentLayout* layout_)
- : PropertyComponent (name),
- layout (layout_),
- button ("mode"),
- component (comp),
- dimension (dimension_),
- includeAnchorOptions (includeAnchorOptions_),
- allowRelativeOptions (allowRelativeOptions_)
- {
- addAndMakeVisible (button);
- button.addListener (this);
- button.setTriggeredOnMouseDown (true);
- button.setConnectedEdges (TextButton::ConnectedOnLeft | TextButton::ConnectedOnRight);
-
- addAndMakeVisible (textEditor = new PositionPropLabel (*this));
- }
-
- String getText() const
- {
- RelativePositionedRectangle rpr (getPosition());
- PositionedRectangle& p = rpr.rect;
- String s;
-
- switch (dimension)
- {
- case componentX:
- if (p.getPositionModeX() == PositionedRectangle::proportionOfParentSize)
- s << valueToString (p.getX() * 100.0) << '%';
- else
- s << valueToString (p.getX());
- break;
-
- case componentY:
- if (p.getPositionModeY() == PositionedRectangle::proportionOfParentSize)
- s << valueToString (p.getY() * 100.0) << '%';
- else
- s << valueToString (p.getY());
- break;
-
- case componentWidth:
- if (p.getWidthMode() == PositionedRectangle::proportionalSize)
- s << valueToString (p.getWidth() * 100.0) << '%';
- else
- s << valueToString (p.getWidth());
- break;
-
- case componentHeight:
- if (p.getHeightMode() == PositionedRectangle::proportionalSize)
- s << valueToString (p.getHeight() * 100.0) << '%';
- else
- s << valueToString (p.getHeight());
- break;
-
- default:
- jassertfalse;
- break;
- };
-
- return s;
- }
-
- static String valueToString (const double n)
- {
- return String (roundToInt (n * 1000.0) / 1000.0);
- }
-
- void setText (const String& newText)
- {
- RelativePositionedRectangle rpr (getPosition());
- PositionedRectangle p (rpr.rect);
- const double value = newText.getDoubleValue();
-
- switch (dimension)
- {
- case componentX:
- if (p.getPositionModeX() == PositionedRectangle::proportionOfParentSize)
- p.setX (value / 100.0);
- else
- p.setX (value);
- break;
-
- case componentY:
- if (p.getPositionModeY() == PositionedRectangle::proportionOfParentSize)
- p.setY (value / 100.0);
- else
- p.setY (value);
- break;
-
- case componentWidth:
- if (p.getWidthMode() == PositionedRectangle::proportionalSize)
- p.setWidth (value / 100.0);
- else
- p.setWidth (value);
- break;
-
- case componentHeight:
- if (p.getHeightMode() == PositionedRectangle::proportionalSize)
- p.setHeight (value / 100.0);
- else
- p.setHeight (value);
- break;
-
- default:
- jassertfalse;
- break;
- };
-
- if (p != rpr.rect)
- {
- rpr.rect = p;
- setPosition (rpr);
- }
- }
-
- void changeListenerCallback (ChangeBroadcaster*)
- {
- refresh();
- }
-
- bool showMenu (ComponentLayout* compLayout)
- {
- RelativePositionedRectangle rpr (getPosition());
- PositionedRectangle p (rpr.rect);
-
- PositionedRectangle::AnchorPoint xAnchor = p.getAnchorPointX();
- PositionedRectangle::AnchorPoint yAnchor = p.getAnchorPointY();
- PositionedRectangle::PositionMode xMode = p.getPositionModeX();
- PositionedRectangle::PositionMode yMode = p.getPositionModeY();
- PositionedRectangle::SizeMode sizeW = p.getWidthMode();
- PositionedRectangle::SizeMode sizeH = p.getHeightMode();
-
- String relCompName ("parent");
-
- if (Component* const relComp = compLayout != nullptr ? compLayout->getComponentRelativePosTarget (component, (int) dimension)
- : nullptr)
- relCompName = compLayout->getComponentMemberVariableName (relComp);
-
- jassert (relCompName.isNotEmpty());
-
- PopupMenu m;
-
- if (dimension == componentX || dimension == componentY)
- {
- const PositionedRectangle::PositionMode posMode = (dimension == componentX) ? xMode : yMode;
-
- m.addItem (10, ((dimension == componentX) ? "Absolute distance from left of "
- : "Absolute distance from top of ") + relCompName,
- true, posMode == PositionedRectangle::absoluteFromParentTopLeft);
-
- m.addItem (11, ((dimension == componentX) ? "Absolute distance from right of "
- : "Absolute distance from bottom of ") + relCompName,
- true, posMode == PositionedRectangle::absoluteFromParentBottomRight);
-
- m.addItem (12, "Absolute distance from centre of " + relCompName,
- true, posMode == PositionedRectangle::absoluteFromParentCentre);
-
- m.addItem (13, ((dimension == componentX) ? "Percentage of width of "
- : "Percentage of height of ") + relCompName,
- true, posMode == PositionedRectangle::proportionOfParentSize);
-
- m.addSeparator();
-
- if (includeAnchorOptions)
- {
- const PositionedRectangle::AnchorPoint anchor = (dimension == componentX) ? xAnchor : yAnchor;
-
- m.addItem (14, (dimension == componentX) ? "Anchored at left of component"
- : "Anchored at top of component",
- true, anchor == PositionedRectangle::anchorAtLeftOrTop);
-
- m.addItem (15, "Anchored at centre of component", true, anchor == PositionedRectangle::anchorAtCentre);
-
- m.addItem (16, (dimension == componentX) ? "Anchored at right of component"
- : "Anchored at bottom of component",
- true, anchor == PositionedRectangle::anchorAtRightOrBottom);
- }
- }
- else
- {
- const PositionedRectangle::SizeMode sizeMode = (dimension == componentWidth) ? sizeW : sizeH;
-
- m.addItem (20, (dimension == componentWidth) ? "Absolute width"
- : "Absolute height",
- true, sizeMode == PositionedRectangle::absoluteSize);
-
- m.addItem (21, ((dimension == componentWidth) ? "Percentage of width of "
- : "Percentage of height of ") + relCompName,
- true, sizeMode == PositionedRectangle::proportionalSize);
-
- m.addItem (22, ((dimension == componentWidth) ? "Subtracted from width of "
- : "Subtracted from height of ") + relCompName,
- true, sizeMode == PositionedRectangle::parentSizeMinusAbsolute);
- }
-
-
- if (allowRelativeOptions && compLayout != nullptr)
- {
- m.addSeparator();
- m.addSubMenu ("Relative to", compLayout->getRelativeTargetMenu (component, (int) dimension));
- }
-
- WeakReference<Component> ref (this);
-
- const int menuResult = m.showAt (&button);
-
- if (menuResult == 0 || ref == nullptr)
- return false;
-
- switch (menuResult)
- {
- case 10:
- if (dimension == componentX)
- xMode = PositionedRectangle::absoluteFromParentTopLeft;
- else
- yMode = PositionedRectangle::absoluteFromParentTopLeft;
- break;
-
- case 11:
- if (dimension == componentX)
- xMode = PositionedRectangle::absoluteFromParentBottomRight;
- else
- yMode = PositionedRectangle::absoluteFromParentBottomRight;
- break;
-
- case 12:
- if (dimension == componentX)
- xMode = PositionedRectangle::absoluteFromParentCentre;
- else
- yMode = PositionedRectangle::absoluteFromParentCentre;
- break;
-
- case 13:
- if (dimension == componentX)
- xMode = PositionedRectangle::proportionOfParentSize;
- else
- yMode = PositionedRectangle::proportionOfParentSize;
- break;
-
- case 14:
- if (dimension == componentX)
- xAnchor = PositionedRectangle::anchorAtLeftOrTop;
- else
- yAnchor = PositionedRectangle::anchorAtLeftOrTop;
- break;
-
- case 15:
- if (dimension == componentX)
- xAnchor = PositionedRectangle::anchorAtCentre;
- else
- yAnchor = PositionedRectangle::anchorAtCentre;
- break;
-
- case 16:
- if (dimension == componentX)
- xAnchor = PositionedRectangle::anchorAtRightOrBottom;
- else
- yAnchor = PositionedRectangle::anchorAtRightOrBottom;
- break;
-
- case 20:
- if (dimension == componentWidth)
- sizeW = PositionedRectangle::absoluteSize;
- else
- sizeH = PositionedRectangle::absoluteSize;
- break;
-
- case 21:
- if (dimension == componentWidth)
- sizeW = PositionedRectangle::proportionalSize;
- else
- sizeH = PositionedRectangle::proportionalSize;
- break;
-
- case 22:
- if (dimension == componentWidth)
- sizeW = PositionedRectangle::parentSizeMinusAbsolute;
- else
- sizeH = PositionedRectangle::parentSizeMinusAbsolute;
- break;
-
- default:
- if (allowRelativeOptions && compLayout != nullptr)
- compLayout->processRelativeTargetMenuResult (component, (int) dimension, menuResult);
- break;
- }
-
- Rectangle<int> parentArea;
-
- if (component->findParentComponentOfClass<ComponentLayoutEditor>() != 0)
- parentArea.setSize (component->getParentWidth(), component->getParentHeight());
- else if (PaintRoutineEditor* pre = dynamic_cast<PaintRoutineEditor*> (component->getParentComponent()))
- parentArea = pre->getComponentArea();
- else
- jassertfalse;
-
- int x, xw, y, yh, w, h;
- rpr.getRelativeTargetBounds (parentArea, compLayout, x, xw, y, yh, w, h);
-
- PositionedRectangle xyRect (p);
- PositionedRectangle whRect (p);
-
- xyRect.setModes (xAnchor, xMode, yAnchor, yMode, sizeW, sizeH,
- Rectangle<int> (x, y, xw, yh));
-
- whRect.setModes (xAnchor, xMode, yAnchor, yMode, sizeW, sizeH,
- Rectangle<int> (x, y, w, h));
-
- p.setModes (xAnchor, xMode, yAnchor, yMode, sizeW, sizeH,
- Rectangle<int> (x, y, xw, yh));
-
- p.setX (xyRect.getX());
- p.setY (xyRect.getY());
- p.setWidth (whRect.getWidth());
- p.setHeight (whRect.getHeight());
-
- if (p != rpr.rect)
- {
- rpr.rect = p;
- setPosition (rpr);
- }
-
- return true;
- }
-
- void resized()
- {
- const Rectangle<int> r (getLookAndFeel().getPropertyComponentContentPosition (*this));
-
- button.changeWidthToFitText (r.getHeight());
- button.setTopRightPosition (r.getRight(), r.getY());
-
- textEditor->setBounds (r.getX(), r.getY(), button.getX() - r.getX(), r.getHeight());
- }
-
- void refresh()
- {
- textEditor->setText (getText(), dontSendNotification);
- }
-
- void buttonClicked (Button*)
- {
- if (showMenu (layout))
- refresh(); // (to clear the text editor if it's got focus)
- }
-
- void textWasEdited()
- {
- const String newText (textEditor->getText());
- if (getText() != newText)
- setText (newText);
- }
-
- //==============================================================================
- virtual void setPosition (const RelativePositionedRectangle& newPos) = 0;
-
- virtual RelativePositionedRectangle getPosition() const = 0;
-
- protected:
- class PositionPropLabel : public Label
- {
- PositionPropertyBase& owner;
-
- public:
- PositionPropLabel (PositionPropertyBase& owner_)
- : Label (String(), String()),
- owner (owner_)
- {
- setEditable (true, true, false);
-
- setColour (backgroundColourId, Colours::white);
- setColour (textColourId, Colours::black);
- setColour (outlineColourId, findColour (ComboBox::outlineColourId));
-
- setColour (TextEditor::textColourId, Colours::black);
- setColour (TextEditor::backgroundColourId, Colours::white);
- setColour (TextEditor::outlineColourId, findColour (ComboBox::outlineColourId));
- }
-
- TextEditor* createEditorComponent()
- {
- TextEditor* ed = Label::createEditorComponent();
- ed->setInputRestrictions (14, "0123456789.-%");
-
- return ed;
- }
-
- void textWasEdited()
- {
- owner.textWasEdited();
- }
- };
-
- ComponentLayout* layout;
- ScopedPointer<PositionPropLabel> textEditor;
- TextButton button;
-
- Component* component;
- ComponentPositionDimension dimension;
- const bool includeAnchorOptions, allowRelativeOptions;
- };
|