[SOLVED] [LibGDX] Custom GUI Component Not Moving

Hi all,

I’m trying to create some scalable GUI components programmatically instead of using png files in order to avoid pixilation when scaling or having to create different sized images for different resolutions.

I found this thread which shows how to create a gradient programmatically using a Sprite:
http://www.badlogicgames.com/forum/viewtopic.php?f=11&t=9361

So I’m using that code to generate the gradient and then I am adding a couple additional layers on top of the gradient to create a bevel effect and a black border from 9patch images.

The only problem I’m having is that my component doesn’t move off the bottom of the screen when I add it to a Table. I have debug lines enabled on the Table and the debug lines are centered where my component is supposed to be placed. Here is a screenshot:

My component class extends Group and I have added the 9patch images to be children of the Group. Unfortunately I cannot do that with the Sprite (since it is not an Actor), but I have created an additional method that sets the position of the Sprite relative to the Group, which I call after my custom component has been added to the Table. However, putting print statements into the “setSpritePosition” method shows that the X and Y position of the Group is “0.0” even after being added to the Table.

It seems like this should work, so I’m not sure why it’s not positioning correctly. Any ideas on how to fix it would be greatly appreciated. :slight_smile:

Here is my code:

Test.java - Main

package com.tekker.test;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Table;

public class Test extends ApplicationAdapter {
	Stage stage;
	SpriteBatch batch;
	static final float rgbMax = 255;
	
	Table tableMain;
	Table table;
	ButtonGradient button;
	
	@Override
	public void create () {
		stage = new Stage();
		Gdx.input.setInputProcessor(stage);
		batch = new SpriteBatch();
		
		tableMain = new Table();
		tableMain.setFillParent(true);
		tableMain.center();
		stage.addActor(tableMain);
		
		table = new Table();
		table.center();
		tableMain.add(table);
				
		button = new ButtonGradient();
		button.setSize(640, 58);
		
		table.add(button);
		table.getCell(button).size(button.getWidth(), button.getHeight());
		button.setSpritePosition();
		
		tableMain.debug();
		table.debug();
	}
	
	@Override
	public void render () {
		Gdx.gl.glClearColor(86/rgbMax, 86/rgbMax, 86/rgbMax, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		stage.draw();
	}
}

ButtonGradient.java - Custom Component

package com.tekker.test;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.ui.Image;

public class ButtonGradient extends Group {
	SpriteGradient gradient;
	Image bevel;
	Image border;
	NinePatch patch9;
	TextureAtlas atlas;
	
	static final float rgbMax = 255;
	static final float bevelTransparency = 0.2f;
	Color top = new Color((134/rgbMax), (134/rgbMax), (135/rgbMax), 1);
	Color bottom = new Color((0/rgbMax), (0/rgbMax), (0/rgbMax), 1);
	
	public ButtonGradient(){		
		Texture texture = new Texture("white.png");
		TextureRegion whitePixel = new TextureRegion(texture);
		
		// GRADIENT
		gradient = new SpriteGradient(whitePixel);
		gradient.setGradientColor(top, bottom, false);
		
		// BEVEL
		atlas = new TextureAtlas(Gdx.files.internal("border.atlas"));
		patch9 = atlas.createPatch("bevel");
		bevel = new Image(patch9);
		
		// BORDER
		atlas = new TextureAtlas(Gdx.files.internal("border.atlas"));
		patch9 = atlas.createPatch("border");
		border = new Image(patch9);
		
		// ADD
		addActor(bevel);
		addActor(border);
	}
	
	@Override
	public void setSize(float width, float height){
		super.setSize(width, height);
		gradient.setSize(width-2, height-2);
		bevel.setSize(width-2, height-2);
		border.setSize(width, height);
	}
	
	public void setSpritePosition(){
		gradient.setPosition(getX()+1, getY()+1);
		bevel.setPosition(getX()+1, getY()+1);
	}
	
	@Override
	public void draw(Batch batch, float parentAlpha){
		gradient.draw(batch);
		bevel.draw(batch, bevelTransparency);
		border.draw(batch, 1);
	}
}

SpriteGradient.java - Generates Gradient

package com.tekker.test;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class SpriteGradient extends Sprite {
	public SpriteGradient(TextureRegion white) {
		setRegion(white);
	}
	
	public void setGradientColor(Color a, Color b, boolean horizontal) {
		float[] vertices = getVertices();
		float ca = a.toFloatBits();
		float cb = b.toFloatBits();
		vertices[SpriteBatch.C1] = horizontal ? ca : cb;	//bottom left
		vertices[SpriteBatch.C2] = ca;						//top left
		vertices[SpriteBatch.C3] = horizontal ? cb : ca;	//top right
		vertices[SpriteBatch.C4] = cb;						//bottom right
	}
}

It seems my problem is related to overriding the draw method in ButtonGradient.java. I tried commenting out the entire draw method and the bevel and black border now show up in the correct position since they are children of the Group. However, the gradient (which is a Sprite and not a child of the Group) does not get drawn at all.

Here is a screenshot after commenting out the draw method in ButtonGradient.java:

Is there a way to make the gradient as an Image instead of a Sprite?..or can I somehow draw the Sprite’s gradient to an Image?..then I could simply add it to the Group as an Actor and it would be placed in the correct location like the other Images.

Also, I’ve seen that ShapeRenderer can be used to draw gradients, but I’m trying to avoid that as I’d have to switch between SpriteBatch and ShapeRenderer, which apparently is a costly operation.

Thanks!

WOOHOO! Finally figured it out! :slight_smile:

I was looking at the wrong source code for information on the draw() method. I thought I needed to look at Actor source since Group extends Actor…turns out Group was the one that held the valuable information:

Draw Method for Group.java:

public void draw (Batch batch, float parentAlpha) {
	if (transform) applyTransform(batch, computeTransform());
	drawChildren(batch, parentAlpha);
	if (transform) resetTransform(batch);
}

So I put my drawing code in between these two lines…

applyTransform(batch, computeTransform());
//...DRAW ACTORS AND SPRITES HERE...
resetTransform(batch);

…and now it works perfectly! This is why nothing moved when I overwrote the draw method, I needed that applyTransform method.

This information might be useful to anyone making custom LibGDX Groups. :slight_smile: