javauis/lcdui_akn/javalcdui/javasrc/javax/microedition/lcdui/CustomItem.java
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:33:18 +0100
branchRCL_3
changeset 26 2455ef1f5bbc
parent 14 04becd199f91
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: v2.2.11 Kit: 201035

/*
* Copyright (c) 1999 - 2004 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/



package javax.microedition.lcdui;

import com.nokia.mj.impl.rt.legacy.NativeError;

public abstract class CustomItem extends Item
{
    protected static final int NONE = 0;
    protected static final int TRAVERSE_HORIZONTAL= 1;
    protected static final int TRAVERSE_VERTICAL = 2;
    protected static final int KEY_PRESS = 4;
    protected static final int KEY_RELEASE = 8;
    protected static final int KEY_REPEAT = 0x10;
    protected static final int POINTER_PRESS = 0x20;
    protected static final int POINTER_RELEASE = 0x40;
    protected static final int POINTER_DRAG = 0x80;
    //
    // Event type : must keep in sync with TEventType in lcdui.h
    // Notice the '....ED' at the end of each name which distinguishes them from
    // the interaction mode bits above
    //

    private static final int MAX_WIDTH  = 640;
    private static final int MAX_HEIGHT = 320;
    private static final int DEFAULT_WIDTH  = 200;
    private static final int DEFAULT_HEIGHT = 200;


    //
    // Graphics
    //
    private Graphics iGraphics;

    //
    // Repainting
    //
    private boolean  iRepaintPending; //waiting for paint to be called
    private int      iRepaintX1;
    private int      iRepaintY1;
    private int      iRepaintX2;
    private int      iRepaintY2;
    private boolean  iPaintEventPending;

    //
    private boolean iShown;
    //
    private int     iWidth;
    private int     iHeight;

    //
    // Traversal
    //
    private boolean iFocusEntered;
    private boolean iSupportsInternalTraversal;
    //

    protected CustomItem(String aLabel)
    {
        super();
        synchronized (iToolkit)
        {
            iHandle = Toolkit.checkHandle(_create(iToolkit.getHandle(),this,aLabel));
        }
        iLabel = aLabel;
    }

    public int getGameAction(int aKeyCode)
    {
        if (aKeyCode == 0)
        {
            throw new IllegalArgumentException();
        }
        synchronized (iToolkit)
        {
            return NativeError.check(Canvas._getGameAction(iToolkit.getHandle(),aKeyCode));
        }
    }

    protected final int getInteractionModes()
    {
        synchronized (iToolkit)
        {
            return NativeError.check(_getInteractionModes(iToolkit.getHandle(), getHandle()));
        }
    }

    protected final void invalidate()
    {
        int min_width;
        int min_height;
        int pref_width;
        int pref_height;

        synchronized (iCallbackLock)
        {
            min_width   = getMinContentWidth();
            min_height  = getMinContentHeight();
            pref_width  = getPrefContentWidth(-1);
            pref_height = getPrefContentHeight(-1);
        }
        synchronized (iToolkit)
        {
            _invalidate(iToolkit.getHandle(), getHandle(), min_width, min_height, pref_width, pref_height);
        }
        repaint();
    }

    /**
     * !!!CALLBACK!!!
     */
    protected boolean traverse(int aDirection,int aViewportWidth,int aViewportHeight,int[] aVisRect_inout)
    {
        return false;
    }

    /**
     * !!!CALLBACK!!!
     */
    protected void traverseOut()
    {
    }

    /**
     * !!!CALLBACK!!!
     */
    protected abstract int getMinContentWidth();

    /**
     * !!!CALLBACK!!!
     */
    protected abstract int getMinContentHeight();

    /**
     * !!!CALLBACK!!!
     */
    protected abstract int getPrefContentWidth(int aHeight);

    /**
     * !!!CALLBACK!!!
     */
    protected abstract int getPrefContentHeight(int aWidth);

    /**
     * !!!CALLBACK!!!
     */
    protected abstract void paint(Graphics aGraphics,int aWidth,int aHeight);

    protected final void repaint()
    {
        repaint(0,0, iWidth, iHeight);
    }

    /**
     * Merge clipping rects if already set
     */
    protected final void repaint(int aX,int aY,int aWidth,int aHeight)
    {
        synchronized (iToolkit)
        {
            if (iShown && (aWidth > 0) && (aHeight > 0))
            {
                int x1 = aX;
                int y1 = aY;
                int x2 = aX+aWidth;
                int y2 = aY+aHeight;

                // Union of clip rect and damage rect
                if (iRepaintPending)
                {
                    iRepaintX1 = Math.min(iRepaintX1, x1);
                    iRepaintY1 = Math.min(iRepaintY1, y1);
                    iRepaintX2 = Math.max(iRepaintX2, x2);
                    iRepaintY2 = Math.max(iRepaintY2, y2);
                }
                else
                {
                    iRepaintX1 = x1;
                    iRepaintY1 = y1;
                    iRepaintX2 = x2;
                    iRepaintY2 = y2;
                    iRepaintPending = true;
                }

                // Clip to bounds
                iRepaintX1 = Math.max(iRepaintX1, 0);
                iRepaintY1 = Math.max(iRepaintY1, 0);
                iRepaintX2 = Math.min(iRepaintX2, iWidth);
                iRepaintY2 = Math.min(iRepaintY2, iHeight);

                if (!iPaintEventPending)
                {
                    iToolkit.postEvent(this, Toolkit.EVENT_PAINT);
                    iPaintEventPending = true;
                }
            }
        }
    }

    protected void keyPressed(int aKeyCode)
    {
    }

    protected void keyReleased(int aKeyCode)
    {
    }

    protected void keyRepeated(int aKeyCode)
    {
    }

    protected void pointerPressed(int aX,int aY)
    {
    }

    protected void pointerReleased(int aX,int aY)
    {
    }

    protected void pointerDragged(int aX,int aY)
    {
    }

    protected void showNotify()
    {
    }

    protected void hideNotify()
    {
    }

    protected void sizeChanged(int aWidth,int aHeight)
    {
    }

    final void handleEvent(int aEvent,int aData0,int aData1,int aData2)
    {
        switch (aEvent)
        {
        case Toolkit.EVENT_PAINT:
            paint();
            break;
        case Toolkit.EVENT_KEY_PRESSED:
            synchronized (iCallbackLock)
            {
                keyPressed(aData0);
            }
            break;
        case Toolkit.EVENT_KEY_RELEASED:
            synchronized (iCallbackLock)
            {
                keyReleased(aData0);
            }
            break;
        case Toolkit.EVENT_KEY_REPEATED:
            synchronized (iCallbackLock)
            {
                keyRepeated(aData0);
            }
            break;
        case Toolkit.EVENT_POINTER_PRESSED:
            synchronized (iCallbackLock)
            {
                pointerPressed(aData0, aData1);
            }
            break;
        case Toolkit.EVENT_POINTER_RELEASED:
            synchronized (iCallbackLock)
            {
                pointerReleased(aData0, aData1);
            }
            break;
        case Toolkit.EVENT_POINTER_DRAGGED:
            synchronized (iCallbackLock)
            {
                pointerDragged(aData0, aData1);
            }
            break;
        case Toolkit.EVENT_VISIBLE:
            handleVisible(aData0>0);
            break;
        case Toolkit.EVENT_SIZE_CHANGED:
            handleSizeChanged(aData0, aData1);
            break;
        case Toolkit.EVENT_TRAVERSE:
        {
            final boolean focus = (aData0 >> 16) > 0;
            final int direction = (aData0 & 0xffff);
            final int visX = (aData1>>16);
            final int visY = (aData1&0xffff);
            final int visW = (aData2>>16);
            final int visH = (aData2&0xffff);
            handleFocusChange(focus, direction, visX, visY, visW, visH);
        }
        break;
        default:
            super.handleEvent(aEvent, aData0, aData1, aData2);
        }
    }

    /**
    aData represents        (focus | direction)
    aData1 represents   (X of the visRect_Out Rect | Y of the visRect_Out Rect)
    aData2 represents   (width of the visRect_Out Rect | height of the visRect_Out Rect)
    */
    final void handleFocusChange(boolean aFocus, int aDirection, int aVisX, int aVisY, int aVisW, int aVisH)
    {
        if (aFocus)
        {
            final Form form = getForm();
            if (form!=null)
            {
                final int viewportWidth  = form.getWidth();
                final int viewportHeight = form.getHeight();

                final int visRect_Out[] = new int[4];

                //
                // The visRect is supplied by subclass. If the subclass supports internal
                // traversal and wants to keep focus, visRect represents the rectangle
                // that should become visible, i.e. the focused area.
                //
                visRect_Out[0] = aVisX;
                visRect_Out[1] = aVisY;
                visRect_Out[2] = aVisW;
                visRect_Out[3] = aVisH;

                // Ask subclass if it wants to keep focus
                final boolean keepFocus;

                synchronized (iCallbackLock)
                {
                    keepFocus = traverse(aDirection,viewportWidth,viewportHeight,visRect_Out);
                }

                // If the subclass wants focus, maintain the visRect
                final int[] scroll = keepFocus ? visRect_Out : null;

                synchronized (iToolkit)
                {
                    FirstTimeEntered(keepFocus);
                    if (!iSupportsInternalTraversal)
                    {
                        _setFocusAndScroll(iToolkit.getHandle(), getHandle(), true, null, aDirection);
                    }
                    else
                    {
                        _setFocusAndScroll(iToolkit.getHandle(), getHandle(), keepFocus, scroll, aDirection);
                        repaint();
                    }
                }
            }
        }
        else
        {
            // The native object has lost focus therfore we must
            // call traverseOut.
            synchronized (iCallbackLock)
            {
                traverseOut();
            }
        }
    }


    /**
    The first time focus enters the CustomItem subclass is special in that it
    signifies whether this CustomItem suports internal traversal.
    */
    final void FirstTimeEntered(boolean aKeepFocus)
    {
        if (!iFocusEntered)
        {
            iFocusEntered = true;
            iSupportsInternalTraversal = aKeepFocus;

            if (!iSupportsInternalTraversal)
            {
                // If internal trversal is not supported we must let the native code know
                // that is the case. Addtional call (below) is necessary to actually transer
                // focus to this item.
                _setFocusAndScroll(iToolkit.getHandle(), getHandle(),false, null, NONE);
            }
        }
    }

    final void handleVisible(boolean aVisible)
    {
        final boolean changed;

        synchronized (iToolkit)
        {
            changed = (iShown != aVisible);
            iShown = aVisible;
        }

        if (changed)
        {
            if (aVisible)
            {
                synchronized (iCallbackLock)
                {
                    showNotify();
                }
                repaint();
            }
            else
            {
                synchronized (iCallbackLock)
                {
                    hideNotify();
                }
            }
        }
    }

    private void paint()
    {
        boolean  clipped;
        int      rx;
        int      ry;
        int      rw;
        int      rh;
        int      width;
        int      height;
        Graphics graphics;

        synchronized (iToolkit)
        {
            iPaintEventPending = false;

            if (!iRepaintPending)
            {
                return; // Don't draw if all the repaints have already been done
            }

            iRepaintPending = false;

            if (!iShown)
            {
                return;
            }

            rx = iRepaintX1;
            ry = iRepaintY1;
            rw = iRepaintX2 - iRepaintX1;
            rh = iRepaintY2 - iRepaintY1;

            graphics = GetGraphics();
            width    = iWidth;
            height   = iHeight;
        }

        clipped = (rw < width) || (rh < height);
        if (clipped)
        {
            graphics.setClip(rx,ry,rw,rh);
        }

        synchronized (iCallbackLock)
        {
            paint(graphics, width, height);
        }

        synchronized (iToolkit)
        {
            if (clipped)
            {
                iToolkit.sync(getHandle(), rx, ry, rw, rh);
            }
            else
            {
                iToolkit.sync(getHandle());
            }
            ReleaseGraphics(graphics);
        }
    }

    private void handleSizeChanged(int aWidth,int aHeight)
    {
        boolean  changed;

        synchronized (iToolkit)
        {
            changed = (iWidth != aWidth) || (iHeight != aHeight);
            if (changed)
            {
                iWidth  = aWidth;
                iHeight = aHeight;
                DisposeGraphics();
            }
        }

        if (changed)
        {
            synchronized (iCallbackLock)
            {
                sizeChanged(aWidth,aHeight);
            }
            repaint();
        }
    }

    void addNotify(Screen aScreen)
    {
        super.addNotify(aScreen);
        invalidate();
        synchronized (iToolkit)
        {
            DisposeGraphics();
        }
    }

    void removeNotify(Screen aScreen)
    {
        super.removeNotify(aScreen);
        synchronized (iToolkit)
        {
            DisposeGraphics();
        }
    }

    private Graphics GetGraphics()
    {
        Graphics graphics = iGraphics;
        iGraphics = null;
        if (graphics == null)
        {
            graphics = new Graphics(iToolkit, this, getHandle(), iWidth, iHeight);
        }
        else
        {
            graphics.reset(iWidth, iHeight);
        }
        return graphics;
    }

    private void ReleaseGraphics(Graphics aGraphics)
    {
        if ((null == iGraphics) && (iWidth==aGraphics.iWidth) && (iHeight==aGraphics.iHeight))
        {
            iGraphics=aGraphics;
        }
        else
        {
            aGraphics.dispose();
        }
    }

    private void DisposeGraphics()
    {
        final Graphics graphics = iGraphics;
        iGraphics = null;
        if (null != graphics)
        {
            graphics.dispose();
        }
    }

    private native int _create(int aToolkit,CustomItem aCustomItem,String aLabel);
    private native int  _getInteractionModes(int aToolkit, int aCustomItem);
    private native void _invalidate(int aToolkit, int aCustomItem,int aMinWidth,int aMinHeight,int aPrefWidth,int aPrefHeight);
    private native void _setFocusAndScroll(int aToolkit, int aCustomItem, boolean aFocus, int[] aScroll, int aDirection);
}