/*
* Copyright 2004-2010 Information & Software Engineering Group (188/1)
* Institute of Software Technology and Interactive Systems
* Vienna University of Technology, Austria
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.tuwien.ifs.somtoolbox.apps.viewer.controls;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import edu.umd.cs.piccolo.PCanvas;
import edu.umd.cs.piccolo.PLayer;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PDragSequenceEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.util.PDimension;
import edu.umd.cs.piccolo.util.PPaintContext;
import edu.umd.cs.piccolox.nodes.P3DRect;
import at.tuwien.ifs.somtoolbox.apps.viewer.CommonSOMViewerStateData;
import at.tuwien.ifs.somtoolbox.apps.viewer.MapPNode;
/**
* Implements an overview of the {@link MapPNode}, indicating the currently displayed area of the map. Allows also to
* move the currently displayed area.
*
* @author Michael Dittenbach
* @version $Id: MapOverviewPane.java 3873 2010-10-28 09:29:58Z frank $
*/
public class MapOverviewPane extends AbstractViewerControl {
private static final long serialVersionUID = 1L;
private final MapOverviewCanvas moc;
public MapOverviewPane(String title, CommonSOMViewerStateData state) {
super(title, state, new GridLayout(1, 1));
moc = new MapOverviewCanvas();
getContentPane().add(moc);
moc.setPreferredSize(new Dimension(state.controlElementsWidth, 150));
setVisible(true);
}
public void connect(PCanvas canvas, PLayer[] viewed_layers) {
moc.connect(canvas, viewed_layers);
}
public class MapOverviewCanvas extends PCanvas implements PropertyChangeListener {
private static final long serialVersionUID = 1L;
/**
* This is the node that shows the viewed area.
*/
PNode areaVisiblePNode;
/**
* This is the canvas that is being viewed
*/
PCanvas viewedCanvas;
/**
* The change listener to know when to update the birds eye view.
*/
PropertyChangeListener changeListener;
int layerCount;
/**
* Creates a new instance of a BirdsEyeView
*/
public MapOverviewCanvas() {
// create the PropertyChangeListener for listening to the viewed canvas
changeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateFromViewed();
}
};
// create the coverage node
areaVisiblePNode = new P3DRect();
areaVisiblePNode.setPaint(new Color(128, 128, 255));
areaVisiblePNode.setTransparency(.8f);
areaVisiblePNode.setBounds(0, 0, 100, 100);
getCamera().addChild(areaVisiblePNode);
// add the drag event handler
getCamera().addInputEventListener(new PDragSequenceEventHandler() {
@Override
protected void startDrag(PInputEvent e) {
if (e.getPickedNode() == areaVisiblePNode) {
super.startDrag(e);
}
}
@Override
protected void drag(PInputEvent e) {
PDimension dim = e.getDelta();
viewedCanvas.getCamera().translateView(0 - dim.getWidth(), 0 - dim.getHeight());
}
});
// remove Pan and Zoom
removeInputEventListener(getPanEventHandler());
removeInputEventListener(getZoomEventHandler());
setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING);
}
public void connect(PCanvas canvas, PLayer[] viewed_layers) {
this.viewedCanvas = canvas;
layerCount = 0;
viewedCanvas.getCamera().addPropertyChangeListener(changeListener);
for (layerCount = 0; layerCount < viewed_layers.length; ++layerCount) {
getCamera().addLayer(layerCount, viewed_layers[layerCount]);
}
}
/**
* Add a layer to list of viewed layers
*/
public void addLayer(PLayer new_layer) {
getCamera().addLayer(new_layer);
layerCount++;
}
/**
* Remove the layer from the viewed layers
*/
public void removeLayer(PLayer old_layer) {
getCamera().removeLayer(old_layer);
layerCount--;
}
/**
* Stop the birds eye view from receiving events from the viewed canvas and remove all layers
*/
public void disconnect() {
viewedCanvas.getCamera().removePropertyChangeListener(changeListener);
for (int i = 0; i < getCamera().getLayerCount(); ++i) {
getCamera().removeLayer(i);
}
}
/**
* This method will get called when the viewed canvas changes
*/
@Override
public void propertyChange(PropertyChangeEvent event) {
updateFromViewed();
}
/**
* This method gets the state of the viewed canvas and updates the BirdsEyeViewer This can be called from
* outside code
*/
public void updateFromViewed() {
double viewedX;
double viewedY;
double viewedHeight;
double viewedWidth;
double ul_camera_x = viewedCanvas.getCamera().getViewBounds().getX();
double ul_camera_y = viewedCanvas.getCamera().getViewBounds().getY();
double lr_camera_x = ul_camera_x + viewedCanvas.getCamera().getViewBounds().getWidth();
double lr_camera_y = ul_camera_y + viewedCanvas.getCamera().getViewBounds().getHeight();
Rectangle2D drag_bounds = getCamera().getUnionOfLayerFullBounds();
double ul_layer_x = drag_bounds.getX();
double ul_layer_y = drag_bounds.getY();
double lr_layer_x = drag_bounds.getX() + drag_bounds.getWidth();
double lr_layer_y = drag_bounds.getY() + drag_bounds.getHeight();
// find the upper left corner
// set to the lesser value
if (ul_camera_x < ul_layer_x) {
viewedX = ul_layer_x;
} else {
viewedX = ul_camera_x;
}
// same for y
if (ul_camera_y < ul_layer_y) {
viewedY = ul_layer_y;
} else {
viewedY = ul_camera_y;
}
// find the lower right corner
// set to the greater value
if (lr_camera_x < lr_layer_x) {
viewedWidth = lr_camera_x - viewedX;
} else {
viewedWidth = lr_layer_x - viewedX;
}
// same for height
if (lr_camera_y < lr_layer_y) {
viewedHeight = lr_camera_y - viewedY;
} else {
viewedHeight = lr_layer_y - viewedY;
}
Rectangle2D bounds = new Rectangle2D.Double(viewedX, viewedY, viewedWidth, viewedHeight);
bounds = getCamera().viewToLocal(bounds);
areaVisiblePNode.setBounds(bounds);
// keep the birds eye view centered
getCamera().animateViewToCenterBounds(drag_bounds, true, 0);
}
} // class BirdsEyeView
}