com.badlogic.gdx.scenes.scene2d.ui.Label.java Source code

Java tutorial

Introduction

Here is the source code for com.badlogic.gdx.scenes.scene2d.ui.Label.java

Source

/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.badlogic.gdx.scenes.scene2d.ui;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;
import com.badlogic.gdx.graphics.g2d.BitmapFontCache;
import com.badlogic.gdx.scenes.scene2d.utils.Align;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.StringBuilder;

/** A text label, with optional word wrapping.
 * <p>
 * The preferred size of the label is determined by the actual text bounds, unless {@link #setWrap(boolean) word wrap} is enabled.
 * @author Nathan Sweet */
public class Label extends Widget {
    static private final Color tempColor = new Color();

    private LabelStyle style;
    private final TextBounds bounds = new TextBounds();
    private final StringBuilder text = new StringBuilder();
    private StringBuilder tempText;
    private BitmapFontCache cache;
    private int labelAlign = Align.left;
    private HAlignment lineAlign = HAlignment.LEFT;
    private boolean wrap;
    private float lastPrefHeight;
    private boolean sizeInvalid = true;
    private float fontScaleX = 1, fontScaleY = 1;
    private boolean ellipsis;

    public Label(CharSequence text, Skin skin) {
        this(text, skin.get(LabelStyle.class));
    }

    public Label(CharSequence text, Skin skin, String styleName) {
        this(text, skin.get(styleName, LabelStyle.class));
    }

    /** Creates a label, using a {@link LabelStyle} that has a BitmapFont with the specified name from the skin and the specified
     * color. */
    public Label(CharSequence text, Skin skin, String fontName, Color color) {
        this(text, new LabelStyle(skin.getFont(fontName), color));
    }

    /** Creates a label, using a {@link LabelStyle} that has a BitmapFont with the specified name and the specified color from the
     * skin. */
    public Label(CharSequence text, Skin skin, String fontName, String colorName) {
        this(text, new LabelStyle(skin.getFont(fontName), skin.getColor(colorName)));
    }

    public Label(CharSequence text, LabelStyle style) {
        if (text != null)
            this.text.append(text);
        setStyle(style);
        setSize(getPrefWidth(), getPrefHeight());
    }

    public void setStyle(LabelStyle style) {
        if (style == null)
            throw new IllegalArgumentException("style cannot be null.");
        if (style.font == null)
            throw new IllegalArgumentException("Missing LabelStyle font.");
        this.style = style;
        cache = new BitmapFontCache(style.font, style.font.usesIntegerPositions());
        invalidateHierarchy();
    }

    /** Returns the label's style. Modifying the returned style may not have an effect until {@link #setStyle(LabelStyle)} is
     * called. */
    public LabelStyle getStyle() {
        return style;
    }

    /** @param newText May be null. */
    public void setText(CharSequence newText) {
        if (newText instanceof StringBuilder) {
            if (text.equals(newText))
                return;
            text.setLength(0);
            text.append((StringBuilder) newText);
        } else {
            if (newText == null)
                newText = "";
            if (textEquals(newText))
                return;
            text.setLength(0);
            text.append(newText);
        }
        invalidateHierarchy();
    }

    public boolean textEquals(CharSequence other) {
        int length = text.length;
        char[] chars = text.chars;
        if (length != other.length())
            return false;
        for (int i = 0; i < length; i++)
            if (chars[i] != other.charAt(i))
                return false;
        return true;
    }

    public StringBuilder getText() {
        return text;
    }

    public void invalidate() {
        super.invalidate();
        sizeInvalid = true;
    }

    private void scaleAndComputeSize() {
        BitmapFont font = cache.getFont();
        float oldScaleX = font.getScaleX();
        float oldScaleY = font.getScaleY();
        if (fontScaleX != 1 || fontScaleY != 1)
            font.setScale(fontScaleX, fontScaleY);

        computeSize();

        if (fontScaleX != 1 || fontScaleY != 1)
            font.setScale(oldScaleX, oldScaleY);
    }

    private void computeSize() {
        sizeInvalid = false;
        if (wrap) {
            float width = getWidth();
            if (style.background != null)
                width -= style.background.getLeftWidth() + style.background.getRightWidth();
            bounds.set(cache.getFont().getWrappedBounds(text, width));
        } else
            bounds.set(cache.getFont().getMultiLineBounds(text));
    }

