/*
* Copyright (C) 2010 Markus Echterhoff <tam@edu.uni-klu.ac.at>,
* Daniel Hoelbling (http://www.tigraine.at)
*
* This file is part of EvoPaint.
*
* EvoPaint is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 EvoPaint. If not, see <http://www.gnu.org/licenses/>.
*/
package evopaint.gui;
import evopaint.Configuration;
import evopaint.commands.*;
import evopaint.Selection;
import evopaint.gui.util.WrappingScalableCanvas;
import evopaint.util.logging.Logger;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.Observable;
import java.util.Observer;
import javax.swing.Timer;
import javax.swing.event.MouseInputListener;
/**
*
* @author Markus Echterhoff <tam@edu.uni-klu.ac.at>
* @author Daniel Hoelbling (http://www.tigraine.at)
*/
public class Showcase extends WrappingScalableCanvas implements MouseInputListener, MouseWheelListener, Observer, SelectionManager {
private Configuration configuration;
private boolean leftButtonPressed = false;
private boolean toggleMouseButton2Drag = false;
private PaintCommand paintCommand;
private MoveCommand moveCommand;
private SelectCommand selectCommand;
private FillSelectionCommand fillCommand;
private EraseCommand eraseCommand;
private SelectionList currentSelections = new SelectionList();
private Selection activeSelection;
private boolean isDrawingSelection = false;
private Point selectionStartPoint;
private Point currentMouseDragPosition;
private BrushIndicatorOverlay brushIndicatorOverlay;
private Timer paintingTimer;
private Painter painter;
private SelectionIndicatorOverlay draggingSelectionOverlay;
private CopySelectionCommand copySelectionCommand;
public Showcase(Configuration configuration, CommandFactory commandFactory) {
super(configuration.perception.getImage());
this.configuration = configuration;
this.paintCommand = new PaintCommand(configuration, this);
this.moveCommand = new MoveCommand(configuration);
this.moveCommand.setCanvas(this);
this.selectCommand = new SelectCommand(currentSelections, this);
this.fillCommand = new FillSelectionCommand(this);
this.eraseCommand = new EraseCommand(configuration, this);
this.copySelectionCommand = new CopySelectionCommand(configuration);
this.currentSelections.addObserver(this);
this.brushIndicatorOverlay = new BrushIndicatorOverlay(this,
new Rectangle(configuration.brush.size, configuration.brush.size));
this.painter = new Painter();
this.paintingTimer = new Timer(0, this.painter);
this.paintingTimer.setDelay(10);
addMouseWheelListener(this);
addMouseListener(this);
addMouseMotionListener(this);
}
public Configuration getConfiguration() {
return configuration;
}
public SelectionList getCurrentSelections() {
return currentSelections;
}
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
}
public void mouseWheelMoved(MouseWheelEvent e) {
// needs to be checked _before_ zooming
if (e.getSource() == this && configuration.mainFrame.getActiveTool() == PaintCommand.class) {
brushIndicatorOverlay.setBounds(new Rectangle(
transformToImageSpace(e.getPoint()),
new Dimension(configuration.brush.size, configuration.brush.size)));
}
ZoomCommand zoomCommand ;
if (e.getWheelRotation() < 0)
zoomCommand = new ZoomInCommand(this);
else
zoomCommand = new ZoomOutCommand(this);
zoomCommand.execute();
}
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
leftButtonPressed = true;
if (configuration.mainFrame.getActiveTool() == PaintCommand.class) {
painter.setLocation(e.getPoint());
paintingTimer.start();
configuration.paint.rememberCurrent();
} else if (configuration.mainFrame.getActiveTool() == MoveCommand.class) {
moveCommand.setSource(e.getPoint());
//moveCommand.setScale(this.scale);
} else if (configuration.mainFrame.getActiveTool() == SelectCommand.class) {
this.selectionStartPoint = transformToImageSpace(e.getPoint());
draggingSelectionOverlay = new SelectionIndicatorOverlay(this, new Rectangle());
subscribe(draggingSelectionOverlay);
selectCommand.setLocation(this.selectionStartPoint);
selectCommand.execute();
} else if (configuration.mainFrame.getActiveTool() == ZoomCommand.class) {
ZoomInCommand zoomInCommand = new ZoomInCommand(this);
zoomInCommand.execute();
this.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
} else if (configuration.mainFrame.getActiveTool() == FillSelectionCommand.class) {
fillCommand.setLocation(transformToImageSpace(e.getPoint()));
fillCommand.execute();
} else if (configuration.mainFrame.getActiveTool() == PickCommand.class) {
PickCommand pickCommand = new PickCommand(configuration);
pickCommand.setLocation(transformToImageSpace(e.getPoint()));
pickCommand.execute();
} else if (configuration.mainFrame.getActiveTool() == EraseCommand.class) {
eraseCommand.setLocation(transformToImageSpace(e.getPoint()));
eraseCommand.execute();
} else if (configuration.mainFrame.getActiveTool() == CopySelectionCommand.class) {
copySelectionCommand.setLocation(transformToImageSpace(e.getPoint()));
copySelectionCommand.execute();
}
} else if (e.getButton() == MouseEvent.BUTTON3) {
if (configuration.mainFrame.getActiveTool() == ZoomCommand.class){
ZoomOutCommand zoomOutCommand = new ZoomOutCommand(this);
zoomOutCommand.execute();
this.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
}
else {
configuration.paint.showHistory(this, e.getPoint());
}
} else if (e.getButton() == MouseEvent.BUTTON2) {
if (configuration.mainFrame.getActiveTool() == ZoomCommand.class){
scaleReset();
} else {
toggleMouseButton2Drag = true;
moveCommand.setSource(e.getPoint());
}
}
}
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
leftButtonPressed = false;
paintingTimer.stop();
Class activeTool = configuration.mainFrame.getActiveTool();
if (activeTool == SelectCommand.class) {
this.isDrawingSelection = false;
selectCommand.setLocation(transformToImageSpace(e.getPoint()));
selectCommand.execute();
unsubscribe(draggingSelectionOverlay);
draggingSelectionOverlay = null;
} else if (activeTool == CopySelectionCommand.class) {
copySelectionCommand.setLocation(transformToImageSpace(e.getPoint()));
copySelectionCommand.execute();
}
} else if (e.getButton() == MouseEvent.BUTTON2) {
toggleMouseButton2Drag = false;
}
}
public void mouseDragged(MouseEvent e) {
this.currentMouseDragPosition = e.getPoint();
Class activeTool = configuration.mainFrame.getActiveTool();
if (leftButtonPressed == true) {
if (activeTool == SelectCommand.class) {
Point pointInImageSpace = transformToImageSpace(currentMouseDragPosition);
draggingSelectionOverlay.setBounds(new Rectangle(selectionStartPoint, new Dimension(pointInImageSpace.x - selectionStartPoint.x, pointInImageSpace.y - selectionStartPoint.y)));
}
else if (activeTool == PaintCommand.class) {
painter.setLocation(currentMouseDragPosition);
} else if (activeTool == MoveCommand.class) {
moveCommand.setDestination(e.getPoint());
moveCommand.execute();
} else if (activeTool == EraseCommand.class) {
eraseCommand.setLocation(transformToImageSpace(currentMouseDragPosition));
eraseCommand.execute();
} else if (activeTool == CopySelectionCommand.class) {
copySelectionCommand.setLocation(transformToImageSpace(currentMouseDragPosition));
}
} else if (toggleMouseButton2Drag == true) {
moveCommand.setDestination(e.getPoint());
moveCommand.execute();
}
if (activeTool == PaintCommand.class) {
brushIndicatorOverlay.setBounds(new Rectangle(
transformToImageSpace(e.getPoint()),
new Dimension(configuration.brush.size, configuration.brush.size)));
}
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
if (configuration.mainFrame.getActiveTool() == PaintCommand.class) {
subscribe(brushIndicatorOverlay);
}
}
public void mouseExited(MouseEvent e) {
unsubscribe(brushIndicatorOverlay);
}
public void mouseMoved(MouseEvent e) {
if (configuration.mainFrame.getActiveTool() == PaintCommand.class) {
brushIndicatorOverlay.setBounds(new Rectangle(
transformToImageSpace(e.getPoint()),
new Dimension(configuration.brush.size, configuration.brush.size)));
}
}
public Selection getActiveSelection() {
return activeSelection;
}
public void clearSelections() {
this.activeSelection = null;
this.currentSelections.clear();
}
public void setActiveSelection(Selection selection) {
this.activeSelection = selection;
for(Selection sel : currentSelections) {
unsubscribe(sel);
}
subscribe(selection);
ClearSelectionHighlight();
}
private void ClearSelectionHighlight() {
for(Selection sel : currentSelections ){
sel.setHighlighted(false);
}
}
public void removeActiveSelection() {
this.currentSelections.remove(activeSelection);
activeSelection = null;
}
public void update(Observable o, Object arg) {
SelectionList.SelectionListEventArgs selectionEvent = (SelectionList.SelectionListEventArgs) arg;
if (selectionEvent.getChangeType() == SelectionList.ChangeType.ITEM_ADDED) {
Selection selection = selectionEvent.getSelection();
setActiveSelection(selection);
Logger.log.error("Selection from %s-%s to %s-%s", selection.getStartPoint().getX(), selection.getStartPoint().getY(), selection.getEndPoint().getX(), selection.getEndPoint().getY());
}
}
private class Painter implements ActionListener {
private Point location;
public Painter() {
}
public void setLocation(Point locationInUserSpace) {
this.location = transformToImageSpace(locationInUserSpace);
}
public void actionPerformed(ActionEvent e) {
paintCommand.setLocation(location);
paintCommand.execute();
}
}
/* a nice idea, but it is slow since we have to draw not only the line, but the pixels into the world
private class ContinuousPainter implements ActionListener {
private Point location;
private Queue<Point> destinations;
public ContinuousPainter() {
this.destinations = new ArrayDeque<Point>();
}
public void setLocation(Point locationInUserSpace) {
this.location = transformToImageSpace(locationInUserSpace);
this.destinations.clear();
}
public void setDestination(Point destinationInUserSpace) {
this.destinations.add(transformToImageSpace(destinationInUserSpace));
}
public void actionPerformed(ActionEvent e) {
Point destination = destinations.peek();
while (destination != null) {
if (destination.x != location.x) {
double gradient = gradient(location, destination);
if (gradient < 0.5) {
if (destination.y != location.y) {
if (destination.y > location.y) {
location.y += gradient;
} else {
location.y -= gradient;
}
}
if (destination.x > location.x) {
location.x += 1;
} else {
location.x -= 1;
}
} else {
if (destination.x > location.x) {
location.x += gradient;
} else {
location.x -= gradient;
}
if (destination.y > location.y) {
location.y += 1;
} else {
location.y -= 1;
}
}
break;
}
else if (destination.y != location.y) {
if (destination.y > location.y) {
location.y += 1;
} else {
location.y -= 1;
}
break;
} else {
destinations.remove();
destination = destinations.peek();
}
}
paintCommand.setLocation(location);
paintCommand.execute();
}
private double gradient(Point location, Point destination) {
assert(location.x - destination.x != 0);
return ((double)Math.abs(destination.y - location.y)) /
((double)Math.abs(destination.x - location.x));
}
}
*/
}