2e46e397901d21432e9d5527631779593bec015e
2 * Jexer - Java Text User Interface
6 * Author: Kevin Lamonte, <a href="mailto:kevin.lamonte@gmail.com">kevin.lamonte@gmail.com</a>
8 * License: LGPLv3 or later
10 * Copyright: This module is licensed under the GNU Lesser General
11 * Public License Version 3. Please see the file "COPYING" in this
12 * directory for more information about the GNU Lesser General Public
15 * Copyright (C) 2015 Kevin Lamonte
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public License
19 * as published by the Free Software Foundation; either version 3 of
20 * the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/licenses/, or write to the Free Software
30 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
35 import jexer
.bits
.Cell
;
36 import jexer
.bits
.CellAttributes
;
39 * This Screen class draws to an xterm/ANSI X3.64/ECMA-48 type terminal.
41 public class ECMA48Screen
extends Screen
{
44 * We call terminal.cursor() so need the instance
46 private ECMA48Terminal terminal
;
51 * @param terminal ECMA48Terminal to use
53 public ECMA48Screen(ECMA48Terminal terminal
) {
54 this.terminal
= terminal
;
56 // Query the screen size
57 setDimensions(terminal
.session
.getWindowWidth(),
58 terminal
.session
.getWindowHeight());
62 * Perform a somewhat-optimal rendering of a line
64 * @param y row coordinate. 0 is the top-most row.
65 * @param sb StringBuilder to write escape sequences to
66 * @param lastAttr cell attributes from the last call to flushLine
68 private void flushLine(int y
, StringBuilder sb
, CellAttributes lastAttr
) {
72 for (int x
= 0; x
< width
; x
++) {
73 Cell lCell
= logical
[x
][y
];
74 if (!lCell
.isBlank()) {
78 // Push textEnd to first column beyond the text area
82 // reallyCleared = true;
84 for (int x
= 0; x
< width
; x
++) {
85 Cell lCell
= logical
[x
][y
];
86 Cell pCell
= physical
[x
][y
];
88 if ((lCell
!= pCell
) || (reallyCleared
== true)) {
91 System
.err
.printf("\n--\n");
92 System
.err
.printf(" Y: %d X: %d\n", y
, x
);
93 System
.err
.printf(" lCell: %s\n", lCell
);
94 System
.err
.printf(" pCell: %s\n", pCell
);
95 System
.err
.printf(" ==== \n");
98 if (lastAttr
== null) {
99 lastAttr
= new CellAttributes();
100 sb
.append(terminal
.normal());
104 if ((lastX
!= (x
- 1)) || (lastX
== -1)) {
105 // Advancing at least one cell, or the first gotoXY
106 sb
.append(terminal
.gotoXY(x
, y
));
109 assert(lastAttr
!= null);
111 if ((x
== textEnd
) && (textEnd
< width
- 1)) {
112 assert(lCell
.isBlank());
114 for (int i
= x
; i
< width
; i
++) {
115 assert(logical
[i
][y
].isBlank());
116 // Physical is always updatesd
117 physical
[i
][y
].reset();
120 // Clear remaining line
121 sb
.append(terminal
.clearRemainingLine());
126 // Now emit only the modified attributes
127 if ((lCell
.foreColor
!= lastAttr
.foreColor
) &&
128 (lCell
.backColor
!= lastAttr
.backColor
) &&
129 (lCell
.bold
== lastAttr
.bold
) &&
130 (lCell
.reverse
== lastAttr
.reverse
) &&
131 (lCell
.underline
== lastAttr
.underline
) &&
132 (lCell
.blink
== lastAttr
.blink
)) {
134 // Both colors changed, attributes the same
135 sb
.append(terminal
.color(lCell
.foreColor
,
139 System
.err
.printf("1 Change only fore/back colors\n");
141 } else if ((lCell
.foreColor
!= lastAttr
.foreColor
) &&
142 (lCell
.backColor
!= lastAttr
.backColor
) &&
143 (lCell
.bold
!= lastAttr
.bold
) &&
144 (lCell
.reverse
!= lastAttr
.reverse
) &&
145 (lCell
.underline
!= lastAttr
.underline
) &&
146 (lCell
.blink
!= lastAttr
.blink
)) {
149 System
.err
.printf("2 Set all attributes\n");
152 // Everything is different
153 sb
.append(terminal
.color(lCell
.foreColor
,
155 lCell
.bold
, lCell
.reverse
, lCell
.blink
,
158 } else if ((lCell
.foreColor
!= lastAttr
.foreColor
) &&
159 (lCell
.backColor
== lastAttr
.backColor
) &&
160 (lCell
.bold
== lastAttr
.bold
) &&
161 (lCell
.reverse
== lastAttr
.reverse
) &&
162 (lCell
.underline
== lastAttr
.underline
) &&
163 (lCell
.blink
== lastAttr
.blink
)) {
165 // Attributes same, foreColor different
166 sb
.append(terminal
.color(lCell
.foreColor
, true));
169 System
.err
.printf("3 Change foreColor\n");
172 } else if ((lCell
.foreColor
== lastAttr
.foreColor
) &&
173 (lCell
.backColor
!= lastAttr
.backColor
) &&
174 (lCell
.bold
== lastAttr
.bold
) &&
175 (lCell
.reverse
== lastAttr
.reverse
) &&
176 (lCell
.underline
== lastAttr
.underline
) &&
177 (lCell
.blink
== lastAttr
.blink
)) {
179 // Attributes same, backColor different
180 sb
.append(terminal
.color(lCell
.backColor
, false));
183 System
.err
.printf("4 Change backColor\n");
186 } else if ((lCell
.foreColor
== lastAttr
.foreColor
) &&
187 (lCell
.backColor
== lastAttr
.backColor
) &&
188 (lCell
.bold
== lastAttr
.bold
) &&
189 (lCell
.reverse
== lastAttr
.reverse
) &&
190 (lCell
.underline
== lastAttr
.underline
) &&
191 (lCell
.blink
== lastAttr
.blink
)) {
193 // All attributes the same, just print the char
197 System
.err
.printf("5 Only emit character\n");
200 // Just reset everything again
201 sb
.append(terminal
.color(lCell
.foreColor
, lCell
.backColor
,
202 lCell
.bold
, lCell
.reverse
, lCell
.blink
,
206 System
.err
.printf("6 Change all attributes\n");
209 // Emit the character
212 // Save the last rendered cell
214 lastAttr
.setTo(lCell
);
216 // Physical is always updatesd
217 physical
[x
][y
].setTo(lCell
);
219 } // if ((lCell != pCell) || (reallyCleared == true))
221 } // for (int x = 0; x < width; x++)
225 * Render the screen to a string that can be emitted to something that
226 * knows how to process ECMA-48/ANSI X3.64 escape sequences.
228 * @return escape sequences string that provides the updates to the
231 public String
flushString() {
232 if (dirty
== false) {
233 assert(reallyCleared
== false);
237 CellAttributes attr
= null;
239 StringBuilder sb
= new StringBuilder();
240 if (reallyCleared
== true) {
241 attr
= new CellAttributes();
242 sb
.append(terminal
.clearAll());
245 for (int y
= 0; y
< height
; y
++) {
246 flushLine(y
, sb
, attr
);
250 reallyCleared
= false;
252 String result
= sb
.toString();
254 System
.err
.printf("flushString(): %s\n", result
);
260 * Push the logical screen to the physical device.
263 public void flushPhysical() {
264 String result
= flushString();
265 if ((cursorVisible
) &&
266 (cursorY
<= height
- 1) &&
267 (cursorX
<= width
- 1)
269 result
+= terminal
.cursor(true);
270 result
+= terminal
.gotoXY(cursorX
, cursorY
);
272 result
+= terminal
.cursor(false);
274 terminal
.getOutput().write(result
);