-/**
+/*
* Jexer - Java Text User Interface
*
- * License: LGPLv3 or later
- *
- * This module is licensed under the GNU Lesser General Public License
- * Version 3. Please see the file "COPYING" in this directory for more
- * information about the GNU Lesser General Public License Version 3.
+ * The MIT License (MIT)
*
- * Copyright (C) 2015 Kevin Lamonte
+ * Copyright (C) 2017 Kevin Lamonte
*
- * This program 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.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
*
- * 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
- * General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * 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/, or write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
*
* @author Kevin Lamonte [kevin.lamonte@gmail.com]
* @version 1
*/
package jexer;
+import java.util.HashSet;
+
import jexer.bits.Cell;
import jexer.bits.CellAttributes;
import jexer.bits.GraphicsChars;
*/
public class TWindow extends TWidget {
+ // ------------------------------------------------------------------------
+ // Public constants -------------------------------------------------------
+ // ------------------------------------------------------------------------
+
/**
- * Window's parent TApplication.
+ * Window is resizable (default yes).
*/
- private TApplication application;
+ public static final int RESIZABLE = 0x01;
/**
- * Get this TWindow's parent TApplication.
- *
- * @return this TWindow's parent TApplication
+ * Window is modal (default no).
*/
- @Override
- public final TApplication getApplication() {
- return application;
- }
+ public static final int MODAL = 0x02;
/**
- * Get the Screen.
- *
- * @return the Screen
+ * Window is centered (default no).
*/
- @Override
- public final Screen getScreen() {
- return application.getScreen();
- }
+ public static final int CENTERED = 0x04;
+
+ // ------------------------------------------------------------------------
+ // Common window attributes -----------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Window flags. Note package private access.
+ */
+ int flags = RESIZABLE;
/**
* Window title.
this.title = title;
}
- /**
- * Window is resizable (default yes).
- */
- public static final int RESIZABLE = 0x01;
+ // ------------------------------------------------------------------------
+ // TApplication integration -----------------------------------------------
+ // ------------------------------------------------------------------------
/**
- * Window is modal (default no).
+ * Window's parent TApplication.
*/
- public static final int MODAL = 0x02;
+ private TApplication application;
/**
- * Window is centered (default no).
+ * Get this TWindow's parent TApplication.
+ *
+ * @return this TWindow's parent TApplication
*/
- public static final int CENTERED = 0x04;
+ @Override
+ public final TApplication getApplication() {
+ return application;
+ }
/**
- * Window flags.
+ * Get the Screen.
+ *
+ * @return the Screen
*/
- private int flags = RESIZABLE;
+ @Override
+ public final Screen getScreen() {
+ return application.getScreen();
+ }
/**
* Z order. Lower number means more in-front.
this.z = z;
}
+ /**
+ * Window's keyboard shortcuts. Any key in this set will be passed to
+ * the window directly rather than processed through the menu
+ * accelerators.
+ */
+ private HashSet<TKeypress> keyboardShortcuts = new HashSet<TKeypress>();
+
+ /**
+ * Add a keypress to be overridden for this window.
+ *
+ * @param key the key to start taking control of
+ */
+ protected void addShortcutKeypress(final TKeypress key) {
+ keyboardShortcuts.add(key);
+ }
+
+ /**
+ * Remove a keypress to be overridden for this window.
+ *
+ * @param key the key to stop taking control of
+ */
+ protected void removeShortcutKeypress(final TKeypress key) {
+ keyboardShortcuts.remove(key);
+ }
+
+ /**
+ * Remove all keypresses to be overridden for this window.
+ */
+ protected void clearShortcutKeypresses() {
+ keyboardShortcuts.clear();
+ }
+
+ /**
+ * Determine if a keypress is overridden for this window.
+ *
+ * @param key the key to check
+ * @return true if this window wants to process this key on its own
+ */
+ public boolean isShortcutKeypress(final TKeypress key) {
+ return keyboardShortcuts.contains(key);
+ }
+
+ /**
+ * A window may have a status bar associated with it. TApplication will
+ * draw this status bar last, and will also route events to it first
+ * before the window.
+ */
+ protected TStatusBar statusBar = null;
+
+ /**
+ * Get the window's status bar, or null if it does not have one.
+ *
+ * @return the status bar, or null
+ */
+ public TStatusBar getStatusBar() {
+ return statusBar;
+ }
+
+ /**
+ * Set the window's status bar to a new one.
+ *
+ * @param text the status bar text
+ * @return the status bar
+ */
+ public TStatusBar newStatusBar(final String text) {
+ statusBar = new TStatusBar(this, text);
+ return statusBar;
+ }
+
+ // ------------------------------------------------------------------------
+ // Window movement/resizing support ---------------------------------------
+ // ------------------------------------------------------------------------
+
/**
* If true, then the user clicked on the title bar and is moving the
* window.
this.maximumWindowWidth = maximumWindowWidth;
}
+ /**
+ * Recenter the window on-screen.
+ */
+ public final void center() {
+ if ((flags & CENTERED) != 0) {
+ if (getWidth() < getScreen().getWidth()) {
+ setX((getScreen().getWidth() - getWidth()) / 2);
+ } else {
+ setX(0);
+ }
+ setY(((application.getDesktopBottom()
+ - application.getDesktopTop()) - getHeight()) / 2);
+ if (getY() < 0) {
+ setY(0);
+ }
+ setY(getY() + application.getDesktopTop());
+ }
+ }
+
+ /**
+ * Maximize window.
+ */
+ private void maximize() {
+ restoreWindowWidth = getWidth();
+ restoreWindowHeight = getHeight();
+ restoreWindowX = getX();
+ restoreWindowY = getY();
+ setWidth(getScreen().getWidth());
+ setHeight(application.getDesktopBottom() - 1);
+ setX(0);
+ setY(1);
+ maximized = true;
+ }
+
+ /**
+ * Restote (unmaximize) window.
+ */
+ private void restore() {
+ setWidth(restoreWindowWidth);
+ setHeight(restoreWindowHeight);
+ setX(restoreWindowX);
+ setY(restoreWindowY);
+ maximized = false;
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructors -----------------------------------------------------------
+ // ------------------------------------------------------------------------
+
/**
* Public constructor. Window will be located at (0, 0).
*
application.addWindow(this);
}
- /**
- * Recenter the window on-screen.
- */
- public final void center() {
- if ((flags & CENTERED) != 0) {
- if (getWidth() < getScreen().getWidth()) {
- setX((getScreen().getWidth() - getWidth()) / 2);
- } else {
- setX(0);
- }
- setY(((application.getDesktopBottom()
- - application.getDesktopTop()) - getHeight()) / 2);
- if (getY() < 0) {
- setY(0);
- }
- setY(getY() + application.getDesktopTop());
- }
- }
+ // ------------------------------------------------------------------------
+ // General behavior -------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Returns true if this window is modal.
return true;
}
- /**
- * Returns true if the mouse is currently on the close button.
- *
- * @return true if mouse is currently on the close button
- */
- private boolean mouseOnClose() {
- if ((mouse != null)
- && (mouse.getAbsoluteY() == getY())
- && (mouse.getAbsoluteX() == getX() + 3)
- ) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if the mouse is currently on the maximize/restore button.
- *
- * @return true if the mouse is currently on the maximize/restore button
- */
- private boolean mouseOnMaximize() {
- if ((mouse != null)
- && !isModal()
- && (mouse.getAbsoluteY() == getY())
- && (mouse.getAbsoluteX() == getX() + getWidth() - 4)
- ) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if the mouse is currently on the resizable lower right
- * corner.
- *
- * @return true if the mouse is currently on the resizable lower right
- * corner
- */
- private boolean mouseOnResize() {
- if (((flags & RESIZABLE) != 0)
- && !isModal()
- && (mouse != null)
- && (mouse.getAbsoluteY() == getY() + getHeight() - 1)
- && ((mouse.getAbsoluteX() == getX() + getWidth() - 1)
- || (mouse.getAbsoluteX() == getX() + getWidth() - 2))
- ) {
- return true;
- }
- return false;
- }
-
/**
* Retrieve the background color.
*
*
* @return the border color
*/
- private CellAttributes getBorder() {
+ public CellAttributes getBorder() {
if (!isModal()
&& (inWindowMove || inWindowResize || inKeyboardResize)
) {
}
}
- /**
- * Subclasses should override this method to cleanup resources. This is
- * called by application.closeWindow().
- */
- public void onClose() {
- // Default: do nothing
- }
-
/**
* Called by TApplication.drawChildren() to render on screen.
*/
// Draw the title
int titleLeft = (getWidth() - title.length() - 2) / 2;
putCharXY(titleLeft, 0, ' ', border);
- putStrXY(titleLeft + 1, 0, title);
+ putStringXY(titleLeft + 1, 0, title);
putCharXY(titleLeft + title.length() + 1, 0, ' ', border);
if (isActive()) {
}
}
+ // ------------------------------------------------------------------------
+ // Event handlers ---------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns true if the mouse is currently on the close button.
+ *
+ * @return true if mouse is currently on the close button
+ */
+ private boolean mouseOnClose() {
+ if ((mouse != null)
+ && (mouse.getAbsoluteY() == getY())
+ && (mouse.getAbsoluteX() == getX() + 3)
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the mouse is currently on the maximize/restore button.
+ *
+ * @return true if the mouse is currently on the maximize/restore button
+ */
+ private boolean mouseOnMaximize() {
+ if ((mouse != null)
+ && !isModal()
+ && (mouse.getAbsoluteY() == getY())
+ && (mouse.getAbsoluteX() == getX() + getWidth() - 4)
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the mouse is currently on the resizable lower right
+ * corner.
+ *
+ * @return true if the mouse is currently on the resizable lower right
+ * corner
+ */
+ private boolean mouseOnResize() {
+ if (((flags & RESIZABLE) != 0)
+ && !isModal()
+ && (mouse != null)
+ && (mouse.getAbsoluteY() == getY() + getHeight() - 1)
+ && ((mouse.getAbsoluteX() == getX() + getWidth() - 1)
+ || (mouse.getAbsoluteX() == getX() + getWidth() - 2))
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Subclasses should override this method to cleanup resources. This is
+ * called by application.closeWindow().
+ */
+ public void onClose() {
+ // Default: do nothing
+ }
+
+ /**
+ * Called by application.switchWindow() when this window gets the
+ * focus, and also by application.addWindow().
+ */
+ public void onFocus() {
+ // Default: do nothing
+ }
+
+ /**
+ * Called by application.switchWindow() when another window gets the
+ * focus.
+ */
+ public void onUnfocus() {
+ // Default: do nothing
+ }
+
/**
* Handle mouse button presses.
*
return;
}
+ // Give the shortcut bar a shot at this.
+ if (statusBar != null) {
+ if (statusBar.statusBarMouseDown(mouse)) {
+ return;
+ }
+ }
+
// I didn't take it, pass it on to my children
super.onMouseDown(mouse);
}
- /**
- * Maximize window.
- */
- private void maximize() {
- restoreWindowWidth = getWidth();
- restoreWindowHeight = getHeight();
- restoreWindowX = getX();
- restoreWindowY = getY();
- setWidth(getScreen().getWidth());
- setHeight(application.getDesktopBottom() - 1);
- setX(0);
- setY(1);
- maximized = true;
- }
-
- /**
- * Restote (unmaximize) window.
- */
- private void restore() {
- setWidth(restoreWindowWidth);
- setHeight(restoreWindowHeight);
- setX(restoreWindowX);
- setY(restoreWindowY);
- maximized = false;
- }
-
/**
* Handle mouse button releases.
*
return;
}
+ // Give the shortcut bar a shot at this.
+ if (statusBar != null) {
+ if (statusBar.statusBarMouseUp(mouse)) {
+ return;
+ }
+ }
+
// I didn't take it, pass it on to my children
super.onMouseUp(mouse);
}
if (getY() < application.getDesktopTop()) {
setY(application.getDesktopTop());
}
+ // Don't go below the status bar
+ if (getY() >= application.getDesktopBottom()) {
+ setY(application.getDesktopBottom() - 1);
+ }
return;
}
return;
}
+ // Give the shortcut bar a shot at this.
+ if (statusBar != null) {
+ statusBar.statusBarMouseMotion(mouse);
+ }
+
// I didn't take it, pass it on to my children
super.onMouseMotion(mouse);
}
if (inKeyboardResize) {
- // ESC - Exit size/move
- if (keypress.equals(kbEsc)) {
+ // ESC or ENTER - Exit size/move
+ if (keypress.equals(kbEsc) || keypress.equals(kbEnter)) {
inKeyboardResize = false;
}
}
}
+ // Pass a resize event to my children
+ onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
+ getWidth(), getHeight()));
+
return;
}
+ // Give the shortcut bar a shot at this.
+ if (statusBar != null) {
+ if (statusBar.statusBarKeypress(keypress)) {
+ return;
+ }
+ }
+
// These keystrokes will typically not be seen unless a subclass
// overrides onMenu() due to how TApplication dispatches
// accelerators.
* @param str string to draw
* @param attr attributes to use (bold, foreColor, backColor)
*/
- public final void putStrXY(final int x, final int y, final String str,
+ public final void putStringXY(final int x, final int y, final String str,
final CellAttributes attr) {
- getScreen().putStrXY(x, y, str, attr);
+ getScreen().putStringXY(x, y, str, attr);
}
/**
* @param y row coordinate. 0 is the top-most row.
* @param str string to draw
*/
- public final void putStrXY(final int x, final int y, final String str) {
- getScreen().putStrXY(x, y, str);
+ public final void putStringXY(final int x, final int y, final String str) {
+ getScreen().putStringXY(x, y, str);
}
/**