retrofit from XtermWM

This commit is contained in:
Kevin Lamonte 2020-05-28 21:02:55 -05:00
parent 5c3be57ef3
commit 2c0aafb67f
24 changed files with 1693 additions and 141 deletions

View file

@ -101,7 +101,7 @@ public class TApplication implements Runnable {
* If true, do "smart placement" on new windows that are not specified to
* be centered.
*/
private static final boolean smartWindowPlacement = true;
protected boolean smartWindowPlacement = true;
/**
* Two backend types are available.
@ -286,7 +286,7 @@ public class TApplication implements Runnable {
/**
* If true, display a text-based mouse cursor.
*/
private boolean textMouse = true;
protected boolean textMouse = true;
/**
* If true, hide the mouse after typing a keystroke.
@ -309,6 +309,14 @@ public class TApplication implements Runnable {
*/
private boolean hideMenuBar = false;
/**
* If true, the desktop can have the cursor blinking/visible even if the
* top-most window does not have the cursor active. This can lead to a
* visible artifact where the desktop's cursor is "showing through" a
* window over it.
*/
protected boolean desktopCanHaveCursor = false;
/**
* Optional text to display at the top right of the menu.
*/
@ -364,6 +372,11 @@ public class TApplication implements Runnable {
*/
protected ArrayList<Topic> helpTopics = new ArrayList<Topic>();
/**
* The last time user input (mouse or keyboard) was received.
*/
protected long lastUserInputTime = System.currentTimeMillis();
/**
* WidgetEventHandler is the main event consumer loop. There are at most
* two such threads in existence: the primary for normal case and a
@ -490,6 +503,12 @@ public class TApplication implements Runnable {
// screen at the end.
application.repaint = true;
if ((event instanceof TMouseEvent)
|| (event instanceof TKeypressEvent)
) {
lastUserInputTime = event.getTime().getTime();
}
if (primary) {
primaryHandleEvent(event);
} else {
@ -1111,7 +1130,7 @@ public class TApplication implements Runnable {
return true;
}
if (menu.getId() == TMenu.MID_SCREEN_OPTIONS) {
new TFontChooserWindow(this);
new TScreenOptionsWindow(this);
return true;
}
@ -1223,7 +1242,8 @@ public class TApplication implements Runnable {
// Process timers and call doIdle()'s
doIdle();
// Give subclass TApplications a chance to update something
// Give subclass TApplications a chance to update something before
// the screen is drawn.
onPreDraw();
// Update the screen
@ -1274,6 +1294,8 @@ public class TApplication implements Runnable {
// Screen resize
if (event instanceof TResizeEvent) {
TResizeEvent resize = (TResizeEvent) event;
assert (resize.getType() == TResizeEvent.Type.SCREEN);
synchronized (getScreen()) {
if ((System.currentTimeMillis() - screenResizeTime >= 15)
|| (resize.getWidth() < getScreen().getWidth())
@ -1295,6 +1317,9 @@ public class TApplication implements Runnable {
(desktopBottom - desktopTop));
desktop.onResize(resize);
}
for (TWindow window: windows) {
window.onResize(resize);
}
// Change menu edges if needed.
recomputeMenuX();
@ -1954,6 +1979,14 @@ public class TApplication implements Runnable {
getScreen().getWidth(), desktop.getHeight());
desktop.onResize(resize);
}
if (hideMenuBar == false) {
// Push any windows that are on the top line down.
for (TWindow window: windows) {
if (window.getY() == 0) {
window.setY(1);
}
}
}
}
/**
@ -2022,6 +2055,20 @@ public class TApplication implements Runnable {
return true;
}
/**
* Check if a system-wide modal thread is running. This thread is used
* to drive a few special dialog boxes such as TMessageBox, TInputBox,
* and TFileOpenBox.
*
* @return true if the modal (secondary) thread is running
*/
public boolean isModalThreadRunning() {
if (secondaryEventReceiver != null) {
return true;
}
return false;
}
// ------------------------------------------------------------------------
// Screen refresh loop ----------------------------------------------------
// ------------------------------------------------------------------------
@ -2035,6 +2082,16 @@ public class TApplication implements Runnable {
// Default does nothing
}
/**
* Function called immediately after the screen is drawn, while the
* screen is still synchronized/locked. This can be used by subclasses
* of TApplication to alter the final post-rendered screen before it goes
* out -- or even replace the entire thing such as a screensaver.
*/
protected void onPostDraw() {
// Default does nothing
}
/**
* Draw the text mouse at position.
*
@ -2154,7 +2211,12 @@ public class TApplication implements Runnable {
oldDrawnMouseX = mouseX;
oldDrawnMouseY = mouseY;
}
if (getScreen().isDirty()) {
// Give subclass TApplications a chance to update the
// post-rendered screen.
onPostDraw();
screenHandler.setDirty();
}
return;
@ -2191,26 +2253,34 @@ public class TApplication implements Runnable {
}
if (hideMenuBar == false) {
// Draw the blank menubar line - reset the screen clipping first
// so it won't trim it out.
getScreen().resetClipping();
getScreen().hLineXY(0, 0, getScreen().getWidth(), ' ',
theme.getColor("tmenu"));
// Now draw the menus.
int x = 1;
for (TMenu menu: menus) {
CellAttributes menuColor;
CellAttributes menuMnemonicColor;
if (menu.isActive()) {
menuIsActive = true;
}
// Now draw the menus.
int x = 1;
for (TMenu menu: menus) {
CellAttributes menuColor;
CellAttributes menuMnemonicColor;
if (menu.isActive()) {
menuIsActive = true;
if (!menu.isContext()) {
menuColor = theme.getColor("tmenu.highlighted");
menuMnemonicColor = theme.getColor("tmenu.mnemonic.highlighted");
topLevel = menu;
} else {
menuColor = theme.getColor("tmenu");
menuMnemonicColor = theme.getColor("tmenu.mnemonic");
}
topLevel = menu;
} else {
menuColor = theme.getColor("tmenu");
menuMnemonicColor = theme.getColor("tmenu.mnemonic");
}
if (hideMenuBar == false) {
// Draw the menu title
getScreen().hLineXY(x, 0,
StringUtils.width(menu.getTitle()) + 2, ' ', menuColor);
@ -2219,31 +2289,31 @@ public class TApplication implements Runnable {
getScreen().putCharXY(x + 1 +
menu.getMnemonic().getScreenShortcutIdx(),
0, menu.getMnemonic().getShortcut(), menuMnemonicColor);
if (menu.isActive()) {
((TWindow) menu).drawChildren();
// Reset the screen clipping so we can draw the next
// title.
getScreen().resetClipping();
}
x += StringUtils.width(menu.getTitle()) + 2;
}
for (TMenu menu: subMenus) {
// Reset the screen clipping so we can draw the next
// sub-menu.
getScreen().resetClipping();
if (menu.isActive()) {
((TWindow) menu).drawChildren();
// Reset the screen clipping so we can draw the next title.
getScreen().resetClipping();
}
x += StringUtils.width(menu.getTitle()) + 2;
}
for (TMenu menu: subMenus) {
// Reset the screen clipping so we can draw the next sub-menu.
getScreen().resetClipping();
((TWindow) menu).drawChildren();
}
if (hideMenuBar == false) {
if ((menuTrayText != null) && (menuTrayText.length() > 0)) {
getScreen().resetClipping();
getScreen().putStringXY(getScreen().getWidth() -
StringUtils.width(menuTrayText), 0, menuTrayText,
theme.getColor("tmenu"));
}
}
getScreen().resetClipping();
if (hideStatusBar == false) {
@ -2321,7 +2391,7 @@ public class TApplication implements Runnable {
visibleWindowCount++;
}
}
if (visibleWindowCount == 0) {
if ((visibleWindowCount == 0) || desktopCanHaveCursor) {
// No windows are visible, only the desktop. Allow it to
// have the cursor.
if (desktop != null) {
@ -2357,6 +2427,10 @@ public class TApplication implements Runnable {
}
if (getScreen().isDirty()) {
// Give subclass TApplications a chance to update the
// post-rendered screen.
onPostDraw();
screenHandler.setDirty();
}
repaint = false;
@ -3052,14 +3126,33 @@ public class TApplication implements Runnable {
if ((mouse.getType() == TMouseEvent.Type.MOUSE_DOWN)
&& (activeMenu != null)
&& (mouse.getAbsoluteY() != 0)
&& (activeMenu.isContext())
&& (!mouseOnMenu(mouse))
) {
// They clicked outside the active menu, turn it off
// They clicked outside the active context menu, turn it off
activeMenu.setActive(false);
activeMenu.setContext(false);
activeMenu = null;
for (TMenu menu: subMenus) {
menu.setActive(false);
menu.setContext(false);
}
subMenus.clear();
// Continue checks
}
if ((mouse.getType() == TMouseEvent.Type.MOUSE_DOWN)
&& (activeMenu != null)
&& (mouse.getAbsoluteY() != 0)
&& (!mouseOnMenu(mouse))
) {
// They clicked outside the active non-context menu, turn it off
activeMenu.setActive(false);
assert (activeMenu.isContext() == false);
activeMenu = null;
for (TMenu menu: subMenus) {
menu.setActive(false);
menu.setContext(false);
}
subMenus.clear();
// Continue checks
@ -3076,6 +3169,7 @@ public class TApplication implements Runnable {
for (TMenu menu: subMenus) {
menu.setActive(false);
assert (menu.isContext() == false);
}
subMenus.clear();
@ -3086,6 +3180,7 @@ public class TApplication implements Runnable {
+ StringUtils.width(menu.getTitle()) + 2)
) {
menu.setActive(true);
assert (menu.isContext() == false);
activeMenu = menu;
} else {
menu.setActive(false);
@ -3105,6 +3200,7 @@ public class TApplication implements Runnable {
TMenu oldMenu = activeMenu;
for (TMenu menu: subMenus) {
menu.setActive(false);
assert (menu.isContext() == false);
}
subMenus.clear();
@ -3115,6 +3211,7 @@ public class TApplication implements Runnable {
+ StringUtils.width(menu.getTitle()) + 2)
) {
menu.setActive(true);
assert (menu.isContext() == false);
activeMenu = menu;
}
}
@ -3175,9 +3272,14 @@ public class TApplication implements Runnable {
public final void closeMenu() {
if (activeMenu != null) {
activeMenu.setActive(false);
if (activeMenu.isContext()) {
activeMenu.setY(0);
activeMenu.setContext(false);
}
activeMenu = null;
for (TMenu menu: subMenus) {
menu.setActive(false);
menu.setContext(false);
}
subMenus.clear();
}
@ -3192,6 +3294,34 @@ public class TApplication implements Runnable {
return new ArrayList<TMenu>(menus);
}
/**
* Open a previously created menu as a context menu at a specific
* location.
*
* @param menu the menu to open
* @param x the context menu X position
* @param y the context menu Y position
* @throws IllegalArgumentException if the menu is already used in
* another TApplication
*/
public final void openContextMenu(final TMenu menu, final int x,
final int y) {
if ((menu.getApplication() != null)
&& (menu.getApplication() != this)
) {
throw new IllegalArgumentException("Menu " + menu + " is already " +
"part of application " + menu.getApplication());
}
assert (activeMenu == null);
menu.setContext(true, x, y);
menu.setActive(true);
activeMenu = menu;
}
/**
* Add a top-level menu to the list.
*

View file

@ -28,6 +28,7 @@
*/
package jexer;
import java.io.IOException;
import java.util.List;
import java.util.ResourceBundle;
@ -90,6 +91,11 @@ public class TEditColorThemeWindow extends TWindow {
*/
boolean bold;
/**
* The RGB background color.
*/
TField rgb;
/**
* Public constructor.
*
@ -103,6 +109,11 @@ public class TEditColorThemeWindow extends TWindow {
final int y, final int width, final int height) {
super(parent, x, y, width, height);
addLabel(i18n.getString("rgbHex"), 1, 6,
"twindow.background.modal");
rgb = addField(6, 6, 7, true, "");
}
/**
@ -289,13 +300,16 @@ public class TEditColorThemeWindow extends TWindow {
*/
@Override
public void onKeypress(final TKeypressEvent keypress) {
if (keypress.equals(kbRight)) {
if (rgb.isActive()) {
rgb.onKeypress(keypress);
} else if (keypress.equals(kbRight)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color, bold);
if (dotX < 10) {
dotX += 3;
}
color = getColorFromPosition(dotX, dotY);
rgb.setText("");
} else if (keypress.equals(kbLeft)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color, bold);
@ -303,6 +317,7 @@ public class TEditColorThemeWindow extends TWindow {
dotX -= 3;
}
color = getColorFromPosition(dotX, dotY);
rgb.setText("");
} else if (keypress.equals(kbUp)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color, bold);
@ -311,6 +326,7 @@ public class TEditColorThemeWindow extends TWindow {
}
color = getColorFromPosition(dotX, dotY);
bold = getBoldFromPosition(dotY);
rgb.setText("");
} else if (keypress.equals(kbDown)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color, bold);
@ -319,10 +335,10 @@ public class TEditColorThemeWindow extends TWindow {
}
color = getColorFromPosition(dotX, dotY);
bold = getBoldFromPosition(dotY);
rgb.setText("");
} else {
// Pass to my parent
super.onKeypress(keypress);
return;
}
// Save this update to the local theme.
@ -345,6 +361,7 @@ public class TEditColorThemeWindow extends TWindow {
}
color = getColorFromPosition(dotX, dotY);
bold = getBoldFromPosition(dotY);
rgb.setText("");
} else if (mouse.isMouseWheelDown()) {
// Do this like kbDown
int dotX = getXColorPosition(color);
@ -354,17 +371,18 @@ public class TEditColorThemeWindow extends TWindow {
}
color = getColorFromPosition(dotX, dotY);
bold = getBoldFromPosition(dotY);
rgb.setText("");
} else if ((mouse.getX() > 0)
&& (mouse.getX() < getWidth() - 1)
&& (mouse.getY() > 0)
&& (mouse.getY() < getHeight() - 1)
&& (mouse.getY() < getHeight() - 3)
) {
color = getColorFromPosition(mouse.getX(), mouse.getY());
bold = getBoldFromPosition(mouse.getY());
rgb.setText("");
} else {
// Let parent class handle it.
super.onMouseDown(mouse);
return;
}
// Save this update to the local theme.
@ -383,6 +401,11 @@ public class TEditColorThemeWindow extends TWindow {
*/
Color color;
/**
* The RGB background color.
*/
TField rgb;
/**
* Public constructor.
*
@ -396,6 +419,10 @@ public class TEditColorThemeWindow extends TWindow {
final int y, final int width, final int height) {
super(parent, x, y, width, height);
addLabel(i18n.getString("rgbHex"), 1, 4,
"twindow.background.modal");
rgb = addField(6, 4, 7, true, "");
}
/**
@ -543,13 +570,16 @@ public class TEditColorThemeWindow extends TWindow {
*/
@Override
public void onKeypress(final TKeypressEvent keypress) {
if (keypress.equals(kbRight)) {
if (rgb.isActive()) {
rgb.onKeypress(keypress);
} else if (keypress.equals(kbRight)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color);
if (dotX < 10) {
dotX += 3;
}
color = getColorFromPosition(dotX, dotY);
rgb.setText("");
} else if (keypress.equals(kbLeft)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color);
@ -557,6 +587,7 @@ public class TEditColorThemeWindow extends TWindow {
dotX -= 3;
}
color = getColorFromPosition(dotX, dotY);
rgb.setText("");
} else if (keypress.equals(kbUp)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color);
@ -564,6 +595,7 @@ public class TEditColorThemeWindow extends TWindow {
dotY--;
}
color = getColorFromPosition(dotX, dotY);
rgb.setText("");
} else if (keypress.equals(kbDown)) {
int dotX = getXColorPosition(color);
int dotY = getYColorPosition(color);
@ -571,6 +603,7 @@ public class TEditColorThemeWindow extends TWindow {
dotY++;
}
color = getColorFromPosition(dotX, dotY);
rgb.setText("");
} else {
// Pass to my parent
super.onKeypress(keypress);
@ -595,6 +628,7 @@ public class TEditColorThemeWindow extends TWindow {
dotY--;
}
color = getColorFromPosition(dotX, dotY);
rgb.setText("");
} else if (mouse.isMouseWheelDown()) {
// Do this like kbDown
int dotX = getXColorPosition(color);
@ -603,17 +637,17 @@ public class TEditColorThemeWindow extends TWindow {
dotY++;
}
color = getColorFromPosition(dotX, dotY);
return;
rgb.setText("");
} else if ((mouse.getX() > 0)
&& (mouse.getX() < getWidth() - 1)
&& (mouse.getY() > 0)
&& (mouse.getY() < getHeight() - 1)
&& (mouse.getY() < getHeight() - 3)
) {
color = getColorFromPosition(mouse.getX(), mouse.getY());
rgb.setText("");
} else {
// Let parent class handle it.
super.onMouseDown(mouse);
return;
}
// Save this update to the local theme.
@ -634,7 +668,7 @@ public class TEditColorThemeWindow extends TWindow {
public TEditColorThemeWindow(final TApplication application) {
// Register with the TApplication
super(application, i18n.getString("windowTitle"), 0, 0, 60, 18, MODAL);
super(application, i18n.getString("windowTitle"), 0, 0, 60, 22, MODAL);
// Initialize with the first color
List<String> colors = getTheme().getColorNames();
@ -666,12 +700,12 @@ public class TEditColorThemeWindow extends TWindow {
}
}
);
foreground = new ForegroundPicker(this, 42, 1, 14, 6);
background = new BackgroundPicker(this, 42, 7, 14, 4);
foreground = new ForegroundPicker(this, 42, 1, 14, 8);
background = new BackgroundPicker(this, 42, 9, 14, 6);
refreshFromTheme(colors.get(0));
colorNames.setSelectedIndex(0);
addButton(i18n.getString("okButton"), getWidth() - 37, getHeight() - 4,
addButton(i18n.getString("okButton"), getWidth() - 53, getHeight() - 4,
new TAction() {
public void DO() {
ColorTheme global = getTheme();
@ -686,7 +720,42 @@ public class TEditColorThemeWindow extends TWindow {
}
);
addButton(i18n.getString("cancelButton"), getWidth() - 25,
addButton(i18n.getString("loadButton"), getWidth() - 41,
getHeight() - 4,
new TAction() {
public void DO() {
try {
String filename = null;
filename = fileOpenBox(".");
if (filename != null) {
editTheme.load(filename);
refreshFromTheme(colorNames.getSelected());
}
} catch (IOException e) {
new TExceptionDialog(getApplication(), e);
}
}
}
);
addButton(i18n.getString("saveButton"), getWidth() - 29,
getHeight() - 4,
new TAction() {
public void DO() {
try {
String filename = null;
filename = fileSaveBox(".");
if (filename != null) {
editTheme.save(filename);
}
} catch (IOException e) {
new TExceptionDialog(getApplication(), e);
}
}
}
);
addButton(i18n.getString("cancelButton"), getWidth() - 17,
getHeight() - 4,
new TAction() {
public void DO() {
@ -745,9 +814,38 @@ public class TEditColorThemeWindow extends TWindow {
// Draw the sample text box
attr.reset();
attr.setForeColor(foreground.color);
attr.setBold(foreground.bold);
attr.setForeColor(foreground.color);
try {
String text = foreground.rgb.getText();
while (text.startsWith("#")) {
text = text.substring(1);
}
if (text.length() > 0) {
int foreColorRGB = Integer.parseInt(text, 16);
if (foreColorRGB >= 0) {
attr.setForeColorRGB(foreColorRGB);
}
}
} catch (NumberFormatException e) {
// SQUASH
}
attr.setBackColor(background.color);
try {
String text = background.rgb.getText();
while (text.startsWith("#")) {
text = text.substring(1);
}
if (text.length() > 0) {
int backColorRGB = Integer.parseInt(text, 16);
if (backColorRGB >= 0) {
attr.setBackColorRGB(backColorRGB);
}
}
} catch (NumberFormatException e) {
// SQUASH
}
putStringXY(getWidth() - 17, getHeight() - 6,
i18n.getString("textTextText"), attr);
putStringXY(getWidth() - 17, getHeight() - 5,
@ -765,9 +863,26 @@ public class TEditColorThemeWindow extends TWindow {
*/
private void refreshFromTheme(final String colorName) {
CellAttributes attr = editTheme.getColor(colorName);
foreground.color = attr.getForeColor();
if (attr.getForeColorRGB() >= 0) {
foreground.rgb.setText(String.format("%06x",
attr.getForeColorRGB()));
} else {
foreground.rgb.setText("");
}
foreground.bold = attr.isBold();
background.color = attr.getBackColor();
if (attr.getBackColorRGB() >= 0) {
background.rgb.setText(String.format("%06x",
attr.getBackColorRGB()));
} else {
foreground.rgb.setText("");
}
}
/**
@ -781,8 +896,38 @@ public class TEditColorThemeWindow extends TWindow {
}
CellAttributes attr = editTheme.getColor(colorName);
attr.setForeColor(foreground.color);
try {
String text = foreground.rgb.getText();
while (text.startsWith("#")) {
text = text.substring(1);
}
if (text.length() > 0) {
int foreColorRGB = Integer.parseInt(text, 16);
if (foreColorRGB >= 0) {
attr.setForeColorRGB(foreColorRGB);
}
}
} catch (NumberFormatException e) {
// SQUASH
}
attr.setBold(foreground.bold);
attr.setBackColor(background.color);
try {
String text = background.rgb.getText();
while (text.startsWith("#")) {
text = text.substring(1);
}
if (text.length() > 0) {
int backColorRGB = Integer.parseInt(text, 16);
if (backColorRGB >= 0) {
attr.setBackColorRGB(backColorRGB);
}
}
} catch (NumberFormatException e) {
// SQUASH
}
editTheme.setColor(colorName, attr);
}

View file

@ -3,6 +3,9 @@ backgroundLabel=\ Background\
windowTitle=Colors
okButton=\ \ &OK\ \
cancelButton=&Cancel
loadButton=\ &Load\
saveButton=\ &Save\
statusBar=Select Colors
colorName=Color Name
textTextText=Text Text Text
rgbHex=RGB:

View file

@ -422,21 +422,22 @@ public class TImage extends TWidget implements EditMenuUser {
}
Cell cell = new Cell();
if ((width != textWidth) || (height != textHeight)) {
BufferedImage newImage;
newImage = new BufferedImage(textWidth, textHeight,
BufferedImage.TYPE_INT_ARGB);
java.awt.Graphics gr = newImage.getGraphics();
gr.drawImage(image.getSubimage(x * textWidth,
y * textHeight, width, height),
0, 0, null, null);
gr.dispose();
cell.setImage(newImage);
} else {
cell.setImage(image.getSubimage(x * textWidth,
y * textHeight, width, height));
}
// Always re-render the image against the cell
// background, so that alpha in the image does not lead
// to bleed-through artifacts.
BufferedImage newImage;
newImage = new BufferedImage(textWidth, textHeight,
BufferedImage.TYPE_INT_ARGB);
java.awt.Graphics gr = newImage.getGraphics();
gr.setColor(cell.getBackground());
gr.fillRect(0, 0, textWidth, textHeight);
gr.drawImage(image.getSubimage(x * textWidth,
y * textHeight, width, height),
0, 0, null, null);
gr.dispose();
cell.setImage(newImage);
cells[x][y] = cell;
}

View file

@ -0,0 +1,880 @@
/*
* Jexer - Java Text User Interface
*
* The MIT License (MIT)
*
* Copyright (C) 2019 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.awt.Font;
import java.awt.GraphicsEnvironment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import jexer.backend.ECMA48Terminal;
import jexer.backend.SwingTerminal;
import jexer.bits.CellAttributes;
import jexer.bits.GraphicsChars;
import jexer.event.TKeypressEvent;
import static jexer.TKeypress.*;
/**
* TScreenOptionsWindow provides an easy UI for users to alter the running
* screen options such as fonts and images.
*/
public class TScreenOptionsWindow extends TWindow {
/**
* Translated strings.
*/
private static final ResourceBundle i18n = ResourceBundle.getBundle(TScreenOptionsWindow.class.getName());
// ------------------------------------------------------------------------
// Variables --------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* The Swing screen.
*/
private SwingTerminal terminal = null;
/**
* The ECMA48 screen.
*/
private ECMA48Terminal ecmaTerminal = null;
/**
* The font name.
*/
private TComboBox fontName;
/**
* The font size.
*/
private TField fontSize;
/**
* The X text adjustment.
*/
private TField textAdjustX;
/**
* The Y text adjustment.
*/
private TField textAdjustY;
/**
* The height text adjustment.
*/
private TField textAdjustHeight;
/**
* The width text adjustment.
*/
private TField textAdjustWidth;
/**
* The sixel palette size.
*/
private TComboBox sixelPaletteSize;
/**
* The wideCharImages option.
*/
private TCheckBox wideCharImages;
/**
* Triple-buffer support.
*/
private TCheckBox tripleBuffer;
/**
* Cursor style.
*/
private TComboBox cursorStyle;
/**
* Mouse style.
*/
private TComboBox mouseStyle;
/**
* Sixel support.
*/
private TCheckBox sixel;
/**
* Whether or not sixel uses a single shared palette.
*/
private TCheckBox sixelSharedPalette;
/**
* 24-bit RGB color for normal system colors.
*/
private TCheckBox rgbColor;
/**
* The original font size.
*/
private int oldFontSize = 20;
/**
* The original font.
*/
private Font oldFont = null;
/**
* The original text adjust X value.
*/
private int oldTextAdjustX = 0;
/**
* The original text adjust Y value.
*/
private int oldTextAdjustY = 0;
/**
* The original text adjust height value.
*/
private int oldTextAdjustHeight = 0;
/**
* The original text adjust width value.
*/
private int oldTextAdjustWidth = 0;
/**
* The original sixel palette (number of colors) value.
*/
private int oldSixelPaletteSize = 1024;
/**
* The original wideCharImages value.
*/
private boolean oldWideCharImages = true;
/**
* The original triple-buffer support.
*/
private boolean oldTripleBuffer = true;
/**
* The original cursor style.
*/
private SwingTerminal.CursorStyle oldCursorStyle;
/**
* The original mouse style.
*/
private String oldMouseStyle = "default";
/**
* The original sixel support.
*/
private boolean oldSixel = true;
/**
* The original sixelSharedPalette value.
*/
private boolean oldSixelSharedPalette = true;
/**
* The original 24-bit RGB color for normal system colors.
*/
private boolean oldRgbColor = false;
// ------------------------------------------------------------------------
// Constructors -----------------------------------------------------------
// ------------------------------------------------------------------------
/**
* Public constructor. The window will be centered on screen.
*
* @param application the TApplication that manages this window
*/
public TScreenOptionsWindow(final TApplication application) {
// Register with the TApplication
super(application, i18n.getString("windowTitle"), 0, 0, 60, 23, MODAL);
// Add shortcut text
newStatusBar(i18n.getString("statusBar"));
if (getScreen() instanceof SwingTerminal) {
terminal = (SwingTerminal) getScreen();
}
if (getScreen() instanceof ECMA48Terminal) {
ecmaTerminal = (ECMA48Terminal) getScreen();
}
addLabel(i18n.getString("fontName"), 3, 2, "ttext", false,
new TAction() {
public void DO() {
if (fontName != null) {
fontName.activate();
}
}
});
addLabel(i18n.getString("fontSize"), 3, 3, "ttext", false,
new TAction() {
public void DO() {
if (fontSize != null) {
fontSize.activate();
}
}
});
addLabel(i18n.getString("textAdjustX"), 3, 4, "ttext", false,
new TAction() {
public void DO() {
if (textAdjustX != null) {
textAdjustX.activate();
}
}
});
addLabel(i18n.getString("textAdjustY"), 3, 5, "ttext", false,
new TAction() {
public void DO() {
if (textAdjustY != null) {
textAdjustY.activate();
}
}
});
addLabel(i18n.getString("textAdjustHeight"), 3, 6, "ttext", false,
new TAction() {
public void DO() {
if (textAdjustHeight != null) {
textAdjustHeight.activate();
}
}
});
addLabel(i18n.getString("textAdjustWidth"), 3, 7, "ttext", false,
new TAction() {
public void DO() {
if (textAdjustWidth != null) {
textAdjustWidth.activate();
}
}
});
addLabel(i18n.getString("cursorStyle"), 3, 10, "ttext", false,
new TAction() {
public void DO() {
if (cursorStyle != null) {
cursorStyle.activate();
}
}
});
addLabel(i18n.getString("mouseStyle"), 3, 11, "ttext", false,
new TAction() {
public void DO() {
if (mouseStyle != null) {
mouseStyle.activate();
}
}
});
sixel = addCheckBox(3, 15, i18n.getString("sixel"),
(ecmaTerminal != null ? ecmaTerminal.hasSixel() :
System.getProperty("jexer.ECMA48.sixel",
"true").equals("true")));
oldSixel = sixel.isChecked();
sixelSharedPalette = addCheckBox(3, 16,
i18n.getString("sixelSharedPalette"),
(ecmaTerminal != null ? ecmaTerminal.hasSixelSharedPalette() :
System.getProperty("jexer.ECMA48.sixelSharedPalette",
"true").equals("true")));
oldSixelSharedPalette = sixelSharedPalette.isChecked();
addLabel(i18n.getString("sixelPaletteSize"), 3, 17, "ttext", false,
new TAction() {
public void DO() {
if (sixelPaletteSize != null) {
sixelPaletteSize.activate();
}
}
});
wideCharImages = addCheckBox(3, 18, i18n.getString("wideCharImages"),
(ecmaTerminal != null ? ecmaTerminal.isWideCharImages() :
System.getProperty("jexer.ECMA48.wideCharImages",
"true").equals("true")));
oldWideCharImages = wideCharImages.isChecked();
rgbColor = addCheckBox(3, 19, i18n.getString("rgbColor"),
(ecmaTerminal != null ? ecmaTerminal.isRgbColor() :
System.getProperty("jexer.ECMA48.rgbColor",
"false").equals("true")));
oldRgbColor = rgbColor.isChecked();
int col = 23;
if (terminal == null) {
// Non-Swing case: turn off stuff we can't change
addLabel(i18n.getString("unavailable"), col, 2);
addLabel(i18n.getString("unavailable"), col, 3);
addLabel(i18n.getString("unavailable"), col, 4);
addLabel(i18n.getString("unavailable"), col, 5);
addLabel(i18n.getString("unavailable"), col, 6);
addLabel(i18n.getString("unavailable"), col, 7);
}
if (ecmaTerminal == null) {
// Swing case: turn off stuff we can't change
addLabel(i18n.getString("unavailable"), col, 17);
sixel.setEnabled(false);
sixelSharedPalette.setEnabled(false);
wideCharImages.setEnabled(false);
rgbColor.setEnabled(false);
}
if (ecmaTerminal != null) {
oldSixelPaletteSize = ecmaTerminal.getSixelPaletteSize();
String [] sixelSizes = { "2", "256", "512", "1024", "2048" };
List<String> sizes = new ArrayList<String>();
sizes.addAll(Arrays.asList(sixelSizes));
sixelPaletteSize = addComboBox(col, 17, 10, sizes, 0, 6,
new TAction() {
public void DO() {
try {
ecmaTerminal.setSixelPaletteSize(Integer.parseInt(
sixelPaletteSize.getText()));
} catch (NumberFormatException e) {
// SQUASH
}
}
}
);
sixelPaletteSize.setText(Integer.toString(oldSixelPaletteSize));
}
if (terminal != null) {
oldFont = terminal.getFont();
oldFontSize = terminal.getFontSize();
oldTextAdjustX = terminal.getTextAdjustX();
oldTextAdjustY = terminal.getTextAdjustY();
oldTextAdjustHeight = terminal.getTextAdjustHeight();
oldTextAdjustWidth = terminal.getTextAdjustWidth();
oldCursorStyle = terminal.getCursorStyle();
oldMouseStyle = terminal.getMouseStyle();
String [] fontNames = GraphicsEnvironment.
getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
List<String> fonts = new ArrayList<String>();
fonts.add(0, i18n.getString("builtInTerminus"));
fonts.addAll(Arrays.asList(fontNames));
fontName = addComboBox(col, 2, 25, fonts, 0, 8,
new TAction() {
public void DO() {
if (fontName.getText().equals(i18n.
getString("builtInTerminus"))) {
terminal.setDefaultFont();
} else {
terminal.setFont(new Font(fontName.getText(),
Font.PLAIN, terminal.getFontSize()));
fontSize.setText(Integer.toString(
terminal.getFontSize()));
textAdjustX.setText(Integer.toString(
terminal.getTextAdjustX()));
textAdjustY.setText(Integer.toString(
terminal.getTextAdjustY()));
textAdjustHeight.setText(Integer.toString(
terminal.getTextAdjustHeight()));
textAdjustWidth.setText(Integer.toString(
terminal.getTextAdjustWidth()));
}
}
}
);
// Font size
fontSize = addField(col, 3, 3, true,
Integer.toString(terminal.getFontSize()),
new TAction() {
public void DO() {
int currentSize = terminal.getFontSize();
int newSize = currentSize;
try {
newSize = Integer.parseInt(fontSize.getText());
} catch (NumberFormatException e) {
fontSize.setText(Integer.toString(currentSize));
}
if (newSize != currentSize) {
terminal.setFontSize(newSize);
textAdjustX.setText(Integer.toString(
terminal.getTextAdjustX()));
textAdjustY.setText(Integer.toString(
terminal.getTextAdjustY()));
textAdjustHeight.setText(Integer.toString(
terminal.getTextAdjustHeight()));
textAdjustWidth.setText(Integer.toString(
terminal.getTextAdjustWidth()));
}
}
},
null);
addSpinner(col + 3, 3,
new TAction() {
public void DO() {
int currentSize = terminal.getFontSize();
int newSize = currentSize;
try {
newSize = Integer.parseInt(fontSize.getText());
newSize++;
} catch (NumberFormatException e) {
fontSize.setText(Integer.toString(currentSize));
}
fontSize.setText(Integer.toString(newSize));
if (newSize != currentSize) {
terminal.setFontSize(newSize);
textAdjustX.setText(Integer.toString(
terminal.getTextAdjustX()));
textAdjustY.setText(Integer.toString(
terminal.getTextAdjustY()));
textAdjustHeight.setText(Integer.toString(
terminal.getTextAdjustHeight()));
textAdjustWidth.setText(Integer.toString(
terminal.getTextAdjustWidth()));
}
}
},
new TAction() {
public void DO() {
int currentSize = terminal.getFontSize();
int newSize = currentSize;
try {
newSize = Integer.parseInt(fontSize.getText());
newSize--;
} catch (NumberFormatException e) {
fontSize.setText(Integer.toString(currentSize));
}
fontSize.setText(Integer.toString(newSize));
if (newSize != currentSize) {
terminal.setFontSize(newSize);
textAdjustX.setText(Integer.toString(
terminal.getTextAdjustX()));
textAdjustY.setText(Integer.toString(
terminal.getTextAdjustY()));
textAdjustHeight.setText(Integer.toString(
terminal.getTextAdjustHeight()));
textAdjustWidth.setText(Integer.toString(
terminal.getTextAdjustWidth()));
}
}
}
);
// textAdjustX
textAdjustX = addField(col, 4, 3, true,
Integer.toString(terminal.getTextAdjustX()),
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustX();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustX.getText());
} catch (NumberFormatException e) {
textAdjustX.setText(Integer.toString(currentAdjust));
}
if (newAdjust != currentAdjust) {
terminal.setTextAdjustX(newAdjust);
}
}
},
null);
addSpinner(col + 3, 4,
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustX();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustX.getText());
newAdjust++;
} catch (NumberFormatException e) {
textAdjustX.setText(Integer.toString(currentAdjust));
}
textAdjustX.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustX(newAdjust);
}
}
},
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustX();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustX.getText());
newAdjust--;
} catch (NumberFormatException e) {
textAdjustX.setText(Integer.toString(currentAdjust));
}
textAdjustX.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustX(newAdjust);
}
}
}
);
// textAdjustY
textAdjustY = addField(col, 5, 3, true,
Integer.toString(terminal.getTextAdjustY()),
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustY();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustY.getText());
} catch (NumberFormatException e) {
textAdjustY.setText(Integer.toString(currentAdjust));
}
if (newAdjust != currentAdjust) {
terminal.setTextAdjustY(newAdjust);
}
}
},
null);
addSpinner(col + 3, 5,
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustY();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustY.getText());
newAdjust++;
} catch (NumberFormatException e) {
textAdjustY.setText(Integer.toString(currentAdjust));
}
textAdjustY.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustY(newAdjust);
}
}
},
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustY();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustY.getText());
newAdjust--;
} catch (NumberFormatException e) {
textAdjustY.setText(Integer.toString(currentAdjust));
}
textAdjustY.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustY(newAdjust);
}
}
}
);
// textAdjustHeight
textAdjustHeight = addField(col, 6, 3, true,
Integer.toString(terminal.getTextAdjustHeight()),
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustHeight();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustHeight.getText());
} catch (NumberFormatException e) {
textAdjustHeight.setText(Integer.toString(currentAdjust));
}
if (newAdjust != currentAdjust) {
terminal.setTextAdjustHeight(newAdjust);
}
}
},
null);
addSpinner(col + 3, 6,
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustHeight();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustHeight.getText());
newAdjust++;
} catch (NumberFormatException e) {
textAdjustHeight.setText(Integer.toString(currentAdjust));
}
textAdjustHeight.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustHeight(newAdjust);
}
}
},
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustHeight();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustHeight.getText());
newAdjust--;
} catch (NumberFormatException e) {
textAdjustHeight.setText(Integer.toString(currentAdjust));
}
textAdjustHeight.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustHeight(newAdjust);
}
}
}
);
// textAdjustWidth
textAdjustWidth = addField(col, 7, 3, true,
Integer.toString(terminal.getTextAdjustWidth()),
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustWidth();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustWidth.getText());
} catch (NumberFormatException e) {
textAdjustWidth.setText(Integer.toString(currentAdjust));
}
if (newAdjust != currentAdjust) {
terminal.setTextAdjustWidth(newAdjust);
}
}
},
null);
addSpinner(col + 3, 7,
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustWidth();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustWidth.getText());
newAdjust++;
} catch (NumberFormatException e) {
textAdjustWidth.setText(Integer.toString(currentAdjust));
}
textAdjustWidth.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustWidth(newAdjust);
}
}
},
new TAction() {
public void DO() {
int currentAdjust = terminal.getTextAdjustWidth();
int newAdjust = currentAdjust;
try {
newAdjust = Integer.parseInt(textAdjustWidth.getText());
newAdjust--;
} catch (NumberFormatException e) {
textAdjustWidth.setText(Integer.toString(currentAdjust));
}
textAdjustWidth.setText(Integer.toString(newAdjust));
if (newAdjust != currentAdjust) {
terminal.setTextAdjustWidth(newAdjust);
}
}
}
);
} // if (terminal != null)
tripleBuffer = addCheckBox(3, 9, i18n.getString("tripleBuffer"),
(terminal != null ? terminal.isTripleBuffer() :
System.getProperty("jexer.Swing.tripleBuffer",
"true").equals("true")));
oldTripleBuffer = tripleBuffer.isChecked();
ArrayList<String> cursorStyles = new ArrayList<String>();
cursorStyles.add(i18n.getString("cursorStyleBlock").toLowerCase());
cursorStyles.add(i18n.getString("cursorStyleOutline").toLowerCase());
cursorStyles.add(i18n.getString("cursorStyleUnderline").toLowerCase());
cursorStyle = addComboBox(22, 10, 25, cursorStyles, 0, 4,
new TAction() {
public void DO() {
terminal.setCursorStyle(cursorStyle.getText());
}
});
cursorStyle.setText((terminal == null ?
System.getProperty("jexer.Swing.cursorStyle", "underline") :
terminal.getCursorStyle().toString().toLowerCase()));
ArrayList<String> mouseStyles = new ArrayList<String>();
mouseStyles.add("default");
mouseStyles.add("crosshair");
mouseStyles.add("hand");
mouseStyles.add("move");
mouseStyles.add("text");
mouseStyles.add("none");
mouseStyle = addComboBox(22, 11, 25, mouseStyles, 0, 7,
new TAction() {
public void DO() {
terminal.setMouseStyle(mouseStyle.getText());
}
});
mouseStyle.setText((terminal == null ?
System.getProperty("jexer.Swing.mouseStyle", "default") :
terminal.getMouseStyle().toLowerCase()));
if (terminal == null) {
tripleBuffer.setEnabled(false);
cursorStyle.setEnabled(false);
mouseStyle.setEnabled(false);
}
addButton(i18n.getString("okButton"),
getWidth() - 13, getHeight() - 7,
new TAction() {
public void DO() {
// Copy values out.
if (ecmaTerminal != null) {
ecmaTerminal.setHasSixel(sixel.isChecked());
ecmaTerminal.setSixelSharedPalette(sixelSharedPalette.
isChecked());
ecmaTerminal.setWideCharImages(wideCharImages.
isChecked());
ecmaTerminal.setRgbColor(rgbColor.isChecked());
}
if (terminal != null) {
synchronized (terminal) {
terminal.setTripleBuffer(tripleBuffer.isChecked());
terminal.setFont(terminal.getFont());
}
}
// Close window.
TScreenOptionsWindow.this.close();
}
});
TButton cancelButton = addButton(i18n.getString("cancelButton"),
getWidth() - 13, getHeight() - 5,
new TAction() {
public void DO() {
// Restore old values, then close the window.
if (terminal != null) {
synchronized (terminal) {
terminal.setFont(oldFont);
terminal.setFontSize(oldFontSize);
terminal.setTextAdjustX(oldTextAdjustX);
terminal.setTextAdjustY(oldTextAdjustY);
terminal.setTextAdjustHeight(oldTextAdjustHeight);
terminal.setTextAdjustWidth(oldTextAdjustWidth);
terminal.setTripleBuffer(oldTripleBuffer);
terminal.setCursorStyle(oldCursorStyle);
terminal.setMouseStyle(oldMouseStyle);
}
}
if (ecmaTerminal != null) {
ecmaTerminal.setHasSixel(oldSixel);
ecmaTerminal.setSixelSharedPalette(oldSixelSharedPalette);
ecmaTerminal.setSixelPaletteSize(oldSixelPaletteSize);
ecmaTerminal.setWideCharImages(oldWideCharImages);
ecmaTerminal.setRgbColor(oldRgbColor);
}
TScreenOptionsWindow.this.close();
}
});
// Save this for last: make the cancel button default action.
activate(cancelButton);
}
// ------------------------------------------------------------------------
// Event handlers ---------------------------------------------------------
// ------------------------------------------------------------------------
/**
* Handle keystrokes.
*
* @param keypress keystroke event
*/
@Override
public void onKeypress(final TKeypressEvent keypress) {
// Escape - behave like cancel
if (keypress.equals(kbEsc)) {
// Restore old values, then close the window.
if (terminal != null) {
synchronized (terminal) {
terminal.setFont(oldFont);
terminal.setFontSize(oldFontSize);
terminal.setTextAdjustX(oldTextAdjustX);
terminal.setTextAdjustY(oldTextAdjustY);
terminal.setTextAdjustHeight(oldTextAdjustHeight);
terminal.setTextAdjustWidth(oldTextAdjustWidth);
terminal.setTripleBuffer(oldTripleBuffer);
terminal.setCursorStyle(oldCursorStyle);
terminal.setMouseStyle(oldMouseStyle);
}
}
if (ecmaTerminal != null) {
ecmaTerminal.setHasSixel(oldSixel);
ecmaTerminal.setSixelSharedPalette(oldSixelSharedPalette);
ecmaTerminal.setSixelPaletteSize(oldSixelPaletteSize);
ecmaTerminal.setWideCharImages(oldWideCharImages);
ecmaTerminal.setRgbColor(oldRgbColor);
}
getApplication().closeWindow(this);
return;
}
// Pass to my parent
super.onKeypress(keypress);
}
// ------------------------------------------------------------------------
// TWindow ----------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* Draw me on screen.
*/
@Override
public void draw() {
super.draw();
int left = 34;
CellAttributes color = getTheme().getColor("ttext");
drawBox(2, 2, left + 24, 14, color, color);
putStringXY(4, 2, i18n.getString("swingOptions"), color);
drawBox(2, 15, left + 12, 22, color, color);
putStringXY(4, 15, i18n.getString("xtermOptions"), color);
drawBox(left + 2, 5, left + 22, 10, color, color, 3, false);
putStringXY(left + 4, 5, i18n.getString("sample"), color);
for (int i = 6; i < 9; i++) {
hLineXY(left + 3, i, 18, GraphicsChars.HATCH, color);
}
}
// ------------------------------------------------------------------------
// TScreenOptionsWindow ---------------------------------------------------
// ------------------------------------------------------------------------
}

