15dee5019a49e9bd1d8aaadd9af1f2f160980df9
2 * Jexer - Java Text User Interface
4 * License: LGPLv3 or later
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
10 * Copyright (C) 2015 Kevin Lamonte
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
33 import jexer
.bits
.Cell
;
34 import jexer
.bits
.CellAttributes
;
37 * This Screen class draws to an xterm/ANSI X3.64/ECMA-48 type terminal.
39 public class ECMA48Screen
extends Screen
{
42 * Emit debugging to stderr.
44 private boolean debugToStderr
;
47 * We call terminal.cursor() so need the instance.
49 private ECMA48Terminal terminal
;
54 * @param terminal ECMA48Terminal to use
56 public ECMA48Screen(final ECMA48Terminal terminal
) {
57 debugToStderr
= false;
59 this.terminal
= terminal
;
61 // Query the screen size
62 setDimensions(terminal
.getSessionInfo().getWindowWidth(),
63 terminal
.getSessionInfo().getWindowHeight());
67 * Perform a somewhat-optimal rendering of a line.
69 * @param y row coordinate. 0 is the top-most row.
70 * @param sb StringBuilder to write escape sequences to
71 * @param lastAttr cell attributes from the last call to flushLine
73 private void flushLine(final int y
, final StringBuilder sb
,
74 CellAttributes lastAttr
) {
78 for (int x
= 0; x
< width
; x
++) {
79 Cell lCell
= logical
[x
][y
];
80 if (!lCell
.isBlank()) {
84 // Push textEnd to first column beyond the text area
88 // reallyCleared = true;
90 for (int x
= 0; x
< width
; x
++) {
91 Cell lCell
= logical
[x
][y
];
92 Cell pCell
= physical
[x
][y
];
94 if ((lCell
!= pCell
) || reallyCleared
) {
97 System
.err
.printf("\n--\n");
98 System
.err
.printf(" Y: %d X: %d\n", y
, x
);
99 System
.err
.printf(" lCell: %s\n", lCell
);
100 System
.err
.printf(" pCell: %s\n", pCell
);
101 System
.err
.printf(" ==== \n");
104 if (lastAttr
== null) {
105 lastAttr
= new CellAttributes();
106 sb
.append(terminal
.normal());
110 if ((lastX
!= (x
- 1)) || (lastX
== -1)) {
111 // Advancing at least one cell, or the first gotoXY
112 sb
.append(terminal
.gotoXY(x
, y
));
115 assert (lastAttr
!= null);
117 if ((x
== textEnd
) && (textEnd
< width
- 1)) {
118 assert (lCell
.isBlank());
120 for (int i
= x
; i
< width
; i
++) {
121 assert (logical
[i
][y
].isBlank());
122 // Physical is always updatesd
123 physical
[i
][y
].reset();
126 // Clear remaining line
127 sb
.append(terminal
.clearRemainingLine());
132 // Now emit only the modified attributes
133 if ((lCell
.getForeColor() != lastAttr
.getForeColor())
134 && (lCell
.getBackColor() != lastAttr
.getBackColor())
135 && (lCell
.getBold() == lastAttr
.getBold())
136 && (lCell
.getReverse() == lastAttr
.getReverse())
137 && (lCell
.getUnderline() == lastAttr
.getUnderline())
138 && (lCell
.getBlink() == lastAttr
.getBlink())
140 // Both colors changed, attributes the same
141 sb
.append(terminal
.color(lCell
.getForeColor(),
142 lCell
.getBackColor()));
145 System
.err
.printf("1 Change only fore/back colors\n");
147 } else if ((lCell
.getForeColor() != lastAttr
.getForeColor())
148 && (lCell
.getBackColor() != lastAttr
.getBackColor())
149 && (lCell
.getBold() != lastAttr
.getBold())
150 && (lCell
.getReverse() != lastAttr
.getReverse())
151 && (lCell
.getUnderline() != lastAttr
.getUnderline())
152 && (lCell
.getBlink() != lastAttr
.getBlink())
154 // Everything is different
155 sb
.append(terminal
.color(lCell
.getForeColor(),
156 lCell
.getBackColor(),
157 lCell
.getBold(), lCell
.getReverse(),
159 lCell
.getUnderline()));
162 System
.err
.printf("2 Set all attributes\n");
164 } else if ((lCell
.getForeColor() != lastAttr
.getForeColor())
165 && (lCell
.getBackColor() == lastAttr
.getBackColor())
166 && (lCell
.getBold() == lastAttr
.getBold())
167 && (lCell
.getReverse() == lastAttr
.getReverse())
168 && (lCell
.getUnderline() == lastAttr
.getUnderline())
169 && (lCell
.getBlink() == lastAttr
.getBlink())
172 // Attributes same, foreColor different
173 sb
.append(terminal
.color(lCell
.getForeColor(), true));
176 System
.err
.printf("3 Change foreColor\n");
178 } else if ((lCell
.getForeColor() == lastAttr
.getForeColor())
179 && (lCell
.getBackColor() != lastAttr
.getBackColor())
180 && (lCell
.getBold() == lastAttr
.getBold())
181 && (lCell
.getReverse() == lastAttr
.getReverse())
182 && (lCell
.getUnderline() == lastAttr
.getUnderline())
183 && (lCell
.getBlink() == lastAttr
.getBlink())
185 // Attributes same, backColor different
186 sb
.append(terminal
.color(lCell
.getBackColor(), false));
189 System
.err
.printf("4 Change backColor\n");
191 } else if ((lCell
.getForeColor() == lastAttr
.getForeColor())
192 && (lCell
.getBackColor() == lastAttr
.getBackColor())
193 && (lCell
.getBold() == lastAttr
.getBold())
194 && (lCell
.getReverse() == lastAttr
.getReverse())
195 && (lCell
.getUnderline() == lastAttr
.getUnderline())
196 && (lCell
.getBlink() == lastAttr
.getBlink())
199 // All attributes the same, just print the char
203 System
.err
.printf("5 Only emit character\n");
206 // Just reset everything again
207 sb
.append(terminal
.color(lCell
.getForeColor(),
208 lCell
.getBackColor(),
212 lCell
.getUnderline()));
215 System
.err
.printf("6 Change all attributes\n");
218 // Emit the character
219 sb
.append(lCell
.getChar());
221 // Save the last rendered cell
223 lastAttr
.setTo(lCell
);
225 // Physical is always updatesd
226 physical
[x
][y
].setTo(lCell
);
228 } // if ((lCell != pCell) || (reallyCleared == true))
230 } // for (int x = 0; x < width; x++)
234 * Render the screen to a string that can be emitted to something that
235 * knows how to process ECMA-48/ANSI X3.64 escape sequences.
237 * @return escape sequences string that provides the updates to the
240 public String
flushString() {
242 assert (!reallyCleared
);
246 CellAttributes attr
= null;
248 StringBuilder sb
= new StringBuilder();
250 attr
= new CellAttributes();
251 sb
.append(terminal
.clearAll());
254 for (int y
= 0; y
< height
; y
++) {
255 flushLine(y
, sb
, attr
);
259 reallyCleared
= false;
261 String result
= sb
.toString();
263 System
.err
.printf("flushString(): %s\n", result
);
269 * Push the logical screen to the physical device.
272 public void flushPhysical() {
273 String result
= flushString();
275 && (cursorY
<= height
- 1)
276 && (cursorX
<= width
- 1)
278 result
+= terminal
.cursor(true);
279 result
+= terminal
.gotoXY(cursorX
, cursorY
);
281 result
+= terminal
.cursor(false);
283 terminal
.getOutput().write(result
);