DrawArea.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.paint.views;

import com.nokia.example.paint.Main;
import com.nokia.example.paint.helpers.DrawableLine;
import com.nokia.example.paint.touch.MultiTouchListener;
import com.nokia.example.paint.touch.MultiTouch;
import com.nokia.example.paint.views.components.ColorChangeListener;
import com.nokia.example.paint.views.components.ColorPicker;
import com.nokia.example.paint.views.components.ColorTool;
import com.nokia.example.paint.views.components.ColorToolS60;
import com.nokia.example.paint.views.components.FileSaveDialog;
import com.nokia.example.paint.views.components.Toolbar;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;

public class DrawArea extends GameCanvas implements ColorChangeListener, MultiTouchListener {

    public static final int SMALL_BRUSH = 4;
    public static final int MEDIUM_BRUSH = 6;
    public static final int LARGE_BRUSH = 8;
    public static final int XL_BRUSH = 10;
    private final int TOUCH_POINTS;
    private Graphics g;
    private Timer mTimer;
    private int[] previousX;
    private int[] previousY;
    private int brushWidth = SMALL_BRUSH;
    private Image drawing;
    private Graphics dg;
    private Toolbar toolbar;
    private ColorPicker colorpicker;
    private FileSaveDialog savedialog;
    private boolean drawingAllowed = true;
    private boolean renderDrawing = false;
    private Vector[] buffers;

    public DrawArea() {
        super(false);
        setFullScreenMode(true);
        int width = getWidth();
        int height = getHeight();
        drawing = Image.createImage(width, height - Toolbar.HEIGHT);
        dg = drawing.getGraphics();
        toolbar = new Toolbar(width);
        ColorTool colortool = width > 240 ? new ColorToolS60() : new ColorTool();
        colortool.colorChanged(0x000000); // initial color
        toolbar.addTool(colortool, 1);
        colorpicker = new ColorPicker(width);
        colorpicker.addListener(this);
        colorpicker.addListener(colortool);
        savedialog = new FileSaveDialog(this);

        MultiTouch.setTouchListener(this);
        TOUCH_POINTS = MultiTouch.getMaxPointers();
        buffers = new Vector[TOUCH_POINTS];
        previousX = new int[TOUCH_POINTS];
        previousY = new int[TOUCH_POINTS];

        for (int i = 0; i < TOUCH_POINTS; i++) {
            buffers[i] = new Vector();
            previousX[i] = -1;
            previousY[i] = -1;
        }
    }

    protected void showNotify() {
        mTimer = new Timer();
        g = getGraphics();
        g.drawImage(drawing, 0, Toolbar.HEIGHT, Graphics.LEFT | Graphics.TOP);
        TimerTask ui = new TimerTask() {

            public void run() {
                render();
                flushGraphics();
            }
        };
        mTimer.schedule(ui, 0, 60);
    }

    protected void hideNotify() {
        mTimer.cancel();
    }

    protected void render() {
        g.setClip(0, 0, getWidth(), getHeight());
        toolbar.render(g);
        if (renderDrawing) {
            g.drawImage(drawing, 0, Toolbar.HEIGHT, Graphics.LEFT | Graphics.TOP);
            renderDrawing = false;
        }
        else {
            if (drawingAllowed) {
                boolean changed = false;
                for (int i = 0; i < TOUCH_POINTS; i++) {
                    Vector buffer = buffers[i];
                    if (!buffer.isEmpty()) {
                        renderLines(buffer);
                        changed = true;
                    }
                }
                if (changed) {
                    g.drawImage(drawing, 0, Toolbar.HEIGHT, Graphics.LEFT | Graphics.TOP);
                }
            }
            else {
                g.drawImage(drawing, 0, Toolbar.HEIGHT, Graphics.LEFT | Graphics.TOP);
            }
            colorpicker.render(g);
            savedialog.render(g);
        }
    }

