Revision: 550 Author: allain.lalonde Date: Thu Jul 23 08:41:42 2009 Log: Fixed Issue 83; Transforming graphics context was introducing slight rounding errors in the font metrics measurements. Calculating string widths using compnent.getGraphics() would yield slightly smaller widths than calculating them using the active Graphics object.
The fix is to calculate the "minimum acceptable" width that erring components (JButtons and JLabels) can be given the current graphics context and checking to see if it's larger than the minimum width the JLabel is reporting (which is computed at creation time assuming an identity transform). If it's larger (ellipsis would be shown) then it changes the minimum size of the component to be the the nearest ceil(minAcceptableWidth). The calculation for the minimum size involves measuring text, adding insets, affording for icons and icon gaps. Also, when calculating the bounds of the component, insets were not being considered but should have been. Only hackish element of this fix is that its only applied to JButton and JLabels right now since I think they're the only components I can think of that calculate their minimum sizes in this way. http://code.google.com/p/piccolo2d/source/detail?r=550 Modified: /piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample2.java /piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java ======================================= --- /piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample2.java Fri Jul 17 06:39:05 2009 +++ /piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/pswing/PSwingExample2.java Thu Jul 23 08:41:42 2009 @@ -30,14 +30,17 @@ import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.event.ActionEvent; import java.io.IOException; import java.util.Vector; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; @@ -227,13 +230,34 @@ // A JLabel JLabel label = new JLabel("A JLabel", SwingConstants.CENTER); - swing = new PSwing(label); leaf = new ZVisualLeaf(swing); transform = new PNode(); transform.translate(-500, 0); transform.addChild(leaf); canvas.getLayer().addChild(transform); + + label = new JLabel("A JLabel", SwingConstants.CENTER); + label.setIcon(new Icon() { + + public int getIconHeight() { + return 20; + } + + public int getIconWidth() { + return 20; + } + + public void paintIcon(Component c, Graphics g, int x, int y) { + g.setColor(Color.BLUE); + g.drawRect(0, 0, 20, 20); + }}); + swing = new PSwing(label); + leaf = new ZVisualLeaf(swing); + transform = new PNode(); + transform.translate(-500, 30); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // Rotated copy of the Scrollable JTextArea leaf = new ZVisualLeaf(swing2); ======================================= --- /piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java Sun Jul 19 16:56:41 2009 +++ /piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java Thu Jul 23 08:41:42 2009 @@ -32,8 +32,10 @@ import java.awt.Color; import java.awt.Component; import java.awt.Container; +import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; +import java.awt.Insets; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; @@ -50,8 +52,12 @@ import java.util.ArrayList; import java.util.Arrays; +import javax.swing.Icon; +import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JLabel; import javax.swing.RepaintManager; +import javax.swing.border.Border; import edu.umd.cs.piccolo.PCamera; import edu.umd.cs.piccolo.PLayer; @@ -213,7 +219,7 @@ private JComponent component = null; private double minFontSize = Double.MAX_VALUE; private Stroke defaultStroke = new BasicStroke(); - private Font defaultFont = new Font("Serif", Font.PLAIN, 12); + private Font defaultFont = new Font("Serif", Font.PLAIN, 12); private PSwingCanvas canvas; // ////////////////////////////////////////////////////////// @@ -258,11 +264,11 @@ }); component.addComponentListener(new ComponentAdapter() { - public void componentHidden(ComponentEvent e) { + public void componentHidden(ComponentEvent e) { setVisible(false); } - public void componentShown(ComponentEvent e) { + public void componentShown(ComponentEvent e) { setVisible(true); } }); @@ -288,8 +294,19 @@ * bounds of this PNode. */ void reshape() { - component.setBounds(0, 0, component.getPreferredSize().width, component.getPreferredSize().height); - setBounds(0, 0, component.getPreferredSize().width, component.getPreferredSize().height); + Border border = component.getBorder(); + + int width = (int) Math.max(component.getMinimumSize().width, component.getPreferredSize().width); + int height = (int) Math.max(component.getMinimumSize().height, component.getPreferredSize().height); + + if (border != null) { + Insets borderInsets = border.getBorderInsets(component); + width += borderInsets.left + borderInsets.right; + height += borderInsets.top + borderInsets.bottom; + } + + component.setBounds(0, 0, width, height); + setBounds(0, 0, width, height); } /** @@ -323,6 +340,15 @@ // pSwingCanvas.getSwingWrapper().add( component ); component.revalidate(); } + + if (component instanceof JLabel) { + JLabel label = (JLabel)component; + enforceNoEllipsis(label.getText(), label.getIcon(), label.getIconTextGap(), g2); + } + else if (component instanceof JButton) { + JButton button = (JButton)component; + enforceNoEllipsis(button.getText(), button.getIcon(), button.getIconTextGap(), g2); + } if (shouldRenderGreek(renderContext)) { paintAsGreek(g2); @@ -330,7 +356,24 @@ else { paint(g2); } - + } + + private void enforceNoEllipsis(String text, Icon icon, int iconGap, Graphics2D g2) { + Rectangle2D textBounds = component.getFontMetrics(component.getFont()).getStringBounds(text, g2); + 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 ) { + Dimension newMinimumSize = new Dimension((int)Math.ceil(minAcceptableWidth), (int)Math.ceil(minAcceptableHeight)); + component.setMinimumSize(newMinimumSize); + reshape(); + } } protected boolean shouldRenderGreek(PPaintContext renderContext) { @@ -387,8 +430,10 @@ manager.lockRepaint(component); RenderingHints oldHints = g2.getRenderingHints(); - + g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + component.paint(g2); g2.setRenderingHints(oldHints); @@ -399,7 +444,7 @@ public void setVisible(boolean visible) { super.setVisible(visible); component.setVisible(visible); - } + } /** * Repaints the specified portion of this visual component Note that the @@ -419,14 +464,7 @@ * copy of these bounds */ public void computeBounds() { - reshape(); - // if( !component.getBounds().isEmpty() ) { - // Dimension d = component.getPreferredSize(); - // getBoundsReference().setRect( 0, 0, d.getWidth(), d.getHeight() ); - // if( !component.getSize().equals( d ) ) { - // component.setBounds( 0, 0, (int)d.getWidth(), (int)d.getHeight() ); - // } - // } + reshape(); } /** --~--~---------~--~----~------------~-------~--~----~ Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en -~----------~----~----~----~------~----~------~--~---