es.eucm.ead.editor.view.widgets.layouts.LinearGallery.java Source code

Java tutorial

Introduction

Here is the source code for es.eucm.ead.editor.view.widgets.layouts.LinearGallery.java

Source

/**
 * eAdventure is a research project of the
 *    e-UCM research group.
 *
 *    Copyright 2005-2014 e-UCM research group.
 *
 *    You can access a list of all the contributors to eAdventure at:
 *          http://e-adventure.e-ucm.es/contributors
 *
 *    e-UCM is a research group of the Department of Software Engineering
 *          and Artificial Intelligence at the Complutense University of Madrid
 *          (School of Computer Science).
 *
 *          CL Profesor Jose Garcia Santesmases 9,
 *          28040 Madrid (Madrid), Spain.
 *
 *          For more info please visit:  <http://e-adventure.e-ucm.es> or
 *          <http://www.e-ucm.es>
 *
 * ****************************************************************************
 *
 *  This file is part of eAdventure
 *
 *      eAdventure is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU Lesser General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      eAdventure is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU Lesser General Public License for more details.
 *
 *      You should have received a copy of the GNU Lesser General Public License
 *      along with eAdventure.  If not, see <http://www.gnu.org/licenses/>.
 */
package es.eucm.ead.editor.view.widgets.layouts;

import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Event;
import com.badlogic.gdx.scenes.scene2d.EventListener;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pools;
import com.badlogic.gdx.utils.SnapshotArray;

import es.eucm.ead.engine.gdx.AbstractWidget;
import es.eucm.ead.editor.view.widgets.WidgetBuilder;

/**
 * A scrollable horizontal linear gallery of items.
 * <p>
 * {@link ChangeEvent} is fired when the main page changes.
 * <p>
 */
public class LinearGallery extends ScrollPane {

    private Actor currentPage;

    private Pages content;

    private boolean wasPanDragFling = false, needsFocus = true;

    public LinearGallery(Skin skin, String background) {
        this(skin.getDrawable(background));
    }

    public LinearGallery(Drawable background) {
        super(null);
        setWidget(content = new Pages());
        getStyle().background = background;
        setScrollingDisabled(false, true);
    }

    @Override
    public void act(float delta) {
        super.act(delta);
        if (wasPanDragFling && !isPanning() && !isDragging() && !isFlinging()) {
            wasPanDragFling = false;
            scrollToPage();
        } else if (!wasPanDragFling && isPanning() || isDragging() || isFlinging()) {
            wasPanDragFling = true;
        }

        float cx = getScrollX() + getParent().getWidth() * .5f;
        float cy = getScrollY() + getParent().getHeight() * .5f;
        checkCurrentPage(cx, cy);
        if (currentPage != null && needsFocus
                && !(getVelocityX() != 0 || isPanning() || getScrollX() != getVisualScrollX())) {
            needsFocus = false;
            fireFocus();
        }
    }

    private void fireFocus() {
        FocusEvent event = Pools.obtain(FocusEvent.class);
        event.actor = currentPage;
        fire(event);
        Pools.free(event);
    }

    private void checkCurrentPage(float cx, float cy) {
        if (currentPage == null || !isVisible(currentPage, cx, cy)) {
            Actor visibleActor = getVisibleActor(cx, cy);
            if (visibleActor != null) {
                currentPage = visibleActor;
                needsFocus = true;
                fireChanged();
            }
        }
    }

    private Actor getVisibleActor(float cx, float cy) {
        for (Actor child : content.getChildren()) {
            if (isVisible(child, cx, cy)) {
                return child;
            }
        }
        return null;
    }

    private void fireChanged() {
        ChangeEvent event = Pools.obtain(ChangeEvent.class);
        fire(event);
        Pools.free(event);
    }

    public Actor getCurrentPage() {
        return currentPage;
    }

    private boolean isVisible(Actor actor, float cx, float cy) {
        return (cx > actor.getX() && cx <= actor.getRight() && cy > actor.getY() && cy <= actor.getTop());
    }

    /**
     * Base class to listen to {@link FocusEvent}s produced by
     * {@link LinearGallery}.
     */
    public static class FocusListener implements EventListener {

        @Override
        public boolean handle(Event event) {
            if (event instanceof FocusEvent) {
                focusGained((FocusEvent) event);
            }
            return true;
        }

        /**
         * The focus has been gained.
         */
        public void focusGained(FocusEvent event) {

        }
    }

    /**
     * Fired when one of the pages has gained focus, after the scroll has ended.
     */
    public static class FocusEvent extends Event {

        private Actor actor;

        public Actor getActor() {
            return actor;
        }

        @Override
        public void reset() {
            super.reset();
            this.actor = null;
        }
    }

    protected int scrollToPage() {
        final float width = getWidth();
        final float scrollX = getScrollX();
        final float maxX = getMaxX();

        if (scrollX >= maxX || scrollX <= 0)
            return -1;

        Array<Actor> pages = content.getChildren();
        float pageX = 0;
        float pageWidth = 0;
        int pageIndex = -1;
        if (pages.size > 0) {

            for (Actor a : pages) {
                pageX = a.getX();
                pageWidth = a.getWidth();
                ++pageIndex;
                if (scrollX < (pageX + pageWidth * 0.5)) {
                    break;
                }
            }
            super.setScrollX(pageX - (width - pageWidth) * .5f);
        }

        return pageIndex;
    }

    public void scrollToPage(int page) {
        Array<Actor> childen = content.getChildren();
        Actor nextPage = childen.get(page);
        super.setScrollX(nextPage.getX() - (getWidth() - nextPage.getWidth()) * .5f);
    }

    /**
     * @param pad
     *            pad between items
     */
    public void pad(float pad) {
        content.pad(pad);
    }

    @Override
    public void clearChildren() {
        content.clearChildren();
    }

    public void add(Actor actor) {
        content.addActor(actor);
    }

    @Override
    public SnapshotArray<Actor> getChildren() {
        return content.getChildren();
    }

    private static class Pages extends AbstractWidget {

        private float pad = WidgetBuilder.dpToPixels(8);

        @Override
        public void layout() {
            int count = 0;
            float rowHeight = getPrefHeight();
            float actorWidth = getParent().getWidth();
            for (Actor actor : getChildren()) {
                setBounds(actor, pad + count * actorWidth, pad, actorWidth - 2 * pad, rowHeight - 2 * pad);
                count++;
            }
        }

        @Override
        public float getPrefWidth() {
            float width = getParent().getWidth() * getChildren().size;
            return width;
        }

        @Override
        public float getPrefHeight() {
            return getParent().getHeight();
        }

        public void pad(float pad) {
            this.pad = pad;
        }
    }
}