    public void layout() {
        BitmapFont font = cache.getFont();
        float oldScaleX = font.getScaleX();
        float oldScaleY = font.getScaleY();
        if (fontScaleX != 1 || fontScaleY != 1)
            font.setScale(fontScaleX, fontScaleY);

        if (sizeInvalid)
            computeSize();

        if (wrap) {
            float prefHeight = getPrefHeight();
            if (prefHeight != lastPrefHeight) {
                lastPrefHeight = prefHeight;
                invalidateHierarchy();
            }
        }

        float width = getWidth(), height = getHeight();
        StringBuilder text;
        if (ellipsis && width < bounds.width) {
            float ellipseWidth = font.getBounds("...").width;
            text = tempText != null ? tempText : (tempText = new StringBuilder());
            text.setLength(0);
            if (width > ellipseWidth) {
                text.append(this.text, 0,
                        font.computeVisibleGlyphs(this.text, 0, this.text.length, width - ellipseWidth));
                text.append("...");
            }
        } else
            text = this.text;

        Drawable background = style.background;
        float x = 0, y = 0;
        if (background != null) {
            x = background.getLeftWidth();
            y = background.getBottomHeight();
            width -= background.getLeftWidth() + background.getRightWidth();
            height -= background.getBottomHeight() + background.getTopHeight();
        }
        if ((labelAlign & Align.top) != 0) {
            y += cache.getFont().isFlipped() ? 0 : height - bounds.height;
            y += style.font.getDescent();
        } else if ((labelAlign & Align.bottom) != 0) {
            y += cache.getFont().isFlipped() ? height - bounds.height : 0;
            y -= style.font.getDescent();
        } else
            y += (int) ((height - bounds.height) / 2);
        if (!cache.getFont().isFlipped())
            y += bounds.height;

        if ((labelAlign & Align.left) == 0) {
            if ((labelAlign & Align.right) != 0)
                x += width - bounds.width;
            else
                x += (int) ((width - bounds.width) / 2);
        }

        if (wrap)
            cache.setWrappedText(text, x, y, bounds.width, lineAlign);
        else
            cache.setMultiLineText(text, x, y, bounds.width, lineAlign);

        if (fontScaleX != 1 || fontScaleY != 1)
            font.setScale(oldScaleX, oldScaleY);
    }

    public void draw(Batch batch, float parentAlpha) {
        validate();
        Color color = tempColor.set(getColor());
        color.a *= parentAlpha;
        if (style.background != null) {
            batch.setColor(color.r, color.g, color.b, color.a);
            style.background.draw(batch, getX(), getY(), getWidth(), getHeight());
        }
        if (style.fontColor != null)
            color.mul(style.fontColor);
        cache.tint(color);
        cache.setPosition(getX(), getY());
        cache.draw(batch);
    }

    public float getPrefWidth() {
        if (wrap)
            return 0;
        if (sizeInvalid)
            scaleAndComputeSize();
        float width = bounds.width;
        Drawable background = style.background;
        if (background != null)
            width += background.getLeftWidth() + background.getRightWidth();
        return width;
    }

    public float getPrefHeight() {
        if (sizeInvalid)
            scaleAndComputeSize();
        float height = bounds.height - style.font.getDescent() * 2;
        Drawable background = style.background;
        if (background != null)
            height += background.getTopHeight() + background.getBottomHeight();
        return height;
    }

    public TextBounds getTextBounds() {
        if (sizeInvalid)
            scaleAndComputeSize();
        return bounds;
    }

    /** If false, the text will only wrap where it contains newlines (\n). The preferred size of the label will be the text bounds.
     * If true, the text will word wrap using the width of the label. The preferred width of the label will be 0, it is expected
     * that the something external will set the width of the label. Default is false.
     * <p>
     * When wrap is enabled, the label's preferred height depends on the width of the label. In some cases the parent of the label
     * will need to layout twice: once to set the width of the label and a second time to adjust to the label's new preferred
     * height. */
    public void setWrap(boolean wrap) {
        this.wrap = wrap;
        invalidateHierarchy();
    }

    /** @param alignment Aligns each line of text horizontally and all the text vertically.
     * @see Align */
    public void setAlignment(int alignment) {
        setAlignment(alignment, alignment);
    }

    /** @param labelAlign Aligns all the text with the label widget.
     * @param lineAlign Aligns each line of text (left, right, or center).
     * @see Align */
    public void setAlignment(int labelAlign, int lineAlign) {
        this.labelAlign = labelAlign;

        if ((lineAlign & Align.left) != 0)
            this.lineAlign = HAlignment.LEFT;
        else if ((lineAlign & Align.right) != 0)
            this.lineAlign = HAlignment.RIGHT;
        else
            this.lineAlign = HAlignment.CENTER;

        invalidate();
    }

    public void setFontScale(float fontScale) {
        this.fontScaleX = fontScale;
        this.fontScaleY = fontScale;
        invalidateHierarchy();
    }

    public void setFontScale(float fontScaleX, float fontScaleY) {
        this.fontScaleX = fontScaleX;
        this.fontScaleY = fontScaleY;
        invalidateHierarchy();
    }

    public float getFontScaleX() {
        return fontScaleX;
    }

    public void setFontScaleX(float fontScaleX) {
        this.fontScaleX = fontScaleX;
        invalidateHierarchy();
    }

    public float getFontScaleY() {
        return fontScaleY;
    }

    public void setFontScaleY(float fontScaleY) {
        this.fontScaleY = fontScaleY;
        invalidateHierarchy();
    }

    /** When true the text will be truncated "..." if it does not fit within the width of the label. Default is false. */
    public void setEllipsis(boolean ellipsis) {
        this.ellipsis = ellipsis;
    }

    /** Allows subclasses to access the cache in {@link #draw(Batch, float)}. */
    protected BitmapFontCache getBitmapFontCache() {
        return cache;
    }

    /** The style for a label, see {@link Label}.
     * @author Nathan Sweet */
    static public class LabelStyle {
        public BitmapFont font;
        /** Optional. */
        public Color fontColor;
        /** Optional. */
        public Drawable background;

        public LabelStyle() {
        }

        public LabelStyle(BitmapFont font, Color fontColor) {
            this.font = font;
            this.fontColor = fontColor;
        }

        public LabelStyle(LabelStyle style) {
            this.font = style.font;
            if (style.fontColor != null)
                fontColor = new Color(style.fontColor);
            background = style.background;
        }
    }
}