Home‎ > ‎

BitmapButton for BlackBerry 5

posted Mar 28, 2011, 5:57 AM by Pieter-Bas IJdens   [ updated Jul 28, 2011, 12:44 AM ]
Two days ago I posted a Blackberry API (6.0) class for creating image buttons. Obviously in the BB5 API there was no support yet for disabling buttons. Included below is an updated version for BB5, which also has a nice feature: It allows the creator to specify a provider for the images, rather than the images themselves. I use this feature to change the meaning, and the image, of a button on-the-fly depending on the state of the underlying object (getting a bit tired of having to fix scrolling issues and virtual keyboard issues all the time when swapping-out controls)

package nl.sevensteps.blackberry.widgets;

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.XYEdges;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.decor.BorderFactory;

/**
 * Button field with a bitmap as its label.
 */
public class BitmapButtonField extends ButtonField implements DrawStyle {
    public static final int STATE_FOCUS = 0;
    public static final int STATE_NORMAL = 1;
    public static final int STATE_DISABLED = 2;

    private Bitmap _bitmap;
    private boolean _isEnabled = true;

    private IBitmapProvider _provider = null;

    BitmapButtonField(final IBitmapProvider provider) {
        super(Field.FOCUSABLE | ButtonField.CONSUME_CLICK);

        _provider = provider;

        setLabel("");
        _bitmap = getNormalBitmap();

        // I don't care which visual state we're in, we do NOT want to draw a
        // border, ever.
        setBorder(VISUAL_STATE_FOCUS,
                BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
        setBorder(VISUAL_STATE_NORMAL,
                BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
        setBorder(VISUAL_STATE_ACTIVE,
                BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
        setBorder(VISUAL_STATE_DISABLED,
                BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
        setBorder(VISUAL_STATE_DISABLED_FOCUS,
                BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));

    }

    BitmapButtonField(final Bitmap noFocus, final Bitmap focus,
            final Bitmap disabled) {
        this(new IBitmapProvider() {

            public Bitmap getBitmap(final int state) {
                switch (state) {
                case STATE_DISABLED:
                    return disabled;
                case STATE_FOCUS:
                    return focus;
                default:
                    return noFocus;
                }
            }
        });
    }

    protected void onFocus(final int direction) {
        if (_isEnabled) {
            _bitmap = getFocusedBitmap();
        } else {
            _bitmap = getDisabledBitmap();
        }
        invalidate();
    }

    protected void onUnfocus() {
        if (_isEnabled) {
            _bitmap = getNormalBitmap();
        } else {
            _bitmap = getDisabledBitmap();
        }
        invalidate();
    }

    public void setEnabled(final boolean enabled) {
        _isEnabled = enabled;
        if (!enabled) {
            setVisualState(Field.VISUAL_STATE_DISABLED);
            _bitmap = getDisabledBitmap();
        } else if (isFocus()) {
            setVisualState(Field.VISUAL_STATE_FOCUS);
            _bitmap = getFocusedBitmap();
        } else {
            setVisualState(Field.VISUAL_STATE_NORMAL);
            _bitmap = getNormalBitmap();
        }
        invalidate();
    }

    public int getPreferredWidth() {
        return getNormalBitmap().getWidth();
    }

    public int getPreferredHeight() {
        return getNormalBitmap().getHeight();
    }

    protected void layout(final int width, final int height) {
        setExtent(getPreferredWidth(), getPreferredHeight());
    }

    protected void paint(final Graphics graphics) {
        graphics.drawBitmap(0, 0, _bitmap.getWidth(), _bitmap.getHeight(),
                _bitmap, 0, 0);
    }

    protected void applyTheme() {
        // Not applying the theme as this will cause the border to be rendered,
        // which we do not want to see, ever.
    }

    protected void applyTheme(final Graphics arg0, final boolean arg1) {
        // Not applying the theme as this will cause the border to be rendered,
        // which we do not want to see, ever.
    }

    private Bitmap getFocusedBitmap() {
        return _provider.getBitmap(STATE_FOCUS);
    }

    private Bitmap getDisabledBitmap() {
        return _provider.getBitmap(STATE_DISABLED);
    }

    private Bitmap getNormalBitmap() {
        return _provider.getBitmap(STATE_NORMAL);
    }

    /**
     * When changing the contents of the bitmaps on the fly (e.g. as part of a
     * button press), it's nice to force redraw.
     * 
     * @param hasFocus
     *            Especially when a result of button-clicks, the proper focus
     *            state is temporarily lost. This happens to coincide with this
     *            call. Therefore, as the caller usually is properly aware of
     *            the state, the caller can also just tell s what the focus
     *            state should be.
     */
    public void redraw(final boolean hasFocus) {
        setDirty(true);
        // Cheap trick to make sure the bitmaps are set properly without having
        // to re-implement all logic.
        if (hasFocus) {
            setFocus();
            onFocus(0);
        } else {
            onUnfocus();
        }
        invalidate();
    }

    /**
     * Redraw (e.g. after a button image change)
     */
    public void redraw() {
        // Unfortunately, this has a habit of returning false when we all know
        // the value is true.
        redraw(isFocus());
    }

    /**
     * Override to implement _isEnabled.
     */
    public boolean isFocusable() {
        return _isEnabled && super.isFocusable();
    }

    /**
     * Interface that is to be implemented by classes.
     */
    public interface IBitmapProvider {
        public Bitmap getBitmap(int state);
    }
}

Comments