LibGDX - Get width of label cell in ImageTextButton - libgdx

I have ImageTextButtons within a container Table. I would like to dynamically change the width of this table and have the ImageTextButtons respond in a particular manner. What I would like them to do is fade in the label text depending on the percentage of the text shown.
I believe I am dynamically setting the table width and contents correctly. As per the LibGDX documents we should not explicitly set the widgets dimensions, but the table (container) cell dimensions. So for testing, I have a simple clickListener on what of the buttons like this;
button.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
float max = container.getCell(button).getMaxWidth();
container.getCell(button).width(max*0.9f);
container.invalidate();
}
});
This works fine, I click it and the cell (and the widget) shrink 90% each time.
For the next step, I thought it would be as simple as this, in my custom ImageTextButton's draw() method;
glyphWidth = getLabel().getGlyphLayout().width;
labelCellWidth = getLabelCell().getMinWidth(); ///<--problem here
float glyphOpacityMultiplier = MathUtils.clamp(labelCellWidth/glyphWidth, 0f, 1f);
origLabelColor = getLabel().getColor().cpy();
newLabelColor = origLabelColor.cpy();
newLabelColor = new Color(newLabelColor.r, newLabelColor.g, newLabelColor.b, newLabelColor.a*glyphOpacityMultiplier);
getLabel().setColor(newLabelColor);
super.draw(batch, parentAlpha);
getLabel().setColor(origLabelColor);
This all works, except for the fact I can't find any method to give me with actual width of the Cell that contains the label. Since the ImageTextButton itself is also a Table, I tried to do button.invalidate() in the ClickListener too but it didn't help. These are the methods I have tried so far;
getLabelCell().getMinWidth();
getLabelCell().getMaxWidth();
getLabelCell().getPrefWidth();
getLabelCell().getActorWidth();
getLabelCell().getSpaceLeft();
getLabelCell().getSpaceRight();
None of them seem to update and give me the correct size, however I know something is working somewhere because I turned on "setClip(true)" on the ImageTextButton, and the label text is successfully being clipped within the boundaries of the NinePatch background when it is resized. So how do I get the correct size?
Any help is greatly appreciated!

Oops.. solved it. I thought the cell containing the label would be offset and sized by the NinePatch background but its not, it is full size but has padding. Therefore the answer is;
labelCellWidth = getWidth()-getPadLeft()-getPadRight();

Related

How do I scale a Libgdx Animation?

I an currently using Libgdx Animation class( com.badlogic.gdx.graphics.g2d.Animation) in a game. However I need the animation to grow in size on certain events. How do I accomplish this?
Animation is used to select the correct frame (TextureRegion) based on the time elapsed. It has nothing to do with how you render that frame. Therefor it is not different as how you render anything else.
You didn't provide enough information for that. But usually you'd render it something like this:
TextureRegion textureRegion = animation.getKeyFrame(time += delta);
spritebatch.draw(textureRegion, x, y, width, height);
So to change the size would be to change the width and height variables. You didn't provide enough information on how you'd like to do that. But you can do that for example using this:
width = 0.8f;
height = 1.9f;

Force an actor to obey the width set in table.add(actor).width()

I am setting the width of actor in table.add(actor).width(width). The padding is set to 1% of screen width. This is the result I get:
As you can see, spacing between actors is way beyond 1% . I tried using fill() methods but it didn't work. I also tried setFillParent(true) on the actor, no success. What is going on here? This is the complete code. The only spacing between actors should be the one I set with padding. How do I achieve this?
private void createScrollPane(){
texture=new Texture("badlogic.jpg");
ImageButton.ImageButtonStyle fibs=new ImageButton.ImageButtonStyle();
fibs.imageUp=new TextureRegionDrawable(new TextureRegion(texture));
button1= new ImageButton(fibs);
button2= new ImageButton(fibs);
button3= new ImageButton(fibs);
button1.setPosition(0, 0);
button2.setPosition(0, 0);
button3.setPosition(0, 0);
scrollTable=new Table();
scrollTable.setBounds(Gdx.graphics.getWidth()*0.03f,0,Gdx.graphics.getWidth()*0.94f, Gdx.graphics.getHeight());
scrollTable.setPosition(Gdx.graphics.getWidth() * 0.03f, 50);
scrollTable.add(button1).width(Gdx.graphics.getWidth() * 0.3f).padLeft(Gdx.graphics.getWidth() * 0.01f).fill();
scrollTable.add(button2).width(Gdx.graphics.getWidth() * 0.3f).padLeft(Gdx.graphics.getWidth() * 0.01f).padRight(Gdx.graphics.getWidth() * 0.01f).fillX();
scrollTable.add(button3).width(Gdx.graphics.getWidth() * 0.3f).padRight(Gdx.graphics.getWidth() * 0.01f).fill();
stage.addActor(scrollTable);
}
ImageButton is a Button with an Image on top of it. If you just want a button then use the Button class and set the up drawable to the drawable you want it to be. Note that you can enable debug drawing of the stage or table to visualize what is going on.
Your function calls are affecting the Table's cells, not the actors in the cells.
Call scrollTable.setDebug(true) to see the cells, padding, etc. You'll be happy to find your function calls are working, just on the cells rather than their contents.
The next step is to build a composite layout with widgets which allow you to expand the buttons but maintain them in a horizontal alignment. You might be able to accomplish that with just a table if you battle the cells hard enough, I'm not sure.
What I did was to use a Table, then add a HorizontalGroup. The HorizontalGroup goes within a cell on the Table. Inside the HorizontalGroup I add my buttons. Laying out the buttons the way I want within the HorizontalGroup is far easier than doing it via the Table.
For an ImageButton you can explicitly set the minHeight and minWidth of the style, which will forcibly scale the attached Image.

