+ * Note that using glyph vector could slow-down the rendering performance. + * Note that if you are not using glyph vector then the text may be clipped when a scene has zoom factor different from 1.0. + * @param useGlyphVector if true, then a glyph vector is used for rendering text + */ + public void setUseGlyphVector (boolean useGlyphVector) { + if (this.useGlyphVector == useGlyphVector) + return; + this.useGlyphVector = useGlyphVector; + cacheGlyphVector = null; + cacheLabel = null; + cacheFont = null; + revalidate (); + } + + private void assureGlyphVector () { + Font font = getFont (); + FontRenderContext fontRenderContext = getGraphics ().getFontRenderContext (); + if (cacheGlyphVector != null && cacheFont == font && cacheLabel == label) + return; + cacheFont = font; + cacheLabel = label; + cacheGlyphVector = font.createGlyphVector (new FontRenderContext (new AffineTransform (), fontRenderContext.isAntiAliased (), fontRenderContext.usesFractionalMetrics ()), cacheLabel); + } + + /** * Calculates a client area for the label. * @return the client area */ protected Rectangle calculateClientArea () { if (label == null) return super.calculateClientArea (); - Graphics2D gr = getGraphics (); - FontMetrics fontMetrics = gr.getFontMetrics (getFont ()); - Rectangle2D stringBounds = fontMetrics.getStringBounds (label, gr); - Rectangle rectangle = GeomUtil.roundRectangle (stringBounds); + Rectangle rectangle; + if (useGlyphVector) { + assureGlyphVector (); + rectangle = GeomUtil.roundRectangle (cacheGlyphVector.getVisualBounds ()); + rectangle.grow (1, 1); // WORKAROUND - even text antialiasing is included into the boundary + } else { + Graphics2D gr = getGraphics (); + FontMetrics fontMetrics = gr.getFontMetrics (getFont ()); + Rectangle2D stringBounds = fontMetrics.getStringBounds (label, gr); + rectangle = GeomUtil.roundRectangle (stringBounds); + } switch (orientation) { case NORMAL: return rectangle; @@ -201,7 +250,10 @@ if (label == null) return; Graphics2D gr = getGraphics (); - gr.setFont (getFont ()); + if (useGlyphVector) + assureGlyphVector (); + else + gr.setFont (getFont ()); FontMetrics fontMetrics = gr.getFontMetrics (); Rectangle clientArea = getClientArea (); @@ -220,10 +272,16 @@ x = clientArea.x; break; case CENTER: - x = clientArea.x + (clientArea.width - fontMetrics.stringWidth (label)) / 2; + if (useGlyphVector) + x = clientArea.x + (clientArea.width - getCacheGlyphVectorWidth ()) / 2; + else + x = clientArea.x + (clientArea.width - fontMetrics.stringWidth (label)) / 2; break; case RIGHT: - x = clientArea.x + clientArea.width - fontMetrics.stringWidth (label); + if (useGlyphVector) + x = clientArea.x + clientArea.width - getCacheGlyphVectorWidth (); + else + x = clientArea.x + clientArea.width - fontMetrics.stringWidth (label); break; default: return; @@ -271,10 +329,16 @@ y = 0; break; case TOP: + if (useGlyphVector) + y = clientArea.y + getCacheGlyphVectorWidth (); + else y = clientArea.y + fontMetrics.stringWidth (label); break; case CENTER: - y = clientArea.y + (clientArea.height + fontMetrics.stringWidth (label)) / 2; + if (useGlyphVector) + y = clientArea.y + (clientArea.height + getCacheGlyphVectorWidth ()) / 2; + else + y = clientArea.y + (clientArea.height + fontMetrics.stringWidth (label)) / 2; break; case BOTTOM: y = clientArea.y + clientArea.height; @@ -304,15 +368,28 @@ if (paintAsDisabled && background instanceof Color) { Color color = ((Color) background); gr.setColor (color.brighter ()); - gr.drawString (label, 1, 1); + if (useGlyphVector) + gr.fill (cacheGlyphVector.getOutline (1, 1)); + else + gr.drawString (label, 1, 1); gr.setColor (color.darker ()); - gr.drawString (label, 0, 0); + if (useGlyphVector) + gr.fill (cacheGlyphVector.getOutline ()); + else + gr.drawString (label, 0, 0); } else { gr.setColor (getForeground ()); - gr.drawString (label, 0, 0); + if (useGlyphVector) + gr.fill (cacheGlyphVector.getOutline ()); + else + gr.drawString (label, 0, 0); } gr.setTransform(previousTransform); + } + + private int getCacheGlyphVectorWidth () { + return GeomUtil.roundRectangle (cacheGlyphVector.getVisualBounds ()).width; } } Index: graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html =================================================================== RCS file: /cvs/graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html,v --- graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html 1 Aug 2007 07:45:32 -0000 1.21 +++ graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html 1 Aug 2007 14:39:15 -0000 @@ -419,6 +419,9 @@
Since version 2.1 the LabelWidget allows rendering vertical labels. It can be set by calling LabelWidget.setOrientation
method. Default value is LabelWidget.Orientation.NORMAL
which renders labels horizontally. The other value is LabelWidget.Orientation.ROTATE_90
which makes the label to render vertically.
+
+Since version 2.8 the LabelWidget allows to use glyph-vector for rendering. This allows accurate text rendering independently on a scene zoom-factor (no more clipped text while zooming onto a scene). +
Index: graph/www/documentation.html =================================================================== RCS file: /cvs/graph/www/documentation.html,v --- graph/www/documentation.html 1 Aug 2007 14:23:16 -0000 1.98 +++ graph/www/documentation.html 1 Aug 2007 14:39:15 -0000 @@ -148,6 +148,7 @@
CycleObjectSceneFocusAction
+LabelWidget
rendering using glyph vector
LabelWidget