How get a string width in Libgdx? - 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.

Related

How to get the natural fontsize of bitmapfont?

If I have a bitmapfont such as;
fonttexture = new Texture(Gdx.files.internal("data/fonttest.png"), true);
font= new BitmapFont(Gdx.files.internal("data/fonttest.fnt"),
new TextureRegion(fonttexture ), true);
Is it possible to retrieve or deduce the natural fontsize used on the associated png texture file?
The *.fnt file itself specifies this on the first line;
info face="Calibri Light" size=32 bold=0 italic=0 charset=""
Its that 32 I am after in code.
I couldn't see a method on BitmapFonts class to directly get it, but there was various other height related attributes possible to get.
I tried recreating the size from those but didn't have much luck.
float baseToAssent = font.getCapHeight()+font.getAscent();
float baseToDecent = -font.getDescent();Decent);
float fontHeight = baseToAssent+baseToDecent; //too small, like 11 not 32
Not being a fonttographer? fontophile?...umm...graphic designer, I am probably putting the pieces together wrong, or maybe just lacking one.
In either case, any way to work out the font size used in the fonttest.png would be helpful.
Thanks
Usecase;
I am manually using that texture with a distance field shader. Knowing the textures natural font size is useful in order to accurately scale the text and lineheight to any requested font size without ever resizing a image and thus losing quality.
Not sure how to get the font size specific, however you can easily get the String width and height of a font using a GlyphLayout, like this:
BitmapFont font = new BitmapFont(Gdx.files.internal("data/fonttest.fnt", false);
GlyphLayout glyph = new GlyphLayout(font, "TextMessage");
float width = glyph.width;
float height = glyph.height;
Read this topic if you want to learn more about GlyphLayout and BitmapFont.
Experimented quite a bit with a 32px font, like yours. The String "W" seemed to be 29px wide, which was the widest I could find, so it's definately not precise if what you want to archive is the size exactly.
You could do a little hacky method, reading the .fnt file as a text file and looking for the Integer after "size=", pretty much like a properties file work, it will be less efficient but will return exact value.

LibGDX - Get width of label cell in ImageTextButton

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();

autosizing movieclips to match text size (AS3)

I'm looking to add a specialized border around some dynamic text.
A special type of border that filters just can not produce
So I need this border to match the length of the dynamic text.
Unfortunately this code is not working
thistext.autoSize = TextFieldAutoSize.LEFT;
border.width = thistext.width;
What happens is, the border width is set to the initial starting width of the text and is not changed as the width of the text changes
Any ideas on how I can make this work?
You should rather listen only to text changes : flash.events.Event.CHANGE, instead of checking every frame.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#event:change
Besides, you may use textWidth attribute to get actual text width, no matter the value of autosize attribute (Width must be set to the maximum width). I'm not a huge fan of auto size feature which hides the maximum width, although it exists internally ( equal to the width attribute of the textfield, BEFORE setting autosize..). I'd rather have a less "magical" but more clear behavior, but it's debatable, especially if your text has to interact with the mouse (click,hover..), then you can take advantage of the bounds being automatically updated
I actually caught my mistake.
I need to add the code into an event listener that checks every frame AFTER the dynamic change so this code works
border.width = thistext.width;

ActionScript 3: Zoom into movieclip while not scaling its childrens

I've included a zoom functionality similar to the one explained at this website:
http://www.flashandmath.com/howtos/zoom/
This works perfectly on my background image(a map, that is), but I want to keep the symbols on my map the same size while zooming in.
I probably could work this out by changing all the children's size when calling the zoom-function, but I am hoping there is some kind of easy code adapt in my children class to make the size of the instances unchangable. Is there?
Thanks!
One crude way, so you don't have to calculate the symbols scale, would be to remove the symbols from the mapDisplayObject so they're no longer a child and instead put symbol placeholders. Then match each symbol's x and y to each place holder, using localToGlobal...
If your children are not scaled or skewed or rotated you can iterate all of them and set transformation matrix to 1/parentScale. Something like:
for each (var child:DisplayObject in parent) {
var matrix:Matrix = child.transform.matrix;
matrix.a = 1/parentScale;
matrix.d = 1/parentScale;
child.transform.matrix = marix;
}

Comparing two bitmaps against each other for match as3

I'm trying to position an image on top of another image based upon the make-up of the smaller image. The smaller image is a cut-out of a larger image and I need it to be positioned exactly on the larger image to make it look like a single image, but allow for separate filters and alphas to be applied. As the images are not simple rectangles or circles, but complex satellite images, I cannot simply redraw them in code. I have quite a few images and therefore do not feel like manually finding the position of each image every and hard setting them manually in actionscript. Is there any way for me to sample a small 5-10 sq. pixel area against the larger image and set the x and y values of the smaller image if a perfect match is found? All the images are in an array and iterating through them has already been set, I just need a way to sample and match pixels. My first guess was to loop the images pixel by pixel right and down, covering the whole bitmap and moving to the next child in the array once a match was found, leaving the matched child where it was when the perfect match was found.
I hope I understood your question correctly.
There may be an option that uses copypixels to achieve what you want. You can use the bitmapdata.rect value to determine the size of the sample you want, and loop through the bigger bitmap using thet rectangle and a moving point. Let's see if I can code this out...
function findBitmapInBitmap(tinyimg:BitmapData, largeimg:BitmapData):Point {
var rect:Rectangle = tinyimg.rect;
var xbound:uint = largeimg.rect.width;
var ybound:uint = largeimg.rect.height;
var imgtest:BitmapData = new BitmapData(tinyimg.rect.width, tinyimg.rect.height);
for (var ypos:uint = 0, y <= ybound, y++) {
for (var xpos:uint = 0, x <= xbound, x++) {
imgtest.copyPixels(largeimg, rect, new Point(xpos, ypos);
if (imgtest.compare(tinyimg) == 0) return new Point(xpos, ypos);
}
}
return new Point(-1,-1); // Dummy value, indicating no match.
}
Something along those lines should work - I'm sure there's room for code elegance and possible optimization. However, it seems like something like this method would be very slow, since you'd have to check each pixel for a match.
There is a better way. Split your big image into layers, and use the blitting technique to composite them at runtime. In your case, you could create a ground texture without satellites, and then create the satellites separately, and use the copyPixels method to place them whereever you want. Google "blitting in as3" to find some good tutorials. I'm currently working on a game project that uses this technique and it's a very good method.
Good luck!
Edit: Forgot to code in a default return statement. Using this method, you'd have to return an invalid point (like (-1,-1)) and check for it outside the function. Alternatively, you could just copy your small bitmap to the big one within the function, which would be much more logical, but I don't know your requirements.
You need to find pixel sequence in the big image. BitmapData.getPixel gives you pixel value. So get first pixel from small image, find it in big image, then continue comparing until you find full match. If you have trouble to code that, feel free to ask.
For the actual comparison, there's BitmapData.compare which returns the number 0 if the BitmapData objects are equivalent.