How can I avoid sprite distortion as the frame's bounding box changes?

I have a spritesheet (packed by the wonderful TexturePacker) that looks like so:
and the animation as an animation works well using the current code.
However, when the animation moves to a frame where the bounding box is smaller (e.g. when the legs are closer, when the figure is kneeling, etc.), the image distorts so that the smaller bounding box fills the bounding box of the sprite.
How can I fix this?
The spritesheet above is a frame-extraction from a sample Adobe flash animation.
Easier way:
You can make all the textureregions the same size.
Hard way:
Keep it like this, but you need to save and calculate the size and position of every textureregion to draw.
I personally recommend you the first option, just make all the image the same size.
cant give you a link but here is what i do for these situations
while making the texture packer strip the white space
make a array of AtlasSprite for images
then in my render method
public void render(float delta) {
atlasSprite = animation.getKeyFrame(statetime, Animation.LOOPING);
atlasSprite.draw(batcher)
};
in my update method, which gives exact rectangular bounds of the current image displayed. Since you have stripped the whitespace and used AtlasSprite so bounds will be without blank whitespace.
public void update(float delta) {
bounds = sprite.getBoundingRectangle();
}
P.S. this is just a pseudo code and many syntatical error could be there its just to give you a idea

Cocos2dx sublayers

I am developing a 2D games with cocos2dx, in which I am still very new... inside the game, there's a number of UI Elements that I'd like to group together as one (I intend to group them into CCLayers). For example a few text labels and sprites form a CStatBar which is a CCLayer. This CStatBar will then be included in the various other CCLayer
How do I do that? I created the CStatBar class and then, inside the containing class's init() function, I CStatBar::create() and call this->addChild(pStatBar) however, the statbar did not appear... is there any obvious thing that I missed? All the positions are correct. Thanks!
EDIT:
Notes:
1. ccTouchesBegan of the sublayer is called, however it is not rendered/seen
2. How do I resize the sublayer so that it only cover partial area of the parent layer? Supposedly the CStatBar should only cover 10% of the top area of the screen, not the whole screen...
inside the CParent::init() function, you can initialize the CSublayer like so:
// Create and initialize CSublayer
CSublayer* pSublayer= CSublayer::create();
float fWidth = pSublayer->getContentSize().width;
float fHeight = pSublayer->getContentSize().height;
pSublayer->setPosition(ccp(fWidth/2.0f, fHeight/2.0f));
this->addChild( pSublayer );
and your CSublayer can be defined like other CCLayer.
If you want to restrict the CSublayer to be smaller than the CParent layer, you can do so inside its init function like so:
CSublayer::init() {
// initialize the size with the size of the background sprite
CCSprite *pSpriteBackground = CCSprite::createWithSpriteFrame(
CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("background.png")
);
this->setContentSize(CCSize(pSpriteBackground->getContentSize().width, pSpriteBackground->getContentSize().height));
pSpriteBackground->setPosition(ccp(fScreenHalfWidth, fScreenHeight-(pSpriteBackground->getContentSize().height/2.0f)));
this->addChild(pSpriteBackground);
}

How get a string width in Libgdx?

I wonder know how to get the width of my string in pixels
BitmapFont API < 1.5.6
To mesure the width of a String you use your Font and get the bounds of the String, you are going to draw.
BitmapFont.getBounds(String str).width
BitmapFont API
You can get the height to for the right offset for drawing too. Just replace width with height.
In addition for multiline texts use getMultiLineBounds(someString).width to get the bounds.
BitmapFont API >= 1.5.6
The BitmapFont API changed in 1.5.7 so there is a different way to get the bounds now:
BitmapFont.TextBounds and getBounds are done. Instead, give the string to GlyphLayout and get the bounds using its width and height fields. You can then draw the text by passing the same GlyphLayout to BitmapFont, which means the glyphs don’t have to be laid out twice like they used to.
Source (Web archive)
Example:
GlyphLayout layout = new GlyphLayout(); //dont do this every frame! Store it as member
layout.setText("meow");
float width = layout.width;// contains the width of the current set text
float height = layout.height; // contains the height of the current set text
According to #Nates answer: https://stackoverflow.com/a/20759876/619673 calling method
BitmapFont.getBounds(String str).width
not always returns proper width! Especially when you are reusing font.
If you want draw text for example in the center of part of view port, you can avoid this problem by using another method
BitmapFont.drawWrapped(...)
Example code:
font.drawWrapped(spriteBatch, "text", x_pos, y_pos, your_area_for_text, BitmapFont.HAlignment.CENTER);
If you use skins in UI it is a hassle to find out the correct font to feed into the GlyphLayout.
In this case I use a throw away instance of Label to figure everything out for me then ask the Label for the width.
Skin skin = getMySkin();
Label cellExample = new Label("888.88888", skin);
cellExample.layout();
float cellWidth = cellExample.getWidth();
Table table = new Table(skin);
table.defaults().width(cellWidth);
// fill table width cells ...
This is not the answer if you want to position the text yourself, but it is useful to make a UI layout stable and less dependent on the actual content of the cells.