|
- /*
- ==============================================================================
-
- 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.
-
- ==============================================================================
- */
-
- #include "../Application/jucer_Headers.h"
- #include "jucer_JucerDocument.h"
- #include "jucer_ObjectTypes.h"
- #include "UI/jucer_JucerDocumentEditor.h"
- #include "Components/jucer_ComponentUndoableAction.h"
-
- //==============================================================================
- ComponentLayout::ComponentLayout()
- : document (nullptr),
- nextCompUID (1)
- {
- }
-
- ComponentLayout::~ComponentLayout()
- {
- components.clear();
- }
-
- //==============================================================================
- void ComponentLayout::changed()
- {
- if (document != nullptr)
- document->changed();
- }
-
- void ComponentLayout::perform (std::unique_ptr<UndoableAction> action, const String& actionName)
- {
- jassert (document != nullptr);
-
- if (document != nullptr)
- document->getUndoManager().perform (action.release(), actionName);
- else
- action->perform();
- }
-
- //==============================================================================
- void ComponentLayout::clearComponents()
- {
- selected.deselectAll();
- selected.dispatchPendingMessages();
- components.clear();
- changed();
- }
-
- //==============================================================================
- class AddCompAction : public UndoableAction
- {
- public:
- AddCompAction (XmlElement* const xml_, ComponentLayout& layout_, int& index)
- : indexRef (index),
- xml (xml_),
- layout (layout_)
- {
- }
-
- bool perform()
- {
- showCorrectTab();
- Component* const newComp = layout.addComponentFromXml (*xml, false);
- jassert (newComp != nullptr);
-
- indexRef = layout.indexOfComponent (newComp);
- jassert (indexRef >= 0);
- return indexRef >= 0;
- }
-
- bool undo()
- {
- showCorrectTab();
- layout.removeComponent (layout.getComponent (indexRef), false);
- return true;
- }
-
- int getSizeInUnits() { return 10; }
-
- int& indexRef;
-
- private:
- std::unique_ptr<XmlElement> xml;
- ComponentLayout& layout;
-
- static void showCorrectTab()
- {
- if (JucerDocumentEditor* const ed = JucerDocumentEditor::getActiveDocumentHolder())
- ed->showLayout();
- }
-
- AddCompAction (const AddCompAction&);
- AddCompAction& operator= (const AddCompAction&);
- };
-
- //==============================================================================
- class DeleteCompAction : public ComponentUndoableAction <Component>
- {
- public:
- DeleteCompAction (Component* const comp, ComponentLayout& l)
- : ComponentUndoableAction <Component> (comp, l),
- oldIndex (-1)
- {
- if (ComponentTypeHandler* const h = ComponentTypeHandler::getHandlerFor (*comp))
- xml.reset (h->createXmlFor (comp, &layout));
- else
- jassertfalse;
-
- oldIndex = l.indexOfComponent (comp);
- }
-
- bool perform()
- {
- showCorrectTab();
- layout.removeComponent (getComponent(), false);
- return true;
- }
-
- bool undo()
- {
- Component* c = layout.addComponentFromXml (*xml, false);
- jassert (c != nullptr);
-
- layout.moveComponentZOrder (layout.indexOfComponent (c), oldIndex);
-
- showCorrectTab();
- return c != nullptr;
- }
-
- private:
- std::unique_ptr<XmlElement> xml;
- int oldIndex;
- };
-
- void ComponentLayout::removeComponent (Component* comp, const bool undoable)
- {
- if (comp != nullptr && components.contains (comp))
- {
- if (undoable)
- {
- perform (std::make_unique<DeleteCompAction> (comp, *this), "Delete components");
- }
- else
- {
- selected.deselect (comp);
- selected.changed (true); // synchronous message to get rid of any property components
-
- components.removeObject (comp);
- changed();
- }
- }
- }
-
- //==============================================================================
- class FrontBackCompAction : public ComponentUndoableAction <Component>
- {
- public:
- FrontBackCompAction (Component* const comp, ComponentLayout& l, int newIndex_)
- : ComponentUndoableAction <Component> (comp, l),
- newIndex (newIndex_)
- {
- oldIndex = l.indexOfComponent (comp);
- }
-
- bool perform()
- {
- showCorrectTab();
- Component* comp = layout.getComponent (oldIndex);
- layout.moveComponentZOrder (oldIndex, newIndex);
- newIndex = layout.indexOfComponent (comp);
- return true;
- }
-
- bool undo()
- {
- showCorrectTab();
- layout.moveComponentZOrder (newIndex, oldIndex);
- return true;
- }
-
- private:
- int newIndex, oldIndex;
- };
-
- void ComponentLayout::moveComponentZOrder (int oldIndex, int newIndex)
- {
- jassert (components [oldIndex] != nullptr);
-
- if (oldIndex != newIndex && components [oldIndex] != nullptr)
- {
- components.move (oldIndex, newIndex);
- changed();
- }
- }
-
- void ComponentLayout::componentToFront (Component* comp, const bool undoable)
- {
- if (comp != nullptr && components.contains (comp))
- {
- if (undoable)
- perform (std::make_unique<FrontBackCompAction> (comp, *this, -1), "Move components to front");
- else
- moveComponentZOrder (components.indexOf (comp), -1);
- }
- }
-
- void ComponentLayout::componentToBack (Component* comp, const bool undoable)
- {
- if (comp != nullptr && components.contains (comp))
- {
- if (undoable)
- perform (std::make_unique<FrontBackCompAction> (comp, *this, 0), "Move components to back");
- else
- moveComponentZOrder (components.indexOf (comp), 0);
- }
- }
-
- //==============================================================================
- const char* const ComponentLayout::clipboardXmlTag = "COMPONENTS";
-
- void ComponentLayout::copySelectedToClipboard()
- {
- if (selected.getNumSelected() == 0)
- return;
-
- XmlElement clip (clipboardXmlTag);
-
- for (int i = 0; i < components.size(); ++i)
- {
- auto c = components.getUnchecked (i);
-
- if (selected.isSelected (c))
- {
- if (auto type = ComponentTypeHandler::getHandlerFor (*c))
- {
- auto e = type->createXmlFor (c, this);
- clip.addChildElement (e);
- }
- }
- }
-
- SystemClipboard::copyTextToClipboard (clip.toString());
- }
-
- void ComponentLayout::paste()
- {
- if (auto doc = parseXMLIfTagMatches (SystemClipboard::getTextFromClipboard(), clipboardXmlTag))
- {
- selected.deselectAll();
-
- for (auto* e : doc->getChildIterator())
- if (Component* newComp = addComponentFromXml (*e, true))
- selected.addToSelection (newComp);
-
- startDragging();
- dragSelectedComps (Random::getSystemRandom().nextInt (40),
- Random::getSystemRandom().nextInt (40));
- endDragging();
- }
- }
-
- void ComponentLayout::deleteSelected()
- {
- const SelectedItemSet <Component*> temp (selected);
- selected.deselectAll();
- selected.changed (true); // synchronous message to get rid of any property components
-
- if (temp.getNumSelected() > 0)
- {
- for (int i = temp.getNumSelected(); --i >= 0;)
- removeComponent (temp.getSelectedItem (i), true);
-
- changed();
-
- if (document != nullptr)
- document->dispatchPendingMessages(); // forces the change to propagate before a paint() callback can happen,
- // in case there are components floating around that are now dangling pointers
- }
- }
-
- void ComponentLayout::selectAll()
- {
- for (int i = 0; i < components.size(); ++i)
- selected.addToSelection (components.getUnchecked (i));
- }
-
- void ComponentLayout::selectedToFront()
- {
- const SelectedItemSet <Component*> temp (selected);
-
- for (int i = temp.getNumSelected(); --i >= 0;)
- componentToFront (temp.getSelectedItem (i), true);
- }
-
- void ComponentLayout::selectedToBack()
- {
- const SelectedItemSet <Component*> temp (selected);
-
- for (int i = 0; i < temp.getNumSelected(); ++i)
- componentToBack (temp.getSelectedItem (i), true);
- }
-
- void ComponentLayout::alignTop()
- {
- if (selected.getNumSelected() > 1)
- {
- auto* main = selected.getSelectedItem (0);
- auto yPos = main->getY();
-
- for (auto* other : selected)
- {
- if (other != main)
- setComponentBoundsAndProperties (other,
- other->getBounds().withPosition (other->getX(), yPos),
- main, true);
- }
- }
- }
-
- void ComponentLayout::alignRight()
- {
- if (selected.getNumSelected() > 1)
- {
- auto* main = selected.getSelectedItem (0);
- auto rightPos = main->getRight();
-
- for (auto* other : selected)
- {
- if (other != main)
- setComponentBoundsAndProperties (other, other->getBounds().withPosition (rightPos - other->getWidth(), other->getY()), main, true);
- }
- }
- }
-
- void ComponentLayout::alignBottom()
- {
- if (selected.getNumSelected() > 1)
- {
- auto* main = selected.getSelectedItem (0);
- auto bottomPos = main->getBottom();
-
- for (auto* other : selected)
- {
- if (other != main)
- setComponentBoundsAndProperties (other, other->getBounds().withPosition (other->getX(), bottomPos - other->getHeight()), main, true);
- }
- }
- }
-
- void ComponentLayout::alignLeft()
- {
- if (selected.getNumSelected() > 1)
- {
- auto* main = selected.getSelectedItem (0);
- auto xPos = main->getX();
-
- for (auto* other : selected)
- {
- if (other != main)
- setComponentBoundsAndProperties (other, other->getBounds().withPosition (xPos, other->getY()), main, true);
- }
- }
- }
-
- void ComponentLayout::bringLostItemsBackOnScreen (int width, int height)
- {
- for (int i = components.size(); --i >= 0;)
- {
- Component* const c = components[i];
-
- if (! c->getBounds().intersects (Rectangle<int> (0, 0, width, height)))
- {
- c->setTopLeftPosition (width / 2, height / 2);
- updateStoredComponentPosition (c, false);
- }
- }
- }
-
- Component* ComponentLayout::addNewComponent (ComponentTypeHandler* const type, int x, int y)
- {
- std::unique_ptr<Component> c (type->createNewComponent (getDocument()));
- jassert (c != nullptr);
-
- if (c != nullptr)
- {
- c->setSize (type->getDefaultWidth(), type->getDefaultHeight());
- c->setCentrePosition (x, y);
- updateStoredComponentPosition (c.get(), false);
-
- c->getProperties().set ("id", nextCompUID++);
-
- std::unique_ptr<XmlElement> xml (type->createXmlFor (c.get(), this));
- c.reset (addComponentFromXml (*xml, true));
-
- String memberName (build_tools::makeValidIdentifier (type->getClassName (c.get()), true, true, false));
- setComponentMemberVariableName (c.get(), memberName);
-
- selected.selectOnly (c.get());
- }
-
- return c.release();
- }
-
-
- Component* ComponentLayout::addComponentFromXml (const XmlElement& xml, const bool undoable)
- {
- if (undoable)
- {
- perform (std::make_unique<AddCompAction> (new XmlElement (xml), *this, addComponentIndexAdded), "Add new components");
- return components [addComponentIndexAdded];
- }
-
- if (ComponentTypeHandler* const type
- = ComponentTypeHandler::getHandlerForXmlTag (xml.getTagName()))
- {
- std::unique_ptr<Component> newComp (type->createNewComponent (getDocument()));
-
- if (type->restoreFromXml (xml, newComp.get(), this))
- {
- // ensure that the new comp's name is unique
- setComponentMemberVariableName (newComp.get(), getComponentMemberVariableName (newComp.get()));
-
- // check for duped IDs..
- while (findComponentWithId (ComponentTypeHandler::getComponentId (newComp.get())) != nullptr)
- ComponentTypeHandler::setComponentId (newComp.get(), Random::getSystemRandom().nextInt64());
-
- components.add (newComp.get());
- changed();
- return newComp.release();
- }
- }
-
- return nullptr;
- }
-
- Component* ComponentLayout::findComponentWithId (const int64 componentId) const
- {
- for (int i = 0; i < components.size(); ++i)
- if (ComponentTypeHandler::getComponentId (components.getUnchecked (i)) == componentId)
- return components.getUnchecked (i);
-
- return nullptr;
- }
-
- //==============================================================================
- static const char* const dimensionSuffixes[] = { "X", "Y", "W", "H" };
-
- Component* ComponentLayout::getComponentRelativePosTarget (Component* comp, int whichDimension) const
- {
- jassert (comp != nullptr);
-
- if (PaintElement* const pe = dynamic_cast<PaintElement*> (comp))
- {
- int64 compId;
-
- if (whichDimension == 0) compId = pe->getPosition().relativeToX;
- else if (whichDimension == 1) compId = pe->getPosition().relativeToY;
- else if (whichDimension == 2) compId = pe->getPosition().relativeToW;
- else compId = pe->getPosition().relativeToH;
-
- return findComponentWithId (compId);
- }
-
- return findComponentWithId (comp->getProperties() [String ("relativeTo") + dimensionSuffixes [whichDimension]]
- .toString().getHexValue64());
- }
-
- void ComponentLayout::setComponentRelativeTarget (Component* comp, int whichDimension, Component* compToBeRelativeTo)
- {
- PaintElement* const pe = dynamic_cast<PaintElement*> (comp);
-
- jassert (comp != nullptr);
- jassert (pe != nullptr || components.contains (comp));
- jassert (compToBeRelativeTo == nullptr || components.contains (compToBeRelativeTo));
- jassert (compToBeRelativeTo == nullptr || ! dependsOnComponentForRelativePos (compToBeRelativeTo, comp));
-
- if (compToBeRelativeTo != getComponentRelativePosTarget (comp, whichDimension)
- && (compToBeRelativeTo == nullptr || ! dependsOnComponentForRelativePos (compToBeRelativeTo, comp)))
- {
- const int64 compId = ComponentTypeHandler::getComponentId (compToBeRelativeTo);
-
- Rectangle<int> oldBounds (comp->getBounds());
- RelativePositionedRectangle pos;
-
- if (pe != nullptr)
- {
- oldBounds = pe->getCurrentBounds (dynamic_cast<PaintRoutineEditor*> (pe->getParentComponent())->getComponentArea());
- pos = pe->getPosition();
- }
- else
- {
- pos = ComponentTypeHandler::getComponentPosition (comp);
- }
-
- if (whichDimension == 0) pos.relativeToX = compId;
- else if (whichDimension == 1) pos.relativeToY = compId;
- else if (whichDimension == 2) pos.relativeToW = compId;
- else if (whichDimension == 3) pos.relativeToH = compId;
-
- if (pe != nullptr)
- {
- pe->setPosition (pos, true);
- pe->setCurrentBounds (oldBounds, dynamic_cast<PaintRoutineEditor*> (pe->getParentComponent())->getComponentArea(), true);
- }
- else
- {
- setComponentPosition (comp, pos, true);
- comp->setBounds (oldBounds);
- updateStoredComponentPosition (comp, false);
- }
-
- changed();
- }
- }
-
- bool ComponentLayout::dependsOnComponentForRelativePos (Component* comp, Component* possibleDependee) const
- {
- for (int i = 0; i < 4; ++i)
- if (Component* const c = getComponentRelativePosTarget (comp, i))
- if (c == possibleDependee || dependsOnComponentForRelativePos (c, possibleDependee))
- return true;
-
- return false;
- }
-
- bool ComponentLayout::isComponentPositionRelative (Component* comp) const
- {
- for (int i = 0; i < getNumComponents(); ++i)
- if (dependsOnComponentForRelativePos (comp, getComponent (i)))
- return true;
-
- return false;
- }
-
- const int menuIdBase = 0x63240000;
-
- PopupMenu ComponentLayout::getRelativeTargetMenu (Component* comp, int whichDimension) const
- {
- PopupMenu m;
-
- auto current = getComponentRelativePosTarget (comp, whichDimension);
-
- m.addItem (menuIdBase, "Relative to parent component", true, current == nullptr);
- m.addSeparator();
-
- for (int i = 0; i < components.size(); ++i)
- {
- auto* const c = components.getUnchecked (i);
-
- if (c != nullptr && c != comp)
- m.addItem (menuIdBase + i + 1,
- "Relative to " + getComponentMemberVariableName (c)
- + " (class: " + ComponentTypeHandler::getHandlerFor (*c)->getClassName (c) + ")",
- ! dependsOnComponentForRelativePos (c, comp),
- current == c);
- }
-
- return m;
- }
-
- void ComponentLayout::processRelativeTargetMenuResult (Component* comp, int whichDimension, int menuResultID)
- {
- if (menuResultID != 0)
- {
- Component* const newTarget = components [menuResultID - menuIdBase - 1];
- setComponentRelativeTarget (comp, whichDimension, newTarget);
- }
- }
-
- //==============================================================================
- class ChangeCompPositionAction : public ComponentUndoableAction <Component>
- {
- public:
- ChangeCompPositionAction (Component* const comp, ComponentLayout& l,
- const RelativePositionedRectangle& newPos_)
- : ComponentUndoableAction <Component> (comp, l),
- newPos (newPos_), oldPos (ComponentTypeHandler::getComponentPosition (comp))
- {
- }
-
- bool perform()
- {
- showCorrectTab();
- layout.setComponentPosition (getComponent(), newPos, false);
- return true;
- }
-
- bool undo()
- {
- showCorrectTab();
- layout.setComponentPosition (getComponent(), oldPos, false);
- return true;
- }
-
- private:
- RelativePositionedRectangle newPos, oldPos;
- };
-
- class ChangeCompBoundsAndPropertiesAction : public ComponentUndoableAction<Component>
- {
- public:
- ChangeCompBoundsAndPropertiesAction (Component* const comp, ComponentLayout& l,
- const Rectangle<int>& bounds, const NamedValueSet& props)
- : ComponentUndoableAction <Component> (comp, l),
- newBounds (bounds),
- oldBounds (comp->getBounds()),
- newProps (props),
- oldProps (comp->getProperties())
- {
- }
-
- bool perform()
- {
- showCorrectTab();
- getComponent()->setBounds (newBounds);
- getComponent()->getProperties() = newProps;
- layout.updateStoredComponentPosition (getComponent(), false);
- return true;
- }
-
- bool undo()
- {
- showCorrectTab();
- getComponent()->setBounds (oldBounds);
- getComponent()->getProperties() = oldProps;
- layout.updateStoredComponentPosition (getComponent(), false);
- return true;
- }
-
- private:
- Rectangle<int> newBounds, oldBounds;
- NamedValueSet newProps, oldProps;
- };
-
- void ComponentLayout::setComponentPosition (Component* comp,
- const RelativePositionedRectangle& newPos,
- const bool undoable)
- {
- if (ComponentTypeHandler::getComponentPosition (comp) != newPos)
- {
- if (undoable)
- {
- perform (std::make_unique<ChangeCompPositionAction> (comp, *this, newPos), "Move components");
- }
- else
- {
- ComponentTypeHandler::setComponentPosition (comp, newPos, this);
- changed();
- }
- }
- }
-
- void ComponentLayout::setComponentBoundsAndProperties (Component* componentToPosition, const Rectangle<int>& newBounds,
- Component* referenceComponent, const bool undoable)
- {
- auto props = NamedValueSet (componentToPosition->getProperties());
-
- auto rect = ComponentTypeHandler::getComponentPosition (componentToPosition).rect;
- auto referenceComponentPosition = ComponentTypeHandler::getComponentPosition (referenceComponent);
- auto referenceComponentRect = referenceComponentPosition.rect;
-
- rect.setModes (referenceComponentRect.getAnchorPointX(), referenceComponentRect.getPositionModeX(),
- referenceComponentRect.getAnchorPointY(), referenceComponentRect.getPositionModeY(),
- referenceComponentRect.getWidthMode(), referenceComponentRect.getHeightMode(),
- componentToPosition->getBounds());
-
- props.set ("pos", rect.toString());
- props.set ("relativeToX", String::toHexString (referenceComponentPosition.relativeToX));
- props.set ("relativeToY", String::toHexString (referenceComponentPosition.relativeToY));
- props.set ("relativeToW", String::toHexString (referenceComponentPosition.relativeToW));
- props.set ("relativeToH", String::toHexString (referenceComponentPosition.relativeToH));
-
- if (componentToPosition->getBounds() != newBounds || componentToPosition->getProperties() != props)
- {
- if (undoable)
- {
- perform (std::make_unique<ChangeCompBoundsAndPropertiesAction> (componentToPosition, *this, newBounds, props), "Change component bounds");
- }
- else
- {
- componentToPosition->setBounds (newBounds);
- componentToPosition->getProperties() = props;
- updateStoredComponentPosition (componentToPosition, false);
- changed();
- }
- }
- }
-
- void ComponentLayout::updateStoredComponentPosition (Component* comp, const bool undoable)
- {
- RelativePositionedRectangle newPos (ComponentTypeHandler::getComponentPosition (comp));
-
- newPos.updateFromComponent (*comp, this);
-
- setComponentPosition (comp, newPos, undoable);
- }
-
- //==============================================================================
- void ComponentLayout::startDragging()
- {
- for (int i = 0; i < components.size(); ++i)
- {
- Component* const c = components[i];
- c->getProperties().set ("xDragStart", c->getX());
- c->getProperties().set ("yDragStart", c->getY());
- }
-
- jassert (document != nullptr);
- document->beginTransaction();
- }
-
- void ComponentLayout::dragSelectedComps (int dx, int dy, const bool allowSnap)
- {
- if (allowSnap && document != nullptr && selected.getNumSelected() > 1)
- {
- dx = document->snapPosition (dx);
- dy = document->snapPosition (dy);
- }
-
- for (int i = 0; i < selected.getNumSelected(); ++i)
- {
- Component* const c = selected.getSelectedItem (i);
-
- const int startX = c->getProperties() ["xDragStart"];
- const int startY = c->getProperties() ["yDragStart"];
-
- if (allowSnap && document != nullptr && selected.getNumSelected() == 1)
- {
- c->setTopLeftPosition (document->snapPosition (startX + dx),
- document->snapPosition (startY + dy));
- }
- else
- {
- c->setTopLeftPosition (startX + dx,
- startY + dy);
- }
-
- updateStoredComponentPosition (c, false);
- }
- }
-
- void ComponentLayout::endDragging()
- {
- // after the drag, roll back all the comps to their start position, then
- // back to their finish positions using an undoable command.
- document->beginTransaction();
-
- for (int i = 0; i < selected.getNumSelected(); ++i)
- {
- Component* const c = selected.getSelectedItem (i);
-
- const int newX = c->getX();
- const int newY = c->getY();
-
- const int startX = c->getProperties() ["xDragStart"];
- const int startY = c->getProperties() ["yDragStart"];
-
- c->setTopLeftPosition (startX, startY);
- updateStoredComponentPosition (c, false);
-
- c->setTopLeftPosition (newX, newY);
- updateStoredComponentPosition (c, true);
- }
-
- document->beginTransaction();
- }
-
- void ComponentLayout::moveSelectedComps (int dx, int dy, bool snap)
- {
- startDragging();
- dragSelectedComps (dx, dy, snap);
- endDragging();
- }
-
- void ComponentLayout::stretchSelectedComps (int dw, int dh, bool allowSnap)
- {
- int neww, newh;
-
- if (document != nullptr && selected.getNumSelected() == 1)
- {
- Component* const c = selected.getSelectedItem (0);
-
- if (allowSnap)
- {
- int bot = c->getBottom() + dh;
- int right = c->getRight() + dw;
- bot = (dh != 0) ? document->snapPosition (bot) : bot;
- right = (dw != 0) ? document->snapPosition (right) : right;
- newh = bot - c->getY();
- neww = right - c->getX();
- }
- else
- {
- newh = c->getHeight() + dh;
- neww = c->getWidth() + dw;
- }
-
- c->setSize (neww, newh);
-
- updateStoredComponentPosition (c, true);
- }
- else
- {
- for (int i = 0; i < selected.getNumSelected(); ++i)
- {
- Component* const c = selected.getSelectedItem (i);
-
- neww = c->getWidth() + dw;
- newh = c->getHeight() + dh;
- c->setSize (neww, newh);
-
- updateStoredComponentPosition (c, true);
- }
- }
- }
-
- //==============================================================================
- void ComponentLayout::fillInGeneratedCode (GeneratedCode& code) const
- {
- for (int i = 0; i < components.size(); ++i)
- if (Component* const comp = components.getUnchecked (i))
- if (ComponentTypeHandler* const type = ComponentTypeHandler::getHandlerFor (*comp))
- type->fillInGeneratedCode (comp, code);
- }
-
- //==============================================================================
- String ComponentLayout::getComponentMemberVariableName (Component* comp) const
- {
- if (comp == nullptr)
- return {};
-
- String name (comp->getProperties() ["memberName"].toString());
-
- if (name.isEmpty())
- name = getUnusedMemberName (build_tools::makeValidIdentifier (comp->getName(), true, true, false), comp);
-
- return name;
- }
-
- void ComponentLayout::setComponentMemberVariableName (Component* comp, const String& newName)
- {
- jassert (comp != nullptr);
- const String oldName (getComponentMemberVariableName (comp));
-
- comp->getProperties().set ("memberName", String());
-
- const String n (getUnusedMemberName (build_tools::makeValidIdentifier (newName, false, true, false), comp));
- comp->getProperties().set ("memberName", n);
-
- if (n != oldName)
- changed();
- }
-
- String ComponentLayout::getUnusedMemberName (String nameRoot, Component* comp) const
- {
- String n (nameRoot);
-
- while (CharacterFunctions::isDigit (nameRoot.getLastCharacter()))
- nameRoot = nameRoot.dropLastCharacters (1);
-
- int suffix = 2;
-
- for (;;)
- {
- bool alreadyUsed = false;
-
- for (int i = 0; i < components.size(); ++i)
- {
- if (components[i] != comp
- && components[i]->getProperties() ["memberName"] == n)
- {
- alreadyUsed = true;
- break;
- }
- }
-
- if (! alreadyUsed)
- break;
-
- n = nameRoot + String (suffix++);
- }
-
- return n;
- }
-
- //==============================================================================
- String ComponentLayout::getComponentVirtualClassName (Component* comp) const
- {
- if (comp == nullptr)
- return {};
-
- return comp->getProperties() ["virtualName"];
- }
-
- void ComponentLayout::setComponentVirtualClassName (Component* comp, const String& newName)
- {
- jassert (comp != nullptr);
- const String name (build_tools::makeValidIdentifier (newName, false, false, true));
-
- if (name != getComponentVirtualClassName (comp))
- {
- comp->getProperties().set ("virtualName", name);
- changed();
- }
- }
-
- //==============================================================================
- void ComponentLayout::addToXml (XmlElement& xml) const
- {
- for (int i = 0; i < components.size(); ++i)
- if (ComponentTypeHandler* h = ComponentTypeHandler::getHandlerFor (*components [i]))
- xml.addChildElement (h->createXmlFor (components [i], this));
- }
-
- static String bracketIfNeeded (const String& s)
- {
- return s.containsAnyOf ("+-*/%") ? "(" + s + ")" : s;
- }
-
- //==============================================================================
- void positionToCode (const RelativePositionedRectangle& position,
- const ComponentLayout* layout,
- String& x, String& y, String& w, String& h)
- {
- // these are the code sections for the positions of the relative comps
- String xrx, xry, xrw, xrh;
- if (Component* const relCompX = layout != nullptr ? layout->findComponentWithId (position.relativeToX) : nullptr)
- positionToCode (ComponentTypeHandler::getComponentPosition (relCompX), layout, xrx, xry, xrw, xrh);
-
- String yrx, yry, yrw, yrh;
-
- if (Component* const relCompY = layout != nullptr ? layout->findComponentWithId (position.relativeToY) : nullptr)
- positionToCode (ComponentTypeHandler::getComponentPosition (relCompY), layout, yrx, yry, yrw, yrh);
-
- String wrx, wry, wrw, wrh;
-
- if (Component* const relCompW = (layout != nullptr && position.rect.getWidthMode() != PositionedRectangle::absoluteSize)
- ? layout->findComponentWithId (position.relativeToW) : nullptr)
- positionToCode (ComponentTypeHandler::getComponentPosition (relCompW), layout, wrx, wry, wrw, wrh);
-
- String hrx, hry, hrw, hrh;
-
- if (Component* const relCompH = (layout != nullptr && position.rect.getHeightMode() != PositionedRectangle::absoluteSize)
- ? layout->findComponentWithId (position.relativeToH) : nullptr)
- positionToCode (ComponentTypeHandler::getComponentPosition (relCompH), layout, hrx, hry, hrw, hrh);
-
- // width
- if (position.rect.getWidthMode() == PositionedRectangle::proportionalSize)
- {
- if (wrw.isNotEmpty())
- w << "juce::roundToInt (" << bracketIfNeeded (wrw) << " * " << CodeHelpers::floatLiteral (position.rect.getWidth(), 4) << ")";
- else
- w << "proportionOfWidth (" << CodeHelpers::floatLiteral (position.rect.getWidth(), 4) << ")";
- }
- else if (position.rect.getWidthMode() == PositionedRectangle::parentSizeMinusAbsolute)
- {
- if (wrw.isNotEmpty())
- w << bracketIfNeeded (wrw) << " - " << roundToInt (position.rect.getWidth());
- else
- w << "getWidth() - " << roundToInt (position.rect.getWidth());
- }
- else
- {
- if (wrw.isNotEmpty())
- w << bracketIfNeeded (wrw) << " + ";
-
- w << roundToInt (position.rect.getWidth());
- }
-
- // height
- if (position.rect.getHeightMode() == PositionedRectangle::proportionalSize)
- {
- if (hrh.isNotEmpty())
- h << "juce::roundToInt (" << bracketIfNeeded (hrh) << " * " << CodeHelpers::floatLiteral (position.rect.getHeight(), 4) << ")";
- else
- h << "proportionOfHeight (" << CodeHelpers::floatLiteral (position.rect.getHeight(), 4) << ")";
- }
- else if (position.rect.getHeightMode() == PositionedRectangle::parentSizeMinusAbsolute)
- {
- if (hrh.isNotEmpty())
- h << bracketIfNeeded (hrh) << " - " << roundToInt (position.rect.getHeight());
- else
- h << "getHeight() - " << roundToInt (position.rect.getHeight());
- }
- else
- {
- if (hrh.isNotEmpty())
- h << bracketIfNeeded (hrh) << " + ";
-
- h << roundToInt (position.rect.getHeight());
- }
-
- // x-pos
- if (position.rect.getPositionModeX() == PositionedRectangle::proportionOfParentSize)
- {
- if (xrx.isNotEmpty() && xrw.isNotEmpty())
- x << bracketIfNeeded (xrx) << " + juce::roundToInt (" << bracketIfNeeded (xrw) << " * " << CodeHelpers::floatLiteral (position.rect.getX(), 4) << ")";
- else
- x << "proportionOfWidth (" << CodeHelpers::floatLiteral (position.rect.getX(), 4) << ")";
- }
- else if (position.rect.getPositionModeX() == PositionedRectangle::absoluteFromParentTopLeft)
- {
- if (xrx.isNotEmpty())
- x << bracketIfNeeded (xrx) << " + ";
-
- x << roundToInt (position.rect.getX());
- }
- else if (position.rect.getPositionModeX() == PositionedRectangle::absoluteFromParentBottomRight)
- {
- if (xrx.isNotEmpty())
- x << bracketIfNeeded (xrx) << " + " << bracketIfNeeded (xrw);
- else
- x << "getWidth()";
-
- const int d = roundToInt (position.rect.getX());
- if (d != 0)
- x << " - " << d;
- }
- else if (position.rect.getPositionModeX() == PositionedRectangle::absoluteFromParentCentre)
- {
- if (xrx.isNotEmpty())
- x << bracketIfNeeded (xrx) << " + " << bracketIfNeeded (xrw) << " / 2";
- else
- x << "(getWidth() / 2)";
-
- const int d = roundToInt (position.rect.getX());
- if (d != 0)
- x << " + " << d;
- }
-
- if (w != "0")
- {
- if (position.rect.getAnchorPointX() == PositionedRectangle::anchorAtRightOrBottom)
- x << " - " << bracketIfNeeded (w);
- else if (position.rect.getAnchorPointX() == PositionedRectangle::anchorAtCentre)
- x << " - (" << bracketIfNeeded (w) << " / 2)";
- }
-
- // y-pos
- if (position.rect.getPositionModeY() == PositionedRectangle::proportionOfParentSize)
- {
- if (yry.isNotEmpty() && yrh.isNotEmpty())
- y << bracketIfNeeded (yry) << " + juce::roundToInt (" << bracketIfNeeded (yrh) << " * " << CodeHelpers::floatLiteral (position.rect.getY(), 4) << ")";
- else
- y << "proportionOfHeight (" << CodeHelpers::floatLiteral (position.rect.getY(), 4) << ")";
- }
- else if (position.rect.getPositionModeY() == PositionedRectangle::absoluteFromParentTopLeft)
- {
- if (yry.isNotEmpty())
- y << bracketIfNeeded (yry) << " + ";
-
- y << roundToInt (position.rect.getY());
- }
- else if (position.rect.getPositionModeY() == PositionedRectangle::absoluteFromParentBottomRight)
- {
- if (yry.isNotEmpty())
- y << bracketIfNeeded (yry) << " + " << bracketIfNeeded (yrh);
- else
- y << "getHeight()";
-
- const int d = roundToInt (position.rect.getY());
- if (d != 0)
- y << " - " << d;
- }
- else if (position.rect.getPositionModeY() == PositionedRectangle::absoluteFromParentCentre)
- {
- if (yry.isNotEmpty())
- y << bracketIfNeeded (yry) << " + " << bracketIfNeeded (yrh) << " / 2";
- else
- y << "(getHeight() / 2)";
-
- const int d = roundToInt (position.rect.getY());
- if (d != 0)
- y << " + " << d;
- }
-
- if (h != "0")
- {
- if (position.rect.getAnchorPointY() == PositionedRectangle::anchorAtRightOrBottom)
- y << " - " << bracketIfNeeded (h);
- else if (position.rect.getAnchorPointY() == PositionedRectangle::anchorAtCentre)
- y << " - (" << bracketIfNeeded (h) << " / 2)";
- }
- }
|