Package org.vaadin.touchmenu.client.ui

Source Code of org.vaadin.touchmenu.client.ui.VTouchMenu

package org.vaadin.touchmenu.client.ui;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import com.google.gwt.animation.client.Animation;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;

public class VTouchMenu extends Widget implements Paintable {

    private static final String BASE_NAME = "touchmenu";
    /** Set the CSS class name to allow styling. */
    public static final String CLASSNAME = "v-" + BASE_NAME;
    public static final String LEFT_NAVI = "v-left";
    public static final String RIGHT_NAVI = "v-right";

    /** The client side widget identifier */
    protected String paintableId;
    protected final VTouchMenu hostReference = this;

    /** Reference to the server connection object. */
    ApplicationConnection client;

    private Element left, right;

    private int width, height, areaWidth;
    private int down;

    protected List<VMenuButton> items;

    private Element touchArea;
    private int rows = 2;
    private int columns = 3;
    private int requestedColumns = columns;
    private int requestedRows = rows;
    private int selected, distance;
    private boolean from = true;
    private boolean pressed = false;
    private boolean animating = false;
    private boolean animate = true;
    private int animationTime = 500;
    private int softAnimationTime = 250;
    private int firstItemLeft = 0;
    private boolean useArrows = true;
    private boolean wpercent = false;
    private boolean hpercent = false;

    /**
     * The constructor should first call super() to initialize the component and
     * then handle any initialization relevant to Vaadin.
     */
    public VTouchMenu() {
        super();
        items = new LinkedList<VMenuButton>();

        // Create base element
        setElement(DOM.createDiv());

        sinkEvents(Event.MOUSEEVENTS);

        // If window is resized check width/height and positions
        Window.addResizeHandler(resize);

        // This method call of the Paintable interface sets the component
        // style name in DOM tree
        setStyleName(CLASSNAME);

        // Create directional buttons left & right
        // Set Default style properties/sizes
        left = DOM.createButton();
        right = DOM.createButton();
        left.setClassName(LEFT_NAVI);
        left.getStyle().setProperty("position", "absolute");
        left.getStyle().setPropertyPx("width", 40);
        right.setClassName(RIGHT_NAVI);
        right.getStyle().setProperty("position", "absolute");
        right.getStyle().setPropertyPx("width", 40);

        // At start selected == 0 and direction == from
        setTransparent(left);

        touchArea = DOM.createDiv();
        touchArea.setClassName("v-toucharea");
        touchArea.getStyle().setProperty("position", "absolute");

        getElement().appendChild(left);
        getElement().appendChild(touchArea);
        getElement().appendChild(right);

    }

    /**
     * Called whenever an update is received from the server
     */
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
        // This call should be made first.
        // It handles sizes, captions, tooltips, etc. automatically.
        if (client.updateComponent(this, uidl, true)) {
            // If client.updateComponent returns true there has been no changes
            // and we do not need to update anything.
            return;
        }

        // Save reference to server connection object to be able to send
        // user interaction later
        this.client = client;

        // Save the client side identifier (paintable id) for the widget
        paintableId = uidl.getId();

