List.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.components;

import com.nokia.example.wordpress.views.ViewMaster;
import com.nokia.example.wordpress.views.Visual;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;

/**
 * List view custom UI control.
 * Provides a cursor for focus and a scrollbar for visualization.
 * Uses a ListDrawer based class for drawing each line of the list.
 */
public class List {

    /**
     * Width of the scrollbar in pixels.
     */
    private final static int SCROLLBAR_WIDTH = 4;
    /**
     * The index of the top visible row. Index points to the items in the ListDrawer.
     */
    //private int topRowIndex = 0;
    /**
     * The index of the focused row, ie. where the cursor is. Index points to the items in the ListDrawer.
     */
    private int focusedRowIndex = 0;
    /**
     * Number of visible rows to be displayed. Calculated using the available
     * height and the height of a list row given by ListDrawer.
     */
    private int listRows = 0;
    /**
     * Drawer instance for doing the drawing of rows.
     */
    private ListDrawer drawer;
    /**
     * Top left x coordinage
     */
    private int x;
    /**
     *  Top left y coordinate
     */
    private int y;
    /**
     * Width for the list
     */
    private int width;
    /**
     * Height for the list
     */
    private int height;
    /**
     * Actual list data.
     */
    Vector data = null;
    /**
     * View reference for background drawing.
     */
    private ViewMaster view;

    /**
     * Constructor. Dimensions and position given as parameters.
     * @param view
     * @param x
     * @param y
     * @param width
     * @param height
     */
    public List(ViewMaster view, int x, int y, int width, int height, ListDrawer drawer) {
        this.view = view;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.drawer = drawer;
        listRows = height / drawer.itemHeight();
    }

    /**
     * Returns the drawer instance.
     * @return
     */
    public ListDrawer getDrawer() {
        return drawer;
    }

    /**
     * Sets the data to be displayed.
     * @param data
     */
    public void setData(Vector data) {
        this.data = data;
    }

    /**
     * Returns the data for accessing.
     * @return
     */
    public Vector getData() {
        return data;
    }

    /**
     * Paints the list.
     * @param g
     */
    public void draw(Graphics g) {

        if (drawer == null) {
            return;
        }

        if (focusedRowIndex < 0) {
            focusedRowIndex = 0;
        }

        if (focusedRowIndex >= data.size()) {
            focusedRowIndex = data.size() - 1;
        }

        // Focus on the middle when scrolling
        int topRowIndex = focusedRowIndex - listRows / 2;
        if (topRowIndex < 0) {
            topRowIndex = 0;
        }
        int maxTopRowIndex = data.size() - listRows;
        if (maxTopRowIndex < 0) {
            maxTopRowIndex = 0;
        }
        if (topRowIndex + listRows >= data.size()) {
            topRowIndex = maxTopRowIndex;
        }

        int prevClipX = g.getClipX();
        int prevClipY = g.getClipY();
        int prevClipWidth = g.getClipWidth();
        int prevClipHeight = g.getClipHeight();

        // Ensure that text does not overlap outside our allocated area.
        g.setClip(x, y, width, height);

        // Scrollbar background
        view.drawBackground(g, width - SCROLLBAR_WIDTH, y, SCROLLBAR_WIDTH, height, false);
        
        // Row drawing loop
        int y = 0;
        for (int i = topRowIndex; i < data.size(); i++) {
            drawer.drawItem(data, g, i, this.x, this.y + y, width - SCROLLBAR_WIDTH, height, i == focusedRowIndex);
            y += drawer.itemHeight();
            if (y >= height) {
                break;
            }
        }

        // Fill the rest of the area (if any) with background. Rely on clip
        // to avoid drawing over softkey labels.
        if (y < height) {
            view.drawBackground(g, this.x, this.y+y, width, height, false);
        }

        // Detemine the need for scrollbar, and the height for it.
        float scrollBarPercentage = (float) listRows / (float) data.size();
        if (scrollBarPercentage < 1) {
            int scrollBarHeight = (int) (height * scrollBarPercentage);
            int yPos = (height - scrollBarHeight) * topRowIndex / maxTopRowIndex;
            g.setColor(Visual.LIST_SCROLLBAR_COLOR);
            g.fillRect(width - SCROLLBAR_WIDTH, yPos + this.y, SCROLLBAR_WIDTH, scrollBarHeight);
        }

        g.setClip(prevClipX, prevClipY, prevClipWidth, prevClipHeight);
    }

    /**
     * Move cursor up one row.
     */
    public void focusUp() {
        focusedRowIndex--;
    }

    /**
     * Move cursor down one row.
     */
    public void focusDown() {
        focusedRowIndex++;
    }

    /**
     * Returns the focused row index in the ListDrawer.
     * @return
     */
    public int focusIndex() {

        return focusedRowIndex;
    }
}