2018-02-28 10:22:33 +01:00
|
|
|
package inf101.v18.gfx.textmode;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.function.BiFunction;
|
|
|
|
|
|
|
|
import inf101.v18.gfx.IPaintLayer;
|
|
|
|
import inf101.v18.gfx.Screen;
|
|
|
|
import javafx.scene.canvas.Canvas;
|
|
|
|
import javafx.scene.canvas.GraphicsContext;
|
|
|
|
import javafx.scene.effect.BlendMode;
|
|
|
|
import javafx.scene.paint.Color;
|
|
|
|
import javafx.scene.paint.Paint;
|
|
|
|
|
|
|
|
public class Printer implements IPaintLayer {
|
|
|
|
private static class Char {
|
|
|
|
public int mode;
|
|
|
|
public String s;
|
|
|
|
public Color fill;
|
|
|
|
public Color stroke;
|
|
|
|
public Paint bg;
|
|
|
|
|
|
|
|
public Char(String s, Color fill, Color stroke, Paint bg, int mode) {
|
|
|
|
this.s = s;
|
|
|
|
this.fill = fill;
|
|
|
|
this.stroke = stroke;
|
|
|
|
this.bg = bg;
|
|
|
|
this.mode = mode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static final TextFont FONT_MONOSPACED = new TextFont("Monospaced", 27.00, TextMode.CHAR_BOX_SIZE, 3.4000,
|
|
|
|
-6.7000, 1.5000, 1.0000, true);
|
|
|
|
public static final TextFont FONT_LMMONO = new TextFont("lmmono10-regular.otf", 30.00, TextMode.CHAR_BOX_SIZE,
|
|
|
|
4.0000, -8.5000, 1.5000, 1.0000, true);
|
|
|
|
public static final TextFont FONT_ZXSPECTRUM7 = new TextFont("ZXSpectrum-7.otf", 22.00, TextMode.CHAR_BOX_SIZE,
|
|
|
|
3.1000, -3.8000, 1.0000, 1.0000, true);
|
2018-02-28 23:51:40 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* TTF file can be found here: http://users.teilar.gr/~g1951d/ in this ZIP file:
|
|
|
|
* http://users.teilar.gr/~g1951d/Symbola.zip
|
|
|
|
* <p>
|
|
|
|
* (Put the extracted Symbola.ttf in src/inf101/v18/gfx/fonts/)
|
|
|
|
*/
|
|
|
|
public static final TextFont FONT_SYMBOLA = new TextFont("Symbola.ttf", 26.70, TextMode.CHAR_BOX_SIZE, -0.4000,
|
|
|
|
-7.6000, 1.35000, 1.0000, true);
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
/**
|
|
|
|
* TTF file can be found here:
|
|
|
|
* http://www.kreativekorp.com/software/fonts/c64.shtml
|
|
|
|
*/
|
|
|
|
public static final TextFont FONT_GIANA = new TextFont("Giana.ttf", 25.00, TextMode.CHAR_BOX_SIZE, 4.6000, -5.0000,
|
|
|
|
1.0000, 1.0000, true);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TTF file can be found here:
|
|
|
|
* http://www.kreativekorp.com/software/fonts/c64.shtml
|
|
|
|
*/
|
|
|
|
public static final TextFont FONT_C64 = new TextFont("PetMe64.ttf", 31.50, TextMode.CHAR_BOX_SIZE, 0.0000, -4.000,
|
|
|
|
1.0000, 1.0000, true);
|
|
|
|
private static final Paint DEFAULT_BACKGROUND = Color.TRANSPARENT;
|
|
|
|
private static final TextMode DEFAULT_MODE = TextMode.MODE_40X22;
|
|
|
|
|
|
|
|
public static String center(String s, int width) {
|
|
|
|
for (; s.length() < width; s = " " + s + " ")
|
|
|
|
;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String repeat(String s, int width) {
|
|
|
|
String r = s;
|
|
|
|
for (; r.length() < width; r += s)
|
|
|
|
;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
Color DEFAULT_FILL = Color.BLACK;
|
|
|
|
|
|
|
|
Color DEFAULT_STROKE = Color.TRANSPARENT;
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
private TextMode textMode;
|
|
|
|
private Color fill;
|
|
|
|
private Color stroke;
|
|
|
|
private Paint background;
|
|
|
|
private Screen screen;
|
|
|
|
private List<Char[]> lineBuffer = new ArrayList<>();
|
|
|
|
private boolean autoscroll = true;
|
|
|
|
private final Canvas textPage;
|
|
|
|
private int x = 1, y = 1, savedX = 1, savedY = 1;
|
|
|
|
// private int pageWidth = LINE_WIDTHS[resMode], pageHeight =
|
|
|
|
// PAGE_HEIGHTS[resMode];
|
|
|
|
private int leftMargin = 1, topMargin = 1;
|
|
|
|
private TextFont font = FONT_LMMONO;
|
|
|
|
private int videoAttrs = 0;
|
|
|
|
|
|
|
|
private String csiSeq = null;
|
|
|
|
|
|
|
|
private boolean csiEnabled = true;
|
|
|
|
|
|
|
|
private int csiMode = 0;
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
public Printer(double width, double height) {
|
|
|
|
this(null, new Canvas(width, height));
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
public Printer(Screen screen, Canvas page) {
|
|
|
|
this.screen = screen;
|
|
|
|
this.textPage = page;
|
|
|
|
for (int i = 0; i < TextMode.PAGE_HEIGHT_MAX; i++) {
|
|
|
|
lineBuffer.add(new Char[TextMode.LINE_WIDTH_MAX]);
|
|
|
|
}
|
|
|
|
resetFull();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addToCharBuffer(String string) {
|
|
|
|
string.codePoints().mapToObj((int i) -> String.valueOf(Character.toChars(i))).forEach((String s) -> {
|
|
|
|
if (csiMode != 0) {
|
|
|
|
s = addToCsiBuffer(s);
|
|
|
|
}
|
|
|
|
switch (s) {
|
|
|
|
case "\r":
|
|
|
|
moveTo(leftMargin, y);
|
|
|
|
break;
|
|
|
|
case "\n":
|
|
|
|
moveTo(leftMargin, y + 1);
|
|
|
|
break;
|
|
|
|
case "\f":
|
|
|
|
GraphicsContext context = textPage.getGraphicsContext2D();
|
|
|
|
moveTo(leftMargin, topMargin);
|
|
|
|
for (Char[] line : lineBuffer)
|
|
|
|
Arrays.fill(line, null);
|
|
|
|
if (background != null && background != Color.TRANSPARENT) {
|
|
|
|
context.setFill(background);
|
|
|
|
context.fillRect(0.0, 0.0, textPage.getWidth(), textPage.getHeight());
|
|
|
|
} else
|
|
|
|
context.clearRect(0.0, 0.0, textPage.getWidth(), textPage.getHeight());
|
|
|
|
break;
|
|
|
|
case "\b":
|
|
|
|
moveHoriz(-1);
|
|
|
|
break;
|
|
|
|
case "\t":
|
|
|
|
moveTo((x + 8) % 8, y);
|
|
|
|
break;
|
|
|
|
case "\u001b":
|
|
|
|
if (csiEnabled) {
|
|
|
|
csiSeq = s;
|
|
|
|
csiMode = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (s.length() > 0 && s.codePointAt(0) >= 0x20) {
|
|
|
|
drawChar(x, y, setChar(x, y, s));
|
|
|
|
moveHoriz(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private String addToCsiBuffer(String s) {
|
|
|
|
if (csiMode == 1) {
|
|
|
|
switch (s) {
|
|
|
|
case "[":
|
|
|
|
csiMode = 2;
|
|
|
|
csiSeq += s;
|
|
|
|
break;
|
|
|
|
case "c":
|
|
|
|
csiMode = 0;
|
|
|
|
resetFull();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
csiReset();
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
} else if (csiMode == 2) {
|
|
|
|
int c = s.codePointAt(0);
|
|
|
|
if (c >= 0x30 && c <= 0x3f) {
|
|
|
|
csiSeq += s;
|
|
|
|
} else if (c >= 0x20 && c <= 0x2f) {
|
|
|
|
csiMode = 3;
|
|
|
|
csiSeq += s;
|
|
|
|
} else if (c >= 0x40 && c <= 0x7e) {
|
|
|
|
csiSeq += s;
|
|
|
|
csiFinish();
|
|
|
|
} else {
|
|
|
|
csiReset();
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (csiMode == 3) {
|
|
|
|
int c = s.codePointAt(0);
|
|
|
|
if (c >= 0x20 && c <= 0x2f) {
|
|
|
|
csiSeq += s;
|
|
|
|
} else if (c >= 0x40 && c <= 0x7e) {
|
|
|
|
csiSeq += s;
|
|
|
|
csiFinish();
|
|
|
|
} else {
|
|
|
|
csiReset();
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
public void beginningOfLine() {
|
|
|
|
x = leftMargin;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void beginningOfPage() {
|
|
|
|
x = leftMargin;
|
|
|
|
y = topMargin;
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
@Override
|
2018-02-28 10:22:33 +01:00
|
|
|
public void clear() {
|
|
|
|
print("\f");
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearAt(int x, int y) {
|
|
|
|
printAt(x, y, " ");
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
public void clearLine(int y) {
|
|
|
|
y = constrainY(y);
|
|
|
|
if (y > 0 && y <= TextMode.PAGE_HEIGHT_MAX) {
|
|
|
|
Arrays.fill(lineBuffer.get(y - 1), null);
|
|
|
|
redrawTextPage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearRegion(int x, int y, int width, int height) {
|
|
|
|
if (x > getLineWidth() || y > getPageHeight())
|
|
|
|
return;
|
|
|
|
int x2 = Math.min(x + width - 1, getLineWidth());
|
|
|
|
int y2 = Math.min(y + height - 1, getPageHeight());
|
|
|
|
if (x2 < 1 || y2 < 1)
|
|
|
|
return;
|
|
|
|
int x1 = Math.max(1, x);
|
|
|
|
int y1 = Math.max(1, y);
|
|
|
|
// Char fillWith = new Char("*", Color.BLACK, Color.GREEN, Color.TRANSPARENT,
|
|
|
|
// 0);
|
|
|
|
for (int i = y1; i <= y2; i++) {
|
|
|
|
Arrays.fill(lineBuffer.get(i - 1), x1 - 1, x2, null);
|
|
|
|
}
|
|
|
|
redrawTextPage();
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
private int constrainX(int x) {
|
|
|
|
return x; // Math.min(LINE_WIDTH_HIRES, Math.max(1, x));
|
|
|
|
}
|
|
|
|
|
|
|
|
public int constrainY(int y) {
|
|
|
|
return y; // Math.min(pageHeight, Math.max(1, y));
|
|
|
|
}
|
|
|
|
|
|
|
|
public int constrainYOrScroll(int y) {
|
|
|
|
if (autoscroll) {
|
|
|
|
if (y < 1) {
|
|
|
|
scroll(y - 1);
|
|
|
|
return 1;
|
|
|
|
} else if (y > getPageHeight()) {
|
|
|
|
scroll(y - getPageHeight());
|
|
|
|
return getPageHeight();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return y;// Math.min(pageHeight, Math.max(1, y));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void csiFinish() {
|
|
|
|
ControlSequences.applyCsi(this, csiSeq);
|
|
|
|
csiReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void csiReset() {
|
|
|
|
csiMode = 0;
|
|
|
|
csiSeq = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void cycleMode(boolean adjustDisplayAspect) {
|
|
|
|
textMode = textMode.nextMode();
|
2018-02-28 23:51:40 +01:00
|
|
|
if (adjustDisplayAspect && screen != null)
|
2018-02-28 10:22:33 +01:00
|
|
|
screen.setAspect(textMode.getAspect());
|
|
|
|
redrawTextPage();
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
private void drawChar(int x, int y, Char c) {
|
|
|
|
if (c != null) {
|
|
|
|
GraphicsContext context = textPage.getGraphicsContext2D();
|
|
|
|
|
|
|
|
context.setFill(c.fill);
|
|
|
|
context.setStroke(c.stroke);
|
|
|
|
font.drawTextAt(context, (x - 1) * getCharWidth(), y * getCharHeight(), c.s,
|
|
|
|
textMode.getCharWidth() / textMode.getCharBoxSize(), c.mode, c.bg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
public void drawCharCells() {
|
2018-02-28 23:51:40 +01:00
|
|
|
if (screen != null) {
|
|
|
|
GraphicsContext context = screen.getBackgroundContext();
|
|
|
|
screen.clearBackground();
|
|
|
|
double w = getCharWidth();
|
|
|
|
double h = getCharHeight();
|
|
|
|
context.save();
|
|
|
|
context.setGlobalBlendMode(BlendMode.EXCLUSION);
|
|
|
|
context.setFill(Color.WHITE.deriveColor(0.0, 1.0, 1.0, 0.1));
|
|
|
|
for (int x = 0; x < getLineWidth(); x++) {
|
|
|
|
for (int y = 0; y < getPageHeight(); y++) {
|
|
|
|
if ((x + y) % 2 == 0)
|
|
|
|
context.fillRect(x * w, y * h, w, h);
|
|
|
|
}
|
2018-02-28 10:22:33 +01:00
|
|
|
}
|
2018-02-28 23:51:40 +01:00
|
|
|
context.restore();
|
2018-02-28 10:22:33 +01:00
|
|
|
}
|
2018-02-28 23:51:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public Color getBackground(int x, int y) {
|
|
|
|
Char c = null;
|
|
|
|
if (x > 0 && x <= TextMode.LINE_WIDTH_MAX && y > 0 && y <= TextMode.PAGE_HEIGHT_MAX) {
|
|
|
|
c = lineBuffer.get(y - 1)[x - 1];
|
|
|
|
}
|
|
|
|
Color bg = Color.TRANSPARENT;
|
|
|
|
if (c != null && c.bg instanceof Color)
|
|
|
|
bg = (Color) c.bg;
|
|
|
|
else if (background instanceof Color)
|
|
|
|
bg = (Color) background;
|
|
|
|
return bg;
|
2018-02-28 10:22:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getBold() {
|
|
|
|
return (videoAttrs & TextFont.ATTR_BRIGHT) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getChar(int x, int y) {
|
|
|
|
Char c = null;
|
|
|
|
if (x > 0 && x <= TextMode.LINE_WIDTH_MAX && y > 0 && y <= TextMode.PAGE_HEIGHT_MAX) {
|
|
|
|
c = lineBuffer.get(y - 1)[x - 1];
|
|
|
|
}
|
|
|
|
if (c != null)
|
|
|
|
return c.s;
|
|
|
|
else
|
|
|
|
return " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
public double getCharHeight() {
|
|
|
|
return textMode.getCharHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
public double getCharWidth() {
|
|
|
|
return textMode.getCharWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Color getColor(int x, int y) {
|
|
|
|
Char c = null;
|
|
|
|
if (x > 0 && x <= TextMode.LINE_WIDTH_MAX && y > 0 && y <= TextMode.PAGE_HEIGHT_MAX) {
|
|
|
|
c = lineBuffer.get(y - 1)[x - 1];
|
|
|
|
}
|
|
|
|
if (c != null)
|
|
|
|
return c.fill;
|
|
|
|
else
|
|
|
|
return fill;
|
|
|
|
}
|
|
|
|
|
|
|
|
public TextFont getFont() {
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getItalics() {
|
|
|
|
return (videoAttrs & TextFont.ATTR_ITALIC) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the leftMargin
|
|
|
|
*/
|
|
|
|
public int getLeftMargin() {
|
|
|
|
return leftMargin;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getLineWidth() {
|
|
|
|
return textMode.getLineWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getPageHeight() {
|
|
|
|
return textMode.getPageHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getReverseVideo() {
|
|
|
|
return (videoAttrs & TextFont.ATTR_INVERSE) != 0;
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
public TextMode getTextMode() {
|
|
|
|
return textMode;
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
/**
|
|
|
|
* @return the topMargin
|
|
|
|
*/
|
|
|
|
public int getTopMargin() {
|
|
|
|
return topMargin;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getVideoMode() {
|
|
|
|
return videoAttrs;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getX() {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getY() {
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isFilled(int x, int y) {
|
|
|
|
return !getChar(x, y).equals(" ");
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
@Override
|
|
|
|
public void layerToBack() {
|
|
|
|
if (screen != null) {
|
|
|
|
screen.moveToBack(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void layerToFront() {
|
|
|
|
if (screen != null) {
|
|
|
|
screen.moveToFront(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
public void move(int deltaX, int deltaY) {
|
|
|
|
x = constrainX(x + deltaX);
|
|
|
|
y = constrainYOrScroll(y + deltaY);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void moveHoriz(int dist) {
|
|
|
|
x = constrainX(x + dist);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void moveTo(int newX, int newY) {
|
|
|
|
x = constrainX(newX);
|
|
|
|
y = constrainYOrScroll(newY);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void moveVert(int dist) {
|
|
|
|
y = constrainYOrScroll(y + dist);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void plot(int x, int y) {
|
|
|
|
plot(x, y, (a, b) -> a | b);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void plot(int x, int y, BiFunction<Integer, Integer, Integer> op) {
|
|
|
|
int textX = (x) / 2 + 1;
|
|
|
|
int textY = (y) / 2 + 1;
|
|
|
|
int bitPos = (x + 1) % 2 + ((y + 1) % 2) * 2;
|
|
|
|
String blockChar = BlocksAndBoxes.unicodeBlocks[1 << bitPos];
|
|
|
|
// System.out.println(blockChar + ", " + bitPos + ", ("+ (x) + ", " + (y) + ")"+
|
|
|
|
// ", (" + (textX) + ", " + (textY) + ")");
|
|
|
|
String s = BlocksAndBoxes.blockComposeOrOverwrite(getChar(textX, textY), blockChar, op);
|
|
|
|
// System.out.println("Merge '" + getChar(textX, textY) + "' + '" + blockChar +
|
|
|
|
// "' = '" + s + "'");
|
|
|
|
printAt(textX, textY, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void print(String s) {
|
|
|
|
addToCharBuffer(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void print(String s, Color paint) {
|
|
|
|
Color tmp = fill;
|
|
|
|
fill = paint;
|
|
|
|
addToCharBuffer(s);
|
|
|
|
fill = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void printAt(int atX, int atY, String s) {
|
|
|
|
moveTo(atX, atY);
|
|
|
|
print(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void printAt(int atX, int atY, String s, Color ink) {
|
|
|
|
moveTo(atX, atY);
|
|
|
|
print(s, ink);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void println() {
|
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
public void println(String s) {
|
|
|
|
print(s);
|
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
public void redrawTextPage() {
|
|
|
|
/*
|
|
|
|
* System.out.printf("redrawTextPage benchmark");
|
|
|
|
* System.out.printf(" %5s %5s %7s %4s %5s %5s %5s%n", "ms", "chars",
|
|
|
|
* "ms/char", "mode", "indir", "inv", "fake"); for (int m = -1; m < 8; m++) {
|
|
|
|
* long t0 = System.currentTimeMillis(); int n = 0;
|
|
|
|
*/
|
|
|
|
GraphicsContext context = textPage.getGraphicsContext2D();
|
|
|
|
|
|
|
|
if (background != null && background != Color.TRANSPARENT) {
|
|
|
|
context.setFill(background);
|
|
|
|
context.fillRect(0.0, 0.0, textPage.getWidth(), textPage.getHeight());
|
|
|
|
} else
|
|
|
|
context.clearRect(0.0, 0.0, textPage.getWidth(), textPage.getHeight());
|
|
|
|
for (int tmpY = 1; tmpY <= getPageHeight(); tmpY++) {
|
|
|
|
Char[] line = lineBuffer.get(tmpY - 1);
|
|
|
|
for (int tmpX = 1; tmpX <= getLineWidth(); tmpX++) {
|
|
|
|
Char c = line[tmpX - 1];
|
|
|
|
if (c != null) {
|
|
|
|
context.save();
|
|
|
|
context.setFill(c.fill);
|
|
|
|
context.setStroke(c.stroke);
|
|
|
|
font.drawTextAt(context, (tmpX - 1) * getCharWidth(), tmpY * getCharHeight(), c.s,
|
|
|
|
textMode.getCharWidth() / textMode.getCharBoxSize(), c.mode/* m */, c.bg);
|
|
|
|
context.restore();
|
|
|
|
// n++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* long t = System.currentTimeMillis() - t0; if (m >= 0)
|
|
|
|
* System.out.printf(" %5d %5d %7.4f %4d %5b %5b %5b%n", t, n, ((double) t) /
|
|
|
|
* n, m, (m & 3) != 0, (m & 1) != 0, (m & 4) != 0); } System.out.println();
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
public void resetAttrs() {
|
|
|
|
this.fill = DEFAULT_FILL;
|
|
|
|
this.stroke = DEFAULT_STROKE;
|
|
|
|
this.background = DEFAULT_BACKGROUND;
|
|
|
|
this.videoAttrs = 0;
|
|
|
|
this.csiSeq = null;
|
|
|
|
this.csiMode = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void resetFull() {
|
|
|
|
resetAttrs();
|
|
|
|
beginningOfPage();
|
|
|
|
this.autoscroll = true;
|
|
|
|
this.textMode = DEFAULT_MODE;
|
|
|
|
redrawTextPage();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void restoreCursor() {
|
|
|
|
x = savedX;
|
|
|
|
y = savedY;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void saveCursor() {
|
|
|
|
savedX = x;
|
|
|
|
savedY = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
void scroll(int i) {
|
|
|
|
while (i < 0) {
|
|
|
|
scrollDown();
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
while (i > 0) {
|
|
|
|
scrollUp();
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void scrollDown() {
|
|
|
|
Char[] remove = lineBuffer.remove(lineBuffer.size() - 1);
|
|
|
|
Arrays.fill(remove, null);
|
|
|
|
lineBuffer.add(0, remove);
|
|
|
|
redrawTextPage();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void scrollUp() {
|
|
|
|
Char[] remove = lineBuffer.remove(0);
|
|
|
|
Arrays.fill(remove, null);
|
|
|
|
lineBuffer.add(remove);
|
|
|
|
redrawTextPage();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean setAutoScroll(boolean autoScroll) {
|
|
|
|
boolean old = autoscroll;
|
|
|
|
autoscroll = autoScroll;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
public void setBackground(int x, int y, Paint bg) {
|
|
|
|
Char c = null;
|
|
|
|
if (x > 0 && x <= TextMode.LINE_WIDTH_MAX && y > 0 && y <= TextMode.PAGE_HEIGHT_MAX) {
|
|
|
|
c = lineBuffer.get(y - 1)[x - 1];
|
|
|
|
}
|
|
|
|
if (c != null) {
|
|
|
|
c.bg = bg;
|
|
|
|
drawChar(x, y, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
public void setBackground(Paint bgColor) {
|
|
|
|
this.background = bgColor != null ? bgColor : DEFAULT_BACKGROUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setBold(boolean enabled) {
|
|
|
|
if (enabled)
|
|
|
|
videoAttrs |= TextFont.ATTR_BRIGHT;
|
|
|
|
else
|
|
|
|
videoAttrs &= ~TextFont.ATTR_BRIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Char setChar(int x, int y, String s) {
|
|
|
|
if (x > 0 && x <= TextMode.LINE_WIDTH_MAX && y > 0 && y <= TextMode.PAGE_HEIGHT_MAX) {
|
|
|
|
Char c = new Char(s, fill, stroke, background, videoAttrs);
|
|
|
|
lineBuffer.get(y - 1)[x - 1] = c;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
public void setColor(int x, int y, Color fill) {
|
|
|
|
Char c = null;
|
|
|
|
if (x > 0 && x <= TextMode.LINE_WIDTH_MAX && y > 0 && y <= TextMode.PAGE_HEIGHT_MAX) {
|
|
|
|
c = lineBuffer.get(y - 1)[x - 1];
|
|
|
|
}
|
|
|
|
if (c != null) {
|
|
|
|
c.fill = fill;
|
|
|
|
drawChar(x, y, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
public void setFill(Color fill) {
|
|
|
|
this.fill = fill != null ? fill : DEFAULT_FILL;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setFont(TextFont font) {
|
|
|
|
this.font = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setInk(Color ink) {
|
|
|
|
fill = ink != null ? ink : DEFAULT_FILL;
|
|
|
|
stroke = ink != null ? ink : DEFAULT_STROKE;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setItalics(boolean enabled) {
|
|
|
|
if (enabled)
|
|
|
|
videoAttrs |= TextFont.ATTR_ITALIC;
|
|
|
|
else
|
|
|
|
videoAttrs &= ~TextFont.ATTR_ITALIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*/
|
|
|
|
public void setLeftMargin() {
|
|
|
|
this.leftMargin = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param leftMargin
|
|
|
|
* the leftMargin to set
|
|
|
|
*/
|
|
|
|
public void setLeftMargin(int leftMargin) {
|
|
|
|
this.leftMargin = constrainX(leftMargin);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setReverseVideo(boolean enabled) {
|
|
|
|
if (enabled)
|
|
|
|
videoAttrs |= TextFont.ATTR_INVERSE;
|
|
|
|
else
|
|
|
|
videoAttrs &= ~TextFont.ATTR_INVERSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setStroke(Color stroke) {
|
|
|
|
this.stroke = stroke != null ? stroke : DEFAULT_STROKE;
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
public void setTextMode(TextMode mode) {
|
|
|
|
setTextMode(mode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setTextMode(TextMode mode, boolean adjustDisplayAspect) {
|
|
|
|
if (mode == null)
|
|
|
|
throw new IllegalArgumentException();
|
|
|
|
textMode = mode;
|
|
|
|
if (adjustDisplayAspect && screen != null)
|
|
|
|
screen.setAspect(textMode.getAspect());
|
|
|
|
redrawTextPage();
|
|
|
|
}
|
|
|
|
|
2018-02-28 10:22:33 +01:00
|
|
|
public void setTopMargin() {
|
|
|
|
this.topMargin = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param topMargin
|
|
|
|
* the topMargin to set
|
|
|
|
*/
|
|
|
|
public void setTopMargin(int topMargin) {
|
|
|
|
this.topMargin = constrainY(topMargin);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setVideoAttrDisabled(int attr) {
|
|
|
|
videoAttrs &= ~attr;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setVideoAttrEnabled(int attr) {
|
|
|
|
videoAttrs |= attr;
|
|
|
|
}
|
|
|
|
|
2018-02-28 23:51:40 +01:00
|
|
|
public void setVideoAttrs(int attr) {
|
|
|
|
videoAttrs = attr;
|
2018-02-28 10:22:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public void unplot(int x, int y) {
|
|
|
|
plot(x, y, (a, b) -> a & ~b);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|