        // Get all Child UIDLs and iterate through them
        Iterator<Object> childUIDL = uidl.getChildIterator();
        while (childUIDL.hasNext()) {
            UIDL child = (UIDL) childUIDL.next();

            if (child.getTag().equals("options")) {
                width = child.getIntAttribute("width");
                height = child.getIntAttribute("height");

                // Percentual width
                if (child.hasAttribute("widthpercentage")) {
                    width = getElement().getParentElement().getClientWidth();
                    wpercent = true;
                } else {
                    wpercent = false;
                }
                // Percentual height
                if (child.hasAttribute("heightpercentage")) {
                    height = getElement().getParentElement().getClientHeight();
                    hpercent = true;
                } else {
                    hpercent = false;
                }
                if (child.hasAttribute("rows")) {
                    setRows(child.getIntAttribute("rows"));
                }
                if (child.hasAttribute("columns")) {
                    setColumns(child.getIntAttribute("columns"));
                }
                if (child.hasAttribute("moveFrom")) {
                    setDirection(child.getBooleanAttribute("moveFrom"));
                }
                if (child.hasAttribute("animate")) {
                    animate = child.getBooleanAttribute("animate");
                }
                if (child.hasAttribute("selected")) {
                    selected = child.getIntAttribute("selected");
                }
                if (child.hasAttribute("useArrows")) {
                    useArrows = child.getBooleanAttribute("useArrows");
                    if (!useArrows) {
                        if (getElement().isOrHasChild(left)) {
                            getElement().removeChild(left);
                        }
                        if (getElement().isOrHasChild(right)) {
                            getElement().removeChild(right);
                        }
                    } else {
                        if (!getElement().isOrHasChild(left)) {
                            getElement().appendChild(left);
                        }
                        if (!getElement().isOrHasChild(right)) {
                            getElement().appendChild(right);
                        }
                    }
                }
                // Set left/right arrow styles
                if (child.hasAttribute("leftArrow")) {
                    left.setClassName(child.getStringAttribute("leftArrow"));
                }
                if (child.hasAttribute("rightArrow")) {
                    right.setClassName(child.getStringAttribute("rightArrow"));
                }

            } else if (child.getTag().equals("item")) {
                UIDL item = child;
                VMenuButton current = null;
                String itemCaption = item.getStringAttribute("caption");
                final int itemId = item.getIntAttribute("id");
                boolean found = false;
                for (VMenuButton button : items) {
                    if (button.getId() == itemId) {
                        found = true;
                    }
                }

                if (!found) {
                    final Command cmd;

                    if (item.hasAttribute("command")) {
                        cmd = new Command() {
                            public void execute() {
                                hostReference.onMenuClick(itemId);
                            }
                        };
                    } else {
                        cmd = null;
                    }

                    String icon = null;
                    if (item.hasAttribute("icon")) {
                        icon = client.translateVaadinUri(item
                                .getStringAttribute("icon"));
                    }

                    current = addMenuItem(itemCaption, icon, cmd, itemId);

                    if (item.hasAttribute("style")) {
                        String styleName = item.getStringAttribute("style");
                        current.setStyle(styleName);
                    }
                    current.setSize(item.getStringAttribute("buttonsize"));
                }
            }
            if (child.getTag().equals("updateItem")) {
                // Update item data
                UIDL item = child;
                VMenuButton current = null;
                String itemCaption = item.getStringAttribute("caption");
                final int itemId = item.getIntAttribute("id");

                for (VMenuButton button : items) {
                    if (button.getId() == itemId) {
                        current = button;
                        break;
                    }
                }
                current.setCaption(itemCaption);

                if (item.hasAttribute("icon")) {
                    current.setIcon(client.translateVaadinUri(item
                            .getStringAttribute("icon")));
                }

                if (item.hasAttribute("style")) {
                    current.setStyle(item.getStringAttribute("style"));
                }

                if (item.hasAttribute("buttonsize")) {
                    current.setSize(item.getStringAttribute("buttonsize"));
                }
            } else if (child.getTag().equals("removeItem")) {
                removeButton(child.getIntAttribute("id"));
            }
        }
        checkSize();

        // Set touch area size depending on arrows or not
        if (useArrows) {
            left.getStyle().setPropertyPx("left", 0);
            left.getStyle().setPropertyPx("height", height);

            touchArea.getStyle().setPropertyPx("left", 40);

            right.getStyle().setPropertyPx("left", width - 40);
            right.getStyle().setPropertyPx("height", height);
        } else {
            touchArea.getStyle().setPropertyPx("left", 0);
        }
        setColumns(requestedColumns);
        setSize();

