|
- /*
- ==============================================================================
-
- 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.
-
- ==============================================================================
- */
-
- #include "../../jucer_Headers.h"
- #include "../../Application/jucer_Application.h"
- #include "jucer_ComponentLayoutEditor.h"
- #include "../ui/jucer_JucerCommandIDs.h"
- #include "../jucer_ObjectTypes.h"
- #include "../components/jucer_JucerComponentHandler.h"
-
- //==============================================================================
- class SubComponentHolderComp : public Component
- {
- public:
- SubComponentHolderComp (JucerDocument& doc,
- SnapGridPainter& g)
- : document (doc), grid (g),
- dontFillBackground (false)
- {
- setInterceptsMouseClicks (false, false);
- setWantsKeyboardFocus (false);
- setFocusContainer (true);
- }
-
- void paint (Graphics& g) override
- {
- if (! dontFillBackground)
- {
- if (PaintRoutine* const background = document.getPaintRoutine (0))
- {
- background->fillWithBackground (g, false);
- background->drawElements (g, getLocalBounds());
-
- grid.draw (g, background);
- }
- else
- grid.draw (g, nullptr);
- }
- }
-
- void resized() override
- {
- if (! getBounds().isEmpty())
- {
- int numTimesToTry = 10;
-
- while (--numTimesToTry >= 0)
- {
- bool anyCompsMoved = false;
-
- for (int i = 0; i < getNumChildComponents(); ++i)
- {
- Component* comp = getChildComponent (i);
-
- if (ComponentTypeHandler* const type = ComponentTypeHandler::getHandlerFor (*comp))
- {
- const Rectangle<int> newBounds (type->getComponentPosition (comp)
- .getRectangle (getLocalBounds(),
- document.getComponentLayout()));
-
- anyCompsMoved = anyCompsMoved || (comp->getBounds() != newBounds);
- comp->setBounds (newBounds);
- }
- }
-
- // repeat this loop until they've all stopped shuffling (might require a few
- // loops for all the relative positioned comps to settle down)
- if (! anyCompsMoved)
- break;
- }
- }
- }
-
- void moved() override
- {
- ((ComponentLayoutEditor*) getParentComponent())->updateOverlayPositions();
- }
-
- JucerDocument& document;
- SnapGridPainter& grid;
- bool dontFillBackground;
- };
-
- //==============================================================================
- ComponentLayoutEditor::ComponentLayoutEditor (JucerDocument& doc, ComponentLayout& cl)
- : document (doc), layout (cl), firstResize (true)
- {
- setWantsKeyboardFocus (true);
-
- addAndMakeVisible (subCompHolder = new SubComponentHolderComp (document, grid));
-
- refreshAllComponents();
-
- setSize (document.getInitialWidth(),
- document.getInitialHeight());
- }
-
- ComponentLayoutEditor::~ComponentLayoutEditor()
- {
- document.removeChangeListener (this);
-
- removeChildComponent (&lassoComp);
- deleteAllChildren();
- }
-
- //==============================================================================
- void ComponentLayoutEditor::visibilityChanged()
- {
- document.beginTransaction();
-
- if (isVisible())
- {
- refreshAllComponents();
- document.addChangeListener (this);
- }
- else
- {
- document.removeChangeListener (this);
- }
- }
-
- void ComponentLayoutEditor::changeListenerCallback (ChangeBroadcaster*)
- {
- refreshAllComponents();
- }
-
- void ComponentLayoutEditor::paint (Graphics&)
- {
- }
-
- void ComponentLayoutEditor::resized()
- {
- if (firstResize && getWidth() > 0 && getHeight() > 0)
- {
- firstResize = false;
- refreshAllComponents();
- }
-
- subCompHolder->setBounds (getComponentArea());
- updateOverlayPositions();
- }
-
- Rectangle<int> ComponentLayoutEditor::getComponentArea() const
- {
- const int editorEdgeGap = 4;
-
- if (document.isFixedSize())
- return Rectangle<int> ((getWidth() - document.getInitialWidth()) / 2,
- (getHeight() - document.getInitialHeight()) / 2,
- document.getInitialWidth(),
- document.getInitialHeight());
-
- return Rectangle<int> (editorEdgeGap, editorEdgeGap,
- getWidth() - editorEdgeGap * 2,
- getHeight() - editorEdgeGap * 2);
- }
-
- Image ComponentLayoutEditor::createComponentLayerSnapshot() const
- {
- ((SubComponentHolderComp*) subCompHolder)->dontFillBackground = true;
- Image im = subCompHolder->createComponentSnapshot (Rectangle<int> (0, 0, subCompHolder->getWidth(), subCompHolder->getHeight()));
- ((SubComponentHolderComp*) subCompHolder)->dontFillBackground = false;
-
- return im;
- }
-
- void ComponentLayoutEditor::updateOverlayPositions()
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- if (ComponentOverlayComponent* const overlay = dynamic_cast<ComponentOverlayComponent*> (getChildComponent (i)))
- overlay->updateBoundsToMatchTarget();
- }
-
- void ComponentLayoutEditor::refreshAllComponents()
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- ScopedPointer<ComponentOverlayComponent> overlay (dynamic_cast<ComponentOverlayComponent*> (getChildComponent (i)));
-
- if (overlay != nullptr && layout.containsComponent (overlay->target))
- overlay.release();
- }
-
- for (int i = subCompHolder->getNumChildComponents(); --i >= 0;)
- {
- Component* const comp = subCompHolder->getChildComponent (i);
-
- if (! layout.containsComponent (comp))
- subCompHolder->removeChildComponent (comp);
- }
-
- Component* lastComp = nullptr;
- Component* lastOverlay = nullptr;
-
- for (int i = layout.getNumComponents(); --i >= 0;)
- {
- Component* const c = layout.getComponent (i);
- jassert (c != nullptr);
-
- ComponentOverlayComponent* overlay = getOverlayCompFor (c);
-
- bool isNewOverlay = false;
-
- if (overlay == 0)
- {
- ComponentTypeHandler* const handler = ComponentTypeHandler::getHandlerFor (*c);
- jassert (handler != nullptr);
-
- overlay = handler->createOverlayComponent (c, layout);
-
- addAndMakeVisible (overlay);
- isNewOverlay = true;
- }
-
- if (lastOverlay != nullptr)
- overlay->toBehind (lastOverlay);
- else
- overlay->toFront (false);
-
- lastOverlay = overlay;
-
- subCompHolder->addAndMakeVisible (c);
-
- if (lastComp != nullptr)
- c->toBehind (lastComp);
- else
- c->toFront (false);
-
- lastComp = c;
-
- c->setWantsKeyboardFocus (false);
- c->setFocusContainer (true);
-
- if (isNewOverlay)
- overlay->updateBoundsToMatchTarget();
- }
-
- if (grid.updateFromDesign (document))
- subCompHolder->repaint();
-
- subCompHolder->setBounds (getComponentArea());
- subCompHolder->resized();
- }
-
- void ComponentLayoutEditor::mouseDown (const MouseEvent& e)
- {
- if (e.mods.isPopupMenu())
- {
- ApplicationCommandManager* commandManager = &ProjucerApplication::getCommandManager();
-
- PopupMenu m;
-
- m.addCommandItem (commandManager, JucerCommandIDs::editCompLayout);
- m.addCommandItem (commandManager, JucerCommandIDs::editCompGraphics);
- m.addSeparator();
-
- for (int i = 0; i < ObjectTypes::numComponentTypes; ++i)
- m.addCommandItem (commandManager, JucerCommandIDs::newComponentBase + i);
-
- m.show();
- }
- else
- {
- addChildComponent (lassoComp);
- lassoComp.beginLasso (e, this);
- }
- }
-
- void ComponentLayoutEditor::mouseDrag (const MouseEvent& e)
- {
- lassoComp.toFront (false);
- lassoComp.dragLasso (e);
- }
-
- void ComponentLayoutEditor::mouseUp (const MouseEvent& e)
- {
- lassoComp.endLasso();
- removeChildComponent (&lassoComp);
-
- if (! (e.mouseWasDraggedSinceMouseDown() || e.mods.isAnyModifierKeyDown()))
- layout.getSelectedSet().deselectAll();
- }
-
- static void moveOrStretch (ComponentLayout& layout, int x, int y, bool snap, bool stretch)
- {
- if (stretch)
- layout.stretchSelectedComps (x, y, snap);
- else
- layout.moveSelectedComps (x, y, snap);
- }
-
- bool ComponentLayoutEditor::keyPressed (const KeyPress& key)
- {
- const bool snap = key.getModifiers().isAltDown();
- const bool stretch = key.getModifiers().isShiftDown();
-
- const int amount = snap ? document.getSnappingGridSize() + 1
- : 1;
-
- if (key.isKeyCode (KeyPress::rightKey))
- {
- moveOrStretch (layout, amount, 0, snap, stretch);
- }
- else if (key.isKeyCode (KeyPress::downKey))
- {
- moveOrStretch (layout, 0,amount, snap, stretch);
- }
- else if (key.isKeyCode (KeyPress::leftKey))
- {
- moveOrStretch (layout, -amount, 0, snap, stretch);
- }
- else if (key.isKeyCode (KeyPress::upKey))
- {
- moveOrStretch (layout, 0, -amount, snap, stretch);
- }
- else
- {
- return false;
- }
-
- return true;
- }
-
- bool ComponentLayoutEditor::isInterestedInFileDrag (const StringArray& filenames)
- {
- const File f (filenames [0]);
- return f.hasFileExtension (".cpp");
- }
-
- void ComponentLayoutEditor::filesDropped (const StringArray& filenames, int x, int y)
- {
- const File f (filenames [0]);
-
- if (JucerDocument::isValidJucerCppFile (f))
- {
- JucerComponentHandler jucerDocHandler;
- layout.getDocument()->beginTransaction();
-
- if (TestComponent* newOne = dynamic_cast<TestComponent*> (layout.addNewComponent (&jucerDocHandler,
- x - subCompHolder->getX(),
- y - subCompHolder->getY())))
- {
- JucerComponentHandler::setJucerComponentFile (*layout.getDocument(), newOne,
- f.getRelativePathFrom (document.getCppFile().getParentDirectory()));
- layout.getSelectedSet().selectOnly (newOne);
- }
-
- layout.getDocument()->beginTransaction();
- }
- }
-
- bool ComponentLayoutEditor::isInterestedInDragSource (const SourceDetails& dragSourceDetails)
- {
- if (dragSourceDetails.description != projectItemDragType)
- return false;
-
- OwnedArray<Project::Item> selectedNodes;
- ProjectContentComponent::getSelectedProjectItemsBeingDragged (dragSourceDetails, selectedNodes);
-
- return selectedNodes.size() > 0;
- }
-
- void ComponentLayoutEditor::itemDropped (const SourceDetails& dragSourceDetails)
- {
- OwnedArray <Project::Item> selectedNodes;
- ProjectContentComponent::getSelectedProjectItemsBeingDragged (dragSourceDetails, selectedNodes);
-
- StringArray filenames;
-
- for (int i = 0; i < selectedNodes.size(); ++i)
- if (selectedNodes.getUnchecked(i)->getFile().hasFileExtension (".cpp"))
- filenames.add (selectedNodes.getUnchecked(i)->getFile().getFullPathName());
-
- filesDropped (filenames, dragSourceDetails.localPosition.x, dragSourceDetails.localPosition.y);
- }
-
- ComponentOverlayComponent* ComponentLayoutEditor::getOverlayCompFor (Component* compToFind) const
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- if (ComponentOverlayComponent* const overlay = dynamic_cast<ComponentOverlayComponent*> (getChildComponent (i)))
- if (overlay->target == compToFind)
- return overlay;
- }
-
- return nullptr;
- }
-
- void ComponentLayoutEditor::findLassoItemsInArea (Array <Component*>& results, const Rectangle<int>& area)
- {
- const Rectangle<int> lasso (area - subCompHolder->getPosition());
-
- for (int i = 0; i < subCompHolder->getNumChildComponents(); ++i)
- {
- Component* c = subCompHolder->getChildComponent (i);
-
- if (c->getBounds().intersects (lasso))
- results.add (c);
- }
- }
-
- SelectedItemSet <Component*>& ComponentLayoutEditor::getLassoSelection()
- {
- return layout.getSelectedSet();
- }
|