Version 2.0.0: update sources
[jvcard.git] / src / com / googlecode / lanterna / gui2 / MultiWindowTextGUI.java
diff --git a/src/com/googlecode/lanterna/gui2/MultiWindowTextGUI.java b/src/com/googlecode/lanterna/gui2/MultiWindowTextGUI.java
deleted file mode 100644 (file)
index 5b6cc44..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * This file is part of lanterna (http://code.google.com/p/lanterna/).
- * 
- * lanterna 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.
- *
- * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
- * 
- * Copyright (C) 2010-2015 Martin
- */
-package com.googlecode.lanterna.gui2;
-
-import com.googlecode.lanterna.TextCharacter;
-import com.googlecode.lanterna.graphics.BasicTextImage;
-import com.googlecode.lanterna.graphics.TextImage;
-import com.googlecode.lanterna.input.KeyStroke;
-import com.googlecode.lanterna.input.KeyType;
-import com.googlecode.lanterna.screen.Screen;
-import com.googlecode.lanterna.TerminalPosition;
-import com.googlecode.lanterna.TerminalSize;
-import com.googlecode.lanterna.TextColor;
-import com.googlecode.lanterna.screen.VirtualScreen;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.util.*;
-
-/**
- * This is the main Text GUI implementation built into Lanterna, supporting multiple tiled windows and a dynamic
- * background area that can be fully customized. If you want to create a text-based GUI with windows and controls,
- * it's very likely this is what you want to use.
- *
- * @author Martin
- */
-public class MultiWindowTextGUI extends AbstractTextGUI implements WindowBasedTextGUI {
-    private final VirtualScreen virtualScreen;
-    private final WindowManager windowManager;
-    private final BasePane backgroundPane;
-    private final List<Window> windows;
-    private final IdentityHashMap<Window, TextImage> windowRenderBufferCache;
-    private final WindowPostRenderer postRenderer;
-
-    private Window activeWindow;
-    private boolean eofWhenNoWindows;
-
-    /**
-     * Creates a new {@code MultiWindowTextGUI} that uses the specified {@code Screen} as the backend for all drawing
-     * operations. The screen will be automatically wrapped in a {@code VirtualScreen} in order to deal with GUIs
-     * becoming too big to fit the terminal. The background area of the GUI will be solid blue.
-     * @param screen Screen to use as the backend for drawing operations
-     */
-    public MultiWindowTextGUI(Screen screen) {
-        this(screen, TextColor.ANSI.BLUE);
-    }
-
-    /**
-     * Creates a new {@code MultiWindowTextGUI} that uses the specified {@code Screen} as the backend for all drawing
-     * operations. The screen will be automatically wrapped in a {@code VirtualScreen} in order to deal with GUIs
-     * becoming too big to fit the terminal. The background area of the GUI will be solid blue
-     * @param guiThreadFactory Factory implementation to use when creating the {@code TextGUIThread}
-     * @param screen Screen to use as the backend for drawing operations
-     */
-    public MultiWindowTextGUI(TextGUIThreadFactory guiThreadFactory, Screen screen) {
-        this(guiThreadFactory,
-                screen,
-                new DefaultWindowManager(),
-                new WindowShadowRenderer(),
-                new EmptySpace(TextColor.ANSI.BLUE));
-    }
-
-    /**
-     * Creates a new {@code MultiWindowTextGUI} that uses the specified {@code Screen} as the backend for all drawing
-     * operations. The screen will be automatically wrapped in a {@code VirtualScreen} in order to deal with GUIs
-     * becoming too big to fit the terminal. The background area of the GUI is a solid color as decided by the
-     * {@code backgroundColor} parameter.
-     * @param screen Screen to use as the backend for drawing operations
-     * @param backgroundColor Color to use for the GUI background
-     */
-    public MultiWindowTextGUI(
-            Screen screen,
-            TextColor backgroundColor) {
-
-        this(screen, new DefaultWindowManager(), new EmptySpace(backgroundColor));
-    }
-
-    /**
-     * Creates a new {@code MultiWindowTextGUI} that uses the specified {@code Screen} as the backend for all drawing
-     * operations. The screen will be automatically wrapped in a {@code VirtualScreen} in order to deal with GUIs
-     * becoming too big to fit the terminal. The background area of the GUI is the component passed in as the
-     * {@code background} parameter, forced to full size.
-     * @param screen Screen to use as the backend for drawing operations
-     * @param windowManager Window manager implementation to use
-     * @param background Component to use as the background of the GUI, behind all the windows
-     */
-    public MultiWindowTextGUI(
-            Screen screen,
-            WindowManager windowManager,
-            Component background) {
-
-        this(screen, windowManager, new WindowShadowRenderer(), background);
-    }
-
-    /**
-     * Creates a new {@code MultiWindowTextGUI} that uses the specified {@code Screen} as the backend for all drawing
-     * operations. The screen will be automatically wrapped in a {@code VirtualScreen} in order to deal with GUIs
-     * becoming too big to fit the terminal. The background area of the GUI is the component passed in as the
-     * {@code background} parameter, forced to full size.
-     * @param screen Screen to use as the backend for drawing operations
-     * @param windowManager Window manager implementation to use
-     * @param postRenderer {@code WindowPostRenderer} object to invoke after each window has been drawn
-     * @param background Component to use as the background of the GUI, behind all the windows
-     */
-    public MultiWindowTextGUI(
-            Screen screen,
-            WindowManager windowManager,
-            WindowPostRenderer postRenderer,
-            Component background) {
-
-        this(new SameTextGUIThread.Factory(), screen, windowManager, postRenderer, background);
-    }
-
-    /**
-     * Creates a new {@code MultiWindowTextGUI} that uses the specified {@code Screen} as the backend for all drawing
-     * operations. The screen will be automatically wrapped in a {@code VirtualScreen} in order to deal with GUIs
-     * becoming too big to fit the terminal. The background area of the GUI is the component passed in as the
-     * {@code background} parameter, forced to full size.
-     * @param guiThreadFactory Factory implementation to use when creating the {@code TextGUIThread}
-     * @param screen Screen to use as the backend for drawing operations
-     * @param windowManager Window manager implementation to use
-     * @param postRenderer {@code WindowPostRenderer} object to invoke after each window has been drawn
-     * @param background Component to use as the background of the GUI, behind all the windows
-     */
-    public MultiWindowTextGUI(
-            TextGUIThreadFactory guiThreadFactory,
-            Screen screen,
-            WindowManager windowManager,
-            WindowPostRenderer postRenderer,
-            Component background) {
-
-        this(guiThreadFactory, new VirtualScreen(screen), windowManager, postRenderer, background);
-    }
-
-    private MultiWindowTextGUI(
-            TextGUIThreadFactory guiThreadFactory,
-            VirtualScreen screen,
-            WindowManager windowManager,
-            WindowPostRenderer postRenderer,
-            Component background) {
-
-        super(guiThreadFactory, screen);
-        if(windowManager == null) {
-            throw new IllegalArgumentException("Creating a window-based TextGUI requires a WindowManager");
-        }
-        if(background == null) {
-            //Use a sensible default instead of throwing
-            background = new EmptySpace(TextColor.ANSI.BLUE);
-        }
-        this.virtualScreen = screen;
-        this.windowManager = windowManager;
-        this.backgroundPane = new AbstractBasePane() {
-            @Override
-            public TextGUI getTextGUI() {
-                return MultiWindowTextGUI.this;
-            }
-
-            @Override
-            public TerminalPosition toGlobal(TerminalPosition localPosition) {
-                return localPosition;
-            }
-
-            public TerminalPosition fromGlobal(TerminalPosition globalPosition) {
-                return globalPosition;
-            }
-        };
-        this.backgroundPane.setComponent(background);
-        this.windows = new LinkedList<Window>();
-        this.windowRenderBufferCache = new IdentityHashMap<Window, TextImage>();
-        this.postRenderer = postRenderer;
-        this.eofWhenNoWindows = false;
-    }
-
-    @Override
-    public synchronized boolean isPendingUpdate() {
-        for(Window window: windows) {
-            if(window.isInvalid()) {
-                return true;
-            }
-        }
-        return super.isPendingUpdate() || backgroundPane.isInvalid() || windowManager.isInvalid();
-    }
-
-    @Override
-    public synchronized void updateScreen() throws IOException {
-        TerminalSize minimumTerminalSize = TerminalSize.ZERO;
-        for(Window window: windows) {
-            if(window.isVisible()) {
-                if (window.getHints().contains(Window.Hint.FULL_SCREEN) ||
-                        window.getHints().contains(Window.Hint.FIT_TERMINAL_WINDOW) ||
-                        window.getHints().contains(Window.Hint.EXPANDED)) {
-                    //Don't take full screen windows or auto-sized windows into account
-                    continue;
-                }
-                TerminalPosition lastPosition = window.getPosition();
-                minimumTerminalSize = minimumTerminalSize.max(
-                        //Add position to size to get the bottom-right corner of the window
-                        window.getDecoratedSize().withRelative(
-                                Math.max(lastPosition.getColumn(), 0),
-                                Math.max(lastPosition.getRow(), 0)));
-            }
-        }
-        virtualScreen.setMinimumSize(minimumTerminalSize);
-        super.updateScreen();
-    }
-
-    @Override
-    protected synchronized KeyStroke readKeyStroke() throws IOException {
-        KeyStroke keyStroke = super.pollInput();
-        if(eofWhenNoWindows && keyStroke == null && windows.isEmpty()) {
-            return new KeyStroke(KeyType.EOF);
-        }
-        else if(keyStroke != null) {
-            return keyStroke;
-        }
-        else {
-            return super.readKeyStroke();
-        }
-    }
-
-    @Override
-    protected synchronized void drawGUI(TextGUIGraphics graphics) {
-        backgroundPane.draw(graphics);
-        getWindowManager().prepareWindows(this, Collections.unmodifiableList(windows), graphics.getSize());
-        for(Window window: windows) {
-            if (window.isVisible()) {
-                // First draw windows to a buffer, then copy it to the real destination. This is to make physical off-screen
-                // drawing work better. Store the buffers in a cache so we don't have to re-create them every time.
-                TextImage textImage = windowRenderBufferCache.get(window);
-                if (textImage == null || !textImage.getSize().equals(window.getDecoratedSize())) {
-                    textImage = new BasicTextImage(window.getDecoratedSize());
-                    windowRenderBufferCache.put(window, textImage);
-                }
-                TextGUIGraphics windowGraphics = new TextGUIGraphics(this, textImage.newTextGraphics(), graphics.getTheme());
-
-                TerminalPosition contentOffset = TerminalPosition.TOP_LEFT_CORNER;
-                if (!window.getHints().contains(Window.Hint.NO_DECORATIONS)) {
-                    WindowDecorationRenderer decorationRenderer = getWindowManager().getWindowDecorationRenderer(window);
-                    windowGraphics = decorationRenderer.draw(this, windowGraphics, window);
-                    contentOffset = decorationRenderer.getOffset(window);
-                }
-
-                window.draw(windowGraphics);
-                window.setContentOffset(contentOffset);
-                Borders.joinLinesWithFrame(windowGraphics);
-
-                graphics.drawImage(window.getPosition(), textImage);
-
-                if (postRenderer != null && !window.getHints().contains(Window.Hint.NO_POST_RENDERING)) {
-                    postRenderer.postRender(graphics, this, window);
-                }
-            }
-        }
-
-        // Purge the render buffer cache from windows that have been removed
-        windowRenderBufferCache.keySet().retainAll(windows);
-    }
-
-    @Override
-    public synchronized TerminalPosition getCursorPosition() {
-        Window activeWindow = getActiveWindow();
-        if(activeWindow != null) {
-            return activeWindow.toGlobal(activeWindow.getCursorPosition());
-        }
-        else {
-            return backgroundPane.getCursorPosition();
-        }
-    }
-
-    /**
-     * Sets whether the TextGUI should return EOF when you try to read input while there are no windows in the window
-     * manager. Setting this to true (on by default) will make the GUI automatically exit when the last window has been
-     * closed.
-     * @param eofWhenNoWindows Should the GUI return EOF when there are no windows left
-     */
-    public void setEOFWhenNoWindows(boolean eofWhenNoWindows) {
-        this.eofWhenNoWindows = eofWhenNoWindows;
-    }
-
-    /**
-     * Returns whether the TextGUI should return EOF when you try to read input while there are no windows in the window
-     * manager. When this is true (true by default) will make the GUI automatically exit when the last window has been
-     * closed.
-     * @return Should the GUI return EOF when there are no windows left
-     */
-    public boolean isEOFWhenNoWindows() {
-        return eofWhenNoWindows;
-    }
-
-    @Override
-    public synchronized Interactable getFocusedInteractable() {
-        Window activeWindow = getActiveWindow();
-        if(activeWindow != null) {
-            return activeWindow.getFocusedInteractable();
-        }
-        else {
-            return backgroundPane.getFocusedInteractable();
-        }
-    }
-
-    @Override
-    public synchronized boolean handleInput(KeyStroke keyStroke) {
-        Window activeWindow = getActiveWindow();
-        if(activeWindow != null) {
-            return activeWindow.handleInput(keyStroke);
-        }
-        else {
-            return backgroundPane.handleInput(keyStroke);
-        }
-    }
-
-    @Override
-    public WindowManager getWindowManager() {
-        return windowManager;
-    }
-
-    @Override
-    public synchronized WindowBasedTextGUI addWindow(Window window) {
-        //To protect against NPE if the user forgot to set a content component
-        if(window.getComponent() == null) {
-            window.setComponent(new EmptySpace(TerminalSize.ONE));
-        }
-
-        if(window.getTextGUI() != null) {
-            window.getTextGUI().removeWindow(window);
-        }
-        window.setTextGUI(this);
-        windowManager.onAdded(this, window, windows);
-        if(!windows.contains(window)) {
-            windows.add(window);
-        }
-        if(!window.getHints().contains(Window.Hint.NO_FOCUS)) {
-            setActiveWindow(window);
-        }
-        invalidate();
-        return this;
-    }
-
-    @Override
-    public WindowBasedTextGUI addWindowAndWait(Window window) {
-        addWindow(window);
-        window.waitUntilClosed();
-        return this;
-    }
-
-    @Override
-    public synchronized WindowBasedTextGUI removeWindow(Window window) {
-        if(!windows.remove(window)) {
-            //Didn't contain this window
-            return this;
-        }
-        window.setTextGUI(null);
-        windowManager.onRemoved(this, window, windows);
-        if(activeWindow == window) {
-            //Go backward in reverse and find the first suitable window
-            for(int index = windows.size() - 1; index >= 0; index--) {
-                Window candidate = windows.get(index);
-                if(!candidate.getHints().contains(Window.Hint.NO_FOCUS)) {
-                    setActiveWindow(candidate);
-                    break;
-                }
-            }
-        }
-        invalidate();
-        return this;
-    }
-
-    @Override
-    public void waitForWindowToClose(Window window) {
-        while(window.getTextGUI() != null) {
-            boolean sleep = true;
-            TextGUIThread guiThread = getGUIThread();
-            if(Thread.currentThread() == guiThread.getThread()) {
-                try {
-                    sleep = !guiThread.processEventsAndUpdate();
-                }
-                catch(EOFException ignore) {
-                    //The GUI has closed so allow exit
-                    break;
-                }
-                catch(IOException e) {
-                    throw new RuntimeException("Unexpected IOException while waiting for window to close", e);
-                }
-            }
-            if(sleep) {
-                try {
-                    Thread.sleep(1);
-                }
-                catch(InterruptedException ignore) {}
-            }
-        }
-    }
-
-    @Override
-    public synchronized Collection<Window> getWindows() {
-        return Collections.unmodifiableList(new ArrayList<Window>(windows));
-    }
-
-    @Override
-    public synchronized MultiWindowTextGUI setActiveWindow(Window activeWindow) {
-        this.activeWindow = activeWindow;
-        return this;
-    }
-
-    @Override
-    public synchronized Window getActiveWindow() {
-        return activeWindow;
-    }
-
-    @Override
-    public BasePane getBackgroundPane() {
-        return backgroundPane;
-    }
-
-    @Override
-    public Screen getScreen() {
-        return virtualScreen;
-    }
-
-    @Override
-    public WindowPostRenderer getWindowPostRenderer() {
-        return postRenderer;
-    }
-
-    @Override
-    public synchronized WindowBasedTextGUI moveToTop(Window window) {
-        if(!windows.contains(window)) {
-            throw new IllegalArgumentException("Window " + window + " isn't in MultiWindowTextGUI " + this);
-        }
-        windows.remove(window);
-        windows.add(window);
-        invalidate();
-        return this;
-    }
-
-    /**
-     * Switches the active window by cyclically shuffling the window list. If {@code reverse} parameter is {@code false}
-     * then the current top window is placed at the bottom of the stack and the window immediately behind it is the new
-     * top. If {@code reverse} is set to {@code true} then the window at the bottom of the stack is moved up to the
-     * front and the previous top window will be immediately below it
-     * @param reverse Direction to cycle through the windows
-     * @return Itself
-     */
-    public synchronized WindowBasedTextGUI cycleActiveWindow(boolean reverse) {
-        if(windows.isEmpty() || windows.size() == 1 || activeWindow.getHints().contains(Window.Hint.MODAL)) {
-            return this;
-        }
-        Window originalActiveWindow = activeWindow;
-        Window nextWindow = getNextWindow(reverse, originalActiveWindow);
-        while(nextWindow.getHints().contains(Window.Hint.NO_FOCUS)) {
-            nextWindow = getNextWindow(reverse, nextWindow);
-            if(nextWindow == originalActiveWindow) {
-                return this;
-            }
-        }
-
-        if(reverse) {
-            moveToTop(nextWindow);
-        }
-        else {
-            windows.remove(originalActiveWindow);
-            windows.add(0, originalActiveWindow);
-        }
-        setActiveWindow(nextWindow);
-        return this;
-    }
-
-    private Window getNextWindow(boolean reverse, Window window) {
-        int index = windows.indexOf(window);
-        if(reverse) {
-            if(++index >= windows.size()) {
-                index = 0;
-            }
-        }
-        else {
-            if(--index < 0) {
-                index = windows.size() - 1;
-            }
-        }
-        return windows.get(index);
-    }
-}