I am using this tool:
https://github.com/codenameone/flamingo-svg-transcoder
you can read more about it here:
https://www.codenameone.com/blog/flamingo-svg-transcoder.html#commento-login-box-container
I used it to convert a svg file and this is the result:
/**
* This class has been automatically generated using
* Flamingo SVG transcoder.
*/
public class MyImageFromSVGSubset extends com.codename1.ui.Image implements Painter {
private int width, height;
private Transform t = Transform.makeIdentity(), t2 = Transform.makeIdentity();
public MyImageFromSVGSubset() {
super(null);
width = getOrigWidth();
height = getOrigHeight();
}
public MyImageFromSVGSubset(int width, int height) {
super(null);
this.width = width;
this.height = height;
fixAspectRatio();
}
#Override
public int getWidth() {
return width;
}
#Override
public int getHeight() {
return height;
}
#Override
public void scale(int width, int height) {
this.width = width;
this.height = height;
fixAspectRatio();
}
#Override
public MyImageFromSVGSubset scaled(int width, int height) {
MyImageFromSVGSubset f = new MyImageFromSVGSubset(width, height);
f.fixAspectRatio();
return f;
}
public Image toImage() {
Image i = Image.createImage(width, height, 0);
Graphics g = i.getGraphics();
drawImage(g, null, 0, 0, width, height);
return i;
}
private void fixAspectRatio() {
if(width == -1) {
float ar = ((float)getOrigWidth()) / ((float)getOrigHeight());
width = Math.round(((float)height) * ar);
}
if (height == -1) {
float ar = ((float)getOrigHeight()) / ((float)getOrigWidth());
height = Math.round(((float)width) * ar);
}
}
#Override
public Image fill(int width, int height) {
return new MyImageFromSVGSubset(width, height);
}
#Override
public Image applyMask(Object mask) {
return new MyImageFromSVGSubset(width, height);
}
#Override
public boolean isAnimation() {
return true;
}
#Override
public boolean requiresDrawImage() {
return true;
}
#Override
protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) {
drawImage(g, nativeGraphics, x, y, width, height);
}
#Override
protected void drawImage(Graphics g, Object nativeGraphics, int x, int y, int w, int h) {
g.getTransform(t);
t2.setTransform(t);
float hRatio = ((float) w) / ((float) getOrigWidth());
float vRatio = ((float) h) / ((float) getOrigHeight());
t2.translate(x + g.getTranslateX(), y + g.getTranslateY());
t2.scale(hRatio, vRatio);
g.setTransform(t2);
paint(g);
g.setTransform(t);
}
private static void paint(Graphics g) {
int origAlpha = g.getAlpha();
Stroke baseStroke;
Shape shape;
g.setAntiAliased(true);
g.setAntiAliasedText(true);
/*Composite origComposite = g.getComposite();
if (origComposite instanceof AlphaComposite) {
AlphaComposite origAlphaComposite = (AlphaComposite)origComposite;
if (origAlphaComposite.getRule() == AlphaComposite.SRC_OVER) {
origAlpha = origAlphaComposite.getAlpha();
}
}
*/
java.util.LinkedList<Transform> transformations = new java.util.LinkedList<Transform>();
//
transformations.push(g.getTransform());
g.transform(new AffineTransform(3.7795277f, 0, 0, 3.7795277f, 0, 0).toTransform());
// _0
// _0_0
// _0_0_0
shape = new Rectangle2D(0.008569182828068733, 0.0054579987190663815, 6.3905863761901855, 6.390747547149658);
g.setColor(0xffffff);
g.fillShape(shape);
// _0_0_1
shape = new GeneralPath();
((GeneralPath) shape).moveTo(5.0011573, 1.454892);
((GeneralPath) shape).curveTo(4.914109, 1.454892, 4.8439946, 1.526065, 4.8439946, 1.6128483);
...
...
//very long sequence of graphical instructions that corresponds to the actual drawing
...
...
((GeneralPath) shape).closePath();
g.fillShape(shape);
g.setTransform(transformations.pop()); // _0
g.setAlpha(origAlpha);
}
/**
* Returns the X of the bounding box of the original SVG image.
*
* #return The X of the bounding box of the original SVG image.
*/
public static int getOrigX() {
return 1;
}
/**
* Returns the Y of the bounding box of the original SVG image.
*
* #return The Y of the bounding box of the original SVG image.
*/
public static int getOrigY() {
return 1;
}
/**
* Returns the width of the bounding box of the original SVG image.
*
* #return The width of the bounding box of the original SVG image.
*/
public static int getOrigWidth() {
return 24;
}
/**
* Returns the height of the bounding box of the original SVG image.
*
* #return The height of the bounding box of the original SVG image.
*/
public static int getOrigHeight() {
return 24;
}
#Override
public void paint(Graphics g, Rectangle rect) {
drawImage(g, null, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}
It's Java code to be used in my application (Codename One) but it doesn't work for me.
I put the following code into a working layout:
button.setIcon(new MyImageFromSVGSubset(256,256));
The image is present because it occupies the right space (256x256) but nothing is drawn.
What is the mistake?
Related
I'm making custom components for my game and I tried everything I found in Stack Overflow and no matter what I still can't place text in the center of a rectangle. I even read all the documentation of working with java text API.
Can anyone explain to me how to align text to the center (Center of rect or frame or anything) in java swing once and for all? This is not a duplicate question because in all the other questions on Stack Overflow I did not get a solution that works.
So far I have used FontMetrics and I measured the width using stringWidth() method and the height using ascent (None of them are accurate).
package com.isi.uicomponents;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import com.isi.core.Game;
import com.isi.states.GameState;
public class Button extends UIComponent {
private Font font;
private String text;
public Button(Game game, GameState state, int x, int y, int width, int height, String text) {
super(game, state, x, y, width, height);
font = new Font("Arial", Font.BOLD, 20);
this.text = text;
}
public Button(Game game, GameState state, int x, int y, int width, int height) {
super(game, state, x, y, width, height);
text = null;
}
public String getText() {
return text;
}
#Override
public void tick() {
}
#Override
public void draw(Graphics2D g) {
g.setColor(fillColor);
g.fillRect(x, y, width, height);
g.setColor(boundsColor);
g.draw(bounds);
if (text != null) {
FontMetrics fm = g.getFontMetrics();
int textX = x + (width / 2) - (fm.stringWidth(text) / 2);
int textY = y + ((height - fm.getHeight()) / 2) + fm.getAscent();
g.setFont(font);
g.setColor(Color.white);
g.drawString(text, textX, textY);
}
}
}
// =============================================
package com.isi.uicomponents;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import com.isi.core.Game;
import com.isi.states.GameState;
public abstract class UIComponent {
public final static Color DEFAULT_BOUNDS_COLOR = Color.white;
public final static Color DEFAULT_FILL_COLOR = Color.gray;
protected Game game;
protected GameState state;
protected int x;
protected int y;
protected int width;
protected int height;
protected Rectangle bounds;
protected Color boundsColor;
protected Color fillColor;
public UIComponent(Game game, GameState state, int x, int y, int width, int height) {
this.game = game;
this.state = state;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
bounds = new Rectangle(x, y, width, height);
boundsColor = DEFAULT_BOUNDS_COLOR;
fillColor = DEFAULT_FILL_COLOR;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Color getBoundsColor() {
return boundsColor;
}
public void setBoundsColor(Color boundsColor) {
this.boundsColor = boundsColor;
}
public Color getFillColor() {
return fillColor;
}
public void setFillColor(Color fillColor) {
this.fillColor = fillColor;
}
public abstract void tick();
public abstract void draw(Graphics2D g);
}
// =============================================
package com.isi.states;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import com.isi.core.Game;
import com.isi.tools.ImageLoader;
import com.isi.uicomponents.Button;
import com.isi.uicomponents.UIComponent;
public class MainMenuState extends GameState {
private static BufferedImage bg = ImageLoader.load("Main Menu Background.jpg");
// Background coordinates for animation
private int x;
private int y;
// MainMenu components array
private ArrayList<UIComponent> components;
public MainMenuState(Game game) {
super(game);
x = 0;
y = 0;
components = new ArrayList<UIComponent>();
components.add(new Button(game, this, game.getWidth() / 2 - 80 / 2, game.getHeight() / 2 - 50 / 2, 80, 50, "Play"));
}
public ArrayList<UIComponent> getComponents() {
return components;
}
public void tick() {
y = y >= game.getHeight() ? 0 : y + 2;
}
public void draw(Graphics2D g) {
g.drawImage(bg, 0, -game.getHeight() + y, game.getWidth(), game.getHeight(), null);
g.drawImage(bg, x, y, game.getWidth(), game.getHeight(), null);
for (int i = 0; i < components.size(); i++) {
components.get(i).draw(g);
}
}
}
This is close, you need to increase x by half the width and then reduce by half the string width. You also need to set the font before you get the font metrics otherwise you're getting the metrics of the existing Graphics font.
g.setFont(font);
FontMetrics fm = g.getFontMetrics();
int textX = x + (width / 2) - (fm.stringWidth(text) / 2);
int textY = y + ((height - fm.getHeight()) / 2) + fm.getAscent();
g.setColor(Color.white);
g.drawString(text, textX, textY);
I have a canvas where I can draw bounding boxes on a canvas in Vaadin, and I am trying to implement an undo function whereby the last drawn box will both be removed from the array and on the canvas. In the undoLast method (which is found in Canvas.java and called in the MainLayout.java), I remove the last element of the array (arrayBoxes which contains all the boxes drawn), and attempt to clear the entire canvas before redrawing the ones left in the array. However, I am getting an array error.
MainLayout:
package com.vaadin.starter.beveragebuddy.backend;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.HtmlImport;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.html.NativeButton;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.theme.Theme;
import com.vaadin.flow.theme.lumo.Lumo;
import com.vaadin.starter.beveragebuddy.ui.components.BoundingBox;
import com.vaadin.starter.beveragebuddy.ui.components.Canvas;
import com.vaadin.starter.beveragebuddy.ui.components.CanvasRenderingContext2D;
import com.vaadin.starter.beveragebuddy.ui.components.MousePosition;
import com.vaadin.flow.component.textfield.TextField;
import java.util.ArrayList;
/**
* The main layout contains the header with the navigation buttons, and the
* child views below that.
*/
#HtmlImport("frontend://styles/shared-styles.html")
#Route("")
#Theme(Lumo.class)
public class MainLayout extends VerticalLayout {
private CanvasRenderingContext2D ctx;
private Canvas canvas;
ArrayList<MousePosition> mousePosArray = Canvas.getMousePosArray();
ArrayList<BoundingBox> bb = Canvas.getArrayBoxes();
public static int count = 0;
public MainLayout() {
VerticalLayout footerLayout = new VerticalLayout();
H2 title = new H2("Annotation UI");
title.addClassName("main-layout__title");
canvas = new Canvas(1580, 700);
ctx = canvas.getContext();
Div buttons = new Div();
buttons.add(new NativeButton("Save Annotations"));
buttons.add(new NativeButton("Previous Picture"));
buttons.add(new NativeButton("Next Picture"));
buttons.add(new NativeButton("Undo", e -> Canvas.undoLast()));
buttons.add(new NativeButton("Clear Canvas",
e -> ctx.clearRect(0, 0, 1580, 700)));
add(canvas, buttons);
Label label = new Label();
canvas.addComponent(label);
add(label);
// HorizontalLayout fieldLayout = new HorizontalLayout();
TextField boxname = new TextField();
boxname.setLabel("Box Name:");
boxname.setPlaceholder("Enter bounding box name");
TextField boxcategory = new TextField();
boxcategory.setLabel("Box Category:");
boxcategory.setPlaceholder("Enter bounding box category");
add(boxname, boxcategory);
Button submitButton = new Button("Submit");
submitButton.addClickListener(event -> {
if (count == 0){
count = count + 1;
}
bb.get(count - 1).setName(boxname.getValue());
bb.get(count - 1).setBoxcategory(boxcategory.getValue());
count = count + 1;
boxname.clear();
boxcategory.clear();
System.out.println(bb.toString());
});
add(submitButton);
canvas.addMouseMoveListener(() -> label.setText("Coordinates: " + mousePosArray.get(0)));
}
}
Canvas.java:
package com.vaadin.starter.beveragebuddy.ui.components;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.dom.ElementFactory;
import com.vaadin.flow.shared.Registration;
import elemental.json.JsonObject;
import java.util.ArrayList;
import java.util.List;
/**
* Canvas component that you can draw shapes and images on. It's a Java wrapper
* for the
* <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">HTML5
* canvas</a>.
* <p>
* Use {#link #getContext()} to get API for rendering shapes and images on the
* canvas.
* <p>
*/
#Tag("canvas")
#SuppressWarnings("serial")
public class Canvas extends Component implements HasStyle, HasSize {
private static CanvasRenderingContext2D context;
private Element element;
private boolean isDrawing = false;
private boolean mouseIsDown = false;
private double endX;
private double endY;
public static ArrayList <BoundingBox> arrayBoxes = new ArrayList<BoundingBox>();
public static ArrayList <MousePosition> mousePosArray = new ArrayList<MousePosition>();
private List<Runnable> mouseMoveListeners = new ArrayList<>(0);
public static ArrayList<BoundingBox> getArrayBoxes() {
return arrayBoxes;
}
public static ArrayList<MousePosition> getMousePosArray() {
return mousePosArray;
}
public static void setMousePosArray(ArrayList<MousePosition> mousePosArray) {
Canvas.mousePosArray = mousePosArray;
}
/**
* Creates a new canvas component with the given size.
* <p>
* Use the API provided by {#link #getContext()} to render graphics on the
* canvas.
* <p>
* The width and height parameters will be used for the canvas' coordinate
* system. They will determine the size of the component in pixels, unless
* you explicitly set the component's size with {#link #setWidth(String)} or
* {#link #setHeight(String)}.
*
// * #param width
// * the width of the canvas
// * #param height
// * the height of the canvas
// */
public Registration addMouseMoveListener(Runnable listener) {
mouseMoveListeners.add(listener);
return () -> mouseMoveListeners.remove(listener);
}
public Canvas(int width, int height) {
context = new CanvasRenderingContext2D(this);
element = getElement();
element.getStyle().set("border", "1px solid");
getElement().setAttribute("width", String.valueOf(width));
getElement().setAttribute("height", String.valueOf(height));
element.addEventListener("mousedown", event -> { // Retrieve Starting Position on MouseDown
Element boundingBoxResult = ElementFactory.createDiv();
element.appendChild(boundingBoxResult);
JsonObject evtData = event.getEventData();
double xBox = evtData.getNumber("event.x");
double yBox = evtData.getNumber("event.y");
boundingBoxResult.setAttribute("data-x", String.format("%f", xBox));
boundingBoxResult.setAttribute("data-y", String.format("%f", yBox));
BoundingBox newBox = new BoundingBox("","", xBox, yBox, 0.0, 0.0);
arrayBoxes.add(newBox);
isDrawing = true;
mouseIsDown=true;
mouseMoveListeners.forEach(Runnable::run);
}).addEventData("event.x").addEventData("event.y");
element.addEventListener("mouseup", event -> { // Draw Box on MouseUp
Element boundingBoxResult2 = ElementFactory.createDiv();
element.appendChild(boundingBoxResult2);
JsonObject evtData2 = event.getEventData();
endX = evtData2.getNumber("event.x");
endY = evtData2.getNumber("event.y");
boundingBoxResult2.setAttribute("end-x", String.format("%f", endX));
boundingBoxResult2.setAttribute("end-y", String.format("%f", endY));
double xcoordi = 0;
double ycoordi = 0;
double boxWidth = 0;
double boxHeight = 0;
for (int i = 0; i < arrayBoxes.size(); i++) {
arrayBoxes.get(i).setWidth(endX, arrayBoxes.get(i).xcoordi);
arrayBoxes.get(i).setHeight(endY, arrayBoxes.get(i).ycoordi);
xcoordi = arrayBoxes.get(i).getXcoordi();
ycoordi = arrayBoxes.get(i).getYcoordi();
boxWidth = arrayBoxes.get(i).getWidth();
boxHeight = arrayBoxes.get(i).getHeight();
}
mouseIsDown=false;
context.beginPath();
context.setStrokeStyle("green");
context.setLineWidth(2);
context.strokeRect(xcoordi, ycoordi, boxWidth, boxHeight);
context.stroke();
context.fill();
System.out.println(arrayBoxes.toString());
mouseMoveListeners.forEach(Runnable::run);
}).addEventData("event.x").addEventData("event.y");
element.addEventListener("mousemove", event -> { // Retrieve Mouse Position when Moving
JsonObject mousePos = event.getEventData();
double mouseX = mousePos.getNumber("event.x");
double mouseY = mousePos.getNumber("event.y");
MousePosition currentPos = new MousePosition(mouseX, mouseY);
mousePosArray.add(0, currentPos);
setMousePosArray(mousePosArray);
mouseMoveListeners.forEach(Runnable::run);
}).addEventData("event.x").addEventData("event.y");
}
public static void undoLast() {
if (arrayBoxes.size() > 0) {
arrayBoxes.remove(arrayBoxes.size() - 1);
}
// System.out.println(arrayBoxes.toString());
System.out.println(arrayBoxes.get(0).toString());
System.out.println(arrayBoxes.size());
for (int i = 0; i < arrayBoxes.size(); i++){
context.clearRect(0, 0, 1580, 700);
context.beginPath();
context.setStrokeStyle("limegreen");
context.setLineWidth(2);
context.strokeRect(arrayBoxes.get(i).xcoordi, arrayBoxes.get(i).ycoordi, arrayBoxes.get(i).boxWidth, arrayBoxes.get(i).boxHeight);
context.fill();
}
}
/**
* Gets the context for rendering shapes and images in the canvas.
* <p>
* It is a Java wrapper for the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D">same
* client-side API</a>.
*
* #return the 2D rendering context of this canvas
*/
public CanvasRenderingContext2D getContext() {
return context;
}
/**
* {#inheritDoc}
* <p>
* <b>NOTE:</b> Canvas has an internal coordinate system that it uses for
* drawing, and it uses the width and height provided in the constructor.
* This coordinate system is independent of the component's size. Changing
* the component's size with this method may scale/stretch the rendered
* graphics.
*/
#Override
public void setWidth(String width) {
HasSize.super.setWidth(width);
}
/**
* {#inheritDoc}
* <p>
* <b>NOTE:</b> Canvas has an internal coordinate system that it uses for
* drawing, and it uses the width and height provided in the constructor.
* This coordinate system is independent of the component's size. Changing
* the component's size with this method may scale/stretch the rendered
* graphics.
*/
#Override
public void setHeight(String height) {
HasSize.super.setHeight(height);
}
/**
* {#inheritDoc}
* <p>
* <b>NOTE:</b> Canvas has an internal coordinate system that it uses for
* drawing, and it uses the width and height provided in the constructor.
* This coordinate system is independent of the component's size. Changing
* the component's size with this method may scale/stretch the rendered
* graphics.
*/
#Override
public void setSizeFull() {
HasSize.super.setSizeFull();
}
public void addComponent(Label label) {
}
}
CanvasRenderingContext2D.java:
package com.vaadin.starter.beveragebuddy.ui.components;
import com.vaadin.starter.beveragebuddy.backend.MainLayout;
import java.io.Serializable;
import java.util.ArrayList;
/**
* The context for rendering shapes and images on a canvas.
* <p>
* This is a Java wrapper for the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D">same
* client-side API</a>.
*/
public class CanvasRenderingContext2D {
private Canvas canvas;
public static ArrayList<BoundingBox> arrayBoxes = new ArrayList<BoundingBox>();
protected CanvasRenderingContext2D(Canvas canvas) {
this.canvas = canvas;
}
public void setFillStyle(String fillStyle) {
setProperty("fillStyle", fillStyle);
}
public void setStrokeStyle(String strokeStyle) {
setProperty("strokeStyle", strokeStyle);
}
public void setLineWidth(double lineWidth) {
setProperty("lineWidth", lineWidth);
}
public void setFont(String font) {
setProperty("font", font);
}
public void arc(double x, double y, double radius, double startAngle,
double endAngle, boolean antiClockwise) {
callJsMethod("arc", x, y, radius, startAngle, endAngle, antiClockwise);
}
public void beginPath() {
callJsMethod("beginPath");
}
public void clearRect(double x, double y, double width, double height) {
callJsMethod("clearRect", x, y, width, height);
Canvas.arrayBoxes.clear();
System.out.println(arrayBoxes.toString());
MainLayout.count = 0;
}
public void closePath() {
callJsMethod("closePath");
}
/**
* Fetches the image from the given location and draws it on the canvas.
* <p>
* <b>NOTE:</b> The drawing will happen asynchronously after the browser has
* received the image.
*
* #param src
* the url of the image to draw
* #param x
* the x-coordinate of the top-left corner of the image
* #param y
* the y-coordinate of the top-left corner of the image
*/
public void drawImage(String src, double x, double y) {
runScript(String.format(
"var zwKqdZ = new Image();" + "zwKqdZ.onload = function () {"
+ "$0.getContext('2d').drawImage(zwKqdZ, %s, %s);};"
+ "zwKqdZ.src='%s';",
x, y, src));
}
/**
* Fetches the image from the given location and draws it on the canvas.
* <p>
* <b>NOTE:</b> The drawing will happen asynchronously after the browser has
* received the image.
*
* #param src
* the url of the image to draw
* #param x
* the x-coordinate of the top-left corner of the image
* #param y
* the y-coordinate of the top-left corner of the image
* #param width
* the width for the image
* #param height
* the height for the image
*/
public void drawImage(String src, double x, double y, double width,
double height) {
runScript(String.format("var zwKqdZ = new Image();"
+ "zwKqdZ.onload = function () {"
+ "$0.getContext('2d').drawImage(zwKqdZ, %s, %s, %s, %s);};"
+ "zwKqdZ.src='%s';", x, y, width, height, src));
}
public void fill() {
callJsMethod("fill");
}
public void fillRect(double x, double y, double width, double height) {
callJsMethod("fillRect", x, y, width, height);
}
public void fillText(String text, double x, double y) {
callJsMethod("fillText", text, x, y);
}
public void lineTo(double x, double y) {
callJsMethod("lineTo", x, y);
}
public void moveTo(double x, double y) {
callJsMethod("moveTo", x, y);
}
public void rect(double x, double y, double width, double height) {
callJsMethod("rect", x, y, width, height);
}
public void restore() {
callJsMethod("restore");
}
public void rotate(double angle) {
callJsMethod("rotate", angle);
}
public void save() {
callJsMethod("save");
}
public void scale(double x, double y) {
callJsMethod("scale", x, y);
}
public void stroke() {
callJsMethod("stroke");
}
public void strokeRect(double x, double y, double width, double height) {
callJsMethod("strokeRect", x, y, width, height);
}
public void strokeText(String text, double x, double y) {
callJsMethod("strokeText", text, x, y);
}
public void translate(double x, double y) {
callJsMethod("translate", x, y);
}
protected void setProperty(String propertyName, Serializable value) {
runScript(String.format("$0.getContext('2d').%s='%s'", propertyName,
value));
}
/**
* Runs the given js so that the execution order works with callJsMethod().
* Any $0 in the script will refer to the canvas element.
*/
private void runScript(String script) {
canvas.getElement().getNode().runWhenAttached(
// This structure is needed to make the execution order work
// with Element.callFunction() which is used in callJsMethod()
ui -> ui.getInternals().getStateTree().beforeClientResponse(
canvas.getElement().getNode(),
context -> ui.getPage().executeJavaScript(script,
canvas.getElement())));
}
protected void callJsMethod(String methodName, Serializable... parameters) {
canvas.getElement().callFunction("getContext('2d')." + methodName,
parameters);
}
}
BoundingBox.java:
package com.vaadin.starter.beveragebuddy.ui.components;
public class BoundingBox {
public double xcoordi = 0;
public double ycoordi = 0;
public double boxWidth = 0;
public double boxHeight = 0;
public String boxname;
public String boxcategory;
public BoundingBox(String boxname, String boxcategory, double xcoordi, double ycoordi, double boxWidth, double boxHeight) {
this.boxname = boxname;
this.boxcategory = boxcategory;
this.xcoordi = xcoordi;
this.ycoordi = ycoordi;
this.boxWidth = boxWidth;
this.boxHeight = boxHeight;
}
public String getBoxName() {
return boxname;
}
public void setName(String boxname) {
this.boxname = boxname;
}
public String getBoxcategory() {
return boxcategory;
}
public void setBoxcategory(String boxcategory) {
this.boxcategory = boxcategory;
}
public double getXcoordi() {
return xcoordi;
}
public void setXcoordi(double xcoordi) {
this.xcoordi = xcoordi;
}
public double getYcoordi() {
return ycoordi;
}
public void setYcoordi(double ycoordi) {
this.ycoordi = ycoordi;
}
public double getWidth() {
return boxWidth;
}
public void setWidth(double endX, double xcoordi) {
boxWidth = endX - xcoordi;
}
public double getHeight() {
return boxHeight;
}
public void setHeight(double endY, double ycoordi) {
boxHeight = endY - ycoordi;
}
#Override
public String toString() {
return "{" +
"Name=" + boxname +
", Class=" + boxcategory +
", X=" + xcoordi +
", Y=" + ycoordi +
", Width=" + boxWidth +
", Height=" + boxHeight +
'}';
}
}
MousePosition.java:
package com.vaadin.starter.beveragebuddy.ui.components;
public class MousePosition {
public double mouseX;
public double mouseY;
public MousePosition(double mouseX, double mouseY) {
this.mouseX = mouseX;
this.mouseY = mouseY;
}
public double getMouseX() {
return mouseX;
}
public void setMouseX(double mouseX) {
this.mouseX = mouseX;
}
public double getMouseY() {
return mouseY;
}
public void setMouseY(double mouseY) {
this.mouseY = mouseY;
}
#Override
public String toString() {
return "X = " + mouseX +
", Y = " + mouseY;
}
}
Stack trace:
[qtp1975873209-21] ERROR com.vaadin.flow.server.DefaultErrorHandler -
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.get(ArrayList.java:433)
at com.vaadin.starter.beveragebuddy.ui.components.Canvas.undoLast(Canvas.java:191)
at com.vaadin.starter.beveragebuddy.backend.MainLayout.lambda$new$9b1b5227$1(MainLayout.java:67)
at com.vaadin.flow.component.ComponentEventBus.fireEvent(ComponentEventBus.java:133)
at com.vaadin.flow.component.ComponentEventBus.handleDomEvent(ComponentEventBus.java:327)
at com.vaadin.flow.component.ComponentEventBus.lambda$addDomTrigger$5ee67f2b$1(ComponentEventBus.java:191)
at com.vaadin.flow.internal.nodefeature.ElementListenerMap.lambda$fireEvent$2(ElementListenerMap.java:379)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at com.vaadin.flow.internal.nodefeature.ElementListenerMap.fireEvent(ElementListenerMap.java:379)
at com.vaadin.flow.server.communication.rpc.EventRpcHandler.handleNode(EventRpcHandler.java:59)
at com.vaadin.flow.server.communication.rpc.AbstractRpcInvocationHandler.handle(AbstractRpcInvocationHandler.java:64)
at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocationData(ServerRpcHandler.java:377)
at com.vaadin.flow.server.communication.ServerRpcHandler.lambda$handleInvocations$0(ServerRpcHandler.java:367)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:367)
at com.vaadin.flow.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:309)
at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:89)
at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1487)
at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:300)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:201)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:258)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:748)
Any help is much appreciated, thank you!
In your undo method, you have this code
for (int i = 0; i < arrayBoxes.size(); i++){
context.clearRect(0, 0, 1580, 700);
context.beginPath();
context.setStrokeStyle("limegreen");
context.setLineWidth(2);
context.strokeRect(arrayBoxes.get(i).xcoordi, arrayBoxes.get(i).ycoordi, arrayBoxes.get(i).boxWidth, arrayBoxes.get(i).boxHeight);
context.fill();
}
Your context.clearRect() function contains the line
Canvas.arrayBoxes.clear();
Which removes all items from the arrayBoxes array. Therefore you get an exception at the end of the for loop when you try executing arrayBoxes.get(i).xcoordi etc.
The Program is simple enough. I'm trying to get 3-10 random looking faces to print on a panel in a frame in Java. The problem is the faces won't print on the panel. I'm pretty new to this so I'm not sure what I've mucked up, and I've been trying to find a solution to my problem for a while. Any help?
//Leonard
//Random Face Drawer(3-10)
//Last Modified: 10/6/18
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
//Main Class
public class FaceDraw {
public static void main(String[] args) {
int width = 900;
int height = 600;
Random rand = new Random();
ArrayList<Face> myFaceList = new ArrayList<Face>();
for( int i = 1; i < (rand.nextInt(8)+3); i ++) {
myFaceList.add(new Face(rand.nextInt(width-50)+50,rand.nextInt(height-50)+50,rand.nextInt(101),rand.nextInt(101)));
System.out.print(myFaceList);
}
FaceFrame myFaceFrame = new FaceFrame(myFaceList, width, height);
myFaceFrame.setVisible(true);
}
}
class OvalDraw extends Oval{
public OvalDraw () {
super(0,0,0,0);
}
public OvalDraw (int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
}
public void paintComponent(Graphics g) {
g.drawOval(getPositionX(),getPositionY(),getWidth(),getHeight());
System.out.format("OvalDraw.paintComponent(x = %d, y = %d, w = %d, h = %d)", getPositionX(),getPositionY(),getWidth(),getHeight());
}
}
//Face Class, extends from OvalDraw makes the face
class Face extends OvalDraw {
private OvalDraw eye1;
private OvalDraw eye2;
private Random smile;
private int smileStatus;
public Face () {
super(0, 0, 0, 0);
eye1 = new OvalDraw(0,0,0,0);
eye2 = new OvalDraw(0,0,0,0);
smileStatus = smile.nextInt(2);
}
public Face (int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
// variables to set my eyes to be the same size but in two different spots on the same y axis
int eyeHeight = heightIn/12;
int eyeWidth = widthIn/10;
int eye1PositionX = positionXIn + positionXIn/3;
int eyePositionY = positionYIn + positionYIn/12;
int eye2PositionX = eye1PositionX + (positionXIn/3)*2;
eye1 = new OvalDraw(eye1PositionX,eyePositionY,eyeWidth,eyeHeight);
eye2 = new OvalDraw(eye2PositionX,eyePositionY,eyeWidth,eyeHeight);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
eye1.paintComponent(g);
eye2.paintComponent(g);
if(smileStatus == 0) {
g.drawArc(getPositionX(), getPositionY() + getHeight()/2, getWidth(), getHeight(), 45, 90);
}else if(smileStatus == 1){
g.drawArc(getPositionX(), getPositionY() + getHeight()/2, getWidth(), getHeight(), 45, 90);
}else{
g.drawArc(getPositionX(), getPositionY() + getHeight()/2, getWidth(), getHeight(), 45, 90);
}
}
}
class FacePanel extends JPanel{
private ArrayList<Face> FaceList;
public void setFaceList(ArrayList<Face> FaceListIn) {
FaceList = FaceListIn;
}
//draw panel
FacePanel(){
super();
assert false:"unexpected error...(shape draw panel)";
}
FacePanel(ArrayList<Face> FaceListIn){
setFaceList(FaceList);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Face oD : FaceList) {
oD.paintComponent(g);
}
}
}
class FaceFrame extends JFrame{
private FacePanel myFacePanel;
public FaceFrame(ArrayList<Face> faceListIn, int width, int height) {
setBounds(100,100,900,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FacePanel myFacepanel = new FacePanel(faceListIn);
}
}
//Main class for my Shapes
abstract class Shape {
//setting of position
//positioning for x
public final void setPositionX(int positionXIn) {
positionX = positionXIn;
}
public final int getPositionX() {
return positionX;
}
private int positionX;
//positioning for y
public final int getPositionY() {
return positionY;
}
public final void setPositionY(int positionYIn) {
positionY = positionYIn;
}
private int positionY;
//The Width of the Shape
public final void setWidth(int widthIn) {
width = OneOrGreater(widthIn);
}
public final int getWidth() {
return width;
}
private int width;
//The Height of the Shape
public final void setHeight(int heightIn) {
height = OneOrGreater(heightIn);
}
public final int getHeight() {
return height;
}
private int height;
//function for shape
public Shape() {
this(0,0,0,0);
}
public Shape(int positionXIn, int positionYIn, int widthIn, int heightIn) {
setPositionX(positionXIn);
setPositionY(positionYIn);
setWidth(widthIn);
setHeight(heightIn);
}
protected static int OneOrGreater(int valueIn) {
assert valueIn>=1:"Shape parameter is unexeptedly less than 1.";
int returnValue = valueIn;
if (valueIn < 1) {
returnValue = 1;
}
return returnValue;
}
//strings
public String toString() {
return String.format("positionX=%d, positionY=%d, width=%d, height=%d", positionX, positionY, getWidth(), getHeight());
}
abstract public double CalcArea();
abstract public double CalcPerimeter();
}
//The Rectangle class that inherits from Shape
class Rectangle extends Shape {
public Rectangle() {
this(0,0);
}
public Rectangle(int widthIn, int heightIn) {
setWidth(widthIn);
setHeight(heightIn);
}
public Rectangle(int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
}
//calculating area for rectangle is base * height
public double CalcArea() {
return getWidth() * getHeight();
}
//calculating rectangle perimeter is 2(width+height)
public double CalcPerimeter() {
return getWidth() + getWidth() + getHeight() + getHeight();
}
}
//Class for Oval that inherits from Shape
class Oval extends Shape {
Oval () {
super();
}
Oval(int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
}
//Calculating area of oval with oval formula
public double CalcArea() {
return Math.PI * (getWidth()/2) * (getHeight()/2);
}
//The perimeter of an oval is 2 pi * square root of ((a^2+b^2)/2)
public double CalcPerimeter() {
double a = getWidth() / 2.0;
double b = getHeight() / 2.0;
double perimeter =2*Math.PI*Math.sqrt((Math.pow(a,2)+Math.pow(b,2))/2);
return perimeter;
}
}
class FaceFrame extends JFrame {
private FacePanel myFacePanel;
public FaceFrame(ArrayList<Face> faceListIn, int width, int height) {
setBounds(100, 100, 900, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FacePanel myFacepanel = new FacePanel(faceListIn);
}
}
Adding myFacepanel to the JFrame might be a good start...
public FaceFrame(ArrayList<Face> faceListIn, int width, int height) {
setBounds(100, 100, 900, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FacePanel myFacepanel = new FacePanel(faceListIn);
// This might be a good place to start
add(myFacepanel);
}
... next problem ...
FacePanel(ArrayList<Face> FaceListIn){
setFaceList(FaceList);
}
Your assigning FaceList to itself (you're not using FaceListIn).
I'd get rid of the static and update the code...
class FacePanel extends JPanel {
private ArrayList<Face> FaceList;
public void setFaceList(ArrayList<Face> FaceListIn) {
FaceList = FaceListIn;
}
//draw panel
FacePanel() {
super();
}
FacePanel(ArrayList<Face> FaceListIn) {
setFaceList(FaceListIn);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Face oD : FaceList) {
oD.paintComponent(g);
}
}
}
Is there some easy way to create a Button in LibGDX that contains several polygon drawables inside.
For example when the simple Button can be pictured like:
and advanced expected button like that:
And in my case following conditions must be met:
The Object must extends Button class.
Separated polygons (circle and triangle in pic) must have one common behavior - same up, down, hover styles, same click listeners ect. (for example when user hover circle the triangle and circle change color to green)
Actually it must have the absolutely same behavior as button with one polygon, just imagine that circle and triangle is one polygon, instead of separated ones.
The one way I figured out is to extend PolygonRegionDrawable, but to make it drawn correctly I need to override almost all methods from Drawable and TransformDrawable, is there any easier way to do that?
Maybe there can be found some DrawableGroup or something like that?
I dont think theres an easy way to make this work, here are some options.
Button is a Table, you can add stuff to it.
Button button = new Button(skin);
Image img = new Image(...); // insert polygon 1 here
img.setPostion(...); // offset so its in correct position in the button
button.addActor(img);
// add more stuff
Sadly this doesnt handle various state changes, like over etc. You would need to keep track of the added stuff and change them as button changes.
Other option is to make the polygons into single image.
Thats quite tricky, you would draw them into FrameBufferObject in correct places and make a textures out of that. Then use that texture for Drawable for the button style. Reapet for each state you want to handle. Packing them into and atlas would be optimal for perfomace reasons. A ton of texture switches is not great.
In order to reach such functionality I have implemented two additional classes that may assume a list of Drawables to draw it like only one.
So I just mention it here, I hope it may be useful for people who want to implement the same behavior.
An abstract class that assumes list of drawables and related coordinates in format:
[drawable1X, drawable1Y, drawable2X, drawable2Y, ..., drawableNX, drawableNY]
BulkBaseDrawable:
abstract class BulkBaseDrawable implements Drawable {
Array<Drawable> drawables;
private float leftWidth, rightWidth, topHeight, bottomHeight, minWidth, minHeight, leftX, bottomY, rightX, topY;
BulkBaseDrawable(Drawable[] drawables,
float... vertices) {
this.infos = new Array<>(drawables.length);
init(drawables, vertices);
}
#Override
public float getLeftWidth() {
return leftWidth;
}
#Override
public void setLeftWidth(float leftWidth) {
this.leftWidth = leftWidth;
}
#Override
public float getRightWidth() {
return rightWidth;
}
#Override
public void setRightWidth(float rightWidth) {
this.rightWidth = rightWidth;
}
#Override
public float getTopHeight() {
return topHeight;
}
#Override
public void setTopHeight(float topHeight) {
this.topHeight = topHeight;
}
#Override
public float getBottomHeight() {
return bottomHeight;
}
#Override
public void setBottomHeight(float bottomHeight) {
this.bottomHeight = bottomHeight;
}
#Override
public float getMinWidth() {
return minWidth;
}
#Override
public void setMinWidth(float minWidth) {
this.minWidth = minWidth;
}
#Override
public float getMinHeight() {
return minHeight;
}
#Override
public void setMinHeight(float minHeight) {
this.minHeight = minHeight;
}
void init(Drawable[] drawables, float[] vertices) {
initInfo(drawables, vertices);
initEdges();
initSize();
}
private void initInfo(Drawable[] drawables, float[] vertices) {
int i = 0;
for (Drawable drawable : drawables) {
infos.add(Info.builder()
.x(vertices[i])
.y(vertices[i + 1])
.width(drawable.getMinWidth())
.height(drawable.getMinHeight())
.drawable(drawable)
.build());
i += 2;
}
}
private void initSize() {
minHeight = topY - bottomY;
minWidth = rightX - leftX;
}
private void initEdges() {
topY = Float.MIN_VALUE;
rightX = Float.MIN_VALUE;
bottomY = Float.MAX_VALUE;
leftX = Float.MAX_VALUE;
int topI = 0;
int rightI = 0;
int bottomI = 0;
int leftI = 0;
for (int i = 0; i < infos.size; i++) {
Info info = infos.get(i);
if (info.y + info.height > topY) {
topY = info.y + info.height;
topI = i;
}
if (info.x + info.width > rightX) {
rightX = info.x + info.width;
rightI = i;
}
if (info.y < bottomY) {
bottomY = info.y;
bottomI = i;
}
if (info.x < leftX) {
leftX = info.x;
leftI = i;
}
}
Drawable top = infos.get(topI).drawable;
Drawable right = infos.get(rightI).drawable;
Drawable bottom = infos.get(bottomI).drawable;
Drawable left = infos.get(leftI).drawable;
leftWidth = left.getLeftWidth();
rightWidth = right.getRightWidth();
topHeight = top.getTopHeight();
bottomHeight = bottom.getBottomHeight();
}
static class Info {
float x, y, width, height;
Drawable drawable;
static InfoBuilder builder() {
return new InfoBuilder();
}
static class InfoBuilder {
float x, y, width, height;
Drawable drawable;
InfoBuilder x(float x) {
this.x = x;
return this;
}
InfoBuilder y(float y) {
this.y = y;
return this;
}
InfoBuilder width(float width) {
this.width = width;
return this;
}
InfoBuilder height(float height) {
this.height = height;
return this;
}
InfoBuilder drawable(Drawable drawable) {
this.drawable = drawable;
return this;
}
Info build() {
return new Info(x, y, width, height, drawable);
}
}
public Info(float x, float y, float width, float height, Drawable drawable) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.drawable = drawable;
}
}
}
And actually implementation BulkRegionDrawable:
public class BulkRegionDrawable extends BulkBaseDrawable {
public BulkRegionDrawable(Drawable[] drawables, float[] vertices) {
super(drawables, vertices);
}
#Override
public void draw(Batch batch,
float x,
float y,
float width,
float height) {
for (int i = 0; i < infos.size; i++) {
Info info = infos.get(i);
float yK = info.height / getMinHeight();
float xK = info.width / getMinWidth();
info.drawable.draw(
batch,
x + (info.x * width) / getMinWidth(),
y + (info.y * height) / getMinHeight(),
width * xK,
height * yK);
}
}
}
So I am creating a sprite and drawing it to the screen using a different class.
I now want to scale it to be the same aspect ratio/size on each screen.
I have tried doing that by using this code:
public Player(Vector2 position, float width, float height, float rotation, float speed)
{
super(speed, rotation, width, height, position);
}
public void update()
{
width = Gdx.graphics.getWidth() / 10;
height = Gdx.graphics.getHeight() / 10;
}
But this doesn't work, it does nothing.
I have also tried setting the width and height to a static value for example 100 by 100. But this does not work either.
Thank you for any help! :)
Edit: adding base and derived classes:
Here's the code for the Entity class:
public abstract class Entity {
public void setPosition(Vector2 position) {
this.position = position;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
}
Here's the code for the MoveEntity class:
public MoveEntity(float speed, float rotation,
float width, float height,
Vector2 position) {
super(position, width, height);
this.speed = speed;
this.rotation = rotation;
vel = new Vector2(0, 0);
}
public Vector2 getVel() {
return vel;
}
public void setVel(Vector2 target) {
this.vel = target;
}
public float getRotation() {
return rotation;
}
public void setRotation(float r) {
..............///
maybe it do not speak English, but you talk about a sprite and I do not see him any site, anyway.
assuming this is the sprite to which you refer -> spr_player
You can do this in several ways but basing on this line of code that you publish
Variable class. (for test):
float width = Gdx.graphics.getWidth() / 10;
float height = Gdx.graphics.getHeight() / 10;
Try to use this:
sb.draw(spr_player, p.getPosition().x, p.getPosition().y
width, height);
this is the funtion in the Class SpriteBatch:
public void draw (Texture texture, float x, float y,
float width, float height)
also you could use, setSize in the Sprite class, somewhere before render.
spr_player.setSize(width, height);
this is the funtion in the Class Sprite:
public void setSize (float width, float height)
if the size will not change during the game maybe, you can call the setSize, in method created or show, or in the constructor call this way, if the result you want:
Sprite spr_player = new Sprite (your_texture, width, height);
this is the funtion in the Class Sprite:
public Sprite (Texture texture, int srcWidth, int srcHeight)