/*
* 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.TerminalPosition;
import com.googlecode.lanterna.input.KeyStroke;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.input.KeyType;
import java.util.*;
/**
* Abstract Window has most of the code requiring for a window to function, all concrete window implementations extends
* from this in one way or another. You can define your own window by extending from this, as an alternative to building
* up the GUI externally by constructing a {@code BasicWindow} and adding components to it.
* @author Martin
*/
public abstract class AbstractWindow extends AbstractBasePane implements Window {
private String title;
private WindowBasedTextGUI textGUI;
private boolean visible;
private TerminalSize lastKnownSize;
private TerminalSize lastKnownDecoratedSize;
private TerminalPosition lastKnownPosition;
private TerminalPosition contentOffset;
private Set hints;
private boolean closeWindowWithEscape;
/**
* Default constructor, this creates a window with no title
*/
public AbstractWindow() {
this("");
}
/**
* Creates a window with a specific title that will (probably) be drawn in the window decorations
* @param title Title of this window
*/
public AbstractWindow(String title) {
super();
this.title = title;
this.textGUI = null;
this.visible = true;
this.lastKnownPosition = null;
this.lastKnownSize = null;
this.lastKnownDecoratedSize = null;
this.closeWindowWithEscape = false;
this.hints = new HashSet();
}
/**
* Setting this property to {@code true} will cause pressing the ESC key to close the window. This used to be the
* default behaviour of lanterna 3 during the development cycle but is not longer the case. You are encouraged to
* put proper buttons or other kind of components to clearly mark to the user how to close the window instead of
* magically taking ESC, but sometimes it can be useful (when doing testing, for example) to enable this mode.
* @param closeWindowWithEscape If {@code true}, this window will self-close if you press ESC key
*/
public void setCloseWindowWithEscape(boolean closeWindowWithEscape) {
this.closeWindowWithEscape = closeWindowWithEscape;
}
@Override
public void setTextGUI(WindowBasedTextGUI textGUI) {
//This is kind of stupid check, but might cause it to blow up on people using the library incorrectly instead of
//just causing weird behaviour
if(this.textGUI != null && textGUI != null) {
throw new UnsupportedOperationException("Are you calling setTextGUI yourself? Please read the documentation"
+ " in that case (this could also be a bug in Lanterna, please report it if you are sure you are "
+ "not calling Window.setTextGUI(..) from your code)");
}
this.textGUI = textGUI;
}
@Override
public WindowBasedTextGUI getTextGUI() {
return textGUI;
}
/**
* Alters the title of the window to the supplied string
* @param title New title of the window
*/
public void setTitle(String title) {
this.title = title;
invalidate();
}
@Override
public String getTitle() {
return title;
}
@Override
public boolean isVisible() {
return visible;
}
@Override
public void setVisible(boolean visible) {
this.visible = visible;
}
@Override
public void draw(TextGUIGraphics graphics) {
if(!graphics.getSize().equals(lastKnownSize)) {
getComponent().invalidate();
}
setSize(graphics.getSize(), false);
super.draw(graphics);
}
@Override
public boolean handleInput(KeyStroke key) {
boolean handled = super.handleInput(key);
if(!handled && closeWindowWithEscape && key.getKeyType() == KeyType.Escape) {
close();
return true;
}
return handled;
}
@Override
public TerminalPosition toGlobal(TerminalPosition localPosition) {
if(localPosition == null) {
return null;
}
return lastKnownPosition.withRelative(contentOffset.withRelative(localPosition));
}
@Override
public TerminalPosition fromGlobal(TerminalPosition globalPosition) {
if(globalPosition == null) {
return null;
}
return globalPosition.withRelative(
-lastKnownPosition.getColumn() - contentOffset.getColumn(),
-lastKnownPosition.getRow() - contentOffset.getRow());
}
@Override
public TerminalSize getPreferredSize() {
return contentHolder.getPreferredSize();
}
@Override
public void setHints(Collection hints) {
this.hints = new HashSet(hints);
invalidate();
}
@Override
public Set getHints() {
return Collections.unmodifiableSet(hints);
}
@Override
public final TerminalPosition getPosition() {
return lastKnownPosition;
}
@Override
public final void setPosition(TerminalPosition topLeft) {
this.lastKnownPosition = topLeft;
}
@Override
public final TerminalSize getSize() {
return lastKnownSize;
}
@Override
public void setSize(TerminalSize size) {
setSize(size, true);
}
private void setSize(TerminalSize size, boolean invalidate) {
this.lastKnownSize = size;
if(invalidate) {
invalidate();
}
}
@Override
public final TerminalSize getDecoratedSize() {
return lastKnownDecoratedSize;
}
@Override
public final void setDecoratedSize(TerminalSize decoratedSize) {
this.lastKnownDecoratedSize = decoratedSize;
}
@Override
public void setContentOffset(TerminalPosition offset) {
this.contentOffset = offset;
}
@Override
public void close() {
if(textGUI != null) {
textGUI.removeWindow(this);
}
setComponent(null);
}
@Override
public void waitUntilClosed() {
WindowBasedTextGUI textGUI = getTextGUI();
if(textGUI != null) {
textGUI.waitForWindowToClose(this);
}
}
}