Label.java :  » Java-2D » pulpcore » pulpcore » sprite » Java Open Source

Java Open Source » Java 2D » pulpcore 
pulpcore » pulpcore » sprite » Label.java
/*
    Copyright (c) 2007-2009, Interactive Pulp, LLC
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without 
    modification, are permitted provided that the following conditions are met:

        * Redistributions of source code must retain the above copyright 
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright 
          notice, this list of conditions and the following disclaimer in the 
          documentation and/or other materials provided with the distribution.
        * Neither the name of Interactive Pulp, LLC nor the names of its 
          contributors may be used to endorse or promote products derived from 
          this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
    POSSIBILITY OF SUCH DAMAGE.
*/

package pulpcore.sprite;

import java.lang.ref.WeakReference;
import pulpcore.animation.Int;
import pulpcore.animation.Property;
import pulpcore.animation.PropertyListener;
import pulpcore.CoreSystem;
import pulpcore.image.CoreFont;
import pulpcore.image.CoreGraphics;
import pulpcore.image.CoreImage;
import pulpcore.math.CoreMath;
import pulpcore.util.StringUtil;

/**
    The Label is a Sprite that displays text. The text can be formatted
    using printf-style parameters 
    @see pulpcore.util.StringUtil
*/
public class Label extends Sprite {
    
    private String formatText;
    private String displayText;
    private Object[] formatArgs;
    private WeakListener formatArgListener;
    
    private int stringWidth;
    private CoreFont font;
    private boolean autoWidth;
    private boolean autoHeight;
    
    public final Int numDisplayChars = new Int(this);
    
    public Label(String text, int x, int y) {
        this(null, text, x, y, -1, -1);
    }
    
    public Label(String text, double x, double y) {
        this(null, text, x, y, -1, -1);
    }
    
    /**
        If height < 0, the height is automatically set to fit the font
        height.
    */
    public Label(String text, int x, int y, int w, int h) {
        this(null, text, x, y, w, h);
    }
    
    /**
        If height < 0, the height is automatically set to fit the font
        height.
    */
    public Label(String text, double x, double y, double w, double h) {
        this(null, text, x, y, w, h);
    }
    
    public Label(CoreFont font, String text, int x, int y) {
        this(font, text, x, y, -1, -1);
    }
    
    public Label(CoreFont font, String text, double x, double y) {
        this(font, text, x, y, -1, -1);
    }
    
    /**
        If height < 0, the height is automatically set to fit the font
        height.
    */
    public Label(CoreFont font, String text, int x, int y, int w, int h) {
        super(x, y, w, h);
        
        init(font, text, w < 0, h < 0);
    }
    
    /**
        If height < 0, the height is automatically set to fit the font
        height.
    */
    public Label(CoreFont font, String text, double x, double y, double w, double h) {
        super(x, y, w, h);
        
        init(font, text, w < 0, h < 0); 
    }
    
    private void init(CoreFont font, String text, boolean autoWidth, boolean autoHeight) {
        if (font == null) {
            this.font = CoreFont.getSystemFont();
        }
        else {
            this.font = font;
        }
        
        this.autoWidth = autoWidth;
        this.autoHeight = autoHeight;
        
        setText(text);
    }
    
    public void propertyChange(Property p) {
        super.propertyChange(p);

        if (p == numDisplayChars) {
            setDirty(true);
        }
        
        if (p == numDisplayChars || 
            (p == super.width && !autoWidth) || 
            (p == super.height && !autoHeight))
        {
            pack();
            return;
        }
        
        if (formatArgs != null) {
            for (int i = 0; i < formatArgs.length; i++) {
                if (p == formatArgs[i]) {
                    format();
                    return;
                }
            }
        }
    }
    
    protected int getNaturalWidth() {
        int w = stringWidth;
        if (numDisplayChars.get() < displayText.length()) {
            w = font.getStringWidth(displayText, 0, numDisplayChars.get());
        }
        return CoreMath.toFixed(w);
    }
    
    protected int getNaturalHeight() {
        return CoreMath.toFixed(font.getHeight());
    }
    
