This commit is contained in:
Autumn Lamonte 2021-12-27 17:39:53 -06:00
parent d638dee6a4
commit a2cfddf1f7
15 changed files with 194 additions and 101 deletions

View file

@ -1437,8 +1437,7 @@ public class TApplication implements Runnable {
if (customMousePointer != null) {
setCustomMousePointerLocation(mouse);
}
setCustomWidgetMousePointerLocation(mouse);
setMouseStyle(mouse);
setMouseState(mouse);
if (mouse.isMouse1() && (mouse.isShift() || mouse.isCtrl())) {
// Screen selection.
@ -1672,8 +1671,7 @@ public class TApplication implements Runnable {
if (customMousePointer != null) {
setCustomMousePointerLocation(mouse);
}
setCustomWidgetMousePointerLocation(mouse);
setMouseStyle(mouse);
setMouseState(mouse);
if ((mouseX != mouse.getX()) || (mouseY != mouse.getY())) {
mouseX = mouse.getX();
@ -2209,7 +2207,7 @@ public class TApplication implements Runnable {
if (customMousePointer == null) {
// Custom bitmap mouse pointer removed.
if (getScreen() instanceof SwingTerminal) {
// Restore the Swing pointer to the Jexer default.
// Restore the Swing pointer to the application default.
SwingTerminal terminal = (SwingTerminal) getScreen();
terminal.setMouseStyle(System.getProperty(
"jexer.Swing.mouseStyle", "default"));
@ -2239,116 +2237,90 @@ public class TApplication implements Runnable {
}
/**
* Set the mouse style to the widget under the mouse.
* Get the visible widget under the mouse position.
*
* @param mouse the mouse position
* @return the widget, or null if the mouse is over the menu
*/
private void setMouseStyle(final TMouseEvent mouse) {
if (!(backend instanceof SwingBackend)) {
return;
}
SwingTerminal terminal = (SwingTerminal) getScreen();
// A bit of a hassle to find the active widget...
private TWidget getWidgetUnderMouse(final TMouseEvent mouse) {
TWidget activeWidget = null;
for (TMenu menu: menus) {
if (menu.isActive()) {
terminal.setMouseStyle(System.getProperty(
"jexer.Swing.mouseStyle", "default"));
return;
return null;
}
}
TWindow window = getActiveWindow();
if (window == null) {
terminal.setMouseStyle(System.getProperty(
"jexer.Swing.mouseStyle", "default"));
return;
return null;
}
activeWidget = window;
for (TWidget widget: window.getChildren()) {
if (widget.mouseWouldHit(mouse)) {
activeWidget = widget;
}
}
if (activeWidget == null) {
terminal.setMouseStyle(System.getProperty(
"jexer.Swing.mouseStyle", "default"));
return;
}
terminal.setMouseStyle(activeWidget.getMouseStyle());
return activeWidget;
}
/**
* Set the custom mouse pointer for the widget under the mouse.
* Set the mouse state to match the style or bitmap requested by the
* widget under the mouse.
*
* @param mouse the mouse position
*/
private void setCustomWidgetMousePointer(final TMouseEvent mouse) {
private void setMouseState(final TMouseEvent mouse) {
/*
* There are three reasons to use pixel-level mouse events:
*
* 1. A custom bitmap mouse pointer is active over the entire
* application.
*
* 2. The active widget or window has requested it.
*
* 3. There is a custom bitmap mouse pointer for the widget
* immediately under the mouse.
*/
boolean pixelMouse = false;
String mouseStyle = System.getProperty("jexer.Swing.mouseStyle",
"default");
if (customWidgetMousePointer == null) {
// Save the state of pixelMouse.
oldPixelMouse = backend.isPixelMouse();
if (customMousePointer != null) {
pixelMouse = true;
}
customWidgetMousePointer = null;
// A bit of a hassle to find the active widget...
TWidget activeWidget = null;
for (TMenu menu: menus) {
if (menu.isActive()) {
if (backend.isPixelMouse() != oldPixelMouse) {
backend.setPixelMouse(oldPixelMouse);
}
return;
}
}
TWindow window = getActiveWindow();
if (window == null) {
if (backend.isPixelMouse() != oldPixelMouse) {
backend.setPixelMouse(oldPixelMouse);
}
return;
}
for (TWidget widget: window.getChildren()) {
if (widget.mouseWouldHit(mouse)) {
activeWidget = widget;
}
}
TWidget activeWidget = getWidgetUnderMouse(mouse);
if (activeWidget == null) {
if (backend.isPixelMouse() != oldPixelMouse) {
backend.setPixelMouse(oldPixelMouse);
}
// Reset to default.
backend.setPixelMouse(pixelMouse);
backend.setMouseStyle(mouseStyle);
return;
}
customWidgetMousePointer = activeWidget.getCustomMousePointer();
if (customWidgetMousePointer != null) {
backend.setPixelMouse(true);
if (activeWidget.isPixelMouse()) {
pixelMouse = true;
}
// We have a widget.
backend.setMouseStyle(activeWidget.getMouseStyle());
MousePointer newCustomWidgetMousePointer;
newCustomWidgetMousePointer = activeWidget.getCustomMousePointer();
if (newCustomWidgetMousePointer != null) {
pixelMouse = true;
int pixelX = mouse.getAbsoluteX() * getScreen().getTextWidth();
pixelX += mouse.getPixelOffsetX();
pixelX -= newCustomWidgetMousePointer.getHotspotX();
int pixelY = mouse.getAbsoluteY() * getScreen().getTextHeight();
pixelY += mouse.getPixelOffsetY();
pixelY -= newCustomWidgetMousePointer.getHotspotY();
newCustomWidgetMousePointer.setX(pixelX);
newCustomWidgetMousePointer.setY(pixelY);
doRepaint();
} else {
if (backend.isPixelMouse() != oldPixelMouse) {
backend.setPixelMouse(oldPixelMouse);
if (customWidgetMousePointer != null) {
doRepaint();
}
}
}
/**
* Set the location of the active widget custom mouse pointer.
*
* @param mouse the mouse position
*/
private void setCustomWidgetMousePointerLocation(final TMouseEvent mouse) {
setCustomWidgetMousePointer(mouse);
if (customWidgetMousePointer == null) {
return;
}
int pixelX = mouse.getAbsoluteX() * getScreen().getTextWidth();
pixelX += mouse.getPixelOffsetX();
pixelX -= customWidgetMousePointer.getHotspotX();
int pixelY = mouse.getAbsoluteY() * getScreen().getTextHeight();
pixelY += mouse.getPixelOffsetY();
pixelY -= customWidgetMousePointer.getHotspotY();
customWidgetMousePointer.setX(pixelX);
customWidgetMousePointer.setY(pixelY);
doRepaint();
backend.setPixelMouse(pixelMouse);
customWidgetMousePointer = newCustomWidgetMousePointer;
}
/**

View file

@ -924,6 +924,19 @@ public class TTerminalWidget extends TScrollableWidget
return false;
}
/**
* Check if per-pixel mouse events are requested.
*
* @return true if per-pixel mouse events are requested
*/
@Override
public boolean isPixelMouse() {
if (emulator != null) {
return emulator.isPixelMouse();
}
return false;
}
/**
* See if the terminal is still running.
*

View file

@ -395,6 +395,19 @@ public class TTerminalWindow extends TScrollableWindow {
return false;
}
/**
* Check if per-pixel mouse events are requested.
*
* @return true if per-pixel mouse events are requested
*/
@Override
public boolean isPixelMouse() {
if (terminal != null) {
return terminal.isPixelMouse();
}
return false;
}
/**
* Claim the keystrokes the emulator will need.
*/

View file

@ -1402,6 +1402,16 @@ public abstract class TWidget implements Comparable<TWidget> {
}
}
/**
* Check if per-pixel mouse events are requested.
*
* @return true if per-pixel mouse events are requested
*/
public boolean isPixelMouse() {
// Default: do not request per-pixel mouse events.
return false;
}
/**
* Get the global color theme.
*

View file

@ -138,4 +138,12 @@ public interface Backend {
*/
public void setPixelMouse(final boolean pixelMouse);
/**
* Set the mouse pointer (cursor) style.
*
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
public void setMouseStyle(final String mouseStyle);
}

View file

@ -224,4 +224,15 @@ public class ECMA48Backend extends GenericBackend {
}
}
/**
* Set the mouse pointer (cursor) style.
*
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
@Override
public void setMouseStyle(final String mouseStyle) {
((ECMA48Terminal) terminal).setMouseStyle(mouseStyle);
}
}

View file

@ -2365,6 +2365,19 @@ public class ECMA48Terminal extends LogicalScreen
}
}
/**
* Set the mouse pointer (cursor) style.
*
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
public void setMouseStyle(final String mouseStyle) {
// TODO: For now disregard this. OSC 22 came out with Xterm 367
// which can select X11 cursors/pointers, but mintty implemented it
// against Win32 cursors/pointers. And neither bothered to implement
// "really, just hide the damn pointer but still give me events" grr.
}
/**
* Reset keyboard/mouse input parser.
*/

View file

@ -264,4 +264,15 @@ public abstract class GenericBackend implements Backend {
// Default: do nothing
}
/**
* Set the mouse pointer (cursor) style.
*
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
@Override
public void setMouseStyle(final String mouseStyle) {
// Default: do nothing
}
}

View file

@ -179,4 +179,15 @@ public class HeadlessBackend extends LogicalScreen implements Backend {
// NOP
}
/**
* Set the mouse pointer (cursor) style.
*
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
@Override
public void setMouseStyle(final String mouseStyle) {
// NOP
}
}

View file

@ -361,4 +361,16 @@ public class MultiBackend implements Backend {
}
}
/**
* Set the mouse pointer (cursor) style.
*
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
public void setMouseStyle(final String mouseStyle) {
for (Backend backend: backends) {
backend.setMouseStyle(mouseStyle);
}
}
}

View file

@ -198,4 +198,15 @@ public class SwingBackend extends GenericBackend {
}
}
/**
* Set the mouse pointer (cursor) style.
*
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
@Override
public void setMouseStyle(final String mouseStyle) {
((SwingTerminal) terminal).setMouseStyle(mouseStyle);
}
}

View file

@ -272,13 +272,13 @@ public class SwingComponent {
/**
* Set the mouse pointer (cursor) style.
*
* @param style the mouse pointer style string, one of: "default",
* @param mouseStyle the mouse pointer style string, one of: "default",
* "none", "hand", "text", "move", or "crosshair"
*/
public void setMouseStyle(final String style) {
assert (style != null);
public void setMouseStyle(final String mouseStyle) {
assert (mouseStyle != null);
String styleLower = style.toLowerCase();
String styleLower = mouseStyle.toLowerCase();
Cursor cursor = Cursor.getDefaultCursor();

View file

@ -722,14 +722,14 @@ public class SwingTerminal extends LogicalScreen
}
/**
* Set the mouse cursor style.
* Set the mouse pointer (cursor) style.
*
* @param style the cursor style string, one of: "default", "none",
* @param mouseStyle the pointer style string, one of: "default", "none",
* "hand", "text", "move", or "crosshair"
*/
public void setMouseStyle(final String style) {
if (!style.equals(mouseStyle)) {
this.mouseStyle = style;
public void setMouseStyle(final String mouseStyle) {
if (!this.mouseStyle.equals(mouseStyle)) {
this.mouseStyle = mouseStyle;
if (swing != null) {
swing.setMouseStyle(mouseStyle);
}

View file

@ -110,7 +110,6 @@ public class DemoPixelsWindow extends TWindow {
if (mouse != null) {
// Turn it off.
getApplication().setCustomMousePointer(null);
getApplication().getBackend().setPixelMouse(false);
} else {
// Turn it on.
try {
@ -123,7 +122,6 @@ public class DemoPixelsWindow extends TWindow {
app.setCustomMousePointer(new MousePointer(0, 0, 0,
image, image.getWidth() / 2,
image.getHeight() / 2));
app.getBackend().setPixelMouse(true);
} catch (Exception e) {
new jexer.TExceptionDialog(getApplication(), e);
}

View file

@ -322,6 +322,11 @@ public class ECMA48 implements Runnable {
*/
private MouseEncoding mouseEncoding = MouseEncoding.X10;
/**
* If true, report mouse events per-pixel rather than per-text-cell.
*/
private boolean pixelMouse = false;
/**
* A terminal may request that the mouse pointer be hidden using a
* Privacy Message containing either "hideMousePointer" or
@ -3629,14 +3634,10 @@ public class ECMA48 implements Runnable {
if (value == true) {
mouseEncoding = MouseEncoding.SGR_PIXELS;
// We need our host widget to report in pixels too.
if (backend != null) {
backend.setPixelMouse(true);
}
pixelMouse = true;
} else {
mouseEncoding = MouseEncoding.X10;
if (backend != null) {
backend.setPixelMouse(false);
}
pixelMouse = false;
}
}
break;
@ -7496,6 +7497,15 @@ public class ECMA48 implements Runnable {
return hideMousePointer;
}
/**
* Check if terminal is reporting pixel-based mouse position.
*
* @return true if single-pixel mouse movements are reported
*/
public final boolean isPixelMouse() {
return pixelMouse;
}
/**
* Get the mouse protocol.
*