/* * Copyright 2020 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU * General Public License, version 3 as published by the Free * Software Foundation. * * Pixelitor 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. * * You should have received a copy of the GNU General Public License * along with Pixelitor. If not, see <http://www.gnu.org/licenses/>. */ package pixelitor.tools.gradient; import pixelitor.RunContext; import pixelitor.gui.ImageArea; import pixelitor.gui.View; import pixelitor.tools.ToolWidget; import pixelitor.tools.util.ArrowKey; import pixelitor.tools.util.DraggablePoint; import pixelitor.tools.util.ImDrag; import pixelitor.tools.util.UserDrag; import pixelitor.utils.Shapes; import pixelitor.utils.VisibleForTesting; import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; /** * The three handles that can be used to manipulate * a gradient by dragging */ public class GradientHandles implements ToolWidget { private final GradientDefiningPoint start; private final GradientDefiningPoint end; private final GradientCenterPoint middle; private final View view; public GradientHandles(Point2D start, Point2D end, View view) { this(start.getX(), start.getY(), end.getX(), end.getY(), view); } public GradientHandles(double startX, double startY, double endX, double endY, View view) { this.view = view; Color defaultColor = Color.WHITE; Color activeColor = Color.RED; start = new GradientDefiningPoint("start", startX, startY, view, defaultColor, activeColor, this); end = new GradientDefiningPoint("end", endX, endY, view, defaultColor, activeColor, this); middle = new GradientCenterPoint(start, end, view, defaultColor, activeColor); end.setOther(start); end.setCenter(middle); start.setOther(end); start.setCenter(middle); } @Override public DraggablePoint handleWasHit(double x, double y) { if (end.handleContains(x, y)) { return end; } if (start.handleContains(x, y)) { return start; } if (middle.handleContains(x, y)) { return middle; } return null; } @Override public void paint(Graphics2D g) { Shapes.drawGradientArrow(g, start.x, start.y, end.x, end.y); start.paintHandle(g); end.paintHandle(g); middle.paintHandle(g); } public ImDrag toImDrag(View view) { double startX = view.componentXToImageSpace(start.x); double startY = view.componentYToImageSpace(start.y); double endX = view.componentXToImageSpace(end.x); double endY = view.componentYToImageSpace(end.y); ImDrag imDrag = new ImDrag(startX, startY, endX, endY); return imDrag; } public UserDrag toUserDrag(GradientDefiningPoint movingPoint) { UserDrag ud; if (movingPoint == end) { ud = new UserDrag(); ud.setStart(start.asPPoint()); ud.setEnd(end.asPPoint()); } else if (movingPoint == start) { // if the user is moving the start point, then return // an UserDrag that points backwards, but calculates // the forward angle ud = new UserDrag() { @Override public double calcAngle() { return calcReversedAngle(); } }; ud.setStart(end.asPPoint()); ud.setEnd(start.asPPoint()); } else { throw new IllegalStateException("movingPoint = " + movingPoint); } return ud; } @Override public void coCoordsChanged(View view) { if (view == this.view) { start.restoreCoordsFromImSpace(view); end.restoreCoordsFromImSpace(view); middle.restoreCoordsFromImSpace(view); } else { // in random tests they can be different if (RunContext.isDevelopment()) { System.out.println("GradientHandles::viewSizeChanged: different views, ui = " + ImageArea.getMode()); } } } @Override public void imCoordsChanged(AffineTransform at) { start.imTransformOnlyThis(at, false); end.imTransformOnlyThis(at, false); middle.imTransformOnlyThis(at, false); } @Override public void arrowKeyPressed(ArrowKey key) { middle.arrowKeyPressed(key); } @VisibleForTesting public GradientDefiningPoint getStart() { return start; } @VisibleForTesting public GradientDefiningPoint getEnd() { return end; } @VisibleForTesting public GradientCenterPoint getMiddle() { return middle; } }