org.spout.api.gui.screen.ScreenStack.java Source code

Java tutorial

Introduction

Here is the source code for org.spout.api.gui.screen.ScreenStack.java

Source

/*
 * This file is part of SpoutAPI.
 *
 * Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
 * SpoutAPI is licensed under the SpoutDev License Version 1.
 *
 * SpoutAPI 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.
 *
 * In addition, 180 days after any changes are published, you can use the
 * software, incorporating those changes, under the terms of the MIT license,
 * as described in the SpoutDev License Version 1.
 *
 * SpoutAPI 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,
 * the MIT license and the SpoutDev License Version 1 along with this program.
 * If not, see <http://www.gnu.org/licenses/> for the GNU Lesser General Public
 * License and see <http://www.spout.org/SpoutDevLicenseV1.txt> for the full license,
 * including the MIT license.
 */
package org.spout.api.gui.screen;

import java.awt.Point;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;

import org.spout.api.tickable.Tickable;
import org.spout.api.gui.KeyboardEventHandler;
import org.spout.api.gui.MouseButton;
import org.spout.api.gui.MouseEventHandler;
import org.spout.api.gui.Renderable;
import org.spout.api.gui.Screen;
import org.spout.api.keyboard.Keyboard;
import org.spout.api.signal.Signal;
import org.spout.api.signal.SignalSubscriberObject;

public class ScreenStack extends SignalSubscriberObject
        implements Renderable, KeyboardEventHandler, MouseEventHandler {
    /**
     * Contains all attached screens in front-to-back order, that means, the topmost screen is the first element
     */
    private LinkedList<Screen> screens = new LinkedList<Screen>();
    /**
     * Contains the visible screens in back-to-front order, that means, the first element is the last screen you can see (and is also a fullscreen)
     */
    private LinkedList<Screen> visibleScreens = new LinkedList<Screen>();

    private int width = -1, height = -1;

    /**
     * @signal resized When the window that contains the screen has been resized
     * 
     * @sarg java.lang.Integer The new width
     * @sarg java.lang.Integer The new height
     */
    public static final Signal SIGNAL_RESIZED = new Signal("resized", Integer.class, Integer.class);

    {
        registerSignal(SIGNAL_RESIZED);
        updateScreenSize();
    }

    private void updateScreenSize() {
        width = Display.getWidth();
        height = Display.getHeight();
    }

    public ScreenStack(FullScreen mainScreen) {
        if (mainScreen == null) {
            throw new IllegalStateException("mainScreen must not be null");
        }
        screens.add(mainScreen);
        visibleScreens.add(mainScreen);
    }

    /**
     * @return the first visible screen
     */
    public Screen getFirstScreen() {
        return screens.getFirst();
    }

    /**
     * @return all visible screens, ordered back-to-front, that means, the first element is the last screen you can see (and is also a FullScreen)
     */
    public List<Screen> getVisibleScreens() {
        return Collections.unmodifiableList(visibleScreens);
    }

    /**
     * Opens the given screen. If the screen already exists, it will push it to the front
     * @param screen
     */
    public void openScreen(Screen screen) {
        if (screen != getMainScreen()) {
            screens.remove(screen);
            screens.addFirst(screen);
            recalculate();
        } else {
            printMainScreenWarning("raise");
        }
    }

    private void printMainScreenWarning(String verb) {
        System.out.println("You can't " + verb
                + " the main screen. To replace it, call setMainScreen with a fullscreen as argument.");
    }

    /**
     * Closes the topmost screen.
     */
    public void closeFirstScreen() {
        if (screens.size() > 1) {
            screens.removeFirst();
            recalculate();
        } else {
            printMainScreenWarning("close");
        }
    }

    /**
     * Closes the given screen.
     * @param screen
     */
    public void closeScreen(Screen screen) {
        if (screen != getMainScreen()) {
            screens.remove(screen);
            recalculate();
        } else {
            printMainScreenWarning("close");
        }
    }

    /**
     * Sets the main screen to a new instance
     * @param mainScreen the new main screen
     */
    public void setMainScreen(FullScreen mainScreen) {
        if (mainScreen == null) {
            throw new IllegalStateException("Main Screen may not be null");
        }
        screens.set(screens.size() - 1, mainScreen);
    }

    /**
     * Gets the main screen
     * @return the main screen
     */
    public FullScreen getMainScreen() {
        if (!(screens.getLast() instanceof FullScreen) && screens.getLast() != null) {
            //Should never happen
            throw new IllegalStateException("Main Screen is not a FullScreen");
        }

        return (FullScreen) screens.getLast();
    }

    private void recalculate() {
        visibleScreens.clear();
        for (Screen screen : screens) {
            visibleScreens.addLast(screen);
            if (screen instanceof FullScreen) {
                FullScreen fs = (FullScreen) screen;
                if (!fs.isTransparent()) {
                    break;
                }
            }
        }
    }

    private Screen getHitScreen(Point position) {
        for (Screen screen : screens) {
            if (screen.getGeometry().contains(position)) {
                return screen;
            }
        }
        return null;
    }

    @Override
    public void onMouseDown(Point position, MouseButton button) {
        Screen screen = getHitScreen(position);
        if (screen != null) {
            Point screenPosition = new Point(position);
            screenPosition.translate(-screen.getGeometry().x, -screen.getGeometry().y);
            getHitScreen(position).onMouseDown(screenPosition, button);
        }
    }

    @Override
    public void onMouseMove(Point from, Point to) {
        Screen screen = getHitScreen(from);
        if (screen != null) {
            Point screenPositionFrom = new Point(from);
            Point screenPositionTo = new Point(to);
            screenPositionFrom.translate(-screen.getGeometry().x, -screen.getGeometry().y);
            screenPositionTo.translate(-screen.getGeometry().x, -screen.getGeometry().y);
            screen.onMouseMove(screenPositionFrom, screenPositionTo);
        }
        screen = getHitScreen(to);
        if (screen != null) {
            Point screenPositionFrom = new Point(from);
            Point screenPositionTo = new Point(to);
            screenPositionFrom.translate(-screen.getGeometry().x, -screen.getGeometry().y);
            screenPositionTo.translate(-screen.getGeometry().x, -screen.getGeometry().y);
            screen.onMouseMove(screenPositionFrom, screenPositionTo);
        }
    }

    @Override
    public void onMouseUp(Point position, MouseButton button) {
        Screen screen = getHitScreen(position);
        if (screen != null) {
            Point screenPosition = new Point(position);
            screenPosition.translate(-screen.getGeometry().x, -screen.getGeometry().y);
            getHitScreen(position).onMouseUp(screenPosition, button);
        }
    }

    @Override
    public void onKeyPress(Keyboard key) {
        getFirstScreen().onKeyPress(key);
    }

    @Override
    public void onKeyRelease(Keyboard key) {
        getFirstScreen().onKeyRelease(key);
    }

    @Override
    public void render() {
        for (Screen screen : visibleScreens) {
            GL11.glTranslated(screen.getGeometry().x, screen.getGeometry().y, 0);
            GL11.glPushMatrix();
            screen.render();
            GL11.glPopMatrix();
        }
    }

    @Override
    public void onTick(float dt) {
        //Check for resize
        if (Display.getWidth() != width || Display.getHeight() != height) {
            updateScreenSize();
            emit(SIGNAL_RESIZED, width, height);
        }
        //Invisible screens don't have to be ticked
        for (Screen screen : visibleScreens) {
            screen.onTick(dt);
        }
    }
}