Wednesday, March 11, 2009

Flicking Frames in SIWL

I ran into a problem with my implementation of FlickableFrame for SIWLExtensions. It turns out that ItemWidgets will block their containing Frame from receiving pointer pressed events. I'm not crystal clear under exactly what circumstances this happens (I believe it is when the pointer is pressed inside of a widget's bounding box), but it is my assessment that flickable frames with widgets are not feasible without lower-level access into SIWL*.

Sadness.

Note, there are ways around this, such as drawing text and images directly onto the frame (i.e. not using StaticText or StaticImage widgets for display) or using a ListFrame (though that's fraught with limitations too). However, unless I can find a way to get around recalculating widget positions every time a layout is drawn, the drawing of Frames is too slow for flicking anyway. This demonstrates the importance of robust event-handling and flexible windowing systems on mobile touch devices, and on tactile devices in general. This is what I'm trying to do with OpenSIWL.

* even as I made that pronouncement I started thinking of a method using a transparent widget covering the drawable area of the frame that intercepts all pointer events and, if they do not match the flick signature, calls the appropriate pointer event handlers on the frame (or rather some other functions that call the handlers, since they're declared protected and final in Frame).

3 comments:

  1. Hey there.

    I've also run into the problem with ItemWidget eating events. I created this class as a work around:

    /*
    * Copyright (c) 2008, Phil Tom
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    * * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in
    * the documentation and/or other materials provided with the
    * distribution.
    * * Neither the name of the Phil Tom nor the names of any contributors
    * may be used to endorse or promote products derived from this
    * software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
    * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    * POSSIBILITY OF SUCH DAMAGE.
    *
    * Created on Oct 6, 2008
    *
    */

    package com.sprintpcs.lcdui.widget;


    /**
    * The pointer event methods on ItemWidget are protected. This
    * means that subclass that are outside of the package can not
    * receive pointer events. This class forwards the events to
    * public methods. This allows using project specfic package
    * and minimized the amount of classes that need to be placed
    * in sprint's packages.
    *
    * @author philtom@gmail.com
    *
    */
    public abstract class PointerItemWidget extends ItemWidget {
    protected void pointerDragged(int x, int y) {
    handlePointerDragged(x, y);
    }

    protected void pointerReleased(int x, int y) {
    handlePointerReleased(x, y);
    }

    public abstract void handlePointerDragged(int x, int y);
    public abstract void handlePointerReleased(int x, int y);
    }

    ReplyDelete
  2. Thanks for the tip! I actually hadn't noticed that Widgets had non-final protected pointerDragged/Released methods (though no pointerPressed, it seems). I likely will use this to create a flickable widgets, but I still wonder whether there's a way to make the entire frame move together. I'm considering creating an overlay transparent Widget whose sole purpose is to sit on top of the Frame and register pointer events. Of course then I'd have to figure out how to get events like pointerPressed to the Widgets underneath the overlay.

    ReplyDelete
  3. I used a Canvas to display scrollable text. When the pointer was pressed, I grabbed those coordinates as the starting point. The subsequent drag events gave me the current coordinates. Subtracting the two gives a vector describing how to scroll.

    I maintained two coordinate systems. One for world coordinates. Another for screen coordinates. The screen ends up being a window into the world. So, you need to know the window's position in the world. Then you can grab the world objects you care about and translate them to screen coordinates for display.

    It looks like you're already doing similar transforms for your widgets. Probably wouldn't be much more work to build on that.

    ReplyDelete