| /* QtGraphics.java -- |
| Copyright (C) 2005, 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package gnu.java.awt.peer.qt; |
| |
| import java.awt.AlphaComposite; |
| import java.awt.AWTPermission; |
| import java.awt.BasicStroke; |
| import java.awt.Color; |
| import java.awt.Composite; |
| import java.awt.GradientPaint; |
| import java.awt.GraphicsConfiguration; |
| import java.awt.Font; |
| import java.awt.FontMetrics; |
| import java.awt.Graphics; |
| import java.awt.Graphics2D; |
| import java.awt.Image; |
| import java.awt.RenderingHints; |
| import java.awt.Rectangle; |
| import java.awt.Paint; |
| import java.awt.Polygon; |
| import java.awt.Shape; |
| import java.awt.Stroke; |
| import java.awt.font.FontRenderContext; |
| import java.awt.font.GlyphVector; |
| import java.awt.geom.AffineTransform; |
| import java.awt.geom.Arc2D; |
| import java.awt.geom.Ellipse2D; |
| import java.awt.geom.Line2D; |
| import java.awt.geom.Rectangle2D; |
| import java.awt.geom.RoundRectangle2D; |
| import java.awt.image.BufferedImage; |
| import java.awt.image.BufferedImageOp; |
| import java.awt.image.ImageObserver; |
| import java.awt.image.RenderedImage; |
| import java.awt.image.renderable.RenderableImage; |
| |
| import java.text.AttributedCharacterIterator; |
| import java.text.CharacterIterator; |
| import java.util.Map; |
| |
| /** |
| * QtGraphics is an abstract implementation of Graphics2D over a QPainter |
| * object. This is to be subclassed for different drawing contexts, |
| * which may have different requirements. |
| */ |
| public abstract class QtGraphics extends Graphics2D |
| { |
| /** |
| * Native QPainter pointer. |
| */ |
| protected long nativeObject; |
| |
| private static final AffineTransform identity = new AffineTransform(); |
| |
| // Graphics state |
| protected Font font; // Current font. |
| protected Color color, bgcolor; // Current color and background color. |
| protected Shape clip; // Current clipping area. |
| protected Shape initialClip; // Initial clip bounds |
| protected AffineTransform xform; // Current transform |
| protected Stroke currentStroke; // the current stroke |
| protected boolean nativeStroking; // whether we're using Qt's stroking or not |
| protected Composite composite; // current composite operator |
| protected double currentAlpha; // current alpha |
| protected Paint currentPaint; // current paint |
| protected RenderingHints renderingHints; // the rendering hints. |
| |
| /** |
| * Owner Graphics, used by subcontext created by create() |
| * to avoid GC of the original context. |
| */ |
| Graphics parent; |
| |
| /** |
| * Do-nothing constructor. |
| */ |
| QtGraphics() |
| { |
| } |
| |
| /** |
| * Copying constructor - used by copy() and subclasses. |
| */ |
| QtGraphics(QtGraphics parent) |
| { |
| cloneNativeContext( parent ); |
| setFont( parent.getFont() ); |
| setAlpha( parent.currentAlpha ); |
| setBackground( parent.getBackground() ); |
| setColor( parent.getColor() ); |
| setClip( (initialClip = parent.getClip()) ); |
| setTransform( parent.getTransform() ); |
| setStroke( parent.getStroke() ); |
| setComposite( parent.getComposite() ); |
| setPaint( parent.getPaint() ); |
| setRenderingHints( parent.getRenderingHints() ); |
| } |
| |
| /** |
| * Set up some generic defaults. |
| */ |
| protected void setup() |
| { |
| font = new Font ("Dialog", Font.PLAIN, 12); |
| setTransform( identity ); |
| setStroke( new BasicStroke() ); |
| renderingHints = new RenderingHints( null ); |
| } |
| |
| public synchronized native void delete(); |
| |
| public void dispose() |
| { |
| } |
| |
| // ********************** etc ******************************* |
| |
| private void resetClip() |
| { |
| AffineTransform current = getTransform(); |
| setTransform( identity ); |
| setClip( initialClip ); |
| setTransform( current ); |
| } |
| |
| protected native void initImage(QtImage image); |
| protected native void initVolatileImage(QtVolatileImage image); |
| |
| // Creates a new native QPainter object on the same context. |
| private native void cloneNativeContext( QtGraphics parent ); |
| private native void setColor(int r, int g, int b, int a); |
| private native void drawNative( QPainterPath p ); |
| private native void fillNative( QPainterPath p ); |
| private native void setClipNative( QPainterPath p ); |
| private native void setClipRectNative( int x, int y, int w, int h ); |
| private native void intersectClipNative( QPainterPath p ); |
| private native void intersectClipRectNative( int x, int y, int w, int h ); |
| private native void setQtTransform(QMatrix m); |
| private native void setNativeStroke(QPen p); |
| private native void setNativeComposite(int alphaMode); |
| private native void drawStringNative(String string, double x, double y); |
| private native void setLinearGradient(int r1, int g1, int b1, |
| int r2, int g2, int b2, |
| double x1, double y1, |
| double x2, double y2, boolean cyclic); |
| private native void setAlphaNative(double alpha); |
| private native void setFontNative(QtFontPeer font); |
| private native QPainterPath getClipNative(); |
| |
| void setAlpha(double alpha) |
| { |
| currentAlpha = alpha; |
| setAlphaNative(currentAlpha); |
| } |
| |
| // ************ Public methods ********************* |
| |
| /** |
| * Context-sensitive methods are declared abstract. |
| */ |
| public abstract Graphics create(); |
| |
| public abstract void copyArea(int x, int y, int width, int height, |
| int dx, int dy); |
| |
| public abstract GraphicsConfiguration getDeviceConfiguration(); |
| |
| |
| public Color getColor() |
| { |
| return new Color(color.getRed(), color.getGreen(), color.getBlue()); |
| } |
| |
| public void setColor(Color c) |
| { |
| if( c == null ) |
| c = Color.white; |
| this.color = c; |
| int alpha = (int)(c.getAlpha() * currentAlpha); |
| setColor(c.getRed(), c.getGreen(), c.getBlue(), alpha); |
| } |
| |
| public void setBackground(Color color) |
| { |
| bgcolor = new Color(color.getRed(), color.getGreen(), color.getBlue()); |
| } |
| |
| public Color getBackground() |
| { |
| return new Color(bgcolor.getRed(), bgcolor.getGreen(), bgcolor.getBlue()); |
| } |
| |
| public void setPaintMode() |
| { |
| } |
| |
| public void setXORMode(Color color) |
| { |
| // FIXME |
| } |
| |
| public boolean hit(Rectangle rect, Shape s, boolean onStroke) |
| { |
| if( onStroke ) |
| { |
| Shape stroked = currentStroke.createStrokedShape( s ); |
| return stroked.intersects( (double)rect.x, (double)rect.y, |
| (double)rect.width, (double)rect.height ); |
| } |
| return s.intersects( (double)rect.x, (double)rect.y, |
| (double)rect.width, (double)rect.height ); |
| } |
| |
| // ******************* Font *********************** |
| public Font getFont() |
| { |
| return font; |
| } |
| |
| public void setFont(Font font) |
| { |
| if( font == null ) |
| return; |
| this.font = font; |
| if(font.getPeer() != null && font.getPeer() instanceof QtFontPeer) |
| setFontNative( (QtFontPeer)font.getPeer() ); |
| } |
| |
| public FontMetrics getFontMetrics(Font font) |
| { |
| return new QtFontMetrics(font, this); |
| } |
| |
| // ***************** Clipping ********************* |
| |
| /** |
| * Intersects the current clip with the shape |
| */ |
| public void clip(Shape s) |
| { |
| intersectClipNative( new QPainterPath( s ) ); |
| } |
| |
| public void clipRect(int x, int y, int width, int height) |
| { |
| intersectClipRectNative( x, y, width, height ); |
| } |
| |
| public void setClip(int x, int y, int width, int height) |
| { |
| setClipRectNative( x, y, width, height ); |
| } |
| |
| public Shape getClip() |
| { |
| return getClipNative().getPath(); |
| } |
| |
| public native Rectangle getClipBounds(); |
| |
| /** |
| * Sets the clip |
| */ |
| public void setClip(Shape clip) |
| { |
| if (clip == null) |
| resetClip(); |
| else |
| setClipNative(new QPainterPath( clip )); |
| } |
| |
| // ***************** Drawing primitives ********************* |
| |
| public void draw(Shape s) |
| { |
| if( nativeStroking ) |
| drawNative( new QPainterPath(s) ); |
| else |
| fillNative( new QPainterPath( currentStroke.createStrokedShape( s ) ) ); |
| } |
| |
| public void fill(Shape s) |
| { |
| fillNative( new QPainterPath(s) ); |
| } |
| |
| public void drawLine(int x1, int y1, int x2, int y2) |
| { |
| if( nativeStroking ) |
| drawNative( new QPainterPath((double)x1, (double)y1, (double)x2, (double)y2, true) ); |
| else |
| draw( new Line2D.Double((double)x1, (double)y1, (double)x2, (double)y2) ); |
| } |
| |
| public void drawRect(int x, int y, int width, int height) |
| { |
| if( nativeStroking ) |
| drawNative( new QPainterPath((double)x, (double)y, |
| (double)width, (double)height) ); |
| else |
| fillNative( new QPainterPath |
| ( currentStroke.createStrokedShape |
| (new Rectangle2D.Double |
| ((double)x, (double)y, |
| (double)width, (double)height) ) ) ); |
| } |
| |
| public void fillRect(int x, int y, int width, int height) |
| { |
| fillNative( new QPainterPath( x, y, width, height ) ); |
| } |
| |
| public void clearRect(int x, int y, int width, int height) |
| { |
| Color c = color; |
| setColor( bgcolor ); // FIXME |
| fillRect( x, y, width, height ); |
| setColor( c ); |
| } |
| |
| public void drawRoundRect(int x, int y, int width, int height, |
| int arcWidth, int arcHeight) |
| { |
| draw( new RoundRectangle2D.Double(x, y, width, height, |
| arcWidth, arcHeight) ); |
| } |
| |
| public void fillRoundRect(int x, int y, int width, int height, |
| int arcWidth, int arcHeight) |
| { |
| fill( new RoundRectangle2D.Double(x, y, width, height, |
| arcWidth, arcHeight) ); |
| } |
| |
| public void drawOval(int x, int y, int width, int height) |
| { |
| draw( new Ellipse2D.Double((double)x, (double)y, |
| (double)width, (double)height) ); |
| } |
| |
| public void fillOval(int x, int y, int width, int height) |
| { |
| fill( new Ellipse2D.Double(x, y, width, height) ); |
| } |
| |
| public void drawArc(int x, int y, int width, int height, |
| int arcStart, int arcAngle) |
| { |
| draw( new Arc2D.Double(x, y, width, height, arcStart, arcAngle, |
| Arc2D.OPEN) ); |
| } |
| |
| public void fillArc(int x, int y, int width, int height, |
| int arcStart, int arcAngle) |
| { |
| fill( new Arc2D.Double(x, y, width, height, arcStart, arcAngle, |
| Arc2D.CHORD) ); |
| } |
| |
| public void drawPolyline(int xPoints[], int yPoints[], int npoints) |
| { |
| for( int i = 0; i < npoints - 1; i++) |
| drawLine(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1]); |
| } |
| |
| public void drawPolygon(int xPoints[], int yPoints[], int npoints) |
| { |
| draw( new Polygon(xPoints, yPoints, npoints) ); |
| } |
| |
| public void fillPolygon(int xPoints[], int yPoints[], int npoints) |
| { |
| fill( new Polygon(xPoints, yPoints, npoints) ); |
| } |
| |
| public native void fill3DRect(int x, int y, int width, int height, boolean raised); |
| |
| public native void draw3DRect(int x, int y, int width, int height, boolean raised); |
| |
| // *********************** Text rendering ************************* |
| |
| public void drawString(String string, int x, int y) |
| { |
| drawStringNative(string, (double)x, (double)y); |
| } |
| |
| public void drawString(String string, float x, float y) |
| { |
| drawStringNative(string, (double)x, (double)y); |
| } |
| |
| public void drawString (AttributedCharacterIterator ci, int x, int y) |
| { |
| // FIXME - to something more correct ? |
| String s = ""; |
| for(char c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) |
| s += c; |
| drawString(s, x, y); |
| } |
| |
| public void drawString(AttributedCharacterIterator ci, |
| float x, float y) |
| { |
| // FIXME - to something more correct ? |
| String s = ""; |
| for(char c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) |
| s += c; |
| drawString(s, x, y); |
| } |
| |
| public void drawGlyphVector(GlyphVector v, float x, float y) |
| { |
| throw new RuntimeException("Not implemented"); |
| } |
| |
| // ******************* Image drawing ****************************** |
| public boolean drawImage(Image image, |
| AffineTransform Tx, |
| ImageObserver obs) |
| { |
| if (image instanceof QtImage) |
| return ((QtImage)image).drawImage(this, new QMatrix( Tx ), obs); |
| |
| return (new QtImage(image.getSource())).drawImage(this, |
| new QMatrix( Tx ), |
| obs); |
| } |
| |
| public boolean drawImage(Image image, int x, int y, Color bgcolor, |
| ImageObserver observer) |
| { |
| if (image instanceof QtImage) |
| return ((QtImage)image).drawImage (this, x, y, bgcolor, observer); |
| return (new QtImage(image.getSource())).drawImage (this, x, y, |
| bgcolor, observer); |
| } |
| |
| public boolean drawImage(Image image, |
| int dx1, int dy1, int dx2, int dy2, |
| int sx1, int sy1, int sx2, int sy2, |
| Color bgcolor, ImageObserver observer) |
| { |
| if (image instanceof QtImage) |
| return ((QtImage)image).drawImage(this, dx1, dy1, dx2, dy2, |
| sx1, sy1, sx2, sy2, bgcolor, observer); |
| |
| return (new QtImage(image.getSource())).drawImage(this, dx1, dy1, |
| dx2, dy2, |
| sx1, sy1, sx2, sy2, |
| bgcolor, observer); |
| } |
| |
| public boolean drawImage(Image image, int x, int y, |
| int width, int height, Color bgcolor, |
| ImageObserver observer) |
| { |
| if (image instanceof QtImage) |
| return ((QtImage)image).drawImage (this, x, y, width, height, |
| bgcolor, observer); |
| return (new QtImage(image.getSource())).drawImage (this, x, y, |
| width, height, |
| bgcolor, observer); |
| } |
| |
| public boolean drawImage(Image image, int x, int y, int width, int height, |
| ImageObserver observer) |
| { |
| return drawImage(image, x, y, width, height, null, observer); |
| } |
| |
| public boolean drawImage(Image image, int x, int y, ImageObserver observer) |
| { |
| return drawImage(image, x, y, null, observer); |
| } |
| |
| public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) |
| { |
| return drawImage(image, dx1, dy1, dx2, dy2, |
| sx1, sy1, sx2, sy2, null, observer); |
| } |
| |
| // *********************** Transform methods ************************* |
| public AffineTransform getTransform() |
| { |
| return new AffineTransform( xform ); |
| } |
| |
| public void setTransform(AffineTransform Tx) |
| { |
| xform = new AffineTransform( Tx ); |
| setQtTransform( new QMatrix( xform ) ); |
| } |
| |
| public void rotate(double theta) |
| { |
| xform.rotate( theta ); |
| setQtTransform( new QMatrix( xform ) ); |
| } |
| |
| public void rotate(double theta, double x, double y) |
| { |
| xform.rotate(theta, x, y); |
| setQtTransform( new QMatrix( xform ) ); |
| } |
| |
| public void scale(double sx, double sy) |
| { |
| xform.scale(sx, sy); |
| setQtTransform( new QMatrix( xform ) ); |
| } |
| |
| public void shear(double shx, double shy) |
| { |
| xform.shear(shx, shy); |
| setQtTransform( new QMatrix( xform ) ); |
| } |
| |
| public void transform(AffineTransform Tx) |
| { |
| xform.concatenate( Tx ); |
| setQtTransform( new QMatrix( xform ) ); |
| } |
| |
| public void translate(double tx, double ty) |
| { |
| xform.translate( tx, ty ); |
| setQtTransform( new QMatrix( xform ) ); |
| } |
| |
| public void translate(int x, int y) |
| { |
| translate((double)x, (double)y); |
| } |
| |
| // *************** Stroking, Filling, Compositing ***************** |
| public void setStroke(Stroke s) |
| { |
| try // ..to convert the stroke into a native one. |
| { |
| QPen pen = new QPen( s ); |
| nativeStroking = true; |
| setNativeStroke( pen ); |
| setColor( color ); |
| } |
| catch (IllegalArgumentException e) |
| { |
| nativeStroking = false; |
| } |
| currentStroke = s; |
| } |
| |
| public Stroke getStroke() |
| { // FIXME: return copy? |
| return currentStroke; |
| } |
| |
| public void setComposite(Composite comp) |
| { |
| if( comp == null) |
| { |
| setNativeComposite( AlphaComposite.SRC_OVER ); |
| return; |
| } |
| |
| if( comp instanceof AlphaComposite ) |
| { |
| if( ((AlphaComposite)comp).getRule() != AlphaComposite.XOR ) |
| setAlpha( ((AlphaComposite)comp).getAlpha() ); |
| setNativeComposite( ((AlphaComposite)comp).getRule() ); |
| composite = comp; |
| } |
| else |
| { |
| // FIXME: this check is only required "if this Graphics2D |
| // context is drawing to a Component on the display screen". |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) |
| sm.checkPermission(new AWTPermission("readDisplayPixels")); |
| |
| throw new UnsupportedOperationException("We don't support custom"+ |
| " composites yet."); |
| } |
| } |
| |
| public Composite getComposite() |
| { |
| return composite; |
| } |
| |
| public void setPaint(Paint p) |
| { |
| if( p == null ) |
| return; |
| |
| // FIXME |
| currentPaint = p; |
| if( p instanceof GradientPaint ) |
| { |
| GradientPaint lg = (GradientPaint)p; |
| setLinearGradient(lg.getColor1().getRed(), lg.getColor1().getGreen(), |
| lg.getColor1().getBlue(), lg.getColor2().getRed(), |
| lg.getColor2().getGreen(), lg.getColor2().getBlue(), |
| lg.getPoint1().getX(), lg.getPoint1().getY(), |
| lg.getPoint2().getX(), lg.getPoint2().getY(), |
| lg.isCyclic() ); |
| return; |
| } |
| if( p instanceof Color ) |
| { |
| setColor((Color) p); |
| return; |
| } |
| throw new UnsupportedOperationException("We don't support custom"+ |
| " paints yet."); |
| } |
| |
| public Paint getPaint() |
| { |
| // FIXME |
| return currentPaint; |
| } |
| |
| // ********************** Rendering Hints ************************* |
| |
| public void addRenderingHints(Map hints) |
| { |
| renderingHints.putAll( hints ); |
| } |
| |
| public Object getRenderingHint(RenderingHints.Key hintKey) |
| { |
| return renderingHints.get( hintKey ); |
| } |
| |
| public RenderingHints getRenderingHints() |
| { |
| return new RenderingHints( renderingHints ); |
| } |
| |
| public void setRenderingHints(Map hints) |
| { |
| renderingHints = new RenderingHints( hints ); |
| updateRenderingHints(); |
| } |
| |
| public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) |
| { |
| renderingHints.put( hintKey, hintValue ); |
| updateRenderingHints(); |
| } |
| |
| private void updateRenderingHints() |
| { |
| // FIXME - update native settings. |
| } |
| |
| ////////////////////////////// unimplemented ///////////////////// |
| |
| public FontRenderContext getFontRenderContext() |
| { |
| throw new UnsupportedOperationException("Not implemented yet"); |
| } |
| |
| public void drawRenderableImage(RenderableImage image, AffineTransform xform) |
| { |
| throw new UnsupportedOperationException("Not implemented yet"); |
| } |
| |
| public void drawRenderedImage(RenderedImage image, AffineTransform xform) |
| { |
| throw new UnsupportedOperationException("Not implemented yet"); |
| } |
| |
| public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) |
| { |
| throw new UnsupportedOperationException("Not implemented yet"); |
| } |
| } |
| |