mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 11:50:19 -06:00
Many changes:
1. TCalendar widget. Double-click or enter for action. 2. TSpinner widget. Up/down actions. 3. TComboBox widget. Double-click on list to set value. Enter for action. 4. 24-bit color now supported, both as output (ECMA48/Swing) and in TTerminalWindow. Not thoroughly tested yet, especially around ColorTheme. 5. Many "final class" restrictions removed.
This commit is contained in:
parent
43ad7b6c50
commit
051e29138b
56 changed files with 1897 additions and 148 deletions
14
docs/TODO.md
14
docs/TODO.md
|
@ -7,11 +7,6 @@ Roadmap
|
|||
|
||||
0.0.6
|
||||
|
||||
- New widgets:
|
||||
- TSpinner
|
||||
- TComboBox
|
||||
- TCalendar
|
||||
|
||||
- TEditor
|
||||
- Horizontal scrollbar integration
|
||||
- True tokenization and syntax highlighting: Java, C, Clojure, XML
|
||||
|
@ -55,7 +50,14 @@ Roadmap
|
|||
- TEditor:
|
||||
- Undo / Redo support
|
||||
|
||||
0.1.0: BETA RELEASE and BUG HUNT
|
||||
0.1.0: LET'S GET PRETTY
|
||||
|
||||
- TChart:
|
||||
- Bar chart
|
||||
- XY chart
|
||||
- Time series chart
|
||||
|
||||
0.1.1: BETA RELEASE and BUG HUNT
|
||||
|
||||
- Verify vttest in multiple tterminals.
|
||||
|
||||
|
|
|
@ -1,6 +1,53 @@
|
|||
Jexer Work Log
|
||||
==============
|
||||
|
||||
December 15, 2017
|
||||
|
||||
We now have 24-bit RGB colors working with Swing backend.
|
||||
EMCA48Terminal isn't happy though, let's try to fix that... still no
|
||||
dice. So RGB is there for ECMA48 backend, but it sometimes flickers
|
||||
or disappears. I'm not sure yet where the fault lies. Ah, found it!
|
||||
Cell.isBlank() wasn't checking RGB.
|
||||
|
||||
Well, I do say it is rather pretty now. Let's get this committed and
|
||||
uploaded.
|
||||
|
||||
December 14, 2017
|
||||
|
||||
TComboBox is stubbed in, and it was quite simple: just a TField and
|
||||
TList, and a teeny bit of glue. Along the way I renamed TCheckbox to
|
||||
TCheckBox, which was almost more work than TComboBox. Heh. Things
|
||||
are starting to come together indeed.
|
||||
|
||||
TSpinner is in. Now working on TCalendar... ...and TCalendar is in!
|
||||
|
||||
December 13, 2017
|
||||
|
||||
A user noticed that the example code given in the README.md caused the
|
||||
main window to freeze when clicking close. Turns out that was due to
|
||||
the addWindow(new TWindow(...)) line, which led to TWindow appearing
|
||||
in TApplication's window list twice. Fixed the README, and then made
|
||||
TApplication.addWindow a package private function plus a check to
|
||||
ensure it isn't added twice.
|
||||
|
||||
On the home front, my main box is now a Fedora 26 running Plasma
|
||||
desktop. That ate a few weekends getting used to. Current-era Linux
|
||||
is pretty nice, systemd so far (cross fingers) isn't creating any real
|
||||
problems, audio and wifi worked out of the box (thanks to Intel
|
||||
chipsets), and I can finally have all of my books and references on
|
||||
the same box as dev. So woohoo!
|
||||
|
||||
SwingTerminal is getting the insets wrong, which is a bit aggravating.
|
||||
So let's add adjustable insets in SwingComponent with a default
|
||||
2-pixel border around the whole thing, which I can tweak for my
|
||||
laptop. Done!
|
||||
|
||||
Alright, so where are we? Well, I will have some time in the evenings
|
||||
over the next couple weeks to put into projects. This one will get a
|
||||
little bit of love, probably a new widget or two; Qodem might get
|
||||
libssh2 + mdebtls support in Windows if those aren't too involved;
|
||||
Jermit will get a little more push towards a Kermit implementation.
|
||||
|
||||
October 17, 2017
|
||||
|
||||
I finally gave up the ghost on using gcj as the default compiler due
|
||||
|
|
|
@ -1384,8 +1384,16 @@ public class TApplication implements Runnable {
|
|||
System.currentTimeMillis(), Thread.currentThread(), x, y);
|
||||
}
|
||||
CellAttributes attr = getScreen().getAttrXY(x, y);
|
||||
attr.setForeColor(attr.getForeColor().invert());
|
||||
attr.setBackColor(attr.getBackColor().invert());
|
||||
if (attr.getForeColorRGB() < 0) {
|
||||
attr.setForeColor(attr.getForeColor().invert());
|
||||
} else {
|
||||
attr.setForeColorRGB(attr.getForeColorRGB() ^ 0x00ffffff);
|
||||
}
|
||||
if (attr.getBackColorRGB() < 0) {
|
||||
attr.setBackColor(attr.getBackColor().invert());
|
||||
} else {
|
||||
attr.setBackColorRGB(attr.getBackColorRGB() ^ 0x00ffffff);
|
||||
}
|
||||
getScreen().putAttrXY(x, y, attr, false);
|
||||
}
|
||||
|
||||
|
@ -1902,11 +1910,12 @@ public class TApplication implements Runnable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a window to my window list and make it active.
|
||||
* Add a window to my window list and make it active. Note package
|
||||
* private access.
|
||||
*
|
||||
* @param window new window to add
|
||||
*/
|
||||
public final void addWindowToApplication(final TWindow window) {
|
||||
final void addWindowToApplication(final TWindow window) {
|
||||
|
||||
// Do not add menu windows to the window list.
|
||||
if (window instanceof TMenu) {
|
||||
|
@ -1919,6 +1928,11 @@ public class TApplication implements Runnable {
|
|||
}
|
||||
|
||||
synchronized (windows) {
|
||||
if (windows.contains(window)) {
|
||||
throw new IllegalArgumentException("Window " + window +
|
||||
" is already in window list");
|
||||
}
|
||||
|
||||
// Whatever window might be moving/dragging, stop it now.
|
||||
for (TWindow w: windows) {
|
||||
if (w.inMovements()) {
|
||||
|
|
|
@ -42,7 +42,7 @@ import static jexer.TKeypress.*;
|
|||
*
|
||||
* @see TAction#DO()
|
||||
*/
|
||||
public final class TButton extends TWidget {
|
||||
public class TButton extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
320
src/jexer/TCalendar.java
Normal file
320
src/jexer/TCalendar.java
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* Jexer - Java Text User Interface
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2017 Kevin Lamonte
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @author Kevin Lamonte [kevin.lamonte@gmail.com]
|
||||
* @version 1
|
||||
*/
|
||||
package jexer;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.event.TKeypressEvent;
|
||||
import jexer.event.TMouseEvent;
|
||||
import static jexer.TKeypress.*;
|
||||
|
||||
/**
|
||||
* TCalendar is a date picker widget.
|
||||
*/
|
||||
public class TCalendar extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The calendar being displayed.
|
||||
*/
|
||||
private GregorianCalendar displayCalendar = new GregorianCalendar();
|
||||
|
||||
/**
|
||||
* The calendar with the selected day.
|
||||
*/
|
||||
private GregorianCalendar calendar = new GregorianCalendar();
|
||||
|
||||
/**
|
||||
* The action to perform when the user changes the value of the calendar.
|
||||
*/
|
||||
private TAction updateAction = null;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param parent parent widget
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param updateAction action to call when the user changes the value of
|
||||
* the calendar
|
||||
*/
|
||||
public TCalendar(final TWidget parent, final int x, final int y,
|
||||
final TAction updateAction) {
|
||||
|
||||
// Set parent and window
|
||||
super(parent, x, y, 28, 8);
|
||||
|
||||
this.updateAction = updateAction;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Event handlers ---------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if the mouse is currently on the left arrow.
|
||||
*
|
||||
* @param mouse mouse event
|
||||
* @return true if the mouse is currently on the left arrow
|
||||
*/
|
||||
private boolean mouseOnLeftArrow(final TMouseEvent mouse) {
|
||||
if ((mouse.getY() == 0)
|
||||
&& (mouse.getX() == 1)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mouse is currently on the right arrow.
|
||||
*
|
||||
* @param mouse mouse event
|
||||
* @return true if the mouse is currently on the right arrow
|
||||
*/
|
||||
private boolean mouseOnRightArrow(final TMouseEvent mouse) {
|
||||
if ((mouse.getY() == 0)
|
||||
&& (mouse.getX() == getWidth() - 2)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse down clicks.
|
||||
*
|
||||
* @param mouse mouse button down event
|
||||
*/
|
||||
@Override
|
||||
public void onMouseDown(final TMouseEvent mouse) {
|
||||
if ((mouseOnLeftArrow(mouse)) && (mouse.isMouse1())) {
|
||||
displayCalendar.add(Calendar.MONTH, -1);
|
||||
} else if ((mouseOnRightArrow(mouse)) && (mouse.isMouse1())) {
|
||||
displayCalendar.add(Calendar.MONTH, 1);
|
||||
} else if (mouse.isMouse1()) {
|
||||
// Find the day this might correspond to, and set it.
|
||||
int index = (mouse.getY() - 2) * 7 + (mouse.getX() / 4) + 1;
|
||||
// System.err.println("index: " + index);
|
||||
|
||||
int lastDayNumber = displayCalendar.getActualMaximum(
|
||||
Calendar.DAY_OF_MONTH);
|
||||
GregorianCalendar firstOfMonth = new GregorianCalendar();
|
||||
firstOfMonth.setTimeInMillis(displayCalendar.getTimeInMillis());
|
||||
firstOfMonth.set(Calendar.DAY_OF_MONTH, 1);
|
||||
int dayOf1st = firstOfMonth.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
// System.err.println("dayOf1st: " + dayOf1st);
|
||||
|
||||
int day = index - dayOf1st;
|
||||
// System.err.println("day: " + day);
|
||||
|
||||
if ((day < 1) || (day > lastDayNumber)) {
|
||||
return;
|
||||
}
|
||||
calendar.setTimeInMillis(displayCalendar.getTimeInMillis());
|
||||
calendar.set(Calendar.DAY_OF_MONTH, day);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse double click.
|
||||
*
|
||||
* @param mouse mouse double click event
|
||||
*/
|
||||
@Override
|
||||
public void onMouseDoubleClick(final TMouseEvent mouse) {
|
||||
if (updateAction != null) {
|
||||
updateAction.DO();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keystrokes.
|
||||
*
|
||||
* @param keypress keystroke event
|
||||
*/
|
||||
@Override
|
||||
public void onKeypress(final TKeypressEvent keypress) {
|
||||
int increment = 0;
|
||||
|
||||
if (keypress.equals(kbUp)) {
|
||||
increment = -7;
|
||||
} else if (keypress.equals(kbDown)) {
|
||||
increment = 7;
|
||||
} else if (keypress.equals(kbLeft)) {
|
||||
increment = -1;
|
||||
} else if (keypress.equals(kbRight)) {
|
||||
increment = 1;
|
||||
} else if (keypress.equals(kbEnter)) {
|
||||
if (updateAction != null) {
|
||||
updateAction.DO();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// Pass to parent for the things we don't care about.
|
||||
super.onKeypress(keypress);
|
||||
return;
|
||||
}
|
||||
|
||||
if (increment != 0) {
|
||||
calendar.add(Calendar.DAY_OF_YEAR, increment);
|
||||
|
||||
if ((displayCalendar.get(Calendar.MONTH) != calendar.get(
|
||||
Calendar.MONTH))
|
||||
|| (displayCalendar.get(Calendar.YEAR) != calendar.get(
|
||||
Calendar.YEAR))
|
||||
) {
|
||||
if (increment < 0) {
|
||||
displayCalendar.add(Calendar.MONTH, -1);
|
||||
} else {
|
||||
displayCalendar.add(Calendar.MONTH, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// TWidget ----------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Draw the combobox down arrow.
|
||||
*/
|
||||
@Override
|
||||
public void draw() {
|
||||
CellAttributes backgroundColor = getTheme().getColor(
|
||||
"tcalendar.background");
|
||||
CellAttributes dayColor = getTheme().getColor(
|
||||
"tcalendar.day");
|
||||
CellAttributes selectedDayColor = getTheme().getColor(
|
||||
"tcalendar.day.selected");
|
||||
CellAttributes arrowColor = getTheme().getColor(
|
||||
"tcalendar.arrow");
|
||||
CellAttributes titleColor = getTheme().getColor(
|
||||
"tcalendar.title");
|
||||
|
||||
// Fill in the interior background
|
||||
for (int i = 0; i < getHeight(); i++) {
|
||||
getScreen().hLineXY(0, i, getWidth(), ' ', backgroundColor);
|
||||
}
|
||||
|
||||
// Draw the title
|
||||
String title = String.format("%tB %tY", displayCalendar,
|
||||
displayCalendar);
|
||||
int titleLeft = (getWidth() - title.length() - 2) / 2;
|
||||
getScreen().putCharXY(titleLeft, 0, ' ', titleColor);
|
||||
getScreen().putStringXY(titleLeft + 1, 0, title, titleColor);
|
||||
getScreen().putCharXY(titleLeft + title.length() + 1, 0, ' ',
|
||||
titleColor);
|
||||
|
||||
// Arrows
|
||||
getScreen().putCharXY(1, 0, GraphicsChars.LEFTARROW, arrowColor);
|
||||
getScreen().putCharXY(getWidth() - 2, 0, GraphicsChars.RIGHTARROW,
|
||||
arrowColor);
|
||||
|
||||
/*
|
||||
* Now draw out the days.
|
||||
*/
|
||||
getScreen().putStringXY(0, 1, " S M T W T F S ", dayColor);
|
||||
int lastDayNumber = displayCalendar.getActualMaximum(
|
||||
Calendar.DAY_OF_MONTH);
|
||||
GregorianCalendar firstOfMonth = new GregorianCalendar();
|
||||
firstOfMonth.setTimeInMillis(displayCalendar.getTimeInMillis());
|
||||
firstOfMonth.set(Calendar.DAY_OF_MONTH, 1);
|
||||
int dayOf1st = firstOfMonth.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
int dayColumn = dayOf1st * 4;
|
||||
int row = 2;
|
||||
|
||||
int dayOfMonth = 1;
|
||||
while (dayOfMonth <= lastDayNumber) {
|
||||
if (dayColumn == 4 * 7) {
|
||||
dayColumn = 0;
|
||||
row++;
|
||||
}
|
||||
if ((dayOfMonth == calendar.get(Calendar.DAY_OF_MONTH))
|
||||
&& (displayCalendar.get(Calendar.MONTH) == calendar.get(
|
||||
Calendar.MONTH))
|
||||
&& (displayCalendar.get(Calendar.YEAR) == calendar.get(
|
||||
Calendar.YEAR))
|
||||
) {
|
||||
getScreen().putStringXY(dayColumn, row,
|
||||
String.format(" %2d ", dayOfMonth), selectedDayColor);
|
||||
} else {
|
||||
getScreen().putStringXY(dayColumn, row,
|
||||
String.format(" %2d ", dayOfMonth), dayColor);
|
||||
}
|
||||
dayColumn += 4;
|
||||
dayOfMonth++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// TCalendar --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get calendar value.
|
||||
*
|
||||
* @return the current calendar value (clone instance)
|
||||
*/
|
||||
public Calendar getValue() {
|
||||
return (Calendar) calendar.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set calendar value.
|
||||
*
|
||||
* @param calendar the new value to use
|
||||
*/
|
||||
public final void setValue(final Calendar calendar) {
|
||||
this.calendar.setTimeInMillis(calendar.getTimeInMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set calendar value.
|
||||
*
|
||||
* @param millis the millis to set to
|
||||
*/
|
||||
public final void setValue(final long millis) {
|
||||
this.calendar.setTimeInMillis(millis);
|
||||
}
|
||||
|
||||
}
|
|
@ -35,9 +35,9 @@ import jexer.event.TKeypressEvent;
|
|||
import jexer.event.TMouseEvent;
|
||||
|
||||
/**
|
||||
* TCheckbox implements an on/off checkbox.
|
||||
* TCheckBox implements an on/off checkbox.
|
||||
*/
|
||||
public final class TCheckbox extends TWidget {
|
||||
public class TCheckBox extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
@ -66,7 +66,7 @@ public final class TCheckbox extends TWidget {
|
|||
* @param label label to display next to (right of) the checkbox
|
||||
* @param checked initial check state
|
||||
*/
|
||||
public TCheckbox(final TWidget parent, final int x, final int y,
|
||||
public TCheckBox(final TWidget parent, final int x, final int y,
|
||||
final String label, final boolean checked) {
|
||||
|
||||
// Set parent and window
|
||||
|
@ -156,7 +156,7 @@ public final class TCheckbox extends TWidget {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// TCheckbox --------------------------------------------------------------
|
||||
// TCheckBox --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
243
src/jexer/TComboBox.java
Normal file
243
src/jexer/TComboBox.java
Normal file
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Jexer - Java Text User Interface
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2017 Kevin Lamonte
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @author Kevin Lamonte [kevin.lamonte@gmail.com]
|
||||
* @version 1
|
||||
*/
|
||||
package jexer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.event.TKeypressEvent;
|
||||
import jexer.event.TMouseEvent;
|
||||
import static jexer.TKeypress.*;
|
||||
|
||||
/**
|
||||
* TComboBox implements a combobox containing a drop-down list and edit
|
||||
* field. Alt-Down can be used to show the drop-down.
|
||||
*/
|
||||
public class TComboBox extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The list of items in the drop-down.
|
||||
*/
|
||||
private TList list;
|
||||
|
||||
/**
|
||||
* The edit field containing the value to return.
|
||||
*/
|
||||
private TField field;
|
||||
|
||||
/**
|
||||
* The action to perform when the user selects an item (clicks or enter).
|
||||
*/
|
||||
private TAction updateAction = null;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param parent parent widget
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param width visible combobox width, including the down-arrow
|
||||
* @param values the possible values for the box, shown in the drop-down
|
||||
* @param valuesIndex the initial index in values, or -1 for no default
|
||||
* value
|
||||
* @param valuesHeight the height of the values drop-down when it is
|
||||
* visible
|
||||
* @param updateAction action to call when a new value is selected from
|
||||
* the list or enter is pressed in the edit field
|
||||
*/
|
||||
public TComboBox(final TWidget parent, final int x, final int y,
|
||||
final int width, final List<String> values, final int valuesIndex,
|
||||
final int valuesHeight, final TAction updateAction) {
|
||||
|
||||
// Set parent and window
|
||||
super(parent, x, y, width, 1);
|
||||
|
||||
this.updateAction = updateAction;
|
||||
|
||||
field = new TField(this, 0, 0, width - 1, false, "",
|
||||
updateAction, null);
|
||||
if (valuesIndex >= 0) {
|
||||
field.setText(values.get(valuesIndex));
|
||||
}
|
||||
|
||||
list = new TList(this, values, 0, 1, width, valuesHeight,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
field.setText(list.getSelected());
|
||||
list.setEnabled(false);
|
||||
list.setVisible(false);
|
||||
TComboBox.this.setHeight(1);
|
||||
TComboBox.this.activate(field);
|
||||
if (updateAction != null) {
|
||||
updateAction.DO();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
list.setEnabled(false);
|
||||
list.setVisible(false);
|
||||
setHeight(1);
|
||||
activate(field);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Event handlers ---------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if the mouse is currently on the down arrow.
|
||||
*
|
||||
* @param mouse mouse event
|
||||
* @return true if the mouse is currently on the down arrow
|
||||
*/
|
||||
private boolean mouseOnArrow(final TMouseEvent mouse) {
|
||||
if ((mouse.getY() == 0)
|
||||
&& (mouse.getX() == getWidth() - 1)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse down clicks.
|
||||
*
|
||||
* @param mouse mouse button down event
|
||||
*/
|
||||
@Override
|
||||
public void onMouseDown(final TMouseEvent mouse) {
|
||||
if ((mouseOnArrow(mouse)) && (mouse.isMouse1())) {
|
||||
// Make the list visible or not.
|
||||
if (list.isActive()) {
|
||||
list.setEnabled(false);
|
||||
list.setVisible(false);
|
||||
setHeight(1);
|
||||
activate(field);
|
||||
} else {
|
||||
list.setEnabled(true);
|
||||
list.setVisible(true);
|
||||
setHeight(list.getHeight() + 1);
|
||||
activate(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keystrokes.
|
||||
*
|
||||
* @param keypress keystroke event
|
||||
*/
|
||||
@Override
|
||||
public void onKeypress(final TKeypressEvent keypress) {
|
||||
if (keypress.equals(kbAltDown)) {
|
||||
list.setEnabled(true);
|
||||
list.setVisible(true);
|
||||
setHeight(list.getHeight() + 1);
|
||||
activate(list);
|
||||
return;
|
||||
}
|
||||
|
||||
if (keypress.equals(kbTab)
|
||||
|| (keypress.equals(kbShiftTab))
|
||||
|| (keypress.equals(kbBackTab))
|
||||
) {
|
||||
if (list.isActive()) {
|
||||
list.setEnabled(false);
|
||||
list.setVisible(false);
|
||||
setHeight(1);
|
||||
activate(field);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass to parent for the things we don't care about.
|
||||
super.onKeypress(keypress);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// TWidget ----------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Draw the combobox down arrow.
|
||||
*/
|
||||
@Override
|
||||
public void draw() {
|
||||
CellAttributes comboBoxColor;
|
||||
|
||||
if (isAbsoluteActive()) {
|
||||
comboBoxColor = getTheme().getColor("tcombobox.active");
|
||||
} else {
|
||||
comboBoxColor = getTheme().getColor("tcombobox.inactive");
|
||||
}
|
||||
|
||||
getScreen().putCharXY(getWidth() - 1, 0, GraphicsChars.DOWNARROW,
|
||||
comboBoxColor);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// TComboBox --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get combobox text value.
|
||||
*
|
||||
* @return text in the edit field
|
||||
*/
|
||||
public String getText() {
|
||||
return field.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set combobox text value.
|
||||
*
|
||||
* @param text the new text in the edit field
|
||||
*/
|
||||
public void setText(final String text) {
|
||||
field.setText(text);
|
||||
for (int i = 0; i < list.getMaxSelectedIndex(); i++) {
|
||||
if (list.getSelected().equals(text)) {
|
||||
list.setSelectedIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
list.setSelectedIndex(-1);
|
||||
}
|
||||
|
||||
}
|
|
@ -35,7 +35,7 @@ import java.util.List;
|
|||
/**
|
||||
* TDirectoryList shows the files within a directory.
|
||||
*/
|
||||
public final class TDirectoryList extends TList {
|
||||
public class TDirectoryList extends TList {
|
||||
|
||||
/**
|
||||
* Files in the directory.
|
||||
|
|
|
@ -43,7 +43,7 @@ import static jexer.TKeypress.*;
|
|||
* TEditorWidget displays an editable text document. It is unaware of
|
||||
* scrolling behavior, but can respond to mouse and keyboard events.
|
||||
*/
|
||||
public final class TEditorWidget extends TWidget {
|
||||
public class TEditorWidget extends TWidget {
|
||||
|
||||
/**
|
||||
* The number of lines to scroll on mouse wheel up/down.
|
||||
|
|
|
@ -384,7 +384,7 @@ public class TField extends TWidget {
|
|||
*
|
||||
* @param text the new field text
|
||||
*/
|
||||
public final void setText(String text) {
|
||||
public void setText(final String text) {
|
||||
this.text = text;
|
||||
position = 0;
|
||||
windowStart = 0;
|
||||
|
|
|
@ -54,7 +54,7 @@ import static jexer.TKeypress.*;
|
|||
* </pre>
|
||||
*
|
||||
*/
|
||||
public final class TFileOpenBox extends TWindow {
|
||||
public class TFileOpenBox extends TWindow {
|
||||
|
||||
/**
|
||||
* Translated strings.
|
||||
|
|
|
@ -35,7 +35,7 @@ import jexer.event.TMouseEvent;
|
|||
/**
|
||||
* THScroller implements a simple horizontal scroll bar.
|
||||
*/
|
||||
public final class THScroller extends TWidget {
|
||||
public class THScroller extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -42,7 +42,7 @@ package jexer;
|
|||
* </pre>
|
||||
*
|
||||
*/
|
||||
public final class TInputBox extends TMessageBox {
|
||||
public class TInputBox extends TMessageBox {
|
||||
|
||||
/**
|
||||
* The input field.
|
||||
|
|
|
@ -31,7 +31,7 @@ package jexer;
|
|||
/**
|
||||
* This class represents keystrokes.
|
||||
*/
|
||||
public final class TKeypress {
|
||||
public class TKeypress {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
|
|
@ -33,7 +33,7 @@ import jexer.bits.CellAttributes;
|
|||
/**
|
||||
* TLabel implements a simple label.
|
||||
*/
|
||||
public final class TLabel extends TWidget {
|
||||
public class TLabel extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
@ -49,6 +49,11 @@ public final class TLabel extends TWidget {
|
|||
*/
|
||||
private String colorKey;
|
||||
|
||||
/**
|
||||
* If true, use the window's background color.
|
||||
*/
|
||||
private boolean useWindowBackground = true;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -79,11 +84,28 @@ public final class TLabel extends TWidget {
|
|||
public TLabel(final TWidget parent, final String text, final int x,
|
||||
final int y, final String colorKey) {
|
||||
|
||||
this(parent, text, x, y, colorKey, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param parent parent widget
|
||||
* @param text label on the screen
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param colorKey ColorTheme key color to use for foreground text
|
||||
* @param useWindowBackground if true, use the window's background color
|
||||
*/
|
||||
public TLabel(final TWidget parent, final String text, final int x,
|
||||
final int y, final String colorKey, final boolean useWindowBackground) {
|
||||
|
||||
// Set parent and window
|
||||
super(parent, false, x, y, text.length(), 1);
|
||||
|
||||
this.label = text;
|
||||
this.colorKey = colorKey;
|
||||
this.useWindowBackground = useWindowBackground;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -98,9 +120,10 @@ public final class TLabel extends TWidget {
|
|||
// Setup my color
|
||||
CellAttributes color = new CellAttributes();
|
||||
color.setTo(getTheme().getColor(colorKey));
|
||||
CellAttributes background = getWindow().getBackground();
|
||||
color.setBackColor(background.getBackColor());
|
||||
|
||||
if (useWindowBackground) {
|
||||
CellAttributes background = getWindow().getBackground();
|
||||
color.setBackColor(background.getBackColor());
|
||||
}
|
||||
getScreen().putStringXY(0, 0, label, color);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import jexer.bits.GraphicsChars;
|
|||
/**
|
||||
* TField implements an editable text field.
|
||||
*/
|
||||
public final class TPasswordField extends TField {
|
||||
public class TPasswordField extends TField {
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
|
|
|
@ -34,7 +34,7 @@ import jexer.bits.GraphicsChars;
|
|||
/**
|
||||
* TProgressBar implements a simple progress bar.
|
||||
*/
|
||||
public final class TProgressBar extends TWidget {
|
||||
public class TProgressBar extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -37,7 +37,7 @@ import static jexer.TKeypress.*;
|
|||
/**
|
||||
* TRadioButton implements a selectable radio button.
|
||||
*/
|
||||
public final class TRadioButton extends TWidget {
|
||||
public class TRadioButton extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -33,7 +33,7 @@ import jexer.bits.CellAttributes;
|
|||
/**
|
||||
* TRadioGroup is a collection of TRadioButtons with a box and label.
|
||||
*/
|
||||
public final class TRadioGroup extends TWidget {
|
||||
public class TRadioGroup extends TWidget {
|
||||
|
||||
/**
|
||||
* Label for this radio button group.
|
||||
|
|
193
src/jexer/TSpinner.java
Normal file
193
src/jexer/TSpinner.java
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Jexer - Java Text User Interface
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2017 Kevin Lamonte
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @author Kevin Lamonte [kevin.lamonte@gmail.com]
|
||||
* @version 1
|
||||
*/
|
||||
package jexer;
|
||||
|
||||
import jexer.bits.CellAttributes;
|
||||
import jexer.bits.GraphicsChars;
|
||||
import jexer.event.TKeypressEvent;
|
||||
import jexer.event.TMouseEvent;
|
||||
import static jexer.TKeypress.*;
|
||||
|
||||
/**
|
||||
* TSpinner implements a simple up/down spinner. Values can be numer
|
||||
*/
|
||||
public class TSpinner extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The action to perform when the user clicks on the up arrow.
|
||||
*/
|
||||
private TAction upAction = null;
|
||||
|
||||
/**
|
||||
* The action to perform when the user clicks on the down arrow.
|
||||
*/
|
||||
private TAction downAction = null;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param parent parent widget
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param upAction action to call when the up arrow is clicked or pressed
|
||||
* @param downAction action to call when the down arrow is clicked or
|
||||
* pressed
|
||||
*/
|
||||
public TSpinner(final TWidget parent, final int x, final int y,
|
||||
final TAction upAction, final TAction downAction) {
|
||||
|
||||
// Set parent and window
|
||||
super(parent, x, y, 2, 1);
|
||||
|
||||
this.upAction = upAction;
|
||||
this.downAction = downAction;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Event handlers ---------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if the mouse is currently on the up arrow.
|
||||
*
|
||||
* @param mouse mouse event
|
||||
* @return true if the mouse is currently on the up arrow
|
||||
*/
|
||||
private boolean mouseOnUpArrow(final TMouseEvent mouse) {
|
||||
if ((mouse.getY() == 0)
|
||||
&& (mouse.getX() == getWidth() - 1)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mouse is currently on the down arrow.
|
||||
*
|
||||
* @param mouse mouse event
|
||||
* @return true if the mouse is currently on the down arrow
|
||||
*/
|
||||
private boolean mouseOnDownArrow(final TMouseEvent mouse) {
|
||||
if ((mouse.getY() == 0)
|
||||
&& (mouse.getX() == getWidth() - 2)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse checkbox presses.
|
||||
*
|
||||
* @param mouse mouse button down event
|
||||
*/
|
||||
@Override
|
||||
public void onMouseDown(final TMouseEvent mouse) {
|
||||
if ((mouseOnUpArrow(mouse)) && (mouse.isMouse1())) {
|
||||
up();
|
||||
} else if ((mouseOnDownArrow(mouse)) && (mouse.isMouse1())) {
|
||||
down();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keystrokes.
|
||||
*
|
||||
* @param keypress keystroke event
|
||||
*/
|
||||
@Override
|
||||
public void onKeypress(final TKeypressEvent keypress) {
|
||||
if (keypress.equals(kbUp)) {
|
||||
up();
|
||||
return;
|
||||
}
|
||||
if (keypress.equals(kbDown)) {
|
||||
down();
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass to parent for the things we don't care about.
|
||||
super.onKeypress(keypress);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// TWidget ----------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Draw the spinner arrows.
|
||||
*/
|
||||
@Override
|
||||
public void draw() {
|
||||
CellAttributes spinnerColor;
|
||||
|
||||
if (isAbsoluteActive()) {
|
||||
spinnerColor = getTheme().getColor("tspinner.active");
|
||||
} else {
|
||||
spinnerColor = getTheme().getColor("tspinner.inactive");
|
||||
}
|
||||
|
||||
getScreen().putCharXY(getWidth() - 2, 0, GraphicsChars.UPARROW,
|
||||
spinnerColor);
|
||||
getScreen().putCharXY(getWidth() - 1, 0, GraphicsChars.DOWNARROW,
|
||||
spinnerColor);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// TSpinner ---------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Perform the "up" action.
|
||||
*/
|
||||
private void up() {
|
||||
if (upAction != null) {
|
||||
upAction.DO();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the "down" action.
|
||||
*/
|
||||
private void down() {
|
||||
if (downAction != null) {
|
||||
downAction.DO();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -40,7 +40,7 @@ import jexer.event.TMouseEvent;
|
|||
/**
|
||||
* TStatusBar implements a status line with clickable buttons.
|
||||
*/
|
||||
public final class TStatusBar extends TWidget {
|
||||
public class TStatusBar extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -417,8 +417,18 @@ public class TTerminalWindow extends TScrollableWindow
|
|||
boolean reverse = line.isReverseColor() ^ ch.isReverse();
|
||||
newCell.setReverse(false);
|
||||
if (reverse) {
|
||||
newCell.setBackColor(ch.getForeColor());
|
||||
newCell.setForeColor(ch.getBackColor());
|
||||
if (ch.getForeColorRGB() < 0) {
|
||||
newCell.setBackColor(ch.getForeColor());
|
||||
newCell.setBackColorRGB(-1);
|
||||
} else {
|
||||
newCell.setBackColorRGB(ch.getForeColorRGB());
|
||||
}
|
||||
if (ch.getBackColorRGB() < 0) {
|
||||
newCell.setForeColor(ch.getBackColor());
|
||||
newCell.setForeColorRGB(-1);
|
||||
} else {
|
||||
newCell.setForeColorRGB(ch.getBackColorRGB());
|
||||
}
|
||||
}
|
||||
if (line.isDoubleWidth()) {
|
||||
getScreen().putCharXY((i * 2) + 1, row, newCell);
|
||||
|
|
|
@ -40,7 +40,7 @@ import static jexer.TKeypress.*;
|
|||
* TText implements a simple scrollable text area. It reflows automatically on
|
||||
* resize.
|
||||
*/
|
||||
public final class TText extends TScrollableWidget {
|
||||
public class TText extends TScrollableWidget {
|
||||
|
||||
/**
|
||||
* Available text justifications.
|
||||
|
|
|
@ -33,7 +33,7 @@ import java.util.Date;
|
|||
/**
|
||||
* TTimer implements a simple timer.
|
||||
*/
|
||||
public final class TTimer {
|
||||
public class TTimer {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -35,7 +35,7 @@ import jexer.event.TMouseEvent;
|
|||
/**
|
||||
* TVScroller implements a simple vertical scroll bar.
|
||||
*/
|
||||
public final class TVScroller extends TWidget {
|
||||
public class TVScroller extends TWidget {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -58,8 +58,8 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
|
||||
/**
|
||||
* Every widget has a parent widget that it may be "contained" in. For
|
||||
* example, a TWindow might contain several TTextFields, or a TComboBox
|
||||
* may contain a TScrollBar.
|
||||
* example, a TWindow might contain several TFields, or a TComboBox may
|
||||
* contain a TList that itself contains a TVScroller.
|
||||
*/
|
||||
private TWidget parent = null;
|
||||
|
||||
|
@ -113,6 +113,11 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* If true, this widget will be rendered.
|
||||
*/
|
||||
private boolean visible = true;
|
||||
|
||||
/**
|
||||
* If true, this widget has a cursor.
|
||||
*/
|
||||
|
@ -710,6 +715,24 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visible flag.
|
||||
*
|
||||
* @param visible if true, this widget will be drawn
|
||||
*/
|
||||
public final void setVisible(final boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if this widget is visible.
|
||||
*
|
||||
* @return if true, this widget will be drawn
|
||||
*/
|
||||
public final boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visible cursor flag.
|
||||
*
|
||||
|
@ -972,14 +995,16 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
|
||||
// Continue down the chain
|
||||
for (TWidget widget: children) {
|
||||
widget.drawChildren();
|
||||
if (widget.isVisible()) {
|
||||
widget.drawChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaint the screen on the next update.
|
||||
*/
|
||||
public void doRepaint() {
|
||||
public final void doRepaint() {
|
||||
window.getApplication().doRepaint();
|
||||
}
|
||||
|
||||
|
@ -1164,13 +1189,30 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
return new TLabel(this, text, x, y, colorKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add a label to this container/window.
|
||||
*
|
||||
* @param text label
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param colorKey ColorTheme key color to use for foreground text.
|
||||
* Default is "tlabel"
|
||||
* @param useWindowBackground if true, use the window's background color
|
||||
* @return the new label
|
||||
*/
|
||||
public final TLabel addLabel(final String text, final int x, final int y,
|
||||
final String colorKey, final boolean useWindowBackground) {
|
||||
|
||||
return new TLabel(this, text, x, y, colorKey, useWindowBackground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add a button to this container/window.
|
||||
*
|
||||
* @param text label on the button
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param action to call when button is pressed
|
||||
* @param action action to call when button is pressed
|
||||
* @return the new button
|
||||
*/
|
||||
public final TButton addButton(final String text, final int x, final int y,
|
||||
|
@ -1188,10 +1230,64 @@ public abstract class TWidget implements Comparable<TWidget> {
|
|||
* @param checked initial check state
|
||||
* @return the new checkbox
|
||||
*/
|
||||
public final TCheckbox addCheckbox(final int x, final int y,
|
||||
public final TCheckBox addCheckBox(final int x, final int y,
|
||||
final String label, final boolean checked) {
|
||||
|
||||
return new TCheckbox(this, x, y, label, checked);
|
||||
return new TCheckBox(this, x, y, label, checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add a combobox to this container/window.
|
||||
*
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param width visible combobox width, including the down-arrow
|
||||
* @param values the possible values for the box, shown in the drop-down
|
||||
* @param valuesIndex the initial index in values, or -1 for no default
|
||||
* value
|
||||
* @param valuesHeight the height of the values drop-down when it is
|
||||
* visible
|
||||
* @param updateAction action to call when a new value is selected from
|
||||
* the list or enter is pressed in the edit field
|
||||
* @return the new combobox
|
||||
*/
|
||||
public final TComboBox addComboBox(final int x, final int y,
|
||||
final int width, final List<String> values, final int valuesIndex,
|
||||
final int valuesHeight, final TAction updateAction) {
|
||||
|
||||
return new TComboBox(this, x, y, width, values, valuesIndex,
|
||||
valuesHeight, updateAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add a spinner to this container/window.
|
||||
*
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param upAction action to call when the up arrow is clicked or pressed
|
||||
* @param downAction action to call when the down arrow is clicked or
|
||||
* pressed
|
||||
* @return the new spinner
|
||||
*/
|
||||
public final TSpinner addSpinner(final int x, final int y,
|
||||
final TAction upAction, final TAction downAction) {
|
||||
|
||||
return new TSpinner(this, x, y, upAction, downAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to add a calendar to this container/window.
|
||||
*
|
||||
* @param x column relative to parent
|
||||
* @param y row relative to parent
|
||||
* @param updateAction action to call when the user changes the value of
|
||||
* the calendar
|
||||
* @return the new calendar
|
||||
*/
|
||||
public final TCalendar addCalendar(final int x, final int y,
|
||||
final TAction updateAction) {
|
||||
|
||||
return new TCalendar(this, x, y, updateAction);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.io.UnsupportedEncodingException;
|
|||
* This class uses an xterm/ANSI X3.64/ECMA-48 type terminal to provide a
|
||||
* screen, keyboard, and mouse to TApplication.
|
||||
*/
|
||||
public final class ECMA48Backend extends GenericBackend {
|
||||
public class ECMA48Backend extends GenericBackend {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
|
|
|
@ -56,8 +56,8 @@ import static jexer.TKeypress.*;
|
|||
* This class reads keystrokes and mouse events and emits output to ANSI
|
||||
* X3.64 / ECMA-48 type terminals e.g. xterm, linux, vt100, ansi.sys, etc.
|
||||
*/
|
||||
public final class ECMA48Terminal extends LogicalScreen
|
||||
implements TerminalReader, Runnable {
|
||||
public class ECMA48Terminal extends LogicalScreen
|
||||
implements TerminalReader, Runnable {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
@ -86,8 +86,9 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
private boolean debugToStderr = false;
|
||||
|
||||
/**
|
||||
* If true, emit T.416-style RGB colors. This is a) expensive in
|
||||
* bandwidth, and b) potentially terrible looking for non-xterms.
|
||||
* If true, emit T.416-style RGB colors for normal system colors. This
|
||||
* is a) expensive in bandwidth, and b) potentially terrible looking for
|
||||
* non-xterms.
|
||||
*/
|
||||
private static boolean doRgbColor = false;
|
||||
|
||||
|
@ -797,6 +798,7 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
// Now emit only the modified attributes
|
||||
if ((lCell.getForeColor() != lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() != lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
|
@ -809,8 +811,25 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
if (debugToStderr) {
|
||||
System.err.printf("1 Change only fore/back colors\n");
|
||||
}
|
||||
|
||||
} else if (lCell.isRGB()
|
||||
&& (lCell.getForeColorRGB() != lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() != lastAttr.getBackColorRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Both colors changed, attributes the same
|
||||
sb.append(colorRGB(lCell.getForeColorRGB(),
|
||||
lCell.getBackColorRGB()));
|
||||
|
||||
if (debugToStderr) {
|
||||
System.err.printf("1 Change only fore/back colors (RGB)\n");
|
||||
}
|
||||
} else if ((lCell.getForeColor() != lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() != lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() != lastAttr.isBold())
|
||||
&& (lCell.isReverse() != lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() != lastAttr.isUnderline())
|
||||
|
@ -828,6 +847,7 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
}
|
||||
} else if ((lCell.getForeColor() != lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() == lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
|
@ -841,8 +861,25 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
if (debugToStderr) {
|
||||
System.err.printf("3 Change foreColor\n");
|
||||
}
|
||||
} else if (lCell.isRGB()
|
||||
&& (lCell.getForeColorRGB() != lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() == lastAttr.getBackColorRGB())
|
||||
&& (lCell.getForeColorRGB() >= 0)
|
||||
&& (lCell.getBackColorRGB() >= 0)
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Attributes same, foreColor different
|
||||
sb.append(colorRGB(lCell.getForeColorRGB(), true));
|
||||
|
||||
if (debugToStderr) {
|
||||
System.err.printf("3 Change foreColor (RGB)\n");
|
||||
}
|
||||
} else if ((lCell.getForeColor() == lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() != lastAttr.getBackColor())
|
||||
&& (!lCell.isRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
|
@ -855,8 +892,24 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
if (debugToStderr) {
|
||||
System.err.printf("4 Change backColor\n");
|
||||
}
|
||||
} else if (lCell.isRGB()
|
||||
&& (lCell.getForeColorRGB() == lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() != lastAttr.getBackColorRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
&& (lCell.isBlink() == lastAttr.isBlink())
|
||||
) {
|
||||
// Attributes same, foreColor different
|
||||
sb.append(colorRGB(lCell.getBackColorRGB(), false));
|
||||
|
||||
if (debugToStderr) {
|
||||
System.err.printf("4 Change backColor (RGB)\n");
|
||||
}
|
||||
} else if ((lCell.getForeColor() == lastAttr.getForeColor())
|
||||
&& (lCell.getBackColor() == lastAttr.getBackColor())
|
||||
&& (lCell.getForeColorRGB() == lastAttr.getForeColorRGB())
|
||||
&& (lCell.getBackColorRGB() == lastAttr.getBackColorRGB())
|
||||
&& (lCell.isBold() == lastAttr.isBold())
|
||||
&& (lCell.isReverse() == lastAttr.isReverse())
|
||||
&& (lCell.isUnderline() == lastAttr.isUnderline())
|
||||
|
@ -871,16 +924,29 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
}
|
||||
} else {
|
||||
// Just reset everything again
|
||||
sb.append(color(lCell.getForeColor(),
|
||||
lCell.getBackColor(),
|
||||
lCell.isBold(),
|
||||
lCell.isReverse(),
|
||||
lCell.isBlink(),
|
||||
lCell.isUnderline()));
|
||||
if (!lCell.isRGB()) {
|
||||
sb.append(color(lCell.getForeColor(),
|
||||
lCell.getBackColor(),
|
||||
lCell.isBold(),
|
||||
lCell.isReverse(),
|
||||
lCell.isBlink(),
|
||||
lCell.isUnderline()));
|
||||
|
||||
if (debugToStderr) {
|
||||
System.err.printf("6 Change all attributes\n");
|
||||
if (debugToStderr) {
|
||||
System.err.printf("6 Change all attributes\n");
|
||||
}
|
||||
} else {
|
||||
sb.append(colorRGB(lCell.getForeColorRGB(),
|
||||
lCell.getBackColorRGB(),
|
||||
lCell.isBold(),
|
||||
lCell.isReverse(),
|
||||
lCell.isBlink(),
|
||||
lCell.isUnderline()));
|
||||
if (debugToStderr) {
|
||||
System.err.printf("6 Change all attributes (RGB)\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Emit the character
|
||||
sb.append(lCell.getChar());
|
||||
|
@ -1694,6 +1760,55 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
rgbColor(bold, color, foreground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a T.416 RGB parameter sequence for a single color change.
|
||||
*
|
||||
* @param colorRGB a 24-bit RGB value for foreground color
|
||||
* @param foreground if true, this is a foreground color
|
||||
* @return the string to emit to an ANSI / ECMA-style terminal,
|
||||
* e.g. "\033[42m"
|
||||
*/
|
||||
private String colorRGB(final int colorRGB, final boolean foreground) {
|
||||
|
||||
int colorRed = (colorRGB >> 16) & 0xFF;
|
||||
int colorGreen = (colorRGB >> 8) & 0xFF;
|
||||
int colorBlue = colorRGB & 0xFF;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (foreground) {
|
||||
sb.append("\033[38;2;");
|
||||
} else {
|
||||
sb.append("\033[48;2;");
|
||||
}
|
||||
sb.append(String.format("%d;%d;%dm", colorRed, colorGreen, colorBlue));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a T.416 RGB parameter sequence for both foreground and
|
||||
* background color change.
|
||||
*
|
||||
* @param foreColorRGB a 24-bit RGB value for foreground color
|
||||
* @param backColorRGB a 24-bit RGB value for foreground color
|
||||
* @return the string to emit to an ANSI / ECMA-style terminal,
|
||||
* e.g. "\033[42m"
|
||||
*/
|
||||
private String colorRGB(final int foreColorRGB, final int backColorRGB) {
|
||||
int foreColorRed = (foreColorRGB >> 16) & 0xFF;
|
||||
int foreColorGreen = (foreColorRGB >> 8) & 0xFF;
|
||||
int foreColorBlue = foreColorRGB & 0xFF;
|
||||
int backColorRed = (backColorRGB >> 16) & 0xFF;
|
||||
int backColorGreen = (backColorRGB >> 8) & 0xFF;
|
||||
int backColorBlue = backColorRGB & 0xFF;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(String.format("\033[38;2;%d;%d;%dm",
|
||||
foreColorRed, foreColorGreen, foreColorBlue));
|
||||
sb.append(String.format("\033[48;2;%d;%d;%dm",
|
||||
backColorRed, backColorGreen, backColorBlue));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a T.416 RGB parameter sequence for a single color change.
|
||||
*
|
||||
|
@ -1915,6 +2030,77 @@ public final class ECMA48Terminal extends LogicalScreen
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SGR parameter sequence for foreground, background, and
|
||||
* several attributes. This sequence first resets all attributes to
|
||||
* default, then sets attributes as per the parameters.
|
||||
*
|
||||
* @param foreColorRGB a 24-bit RGB value for foreground color
|
||||
* @param backColorRGB a 24-bit RGB value for foreground color
|
||||
* @param bold if true, set bold
|
||||
* @param reverse if true, set reverse
|
||||
* @param blink if true, set blink
|
||||
* @param underline if true, set underline
|
||||
* @return the string to emit to an ANSI / ECMA-style terminal,
|
||||
* e.g. "\033[0;1;31;42m"
|
||||
*/
|
||||
private String colorRGB(final int foreColorRGB, final int backColorRGB,
|
||||
final boolean bold, final boolean reverse, final boolean blink,
|
||||
final boolean underline) {
|
||||
|
||||
int foreColorRed = (foreColorRGB >> 16) & 0xFF;
|
||||
int foreColorGreen = (foreColorRGB >> 8) & 0xFF;
|
||||
int foreColorBlue = foreColorRGB & 0xFF;
|
||||
int backColorRed = (backColorRGB >> 16) & 0xFF;
|
||||
int backColorGreen = (backColorRGB >> 8) & 0xFF;
|
||||
int backColorBlue = backColorRGB & 0xFF;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if ( bold && reverse && blink && !underline ) {
|
||||
sb.append("\033[0;1;7;5;");
|
||||
} else if ( bold && reverse && !blink && !underline ) {
|
||||
sb.append("\033[0;1;7;");
|
||||
} else if ( !bold && reverse && blink && !underline ) {
|
||||
sb.append("\033[0;7;5;");
|
||||
} else if ( bold && !reverse && blink && !underline ) {
|
||||
sb.append("\033[0;1;5;");
|
||||
} else if ( bold && !reverse && !blink && !underline ) {
|
||||
sb.append("\033[0;1;");
|
||||
} else if ( !bold && reverse && !blink && !underline ) {
|
||||
sb.append("\033[0;7;");
|
||||
} else if ( !bold && !reverse && blink && !underline) {
|
||||
sb.append("\033[0;5;");
|
||||
} else if ( bold && reverse && blink && underline ) {
|
||||
sb.append("\033[0;1;7;5;4;");
|
||||
} else if ( bold && reverse && !blink && underline ) {
|
||||
sb.append("\033[0;1;7;4;");
|
||||
} else if ( !bold && reverse && blink && underline ) {
|
||||
sb.append("\033[0;7;5;4;");
|
||||
} else if ( bold && !reverse && blink && underline ) {
|
||||
sb.append("\033[0;1;5;4;");
|
||||
} else if ( bold && !reverse && !blink && underline ) {
|
||||
sb.append("\033[0;1;4;");
|
||||
} else if ( !bold && reverse && !blink && underline ) {
|
||||
sb.append("\033[0;7;4;");
|
||||
} else if ( !bold && !reverse && blink && underline) {
|
||||
sb.append("\033[0;5;4;");
|
||||
} else if ( !bold && !reverse && !blink && underline) {
|
||||
sb.append("\033[0;4;");
|
||||
} else {
|
||||
assert (!bold && !reverse && !blink && !underline);
|
||||
sb.append("\033[0;");
|
||||
}
|
||||
|
||||
sb.append("m\033[38;2;");
|
||||
sb.append(String.format("%d;%d;%d", foreColorRed, foreColorGreen,
|
||||
foreColorBlue));
|
||||
sb.append("m\033[48;2;");
|
||||
sb.append(String.format("%d;%d;%d", backColorRed, backColorGreen,
|
||||
backColorBlue));
|
||||
sb.append("m");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SGR parameter sequence to reset to defaults.
|
||||
*
|
||||
|
|
|
@ -35,7 +35,7 @@ import javax.swing.JComponent;
|
|||
* This class uses standard Swing calls to handle screen, keyboard, and mouse
|
||||
* I/O.
|
||||
*/
|
||||
public final class SwingBackend extends GenericBackend {
|
||||
public class SwingBackend extends GenericBackend {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
|
|
|
@ -71,6 +71,17 @@ class SwingComponent {
|
|||
*/
|
||||
private JComponent component;
|
||||
|
||||
/**
|
||||
* An optional border in pixels to add.
|
||||
*/
|
||||
private static final int BORDER = 5;
|
||||
|
||||
/**
|
||||
* Adjustable Insets for this component. This has the effect of adding a
|
||||
* black border around the drawing area.
|
||||
*/
|
||||
Insets adjustInsets = new Insets(BORDER, BORDER, BORDER, BORDER);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -237,11 +248,17 @@ class SwingComponent {
|
|||
* @return the value of the insets property
|
||||
*/
|
||||
public Insets getInsets() {
|
||||
Insets swingInsets = null;
|
||||
if (frame != null) {
|
||||
return frame.getInsets();
|
||||
swingInsets = frame.getInsets();
|
||||
} else {
|
||||
return component.getInsets();
|
||||
swingInsets = component.getInsets();
|
||||
}
|
||||
Insets result = new Insets(swingInsets.top + adjustInsets.top,
|
||||
swingInsets.left + adjustInsets.left,
|
||||
swingInsets.bottom + adjustInsets.bottom,
|
||||
swingInsets.right + adjustInsets.right);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -348,12 +365,12 @@ class SwingComponent {
|
|||
public void setDimensions(final int width, final int height) {
|
||||
// Figure out the thickness of borders and use that to set the final
|
||||
// size.
|
||||
Insets insets = getInsets();
|
||||
|
||||
if (frame != null) {
|
||||
Insets insets = frame.getInsets();
|
||||
frame.setSize(width + insets.left + insets.right,
|
||||
height + insets.top + insets.bottom);
|
||||
} else {
|
||||
Insets insets = component.getInsets();
|
||||
component.setSize(width + insets.left + insets.right,
|
||||
height + insets.top + insets.bottom);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import java.awt.Insets;
|
|||
* Swing to support queryWindowSize(). The username is blank, language is
|
||||
* "en_US", with a 80x25 text window.
|
||||
*/
|
||||
public final class SwingSessionInfo implements SessionInfo {
|
||||
public class SwingSessionInfo implements SessionInfo {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -80,11 +80,11 @@ import static jexer.TKeypress.*;
|
|||
* and uses a SwingComponent wrapper class to call the JFrame or JComponent
|
||||
* methods.
|
||||
*/
|
||||
public final class SwingTerminal extends LogicalScreen
|
||||
implements TerminalReader,
|
||||
ComponentListener, KeyListener,
|
||||
MouseListener, MouseMotionListener,
|
||||
MouseWheelListener, WindowListener {
|
||||
public class SwingTerminal extends LogicalScreen
|
||||
implements TerminalReader,
|
||||
ComponentListener, KeyListener,
|
||||
MouseListener, MouseMotionListener,
|
||||
MouseWheelListener, WindowListener {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
@ -742,6 +742,15 @@ public final class SwingTerminal extends LogicalScreen
|
|||
* @return the Swing Color
|
||||
*/
|
||||
private Color attrToForegroundColor(final CellAttributes attr) {
|
||||
int rgb = attr.getForeColorRGB();
|
||||
if (rgb >= 0) {
|
||||
int red = (rgb >> 16) & 0xFF;
|
||||
int green = (rgb >> 8) & 0xFF;
|
||||
int blue = rgb & 0xFF;
|
||||
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
if (attr.isBold()) {
|
||||
if (attr.getForeColor().equals(jexer.bits.Color.BLACK)) {
|
||||
return MYBOLD_BLACK;
|
||||
|
@ -790,6 +799,15 @@ public final class SwingTerminal extends LogicalScreen
|
|||
* @return the Swing Color
|
||||
*/
|
||||
private Color attrToBackgroundColor(final CellAttributes attr) {
|
||||
int rgb = attr.getBackColorRGB();
|
||||
if (rgb >= 0) {
|
||||
int red = (rgb >> 16) & 0xFF;
|
||||
int green = (rgb >> 8) & 0xFF;
|
||||
int blue = rgb & 0xFF;
|
||||
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
if (attr.getBackColor().equals(jexer.bits.Color.BLACK)) {
|
||||
return MYBLACK;
|
||||
} else if (attr.getBackColor().equals(jexer.bits.Color.RED)) {
|
||||
|
@ -1106,7 +1124,8 @@ public final class SwingTerminal extends LogicalScreen
|
|||
*/
|
||||
}
|
||||
|
||||
if ((swing.getBufferStrategy() != null)
|
||||
if ((swing.getFrame() != null)
|
||||
&& (swing.getBufferStrategy() != null)
|
||||
&& (SwingUtilities.isEventDispatchThread())
|
||||
) {
|
||||
// System.err.println("paint(), skip first paint on swing thread");
|
||||
|
|
|
@ -32,7 +32,7 @@ package jexer.backend;
|
|||
* TSessionInfo provides a default session implementation. The username is
|
||||
* blank, language is "en_US", with a 80x24 text window.
|
||||
*/
|
||||
public final class TSessionInfo implements SessionInfo {
|
||||
public class TSessionInfo implements SessionInfo {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.util.StringTokenizer;
|
|||
* the session information. The username is taken from user.name, language
|
||||
* is taken from user.language, and text window size from 'stty size'.
|
||||
*/
|
||||
public final class TTYSessionInfo implements SessionInfo {
|
||||
public class TTYSessionInfo implements SessionInfo {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -114,6 +114,7 @@ public final class Cell extends CellAttributes {
|
|||
&& !isReverse()
|
||||
&& !isUnderline()
|
||||
&& !isProtect()
|
||||
&& !isRGB()
|
||||
&& (ch == ' ')
|
||||
) {
|
||||
return true;
|
||||
|
|
|
@ -72,6 +72,16 @@ public class CellAttributes {
|
|||
*/
|
||||
private Color backColor;
|
||||
|
||||
/**
|
||||
* Foreground color as 24-bit RGB value. Negative value means not set.
|
||||
*/
|
||||
private int foreColorRGB = -1;
|
||||
|
||||
/**
|
||||
* Background color as 24-bit RGB value. Negative value means not set.
|
||||
*/
|
||||
private int backColorRGB = -1;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -226,18 +236,65 @@ public class CellAttributes {
|
|||
this.backColor = backColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for foreColor RGB.
|
||||
*
|
||||
* @return foreColor value. Negative means unset.
|
||||
*/
|
||||
public final int getForeColorRGB() {
|
||||
return foreColorRGB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for foreColor RGB.
|
||||
*
|
||||
* @param foreColor new foreColor RGB value
|
||||
*/
|
||||
public final void setForeColorRGB(final int foreColorRGB) {
|
||||
this.foreColorRGB = foreColorRGB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for backColor RGB.
|
||||
*
|
||||
* @return backColor value. Negative means unset.
|
||||
*/
|
||||
public final int getBackColorRGB() {
|
||||
return backColorRGB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for backColor RGB.
|
||||
*
|
||||
* @param backColor new backColor RGB value
|
||||
*/
|
||||
public final void setBackColorRGB(final int backColorRGB) {
|
||||
this.backColorRGB = backColorRGB;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if this cell uses RGB or ANSI colors.
|
||||
*
|
||||
* @return true if this cell has a RGB color
|
||||
*/
|
||||
public final boolean isRGB() {
|
||||
return (foreColorRGB >= 0) || (backColorRGB >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to default: white foreground on black background, no
|
||||
* bold/underline/blink/rever/protect.
|
||||
*/
|
||||
public void reset() {
|
||||
bold = false;
|
||||
blink = false;
|
||||
reverse = false;
|
||||
underline = false;
|
||||
protect = false;
|
||||
foreColor = Color.WHITE;
|
||||
backColor = Color.BLACK;
|
||||
bold = false;
|
||||
blink = false;
|
||||
reverse = false;
|
||||
underline = false;
|
||||
protect = false;
|
||||
foreColor = Color.WHITE;
|
||||
backColor = Color.BLACK;
|
||||
foreColorRGB = -1;
|
||||
backColorRGB = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -255,6 +312,8 @@ public class CellAttributes {
|
|||
CellAttributes that = (CellAttributes) rhs;
|
||||
return ((foreColor == that.foreColor)
|
||||
&& (backColor == that.backColor)
|
||||
&& (foreColorRGB == that.foreColorRGB)
|
||||
&& (backColorRGB == that.backColorRGB)
|
||||
&& (bold == that.bold)
|
||||
&& (reverse == that.reverse)
|
||||
&& (underline == that.underline)
|
||||
|
@ -279,6 +338,8 @@ public class CellAttributes {
|
|||
hash = (B * hash) + (protect ? 1 : 0);
|
||||
hash = (B * hash) + foreColor.hashCode();
|
||||
hash = (B * hash) + backColor.hashCode();
|
||||
hash = (B * hash) + foreColorRGB;
|
||||
hash = (B * hash) + backColorRGB;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
@ -290,13 +351,15 @@ public class CellAttributes {
|
|||
public void setTo(final Object rhs) {
|
||||
CellAttributes that = (CellAttributes) rhs;
|
||||
|
||||
this.bold = that.bold;
|
||||
this.blink = that.blink;
|
||||
this.reverse = that.reverse;
|
||||
this.underline = that.underline;
|
||||
this.protect = that.protect;
|
||||
this.foreColor = that.foreColor;
|
||||
this.backColor = that.backColor;
|
||||
this.bold = that.bold;
|
||||
this.blink = that.blink;
|
||||
this.reverse = that.reverse;
|
||||
this.underline = that.underline;
|
||||
this.protect = that.protect;
|
||||
this.foreColor = that.foreColor;
|
||||
this.backColor = that.backColor;
|
||||
this.foreColorRGB = that.foreColorRGB;
|
||||
this.backColorRGB = that.backColorRGB;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -306,6 +369,11 @@ public class CellAttributes {
|
|||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if ((foreColorRGB >= 0) || (backColorRGB >= 0)) {
|
||||
return String.format("RGB: #%06x on #%06x",
|
||||
(foreColorRGB & 0xFFFFFF),
|
||||
(backColorRGB & 0xFFFFFF));
|
||||
}
|
||||
return String.format("%s%s%s on %s", (bold == true ? "bold " : ""),
|
||||
(blink == true ? "blink " : ""), foreColor, backColor);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import java.util.TreeMap;
|
|||
* ColorTheme is a collection of colors keyed by string. A default theme is
|
||||
* also provided that matches the blue-and-white theme used by Turbo Vision.
|
||||
*/
|
||||
public final class ColorTheme {
|
||||
public class ColorTheme {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
@ -146,6 +146,37 @@ public final class ColorTheme {
|
|||
|
||||
StringTokenizer tokenizer = new StringTokenizer(text);
|
||||
token = tokenizer.nextToken();
|
||||
|
||||
if (token.toLowerCase().equals("rgb:")) {
|
||||
// Foreground
|
||||
int foreColorRGB = -1;
|
||||
try {
|
||||
foreColorRGB = Integer.parseInt(tokenizer.nextToken(), 16);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// "on"
|
||||
if (!tokenizer.nextToken().toLowerCase().equals("on")) {
|
||||
// Invalid line.
|
||||
return;
|
||||
}
|
||||
|
||||
// Background
|
||||
int backColorRGB = -1;
|
||||
try {
|
||||
backColorRGB = Integer.parseInt(tokenizer.nextToken(), 16);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
CellAttributes color = new CellAttributes();
|
||||
color.setForeColorRGB(foreColorRGB);
|
||||
color.setBackColorRGB(backColorRGB);
|
||||
colors.put(key, color);
|
||||
return;
|
||||
}
|
||||
|
||||
while (token.equals("bold") || token.equals("blink")) {
|
||||
if (token.equals("bold")) {
|
||||
bold = true;
|
||||
|
@ -350,7 +381,7 @@ public final class ColorTheme {
|
|||
color.setBold(true);
|
||||
colors.put("tfield.active", color);
|
||||
|
||||
// TCheckbox
|
||||
// TCheckBox
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.WHITE);
|
||||
color.setBackColor(Color.BLUE);
|
||||
|
@ -362,6 +393,57 @@ public final class ColorTheme {
|
|||
color.setBold(true);
|
||||
colors.put("tcheckbox.active", color);
|
||||
|
||||
// TComboBox
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.BLACK);
|
||||
color.setBackColor(Color.WHITE);
|
||||
color.setBold(false);
|
||||
colors.put("tcombobox.inactive", color);
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.BLUE);
|
||||
color.setBackColor(Color.CYAN);
|
||||
color.setBold(false);
|
||||
colors.put("tcombobox.active", color);
|
||||
|
||||
// TSpinner
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.BLACK);
|
||||
color.setBackColor(Color.WHITE);
|
||||
color.setBold(false);
|
||||
colors.put("tspinner.inactive", color);
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.BLUE);
|
||||
color.setBackColor(Color.CYAN);
|
||||
color.setBold(false);
|
||||
colors.put("tspinner.active", color);
|
||||
|
||||
// TCalendar
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.WHITE);
|
||||
color.setBackColor(Color.BLUE);
|
||||
color.setBold(false);
|
||||
colors.put("tcalendar.background", color);
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.WHITE);
|
||||
color.setBackColor(Color.BLUE);
|
||||
color.setBold(false);
|
||||
colors.put("tcalendar.day", color);
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.RED);
|
||||
color.setBackColor(Color.WHITE);
|
||||
color.setBold(false);
|
||||
colors.put("tcalendar.day.selected", color);
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.BLUE);
|
||||
color.setBackColor(Color.CYAN);
|
||||
color.setBold(false);
|
||||
colors.put("tcalendar.arrow", color);
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.WHITE);
|
||||
color.setBackColor(Color.BLUE);
|
||||
color.setBold(true);
|
||||
colors.put("tcalendar.title", color);
|
||||
|
||||
// TRadioButton
|
||||
color = new CellAttributes();
|
||||
color.setForeColor(Color.WHITE);
|
||||
|
|
|
@ -34,7 +34,7 @@ package jexer.bits;
|
|||
* two '&&' characters, e.g. "&File && Stuff" would be
|
||||
* "File & Stuff" with the first 'F' highlighted.
|
||||
*/
|
||||
public final class MnemonicString {
|
||||
public class MnemonicString {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -40,7 +40,7 @@ import java.util.LinkedList;
|
|||
* - Unescape C0 control codes.
|
||||
*
|
||||
*/
|
||||
public final class StringUtils {
|
||||
public class StringUtils {
|
||||
|
||||
/**
|
||||
* Left-justify a string into a list of lines.
|
||||
|
|
|
@ -28,15 +28,28 @@
|
|||
*/
|
||||
package jexer.demos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jexer.*;
|
||||
import static jexer.TCommand.*;
|
||||
import static jexer.TKeypress.*;
|
||||
|
||||
/**
|
||||
* This window demonstates the TRadioGroup, TRadioButton, and TCheckbox
|
||||
* This window demonstates the TRadioGroup, TRadioButton, and TCheckBox
|
||||
* widgets.
|
||||
*/
|
||||
public class DemoCheckboxWindow extends TWindow {
|
||||
public class DemoCheckBoxWindow extends TWindow {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Combo box. Has to be at class scope so that it can be accessed by the
|
||||
* anonymous TAction class.
|
||||
*/
|
||||
TComboBox comboBox = null;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
|
@ -47,7 +60,7 @@ public class DemoCheckboxWindow extends TWindow {
|
|||
*
|
||||
* @param parent the main application
|
||||
*/
|
||||
DemoCheckboxWindow(final TApplication parent) {
|
||||
DemoCheckBoxWindow(final TApplication parent) {
|
||||
this(parent, CENTERED | RESIZABLE);
|
||||
}
|
||||
|
||||
|
@ -57,18 +70,19 @@ public class DemoCheckboxWindow extends TWindow {
|
|||
* @param parent the main application
|
||||
* @param flags bitmask of MODAL, CENTERED, or RESIZABLE
|
||||
*/
|
||||
DemoCheckboxWindow(final TApplication parent, final int flags) {
|
||||
DemoCheckBoxWindow(final TApplication parent, final int flags) {
|
||||
// Construct a demo window. X and Y don't matter because it will be
|
||||
// centered on screen.
|
||||
super(parent, "Radiobuttons and Checkboxes", 0, 0, 60, 15, flags);
|
||||
super(parent, "Radiobuttons, CheckBoxes, and ComboBox",
|
||||
0, 0, 60, 17, flags);
|
||||
|
||||
int row = 1;
|
||||
|
||||
// Add some widgets
|
||||
addLabel("Check box example 1", 1, row);
|
||||
addCheckbox(35, row++, "Checkbox 1", false);
|
||||
addCheckBox(35, row++, "CheckBox 1", false);
|
||||
addLabel("Check box example 2", 1, row);
|
||||
addCheckbox(35, row++, "Checkbox 2", true);
|
||||
addCheckBox(35, row++, "CheckBox 2", true);
|
||||
row += 2;
|
||||
|
||||
TRadioGroup group = addRadioGroup(1, row, "Group 1");
|
||||
|
@ -76,11 +90,37 @@ public class DemoCheckboxWindow extends TWindow {
|
|||
group.addRadioButton("Radio option 2");
|
||||
group.addRadioButton("Radio option 3");
|
||||
|
||||
List<String> comboValues = new ArrayList<String>();
|
||||
comboValues.add("String 0");
|
||||
comboValues.add("String 1");
|
||||
comboValues.add("String 2");
|
||||
comboValues.add("String 3");
|
||||
comboValues.add("String 4");
|
||||
comboValues.add("String 5");
|
||||
comboValues.add("String 6");
|
||||
comboValues.add("String 7");
|
||||
comboValues.add("String 8");
|
||||
comboValues.add("String 9");
|
||||
comboValues.add("String 10");
|
||||
|
||||
comboBox = addComboBox(35, row, 12, comboValues, 2, 6,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
getApplication().messageBox("ComboBox",
|
||||
"You selected the following value:\n" +
|
||||
"\n" +
|
||||
comboBox.getText() +
|
||||
"\n",
|
||||
TMessageBox.Type.OK);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
addButton("&Close Window", (getWidth() - 14) / 2, getHeight() - 4,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
DemoCheckboxWindow.this.getApplication()
|
||||
.closeWindow(DemoCheckboxWindow.this);
|
||||
DemoCheckBoxWindow.this.getApplication()
|
||||
.closeWindow(DemoCheckBoxWindow.this);
|
||||
}
|
||||
}
|
||||
);
|
|
@ -29,6 +29,7 @@
|
|||
package jexer.demos;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import jexer.*;
|
||||
import jexer.event.*;
|
||||
|
@ -67,6 +68,17 @@ public class DemoMainWindow extends TWindow {
|
|||
*/
|
||||
TProgressBar progressBar;
|
||||
|
||||
/**
|
||||
* Day of week label is updated with TSpinner clicks.
|
||||
*/
|
||||
TLabel dayOfWeekLabel;
|
||||
|
||||
/**
|
||||
* Day of week to demonstrate TSpinner. Has to be at class scope so that
|
||||
* it can be accessed by the anonymous TAction class.
|
||||
*/
|
||||
GregorianCalendar calendar = new GregorianCalendar();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -95,7 +107,7 @@ public class DemoMainWindow extends TWindow {
|
|||
|
||||
// Add some widgets
|
||||
addLabel("Message Boxes", 1, row);
|
||||
addButton("&MessageBoxes", 35, row,
|
||||
TWidget first = addButton("&MessageBoxes", 35, row,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
new DemoMsgBoxWindow(getApplication());
|
||||
|
@ -114,7 +126,7 @@ public class DemoMainWindow extends TWindow {
|
|||
);
|
||||
row += 2;
|
||||
|
||||
addLabel("Text fields", 1, row);
|
||||
addLabel("Text fields and calendar", 1, row);
|
||||
addButton("Field&s", 35, row,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
|
@ -124,11 +136,11 @@ public class DemoMainWindow extends TWindow {
|
|||
);
|
||||
row += 2;
|
||||
|
||||
addLabel("Radio buttons and checkboxes", 1, row);
|
||||
addButton("&Checkboxes", 35, row,
|
||||
addLabel("Radio buttons, check and combobox", 1, row);
|
||||
addButton("&CheckBoxes", 35, row,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
new DemoCheckboxWindow(getApplication());
|
||||
new DemoCheckBoxWindow(getApplication());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -214,6 +226,35 @@ public class DemoMainWindow extends TWindow {
|
|||
}
|
||||
);
|
||||
|
||||
dayOfWeekLabel = addLabel("Wednesday-", 35, row - 1, "tmenu", false);
|
||||
dayOfWeekLabel.setLabel(String.format("%-10s",
|
||||
calendar.getDisplayName(Calendar.DAY_OF_WEEK,
|
||||
Calendar.LONG, Locale.getDefault())));
|
||||
|
||||
addSpinner(35 + dayOfWeekLabel.getWidth(), row - 1,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
calendar.add(Calendar.DAY_OF_WEEK, 1);
|
||||
dayOfWeekLabel.setLabel(String.format("%-10s",
|
||||
calendar.getDisplayName(
|
||||
Calendar.DAY_OF_WEEK, Calendar.LONG,
|
||||
Locale.getDefault())));
|
||||
}
|
||||
},
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
calendar.add(Calendar.DAY_OF_WEEK, -1);
|
||||
dayOfWeekLabel.setLabel(String.format("%-10s",
|
||||
calendar.getDisplayName(
|
||||
Calendar.DAY_OF_WEEK, Calendar.LONG,
|
||||
Locale.getDefault())));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
activate(first);
|
||||
|
||||
statusBar = newStatusBar("Demo Main Window");
|
||||
statusBar.addShortcutKeypress(kbF1, cmHelp, "Help");
|
||||
statusBar.addShortcutKeypress(kbF2, cmShell, "Shell");
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
*/
|
||||
package jexer.demos;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jexer.*;
|
||||
import static jexer.TCommand.*;
|
||||
import static jexer.TKeypress.*;
|
||||
|
@ -37,6 +39,16 @@ import static jexer.TKeypress.*;
|
|||
*/
|
||||
public class DemoTextFieldWindow extends TWindow {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Calendar. Has to be at class scope so that it can be accessed by the
|
||||
* anonymous TAction class.
|
||||
*/
|
||||
TCalendar calendar = null;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -59,7 +71,7 @@ public class DemoTextFieldWindow extends TWindow {
|
|||
DemoTextFieldWindow(final TApplication parent, final int flags) {
|
||||
// Construct a demo window. X and Y don't matter because it
|
||||
// will be centered on screen.
|
||||
super(parent, "Text Fields", 0, 0, 60, 10, flags);
|
||||
super(parent, "Text Fields", 0, 0, 60, 20, flags);
|
||||
|
||||
int row = 1;
|
||||
|
||||
|
@ -76,6 +88,19 @@ public class DemoTextFieldWindow extends TWindow {
|
|||
"Very very long field text that should be outside the window");
|
||||
row += 1;
|
||||
|
||||
calendar = addCalendar(1, row++,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
getApplication().messageBox("Calendar",
|
||||
"You selected the following date:\n" +
|
||||
"\n" +
|
||||
new Date(calendar.getValue().getTimeInMillis()) +
|
||||
"\n",
|
||||
TMessageBox.Type.OK);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
addButton("&Close Window", (getWidth() - 14) / 2, getHeight() - 4,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
|
|
|
@ -35,7 +35,7 @@ import jexer.TCommand;
|
|||
* generated by menu actions, keyboard accelerators, and other UI elements.
|
||||
* Commands can operate on both the application and individual widgets.
|
||||
*/
|
||||
public final class TCommandEvent extends TInputEvent {
|
||||
public class TCommandEvent extends TInputEvent {
|
||||
|
||||
/**
|
||||
* Command dispatched.
|
||||
|
|
|
@ -33,7 +33,7 @@ import jexer.TKeypress;
|
|||
/**
|
||||
* This class encapsulates a keyboard input event.
|
||||
*/
|
||||
public final class TKeypressEvent extends TInputEvent {
|
||||
public class TKeypressEvent extends TInputEvent {
|
||||
|
||||
/**
|
||||
* Keystroke received.
|
||||
|
|
|
@ -33,7 +33,7 @@ package jexer.event;
|
|||
* TApplication.getMenuItem(id) can be used to obtain the TMenuItem itself,
|
||||
* say for setting enabled/disabled/checked/etc.
|
||||
*/
|
||||
public final class TMenuEvent extends TInputEvent {
|
||||
public class TMenuEvent extends TInputEvent {
|
||||
|
||||
/**
|
||||
* MenuItem ID.
|
||||
|
|
|
@ -33,7 +33,7 @@ package jexer.event;
|
|||
* the relative (x,y) ARE MUTABLE: TWidget's onMouse() handlers perform that
|
||||
* update during event dispatching.
|
||||
*/
|
||||
public final class TMouseEvent extends TInputEvent {
|
||||
public class TMouseEvent extends TInputEvent {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
|
|
@ -31,7 +31,7 @@ package jexer.event;
|
|||
/**
|
||||
* This class encapsulates a screen or window resize event.
|
||||
*/
|
||||
public final class TResizeEvent extends TInputEvent {
|
||||
public class TResizeEvent extends TInputEvent {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
|
|
@ -44,7 +44,7 @@ import static jexer.TKeypress.*;
|
|||
/**
|
||||
* TMenu is a top-level collection of TMenuItems.
|
||||
*/
|
||||
public final class TMenu extends TWindow {
|
||||
public class TMenu extends TWindow {
|
||||
|
||||
/**
|
||||
* Translated strings.
|
||||
|
|
|
@ -34,7 +34,7 @@ import jexer.bits.GraphicsChars;
|
|||
/**
|
||||
* TMenuSeparator is a special case menu item.
|
||||
*/
|
||||
public final class TMenuSeparator extends TMenuItem {
|
||||
public class TMenuSeparator extends TMenuItem {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
|
|
|
@ -38,7 +38,7 @@ import static jexer.TKeypress.*;
|
|||
/**
|
||||
* TSubMenu is a special case menu item that wraps another TMenu.
|
||||
*/
|
||||
public final class TSubMenu extends TMenuItem {
|
||||
public class TSubMenu extends TMenuItem {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -40,8 +40,7 @@ import static jexer.net.TelnetSocket.*;
|
|||
/**
|
||||
* TelnetInputStream works with TelnetSocket to perform the telnet protocol.
|
||||
*/
|
||||
public final class TelnetInputStream extends InputStream
|
||||
implements SessionInfo {
|
||||
public class TelnetInputStream extends InputStream implements SessionInfo {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
|
|
@ -36,7 +36,7 @@ import static jexer.net.TelnetSocket.*;
|
|||
/**
|
||||
* TelnetOutputStream works with TelnetSocket to perform the telnet protocol.
|
||||
*/
|
||||
public final class TelnetOutputStream extends OutputStream {
|
||||
public class TelnetOutputStream extends OutputStream {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -37,7 +37,7 @@ import java.net.SocketException;
|
|||
/**
|
||||
* This class provides a ServerSocket that return TelnetSocket's in accept().
|
||||
*/
|
||||
public final class TelnetServerSocket extends ServerSocket {
|
||||
public class TelnetServerSocket extends ServerSocket {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variables --------------------------------------------------------------
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.net.Socket;
|
|||
* establish an 8-bit clean no echo channel and expose window resize events
|
||||
* to the Jexer ECMA48 backend.
|
||||
*/
|
||||
public final class TelnetSocket extends Socket {
|
||||
public class TelnetSocket extends Socket {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
|
|
@ -34,7 +34,7 @@ import jexer.bits.CellAttributes;
|
|||
/**
|
||||
* This represents a single line of the display buffer.
|
||||
*/
|
||||
public final class DisplayLine {
|
||||
public class DisplayLine {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constants --------------------------------------------------------------
|
||||
|
|
|
@ -438,6 +438,11 @@ public class ECMA48 implements Runnable {
|
|||
*/
|
||||
private SaveableState savedState;
|
||||
|
||||
/**
|
||||
* The 88- or 256-color support RGB colors.
|
||||
*/
|
||||
private List<Integer> colors88;
|
||||
|
||||
/**
|
||||
* DECSC/DECRC save/restore a subset of the total state. This class
|
||||
* encapsulates those specific flags/modes.
|
||||
|
@ -1077,6 +1082,99 @@ public class ECMA48 implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the 88- or 256-colors.
|
||||
*/
|
||||
private void resetColors() {
|
||||
colors88 = new ArrayList<Integer>(256);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
colors88.add(0);
|
||||
}
|
||||
|
||||
// Set default system colors.
|
||||
colors88.set(0, 0x00000000);
|
||||
colors88.set(1, 0x00a80000);
|
||||
colors88.set(2, 0x0000a800);
|
||||
colors88.set(3, 0x00a85400);
|
||||
colors88.set(4, 0x000000a8);
|
||||
colors88.set(5, 0x00a800a8);
|
||||
colors88.set(6, 0x0000a8a8);
|
||||
colors88.set(7, 0x00a8a8a8);
|
||||
|
||||
colors88.set(8, 0x00545454);
|
||||
colors88.set(9, 0x00fc5454);
|
||||
colors88.set(10, 0x0054fc54);
|
||||
colors88.set(11, 0x00fcfc54);
|
||||
colors88.set(12, 0x005454fc);
|
||||
colors88.set(13, 0x00fc54fc);
|
||||
colors88.set(14, 0x0054fcfc);
|
||||
colors88.set(15, 0x00fcfcfc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the RGB value of one of the indexed colors.
|
||||
*
|
||||
* @param index the color index
|
||||
* @return the RGB value
|
||||
*/
|
||||
private int get88Color(final int index) {
|
||||
// System.err.print("get88Color: " + index);
|
||||
if ((index < 0) || (index > colors88.size())) {
|
||||
// System.err.println(" -- UNKNOWN");
|
||||
return 0;
|
||||
}
|
||||
// System.err.printf(" %08x\n", colors88.get(index));
|
||||
return colors88.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one of the indexed colors to a color specification.
|
||||
*
|
||||
* @param index the color index
|
||||
* @param spec the specification, typically something like "rgb:aa/bb/cc"
|
||||
*/
|
||||
private void set88Color(final int index, final String spec) {
|
||||
// System.err.println("set88Color: " + index + " '" + spec + "'");
|
||||
|
||||
if ((index < 0) || (index > colors88.size())) {
|
||||
return;
|
||||
}
|
||||
if (spec.startsWith("rgb:")) {
|
||||
String [] rgbTokens = spec.substring(4).split("/");
|
||||
if (rgbTokens.length == 3) {
|
||||
try {
|
||||
int rgb = (Integer.parseInt(rgbTokens[0], 16) << 16);
|
||||
rgb |= Integer.parseInt(rgbTokens[1], 16) << 8;
|
||||
rgb |= Integer.parseInt(rgbTokens[2], 16);
|
||||
// System.err.printf(" set to %08x\n", rgb);
|
||||
colors88.set(index, rgb);
|
||||
} catch (NumberFormatException e) {
|
||||
// SQUASH
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (spec.toLowerCase().equals("black")) {
|
||||
colors88.set(index, 0x00000000);
|
||||
} else if (spec.toLowerCase().equals("red")) {
|
||||
colors88.set(index, 0x00a80000);
|
||||
} else if (spec.toLowerCase().equals("green")) {
|
||||
colors88.set(index, 0x0000a800);
|
||||
} else if (spec.toLowerCase().equals("yellow")) {
|
||||
colors88.set(index, 0x00a85400);
|
||||
} else if (spec.toLowerCase().equals("blue")) {
|
||||
colors88.set(index, 0x000000a8);
|
||||
} else if (spec.toLowerCase().equals("magenta")) {
|
||||
colors88.set(index, 0x00a800a8);
|
||||
} else if (spec.toLowerCase().equals("cyan")) {
|
||||
colors88.set(index, 0x0000a8a8);
|
||||
} else if (spec.toLowerCase().equals("white")) {
|
||||
colors88.set(index, 0x00a8a8a8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the emulation state.
|
||||
*/
|
||||
|
@ -1122,6 +1220,9 @@ public class ECMA48 implements Runnable {
|
|||
// Tab stops
|
||||
resetTabStops();
|
||||
|
||||
// Reset extra colors
|
||||
resetColors();
|
||||
|
||||
// Clear CSI stuff
|
||||
toGround();
|
||||
}
|
||||
|
@ -3529,8 +3630,87 @@ public class ECMA48 implements Runnable {
|
|||
return;
|
||||
}
|
||||
|
||||
int sgrColorMode = -1;
|
||||
boolean idx88Color = false;
|
||||
boolean rgbColor = false;
|
||||
int rgbRed = -1;
|
||||
int rgbGreen = -1;
|
||||
|
||||
for (Integer i: csiParams) {
|
||||
|
||||
if ((sgrColorMode == 38) || (sgrColorMode == 48)) {
|
||||
|
||||
assert (type == DeviceType.XTERM);
|
||||
|
||||
if (idx88Color) {
|
||||
/*
|
||||
* Indexed color mode, we now have the index number.
|
||||
*/
|
||||
if (sgrColorMode == 38) {
|
||||
currentState.attr.setForeColorRGB(get88Color(i));
|
||||
} else {
|
||||
assert (sgrColorMode == 48);
|
||||
currentState.attr.setBackColorRGB(get88Color(i));
|
||||
}
|
||||
sgrColorMode = -1;
|
||||
idx88Color = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rgbColor) {
|
||||
/*
|
||||
* RGB color mode, we are collecting tokens.
|
||||
*/
|
||||
if (rgbRed == -1) {
|
||||
rgbRed = i & 0xFF;
|
||||
} else if (rgbGreen == -1) {
|
||||
rgbGreen = i & 0xFF;
|
||||
} else {
|
||||
int rgb = rgbRed << 16;
|
||||
rgb |= rgbGreen << 8;
|
||||
rgb |= i & 0xFF;
|
||||
|
||||
// System.err.printf("RGB: %08x\n", rgb);
|
||||
|
||||
if (sgrColorMode == 38) {
|
||||
currentState.attr.setForeColorRGB(rgb);
|
||||
} else {
|
||||
assert (sgrColorMode == 48);
|
||||
currentState.attr.setBackColorRGB(rgb);
|
||||
}
|
||||
rgbRed = -1;
|
||||
rgbGreen = -1;
|
||||
sgrColorMode = -1;
|
||||
rgbColor = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
|
||||
case 2:
|
||||
/*
|
||||
* RGB color mode.
|
||||
*/
|
||||
rgbColor = true;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
/*
|
||||
* Indexed color mode.
|
||||
*/
|
||||
idx88Color = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* This is neither indexed nor RGB color. Bail out.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
} // if ((sgrColorMode == 38) || (sgrColorMode == 48))
|
||||
|
||||
switch (i) {
|
||||
|
||||
case 0:
|
||||
|
@ -3571,6 +3751,72 @@ public class ECMA48 implements Runnable {
|
|||
// TODO
|
||||
break;
|
||||
|
||||
case 90:
|
||||
// Set black foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(8));
|
||||
break;
|
||||
case 91:
|
||||
// Set red foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(9));
|
||||
break;
|
||||
case 92:
|
||||
// Set green foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(10));
|
||||
break;
|
||||
case 93:
|
||||
// Set yellow foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(11));
|
||||
break;
|
||||
case 94:
|
||||
// Set blue foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(12));
|
||||
break;
|
||||
case 95:
|
||||
// Set magenta foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(13));
|
||||
break;
|
||||
case 96:
|
||||
// Set cyan foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(14));
|
||||
break;
|
||||
case 97:
|
||||
// Set white foreground
|
||||
currentState.attr.setForeColorRGB(get88Color(15));
|
||||
break;
|
||||
|
||||
case 100:
|
||||
// Set black background
|
||||
currentState.attr.setBackColorRGB(get88Color(8));
|
||||
break;
|
||||
case 101:
|
||||
// Set red background
|
||||
currentState.attr.setBackColorRGB(get88Color(9));
|
||||
break;
|
||||
case 102:
|
||||
// Set green background
|
||||
currentState.attr.setBackColorRGB(get88Color(10));
|
||||
break;
|
||||
case 103:
|
||||
// Set yellow background
|
||||
currentState.attr.setBackColorRGB(get88Color(11));
|
||||
break;
|
||||
case 104:
|
||||
// Set blue background
|
||||
currentState.attr.setBackColorRGB(get88Color(12));
|
||||
break;
|
||||
case 105:
|
||||
// Set magenta background
|
||||
currentState.attr.setBackColorRGB(get88Color(13));
|
||||
break;
|
||||
case 106:
|
||||
// Set cyan background
|
||||
currentState.attr.setBackColorRGB(get88Color(14));
|
||||
break;
|
||||
case 107:
|
||||
// Set white background
|
||||
currentState.attr.setBackColorRGB(get88Color(15));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3615,34 +3861,42 @@ public class ECMA48 implements Runnable {
|
|||
case 30:
|
||||
// Set black foreground
|
||||
currentState.attr.setForeColor(Color.BLACK);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 31:
|
||||
// Set red foreground
|
||||
currentState.attr.setForeColor(Color.RED);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 32:
|
||||
// Set green foreground
|
||||
currentState.attr.setForeColor(Color.GREEN);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 33:
|
||||
// Set yellow foreground
|
||||
currentState.attr.setForeColor(Color.YELLOW);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 34:
|
||||
// Set blue foreground
|
||||
currentState.attr.setForeColor(Color.BLUE);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 35:
|
||||
// Set magenta foreground
|
||||
currentState.attr.setForeColor(Color.MAGENTA);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 36:
|
||||
// Set cyan foreground
|
||||
currentState.attr.setForeColor(Color.CYAN);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 37:
|
||||
// Set white foreground
|
||||
currentState.attr.setForeColor(Color.WHITE);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 38:
|
||||
if (type == DeviceType.XTERM) {
|
||||
|
@ -3652,21 +3906,28 @@ public class ECMA48 implements Runnable {
|
|||
* permits these ISO-8613-3 SGR sequences to be separated
|
||||
* by colons rather than semicolons.)
|
||||
*
|
||||
* We will not support any of these additional color
|
||||
* codes at this time:
|
||||
* We will support only the following:
|
||||
*
|
||||
* 1. http://invisible-island.net/ncurses/ncurses.faq.html#xterm_16MegaColors
|
||||
* has a detailed discussion of the current state of
|
||||
* RGB in various terminals, the point of which is
|
||||
* that none of them really do the same thing despite
|
||||
* all appearing to be "xterm".
|
||||
* 1. Indexed color mode (88- or 256-color modes).
|
||||
*
|
||||
* 2. As seen in
|
||||
* https://bugs.kde.org/show_bug.cgi?id=107487#c3,
|
||||
* even supporting just the "indexed mode" of these
|
||||
* sequences (which could align easily with existing
|
||||
* SGR colors) is assumed to mean full support of
|
||||
* 24-bit RGB. So it is all or nothing.
|
||||
* 2. Direct RGB.
|
||||
*
|
||||
* These cover most of the use cases in the real world.
|
||||
*
|
||||
* HOWEVER, note that this is an awful broken "standard",
|
||||
* with no way to do it "right". See
|
||||
* http://invisible-island.net/ncurses/ncurses.faq.html#xterm_16MegaColors
|
||||
* for a detailed discussion of the current state of RGB
|
||||
* in various terminals, the point of which is that none
|
||||
* of them really do the same thing despite all appearing
|
||||
* to be "xterm".
|
||||
*
|
||||
* Also see
|
||||
* https://bugs.kde.org/show_bug.cgi?id=107487#c3 .
|
||||
* where it is assumed that supporting just the "indexed
|
||||
* mode" of these sequences (which could align easily
|
||||
* with existing SGR colors) is assumed to mean full
|
||||
* support of 24-bit RGB. So it is all or nothing.
|
||||
*
|
||||
* Finally, these sequences break the assumptions of
|
||||
* standard ECMA-48 style parsers as pointed out at
|
||||
|
@ -3674,7 +3935,8 @@ public class ECMA48 implements Runnable {
|
|||
* Therefore in order to keep a clean display, we cannot
|
||||
* parse anything else in this sequence.
|
||||
*/
|
||||
return;
|
||||
sgrColorMode = 38;
|
||||
continue;
|
||||
} else {
|
||||
// Underscore on, default foreground color
|
||||
currentState.attr.setUnderline(true);
|
||||
|
@ -3685,38 +3947,47 @@ public class ECMA48 implements Runnable {
|
|||
// Underscore off, default foreground color
|
||||
currentState.attr.setUnderline(false);
|
||||
currentState.attr.setForeColor(Color.WHITE);
|
||||
currentState.attr.setForeColorRGB(-1);
|
||||
break;
|
||||
case 40:
|
||||
// Set black background
|
||||
currentState.attr.setBackColor(Color.BLACK);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 41:
|
||||
// Set red background
|
||||
currentState.attr.setBackColor(Color.RED);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 42:
|
||||
// Set green background
|
||||
currentState.attr.setBackColor(Color.GREEN);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 43:
|
||||
// Set yellow background
|
||||
currentState.attr.setBackColor(Color.YELLOW);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 44:
|
||||
// Set blue background
|
||||
currentState.attr.setBackColor(Color.BLUE);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 45:
|
||||
// Set magenta background
|
||||
currentState.attr.setBackColor(Color.MAGENTA);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 46:
|
||||
// Set cyan background
|
||||
currentState.attr.setBackColor(Color.CYAN);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 47:
|
||||
// Set white background
|
||||
currentState.attr.setBackColor(Color.WHITE);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
case 48:
|
||||
if (type == DeviceType.XTERM) {
|
||||
|
@ -3726,16 +3997,43 @@ public class ECMA48 implements Runnable {
|
|||
* permits these ISO-8613-3 SGR sequences to be separated
|
||||
* by colons rather than semicolons.)
|
||||
*
|
||||
* We will not support this at this time. Also, in order
|
||||
* to keep a clean display, we cannot parse anything else
|
||||
* in this sequence.
|
||||
* We will support only the following:
|
||||
*
|
||||
* 1. Indexed color mode (88- or 256-color modes).
|
||||
*
|
||||
* 2. Direct RGB.
|
||||
*
|
||||
* These cover most of the use cases in the real world.
|
||||
*
|
||||
* HOWEVER, note that this is an awful broken "standard",
|
||||
* with no way to do it "right". See
|
||||
* http://invisible-island.net/ncurses/ncurses.faq.html#xterm_16MegaColors
|
||||
* for a detailed discussion of the current state of RGB
|
||||
* in various terminals, the point of which is that none
|
||||
* of them really do the same thing despite all appearing
|
||||
* to be "xterm".
|
||||
*
|
||||
* Also see
|
||||
* https://bugs.kde.org/show_bug.cgi?id=107487#c3 .
|
||||
* where it is assumed that supporting just the "indexed
|
||||
* mode" of these sequences (which could align easily
|
||||
* with existing SGR colors) is assumed to mean full
|
||||
* support of 24-bit RGB. So it is all or nothing.
|
||||
*
|
||||
* Finally, these sequences break the assumptions of
|
||||
* standard ECMA-48 style parsers as pointed out at
|
||||
* https://bugs.kde.org/show_bug.cgi?id=107487#c11 .
|
||||
* Therefore in order to keep a clean display, we cannot
|
||||
* parse anything else in this sequence.
|
||||
*/
|
||||
return;
|
||||
sgrColorMode = 48;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 49:
|
||||
// Default background
|
||||
currentState.attr.setBackColor(Color.BLACK);
|
||||
currentState.attr.setBackColorRGB(-1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -4186,13 +4484,22 @@ public class ECMA48 implements Runnable {
|
|||
* @param xtermChar the character received from the remote side
|
||||
*/
|
||||
private void oscPut(final char xtermChar) {
|
||||
// System.err.println("oscPut: " + xtermChar);
|
||||
|
||||
// Collect first
|
||||
collectBuffer.append(xtermChar);
|
||||
|
||||
// Xterm cases...
|
||||
if (xtermChar == 0x07) {
|
||||
String args = collectBuffer.substring(0,
|
||||
collectBuffer.length() - 1);
|
||||
if ((xtermChar == 0x07)
|
||||
|| (collectBuffer.toString().endsWith("\033\\"))
|
||||
) {
|
||||
String args = null;
|
||||
if (xtermChar == 0x07) {
|
||||
args = collectBuffer.substring(0, collectBuffer.length() - 1);
|
||||
} else {
|
||||
args = collectBuffer.substring(0, collectBuffer.length() - 2);
|
||||
}
|
||||
|
||||
String [] p = args.toString().split(";");
|
||||
if (p.length > 0) {
|
||||
if ((p[0].equals("0")) || (p[0].equals("2"))) {
|
||||
|
@ -4201,6 +4508,17 @@ public class ECMA48 implements Runnable {
|
|||
screenTitle = p[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (p[0].equals("4")) {
|
||||
for (int i = 1; i + 1 < p.length; i += 2) {
|
||||
// Set a color index value
|
||||
try {
|
||||
set88Color(Integer.parseInt(p[i]), p[i + 1]);
|
||||
} catch (NumberFormatException e) {
|
||||
// SQUASH
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go to SCAN_GROUND state
|
||||
|
@ -4236,16 +4554,21 @@ public class ECMA48 implements Runnable {
|
|||
// 80-8F, 91-97, 99, 9A, 9C --> execute, then switch to SCAN_GROUND
|
||||
|
||||
// 0x1B == ESCAPE
|
||||
if ((ch == 0x1B)
|
||||
&& (scanState != ScanState.DCS_ENTRY)
|
||||
&& (scanState != ScanState.DCS_INTERMEDIATE)
|
||||
&& (scanState != ScanState.DCS_IGNORE)
|
||||
&& (scanState != ScanState.DCS_PARAM)
|
||||
&& (scanState != ScanState.DCS_PASSTHROUGH)
|
||||
) {
|
||||
if (ch == 0x1B) {
|
||||
if ((type == DeviceType.XTERM)
|
||||
&& (scanState == ScanState.OSC_STRING)
|
||||
) {
|
||||
// Xterm can pass ESCAPE to its OSC sequence.
|
||||
} else if ((scanState != ScanState.DCS_ENTRY)
|
||||
&& (scanState != ScanState.DCS_INTERMEDIATE)
|
||||
&& (scanState != ScanState.DCS_IGNORE)
|
||||
&& (scanState != ScanState.DCS_PARAM)
|
||||
&& (scanState != ScanState.DCS_PASSTHROUGH)
|
||||
) {
|
||||
|
||||
scanState = ScanState.ESCAPE;
|
||||
return;
|
||||
scanState = ScanState.ESCAPE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x9B == CSI 8-bit sequence
|
||||
|
@ -6100,7 +6423,7 @@ public class ECMA48 implements Runnable {
|
|||
|
||||
case OSC_STRING:
|
||||
// Special case for Xterm: OSC can pass control characters
|
||||
if ((ch == 0x9C) || (ch <= 0x07)) {
|
||||
if ((ch == 0x9C) || (ch == 0x07) || (ch == 0x1B)) {
|
||||
oscPut(ch);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue