TipBox.java

/**
 * Copyright (c) 2012-2013 Nokia Corporation. All rights reserved.
 * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation.
 * Oracle and Java are trademarks or registered trademarks of Oracle and/or its
 * affiliates. Other product and company names mentioned herein may be trademarks
 * or trade names of their respective owners.
 * See LICENSE.TXT for license information.
 */

package com.nokia.example.amaze.ui;

import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import com.nokia.example.amaze.Main;
import com.nokia.example.amaze.model.MyTimer;

/**
 * A small dialog-like box for displaying tips for the user.  
 */
public class TipBox implements MyTimer.Listener {
    // Constants
    private static final int WIDTH = 220;
    private static final int TEXT_WIDTH = 180;
    private static final int TEXT_HEIGHT = 100;
    private static final int TEXT_X_MARGIN = 20;
    private static final int TEXT_Y_TOP_MARGIN = 40;
    private static final int DEFAULT_Y_POSITION = 180;
    private static final int X_POSITION = (240 - WIDTH) / 2;
    private static final int TIMEOUT = 8000; // Milliseconds
    
    // Members
    static private TipBox _instance = null;
    private Image _backgroundImage = null;
    private TextWrapper _textWrapper = null;
    private String _text = null;
    private boolean _visible = false;
    private int _screenHeight = 0;
    private int _y = 0;
    private int _textY = 0;

    /**
     * Constructor.
     */
    private TipBox(final int screenHeight) {
        _backgroundImage = Main.makeImage("/graphics/tip-box-bg.png");
        _textWrapper = TextWrapper.instance(Font.getDefaultFont(), TEXT_WIDTH);
        _screenHeight = screenHeight;
        
        if (_backgroundImage == null) {
            _y = DEFAULT_Y_POSITION;
        }
        else {
            _y = (screenHeight - _backgroundImage.getHeight()) / 2;
        }
    }

    /**
     * Shows the tip box.
     * @param text The tip text to show.
     */
    static public void show(final String text, final int screenHeight) {
        if (_instance == null) {
            _instance = new TipBox(screenHeight);
        }
        
        if (text != null && text.length() > 0) {
            _instance._text = text;
            _instance._visible = true;
            _instance._textWrapper.setText(_instance._text);
            _instance._textY =
                    (TEXT_HEIGHT - _instance._textWrapper.lineCount()
                            * _instance._textWrapper.lineHeight()) / 2;
            
            // Set the timer to hide the tip box after timeout
            MyTimer.instance().addListener(_instance, false, TIMEOUT);
        }
    }

    /**
     * Hides the tip box.
     */
    static public void hide() {
        // Automatic tip showing ->
        if (tipsToShow > 0) {
            _instance._visible = false;
            _instance._text = null;
            return;
        }
        // <- Automatic tip showing
        
        if (_instance != null) {
            MyTimer.instance().removeListener(_instance);
            _instance._visible = false;
            _instance._text = null;
            free();
        }
    }

    /** 
     * @return True if the tip is visible, false otherwise.
     */
    static public boolean visible() {
        if (_instance != null) {
            return _instance._visible;
        }
        
        return false;
    }

    /**
     * Releases the handle of the singleton instance so the garbage collector
     * can collect it.
     */
    static public void free() {
        if (_instance != null) {
            System.out.println("TipBox::free(): Releasing the instance.");
            _instance = null;
        }
    }

    // LOGIC FOR AUTOMATICALLY SHOWING THE TIPS STARTS HERE
    // But some of it is added to timeout() and hide()
    static final private int TIP_INTERVAL = TIMEOUT; // Milliseconds
    static final private String[] TIPS =
        {
        /* 3rd */ "Tip: To recalibrate the accelerometer sensor pause and resume the game.",
        /* 2nd */ "Tip: Douple tap the screen to toggle between the set and the default zoom.",
        /* 1st */ "Tip: Pinch the screen to zoom in and out."
        };
    static private int tipsToShow = TIPS.length;

    /**
     * Starts the timed tip showing procedure.
     */
    static public void showTips(final int screenHeight) {
        if (_instance == null) {
            _instance = new TipBox(screenHeight);
        }
        
        MyTimer.instance().addListener(_instance, true, TIP_INTERVAL);
    }
    // LOGIC FOR AUTOMATICALLY SHOWING THE TIPS STOPS HERE

    /**
     * Static public interface for painting the tip box.
     * @param graphics
     */
    static public void paint(Graphics graphics) {
        if (_instance != null) {
            _instance.doPaint(graphics);
        }
    }

    /**
     * From MyTimer.Listener.
     * Hides the tip box.
     */
    public void onTimeout() {
        System.out.println("TipBox::onTimeout()");
        
        // Automatic tip showing ->
        if (tipsToShow > 0) {
            if (_text == null) {
                show(TIPS[tipsToShow - 1], _screenHeight);
                tipsToShow--;
            }
            else {
                _visible = false;
                _text = null;
            }
            
            return;
        }
        // <- Automatic tip showing
        
        hide();
    }

    /**
     * Paints the tip box.
     * @param graphics
     */
    private void doPaint(Graphics graphics) {
        if (!_visible || _text == null || _text.length() == 0) {
            return;
        }
        
        // Draw background
        final int topLeft = Graphics.TOP | Graphics.LEFT;
        graphics.drawImage(_backgroundImage, X_POSITION, _y, topLeft);
        
        // Draw the tip text
        graphics.setColor(MazeCanvas.TEXT_COLOR);
        _textWrapper.setWidth(TEXT_WIDTH);
        int y = _y + TEXT_Y_TOP_MARGIN + _textY;
        
        try {
            _textWrapper.setText(_text);
            String line = null;

            while (_textWrapper.hasMoreLines()) {
                line = _textWrapper.nextLine();
                graphics.drawString(line,
                        X_POSITION + TEXT_X_MARGIN
                            + (TEXT_WIDTH - _textWrapper.lineWidth(line)) / 2,
                        y, topLeft);
                y += _textWrapper.lineHeight();
            }
        }
        catch (IllegalArgumentException e) {}
    }
}