/* * $Id: BottomWindow.java 535 2008-02-19 06:02:50Z weiju $ * * Created on 2006/01/23 * Copyright 2005-2008 by Wei-ju Wu * This file is part of The Z-machine Preservation Project (ZMPP). * * ZMPP is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ZMPP 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. * * You should have received a copy of the GNU General Public License * along with ZMPP. If not, see <http://www.gnu.org/licenses/>. */ package org.zmpp.swingui; import java.awt.Color; import java.awt.Font; /** * This class implements the lower window of the standard Z-machine screen * model. It extends on the base functionality defined in its super class, and * is much more complex than TopWindow, because it supports paging, buffering * and proportional font. * * @author Wei-ju Wu * @version 1.0 */ public class BottomWindow extends SubWindow { private boolean isBuffered; private boolean isPaged; private int verticalTextPixelsPrinted; private int currentX; private int currentY; private int lineHeight; private StringBuilder streambuffer; /** * Constructor. * * @param screen the screen model * @param editor the line editor * @param canvas the canvas to draw to */ public BottomWindow(Viewport viewport) { super(viewport, "BOTTOM"); setBufferMode(true); setPagingEnabled(true); streambuffer = new StringBuilder(); } /** * {@inheritDoc} */ public void flushBuffer() { // save some unnecessary flushes if (streambuffer.length() > 0) { printString(streambuffer.toString()); streambuffer = new StringBuilder(); } } /** * {@inheritDoc} */ public boolean isBuffered() { return isBuffered; } /** * {@inheritDoc} */ public void setPagingEnabled(boolean flag) { isPaged = flag; } /** * {@inheritDoc} */ public boolean isPagingEnabled() { return isPaged; } /** * {@inheritDoc} */ public void setBufferMode(boolean flag) { isBuffered = flag; } /** * {@inheritDoc} */ public void resetCursorToHome() { //System.out.println("resetCursorToHome()"); // We calulate an available height with a correction amount // of fm.getMaxDescent() to reserve enough scrolling space setCursorPosition(getAvailableLines(), 1); currentY = getTop() + getHeight() - getCanvas().getFontDescent(getFont()); } /** * Returns the available lines. * * @return the available lines */ private int getAvailableLines() { int descent = getCanvas().getFontDescent(getFont()); int fontHeight = getCanvas().getFontHeight(getFont()); return (getHeight() - descent) / fontHeight; } /** * Check if paging should be done. */ private void handlePaging() { if (isPaged && pageMinusOneLinePrinted()) { doMeMore(); } } private boolean pageMinusOneLinePrinted() { return (verticalTextPixelsPrinted + getCanvas().getFontDescent(getFont()) + getCanvas().getFontHeight(getFont())) >= getHeight(); } /** * Wait for key press. */ private void doMeMore() { // Invoke the super method, which does not handle paging printLineNonPaged("\n<MORE> (Press key to continue)", getTextBackground(), getTextColor()); getScreen().redraw(); // Do this exclusively to have better thread control, we need to stay // in the application thread getEditor().setInputMode(true, true); getEditor().nextZsciiChar(); resetCursorToHome(); eraseLine(); getEditor().setInputMode(false, true); resetPager(); } /** * Updates the page size. */ protected void sizeUpdated() { } /** * {@inheritDoc} */ @Override protected void newline() { //System.out.println("newline()"); super.newline(); scrollIfNeeded(); currentX = 0; // We need to remember the line height to calculate the next y position verticalTextPixelsPrinted += lineHeight; currentY += lineHeight; lineHeight = 0; } /** * {@inheritDoc} */ public void printChar(char c, boolean isInput) { if (isInput || !isBuffered()) { printString(String.valueOf(c)); } else { streambuffer.append(c); } } /** * {@inheritDoc} */ @Override protected void printLine(String line, Color textbackColor, Color textColor) { //System.out.printf("printLine(): '%s' current x: %d -> ", line, currentX); handlePaging(); scrollIfNeeded(); super.printLine(line, textbackColor, textColor); // Every elementary print instruction adds to the current line currentX += getCanvas().getStringWidth(getFont(), line); //System.out.printf("current x: %d\n", currentX); // Adjust the maximum line height lineHeight = Math.max(lineHeight, getCanvas().getFontHeight(getFont())); } private void printLineNonPaged(String line, Color textbackColor, Color textColor) { scrollIfNeeded(); super.printLine(line, textbackColor, textColor); // Every elementary print instruction adds to the current line currentX += getCanvas().getStringWidth(getFont(), line); // Adjust the maximum line height lineHeight = Math.max(lineHeight, getCanvas().getFontHeight(getFont())); } /** * {@inheritDoc} */ public void resetPager() { verticalTextPixelsPrinted = 0; } /** * {@inheritDoc} */ protected int getCurrentX() { return currentX; } /** * {@inheritDoc} */ protected int getCurrentY() { return currentY; } /** * {@inheritDoc} */ private void setCurrentY(int value) { currentY = value; } /** * {@inheritDoc} */ @Override public void backspace(char c) { super.backspace(c); currentX -= getCanvas().getCharWidth(getFont(), c); if (currentX < 0) { currentX = 0; } } /** * {@inheritDoc} */ public void updateCursorCoordinates() { Canvas canvas = getCanvas(); Font font = getFont(); int currentLine = getCursor().getLine(); int currentColumn = getCursor().getColumn(); currentX = (currentColumn - 1) * canvas.getCharWidth(font, '0'); currentY = getTop() + (currentLine - 1) * canvas.getFontHeight(font) + (canvas.getFontHeight(font) - canvas.getFontDescent(font)); } /** * {@inheritDoc} */ protected void scrollIfNeeded() { //System.out.printf("scrollIfNeeded(), current y: %d, window bottom: %d" + // ", font descent: %d, font height: %d\n", getCurrentY(), // (getTop() + getHeight()), getCanvas().getFontDescent(getFont()), // getCanvas().getFontHeight(getFont())); int fontDescent = getCanvas().getFontDescent(getFont()); int fontHeight = getCanvas().getFontHeight(getFont()); clipToCurrentBounds(); // We calulate an available height with a correction amount // of fontDescent to reserve enough scrolling space while (getCurrentY() > (getTop() + getHeight() - fontDescent)) { getCanvas().scrollUp(getBackgroundColor(), getFont(), getTop(), getHeight()); getCursor().setLine(getCursor().getLine() - 1); setCurrentY(getCurrentY() - fontHeight); } } }