    public void update(int elapsedTime) {
        super.update(elapsedTime);
        
        numDisplayChars.update(elapsedTime);
        
        CoreImage fontImage = font.getImage();
        fontImage.update(elapsedTime);
    }
    
    private void pack() {
        if (autoWidth) {
            setDirty(true);
            if (autoHeight) {
                width.setAsFixed(getNaturalWidth());
            }
            else {
                width.setAsFixed(CoreMath.mulDiv(getNaturalWidth(), height.getAsFixed(), 
                    getNaturalHeight()));
            }
        }
        if (autoHeight) {
            setDirty(true);
            if (autoWidth) {
                height.setAsFixed(getNaturalHeight());
            }
            else {
                height.setAsFixed(CoreMath.mulDiv(getNaturalHeight(), width.getAsFixed(), 
                    getNaturalWidth()));
            }
        }
    }

    //@Override
    protected boolean isTransparent(int localX, int localY) {
        if (localX < 0 || localY < 0 || localY >= font.getHeight()) {
            return true;
        }
        else {
            int numChars = Math.min(numDisplayChars.get(), displayText.length());
            for (int i = 0; i < numChars; i++) {
                int cx = font.getCharPosition(displayText, 0, i);
                char ch = displayText.charAt(i);
                //int charWidth = font.getCharWidth(ch);
                //if (localX < cx + charWidth) {
                    if (!font.isTransparent(ch, localX - cx, localY)) {
                        return false;
                    }
                //}
            }
            return true;
        }
    }
    
    /**
        @return this Label's font.
    */
    public CoreFont getFont() {
        return font;
    }
    
    /**
        Set this Label's font and resizes it if necessary. If font is {@code null}, the system
        font is used.
    */
    public void setFont(CoreFont font) {
        if (font == null) {
            font = CoreFont.getSystemFont();
        }
        if (this.font != font) {
            this.font = font;
            format();
        }
    }
    
    /**
        @return the formatted display text.
    */
    public String getText() {
        return displayText;
    }
    
    public void setText(String text) {
        this.formatText = text;
        format();
    }
    
    public void setFormatArg(Object arg) {
        setFormatArgs(new Object[] { arg });
    }
    
    public void setFormatArgs(Object[] args) {
        removeFormatArgListeners();
        formatArgs = CoreSystem.arraycopy(args);
        if (formatArgs != null) {
            if (formatArgListener == null) {
                formatArgListener = new WeakListener(this);
            }
            for (int i = 0; i < formatArgs.length; i++) {
                if (formatArgs[i] instanceof Property) {
                    Property p = (Property)formatArgs[i];
                    checkFormatArgListeners(p);
                    p.addListener(formatArgListener);
                }
            }
        }
        format();
    }
    
    private void checkFormatArgListeners(Property p) {
        PropertyListener[] listeners = p.getListeners();
        for (int i = 0; i < listeners.length; i++) {
            if (listeners[i] instanceof WeakListener) {
                WeakListener l = (WeakListener)listeners[i];
                if (l.getListener() == null) {
                    p.removeListener(l);
                }
            }
        }
    }
    
    private void removeFormatArgListeners() {
        if (formatArgs != null && formatArgListener != null) {
            for (int i = 0; i < formatArgs.length; i++) {
                if (formatArgs[i] instanceof Property) {
                    ((Property)formatArgs[i]).removeListener(formatArgListener);
                }
            }
        }
    }
    
    private void format() {
        displayText = StringUtil.format(formatText, formatArgs);
        if (displayText == null) {
            displayText = "null";
        }
        stringWidth = font.getStringWidth(displayText);
        numDisplayChars.set(displayText.length());
        setDirty(true);
        pack();
    }
    
    protected void drawSprite(CoreGraphics g) {
        String currDisplayText = displayText;
        if (numDisplayChars.get() < displayText.length()) {
            currDisplayText = displayText.substring(0, numDisplayChars.get());
        }
        
        drawText(g, currDisplayText);
    }
    
    protected void drawText(CoreGraphics g, String text) {
        g.setFont(getFont());
        g.drawString(text);
    }
    