View file

@ -0,0 +1,34 @@
windowTitle=Screen
okButton=\ \ &OK\ \
cancelButton=&Cancel
statusBar=Select Screen Options
unavailable=Unavailable
builtInTerminus=Built-In Terminus
swingOptions=\ Swing Options\
fontName=&Font name:
fontSize=Fo&nt size:
textAdjustX=&X adjust:
textAdjustY=&Y adjust:
textAdjustHeight=&Height adjust:
textAdjustWidth=&Width adjust:
tripleBuffer=Triple-&buffer output
cursorStyle=C&ursor style:
cursorStyleBlock=block
cursorStyleOutline=outline
cursorStyleUnderline=underline
mouseStyle=&Mouse style:
mouseStyleBlock=block
mouseStyleOutline=outline
mouseStyleUnderline=underline
sample=\ Sample Window\
xtermOptions=\ Xterm Options\
sixel=Display images with &sixel
sixelPaletteSize=Sixel &palette size:
sixelSharedPalette=Us&e shared sixel palette
wideCharImages=D&raw fullwidth characters as images
rgbColor=Use 24-bit R&GB for all colors

View file

@ -357,7 +357,7 @@ public class TSplitPane extends TWidget {
/**
* Get focusFollowsMouse flag.
*
* @return true if focus follows mouse: widgets automatically activated
* @return true if focus follows mouse: widgets automatically activate
* if the mouse passes over them
*/
public boolean getFocusFollowsMouse() {

View file

@ -961,6 +961,15 @@ public class TTerminalWidget extends TScrollableWidget
hideMouseWhenTyping = false;
}
try {
int scrollbackMax = Integer.parseInt(System.getProperty(
"jexer.TTerminal.scrollbackMax", "2000"));
emulator.setScrollbackMax(scrollbackMax);
} catch (NumberFormatException e) {
// SQUASH
}
}
/**

View file

@ -62,6 +62,11 @@ public class TTerminalWindow extends TScrollableWindow {
*/
private boolean closeOnExit = false;
/**
* If true, setTitle() was called and this title will be honored.
*/
private boolean titleOverride = false;
// ------------------------------------------------------------------------
// Constructors -----------------------------------------------------------
// ------------------------------------------------------------------------
@ -221,7 +226,7 @@ public class TTerminalWindow extends TScrollableWindow {
*/
@Override
public void draw() {
if (terminal != null) {
if ((terminal != null) && (titleOverride == false)) {
setTitle(terminal.getTitle());
}
reflowData();
@ -477,4 +482,16 @@ public class TTerminalWindow extends TScrollableWindow {
return terminal.getExitValue();
}
/**
* Set window title.
*
* @param title new window title
* @param override if true, force the title to never change regardless of
* the desired title from the running terminal
*/
public final void setTitle(final String title, final boolean override) {
super.setTitle(title);
this.titleOverride = override;
}
}

View file

@ -1351,9 +1351,9 @@ public abstract class TWidget implements Comparable<TWidget> {
}
/**
* Called by parent to render to TWindow. Note package private access.
* Called by parent to render to TWindow.
*/
final void drawChildren() {
public final void drawChildren() {
if (!isDrawable()) {
return;
}
@ -1686,6 +1686,9 @@ public abstract class TWidget implements Comparable<TWidget> {
// TSplitPane has a left/right/top/bottom link to me somewhere,
// replace it with a link to splitPane.
((TSplitPane) myParent).replaceWidget(this, splitPane);
splitPane.setFocusFollowsMouse(((TSplitPane) myParent).
getFocusFollowsMouse());
}
splitPane.setParent(myParent, false);
if (newWidgetOnLeft) {
@ -1737,6 +1740,9 @@ public abstract class TWidget implements Comparable<TWidget> {
// TSplitPane has a left/right/top/bottom link to me somewhere,
// replace it with a link to splitPane.
((TSplitPane) myParent).replaceWidget(this, splitPane);
splitPane.setFocusFollowsMouse(((TSplitPane) myParent).
getFocusFollowsMouse());
}
splitPane.setParent(myParent, false);
if (newWidgetOnTop) {

View file

@ -1029,7 +1029,7 @@ public class TWindow extends TWidget {
*
* @param key the key to start taking control of
*/
protected void addShortcutKeypress(final TKeypress key) {
public void addShortcutKeypress(final TKeypress key) {
keyboardShortcuts.add(key);
}
@ -1038,7 +1038,7 @@ public class TWindow extends TWidget {
*
* @param key the key to stop taking control of
*/
protected void removeShortcutKeypress(final TKeypress key) {
public void removeShortcutKeypress(final TKeypress key) {
keyboardShortcuts.remove(key);
}
@ -1079,6 +1079,15 @@ public class TWindow extends TWidget {
return statusBar;
}
/**
* Get the maximum width for this window.
*
* @return the maximum width
*/
public final int getMaximumWindowWidth() {
return maximumWindowWidth;
}
/**
* Set the maximum width for this window.
*
@ -1094,6 +1103,15 @@ public class TWindow extends TWidget {
this.maximumWindowWidth = maximumWindowWidth;
}
/**
* Get the minimum width for this window.
*
* @return the minimum width
*/
public final int getMinimumWindowWidth() {
return minimumWindowWidth;
}
/**
* Set the minimum width for this window.
*
@ -1109,6 +1127,15 @@ public class TWindow extends TWidget {
this.minimumWindowWidth = minimumWindowWidth;
}
/**
* Get the maximum height for this window.
*
* @return the maximum height
*/
public final int getMaximumWindowHeight() {
return maximumWindowHeight;
}
/**
* Set the maximum height for this window.
*
@ -1124,6 +1151,15 @@ public class TWindow extends TWidget {
this.maximumWindowHeight = maximumWindowHeight;
}
/**
* Get the minimum height for this window.
*
* @return the minimum height
*/
public final int getMinimumWindowHeight() {
return minimumWindowHeight;
}
/**
* Set the minimum height for this window.
*

View file

@ -3116,6 +3116,86 @@ public class ECMA48Terminal extends LogicalScreen
// Sixel output support ---------------------------------------------------
// ------------------------------------------------------------------------
/**
* Get the wideCharImages flag.
*
* @return true if fullwidth characters (e.g. CJK) are being drawn as
* images
*/
public boolean isWideCharImages() {
return wideCharImages;
}
/**
* Set the wideCharImages flag.
*
* @param wideCharImages if true, draw fullwidth characters (e.g. CJK) as
* images
*/
public void setWideCharImages(final boolean wideCharImages) {
this.wideCharImages = wideCharImages;
}
/**
* Get the rgbColor flag.
*
* @return true if the standard system colors will be emitted as 24-bit RGB
*/
public boolean isRgbColor() {
return doRgbColor;
}
/**
* Set the rgbColor flag.
*
* @param rgbColor if true, the standard system colors will be emitted as
* 24-bit RGB images
*/
public void setRgbColor(final boolean rgbColor) {
doRgbColor = rgbColor;
}
/**
* Set sixel output support flag.
*
* @param sixel if true, then images will be emitted as sixel
*/
public void setHasSixel(final boolean sixel) {
// Don't step on the screen refresh thread.
synchronized (this) {
this.sixel = sixel;
palette = null;
sixelCache = null;
clearPhysical();
}
}
/**
* Get the sixel shared palette option.
*
* @return true if all sixel output is using the same palette that is set
* in one DCS sequence and used in later sequences
*/
public boolean hasSixelSharedPalette() {
return sixelSharedPalette;
}
/**
* Set the sixel shared palette option.
*
* @param sharedPalette if true, then all sixel output will use the same
* palette that is set in one DCS sequence and used in later sequences
*/
public void setSixelSharedPalette(final boolean sharedPalette) {
// Don't step on the screen refresh thread.
synchronized (this) {
this.sixelSharedPalette = sharedPalette;
palette = null;
sixelCache = null;
clearPhysical();
}
}
/**
* Get the number of colors in the sixel palette.
*

View file

@ -1223,4 +1223,23 @@ public class LogicalScreen implements Screen {
clipboard.copyText(sb.toString());
}
/**
* Obtain a snapshot copy of the screen.
*
* @return a copy of the screen's data
*/
public Screen snapshot() {
LogicalScreen other = null;
synchronized (this) {
other = new LogicalScreen();
other.setDimensions(width, height);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
other.logical[col][row] = new Cell(logical[col][row]);
}
}
}
return other;
}
}

View file

@ -770,4 +770,26 @@ public class MultiScreen implements Screen {
}
}
/**
* Obtain a snapshot copy of the screen.
*
* @return a copy of the screen's data
*/
public Screen snapshot() {
// Only copy from the first screen.
if (screens.size() > 0) {
return screens.get(0).snapshot();
}
// No screens are defined, create a blank.
LogicalScreen other = null;
other = new LogicalScreen();
int width = 80;
int height = 25;
other.setDimensions(width, height);
return other;
}
}

View file

@ -456,4 +456,11 @@ public interface Screen {
final int x0, final int y0, final int x1, final int y1,
final boolean rectangle);
/**
* Obtain a snapshot copy of the screen.
*
* @return a copy of the screen's data
*/
public Screen snapshot();
}

View file

@ -167,13 +167,14 @@ public class SwingComponent {
if (System.getProperty("jexer.Swing.mouseImage") != null) {
component.setCursor(getMouseImage());
} else if (System.getProperty("jexer.Swing.mouseStyle") != null) {
component.setCursor(getMouseCursor());
setMouseStyle(System.getProperty("jexer.Swing.mouseStyle"));
} else if (System.getProperty("jexer.textMouse",
"true").equals("false")
) {
// If the user has suppressed the text mouse, don't kill the X11
// mouse.
component.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
component.setCursor(Cursor.getPredefinedCursor(
Cursor.DEFAULT_CURSOR));
} else {
// Kill the X11 cursor
// Transparent 16 x 16 pixel cursor image.
@ -200,13 +201,13 @@ public class SwingComponent {
if (System.getProperty("jexer.Swing.mouseImage") != null) {
frame.setCursor(getMouseImage());
} else if (System.getProperty("jexer.Swing.mouseStyle") != null) {
frame.setCursor(getMouseCursor());
setMouseStyle(System.getProperty("jexer.Swing.mouseStyle"));
} else if (System.getProperty("jexer.textMouse",
"true").equals("false")
) {
// If the user has suppressed the text mouse, don't kill the X11
// mouse.
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
} else {
// Kill the X11 cursor
// Transparent 16 x 16 pixel cursor image.
@ -269,37 +270,43 @@ public class SwingComponent {
}
/**
* Get the appropriate mouse cursor based on jexer.Swing.mouseStyle.
* Set the mouse cursor style.
*
* @return the cursor
* @param style the cursor style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
private Cursor getMouseCursor() {
Cursor cursor = Cursor.getDefaultCursor();
String style = System.getProperty("jexer.Swing.mouseStyle");
public void setMouseStyle(final String style) {
assert (style != null);
style = style.toLowerCase();
String styleLower = style.toLowerCase();
if (style.equals("none")) {
Cursor cursor = Cursor.getDefaultCursor();
if (styleLower.equals("none")) {
// Transparent 16 x 16 pixel cursor image.
BufferedImage cursorImg = new BufferedImage(16, 16,
BufferedImage.TYPE_INT_ARGB);
// Create a new blank cursor.
cursor = Toolkit.getDefaultToolkit().createCustomCursor(
cursorImg, new Point(0, 0), "blank cursor");
} else if (style.equals("default")) {
} else if (styleLower.equals("default")) {
cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
} else if (style.equals("hand")) {
} else if (styleLower.equals("hand")) {
cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
} else if (style.equals("text")) {
} else if (styleLower.equals("text")) {
cursor = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
} else if (style.equals("move")) {
} else if (styleLower.equals("move")) {
cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
} else if (style.equals("crosshair")) {
} else if (styleLower.equals("crosshair")) {
cursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
}
return cursor;
if (frame != null) {
frame.setCursor(cursor);
}
if (component != null) {
component.setCursor(cursor);
}
}
/**

View file

@ -245,6 +245,11 @@ public class SwingTerminal extends LogicalScreen
*/
private CursorStyle cursorStyle = CursorStyle.UNDERLINE;
/**
* The mouse cursor style.
*/
private String mouseStyle = "default";
/**
* The number of millis to wait before switching the blink from visible
* to invisible. Set to 0 or negative to disable blinking.
@ -411,6 +416,8 @@ public class SwingTerminal extends LogicalScreen
SwingTerminal.this.resizeToScreen(true);
SwingTerminal.this.swing.setVisible(true);
SwingTerminal.this.swing.setMouseStyle(mouseStyle);
}
});
} catch (java.lang.reflect.InvocationTargetException e) {
@ -524,6 +531,8 @@ public class SwingTerminal extends LogicalScreen
new SwingSessionInfo(SwingTerminal.this.swing,
SwingTerminal.this.textWidth,
SwingTerminal.this.textHeight);
SwingTerminal.this.swing.setMouseStyle(mouseStyle);
}
});
} catch (java.lang.reflect.InvocationTargetException e) {
@ -644,17 +653,8 @@ public class SwingTerminal extends LogicalScreen
*/
public void reloadOptions() {
// Figure out my cursor style.
String cursorStyleString = System.getProperty(
"jexer.Swing.cursorStyle", "underline").toLowerCase();
if (cursorStyleString.equals("underline")) {
cursorStyle = CursorStyle.UNDERLINE;
} else if (cursorStyleString.equals("outline")) {
cursorStyle = CursorStyle.OUTLINE;
} else if (cursorStyleString.equals("block")) {
cursorStyle = CursorStyle.BLOCK;
} else if (cursorStyleString.equals("verticalbar")) {
cursorStyle = CursorStyle.VERTICAL_BAR;
}
setCursorStyle(System.getProperty("jexer.Swing.cursorStyle",
"underline"));
// Pull the system property for triple buffering.
if (System.getProperty("jexer.Swing.tripleBuffer",
@ -665,6 +665,8 @@ public class SwingTerminal extends LogicalScreen
SwingComponent.tripleBuffer = false;
}
mouseStyle = System.getProperty("jexer.Swing.mouseStyle", "default");
// Set custom colors
setCustomSystemColors();
}
@ -673,6 +675,80 @@ public class SwingTerminal extends LogicalScreen
// SwingTerminal ----------------------------------------------------------
// ------------------------------------------------------------------------
/**
* Get triple buffering flag.
*
* @return true if triple buffering is enabled
*/
public boolean isTripleBuffer() {
return SwingComponent.tripleBuffer;
}
/**
* Set triple buffering.
*
* @param tripleBuffer if true, enable triple buffering
*/
public void setTripleBuffer(final boolean tripleBuffer) {
SwingComponent.tripleBuffer = tripleBuffer;
}
/**
* Set the mouse cursor style.
*
* @param style the cursor style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
public void setMouseStyle(final String style) {
this.mouseStyle = style;
swing.setMouseStyle(mouseStyle);
}
/**
* Get the mouse cursor style.
*
* @return the cursor style string, one of: "default", "none", "hand",
* "text", "move", or "crosshair"
*/
public String getMouseStyle() {
return mouseStyle;
}
/**
* Get the cursor style.
*
* @return the cursor style
*/
public CursorStyle getCursorStyle() {
return cursorStyle;
}
/**
* Set the cursor style.
*
* @param cursorStyle the new cursor style
*/
public void setCursorStyle(final CursorStyle cursorStyle) {
this.cursorStyle = cursorStyle;
}
/**
* Set the cursor style.
*
* @param cursorStyleString the new cursor style
*/
public void setCursorStyle(final String cursorStyleString) {
if (cursorStyleString.toLowerCase().equals("underline")) {
cursorStyle = CursorStyle.UNDERLINE;
} else if (cursorStyleString.toLowerCase().equals("outline")) {
cursorStyle = CursorStyle.OUTLINE;
} else if (cursorStyleString.toLowerCase().equals("block")) {
cursorStyle = CursorStyle.BLOCK;
} else if (cursorStyleString.toLowerCase().equals("verticalbar")) {
cursorStyle = CursorStyle.VERTICAL_BAR;
}
}
/**
* Get the width of a character cell in pixels.
*
@ -1238,27 +1314,15 @@ public class SwingTerminal extends LogicalScreen
// Draw the background rectangle, then the foreground character.
assert (cell.isImage());
// Enable anti-aliasing
if (gr instanceof Graphics2D) {
((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
}
gr.setColor(cell.getBackground());
gr.fillRect(xPixel, yPixel, textWidth, textHeight);
BufferedImage image = cell.getImage();
if (image != null) {
if (swing.getFrame() != null) {
gr.drawImage(image, xPixel, yPixel, getTextWidth(),
getTextHeight(), swing.getFrame());
} else {
gr.drawImage(image, xPixel, yPixel, getTextWidth(),
getTextHeight(), swing.getComponent());
}
return;
assert (image != null);
if (swing.getFrame() != null) {
gr.drawImage(image, xPixel, yPixel, textWidth,
textHeight, swing.getFrame());
} else {
gr.drawImage(image, xPixel, yPixel, textWidth,
textHeight, swing.getComponent());
}
}
@ -1318,17 +1382,6 @@ public class SwingTerminal extends LogicalScreen
cellColor.setBackColor(cell.getForeColor());
}
// Enable anti-aliasing
if ((gr instanceof Graphics2D) && (swing.getFrame() != null)) {
// Anti-aliasing on JComponent makes the hash character disappear
// for Terminus font, and also kills performance. Only enable it
// for JFrame.
((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
}
// Draw the background rectangle, then the foreground character.
gr2.setColor(attrToBackgroundColor(cellColor));
gr2.fillRect(gr2x, gr2y, textWidth, textHeight);

View file

@ -28,7 +28,6 @@
*/
package jexer.bits;
import java.awt.Color;
import java.awt.image.BufferedImage;
/**
@ -94,7 +93,7 @@ public class Cell extends CellAttributes {
* The background color used for the area the image portion might not
* cover.
*/
private Color background = Color.BLACK;
private java.awt.Color background = java.awt.Color.BLACK;
/**
* hashCode() needs to call image.hashCode(), which can get quite
@ -194,7 +193,7 @@ public class Cell extends CellAttributes {
*
* @return the bitmap image background color
*/
public Color getBackground() {
public java.awt.Color getBackground() {
return background;
}
@ -306,7 +305,7 @@ public class Cell extends CellAttributes {
image = null;
imageHashCode = 0;
invertedImage = null;
background = Color.BLACK;
background = java.awt.Color.BLACK;
backgroundHashCode = 0;
}
@ -321,7 +320,7 @@ public class Cell extends CellAttributes {
image = null;
imageHashCode = 0;
invertedImage = null;
background = Color.BLACK;
background = java.awt.Color.BLACK;
backgroundHashCode = 0;
}
@ -336,8 +335,8 @@ public class Cell extends CellAttributes {
if ((ch == UNSET_VALUE) || (image != null)) {
return false;
}
if ((getForeColor().equals(Color.WHITE))
&& (getBackColor().equals(Color.BLACK))
if ((getForeColor().equals(jexer.bits.Color.WHITE))
&& (getBackColor().equals(jexer.bits.Color.BLACK))
&& !isBold()
&& !isBlink()
&& !isReverse()
@ -350,7 +349,6 @@ public class Cell extends CellAttributes {
) {
return true;
}
return false;
}

View file

@ -245,6 +245,7 @@ public class CellAttributes {
*/
public final void setForeColor(final Color foreColor) {
this.foreColor = foreColor;
this.foreColorRGB = -1;
}
/**
@ -263,6 +264,7 @@ public class CellAttributes {
*/
public final void setBackColor(final Color backColor) {
this.backColor = backColor;
this.backColorRGB = -1;
}
/**
@ -383,9 +385,22 @@ public class CellAttributes {
@Override
public String toString() {
if ((foreColorRGB >= 0) || (backColorRGB >= 0)) {
return String.format("RGB: #%06x on #%06x",
(foreColorRGB & 0xFFFFFF),
(backColorRGB & 0xFFFFFF));
StringBuilder sb = new StringBuilder("RGB: ");
if (foreColorRGB < 0) {
sb.append(foreColor.toRgbString());
} else {
sb.append(String.format("#%06x",
(foreColorRGB & 0xFFFFFF)));
}
sb.append(" on ");
if (backColorRGB < 0) {
sb.append(backColor.toRgbString());
} else {
sb.append(String.format("#%06x",
(backColorRGB & 0xFFFFFF)));
}
return sb.toString();
}
return String.format("%s%s%s on %s", (isBold() ? "bold " : ""),
(isBlink() ? "blink " : ""), foreColor, backColor);

View file

@ -151,7 +151,11 @@ public class ColorTheme {
// Foreground
int foreColorRGB = -1;
try {
foreColorRGB = Integer.parseInt(tokenizer.nextToken(), 16);
String rgbText = tokenizer.nextToken();
while (rgbText.startsWith("#")) {
rgbText = rgbText.substring(1);
}
foreColorRGB = Integer.parseInt(rgbText, 16);
} catch (NumberFormatException e) {
// Default to white on black
foreColorRGB = 0xFFFFFF;
@ -166,7 +170,11 @@ public class ColorTheme {
// Background
int backColorRGB = -1;
try {
backColorRGB = Integer.parseInt(tokenizer.nextToken(), 16);
String rgbText = tokenizer.nextToken();
while (rgbText.startsWith("#")) {
rgbText = rgbText.substring(1);
}
backColorRGB = Integer.parseInt(rgbText, 16);
} catch (NumberFormatException e) {
backColorRGB = 0;
}

View file

@ -159,6 +159,11 @@ public class TMenu extends TWindow {
*/
boolean useIcons = false;
/**
* If true, this is a context menu.
*/
private boolean context = false;
// ------------------------------------------------------------------------
// Constructors -----------------------------------------------------------
// ------------------------------------------------------------------------
@ -314,14 +319,18 @@ public class TMenu extends TWindow {
return;
}
if (keypress.equals(kbRight)) {
getApplication().switchMenu(true);
if (!context) {
getApplication().switchMenu(true);
}
return;
}
if (keypress.equals(kbLeft)) {
if (isSubMenu) {
getApplication().closeSubMenu();
} else {
getApplication().switchMenu(false);
if (!context) {
getApplication().switchMenu(false);
}
}
return;
}
@ -435,6 +444,50 @@ public class TMenu extends TWindow {
return mnemonic;
}
/**
* Get the context flag.
*
* @return true if this menu is a right-click context menu
*/
public boolean isContext() {
return context;
}
/**
* Set the context flag, used to open a context menu at a specific screen
* position.
*
* @param context if true, this is a context menu
* @param x the screen X position
* @param y the screen Y position
*/
public void setContext(final boolean context, final int x, final int y) {
this.context = context;
setX(x);
setY(y);
while (getX() + getWidth() > getScreen().getWidth()) {
setX(getX() - 1);
}
while (getY() + getHeight() > getApplication().getDesktopBottom()) {
setY(getY() - 1);
}
}
/**
* Set the context flag.
*
* @param context if true, this is a context menu
*/
public void setContext(final boolean context) {
if (context == false) {
setX(0);
setY(1);
getApplication().recomputeMenuX();
}
this.context = context;
}
/**
* Convenience function to add a menu item.
*

View file

@ -129,7 +129,9 @@ public class TSubMenu extends TMenuItem {
if (parentMenu.isSubMenu) {
getApplication().closeSubMenu();
} else {
getApplication().switchMenu(false);
if (!parentMenu.isContext()) {
getApplication().switchMenu(false);
}
}
return;
}
@ -174,8 +176,23 @@ public class TSubMenu extends TMenuItem {
assert (isEnabled());
if (isAbsoluteActive()) {
if (!menu.isActive()) {
menu.setX(getAbsoluteX() + getWidth() - 1);
menu.setY(getAbsoluteY());
while (menu.getX() + menu.getWidth() > getScreen().getWidth()) {
menu.setX(menu.getX() - 1);
}
while (menu.getY() + menu.getHeight() > getApplication().
getDesktopBottom()
) {
menu.setY(menu.getY() - 1);
}
getApplication().addSubMenu(menu);
menu.setActive(true);
TMenu parentMenu = (TMenu) getParent();
if (parentMenu.isContext()) {
menu.setContext(true, menu.getX(), menu.getY());
}
}
}
}

View file

@ -141,7 +141,15 @@ public class Document {
other.overwrite = overwrite;
other.dirty = dirty;
other.defaultColor = defaultColor;
other.highlighter.setTo(highlighter);
if ((other.highlighter != null) && (this.highlighter != null)) {
other.highlighter.setTo(highlighter);
} else if (this.highlighter == null) {
other.highlighter = this.highlighter;
} else {
assert (other.highlighter == null);
other.highlighter = new Highlighter();
other.highlighter.setTo(this.highlighter);
}
return other;
}

View file

@ -82,8 +82,12 @@ public class Highlighter {
* @param rhs an instance of Highlighter
*/
public void setTo(final Highlighter rhs) {
colors = new TreeMap<String, CellAttributes>();
colors.putAll(rhs.colors);
if (rhs.colors != null) {
colors = new TreeMap<String, CellAttributes>();
colors.putAll(rhs.colors);
} else {
colors = null;
}
}
/**