diff --git a/examples/src/main/java/edu/umd/cs/piccolo/examples/PrintExample.java b/examples/src/main/java/edu/umd/cs/piccolo/examples/PrintExample.java new file mode 100644 index 0000000..97a5cb5 --- /dev/null +++ b/examples/src/main/java/edu/umd/cs/piccolo/examples/PrintExample.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2008-2009, Piccolo2D project, http://piccolo2d.org + * Copyright (c) 1998-2008, University of Maryland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its + * contributors may be used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.umd.cs.piccolo.examples; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.util.Iterator; + +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; + +import edu.umd.cs.piccolo.PCanvas; +import edu.umd.cs.piccolo.PLayer; +import edu.umd.cs.piccolo.nodes.PPath; +import edu.umd.cs.piccolo.util.PAffineTransform; +import edu.umd.cs.piccolo.util.PBounds; +import edu.umd.cs.piccolox.PFrame; +import edu.umd.cs.piccolox.swing.PDefaultScrollDirector; +import edu.umd.cs.piccolox.swing.PScrollDirector; +import edu.umd.cs.piccolox.swing.PScrollPane; +import edu.umd.cs.piccolox.swing.PViewport; + +/** + * Adding print action to scrolling example. + * + * @author Lance Good + * @author Ben Bederson + */ +public class PrintExample extends PFrame { + + public PrintExample() { + this(null); + } + + public PrintExample(PCanvas aCanvas) { + super("ScrollingExample", false, aCanvas); + } + + public void initialize() { + final PCanvas canvas = getCanvas(); + final PScrollPane scrollPane = new PScrollPane(canvas); + final PViewport viewport = (PViewport) scrollPane.getViewport(); + final PScrollDirector windowSD = viewport.getScrollDirector(); + final PScrollDirector documentSD = new DocumentScrollDirector(); + + // Make some rectangles on the surface so we can see where we are + for (int x = 0; x < 20; x++) { + for (int y = 0; y < 20; y++) { + if (((x + y) % 2) == 0) { + PPath path = PPath.createRectangle(50 * x, 50 * y, 40, 40); + path.setPaint(Color.blue); + path.setStrokePaint(Color.black); + canvas.getLayer().addChild(path); + } + else if (((x + y) % 2) == 1) { + PPath path = PPath.createEllipse(50 * x, 50 * y, 40, 40); + path.setPaint(Color.blue); + path.setStrokePaint(Color.black); + canvas.getLayer().addChild(path); + } + } + } + + // Now, create the toolbar + JToolBar toolBar = new JToolBar(); + JToggleButton window = new JToggleButton("Window Scrolling"); + JToggleButton document = new JToggleButton("Document Scrolling"); + JButton print = new JButton("Print"); + ButtonGroup bg = new ButtonGroup(); + bg.add(window); + bg.add(document); + toolBar.add(window); + toolBar.add(document); + toolBar.addSeparator(); + toolBar.add(print); + toolBar.setFloatable(false); + window.setSelected(true); + window.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + viewport.setScrollDirector(windowSD); + viewport.fireStateChanged(); + scrollPane.revalidate(); + getContentPane().validate(); + } + }); + document.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + viewport.setScrollDirector(documentSD); + viewport.fireStateChanged(); + scrollPane.revalidate(); + getContentPane().validate(); + } + }); + print.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + print(); + } + }); + JPanel contentPane = new JPanel(); + contentPane.setLayout(new BorderLayout()); + contentPane.add("Center", scrollPane); + contentPane.add("North", toolBar); + setContentPane(contentPane); + validate(); + } + + /** + * A modified scroll director that performs document based scroling rather + * than window based scrolling (ie. the scrollbars act in the inverse + * direction as normal) + */ + public class DocumentScrollDirector extends PDefaultScrollDirector { + + /** + * Get the View position given the specified camera bounds - modified + * such that: + * + * Rather than finding the distance from the upper left corner of the + * window to the upper left corner of the document - we instead find the + * distance from the lower right corner of the window to the upper left + * corner of the document THEN we subtract that value from total + * document width so that the position is inverted + * + * @param viewBounds The bounds for which the view position will be + * computed + * @return The view position + */ + public Point getViewPosition(Rectangle2D viewBounds) { + Point pos = new Point(); + if (camera != null) { + // First we compute the union of all the layers + PBounds layerBounds = new PBounds(); + java.util.List layers = camera.getLayersReference(); + for (Iterator i = layers.iterator(); i.hasNext();) { + PLayer layer = (PLayer) i.next(); + layerBounds.add(layer.getFullBoundsReference()); + } + + // Then we put the bounds into camera coordinates and + // union the camera bounds + camera.viewToLocal(layerBounds); + layerBounds.add(viewBounds); + + // Rather than finding the distance from the upper left corner + // of the window to the upper left corner of the document - + // we instead find the distance from the lower right corner + // of the window to the upper left corner of the document + // THEN we measure the offset from the lower right corner + // of the document + pos.setLocation((int) (layerBounds.getWidth() + - (viewBounds.getX() + viewBounds.getWidth() - layerBounds.getX()) + 0.5), (int) (layerBounds + .getHeight() + - (viewBounds.getY() + viewBounds.getHeight() - layerBounds.getY()) + 0.5)); + } + + return pos; + + } + + /** + * We do the same thing we did in getViewPosition above to flip the + * document-window position relationship + * + * @param x The new x position + * @param y The new y position + */ + public void setViewPosition(double x, double y) { + if (camera != null) { + // If a scroll is in progress - we ignore new scrolls - + // if we didn't, since the scrollbars depend on the camera + // location + // we can end up with an infinite loop + if (!scrollInProgress) { + scrollInProgress = true; + + // Get the union of all the layers' bounds + PBounds layerBounds = new PBounds(); + java.util.List layers = camera.getLayersReference(); + for (Iterator i = layers.iterator(); i.hasNext();) { + PLayer layer = (PLayer) i.next(); + layerBounds.add(layer.getFullBoundsReference()); + } + + PAffineTransform at = camera.getViewTransform(); + at.transform(layerBounds, layerBounds); + + // Union the camera view bounds + PBounds viewBounds = camera.getBoundsReference(); + layerBounds.add(viewBounds); + + // Now find the new view position in view coordinates - + // This is basically the distance from the lower right + // corner of the window to the upper left corner of the + // document + // We then measure the offset from the lower right corner + // of the document + Point2D newPoint = new Point2D.Double(layerBounds.getX() + layerBounds.getWidth() + - (x + viewBounds.getWidth()), layerBounds.getY() + layerBounds.getHeight() + - (y + viewBounds.getHeight())); + + // Now transform the new view position into global coords + camera.localToView(newPoint); + + // Compute the new matrix values to put the camera at the + // correct location + double newX = -(at.getScaleX() * newPoint.getX() + at.getShearX() * newPoint.getY()); + double newY = -(at.getShearY() * newPoint.getX() + at.getScaleY() * newPoint.getY()); + + at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), newX, newY); + + // Now actually set the camera's transform + camera.setViewTransform(at); + scrollInProgress = false; + } + } + } + } + + /** + * Print the canvas. + */ + private void print() + { + PrinterJob printJob = PrinterJob.getPrinterJob(); + printJob.setPrintable(new Printable() { + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + if (pageIndex > 0) { + return (NO_SUCH_PAGE); + } else { + Graphics2D g2 = (Graphics2D) graphics; + g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); + getCanvas().printAll(g2); + return (PAGE_EXISTS); + } + } + }); + if (printJob.printDialog()) { + try { + printJob.print(); + } catch (PrinterException e) { + e.printStackTrace(); + } + } + } + + public static void main(String[] args) { + new PrintExample(); + } +}