        // Set base element width and height
        getElement().getStyle().setPropertyPx("width", width);
        getElement().getStyle().setPropertyPx("height", height);
    }

    /**
     * Checks size according to content
     */
    private void checkSize() {
        // If width == 0 or is undefined -1 then get size
        // according to content
        if (width <= 0) {
            width = requestedColumns * items.get(0).WIDTH + 20;
            if (useArrows) {
                width += 80;
            }
        }
        // If height == 0 or is undefined -1 then get size
        // according to content
        if (height <= 0) {
            height = requestedRows * items.get(0).HEIGHT + 20;
        }

        if (useArrows) {
            areaWidth = width - 80;
        } else {
            areaWidth = width;
        }
    }

    @Override
    public void onBrowserEvent(Event event) {
        if (paintableId == null || client == null || animating) {
            return;
        }

        switch (DOM.eventGetType(event)) {
        case Event.ONMOUSEDOWN: {
            // prevent default events
            event.preventDefault();
            // Get X position for mouse down
            down = event.getClientX();
            pressed = true;
            break;
        }
        case Event.ONMOUSEMOVE: {
            // prevent default events
            event.preventDefault();
            // If mouse pressed and animate on update item positions
            if (pressed) {
                moveButtons(event.getClientX() - down);
            }
            break;
        }
        case Event.ONMOUSEOUT: {
            if (pressed) {
                event.preventDefault();
                int amount = Math.abs(event.getClientX() - down);
                // If user dragged more than button width
                if (amount > items.get(0).WIDTH) {
                    setSelectedAfterDragging(event, amount);
                    softPositioning();
                } else {
                    moveButtons(0);
                }
                pressed = false;
            }
            break;
        }
        case Event.ONMOUSEUP: {
            pressed = false;
            if (event.getButton() == NativeEvent.BUTTON_LEFT) {
                event.preventDefault();

                int amount = Math.abs(event.getClientX() - down);
                // If user dragged more than button width
                if (amount > items.get(0).WIDTH) {
                    setSelectedAfterDragging(event, amount);
                    softPositioning();
                    break;
                } else {
                    // Set positions for items
                    for (VMenuButton button : items) {
                        button.setLeft(button.getLeft() + event.getClientX()
                                - down);
                    }
                    softPositioning();
                }
                Element target = (Element) Element.as(event.getEventTarget());
                if (left.equals(target)) {
                    moveLeft();
                } else if (right.equals(target)) {
                    moveRight();
                } else {
                    // Else check if a button (or button icon/caption)
                    // was clicked
                    for (VMenuButton item : items) {
                        if (item.getElement().equals(target)
                                || item.getElement().equals(
                                        target.getParentElement())) {
                            itemClick(item);
                        }
                    }
                }

            }
            break;
        }
        }// End switch
    }

    /**
     * Set selected item after drag event
     *
     * @param event
     *            Event
     * @param amount
     *            Absolute px moved
     */
    private void setSelectedAfterDragging(Event event, int amount) {

        int modifier = (amount / distance);
        if (modifier < 1) {
            modifier = 1;
        }

        // Set positions for items
        for (VMenuButton button : items) {
            button.setLeft(button.getLeft() + event.getClientX() - down);
        }

        if (event.getClientX() < down) {
            // if we are in last position return
            if ((selected + (rows * columns)) >= items.size()) {
                softPositioning();
                return;
            }
            // set new position
            selected += (rows * modifier);
            if ((selected + (rows * columns)) >= items.size()) {
                selected = (items.size() - (rows * columns));
                if (selected % rows != 0) {
                    selected += selected % rows;
                }
            }
        } else {
            // if at first position return
            if (selected == 0) {
                softPositioning();
                return;
            }
            // set new position
            selected -= (rows * modifier);
            if (selected < rows) {
                selected = 0;
            }
        }

    }

    /**
     * Animate movement for buttons from place dropped after dragging to
     * "static" position
     */
    private void softPositioning() {

        // Calculate the position of the first button and how far it is from
        // this position
        int columnMargine = (int) Math.ceil(((areaWidth / columns) - items
                .get(0).WIDTH) / 2.0);
        int step = 2 * columnMargine + items.get(0).WIDTH;
        firstItemLeft = columnMargine
                - (int) (Math.ceil(selected / rows) * step);

        Animation animation = new Animation() {
            int move = (firstItemLeft - items.get(0).getLeft());

            @Override
            protected void onUpdate(double progress) {
                moveButtons((int) (move * progress));

                if (progress >= 1) {
                    animating = false;
                    setSize();
                    client
                            .updateVariable(paintableId, "cursor", selected,
                                    true);
                }
            }
        };

        // softAnimationTime = 250 * (Math.abs(firstItemLeft
        // - items.get(0).getLeft()) / 100);
        animating = true;
        animation.run(softAnimationTime);
    }

    /**
     * Send clicked item id to server
     *
     * @param id
     *            Clicked button
     */
    public void onMenuClick(int id) {
        if (paintableId != null && client != null) {
            client.updateVariable(paintableId, "clickedId", id, true);
        }
    }

    // Enqueue Command to be fired after all current events have been handled.
    public void itemClick(VMenuButton item) {
        if (item.getCommand() != null) {
            DeferredCommand.addCommand(item.getCommand());
        }
    }

    /**
     * Set number of columns. Min 1.
     *
     * @param columns
     */
    public void setColumns(int columns) {
        if (columns < 1) {
            columns = 1;
        } else {
            this.columns = columns;
        }
        requestedColumns = columns;
    }

    /**
     * Set number of rows. Min 1.
     *
     * @param rows
     */
    public void setRows(int rows) {
        if (rows < 1) {
            rows = 1;
        } else {
            this.rows = rows;
        }
        requestedRows = rows;
    }

    /**
     * Check that columns fit inside touch area and calculate animation time
     * based on how far on step needs to move
     */
    private void checkColumns() {
        if (requestedColumns != columns) {
            columns = requestedColumns;
        } else {
            requestedColumns = columns;
        }
        if ((columns * items.get(0).WIDTH) > touchArea.getClientWidth()) {
            columns = touchArea.getClientWidth() / items.get(0).WIDTH;
        }
        animationTime = 250 * ((areaWidth / columns) / 100);
    }

    /**
     * Check that rows fit into area
     */
    private void checkRows() {
        if (requestedRows != rows) {
            rows = requestedRows;
        } else {
            requestedRows = rows;
        }
        if ((rows * items.get(0).HEIGHT) > touchArea.getClientHeight()) {
            rows = touchArea.getClientHeight() / items.get(0).HEIGHT;
        }
    }

    /**
     * Set direction for scroll buttons
     *
     * @param from
     */
    public void setDirection(boolean from) {
        this.from = from;
    }

    /**
     * Animate moving one item in from the left
     */
    private void animateFromLeft() {
        Animation animation = new Animation() {
            int move = (areaWidth / columns);

            @Override
            protected void onUpdate(double progress) {
                moveButtons((int) (move * progress));

                if (progress >= 1) {
                    animating = false;
                    selected -= rows;
                    if (selected < rows) {
                        selected = 0;
                    }
                    setSize();
                    client
                            .updateVariable(paintableId, "cursor", selected,
                                    true);
                }
            }
        };
        animating = true;
        animation.run(animationTime);
    }

    /**
     * Animate moving one item in from the right
     */
    private void animateFromRight() {
        Animation animation = new Animation() {
            int move = (areaWidth / columns);

            @Override
            protected void onUpdate(double progress) {
                moveButtons(-(int) (move * progress));

                if (progress >= 1) {
                    animating = false;
                    selected += rows;
                    setSize();
                    client
                            .updateVariable(paintableId, "cursor", selected,
                                    true);
                }
            }
        };
        animating = true;
        animation.run(animationTime);
    }

    /**
     * Move in buttons from left(default)
     */
    public void moveLeft() {
        if (from) {
            if (selected <= 0) {
                return;
            }
            if (animate) {
                animateFromLeft();
            } else {
                selected -= rows;
                if (selected < rows) {
                    selected = 0;
                }
                setSize();
                client.updateVariable(paintableId, "cursor", selected, true);
            }
        } else {
            if ((selected + (rows * columns)) >= items.size()) {
                return;
            }
            if (animate) {
                animateFromRight();
            } else {
                selected += rows;
                setSize();
                client.updateVariable(paintableId, "cursor", selected, true);
            }
        }
    }

    /**
     * Move in buttons from right(default)
     */
    public void moveRight() {
        if (from) {
            if ((selected + (rows * columns)) >= items.size()) {
                return;
            }
            if (animate) {
                animateFromRight();
            } else {
                selected += rows;
                // setSize();
                client.updateVariable(paintableId, "cursor", selected, true);
            }
        } else {
            if (selected <= 0) {
                return;
            }
            if (animate) {
                animateFromLeft();
            } else {
                selected -= rows;
                if (selected < rows) {
                    selected = 0;
                }
                // setSize();
                client.updateVariable(paintableId, "cursor", selected, true);
            }
        }
    }

    /**
     * Set touchArea size and calculate button positions.
     */
    private void setSize() {
        touchArea.getStyle().setPropertyPx("width", areaWidth);
        touchArea.getStyle().setPropertyPx("height", height);
        // Check columns/rows
        checkColumns();
        checkRows();
        // Set button positions
        if (!items.isEmpty()) {
            int columnMargine = (int) Math.ceil(((areaWidth / columns) - items
                    .get(0).WIDTH) / 2.0);
            distance = ((areaWidth / columns) - (columnMargine / 2));
            int step = 2 * columnMargine + items.get(0).WIDTH;
            int rowMargine = (int) Math
                    .ceil(((height / rows) - items.get(0).HEIGHT) / 2);
            int left = columnMargine
                    - (int) (Math.ceil(selected / rows) * step);
            int top = rowMargine;

            for (int i = 0; i < items.size(); i++) {
                VMenuButton item = items.get(i);

                // if rows filled move next button left;
                if ((rows == 1 && i > 0) || (i > 0 && (i % rows) == 0)) {
                    left += step;
                }

                item.getElement().getStyle().setPropertyPx("left", left);
                item.getElement().getStyle().setPropertyPx(
                        "top",
                        top
                                + ((i % rows) * (rowMargine
                                        + items.get(0).HEIGHT + rowMargine)));
                // Set button position to use for animation.
                item.setLeft(left);
            }
        }
        // Check if at last or first item and set transparent accordingly
        if (selected == 0) {
            if (from) {
                setTransparent(left);
            } else {
                setTransparent(right);
            }
        } else {
            if (from) {
                removeTransparent(left);
            } else {
                removeTransparent(right);
            }
        }
        if ((selected + (rows * columns)) >= items.size()) {
            if (from) {
                setTransparent(right);
            } else {
                setTransparent(left);
            }
        } else {
            if (from) {
                removeTransparent(right);
            } else {
                removeTransparent(left);
            }
        }
    }

    /**
     * Move button position relative to starting position
     *
     * @param distance
     *            Amount to move
     */
    private void moveButtons(int distance) {
        for (VMenuButton item : items) {
            item.getElement().getStyle().setPropertyPx("left",
                    item.getLeft() + distance);
        }
    }

    /**
     * Remove a button
     *
     * @param id
     *            Id of button to remove
     */
    private void removeButton(int id) {
        VMenuButton target = null;
        for (VMenuButton item : items) {
            if (item.getId() == id) {
                target = item;
                break;
            }
        }
        if (target != null) {
            items.remove(target);
            touchArea.removeChild(target.getElement());
        }
        if ((selected + (rows * columns)) >= items.size()) {
            moveLeft();
        }
    }

    /**
     * Make element transparent
     *
     * @param target
     */
    private void setTransparent(Element target) {
        Style targetStyle = target.getStyle();
        targetStyle.setProperty("opacity", "0.3");
        targetStyle.setProperty("filter", "alpha(opacity=30)");
    }

    /**
     * Make element opaque
     *
     * @param target
     */
    private void removeTransparent(Element target) {
        Style targetStyle = target.getStyle();
        targetStyle.setProperty("opacity", "1");
        targetStyle.setProperty("filter", "alpha(opacity=100)");
    }

    /**
     * Create and add a new menu item with caption, icon and command
     *
     * @param caption
     *            Button caption
     * @param image
     *            Button icon
     * @param cmd
     *            Button command
     * @return Created VMenuButton
     */
    public VMenuButton addMenuItem(String caption, String image, Command cmd,
            int id) {
        VMenuButton newItem = new VMenuButton(caption, image, cmd, id);
        items.add(newItem);
        touchArea.appendChild(newItem.getElement());
        setSize();
        return newItem;
    }

    /**
     * Handle resizing of Window
     */
    private ResizeHandler resize = new ResizeHandler() {

        @Override
        public void onResize(ResizeEvent event) {
            // if percentual value given resize else return
            if (!wpercent || hpercent) {
                return;
            }

            if (wpercent) {
                width = getElement().getParentElement().getClientWidth();
            }
            if (hpercent) {
                height = getElement().getParentElement().getClientHeight();
                if (height <= 0) {
                    height = rows * items.get(0).HEIGHT + 20;
                }
            }
            if (useArrows) {
                areaWidth = width - 80;
                // move right arrow to place
                right.getStyle().setPropertyPx("left", width - 40);
            } else {
                areaWidth = width;
            }
            // set new sizes,positions,check rows & columns
            setSize();
        }

    };
}
TOP

Related Classes of org.vaadin.touchmenu.client.ui.VTouchMenu

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.