RatingItem.java

/*
 * Copyright © 2012 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.favouriteartists;

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

import com.nokia.example.favouriteartists.tool.Log;
import com.nokia.example.favouriteartists.tool.Util;
import com.nokia.mid.ui.gestures.*;


/**
 * Displays rating stars that can be tapped to modify the rating. Rating stars are displayed either empty or
 * filled, depending on rating. Tapping the first star when rating is 1 will change rating to 0.
 * As with other form items, the user first has to attain focus for the item by tapping it, after that,
 * the item will receive gesture events upon successive taps.
 * <p>
 * This class illustrates the use of Gestures API with multiple gesture zones and in a CustomItem.
 * Points of interests are: the constructor {@link #RatingItem(ImageProvider, int, short)} and
 * Gestures API callback {@link #gestureAction(Object, GestureInteractiveZone, GestureEvent)}
 * <p>
 * Gestures used in this example:
 * {@link GestureInteractiveZone#GESTURE_TAP}
 */
public class RatingItem extends CustomItem implements GestureListener {

    // Constants
    /** Filled rating star image filename */
    private static final String BIG_STAR_FILLED_IMG_FILE = "/big_star_filled.png";
    /** Empty rating star image filename */
    private static final String BIG_STAR_EMPTY_IMG_FILE = "/big_star_empty.png";
    /** Vertical padding */
    private static final int V_PAD = 2;
    /** Horizontal padding */
    private static final int H_PAD = 20;
    /** Number of stars displayed in the item */
    private static final int STAR_COUNT = 3;
    /** Width of individual gesture zone */
    private static final int GESTURE_ZONE_WIDTH = 60;
    /** Height of individual gesture zone */
    private static final int GESTURE_ZONE_HEIGHT = 60;

    // Member data
    /** Width of the item */
    int width;
    /** Height of the item */
    int height;
    /** The font used for drawing title text */
    Font font;
    /** Filled star image */
    Image starImgFilled;
    /** Empty star image */
    Image starImgEmpty;
    /** The gesture zones for each star. */
    GestureInteractiveZone[] zones;
    /** Rating value. */
    int rating;


    /**
     * Constructor.
     *
     * @param imageProvider For image retrieval.
     * @param width Width of the item.
     * @param rating Initial rating.
     * @throws FavouriteArtistsException
     */
    protected RatingItem(ImageProvider imageProvider, int width, short rating) throws FavouriteArtistsException {
        super(null);

        this.width = width;
        this.rating = rating;

        // Create images
        starImgFilled = imageProvider.getImage(BIG_STAR_FILLED_IMG_FILE);
        starImgEmpty = imageProvider.getImage(BIG_STAR_EMPTY_IMG_FILE);

        // Get font
        font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);

        // Calculate height
        height += V_PAD * 2;
        height += font.getHeight();
        height += GESTURE_ZONE_HEIGHT;

        // Create GIZ for each star icon
        zones = new GestureInteractiveZone[STAR_COUNT];
        int starX = 0;
        int starY = font.getHeight() + V_PAD;
        for(int i = 0; i < STAR_COUNT; i++){
            GestureInteractiveZone zone =
                new GestureInteractiveZone(GestureInteractiveZone.GESTURE_TAP);
            // Set dimensions of the GIZ in relation to the Displayable
            zone.setRectangle(starX, starY, GESTURE_ZONE_WIDTH, GESTURE_ZONE_HEIGHT);
            // Register the GIZ
            if(GestureRegistrationManager.register(this, zone) != true){
                throw new FavouriteArtistsException("GestureRegistrationManager.register() failed!");
            }
            // Add a listener for gesture events.
            GestureRegistrationManager.setListener(this, this);
            zones[i] = zone;
            starX += starImgFilled.getWidth() + H_PAD;
        }
    }

    /**
     * @see javax.microedition.lcdui.CustomItem#getMinContentHeight()
     */
    protected int getMinContentHeight() {

        return height;
    }


    /**
     * @see javax.microedition.lcdui.CustomItem#getMinContentWidth()
     */
    protected int getMinContentWidth() {

        return width;
    }


    /**
     * @see javax.microedition.lcdui.CustomItem#getPrefContentHeight(int)
     */
    protected int getPrefContentHeight(int width) {

        return height;
    }


    /**
     * @see javax.microedition.lcdui.CustomItem#getPrefContentWidth(int)
     */
    protected int getPrefContentWidth(int height) {

        return width;
    }


    /**
     * @see javax.microedition.lcdui.CustomItem#paint(javax.microedition.lcdui.Graphics, int, int)
     */
    protected void paint(Graphics g, int w, int h) {
        // Draw the title text
        Util.drawStringCenteredAndTruncated(g, "Rating:", font, 0, 0, w, font.getHeight(),
                Graphics.TOP | Graphics.LEFT );
        for(int i = 0; i < zones.length; i++) {
            GestureInteractiveZone zone = zones[i];
            Image image = null;
            // Determine whether a full or empty star needs to be drawn
            if(i < rating){
                image = starImgFilled;
            } else{
                image = starImgEmpty;
            }
            // Draw a star image
            Util.drawImageCentered(g, image, zone.getX(), zone.getY(),
                    zone.getWidth(), zone.getHeight());
        }
    }

    /**
     * Setter for rating.
     *
     * @param rating
     */
    public void setRating(short rating){
        this.rating = rating;
    }

    /**
     * Getter for rating.
     *
     * @return rating
     */
    public short getRating(){
        return (short)rating;
    }

    /**
     * @see com.nokia.mid.ui.gestures.GestureListener#gestureAction(java.lang.Object, com.nokia.mid.ui.gestures.GestureInteractiveZone, com.nokia.mid.ui.gestures.GestureEvent)
     */
    public void gestureAction(Object container, GestureInteractiveZone zone, GestureEvent event) {
        if (Log.TEST) Log.note("[RatingItem#gestureAction]-->");

        switch (event.getType()) {
        case GestureInteractiveZone.GESTURE_TAP:{
            if (Log.TEST) Log.note("[RatingItem#gestureAction] tap");
            // Only tap gesture is handled here
            for(int i = 0; i < zones.length; i++){
                if(zone == zones[i]){
                    // Special case; change rating to zero if first star is tapped when rating is already 1.
                    if(rating == 1 && i == 0){
                        rating = 0;
                    } else {
                        rating = i + 1;
                    }
                    repaint();
                    break;
                }
            }
            break;
        }
        default:
            break;
        }
    }
}