/*
* Copyright 2016 Laszlo Balazs-Csiki
*
* 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.layers;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.MouseEvent;
/**
* The MouseListener and MouseMotionListener for the layer buttons for the drag-reordering
*/
public class DragReorderHandler extends MouseInputAdapter {
private static final Cursor MOVE_CURSOR = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
private static final Cursor DEFAULT_CURSOR = Cursor.getDefaultCursor();
private static final int DRAG_X_INDENT = 10;
private final LayersPanel layersPanel;
private int dragStartYInButton;
private boolean dragging = false;
private long lastNameEditorPressesMillis;
public DragReorderHandler(LayersPanel layersPanel) {
this.layersPanel = layersPanel;
}
@Override
public void mousePressed(MouseEvent e) {
// a manual double-click watch - necessary on Mac?
Component c = e.getComponent();
if (c instanceof LayerNameEditor) {
long when = e.getWhen();
long diffMillis = when - lastNameEditorPressesMillis;
if (diffMillis < 250) {
LayerNameEditor editor = (LayerNameEditor) c;
editor.enableEditing();
}
lastNameEditorPressesMillis = when;
}
getLayerButtonFromEvent(e); // the call is necessary for translating the mouse event
dragStartYInButton = e.getY();
}
@Override
public void mouseDragged(MouseEvent e) {
LayerButton layerButton = getLayerButtonFromEvent(e);
if (!dragging && Math.abs(dragStartYInButton - e.getY()) < 5) {
// it seems that on Mac we get mouseDragged events even when the mouse is not moved
return;
}
if (layerButton.isNameEditing()) {
return;
}
// since the LayerButton is continuously relocated, e.getY() returns
// the mouse relative to the last LayerButton position
int newY = layerButton.getY() + e.getY() - dragStartYInButton;
layerButton.setLocation(DRAG_X_INDENT, newY);
layersPanel.updateDrag(layerButton, newY, !dragging);
dragging = true;
layerButton.setCursor(MOVE_CURSOR);
layersPanel.doLayout();
}
@Override
public void mouseReleased(MouseEvent e) {
LayerButton layerButton = getLayerButtonFromEvent(e);
if (dragging) {
layerButton.setCursor(DEFAULT_CURSOR);
layersPanel.dragFinished();
} else {
// necessary on Mac so that the layer gets selected
// even if the user clicks on the name field
layerButton.setSelected(true);
}
dragging = false;
}
/**
* Returns the layer button for the mouse event and also translate
* the coordinates of the argument into the layer button space
*/
private static LayerButton getLayerButtonFromEvent(MouseEvent e) {
LayerButton layerButton;
Component c = e.getComponent();
// the source of the event must be either the layer button
// or the textfield inside it
if (c instanceof LayerNameEditor) {
LayerNameEditor nameEditor = (LayerNameEditor) c;
layerButton = nameEditor.getLayerButton();
// translate into the LayerButton coordinate system
e.translatePoint(nameEditor.getX(), nameEditor.getY());
} else if (c instanceof JLabel) {
layerButton = (LayerButton) c.getParent();
e.translatePoint(c.getX(), c.getY());
} else {
layerButton = (LayerButton) c;
}
return layerButton;
}
public void attachToComponent(Component c) {
c.addMouseListener(this);
c.addMouseMotionListener(this);
}
public void detachFromComponent(Component c) {
c.addMouseListener(this);
c.addMouseMotionListener(this);
}
}