only keep the (re)sources here
[nikiroo-utils.git] / jexer / TTerminalWindow.java
CommitLineData
daa4106c 1/*
34a42e78
KL
2 * Jexer - Java Text User Interface
3 *
e16dda65 4 * The MIT License (MIT)
34a42e78 5 *
a69ed767 6 * Copyright (C) 2019 Kevin Lamonte
34a42e78 7 *
e16dda65
KL
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
34a42e78 14 *
e16dda65
KL
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
34a42e78 17 *
e16dda65
KL
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
34a42e78
KL
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
d1115203
KL
31import java.awt.Font;
32import java.awt.FontMetrics;
33import java.awt.Graphics2D;
5fc7bf09 34import java.awt.image.BufferedImage;
d1115203
KL
35
36import java.io.InputStream;
34a42e78 37import java.io.IOException;
55d2b2c2 38import java.lang.reflect.Field;
339652cc 39import java.text.MessageFormat;
a69ed767 40import java.util.ArrayList;
d1115203 41import java.util.HashMap;
34a42e78 42import java.util.List;
bd8d51fa 43import java.util.Map;
339652cc 44import java.util.ResourceBundle;
34a42e78 45
d1115203 46import jexer.backend.ECMA48Terminal;
0d86ab84 47import jexer.backend.GlyphMaker;
d1115203
KL
48import jexer.backend.MultiScreen;
49import jexer.backend.SwingTerminal;
34a42e78
KL
50import jexer.bits.Cell;
51import jexer.bits.CellAttributes;
52import jexer.event.TKeypressEvent;
b2d49e0f 53import jexer.event.TMenuEvent;
34a42e78
KL
54import jexer.event.TMouseEvent;
55import jexer.event.TResizeEvent;
b2d49e0f 56import jexer.menu.TMenu;
34a42e78 57import jexer.tterminal.DisplayLine;
be72cb5c 58import jexer.tterminal.DisplayListener;
34a42e78
KL
59import jexer.tterminal.ECMA48;
60import static jexer.TKeypress.*;
61
62/**
63 * TTerminalWindow exposes a ECMA-48 / ANSI X3.64 style terminal in a window.
64 */
4d2c61b4 65public class TTerminalWindow extends TScrollableWindow {
34a42e78 66
339652cc
KL
67 /**
68 * Translated strings.
69 */
70 private static final ResourceBundle i18n = ResourceBundle.getBundle(TTerminalWindow.class.getName());
71
615a0d99
KL
72 // ------------------------------------------------------------------------
73 // Variables --------------------------------------------------------------
74 // ------------------------------------------------------------------------
75
34a42e78 76 /**
4d2c61b4 77 * The terminal.
34a42e78 78 */
4d2c61b4 79 private TTerminalWidget terminal;
1d99a38f 80
a69ed767
KL
81 /**
82 * If true, close the window when the shell exits.
83 */
84 private boolean closeOnExit = false;
85
615a0d99
KL
86 // ------------------------------------------------------------------------
87 // Constructors -----------------------------------------------------------
88 // ------------------------------------------------------------------------
34a42e78 89
b2d49e0f
KL
90 /**
91 * Public constructor spawns a custom command line.
92 *
93 * @param application TApplication that manages this window
94 * @param x column relative to parent
95 * @param y row relative to parent
96 * @param commandLine the command line to execute
97 */
98 public TTerminalWindow(final TApplication application, final int x,
99 final int y, final String commandLine) {
100
00691e80 101 this(application, x, y, RESIZABLE, commandLine.split("\\s+"),
a69ed767
KL
102 System.getProperty("jexer.TTerminal.closeOnExit",
103 "false").equals("true"));
104 }
105
106 /**
107 * Public constructor spawns a custom command line.
108 *
109 * @param application TApplication that manages this window
110 * @param x column relative to parent
111 * @param y row relative to parent
112 * @param commandLine the command line to execute
113 * @param closeOnExit if true, close the window when the command exits
114 */
115 public TTerminalWindow(final TApplication application, final int x,
116 final int y, final String commandLine, final boolean closeOnExit) {
117
00691e80 118 this(application, x, y, RESIZABLE, commandLine.split("\\s+"),
a69ed767 119 closeOnExit);
b2d49e0f
KL
120 }
121
6f8ff91a
KL
122 /**
123 * Public constructor spawns a custom command line.
124 *
125 * @param application TApplication that manages this window
126 * @param x column relative to parent
127 * @param y row relative to parent
128 * @param flags mask of CENTERED, MODAL, or RESIZABLE
a0d734e6 129 * @param command the command line to execute
6f8ff91a
KL
130 */
131 public TTerminalWindow(final TApplication application, final int x,
a0d734e6 132 final int y, final int flags, final String [] command) {
6f8ff91a 133
a69ed767
KL
134 this(application, x, y, flags, command,
135 System.getProperty("jexer.TTerminal.closeOnExit",
136 "false").equals("true"));
137 }
138
139 /**
140 * Public constructor spawns a custom command line.
141 *
142 * @param application TApplication that manages this window
143 * @param x column relative to parent
144 * @param y row relative to parent
145 * @param flags mask of CENTERED, MODAL, or RESIZABLE
146 * @param command the command line to execute
147 * @param closeOnExit if true, close the window when the command exits
148 */
149 public TTerminalWindow(final TApplication application, final int x,
150 final int y, final int flags, final String [] command,
151 final boolean closeOnExit) {
152
6f8ff91a
KL
153 super(application, i18n.getString("windowTitle"), x, y,
154 80 + 2, 24 + 2, flags);
155
955c55b7
KL
156 // Require at least one line for the display.
157 setMinimumWindowHeight(3);
158
a69ed767 159 this.closeOnExit = closeOnExit;
4d2c61b4
KL
160 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
161
162 // Claim the keystrokes the emulator will need.
163 addShortcutKeys();
a69ed767 164
4d2c61b4
KL
165 // Add shortcut text
166 newStatusBar(i18n.getString("statusBarRunning"));
6f8ff91a 167
4d2c61b4 168 // Spin it up
2bc32111
KL
169 terminal = new TTerminalWidget(this, 0, 0, new TAction() {
170 public void DO() {
171 onShellExit();
172 }
173 });
6f8ff91a
KL
174 }
175
176 /**
177 * Public constructor spawns a shell.
178 *
179 * @param application TApplication that manages this window
180 * @param x column relative to parent
181 * @param y row relative to parent
182 * @param flags mask of CENTERED, MODAL, or RESIZABLE
183 */
184 public TTerminalWindow(final TApplication application, final int x,
185 final int y, final int flags) {
186
a69ed767
KL
187 this(application, x, y, flags,
188 System.getProperty("jexer.TTerminal.closeOnExit",
189 "false").equals("true"));
190
191 }
192
193 /**
194 * Public constructor spawns a shell.
195 *
196 * @param application TApplication that manages this window
197 * @param x column relative to parent
198 * @param y row relative to parent
199 * @param flags mask of CENTERED, MODAL, or RESIZABLE
200 * @param closeOnExit if true, close the window when the shell exits
201 */
202 public TTerminalWindow(final TApplication application, final int x,
203 final int y, final int flags, final boolean closeOnExit) {
204
6f8ff91a
KL
205 super(application, i18n.getString("windowTitle"), x, y,
206 80 + 2, 24 + 2, flags);
207
955c55b7
KL
208 // Require at least one line for the display.
209 setMinimumWindowHeight(3);
210
a69ed767 211 this.closeOnExit = closeOnExit;
4d2c61b4 212 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
a69ed767 213
4d2c61b4
KL
214 // Claim the keystrokes the emulator will need.
215 addShortcutKeys();
6f8ff91a 216
4d2c61b4
KL
217 // Add shortcut text
218 newStatusBar(i18n.getString("statusBarRunning"));
6f8ff91a 219
4d2c61b4 220 // Spin it up
2bc32111
KL
221 terminal = new TTerminalWidget(this, 0, 0, new TAction() {
222 public void DO() {
223 onShellExit();
224 }
225 });
6f8ff91a
KL
226 }
227
615a0d99
KL
228 // ------------------------------------------------------------------------
229 // TScrollableWindow ------------------------------------------------------
230 // ------------------------------------------------------------------------
55d2b2c2 231
34a42e78
KL
232 /**
233 * Draw the display buffer.
234 */
235 @Override
236 public void draw() {
1104f8d7
KL
237 if (terminal != null) {
238 setTitle(terminal.getTitle());
239 }
4d2c61b4 240 reflowData();
ab215e38 241 super.draw();
107bba16
KL
242 }
243
be72cb5c 244 /**
615a0d99 245 * Handle window/screen resize events.
aa77d682 246 *
615a0d99 247 * @param resize resize event
aa77d682 248 */
615a0d99
KL
249 @Override
250 public void onResize(final TResizeEvent resize) {
4d2c61b4 251 if (resize.getType() == TResizeEvent.Type.WIDGET) {
1104f8d7
KL
252 if (terminal != null) {
253 terminal.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
254 getWidth() - 2, getHeight() - 2));
255 }
615a0d99 256
4d2c61b4
KL
257 // Resize the scroll bars
258 reflowData();
259 placeScrollbars();
260 }
261 return;
aa77d682
KL
262 }
263
264 /**
615a0d99 265 * Resize scrollbars for a new width/height.
aa77d682 266 */
615a0d99
KL
267 @Override
268 public void reflowData() {
4d2c61b4 269 // Vertical scrollbar
1104f8d7
KL
270 if (terminal != null) {
271 terminal.reflowData();
272 setTopValue(terminal.getTopValue());
273 setBottomValue(terminal.getBottomValue());
274 setVerticalBigChange(terminal.getVerticalBigChange());
275 setVerticalValue(terminal.getVerticalValue());
276 }
aa77d682
KL
277 }
278
b2d49e0f 279 /**
615a0d99
KL
280 * Handle keystrokes.
281 *
282 * @param keypress keystroke event
34a42e78 283 */
615a0d99
KL
284 @Override
285 public void onKeypress(final TKeypressEvent keypress) {
1104f8d7 286 if ((terminal != null) && (terminal.isReading())) {
4d2c61b4
KL
287 terminal.onKeypress(keypress);
288 } else {
289 super.onKeypress(keypress);
34a42e78 290 }
34a42e78
KL
291 }
292
293 /**
294 * Handle mouse press events.
295 *
296 * @param mouse mouse button press event
297 */
298 @Override
299 public void onMouseDown(final TMouseEvent mouse) {
bd8d51fa
KL
300 if (inWindowMove || inWindowResize) {
301 // TWindow needs to deal with this.
302 super.onMouseDown(mouse);
303 return;
304 }
34a42e78 305
34a42e78
KL
306 super.onMouseDown(mouse);
307 }
308
bd8d51fa
KL
309 /**
310 * Handle mouse release events.
311 *
312 * @param mouse mouse button release event
313 */
314 @Override
315 public void onMouseUp(final TMouseEvent mouse) {
316 if (inWindowMove || inWindowResize) {
317 // TWindow needs to deal with this.
318 super.onMouseUp(mouse);
319 return;
320 }
321
bd8d51fa 322 super.onMouseUp(mouse);
dbf8e80a
KL
323
324 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
325 // Clicked on vertical scrollbar
1104f8d7
KL
326 if (terminal != null) {
327 terminal.setVerticalValue(getVerticalValue());
328 }
dbf8e80a 329 }
bd8d51fa
KL
330 }
331
332 /**
333 * Handle mouse motion events.
334 *
335 * @param mouse mouse motion event
336 */
337 @Override
338 public void onMouseMotion(final TMouseEvent mouse) {
339 if (inWindowMove || inWindowResize) {
340 // TWindow needs to deal with this.
341 super.onMouseMotion(mouse);
342 return;
343 }
344
bd8d51fa 345 super.onMouseMotion(mouse);
dbf8e80a
KL
346
347 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
348 // Clicked/dragged on vertical scrollbar
1104f8d7
KL
349 if (terminal != null) {
350 terminal.setVerticalValue(getVerticalValue());
351 }
dbf8e80a 352 }
bd8d51fa
KL
353 }
354
615a0d99
KL
355 // ------------------------------------------------------------------------
356 // TTerminalWindow --------------------------------------------------------
357 // ------------------------------------------------------------------------
358
80b1b7b5
KL
359 /**
360 * Returns true if this window does not want the application-wide mouse
361 * cursor drawn over it.
362 *
363 * @return true if this window does not want the application-wide mouse
364 * cursor drawn over it
365 */
366 @Override
367 public boolean hasHiddenMouse() {
1104f8d7
KL
368 if (terminal != null) {
369 return terminal.hasHiddenMouse();
370 }
371 return false;
80b1b7b5
KL
372 }
373
615a0d99
KL
374 /**
375 * Claim the keystrokes the emulator will need.
376 */
377 private void addShortcutKeys() {
378 addShortcutKeypress(kbCtrlA);
379 addShortcutKeypress(kbCtrlB);
380 addShortcutKeypress(kbCtrlC);
381 addShortcutKeypress(kbCtrlD);
382 addShortcutKeypress(kbCtrlE);
383 addShortcutKeypress(kbCtrlF);
384 addShortcutKeypress(kbCtrlG);
385 addShortcutKeypress(kbCtrlH);
386 addShortcutKeypress(kbCtrlU);
387 addShortcutKeypress(kbCtrlJ);
388 addShortcutKeypress(kbCtrlK);
389 addShortcutKeypress(kbCtrlL);
390 addShortcutKeypress(kbCtrlM);
391 addShortcutKeypress(kbCtrlN);
392 addShortcutKeypress(kbCtrlO);
393 addShortcutKeypress(kbCtrlP);
394 addShortcutKeypress(kbCtrlQ);
395 addShortcutKeypress(kbCtrlR);
396 addShortcutKeypress(kbCtrlS);
397 addShortcutKeypress(kbCtrlT);
398 addShortcutKeypress(kbCtrlU);
399 addShortcutKeypress(kbCtrlV);
400 addShortcutKeypress(kbCtrlW);
401 addShortcutKeypress(kbCtrlX);
402 addShortcutKeypress(kbCtrlY);
403 addShortcutKeypress(kbCtrlZ);
404 addShortcutKeypress(kbF1);
405 addShortcutKeypress(kbF2);
406 addShortcutKeypress(kbF3);
407 addShortcutKeypress(kbF4);
408 addShortcutKeypress(kbF5);
409 addShortcutKeypress(kbF6);
410 addShortcutKeypress(kbF7);
411 addShortcutKeypress(kbF8);
412 addShortcutKeypress(kbF9);
413 addShortcutKeypress(kbF10);
414 addShortcutKeypress(kbF11);
415 addShortcutKeypress(kbF12);
416 addShortcutKeypress(kbAltA);
417 addShortcutKeypress(kbAltB);
418 addShortcutKeypress(kbAltC);
419 addShortcutKeypress(kbAltD);
420 addShortcutKeypress(kbAltE);
421 addShortcutKeypress(kbAltF);
422 addShortcutKeypress(kbAltG);
423 addShortcutKeypress(kbAltH);
424 addShortcutKeypress(kbAltU);
425 addShortcutKeypress(kbAltJ);
426 addShortcutKeypress(kbAltK);
427 addShortcutKeypress(kbAltL);
428 addShortcutKeypress(kbAltM);
429 addShortcutKeypress(kbAltN);
430 addShortcutKeypress(kbAltO);
431 addShortcutKeypress(kbAltP);
432 addShortcutKeypress(kbAltQ);
433 addShortcutKeypress(kbAltR);
434 addShortcutKeypress(kbAltS);
435 addShortcutKeypress(kbAltT);
436 addShortcutKeypress(kbAltU);
437 addShortcutKeypress(kbAltV);
438 addShortcutKeypress(kbAltW);
439 addShortcutKeypress(kbAltX);
440 addShortcutKeypress(kbAltY);
441 addShortcutKeypress(kbAltZ);
442 }
443
615a0d99
KL
444 /**
445 * Hook for subclasses to be notified of the shell termination.
446 */
447 public void onShellExit() {
a69ed767
KL
448 if (closeOnExit) {
449 close();
450 }
4d2c61b4 451 clearShortcutKeypresses();
615a0d99
KL
452 getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT));
453 }
454
34a42e78 455}