    /**
        Weak listener to prevent memory leaks. (Many throw-away Labels listening to one Property)
    */
    private static class WeakListener implements PropertyListener {
        
        private WeakReference reference;
        
        public WeakListener(PropertyListener l) {
            reference = new WeakReference(l);
        }
        
        public PropertyListener getListener() {
            return (PropertyListener)reference.get();
        }
        
        public void propertyChange(Property p) {
            PropertyListener l = getListener();
            if (l == null) {
                // The Label was garbage collected.
                p.removeListener(this);
            }
            else {
                l.propertyChange(p);
            }
        }
    }
    
    /**
        Creates a Group of Labels with the system font. The newline ('\n') character can be used 
        to specify explicit line breaks.
    */
    public static Group createMultilineLabel(String text, int x, int y) {
        return createMultilineLabel(new Group(x, y), CoreFont.getSystemFont(),
            StringUtil.split(text, '\n'));
    }
    
    /**
        Creates a Group of Labels with the system font. Word-wrapping is used to confine the
        text to the specified viewWidth. The newline ('\n') character can be used to specify 
        explicit line breaks.
    */
    public static Group createMultilineLabel(String text, int x, int y, int viewWidth) {
        return createMultilineLabel(new Group(x, y), CoreFont.getSystemFont(),
            StringUtil.wordWrap(text, CoreFont.getSystemFont(), viewWidth));
    }         
    
    /**
        Creates a Group of Labels with the system font. The newline ('\n') character can be used 
        to specify explicit line breaks.
    */
    public static Group createMultilineLabel(String text, double x, double y) {
        return createMultilineLabel(new Group(x, y), CoreFont.getSystemFont(),
            StringUtil.split(text, '\n'));
    }                                 
    
    /**
        Creates a Group of Labels with the system font. Word-wrapping is used to confine the
        text to the specified viewWidth. The newline ('\n') character can be used to specify 
        explicit line breaks.
    */
    public static Group createMultilineLabel(String text, double x, double y, int viewWidth) {
        return createMultilineLabel(new Group(x, y), CoreFont.getSystemFont(),
            StringUtil.wordWrap(text, CoreFont.getSystemFont(), viewWidth));
    }
    
    /**
        Creates a Group of Labels with the specified Font. The newline ('\n') character can be used 
        to specify explicit line breaks.
    */
    public static Group createMultilineLabel(CoreFont font, String text, int x, int y) {
        return createMultilineLabel(new Group(x, y), font, StringUtil.split(text, '\n'));
    }
    
    /**
        Creates a Group of Labels with the specified Font. Word-wrapping is used to confine the
        text to the specified viewWidth. The newline ('\n') character can be used to specify 
        explicit line breaks.
    */
    public static Group createMultilineLabel(CoreFont font, String text, int x, int y, 
        int viewWidth) 
    {
        return createMultilineLabel(new Group(x, y), font,
            StringUtil.wordWrap(text, font, viewWidth));
    }
    
    /**
        Creates a Group of Labels with the specified Font. The newline ('\n') character can be used 
        to specify explicit line breaks.
    */
    public static Group createMultilineLabel(CoreFont font, String text, double x, double y) {
        return createMultilineLabel(new Group(x, y), font, StringUtil.split(text, '\n'));
    }
    
    /**
        Creates a Group of Labels with the specified Font. Word-wrapping is used to confine the
        text to the specified viewWidth. The newline ('\n') character can be used to specify 
        explicit line breaks.
    */
    public static Group createMultilineLabel(CoreFont font, String text, double x, double y, 
        int viewWidth) 
    {
        return createMultilineLabel(new Group(x, y), font,
            StringUtil.wordWrap(text, font, viewWidth));
    }
    
    private static Group createMultilineLabel(Group group, CoreFont font, String[] lines) {
        int lineSpacing = font.getHeight() + (font.getHeight() / 8);
        for (int i = 0; i < lines.length; i++) {
            group.add(new Label(font, lines[i], 0, i * lineSpacing));
        }
        group.pack();
        return group;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.