X-Git-Url: http://git.nikiroo.be/?p=jvcard.git;a=blobdiff_plain;f=src%2Fcom%2Fgooglecode%2Flanterna%2Fgui2%2FMultiWindowTextGUI.java;fp=src%2Fcom%2Fgooglecode%2Flanterna%2Fgui2%2FMultiWindowTextGUI.java;h=0000000000000000000000000000000000000000;hp=5b6cc443d30b9f99bf23c6659dff293ae2940515;hb=f06c81000632cfb5f525ca458f719338f55f9f66;hpb=a73a906356c971b080c36368e71a15d87e8b8d31 diff --git a/src/com/googlecode/lanterna/gui2/MultiWindowTextGUI.java b/src/com/googlecode/lanterna/gui2/MultiWindowTextGUI.java deleted file mode 100644 index 5b6cc44..0000000 --- a/src/com/googlecode/lanterna/gui2/MultiWindowTextGUI.java +++ /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 . - * - * 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 windows; - private final IdentityHashMap 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(); - this.windowRenderBufferCache = new IdentityHashMap(); - 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 getWindows() { - return Collections.unmodifiableList(new ArrayList(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); - } -}