All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codename1.ui.Graphics Maven / Gradle / Ivy

There is a newer version: 7.0.164
Show newest version
/*
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores
 * CA 94065 USA or visit www.oracle.com if you need additional information or
 * have any questions.
 */
package com.codename1.ui;

import com.codename1.ui.geom.GeneralPath;
import com.codename1.impl.CodenameOneImplementation;
import com.codename1.ui.geom.Rectangle;
import com.codename1.ui.geom.Shape;

/**
 * Abstracts the underlying platform graphics context thus allowing us to achieve
 * portability between MIDP devices and CDC devices. This abstaction simplifies
 * and unifies the Graphics implementations of various platforms.
 * 
 * 

A graphics instance should never be created by the developer and is always accessed * using either a paint callback or a mutable image. There is no supported way to create this * object directly. */ public final class Graphics { /** * Flag that specifies that native peers are rendered "behind" the this * graphics context. The main difference is that drawPeerComponent() will * call clearRect() for its bounds to "poke a hole" in the graphics context * to see through to the native layer. */ boolean paintPeersBehind; private int xTranslate; private int yTranslate; private Transform translation; private GeneralPath tmpClipShape; /// A buffer shape to use when we need to transform a shape private int color; private Paint paint; private Font current = Font.getDefaultFont(); private CodenameOneImplementation impl; private Object nativeGraphics; private Object[] nativeGraphicsState; private float scaleX = 1, scaleY = 1; /** * Rendering hint to indicate that the context should prefer to render * primitives in a quick way, at the cost of quality, if there is an * expensive operation. * @see #setRenderingHints(int) * @see #getRenderingHints() * @since 7.0 */ public static final int RENDERING_HINT_FAST=1; /** * Constructing new graphics with a given javax.microedition.lcdui.Graphics * @param g an implementation dependent native graphics instance */ Graphics(Object nativeGraphics) { setGraphics(nativeGraphics); impl = Display.impl; } protected void finalize() { if (nativeGraphics != null) { impl.disposeGraphics(nativeGraphics); } } private Transform translation() { if (translation == null) { translation = Transform.makeTranslation(xTranslate, yTranslate); } else { translation.setTranslation(xTranslate, yTranslate); } return translation; } private GeneralPath tmpClipShape() { if (tmpClipShape == null) { tmpClipShape = new GeneralPath(); } return tmpClipShape; } /** * Setting graphics with a given javax.microedition.lcdui.Graphics * * @param g a given javax.microedition.lcdui.Graphics */ void setGraphics(Object g) { this.nativeGraphics = g; } /** * Returns the underlying native graphics object * * @return the underlying native graphics object */ Object getGraphics() { return nativeGraphics; } /** * Translates the X/Y location for drawing on the underlying surface. Translation * is incremental so the new value will be added to the current translation and * in order to reset translation we have to invoke * {@code translate(-getTranslateX(), -getTranslateY()) } * * @param x the x coordinate * @param y the y coordinate */ public void translate(int x, int y) { if(impl.isTranslationSupported()) { impl.translate(nativeGraphics, x, y); } else { xTranslate += x; yTranslate += y; } } /** * Returns the current x translate value * * @return the current x translate value */ public int getTranslateX() { if(impl.isTranslationSupported()) { return impl.getTranslateX(nativeGraphics); } else { return xTranslate; } } /** * Returns the current y translate value * * @return the current y translate value */ public int getTranslateY() { if(impl.isTranslationSupported()) { return impl.getTranslateY(nativeGraphics); } else { return yTranslate; } } /** * Returns the current color * * @return the RGB graphics color */ public int getColor() { return color; } /** * Gets the current {@link Paint} that is set to be used for filling shapes. * * @return The paint that is to be used for filling shapes. * @since 7.0 * @see LinearGradientPaint */ public Paint getPaint() { return paint; } /** * Sets the current rgb color while ignoring any potential alpha component within * said color value. * * @param RGB the RGB value for the color. */ public void setColor(int RGB) { paint = null; color = 0xffffff & RGB; impl.setColor(nativeGraphics, color); } /** * Sets the current rgb color while ignoring any potential alpha component within * said color value. * * @param RGB the RGB value for the color. * @return The previous color value. * @since 8.0 */ public int setAndGetColor(int RGB) { int old = getColor(); setColor(RGB); return old; } /** * Sets paint to be used for filling shapes. This is only used for the {@link #fillShape(com.codename1.ui.geom.Shape) } method. * @param paint * @since 7.0 * @see LinearGradientPaint */ public void setColor(Paint paint) { this.paint = paint; } /** * Returns the font used with the drawString method calls * * @return the font used with the drawString method calls */ public Font getFont() { return current; } /** * Sets the font to use with the drawString method calls * * @param font the font used with the drawString method calls */ public void setFont(Font font) { this.current = font; if(!(font instanceof CustomFont)) { impl.setNativeFont(nativeGraphics, font.getNativeFont()); } } /** * Returns the x clipping position * * @return the x clipping position */ public int getClipX() { return impl.getClipX(nativeGraphics) - xTranslate; } /** * Returns the clip as an x,y,w,h array * @return clip array copy */ public int[] getClip() { return new int[] {getClipX(), getClipY(), getClipWidth(), getClipHeight()}; } /** * Sets the clip from an array containing x, y, width, height value * @param clip 4 element array */ public void setClip(int[] clip) { setClip(clip[0], clip[1], clip[2], clip[3]); } /** * Returns the y clipping position * * @return the y clipping position */ public int getClipY() { return impl.getClipY(nativeGraphics) - yTranslate; } /** * Returns the clip width * * @return the clip width */ public int getClipWidth() { return impl.getClipWidth(nativeGraphics); } /** * Returns the clip height * * @return the clip height */ public int getClipHeight() { return impl.getClipHeight(nativeGraphics); } /** * Clips the given rectangle by intersecting with the current clipping region, this * method can thus only shrink the clipping region and never increase it. * * @param x the x coordinate of the rectangle to intersect the clip with * @param y the y coordinate of the rectangle to intersect the clip with * @param width the width of the rectangle to intersect the clip with * @param height the height of the rectangle to intersect the clip with */ public void clipRect(int x, int y, int width, int height) { impl.clipRect(nativeGraphics, xTranslate + x, yTranslate + y, width, height); } /** * Updates the clipping region to match the given region exactly * * @param x the x coordinate of the new clip rectangle. * @param y the y coordinate of the new clip rectangle. * @param width the width of the new clip rectangle. * @param height the height of the new clip rectangle. */ public void setClip(int x, int y, int width, int height) { impl.setClip(nativeGraphics, xTranslate + x, yTranslate + y, width, height); } /** * Clips the Graphics context to the Shape. *

This is not supported on all platforms and contexts currently. * Use {@link #isShapeClipSupported} to check if the current * context supports clipping shapes.

* * * Shaped clipping in action * * @param shape The shape to clip. * @see #isShapeClipSupported */ public void setClip(Shape shape) { if (xTranslate != 0 || yTranslate != 0) { GeneralPath p = tmpClipShape(); p.setShape(shape, translation()); shape = p; } impl.setClip(nativeGraphics, shape); } /** * Pushes the current clip onto the clip stack. It can later be restored * using {@link #popClip}. */ public void pushClip(){ impl.pushClip(nativeGraphics); } /** * Pops the top clip from the clip stack and sets it as the current clip. */ public void popClip(){ impl.popClip(nativeGraphics); } /** * Draws a line between the 2 X/Y coordinates * * @param x1 first x position * @param y1 first y position * @param x2 second x position * @param y2 second y position */ public void drawLine(int x1, int y1, int x2, int y2) { impl.drawLine(nativeGraphics, xTranslate + x1, yTranslate + y1, xTranslate + x2, yTranslate + y2); } /** * Fills the rectangle from the given position according to the width/height * minus 1 pixel according to the convention in Java. * * @param x the x coordinate of the rectangle to be filled. * @param y the y coordinate of the rectangle to be filled. * @param width the width of the rectangle to be filled. * @param height the height of the rectangle to be filled. */ public void fillRect(int x, int y, int width, int height) { impl.fillRect(nativeGraphics, xTranslate + x, yTranslate + y, width, height); } public void drawShadow(Image img, int x, int y, int offsetX, int offsetY, int blurRadius, int spreadRadius, int color, float opacity) { impl.drawShadow(nativeGraphics, img.getImage(), xTranslate + x, yTranslate + y, offsetX, offsetY, blurRadius, spreadRadius, color, opacity); } /** * Clears rectangular area of the graphics context. This will remove any color * information that has already been drawn to the graphics context making it transparent. *

The difference between this method and say {@link #fillRect(int, int, int, int) } with alpha=0 is * that fillRect() will just blend with the colors underneath (and thus {@link #fillRect(int, int, int, int) } * with an alpha of 0 actually does nothing.

* NOTE: In contrast to other drawing methods, coordinates input here * are absolute and will not be adjusted by the xTranslate and yTranslate values * *

This method is designed to be used by {@link #drawPeerComponent(com.codename1.ui.PeerComponent) } only.

* @param x The x-coordinate of the box to clear. In screen coordinates. * @param y The y-coordinate of the box to clear. In screen coordinates. * @param width The width of the box to clear. * @param height The height of the box to clear. */ public void clearRect(int x, int y, int width, int height) { clearRectImpl(xTranslate + x, yTranslate + y, width, height);; } /** * Clears rectangular area of the graphics context. This will remove any color * information that has already been drawn to the graphics context making it transparent. *

The difference between this method and say {@link #fillRect(int, int, int, int) } with alpha=0 is * that fillRect() will just blend with the colors underneath (and thus {@link #fillRect(int, int, int, int) } * with an alpha of 0 actually does nothing.

* NOTE: In contrast to other drawing methods, coordinates input here * are absolute and will not be adjusted by the xTranslate and yTranslate values * *

This method is designed to be used by {@link #drawPeerComponent(com.codename1.ui.PeerComponent) } only.

* @param x The x-coordinate of the box to clear. In screen coordinates. * @param y The y-coordinate of the box to clear. In screen coordinates. * @param width The width of the box to clear. * @param height The height of the box to clear. */ private void clearRectImpl(int x, int y, int width, int height) { impl.clearRect(nativeGraphics, x, y, width, height); } /** * Draws a rectangle in the given coordinates * * @param x the x coordinate of the rectangle to be drawn. * @param y the y coordinate of the rectangle to be drawn. * @param width the width of the rectangle to be drawn. * @param height the height of the rectangle to be drawn. */ public void drawRect(int x, int y, int width, int height) { impl.drawRect(nativeGraphics, xTranslate + x, yTranslate + y, width, height); } /** * Draws a rectangle in the given coordinates with the given thickness * * @param x the x coordinate of the rectangle to be drawn. * @param y the y coordinate of the rectangle to be drawn. * @param width the width of the rectangle to be drawn. * @param height the height of the rectangle to be drawn. * @param thickness the thickness in pixels */ public void drawRect(int x, int y, int width, int height, int thickness) { impl.drawRect(nativeGraphics, xTranslate + x, yTranslate + y, width, height, thickness); } /** * Draws a rounded corner rectangle in the given coordinates with the arcWidth/height * matching the last two arguments respectively. * * @param x the x coordinate of the rectangle to be drawn. * @param y the y coordinate of the rectangle to be drawn. * @param width the width of the rectangle to be drawn. * @param height the height of the rectangle to be drawn. * @param arcWidth the horizontal diameter of the arc at the four corners. * @param arcHeight the vertical diameter of the arc at the four corners. */ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { impl.drawRoundRect(nativeGraphics, xTranslate + x, yTranslate + y, width, height, arcWidth, arcHeight); } /** * Makes the current color slightly lighter, this is useful for many visual effects * * @param factor the degree of lightening a color per channel a number from 1 to 255 */ public void lighterColor(int factor) { int color = getColor(); int r = color >> 16 & 0xff; int g = color >> 8 & 0xff; int b = color & 0xff; r = Math.min(0xff, r + factor); g = Math.min(0xff, g + factor); b = Math.min(0xff, b + factor); setColor(((r << 16) & 0xff0000) | ((g << 8) & 0xff00) | (b & 0xff)); } /** * Makes the current color slightly darker, this is useful for many visual effects * * @param factor the degree of lightening a color per channel a number from 1 to 255 */ public void darkerColor(int factor) { int color = getColor(); int r = color >> 16 & 0xff; int g = color >> 8 & 0xff; int b = color & 0xff; r = Math.max(0, r - factor); g = Math.max(0, g - factor); b = Math.max(0, b - factor); setColor(((r << 16) & 0xff0000) | ((g << 8) & 0xff00) | (b & 0xff)); } /** * Fills a rounded rectangle in the same way as drawRoundRect * * @param x the x coordinate of the rectangle to be filled. * @param y the y coordinate of the rectangle to be filled. * @param width the width of the rectangle to be filled. * @param height the height of the rectangle to be filled. * @param arcWidth the horizontal diameter of the arc at the four corners. * @param arcHeight the vertical diameter of the arc at the four corners. * @see #drawRoundRect */ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { impl.fillRoundRect(nativeGraphics, xTranslate + x, yTranslate + y, width, height, arcWidth, arcHeight); } /** * Fills a circular or elliptical arc based on the given angles and bounding * box. The resulting arc begins at startAngle and extends for arcAngle * degrees. Usage: * * * * @param x the x coordinate of the upper-left corner of the arc to be filled. * @param y the y coordinate of the upper-left corner of the arc to be filled. * @param width the width of the arc to be filled, must be 1 or more. * @param height the height of the arc to be filled, must be 1 or more. * @param startAngle the beginning angle. * @param arcAngle the angular extent of the arc, relative to the start angle. */ public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { if(width < 1 || height < 1) { throw new IllegalArgumentException("Width & Height of fillAsrc must be greater than 0"); } impl.fillArc(nativeGraphics, xTranslate + x, yTranslate + y, width, height, startAngle, arcAngle); } /** * Draws a circular or elliptical arc based on the given angles and bounding * box * * @param x the x coordinate of the upper-left corner of the arc to be drawn. * @param y the y coordinate of the upper-left corner of the arc to be drawn. * @param width the width of the arc to be drawn. * @param height the height of the arc to be drawn. * @param startAngle the beginning angle. * @param arcAngle the angular extent of the arc, relative to the start angle. */ public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { impl.drawArc(nativeGraphics, xTranslate + x, yTranslate + y, width, height, startAngle, arcAngle); } private void drawStringImpl(String str, int x, int y) { // remove a commonly used trick to create a spacer label from the paint queue if(str.length() == 0 || (str.length() == 1 && str.charAt(0) == ' ')) { return; } if(!(current instanceof CustomFont)) { impl.drawString(nativeGraphics, str, x + xTranslate, y + yTranslate); } else { current.drawString(this, str, x, y); } } /** * Draw a string using the current font and color in the x,y coordinates. The font is drawn * from the top position and not the baseline. * * @param str the string to be drawn. * @param x the x coordinate. * @param y the y coordinate. * @param textDecoration Text decoration bitmask (See Style's TEXT_DECORATION_* constants) */ public void drawString(String str, int x, int y,int textDecoration) { // remove a commonly used trick to create a spacer label from the paint queue if(str.length() == 0 || (str.length() == 1 && str.charAt(0) == ' ')) { return; } Object nativeFont = null; if(current != null) { nativeFont = current.getNativeFont(); } if (current instanceof CustomFont) { current.drawString(this, str, x, y); } else { impl.drawString(nativeGraphics, nativeFont, str, x + xTranslate, y + yTranslate, textDecoration); } } /** * Draws a string using baseline coordinates. * @param str The string to be drawn. * @param x The x-coordinate of the start of left edge of the text block. * @param y The y-coordinate of the baseline of the text. * @see #drawString(java.lang.String, int, int) */ public void drawStringBaseline(String str, int x, int y){ drawString(str, x, y-current.getAscent()); } /** * Draws a string using baseline coordinates. * @param str The string to be drawn. * @param x The x-coordinate of the start of left edge of the text block. * @param y The y-coordinate of the baseline of the text. * @param textDecoration Text decoration bitmask (See Style's TEXT_DECORATION_* constants) * @see #drawString(java.lang.String, int, int, int) */ public void drawStringBaseline(String str, int x, int y, int textDecoration){ drawString(str, x, y-current.getAscent(), textDecoration); } /** * Draw a string using the current font and color in the x,y coordinates. The font is drawn * from the top position and not the baseline. * * @param str the string to be drawn. * @param x the x coordinate. * @param y the y coordinate. */ public void drawString(String str, int x, int y) { drawString(str, x, y, 0); } /** * Draw the given char using the current font and color in the x,y * coordinates. The font is drawn from the top position and not the * baseline. * * @param character - the character to be drawn * @param x the x coordinate of the baseline of the text * @param y the y coordinate of the baseline of the text */ public void drawChar(char character, int x, int y) { drawString("" + character, x, y); } /** * Draw the given char array using the current font and color in the x,y coordinates. The font is drawn * from the top position and not the baseline. * * @param data the array of characters to be drawn * @param offset the start offset in the data * @param length the number of characters to be drawn * @param x the x coordinate of the baseline of the text * @param y the y coordinate of the baseline of the text */ public void drawChars(char[] data, int offset, int length, int x, int y) { if(!(current instanceof CustomFont)) { drawString(new String(data, offset, length), x, y); } else { CustomFont f = (CustomFont)current; f.drawChars(this, data, offset, length, x, y); } } /** * Draws the image so its top left coordinate corresponds to x/y * * @param img the specified image to be drawn. This method does * nothing if img is null. * @param x the x coordinate. * @param y the y coordinate. */ public void drawImage(Image img, int x, int y) { img.drawImage(this, nativeGraphics, x, y); } /** * Draws the image so its top left coordinate corresponds to x/y and scales it to width/height * * @param img the specified image to be drawn. This method does * nothing if img is null. * @param x the x coordinate. * @param y the y coordinate. * @param w the width to occupy * @param h the height to occupy */ public void drawImage(Image img, int x, int y, int w ,int h) { if(impl.isScaledImageDrawingSupported()) { img.drawImage(this, nativeGraphics, x, y, w, h); } else { drawImage(img.scaled(w, h), x, y); } } void drawImageWH(Object nativeImage, int x, int y, int w ,int h) { impl.drawImage(nativeGraphics, nativeImage, x + xTranslate, y + yTranslate, w, h); } void drawImage(Object img, int x, int y) { impl.drawImage(nativeGraphics, img, x + xTranslate, y + yTranslate); } /** * Draws an image with a MIDP trasnform for fast rotation */ void drawImage(Object img, int x, int y, int transform) { if (transform != 0) { impl.drawImageRotated(nativeGraphics, img, x + xTranslate, y + yTranslate, transform); } else { drawImage(img, x, y); } } //-------------------------------------------------------------------------- // START SHAPE DRAWING STUFF //-------------------------------------------------------------------------- /** * Draws a outline shape inside the specified bounding box. The bounding box will resize the shape to fit in its dimensions. *

This is not supported on * all platforms and contexts currently. Use {@link #isShapeSupported} to check if the current * context supports drawing shapes.

* * * Fill a shape general path * * * @param shape The shape to be drawn. * @param stroke the stroke to use * * @see #setStroke * @see #isShapeSupported */ public void drawShape(Shape shape, Stroke stroke){ if ( isShapeSupported()){ if ( xTranslate != 0 || yTranslate != 0 ){ GeneralPath p = tmpClipShape(); p.setShape(shape, translation()); shape = p; } impl.drawShape(nativeGraphics, shape, stroke); } } /** * Fills the given shape using the current alpha and color settings. *

This is not supported on * all platforms and contexts currently. Use {@link #isShapeSupported} to check if the current * context supports drawing shapes.

* * * Fill a shape general path * *

Note: You can specify a custom {@link Paint} to use for filling the shape using the {@link #setColor(com.codename1.ui.Paint) } * method. This is useful for filling the shape with a {@link LinearGradientPaint}, for example.

* * * @param shape The shape to be filled. * * @see #isShapeSupported */ public void fillShape(Shape shape){ if ( isShapeSupported() ){ if (paint != null) { int clipX = getClipX(); int clipY = getClipY(); int clipW = getClipWidth(); int clipH = getClipHeight(); setClip(shape); clipRect(clipX, clipY, clipW, clipH); if ( xTranslate != 0 || yTranslate != 0 ){ GeneralPath p = tmpClipShape(); p.setShape(shape, translation()); shape = p; } Rectangle bounds = shape.getBounds(); paint.paint(this, bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); setClip(clipX, clipY, clipW, clipH); return; } if ( xTranslate != 0 || yTranslate != 0 ){ GeneralPath p = tmpClipShape(); p.setShape(shape, translation()); shape = p; } impl.fillShape(nativeGraphics, shape); } } /** * Checks to see if {@link com.codename1.ui.geom.Matrix} transforms are supported by this graphics context. * @return {@literal true} if this graphics context supports {@link com.codename1.ui.geom.Matrix} transforms. *

Note that this method only confirms that 2D transforms are supported. If you need to perform 3D * transformations, you should use the {@link #isPerspectiveTransformSupported} method.

* @see #setTransform * @see #getTransform * @see #isPerspectiveTransformSupported */ public boolean isTransformSupported(){ return impl.isTransformSupported(nativeGraphics); } /** * Checks to see if perspective (3D) {@link com.codename1.ui.geom.Matrix} transforms are supported by this graphics * context. If 3D transforms are supported, you can use a 4x4 transformation {@link com.codename1.ui.geom.Matrix} * via {@link #setTransform} to perform 3D transforms. * *

Note: It is possible for 3D transforms to not be supported but Affine (2D) * transforms to be supported. In this case you would be limited to a 3x3 transformation * matrix in {@link #setTransform}. You can check for 2D transformation support using the {@link #isTransformSupported} method.

* * @return {@literal true} if Perspective (3D) transforms are supported. {@literal false} otherwise. * @see #isTransformSupported * @see #setTransform * @see #getTransform */ public boolean isPerspectiveTransformSupported(){ return impl.isPerspectiveTransformSupported(nativeGraphics); } /** *

Checks to see if this graphics context supports drawing shapes (i.e. {@link #drawShape} * and {@link #fillShape} methods. If this returns {@literal false}, and you call {@link #drawShape} or {@link #fillShape}, then * nothing will be drawn.

* @return {@literal true} If {@link #drawShape} and {@link #fillShape} are supported. * @see #drawShape * @see #fillShape */ public boolean isShapeSupported(){ return impl.isShapeSupported(nativeGraphics); } /** * Checks to see if this graphics context supports clip Shape. * If this returns {@literal false}, calling setClip(Shape) will have no effect on the Graphics clipping area * @return {@literal true} If setClip(Shape) is supported. */ public boolean isShapeClipSupported(){ return impl.isShapeClipSupported(nativeGraphics); } /** * Sets the transformation {@link com.codename1.ui.geom.Matrix} to apply to drawing in this graphics context. * In order to use this for 2D/Affine transformations you should first check to * make sure that transforms are supported by calling the {@link #isTransformSupported} * method. For 3D/Perspective transformations, you should first check to * make sure that 3D/Perspective transformations are supported by calling the * {@link #isPerspectiveTransformSupported}. * *

Transformations are applied with {@literal (0,0)} as the origin. So rotations and * scales are anchored at this point on the screen. You can use a different * anchor point by either embedding it in the transformation matrix (i.e. pre-transform the {@link com.codename1.ui.geom.Matrix} to anchor at a different point) * or use the {@link #setTransform(com.codename1.ui.geom.Matrix,int,int)} variation that allows you to explicitly set the * anchor point.

* @param transform The transformation {@link com.codename1.ui.geom.Matrix} to use for drawing. 2D/Affine transformations * can be achieved using a 3x3 transformation {@link com.codename1.ui.geom.Matrix}. 3D/Perspective transformations * can be achieved using a 4x3 transformation {@link com.codename1.ui.geom.Matrix}. * * @see #isTransformSupported * @see #isPerspectiveTransformSupported * @see #setTransform(com.codename1.ui.geom.Matrix,int,int) */ public void setTransform(Transform transform){ impl.setTransform(nativeGraphics, transform); } /** * Concatenates the given transform to the context's transform. * @param transform The transform to concatenate. * @since 7.0 */ public void transform(Transform transform) { Transform existing = getTransform(); existing.concatenate(transform); setTransform(existing); } /** * Gets the transformation matrix that is currently applied to this graphics context. * @return The current transformation matrix. * @see #setTransform * @deprecated Use {@link #getTransform(com.codename1.ui.Transform) } instead. */ public Transform getTransform(){ return impl.getTransform(nativeGraphics); } /** * Loads the provided transform with the current transform applied to this graphics context. * @param t An "out" parameter to be filled with the current transform. */ public void getTransform(Transform t) { impl.getTransform(nativeGraphics, t); } //-------------------------------------------------------------------------- // END SHAPE DRAWING METHODS //-------------------------------------------------------------------------- /** * Draws a filled triangle with the given coordinates * * @param x1 the x coordinate of the first vertex of the triangle * @param y1 the y coordinate of the first vertex of the triangle * @param x2 the x coordinate of the second vertex of the triangle * @param y2 the y coordinate of the second vertex of the triangle * @param x3 the x coordinate of the third vertex of the triangle * @param y3 the y coordinate of the third vertex of the triangle */ public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) { impl.fillTriangle(nativeGraphics, xTranslate + x1, yTranslate + y1, xTranslate + x2, yTranslate + y2, xTranslate + x3, yTranslate + y3); } /** * Draws the RGB values based on the MIDP API of a similar name. Renders a * series of device-independent RGB+transparency values in a specified * region. The values are stored in rgbData in a format with 24 bits of * RGB and an eight-bit alpha value (0xAARRGGBB), with the first value * stored at the specified offset. The scanlength specifies the relative * offset within the array between the corresponding pixels of consecutive * rows. Any value for scanlength is acceptable (even negative values) * provided that all resulting references are within the bounds of the * rgbData array. The ARGB data is rasterized horizontally from left to * right within each row. The ARGB values are rendered in the region * specified by x, y, width and height, and the operation is subject * to the current clip region and translation for this Graphics object. * * @param rgbData an array of ARGB values in the format 0xAARRGGBB * @param offset the array index of the first ARGB value * @param x the horizontal location of the region to be rendered * @param y the vertical location of the region to be rendered * @param w the width of the region to be rendered * @param h the height of the region to be rendered * @param processAlpha true if rgbData has an alpha channel, false if * all pixels are fully opaque */ void drawRGB(int[] rgbData, int offset, int x, int y, int w, int h, boolean processAlpha) { impl.drawRGB(nativeGraphics, rgbData, offset, x + xTranslate, y + yTranslate, w, h, processAlpha); } /** * Draws a radial gradient in the given coordinates with the given colors, * doesn't take alpha into consideration when drawing the gradient. * Notice that a radial gradient will result in a circular shape, to create * a square use fillRect or draw a larger shape and clip to the appropriate size. * * @param startColor the starting RGB color * @param endColor the ending RGB color * @param x the x coordinate * @param y the y coordinate * @param width the width of the region to be filled * @param height the height of the region to be filled */ public void fillRadialGradient(int startColor, int endColor, int x, int y, int width, int height) { impl.fillRadialGradient(nativeGraphics, startColor, endColor, x + xTranslate, y + yTranslate, width, height); } /** * Draws a radial gradient in the given coordinates with the given colors, * doesn't take alpha into consideration when drawing the gradient. * Notice that a radial gradient will result in a circular shape, to create * a square use fillRect or draw a larger shape and clip to the appropriate size. * * @param startColor the starting RGB color * @param endColor the ending RGB color * @param x the x coordinate * @param y the y coordinate * @param width the width of the region to be filled * @param height the height of the region to be filled * @param startAngle the beginning angle. Zero is at 3 o'clock. Positive angles are counter-clockwise. * @param arcAngle the angular extent of the arc, relative to the start angle. Positive angles are counter-clockwise. */ public void fillRadialGradient(int startColor, int endColor, int x, int y, int width, int height, int startAngle, int arcAngle) { impl.fillRadialGradient(nativeGraphics, startColor, endColor, x + xTranslate, y + yTranslate, width, height, startAngle, arcAngle); } /** * Draws a radial gradient in the given coordinates with the given colors, * doesn't take alpha into consideration when drawing the gradient. Notice that this method * differs from fillRadialGradient since it draws a square gradient at all times * and can thus be cached * Notice that a radial gradient will result in a circular shape, to create * a square use fillRect or draw a larger shape and clip to the appropriate size. * * @param startColor the starting RGB color * @param endColor the ending RGB color * @param x the x coordinate * @param y the y coordinate * @param width the width of the region to be filled * @param height the height of the region to be filled * @param relativeX indicates the relative position of the gradient within the drawing region * @param relativeY indicates the relative position of the gradient within the drawing region * @param relativeSize indicates the relative size of the gradient within the drawing region */ public void fillRectRadialGradient(int startColor, int endColor, int x, int y, int width, int height, float relativeX, float relativeY, float relativeSize) { // people do that a lot sadly... if(startColor == endColor) { setColor(startColor); fillRect(x, y, width, height, (byte)0xff); return; } impl.fillRectRadialGradient(nativeGraphics, startColor, endColor, x + xTranslate, y + yTranslate, width, height, relativeX, relativeY, relativeSize); } /** * Draws a linear gradient in the given coordinates with the given colors, * doesn't take alpha into consideration when drawing the gradient * * @param startColor the starting RGB color * @param endColor the ending RGB color * @param x the x coordinate * @param y the y coordinate * @param width the width of the region to be filled * @param height the height of the region to be filled * @param horizontal indicating wheter it is a horizontal fill or vertical */ public void fillLinearGradient(int startColor, int endColor, int x, int y, int width, int height, boolean horizontal) { // people do that a lot sadly... if(startColor == endColor) { setColor(startColor); fillRect(x, y, width, height, (byte)0xff); return; } impl.fillLinearGradient(nativeGraphics, startColor, endColor, x + xTranslate, y + yTranslate, width, height, horizontal); } /** * Fills a rectangle with an optionally translucent fill color * * @param x the x coordinate of the rectangle to be filled * @param y the y coordinate of the rectangle to be filled * @param w the width of the rectangle to be filled * @param h the height of the rectangle to be filled * @param alpha the alpha values specify semitransparency */ public void fillRect(int x, int y, int w, int h, byte alpha) { impl.fillRect(nativeGraphics, x+xTranslate, y+yTranslate, w, h, alpha); } /** * Fills a closed polygon defined by arrays of x and y coordinates. * Each pair of (x, y) coordinates defines a point. * * @param xPoints - a an array of x coordinates. * @param yPoints - a an array of y coordinates. * @param nPoints - a the total number of points. */ public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { int[] cX = xPoints; int[] cY = yPoints; if((!impl.isTranslationSupported()) && (xTranslate != 0 || yTranslate != 0)) { cX = new int[nPoints]; cY = new int[nPoints]; System.arraycopy(xPoints, 0, cX, 0, nPoints); System.arraycopy(yPoints, 0, cY, 0, nPoints); for(int iter = 0 ; iter < nPoints ; iter++) { cX[iter] += xTranslate; cY[iter] += yTranslate; } } impl.fillPolygon(nativeGraphics, cX, cY, nPoints); } /** * Draws a region of an image in the given x/y coordinate * * @param img the image to draw * @param x x location for the image * @param y y location for the image * @param imageX location within the image to draw * @param imageY location within the image to draw * @param imageWidth size of the location within the image to draw * @param imageHeight size of the location within the image to draw */ void drawImageArea(Image img, int x, int y, int imageX, int imageY, int imageWidth, int imageHeight) { img.drawImageArea(this, nativeGraphics, x, y, imageX, imageY, imageWidth, imageHeight); } /** * Draws a closed polygon defined by arrays of x and y coordinates. * Each pair of (x, y) coordinates defines a point. * * @param xPoints - a an array of x coordinates. * @param yPoints - a an array of y coordinates. * @param nPoints - a the total number of points. */ public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { int[] cX = xPoints; int[] cY = yPoints; if((!impl.isTranslationSupported()) && (xTranslate != 0 || yTranslate != 0)) { cX = new int[nPoints]; cY = new int[nPoints]; System.arraycopy(xPoints, 0, cX, 0, nPoints); System.arraycopy(yPoints, 0, cY, 0, nPoints); for(int iter = 0 ; iter < nPoints ; iter++) { cX[iter] += xTranslate; cY[iter] += yTranslate; } } impl.drawPolygon(nativeGraphics, cX, cY, nPoints); } /** * Indicates whether invoking set/getAlpha would have an effect on all further * rendering from this graphics object. * * @return false if setAlpha has no effect true if it applies to everything some effect */ public boolean isAlphaSupported() { return impl.isAlphaGlobal(); } /** * Sets alpha as a value between 0-255 (0 - 0xff) where 255 is completely opaque * and 0 is completely transparent * * @param a the alpha value */ public void setAlpha(int a) { impl.setAlpha(nativeGraphics, a); } /** * Sets alpha as a value between 0-255 (0 - 0xff) where 255 is completely opaque * and 0 is completely transparent * * @param a the alpha value * @return The previous alpha value. */ public int setAndGetAlpha(int a) { int old = getAlpha(); setAlpha(a); return old; } /** * Concatenates the given alpha value to the current alpha setting, and returns the previous alpha * setting. * @param a Alpha value to concatenate (0-255). * @return The previous alpha setting (0-255). * @since 7.0 */ public int concatenateAlpha(int a) { if (a == 255) return getAlpha(); int oldAlpha = getAlpha(); setAlpha((int)(oldAlpha * (a/255f))); return oldAlpha; } /** * Returnes the alpha as a value between 0-255 (0 - 0xff) where 255 is completely opaque * and 0 is completely transparent * * @return the alpha value */ public int getAlpha() { return impl.getAlpha(nativeGraphics); } /** * Returns true if anti-aliasing for standard rendering operations is supported, * notice that text anti-aliasing is a separate attribute. * * @return true if anti aliasing is supported */ public boolean isAntiAliasingSupported() { return impl.isAntiAliasingSupported(nativeGraphics); } /** * Returns true if anti-aliasing for text is supported, * notice that text anti-aliasing is a separate attribute from standard anti-alisaing. * * @return true if text anti aliasing is supported */ public boolean isAntiAliasedTextSupported() { return impl.isAntiAliasedTextSupported(nativeGraphics); } /** * Returns true if anti-aliasing for standard rendering operations is turned on. * * @return true if anti aliasing is active */ public boolean isAntiAliased() { return impl.isAntiAliased(nativeGraphics); } /** * Set whether anti-aliasing for standard rendering operations is turned on. * * @param a true if anti aliasing is active */ public void setAntiAliased(boolean a) { impl.setAntiAliased(nativeGraphics, a); } /** * Set whether anti-aliasing for text is active, * notice that text anti-aliasing is a separate attribute from standard anti-alisaing. * * @param a true if text anti aliasing is supported */ public void setAntiAliasedText(boolean a) { impl.setAntiAliasedText(nativeGraphics, a); } /** * Indicates whether anti-aliasing for text is active, * notice that text anti-aliasing is a separate attribute from standard anti-alisaing. * * @return true if text anti aliasing is supported */ public boolean isAntiAliasedText() { return impl.isAntiAliasedText(nativeGraphics); } /** * Indicates whether the underlying implementation can draw using an affine * transform hence methods such as rotate, scale and shear would work * * @return true if an affine transformation matrix is present */ public boolean isAffineSupported() { return impl.isAffineSupported(); } /** * Resets the affine transform to the default value */ public void resetAffine() { impl.resetAffine(nativeGraphics); scaleX = 1; scaleY = 1; } /** * Scales the coordinate system using the affine transform * * @param x scale factor for x * @param y scale factor for y */ public void scale(float x, float y) { impl.scale(nativeGraphics, x, y); scaleX = x; scaleY = y; } /** * Rotates the coordinate system around a radian angle using the affine transform * * @param angle the rotation angle in radians about the screen origin. * @deprecated The behaviour of this method is inconsistent with the rest of the API, in that it doesn't * take into account the current Graphics context's translation. Rotation is performed around the Screen's origin * rather than the current Graphics context's translated origin. Prefer to use {@link #rotateRadians(float) } * which pivots around the context's translated origin. * @see #rotateRadians(float) * */ public void rotate(float angle) { impl.rotate(nativeGraphics, angle); } /** * RRotates the coordinate system around a radian angle using the affine transform * * @param angle the rotation angle in radians about graphics context's translated origin. * @since 6.0 */ public void rotateRadians(float angle) { rotateRadians(angle, 0, 0); } /** * Rotates the coordinate system around a radian angle using the affine transform * * @param angle the rotation angle in radians * @param pivotX the pivot point In absolute coordinates. * @param pivotY the pivot point In absolute coordinates. * @deprecated The behaviour of this method is inconsistent with the rest of the API, in that the pivotX and pivotY parameters * are expressed in absolute screen coordinates and don't take into account the current Graphics context's translation. Prefer * to use {@link #rotateRadians(float, int, int) } whose pivot coordinates are relative to the current translation. * @see #rotateRadians(float, int, int) */ public void rotate(float angle, int pivotX, int pivotY) { impl.rotate(nativeGraphics, angle, pivotX, pivotY); } /** * Rotates the coordinate system around a radian angle using the affine transform * * @param angle the rotation angle in radians * @param pivotX the pivot point relative to the current graphics context's translation. * @param pivotY the pivot point relative to the current graphics context's translation. * @since 6.0 */ public void rotateRadians(float angle, int pivotX, int pivotY) { impl.rotate(nativeGraphics, angle, pivotX+xTranslate, pivotY+yTranslate); } /** * Shear the graphics coordinate system using the affine transform * * @param x shear factor for x * @param y shear factor for y */ public void shear(float x, float y) { impl.shear(nativeGraphics, x, y); } /** * Starts accessing the native graphics in the underlying OS, when accessing * the native graphics Codename One shouldn't be used! The native graphics is unclipped * and untranslated by default and its the responsibility of the caller to clip/translate * appropriately. *

When finished with the native graphics it is essential to invoke endNativeGraphicsAccess * * @return an instance of the underlying native graphics object */ public Object beginNativeGraphicsAccess() { if(nativeGraphicsState != null) { throw new IllegalStateException("beginNativeGraphicsAccess invoked twice in a row"); } Boolean a = Boolean.FALSE, b = Boolean.FALSE; if(isAntiAliasedText()) { b = Boolean.TRUE; } if(isAntiAliased()) { a = Boolean.TRUE; } nativeGraphicsState = new Object[] { new Integer(getTranslateX()), new Integer(getTranslateY()), new Integer(getColor()), new Integer(getAlpha()), new Integer(getClipX()), new Integer(getClipY()), new Integer(getClipWidth()), new Integer(getClipHeight()), a, b }; translate(-getTranslateX(), -getTranslateY()); setAlpha(255); setClip(0, 0, Display.getInstance().getDisplayWidth(), Display.getInstance().getDisplayHeight()); return nativeGraphics; } /** * Invoke this to restore Codename One's graphics settings into the native graphics */ public void endNativeGraphicsAccess() { translate(((Integer)nativeGraphicsState[0]).intValue(), ((Integer)nativeGraphicsState[1]).intValue()); setColor(((Integer)nativeGraphicsState[2]).intValue()); setAlpha(((Integer)nativeGraphicsState[3]).intValue()); setClip(((Integer)nativeGraphicsState[4]).intValue(), ((Integer)nativeGraphicsState[5]).intValue(), ((Integer)nativeGraphicsState[6]).intValue(), ((Integer)nativeGraphicsState[7]).intValue()); setAntiAliased(((Boolean)nativeGraphicsState[8]).booleanValue()); setAntiAliasedText(((Boolean)nativeGraphicsState[9]).booleanValue()); nativeGraphicsState = null; } /** * Allows an implementation to optimize image tiling rendering logic * * @param img the image * @param x coordinate to tile the image along * @param y coordinate to tile the image along * @param w coordinate to tile the image along * @param h coordinate to tile the image along */ public void tileImage(Image img, int x, int y, int w, int h) { if(img.requiresDrawImage()) { int iW = img.getWidth(); int iH = img.getHeight(); int clipX = getClipX(); int clipW = getClipWidth(); int clipY = getClipY(); int clipH = getClipHeight(); clipRect(x, y, w, h); for (int xPos = 0; xPos <= w; xPos += iW) { for (int yPos = 0; yPos < h; yPos += iH) { int actualX = xPos + x; int actualY = yPos + y; if(actualX > clipX + clipW) { continue; } if(actualX + iW < clipX) { continue; } if(actualY > clipY + clipH) { continue; } if(actualY + iH < clipY) { continue; } drawImage(img, actualX, actualY); } } setClip(clipX, clipY, clipW, clipH); } else { impl.tileImage(nativeGraphics, img.getImage(), x + xTranslate, y + yTranslate, w, h); } } /** * Returns the affine X scale * @return the current scale */ public float getScaleX() { return scaleX; } /** * Returns the affine Y scale * @return the current scale */ public float getScaleY() { return scaleY; } /** * Draws a peer component. This doesn't actually draw anything, it just activates * the front graphics buffer and begins redirecting drawing operations to that buffer. *

This is only used on platforms where {@link CodenameOneImplementation#isFrontGraphicsSupported() } is enabled.

* @param peer The peer component to be drawn. */ void drawPeerComponent(PeerComponent peer) { if (paintPeersBehind) { clearRectImpl(peer.getAbsoluteX(), peer.getAbsoluteY(), peer.getWidth(), peer.getHeight()); } } /** * Sets rendering hints for this context. * @param hints int of rendering hints produced by logical AND on all applicable hints. * @see #RENDERING_HINT_FAST * @see #getRenderingHints() * @since 7.0 */ public void setRenderingHints(int hints) { impl.setRenderingHints(nativeGraphics, hints); } /** * Gets the current rendering hints for this context. * @see #RENDERING_HINT_FAST * @return The rendering hints. */ public int getRenderingHints() { return impl.getRenderingHints(nativeGraphics); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy