diff --git a/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample3.java b/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample3.java new file mode 100644 index 0000000..43644cb --- /dev/null +++ b/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample3.java @@ -0,0 +1,162 @@ +/* + * 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.pswing; + +import java.awt.Dimension; +import java.awt.Graphics2D; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; + +import edu.umd.cs.piccolo.PNode; +import edu.umd.cs.piccolo.nodes.PText; +import edu.umd.cs.piccolo.util.PPaintContext; +import edu.umd.cs.piccolox.pswing.PSwing; +import edu.umd.cs.piccolox.pswing.PSwingCanvas; + +/** + * User: Sam Reid Date: Jul 11, 2005 Time: 12:15:55 PM + */ +public class PSwingExample3 extends JFrame { + private static final long serialVersionUID = 1L; + private ExampleList exampleList; + + public PSwingExample3() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + PSwingCanvas canvas; + + // Set up basic frame + setBounds(50, 50, 750, 750); + setResizable(true); + setBackground(null); + setVisible(true); + canvas = new PSwingCanvas(); + canvas.setPanEventHandler(null); + getContentPane().add(canvas); + validate(); + + exampleList = new ExampleList("Button Examples"); + + addButtonExamples(); + + canvas.getLayer().addChild(exampleList); + + canvas.getCamera().animateViewToCenterBounds(canvas.getLayer().getFullBounds(), true, 1200); + } + + private void addButtonExamples() { + addButtonAloneNoSizing(); + addButtonAlone200x50(); + addButtonOnPanelNoSizing(); + addButtonOnPanel200x50(); + addButtonAlone10x10(); + } + + private void addButtonAloneNoSizing() { + JButton button = new JButton("Button"); + PSwing pButton = new PSwing(button); + exampleList.addExample("Alone - No Sizing", pButton); + } + + private void addButtonAlone200x50() { + JButton button = new JButton("Button"); + button.setPreferredSize(new Dimension(200, 50)); + PSwing pButton = new PSwing(button); + exampleList.addExample("Alone - 200x50", pButton); + } + + private void addButtonAlone10x10() { + JButton button = new JButton("Button"); + button.setPreferredSize(new Dimension(10, 10)); + PSwing pButton = new PSwing(button); + exampleList.addExample("Alone - 10x10", pButton); + } + + private void addButtonOnPanelNoSizing() { + JButton button = new JButton("Button"); + JPanel panel = new JPanel(); + panel.add(button); + PSwing pPanel = new PSwing(panel); + + exampleList.addExample("On JPanel - No Sizing", pPanel); + } + + private void addButtonOnPanel200x50() { + JButton button = new JButton("Button"); + button.setPreferredSize(new Dimension(200, 50)); + + JPanel panel = new JPanel(); + panel.add(button); + PSwing pPanel = new PSwing(panel); + + exampleList.addExample("On JPanel - 200x50", pPanel); + } + + public static void main(final String[] args) { + new PSwingExample3().setVisible(true); + } + + class ExampleList extends PText { + ExampleList(String name) { + super(name); + setScale(2); + } + + public void layoutChildren() { + PNode node; + double currentY = getHeight(); + for (int i=0; inew BasicStroke(). Cannot be made static @@ -226,6 +229,8 @@ */ private transient Stroke defaultStroke = new BasicStroke(); + private static final Color BUFFER_BACKGROUND_COLOR = new Color( 0, 0, 0, 0 ); + /** * Default font, 12 point "SansSerif". Will be made final in * version 2.0. @@ -240,6 +245,8 @@ /** Swing canvas for this swing node. */ private PSwingCanvas canvas; + private BufferedImage buffer; + /** * Used to keep track of which nodes we've attached listeners to since no * built in support in PNode. @@ -326,18 +333,8 @@ * bounds of this PNode. */ void reshape() { - final Border border = component.getBorder(); - - int width = Math.max(component.getMinimumSize().width, component.getPreferredSize().width); - final int height = component.getPreferredSize().height; - - if (border != null) { - final Insets borderInsets = border.getBorderInsets(component); - width += borderInsets.left + borderInsets.right; - } - - component.setBounds(0, 0, width, height); - setBounds(0, 0, width, height); + component.setBounds( 0, 0, component.getPreferredSize().width, component.getPreferredSize().height ); + setBounds( 0, 0, component.getPreferredSize().width, component.getPreferredSize().height ); } /** {@inheritDoc} */ @@ -354,52 +351,15 @@ if (component.getParent() == null) { component.revalidate(); } - - if (component instanceof JLabel) { - final JLabel label = (JLabel) component; - enforceNoEllipsis(label.getText(), label.getIcon(), label.getIconTextGap(), graphics); - } - else if (component instanceof JButton) { - final JButton button = (JButton) component; - enforceNoEllipsis(button.getText(), button.getIcon(), button.getIconTextGap(), graphics); - } - + if (shouldRenderGreek(paintContext)) { - paintGreek(paintContext); + paintGreek(graphics); } else { - paintComponent(paintContext); - } + paintComponent(graphics); + } } - - /** - * Workaround to prevent text-rendering Swing components from drawing an - * ellipsis incorrectly. - * - * @param text text - * @param icon icon - * @param iconGap icon gap - * @param graphics graphics - */ - private void enforceNoEllipsis(final String text, final Icon icon, final int iconGap, final Graphics2D graphics) { - final Rectangle2D textBounds = component.getFontMetrics(component.getFont()).getStringBounds(text, graphics); - double minAcceptableWidth = textBounds.getWidth(); - double minAcceptableHeight = textBounds.getHeight(); - - if (icon != null) { - minAcceptableWidth += icon.getIconWidth(); - minAcceptableWidth += iconGap; - minAcceptableHeight = Math.max(icon.getIconHeight(), minAcceptableHeight); - } - - if (component.getMinimumSize().getWidth() < minAcceptableWidth) { - final Dimension newMinimumSize = new Dimension((int) Math.ceil(minAcceptableWidth), (int) Math - .ceil(minAcceptableHeight)); - component.setMinimumSize(newMinimumSize); - reshape(); - } - } - + /** * Return the greek threshold in scale. When the scale will be below this * threshold the Swing component is rendered as 'greek' instead of painting @@ -445,8 +405,7 @@ * * @param paintContext paint context */ - protected void paintGreek(final PPaintContext paintContext) { - final Graphics2D graphics = paintContext.getGraphics(); + protected void paintGreek(final Graphics2D graphics) { final Color background = component.getBackground(); final Color foreground = component.getForeground(); final Rectangle2D rect = getBounds(); @@ -477,18 +436,55 @@ * * @param paintContext paint context */ - protected void paintComponent(final PPaintContext paintContext) { - if (component.getBounds().isEmpty()) { + protected void paintComponent(final Graphics2D g2) { + if( component.getBounds().isEmpty() ) { // The component has not been initialized yet. return; } - final Graphics2D graphics = paintContext.getGraphics(); - final PSwingRepaintManager manager = (PSwingRepaintManager) RepaintManager.currentManager(component); - manager.lockRepaint(component); - component.paint(graphics); - manager.unlockRepaint(component); + PSwingRepaintManager manager = (PSwingRepaintManager)RepaintManager.currentManager( component ); + manager.lockRepaint( component ); + + Graphics2D bufferedGraphics = null; + if( !isBufferValid() ) { + // Get the graphics context associated with a new buffered image. + // Use TYPE_INT_ARGB_PRE so that transparent components look good on Windows. + buffer = new BufferedImage( component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE ); + bufferedGraphics = buffer.createGraphics(); + } + else { + // Use the graphics context associated with the existing buffered image + bufferedGraphics = buffer.createGraphics(); + // Clear the buffered image to prevent artifacts on Macintosh + bufferedGraphics.setBackground( BUFFER_BACKGROUND_COLOR ); + bufferedGraphics.clearRect( 0, 0, component.getWidth(), component.getHeight() ); + } + + // Start with the rendering hints from the provided graphics context + bufferedGraphics.setRenderingHints( g2.getRenderingHints() ); + + //PSwing sometimes causes JComponent text to render with "..." when fractional font metrics are enabled. These are now always disabled for the offscreen buffer. + bufferedGraphics.setRenderingHint( RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF ); + + // Draw the component to the buffer + component.paint( bufferedGraphics ); + + // Draw the buffer to g2's associated drawing surface + g2.drawRenderedImage( buffer, IDENTITY_TRANSFORM ); + + manager.unlockRepaint( component ); } + + /** + * Tells whether the buffer for the image of the Swing components + * is currently valid. + * + * @return true if the buffer is currently valid + */ + private boolean isBufferValid() { + return !( buffer == null || buffer.getWidth() != component.getWidth() || buffer.getHeight() != component.getHeight() ); + } + /** {@inheritDoc} */ public void setVisible(final boolean visible) { diff --git a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java index 5f0dbb0..63d81e8 100644 --- a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java +++ b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java @@ -291,17 +291,16 @@ return image; } - public void paintComponentOnto(BufferedImage image) { - PPaintContext paintContext = new PPaintContext(image.createGraphics()); - paintComponent(paintContext); + public void paintComponentOnto(BufferedImage image) { + paintComponent(image.createGraphics()); } - protected void paintComponent(PPaintContext paintContext) { + protected void paintComponent(Graphics2D paintContext) { super.paintComponent(paintContext); paintedComponent = true; } - protected void paintGreek(PPaintContext paintContext) { + protected void paintGreek(Graphics2D paintContext) { super.paintGreek(paintContext); paintedGreek = true; }