/*
* $Id: SubWindow.java 535 2008-02-19 06:02:50Z weiju $
*
* Created on 2005/11/19
* 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;
import org.zmpp.vm.ScreenModel;
import org.zmpp.vm.TextCursor;
/**
* The class SubWindow manages a sub window within the screen model.
*
* @author Wei-ju Wu
* @version 1.0
*/
public abstract class SubWindow implements CursorWindow {
private Viewport viewport;
private TextCursor cursor;
private int top;
private int height;
private int foreground;
private int background;
private int fontnumber;
private Font font;
private boolean isReverseVideo;
private String name;
/**
* Constructor.
*
* @param parentComponent the parent component
* @param editor the line editor
* @param canvas the canvas
* @param name the window name
*/
public SubWindow(Viewport viewport, String name) {
this.viewport = viewport;
this.cursor = new TextCursorImpl(this);
this.name = name;
}
public int getFontNumber() {
return fontnumber;
}
public void setFontNumber(int fontnumber) {
this.fontnumber = fontnumber;
}
/**
* Sets the reverse video text mode.
*
* @param flag true or false to activate or deactivate reverse video
*/
public void setReverseVideo(boolean flag) {
isReverseVideo = flag;
}
/**
* Returns the reverse video status.
*
* @return true if reverse video, false otherwise
*/
public boolean isReverseVideo() {
return isReverseVideo;
}
/**
* Access to this window's cursor.
*
* @return the cursor
*/
public TextCursor getCursor() {
return cursor;
}
public void setCursorPosition(int line, int column) {
cursor.setPosition(line, column);
}
public int getHeight() {
return height;
}
public int getTop() {
return top;
}
public void setVerticalBounds(int top, int height) {
this.top = top;
this.height = height;
sizeUpdated();
}
public void resize(int numLines) {
height = getCanvas().getFontHeight(font) * numLines;
sizeUpdated();
}
/**
* Sets this window's current font.
*
* @param aFont the current font
*/
public void setFont(Font aFont) {
font = aFont;
}
/**
* Returns this window's current font.
*
* @return the current font
*/
public Font getFont() {
return font;
}
/**
* {@inheritDoc}
*/
public void clear() {
clipToCurrentBounds();
getCanvas().fillRect(getBackgroundColor(), 0, getTop(),
getCanvas().getWidth(), height);
resetCursorToHome();
}
public void eraseLine() {
Canvas canvas = getCanvas();
int currentX = getCurrentX();
clipToCurrentBounds();
canvas.fillRect(getBackgroundColor(), currentX,
getCurrentY() - canvas.getFontAscent(font),
canvas.getWidth() - currentX,
canvas.getFontHeight(font));
}
public void setBackground(int colornum) {
background = colornum;
}
protected Color getBackgroundColor() {
if (background == ColorTranslator.COLOR_UNDER_CURSOR) {
return getCanvas().getColorAtPixel(getCurrentX(), getCurrentY());
}
return ColorTranslator.getInstance().translate(background,
viewport.getDefaultBackground());
}
public void setForeground(int colornum) {
foreground = colornum;
}
protected Color getForegroundColor() {
if (foreground == ColorTranslator.COLOR_UNDER_CURSOR) {
return getCanvas().getColorAtPixel(getCurrentX(), getCurrentY());
}
return ColorTranslator.getInstance().translate(foreground,
viewport.getDefaultForeground());
}
/**
* This is the function that does the actual printing to the screen.
*
* @param str a string to pring
*/
protected void printString(String str) {
//System.out.printf("printString(), %s: '%s'\n", name, str);
Canvas canvas = getCanvas();
int width = canvas.getWidth();
int lineLength = width;
WordWrapper wordWrapper
= new WordWrapper(lineLength, canvas, font, isBuffered());
String[] lines = wordWrapper.wrap(getCurrentX(), str);
printLines(lines);
}
public String toString() {
return "[" + name + "]";
}
public void drawCursor(boolean flag) {
Canvas canvas = getCanvas();
int meanCharWidth = canvas.getCharWidth(font, '0');
clipToCurrentBounds();
canvas.fillRect(flag ? getForegroundColor() : getBackgroundColor(),
getCurrentX(), getCurrentY() - canvas.getFontAscent(font),
meanCharWidth, canvas.getFontHeight(font));
}
public void backspace(char c) {
Canvas canvas = getCanvas();
int charWidth = canvas.getCharWidth(font, c);
// Clears the text under the cursor
clipToCurrentBounds();
canvas.fillRect(getBackgroundColor(), getCurrentX() - charWidth,
getCurrentY() - canvas.getFontAscent(font), charWidth,
canvas.getFontHeight(font));
cursor.setColumn(cursor.getColumn() - 1);
}
/**
* Scrolls the window if necessary.
*/
abstract protected void scrollIfNeeded();
// **********************************************************************
// ***** Protected methods
// **************************************
protected void newline() {
//System.out.println("newline()");
cursor.setLine(cursor.getLine() + 1);
cursor.setColumn(1);
}
protected Canvas getCanvas() {
return viewport.getCanvas();
}
protected LineEditor getEditor() {
return viewport.getLineEditor();
}
protected ScreenModel getScreen() {
return (ScreenModel) viewport;
}
protected Viewport getViewport() {
return viewport;
}
protected Color getTextBackground() {
return isReverseVideo ? getForegroundColor() : getBackgroundColor();
}
protected Color getTextColor() {
return isReverseVideo ? getBackgroundColor() : getForegroundColor();
}
protected void printLine(String line, Color textbackColor,
Color textColor) {
clipToCurrentBounds();
Canvas canvas = getCanvas();
canvas.fillRect(textbackColor, getCurrentX(),
getCurrentY() - canvas.getFontHeight(font)
+ canvas.getFontDescent(font),
canvas.getStringWidth(font, line),
canvas.getFontHeight(font));
canvas.drawString(textColor, font, getCurrentX(), getCurrentY(), line);
cursor.setColumn(cursor.getColumn() + line.length());
}
public void flushBuffer() {
// default implementation is empty
}
// ************************************************************************
// ******* Abstract methods
// *************************************************
/**
* Sets the buffer mode.
*
* @param flag the buffer mode flag
*/
public abstract void setBufferMode(boolean flag);
/**
* Returns the buffer mode.
*
* @return the buffer mode
*/
public abstract boolean isBuffered();
/**
* Sets the paging flag. This feature must be available to be controlled
* from within the core (file input for replaying recorded sessions).
*
* @param flag true to enable paging, false otherwise
*/
public abstract void setPagingEnabled(boolean flag);
/**
* Returns the status of the paging flag.
*
* @return the paging status
*/
public abstract boolean isPagingEnabled();
/**
* Resets the cursor to its home position.
*/
public abstract void resetCursorToHome();
/**
* Resets the internal pager.
*/
public abstract void resetPager();
protected abstract void sizeUpdated();
protected abstract int getCurrentX();
protected abstract int getCurrentY();
// ************************************************************************
// ******* Private methods
// *************************************************
private void printLines(String lines[]) {
Color textColor = getTextColor();
Color textbackColor = getTextBackground();
// This is a feature that is not specified, but it is supported by
// DOS Frotz
if ((getFont().getStyle() & Font.BOLD) > 0 && !isReverseVideo) {
textColor = textColor.brighter();
}
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
printLine(line, textbackColor, textColor);
if (endsWithNewLine(line)) {
newline();
}
}
// Note: this is a patch for the issue that Fredrik revealed, the
// cursor being out of the visible area
scrollIfNeeded();
}
private static boolean endsWithNewLine(String str) {
return str.length() > 0 && str.charAt(str.length() - 1) == '\n';
}
protected void clipToCurrentBounds() {
Canvas canvas = getCanvas();
canvas.setClip(0, top, canvas.getWidth(), height);
}
}