    private void renderLines(Vector buffer) {
        int l = buffer.size();
        DrawableLine[] currentLines = new DrawableLine[buffer.size()];
        for (int i = 0; i < l; i++) {
            currentLines[i] = (DrawableLine) buffer.elementAt(i);
        }

        int s = currentLines.length;
        float divider = brushWidth / 3;
        for (int j = 0; j < s; j++) {
            DrawableLine line = currentLines[j];

            buffer.removeElement(line);
            int startX  = line.startX;
            int startY  = line.startY;
            int endX = line.endX;
            int endY = line.endY;
            if (startX  > 0 && startY  > 0 && endX > 0 && endY > 0) {
                float d = calcDistance(startX , startY , endX, endY);
                if (d > divider) {
                    int steps = (int) (d / divider + 0.5);
                    float dx = (endX - startX ) / (float) steps;
                    float dy = (endY - startY ) / (float) steps;
                    for (int i = 0; i < steps; i++) {
                        int x = (int) (startX  + dx * i + 0.5);
                        int y = (int) (startY  + dy * i + 0.5);
                        dg.fillArc(x, y - ToolBar.HEIGHT, brushWidth, brushWidth, 0, 360);
                    }
                }
                dg.fillArc((int) endX, (int) endY - ToolBar.HEIGHT, brushWidth, brushWidth, 0, 360);
            }
        }
    }

    private float calcDistance(float x1, float y1, float x2, float y2) {
        return (float) (Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)));
    }

    public void pointerPressed(int x, int y) {
        if (TOUCH_POINTS == 1) { // Prevent redundant calls
            pointerPressed(x, y, 0);
        }
    }

    public void pointerDragged(int x, int y) {
        if (TOUCH_POINTS == 1) {
            pointerDragged(x, y, 0);
        }
    }

    public void pointerReleased(int x, int y) {
        if (TOUCH_POINTS == 1) {
            pointerReleased(x, y, 0);
        }
    }

    public void pointerPressed(int x, int y, int id) {
        if (drawingAllowed) {
            if (y > Toolbar.HEIGHT) {
                buffers[id].addElement(new DrawableLine(x, y, x, y));
                previousX[id] = x;
                previousY[id] = y;
            }
            else {
                toolbar.pointerPressed(x, y);
            }
        }
        else if (savedialog.isVisible()) {
            savedialog.pointerPressed(x, y);
        }
    }

    public void pointerDragged(int x, int y, int id) {
        if (!drawingAllowed && colorpicker.isVisible()) {
            colorpicker.dragged(x, y);
        }
        else if (y > Toolbar.HEIGHT) {
            buffers[id].addElement(new DrawableLine(previousX[id], previousY[id], x, y));
            previousX[id] = x;
            previousY[id] = y;
        }
    }

    public void pointerReleased(int x, int y, int id) {
        if (!drawingAllowed) {
            if (colorpicker.isVisible()) {
                colorpicker.pressed(x, y);
            }
            else if (savedialog.isVisible()) {
                savedialog.pointerUnpressed(x, y);
            }
        }
        else {
            previousX[id] = -1;
            previousY[id] = -1;
            toolbar.pointerUnpressed(x, y);
        }
    }

    public Image getDrawing() {
        return drawing;
    }

    public void setBrush(final int brushsize) {
        brushWidth = brushsize;
    }

    public void showColorPicker() {
        drawingAllowed = false;
        colorpicker.show();
    }

    public void hideColorPicker() {
        colorpicker.hide();
        g.drawImage(drawing, 0, Toolbar.HEIGHT, Graphics.TOP | Graphics.LEFT);
        drawingAllowed = true;
    }

    public void colorChanged(int brushColor) {
        dg.setColor(brushColor);
    }

    public void clearDrawing() {
        int oldcolor = dg.getColor();
        dg.setColor(0xffffff);
        dg.fillRect(0, 0, drawing.getWidth(), drawing.getHeight());
        dg.setColor(oldcolor);
        renderDrawing = true;
    }

    public void showSaveDialog() {
        drawingAllowed = false;

        String keyboard = System.getProperty("com.nokia.keyboard.type");
        if ((keyboard != null && keyboard.equals("None")) || getWidth() > 240) {
            Main.getInstance().showSaveDialogS60();
        }
        else {
            savedialog.show();
        }
    }

    public void allowDrawing(boolean value) {
        if (value) {
            renderDrawing = true;
        }
        drawingAllowed = value;
    }
}