/* ============================================================================== 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 "jucer_ComponentLayoutEditor.h" #include "../jucer_UtilityFunctions.h" //============================================================================== ComponentOverlayComponent::ComponentOverlayComponent (Component* const target_, ComponentLayout& layout_) : target (target_), borderThickness (4), layout (layout_), selected (false), dragging (false), originalAspectRatio (1.0) { setMinimumOnscreenAmounts (0, 0, 0, 0); setSizeLimits (borderThickness * 2 + 2, borderThickness * 2 + 2, 8192, 8192); addChildComponent (border = new ResizableBorderComponent (this, this)); border->setBorderThickness (BorderSize (borderThickness)); target->addComponentListener (this); changeListenerCallback (nullptr); layout.getSelectedSet().addChangeListener (this); setRepaintsOnMouseActivity (true); border->setRepaintsOnMouseActivity (true); } ComponentOverlayComponent::~ComponentOverlayComponent() { layout.getSelectedSet().removeChangeListener (this); if (target != nullptr) target->removeComponentListener (this); } void ComponentOverlayComponent::changeListenerCallback (ChangeBroadcaster*) { const bool nowSelected = layout.getSelectedSet().isSelected (target); if (selected != nowSelected) { selected = nowSelected; border->setVisible (nowSelected); repaint(); } } void ComponentOverlayComponent::paint (Graphics& g) { jassert (target != nullptr); if (selected) { const BorderSize borderSize (border->getBorderThickness()); drawResizableBorder (g, getWidth(), getHeight(), borderSize, (isMouseOverOrDragging() || border->isMouseOverOrDragging())); } else if (isMouseOverOrDragging()) { drawMouseOverCorners (g, getWidth(), getHeight()); } } void ComponentOverlayComponent::resized() { jassert (target != nullptr); border->setBounds (getLocalBounds()); } void ComponentOverlayComponent::mouseDown (const MouseEvent& e) { dragging = false; mouseDownSelectStatus = layout.getSelectedSet().addToSelectionOnMouseDown (target, e.mods); if (e.mods.isPopupMenu()) { showPopupMenu(); return; // this may be deleted now.. } } void ComponentOverlayComponent::mouseDrag (const MouseEvent& e) { if (! e.mods.isPopupMenu()) { if (selected && ! dragging) { dragging = e.mouseWasDraggedSinceMouseDown(); if (dragging) layout.startDragging(); } if (dragging) { layout.dragSelectedComps (e.getDistanceFromDragStartX(), e.getDistanceFromDragStartY()); } } } void ComponentOverlayComponent::mouseUp (const MouseEvent& e) { if (dragging) layout.endDragging(); layout.getSelectedSet().addToSelectionOnMouseUp (target, e.mods, dragging, mouseDownSelectStatus); } void ComponentOverlayComponent::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/) { updateBoundsToMatchTarget(); } void ComponentOverlayComponent::updateBoundsToMatchTarget() { if (Component* const parent = target->getParentComponent()) { const int dx = parent->getX(); const int dy = parent->getY(); setBounds (dx + target->getX() - borderThickness, dy + target->getY() - borderThickness, target->getWidth() + borderThickness * 2, target->getHeight() + borderThickness * 2); } if (border->isMouseButtonDown()) layout.changed(); } void ComponentOverlayComponent::resizeStart() { if (getHeight() > 0) originalAspectRatio = getWidth() / (double) getHeight(); else originalAspectRatio = 1.0; layout.getDocument()->beginTransaction ("Resize components"); } void ComponentOverlayComponent::resizeEnd() { layout.getDocument()->beginTransaction(); } void ComponentOverlayComponent::checkBounds (Rectangle& b, const Rectangle& previousBounds, const Rectangle& limits, const bool isStretchingTop, const bool isStretchingLeft, const bool isStretchingBottom, const bool isStretchingRight) { if (ModifierKeys::getCurrentModifiers().isShiftDown()) setFixedAspectRatio (originalAspectRatio); else setFixedAspectRatio (0.0); ComponentBoundsConstrainer::checkBounds (b, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight); if (layout.getDocument()->isSnapActive (true)) { if (Component* const parent = target->getParentComponent()) { const int dx = parent->getX(); const int dy = parent->getY(); int x = b.getX(); int y = b.getY(); int w = b.getWidth(); int h = b.getHeight(); x += borderThickness - dx; y += borderThickness - dy; w -= borderThickness * 2; h -= borderThickness * 2; int right = x + w; int bottom = y + h; if (isStretchingRight) right = layout.getDocument()->snapPosition (right); if (isStretchingBottom) bottom = layout.getDocument()->snapPosition (bottom); if (isStretchingLeft) x = layout.getDocument()->snapPosition (x); if (isStretchingTop) y = layout.getDocument()->snapPosition (y); w = (right - x) + borderThickness * 2; h = (bottom - y) + borderThickness * 2; x -= borderThickness - dx; y -= borderThickness - dy; b = Rectangle (x, y, w, h); } } } void ComponentOverlayComponent::applyBoundsToComponent (Component* component, const Rectangle& b) { if (component->getBounds() != b) { layout.getDocument()->getUndoManager().undoCurrentTransactionOnly(); component->setBounds (b); if (Component* const parent = target->getParentComponent()) target->setBounds (b.getX() + borderThickness - parent->getX(), b.getY() + borderThickness - parent->getY(), b.getWidth() - borderThickness * 2, b.getHeight() - borderThickness * 2); layout.updateStoredComponentPosition (target, true); } } void ComponentOverlayComponent::showPopupMenu() { ComponentTypeHandler::getHandlerFor (*target)->showPopupMenu (target, layout); }