BaseView.java

/*
 * Copyright © 2011 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.wordpress.views;

import com.nokia.example.wordpress.components.DataModel;
import com.nokia.example.wordpress.WordpressMidlet;
import com.nokia.example.wordpress.components.OptionsMenu;
import com.nokia.example.wordpress.helpers.ImageLoader;
import java.io.IOException;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

/**
 * Base class for views.
 */
public abstract class BaseView {

    /**
     * View identifier
     */
    protected int id;
    /**
     * Position of the view on screen, x-coordinate.
     */
    protected int x;
    /**
     * Position of the view on screen, y-coordinate.
     */
    protected int y;
    /**
     * Available width on screen to be used.
     */
    protected int width;
    /**
     * Available height on screen to be used.
     */
    protected int height;
    /**
     * Midlet instance
     */
    protected WordpressMidlet midlet = WordpressMidlet.getInstance();
    /**
     * ViewMaster instance
     */
    protected ViewMaster viewMaster = ViewMaster.getInstance();
    /**
     *  DataModel instance.
     */
    protected DataModel data = DataModel.getInstance();
    /**
     * Active state. Active views can be drawn and animated.
     */
    public boolean active = false;
    /**
     * Options menu for the view.
     */
    protected OptionsMenu menu = null;
    /**
     * Left softkey label
     */
    protected String softkey1Label = "";
    /**
     * Middle softkey label
     */
    protected String softkey2Label = "";
    /**
     * Right softkey label
     */
    protected String softkey3Label = "";
    /**
     * Tabbar image
     */
    protected Image tabHeader;
    /**
     * Tab highlight flash color.
     */
    public int tabHighlight = 0;
    /**
     * Tab highlight flash color delta value.
     */
    public int tabHighlightDirection = 16;
    /**
     * Graphics to paint to the screen canvas.
     */
    protected Graphics g;
    /**
     * If this is set to true, tab flashing animation and drawing are
     * enabled.
     */
    protected boolean haveTabs = false;
    /**
     * If set to true, a busy animation is drawn on the screen.
     */
    protected boolean busy = false;
    /**
     * Rotating busy indicator orb state.
     */
    private int busyIndicatorAngle = 0;

    BaseView(Graphics g, int id, int x, int y, int width, int height) {
        this.id = id;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.g = g;

        try {
            tabHeader = ImageLoader.getInstance().loadImage("/header.png");
        } catch (IOException e) {
        }
    }

    /**
     * After this call the view will be painted on screen by calling draw().
     */
    public void activate() {

        System.out.println("activating " + id());
        busy = false;
        active = true;
    }

    /**
     *  After this call the view should not do anything.
     */
    public void deactivate() {
        System.out.println("deactivating " + id());
        active = false;
    }

    /**
     * Empty implementation.
     * Draw event.
     */
    public void draw(int x, int y, int width, int height) {
    }

    /**
     * Empty implementation
     * Key press event.
     */
    public void keyPressed(int keyCode) {
    }

    /**
     * Empty implementation.
     * Key released event.
     */
    public void keyReleased(int keyCode) {
    }

    /**
     * Empty implementation.
     * Called when view transition animation is done.
     */
    public void transitionFinished() {
    }

    /**
     *  Returns the view id.
     */
    public int id() {
        return id;
    }

    /**
     * Draws the sofkeys.
     */
    protected void drawSoftkeys() {
        if (menu != null && menu.isVisible()) {
            return;
        }

        // Visual enchancement in the form of a grey line
        g.setColor(Visual.SOFTKEY_DECORATOR_COLOR);
        g.drawLine(30, height - Visual.SOFTKEYBAR_HEIGHT + 2, width - 30, height - Visual.SOFTKEYBAR_HEIGHT + 2);

        g.setColor(Visual.BACKGROUND_COLOR);
        g.fillRect(0, height - Visual.SOFTKEY_FONT.getHeight(), width, Visual.SOFTKEY_FONT.getHeight());

        g.setFont(Visual.SOFTKEY_FONT);
        g.setColor(Visual.SOFTKEY_TEXT_COLOR);
        g.drawString(softkey1Label, 0, height, g.LEFT | g.BOTTOM);
        g.drawString(softkey2Label, width / 2, height, g.HCENTER | g.BOTTOM);
        g.drawString(softkey3Label, width, height, g.RIGHT | g.BOTTOM);
    }

    public int tabsHeight() {
        return tabHeader.getHeight();
    }

    /**
     * Draws the tabs.
     */
    protected void drawTabs() {
        if (!haveTabs) {
            return;
        }
        int selectorX1 = 10;
        int selectorX2 = 110;
        if (id() == ViewMaster.VIEW_COMMENTS || id() == ViewMaster.VIEW_SINGLECOMMENT || id() == ViewMaster.VIEW_COMMENTSFORPOST) {
            selectorX1 = 122;
            selectorX2 = 222;
        }
        g.setColor(0);
        g.fillRect(0, 0, width, tabsHeight());
        g.setColor(0, tabHighlight, tabHighlight);
        g.fillRect(selectorX1, 0, selectorX2 - selectorX1, tabsHeight());
        g.drawImage(tabHeader, 0, 0, g.TOP | g.LEFT);
    }

    /**
     * Draws a red object that acts as an update indicator. Used when doing
     * some lenghty operations, such as posting. Animation is provided in
     * animationRunner().
     */
    private void drawBusyIndicator(Graphics g) {
        // Draw an animating red orb.
        int size = 40;
        g.setColor((busyIndicatorAngle * 256) / 360, 0, 0);
        g.fillArc(width / 2 - size / 2, height / 2 - size / 2, size, size, busyIndicatorAngle, busyIndicatorAngle + 10);
        viewMaster.updateScreen(width / 2 - size / 2, height / 2 - size / 2, size, size);
    }

    /**
     * Animation runner, called from the timer thread.
     * Graphics contexts are accessed synchronously so as to avoid
     * drawing unexpected things as drawing is also done in the main
     * application thread.
     */
    public void animate() {
        if (!viewMaster.isShown() || !active) {
            return;
        }

        // Check if menu is being animated.
        if (menu != null && menu.isVisible()) {
            if (menu.animate()) {
                synchronized (g) {
                    menu.draw(g);
                    viewMaster.updateScreen(menu.x, menu.y, menu.width, menu.height);
                }
            }
            return;
        }

        // Flashing tabs...
        if (haveTabs && !busy) {
            // Tab bar blinking animation:
            tabHighlight += tabHighlightDirection;
            if (tabHighlight > 255) {
                tabHighlight = 255;
                tabHighlightDirection = -tabHighlightDirection;
            }

            if (tabHighlight < 0) {
                tabHighlight = 0;
                tabHighlightDirection = -tabHighlightDirection;
            }

            // Flush only tab bar area
            synchronized (g) {
                drawTabs();
                viewMaster.updateScreen(0, 0, width, tabsHeight());
            }
        }

        // ...and the busy indicator
        if (busy) {
            busyIndicatorAngle = (busyIndicatorAngle + 7) % 360;
            synchronized (g) {
                drawBusyIndicator(g);
            }
        }
    }

    /**
     * Graphics setter. This is used to change the target when
     * doing view transitions.
     * @param g
     */
    public void setGraphics(Graphics g) {
        this.g = g;
    }
}