599 lines
15 KiB
Java
599 lines
15 KiB
Java
/*
|
|
Copyright 2007 Infordata S.p.A.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
!!V 26/03/97 rel. 0.90 - start of revisions history.
|
|
26/03/97 rel. 0.90 - changed to speed up drawing.
|
|
10/04/97 rel. 0.93 - chars less than space are not drawed but are stored in ivCharBuffer.
|
|
28/04/97 rel. _.__ - ivCharBuffer, ivAttrBuffer array from [cols][rows] to [rows][cols].
|
|
14/05/97 rel. 1.00 - first release.
|
|
30/07/97 rel. 1.03b- bugs.
|
|
13/01/98 rel. 1.05d- NT painting bug.
|
|
14/01/98 rel. 1.06 - asynchronous paint on off-screen image.
|
|
03/03/98 rel. _.___- SWING and reorganization.
|
|
***
|
|
30/06/98 rel. _.___- Swing, JBuilder2 e VSS.
|
|
29/07/99 rel. 1.14 - Rework on 3d look&feel.
|
|
*/
|
|
|
|
|
|
package net.infordata.em.crt;
|
|
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Dimension;
|
|
import java.awt.FontMetrics;
|
|
import java.awt.Graphics;
|
|
import java.awt.Point;
|
|
import java.awt.Rectangle;
|
|
import java.io.IOException;
|
|
import java.io.ObjectInputStream;
|
|
import java.io.ObjectOutputStream;
|
|
import java.io.PrintStream;
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Implements an off-screen image buffer.
|
|
* To be used by XICrt.
|
|
*
|
|
* @see XICrt
|
|
*
|
|
* @author Valentino Proietti - Infordata S.p.A.
|
|
*/
|
|
public class XICrtBuffer implements Serializable {
|
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
private int ivNCols;
|
|
private int ivNRows;
|
|
|
|
transient private Graphics ivGr;
|
|
transient private int ivCharW;
|
|
transient private int ivCharH;
|
|
transient private int ivCharD;
|
|
transient private int ivGrW;
|
|
transient private int ivGrH;
|
|
|
|
private int ivDefAttr; // default char attribute
|
|
|
|
// [rows][cols]
|
|
private char[][] ivCharBuffer;
|
|
private int[][] ivAttrBuffer;
|
|
|
|
//!!1.06
|
|
transient private List<Rectangle> ivDirtyAreas = new ArrayList<Rectangle>(20);
|
|
|
|
//!!1.14
|
|
transient private XICrt ivCrt;
|
|
|
|
|
|
/**
|
|
* Creates a XICrtBuffer with the given dimensions expressed in number of
|
|
* chars.
|
|
*/
|
|
public XICrtBuffer(int nCols, int nRows) {
|
|
ivNCols = nCols;
|
|
ivNRows = nRows;
|
|
ivCharBuffer = new char[ivNRows][ivNCols];
|
|
ivAttrBuffer = new int[ivNRows][ivNCols];
|
|
|
|
clear();
|
|
}
|
|
|
|
|
|
/**
|
|
* Creates a XICrtBuffer filling it with a portion of another one.
|
|
*/
|
|
public XICrtBuffer(XICrtBuffer from, int aC, int aR, int aW, int aH) {
|
|
this(aW, aH);
|
|
copyFrom(0, 0, from, aC, aR, aW, aH);
|
|
setDefAttr(from.getDefAttr());
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a cloned XICrtBuffer (the new one needs initGraphics() to be
|
|
* displayed).
|
|
*/
|
|
@Override
|
|
public Object clone() {
|
|
XICrtBuffer aClone = new XICrtBuffer(this, 0, 0, ivNCols, ivNRows);
|
|
/* !!1.04
|
|
XICrtBuffer aClone = new XICrtBuffer(ivNCols, ivNRows);
|
|
aClone.copyFrom(this);
|
|
*/
|
|
return aClone;
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
final void setCrt(XICrt crt) {
|
|
ivCrt = crt;
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public final XICrt getCrt() {
|
|
return ivCrt;
|
|
}
|
|
|
|
|
|
/**
|
|
* Initializes the graphics area.
|
|
*/
|
|
public synchronized void setGraphics(Graphics gr) {
|
|
ivGr = gr;
|
|
if (ivGr != null) {
|
|
FontMetrics fontMetrics = ivGr.getFontMetrics();
|
|
ivCharW = fontMetrics.charWidth('W');
|
|
ivCharH = fontMetrics.getHeight();
|
|
ivCharD = fontMetrics.getDescent();
|
|
ivGrW = ivNCols * ivCharW;
|
|
ivGrH = ivNRows * ivCharH;
|
|
|
|
copyFrom(this); // refresh !!1.06 required
|
|
}
|
|
else {
|
|
//!!1.03b
|
|
ivCharW = 1; // to avoid possible division by 0 in pending events
|
|
ivCharH = 1;
|
|
ivCharD = 1;
|
|
ivGrW = ivNCols * ivCharW;
|
|
ivGrH = ivNRows * ivCharH;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Dumps the buffer on System.out stream.
|
|
* Useful for debugging.
|
|
*/
|
|
public void dumpBuffer(PrintStream out) {
|
|
out.println("BUFFER DUMP");
|
|
for (int r = 0; r < ivNRows; r++) {
|
|
for (int c = 0; c < ivNCols; c++)
|
|
out.print(ivCharBuffer[r][c]);
|
|
out.println();
|
|
}
|
|
for (int r = 0; r < ivNRows; r++) {
|
|
for (int c = 0; c < ivNCols; c++)
|
|
out.print(Integer.toHexString(ivAttrBuffer[r][c]) + " ");
|
|
out.println();
|
|
}
|
|
out.println("END BUFFER DUMP");
|
|
}
|
|
|
|
|
|
/**
|
|
* Copy contents from another XICrtBuffer (can be itself).
|
|
*/
|
|
public void copyFrom(XICrtBuffer from) {
|
|
copyFrom(0, 0, from, 0, 0, from.ivNCols, from.ivNRows);
|
|
}
|
|
|
|
|
|
/**
|
|
* Copy contents from another XICrtBuffer (can be itself).
|
|
* @param col the destination column pos.
|
|
* @param row the destination row pos.
|
|
* @param from the source XICrtBuffer.
|
|
* @param aC the source column pos.
|
|
* @param aR the source row pos.
|
|
* @param aW the source dimension.
|
|
* @param aH the source dimension.
|
|
*/
|
|
public synchronized void copyFrom(int col, int row,
|
|
XICrtBuffer from,
|
|
int aC, int aR, int aW, int aH) {
|
|
aW = Math.min(aW, from.ivNCols - aC);
|
|
aH = Math.min(aH, from.ivNRows - aR);
|
|
int nCols = Math.min(ivNCols - col, aW);
|
|
int nRows = Math.min(ivNRows - row, aH);
|
|
int lastAttr;
|
|
int lastCol;
|
|
int lastRow;
|
|
StringBuilder str;
|
|
|
|
for (int r = 0; r < nRows; r++) {
|
|
for (int c = 0; c < nCols; ) {
|
|
lastCol = col + c;
|
|
lastRow = row + r;
|
|
lastAttr = from.getAttrInternal(aC + c, aR + r);
|
|
str = new StringBuilder();
|
|
|
|
// group chars with the same attribute
|
|
for ( ; c < nCols && lastAttr == from.getAttrInternal(aC + c, aR + r); c++)
|
|
str.append(from.getChar(aC + c, aR + r));
|
|
|
|
drawString(new String(str), lastCol, lastRow, lastAttr);
|
|
}
|
|
}
|
|
}
|
|
|
|
public synchronized void invalidateAll() {
|
|
addDirtyArea(new Rectangle(0, 0, ivNCols, ivNRows));
|
|
}
|
|
|
|
/**
|
|
* Clears the screen buffer.
|
|
*/
|
|
public synchronized void clear() {
|
|
for (int c = 0; c < ivNCols; c++)
|
|
for (int r = 0; r < ivNRows; r++) {
|
|
ivCharBuffer[r][c] = '\u0000';
|
|
ivAttrBuffer[r][c] = ivDefAttr;
|
|
}
|
|
|
|
ivDirtyAreas.clear();
|
|
|
|
if (ivGr != null) {
|
|
Graphics gr = ivGr.create(); //!!1.05d
|
|
try {
|
|
gr.setColor(getBackground(ivDefAttr));
|
|
gr.fillRect(0, 0, ivGrW, ivGrH);
|
|
}
|
|
finally {
|
|
gr.dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public synchronized void scrollDown(int r1, int r2, int nRows) {
|
|
if ((r1 >= r2) || (nRows == 0))
|
|
throw new IllegalArgumentException("ScrollDown()");
|
|
|
|
sync();
|
|
|
|
nRows = Math.max(nRows, r2 - r1);
|
|
|
|
for (int r = r2; r > (r1 + nRows); r--)
|
|
for (int c = 0; c < ivNCols; c++) {
|
|
ivCharBuffer[r][c] = ivCharBuffer[r - nRows][c];
|
|
ivAttrBuffer[r][c] = ivAttrBuffer[r - nRows][c];
|
|
}
|
|
|
|
for (int r = r1; r <= (r1 + nRows); r++)
|
|
for (int c = 0; c < ivNCols; c++) {
|
|
ivCharBuffer[r][c] = '\u0000';
|
|
ivAttrBuffer[r][c] = ivDefAttr;
|
|
}
|
|
|
|
if (ivGr != null) {
|
|
Graphics gr = ivGr.create(); //!!1.05d
|
|
try {
|
|
gr.copyArea(0, r1 * ivCharH, ivNCols * ivCharW, (r2 - r1) * ivCharH,
|
|
0, ivCharH * nRows);
|
|
gr.setColor(getBackground(ivDefAttr));
|
|
gr.fillRect(0, r1 * ivCharH, ivNCols * ivCharW, ivCharH * nRows);
|
|
}
|
|
finally {
|
|
gr.dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public synchronized void scrollUp(int r1, int r2, int nRows) {
|
|
if ((r1 >= r2) || (nRows == 0))
|
|
throw new IllegalArgumentException("ScrollUp()");
|
|
|
|
sync();
|
|
|
|
nRows = Math.max(nRows, r2 - r1);
|
|
|
|
for (int r = r1; r < (r2 - nRows); r++)
|
|
for (int c = 0; c < ivNCols; c++) {
|
|
ivCharBuffer[r][c] = ivCharBuffer[r + nRows][c];
|
|
ivAttrBuffer[r][c] = ivAttrBuffer[r + nRows][c];
|
|
}
|
|
|
|
for (int r = r2; r >= (r2 - nRows); r--)
|
|
for (int c = 0; c < ivNCols; c++) {
|
|
ivCharBuffer[r][c] = '\u0000';
|
|
ivAttrBuffer[r][c] = ivDefAttr;
|
|
}
|
|
|
|
if (ivGr != null) {
|
|
Graphics gr = ivGr.create(); //!!1.05d
|
|
try {
|
|
gr.copyArea(0, (r1 + 1) * ivCharH, ivNCols * ivCharW, (r2 - r1) * ivCharH,
|
|
0, -ivCharH * nRows);
|
|
gr.setColor(getBackground(ivDefAttr));
|
|
gr.fillRect(0, (r2 - nRows + 1) * ivCharH, ivNCols * ivCharW, ivCharH * nRows);
|
|
}
|
|
finally {
|
|
gr.dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the dimensions in chars.
|
|
*/
|
|
public Dimension getCrtSize() {
|
|
return new Dimension(ivNCols, ivNRows);
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the dimensions in pixels.
|
|
*/
|
|
public Dimension getSize() {
|
|
return new Dimension(ivGrW, ivGrH);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public Dimension getCharSize() {
|
|
return new Dimension(ivCharW, ivCharH);
|
|
}
|
|
|
|
|
|
/**
|
|
* Converts characters coordinates in pixels coordinates.
|
|
*/
|
|
public Point toPoint(int col, int row) {
|
|
return new Point(col * ivCharW, (row + 1) * ivCharH);
|
|
}
|
|
|
|
|
|
/**
|
|
* Uses the default attribute.
|
|
*/
|
|
public void drawString(String str, int col, int row) {
|
|
drawString(str, col, row, ivDefAttr);
|
|
}
|
|
|
|
|
|
/**
|
|
* Uses the given attribute.
|
|
*/
|
|
public synchronized void drawString(String aStr, int col, int row,
|
|
int aAttr) {
|
|
col = Math.max(0, Math.min(ivNCols - 1, col));
|
|
row = Math.max(0, Math.min(ivNRows - 1, row));
|
|
int len = Math.min(aStr.length(), ivNCols - col);
|
|
|
|
if (len <= 0)
|
|
return;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
ivCharBuffer[row][col + i] = aStr.charAt(i);
|
|
ivAttrBuffer[row][col + i] = aAttr;
|
|
}
|
|
|
|
addDirtyArea(new Rectangle(col, row, len, 1));
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
private void addDirtyArea(Rectangle newRt) {
|
|
Rectangle rt;
|
|
Rectangle rtG;
|
|
Rectangle res = new Rectangle(newRt); //!!V 03/03/98
|
|
int count = 0;
|
|
for (Iterator<Rectangle> e = ivDirtyAreas.iterator(); e.hasNext(); ) {
|
|
rt = (Rectangle)e.next();
|
|
// used to see if rectangles are adiacent (x coord)
|
|
rtG = new Rectangle(rt);
|
|
rtG.grow(1, 0);
|
|
if (rtG.intersects(newRt)) {
|
|
e.remove();
|
|
res = res.union(rt);
|
|
// no more than two rects can be joined (x coord)
|
|
if (++count >= 2)
|
|
break;
|
|
}
|
|
}
|
|
ivDirtyAreas.add(res);
|
|
}
|
|
|
|
|
|
/**
|
|
* To be called just before painting the offscreen image.
|
|
*/
|
|
public synchronized void sync() {
|
|
if (ivGr == null || ivDirtyAreas.isEmpty())
|
|
return;
|
|
|
|
Graphics gr = ivGr.create(); //!!1.05d
|
|
try {
|
|
Rectangle rt;
|
|
for (Iterator<Rectangle> e = ivDirtyAreas.iterator(); e.hasNext(); ) {
|
|
rt = (Rectangle)e.next();
|
|
|
|
int lastAttr;
|
|
int lastCol;
|
|
int lastRow;
|
|
StringBuilder str;
|
|
|
|
for (int r = 0; r < rt.height; r++) {
|
|
for (int c = 0; c < rt.width; ) {
|
|
lastCol = rt.x + c;
|
|
lastRow = rt.y + r;
|
|
lastAttr = getAttr(rt.x + c, rt.y + r);
|
|
str = new StringBuilder();
|
|
|
|
// group char with the same attribute to speed up drawing
|
|
for ( ; c < rt.width && lastAttr == getAttr(rt.x + c, rt.y + r); c++)
|
|
str.append(getChar(rt.x + c, rt.y + r));
|
|
|
|
_drawString(gr, new String(str), lastCol, lastRow, lastAttr);
|
|
}
|
|
}
|
|
|
|
if (XICrt.DEBUG >= 2) {
|
|
gr.setColor(Color.yellow);
|
|
gr.drawRect(rt.x * ivCharW + 1, rt.y * ivCharH + 1,
|
|
rt.width * ivCharW - 3, rt.height * ivCharH - 3);
|
|
}
|
|
}
|
|
|
|
ivDirtyAreas.clear();
|
|
}
|
|
finally {
|
|
gr.dispose();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Draws the given string on the graphics context (called by sync()).
|
|
*/
|
|
protected void _drawString(Graphics gr, String aStr, int col, int row,
|
|
int aAttr) { //!!1.06
|
|
int len = aStr.length();
|
|
|
|
gr.setColor(getBackground(aAttr));
|
|
gr.fillRect(col * ivCharW, row * ivCharH, ivCharW * len, ivCharH);
|
|
|
|
// do not draw char less than space
|
|
StringBuilder strBuf = new StringBuilder(aStr);
|
|
for (int i = 0; i < strBuf.length(); i++) {
|
|
if (strBuf.charAt(i) < ' ')
|
|
strBuf.setCharAt(i, ' ');
|
|
}
|
|
String str = new String(strBuf);
|
|
|
|
gr.setColor(getForeground(aAttr));
|
|
gr.drawString(str.substring(0, len), col * ivCharW,
|
|
(row + 1) * ivCharH - ivCharD);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public String getString(int col, int row, int nChars) {
|
|
StringBuilder str = new StringBuilder();
|
|
for (int i = 0; i < nChars; i++) {
|
|
str.append(getChar(col + i, row));
|
|
}
|
|
return new String(str);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public String getString() {
|
|
char[] buf = new char[ivNRows * ivNCols];
|
|
|
|
for (int i = 0; i < ivNRows; i++)
|
|
System.arraycopy(ivCharBuffer[i], 0, buf, i * ivNCols, ivNCols);
|
|
|
|
return new String(buf);
|
|
}
|
|
|
|
|
|
/**
|
|
* Background attribute to color mapping.
|
|
*/
|
|
protected Color getBackground(int aAttribute){
|
|
return Color.red;
|
|
}
|
|
|
|
|
|
/**
|
|
* Foreground attribute to color mapping.
|
|
*/
|
|
protected Color getForeground(int aAttribute) {
|
|
return Color.blue;
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public final int getAttrInternal(int col, int row) {
|
|
col = Math.max(0, Math.min(ivNCols - 1, col));
|
|
row = Math.max(0, Math.min(ivNRows - 1, row));
|
|
|
|
return ivAttrBuffer[row][col];
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public int getAttr(int col, int row) {
|
|
return getAttrInternal(col, row);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public final char getChar(int col, int row) {
|
|
col = Math.max(0, Math.min(ivNCols - 1, col));
|
|
row = Math.max(0, Math.min(ivNRows - 1, row));
|
|
|
|
return ivCharBuffer[row][col];
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the default attribute.
|
|
*/
|
|
public void setDefAttr(int aAttr) {
|
|
ivDefAttr = aAttr;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the default attribute.
|
|
*/
|
|
public final int getDefAttr() {
|
|
return ivDefAttr;
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public Point toPoints(int aCol, int aRow) {
|
|
return new Point(aCol * ivCharW, aRow * ivCharH);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
public Rectangle toPoints(int aCol, int aRow, int aNCols, int aNRows) {
|
|
return new Rectangle(aCol * ivCharW, aRow * ivCharH,
|
|
aNCols * ivCharW, aNRows * ivCharH);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
void writeObject(ObjectOutputStream oos) throws IOException {
|
|
oos.defaultWriteObject();
|
|
}
|
|
|
|
void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
|
ois.defaultReadObject();
|
|
}
|
|
}
|