From b6faeac0d9c3e3ae3376ed28b54ec6ea6408ad7a Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Wed, 23 Aug 2017 21:06:49 -0400 Subject: [PATCH] double-click support --- src/jexer/TApplication.java | 66 ++++++++++++++++++++++++++++++++ src/jexer/TEditorWidget.java | 22 +++++++++++ src/jexer/TEditorWindow.java | 12 +++--- src/jexer/TList.java | 21 +++++++++- src/jexer/TWidget.java | 27 +++++++++++++ src/jexer/bits/ColorTheme.java | 15 +++++--- src/jexer/event/TMouseEvent.java | 7 +++- 7 files changed, 157 insertions(+), 13 deletions(-) diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index 78a81ef8..d74d6c5a 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -350,6 +350,17 @@ public class TApplication implements Runnable { */ private int oldMouseY; + /** + * The last mouse up click time, used to determine if this is a mouse + * double-click. + */ + private long lastMouseUpTime; + + /** + * The amount of millis between mouse up events to assume a double-click. + */ + private long doubleClickTime = 250; + /** * Event queue that is filled by run(). */ @@ -1071,6 +1082,7 @@ public class TApplication implements Runnable { if (debugEvents) { System.err.printf("Handle event: %s\n", event); } + TMouseEvent doubleClick = null; // Special application-wide events ----------------------------------- @@ -1082,6 +1094,25 @@ public class TApplication implements Runnable { oldMouseY = mouseY; mouseX = mouse.getX(); mouseY = mouse.getY(); + } else { + if (mouse.getType() == TMouseEvent.Type.MOUSE_UP) { + if ((mouse.getTime().getTime() - lastMouseUpTime) < + doubleClickTime) { + + // This is a double-click. + doubleClick = new TMouseEvent(TMouseEvent.Type. + MOUSE_DOUBLE_CLICK, + mouse.getX(), mouse.getY(), + mouse.getAbsoluteX(), mouse.getAbsoluteY(), + mouse.isMouse1(), mouse.isMouse2(), + mouse.isMouse3(), + mouse.isMouseWheelUp(), mouse.isMouseWheelDown()); + + } else { + // The first click of a potential double-click. + lastMouseUpTime = mouse.getTime().getTime(); + } + } } // See if we need to switch focus to another window or the menu @@ -1189,6 +1220,11 @@ public class TApplication implements Runnable { mouse.setX(mouse.getX() - window.getX()); mouse.setY(mouse.getY() - window.getY()); + if (doubleClick != null) { + doubleClick.setX(doubleClick.getX() - window.getX()); + doubleClick.setY(doubleClick.getY() - window.getY()); + } + if (window.mouseWouldHit(mouse)) { dispatchToDesktop = false; } @@ -1201,11 +1237,17 @@ public class TApplication implements Runnable { event); } window.handleEvent(event); + if (doubleClick != null) { + window.handleEvent(doubleClick); + } } if (dispatchToDesktop) { // This event is fair game for the desktop to process. if (desktop != null) { desktop.handleEvent(event); + if (doubleClick != null) { + desktop.handleEvent(doubleClick); + } } } } @@ -1219,6 +1261,8 @@ public class TApplication implements Runnable { * @see #primaryHandleEvent(TInputEvent event) */ private void secondaryHandleEvent(final TInputEvent event) { + TMouseEvent doubleClick = null; + // Peek at the mouse position if (event instanceof TMouseEvent) { TMouseEvent mouse = (TMouseEvent) event; @@ -1227,10 +1271,32 @@ public class TApplication implements Runnable { oldMouseY = mouseY; mouseX = mouse.getX(); mouseY = mouse.getY(); + } else { + if (mouse.getType() == TMouseEvent.Type.MOUSE_UP) { + if ((mouse.getTime().getTime() - lastMouseUpTime) < + doubleClickTime) { + + // This is a double-click. + doubleClick = new TMouseEvent(TMouseEvent.Type. + MOUSE_DOUBLE_CLICK, + mouse.getX(), mouse.getY(), + mouse.getAbsoluteX(), mouse.getAbsoluteY(), + mouse.isMouse1(), mouse.isMouse2(), + mouse.isMouse3(), + mouse.isMouseWheelUp(), mouse.isMouseWheelDown()); + + } else { + // The first click of a potential double-click. + lastMouseUpTime = mouse.getTime().getTime(); + } + } } } secondaryEventReceiver.handleEvent(event); + if (doubleClick != null) { + secondaryEventReceiver.handleEvent(doubleClick); + } } /** diff --git a/src/jexer/TEditorWidget.java b/src/jexer/TEditorWidget.java index 823dea2d..3d8d57e1 100644 --- a/src/jexer/TEditorWidget.java +++ b/src/jexer/TEditorWidget.java @@ -385,6 +385,28 @@ public final class TEditorWidget extends TWidget { return document.getLineCount(); } + /** + * Get the current visible top row number. 1-based. + * + * @return the visible top row number. Row 1 is the first row. + */ + public int getVisibleRowNumber() { + return topLine + 1; + } + + /** + * Set the current visible row number. 1-based. + * + * @param row the new visible row number. Row 1 is the first row. + */ + public void setVisibleRowNumber(final int row) { + assert (row > 0); + if ((row > 0) && (row < document.getLineCount())) { + topLine = row - 1; + alignDocument(true); + } + } + /** * Get the current editing row number. 1-based. * diff --git a/src/jexer/TEditorWindow.java b/src/jexer/TEditorWindow.java index d474db2f..9f1ae67a 100644 --- a/src/jexer/TEditorWindow.java +++ b/src/jexer/TEditorWindow.java @@ -239,13 +239,13 @@ public class TEditorWindow extends TScrollableWindow { if (mouseOnEditor(mouse)) { // The editor might have changed, update the scollbars. setBottomValue(editField.getMaximumRowNumber()); - setVerticalValue(editField.getEditingRowNumber()); + setVerticalValue(editField.getVisibleRowNumber()); setRightValue(editField.getMaximumColumnNumber()); setHorizontalValue(editField.getEditingColumnNumber()); } else { if (mouse.isMouseWheelUp() || mouse.isMouseWheelDown()) { // Vertical scrollbar actions - editField.setEditingRowNumber(getVerticalValue()); + editField.setVisibleRowNumber(getVerticalValue()); } } } @@ -262,7 +262,7 @@ public class TEditorWindow extends TScrollableWindow { if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) { // Clicked on vertical scrollbar - editField.setEditingRowNumber(getVerticalValue()); + editField.setVisibleRowNumber(getVerticalValue()); } // TODO: horizontal scrolling @@ -281,13 +281,13 @@ public class TEditorWindow extends TScrollableWindow { if (mouseOnEditor(mouse) && mouse.isMouse1()) { // The editor might have changed, update the scollbars. setBottomValue(editField.getMaximumRowNumber()); - setVerticalValue(editField.getEditingRowNumber()); + setVerticalValue(editField.getVisibleRowNumber()); setRightValue(editField.getMaximumColumnNumber()); setHorizontalValue(editField.getEditingColumnNumber()); } else { if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) { // Clicked/dragged on vertical scrollbar - editField.setEditingRowNumber(getVerticalValue()); + editField.setVisibleRowNumber(getVerticalValue()); } // TODO: horizontal scrolling @@ -307,7 +307,7 @@ public class TEditorWindow extends TScrollableWindow { // The editor might have changed, update the scollbars. setBottomValue(editField.getMaximumRowNumber()); - setVerticalValue(editField.getEditingRowNumber()); + setVerticalValue(editField.getVisibleRowNumber()); setRightValue(editField.getMaximumColumnNumber()); setHorizontalValue(editField.getEditingColumnNumber()); } diff --git a/src/jexer/TList.java b/src/jexer/TList.java index 644c5647..e47d7512 100644 --- a/src/jexer/TList.java +++ b/src/jexer/TList.java @@ -304,7 +304,6 @@ public class TList extends TScrollableWidget { && (mouse.getY() < getHeight() - 1)) { if (getVerticalValue() + mouse.getY() < strings.size()) { selectedString = getVerticalValue() + mouse.getY(); - dispatchEnter(); } return; } @@ -313,6 +312,26 @@ public class TList extends TScrollableWidget { super.onMouseDown(mouse); } + /** + * Handle mouse double click. + * + * @param mouse mouse double click event + */ + @Override + public void onMouseDoubleClick(final TMouseEvent mouse) { + if ((mouse.getX() < getWidth() - 1) + && (mouse.getY() < getHeight() - 1)) { + if (getVerticalValue() + mouse.getY() < strings.size()) { + selectedString = getVerticalValue() + mouse.getY(); + dispatchEnter(); + } + return; + } + + // Pass to children + super.onMouseDoubleClick(mouse); + } + /** * Handle keystrokes. * diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index 12e43444..8833f8ff 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -980,6 +980,29 @@ public abstract class TWidget implements Comparable { } } + /** + * Method that subclasses can override to handle mouse button + * double-clicks. + * + * @param mouse mouse button event + */ + public void onMouseDoubleClick(final TMouseEvent mouse) { + // Default: do nothing, pass to children instead + for (int i = children.size() - 1 ; i >= 0 ; i--) { + TWidget widget = children.get(i); + if (widget.mouseWouldHit(mouse)) { + // Dispatch to this child, also activate it + activate(widget); + + // Set x and y relative to the child's coordinates + mouse.setX(mouse.getAbsoluteX() - widget.getAbsoluteX()); + mouse.setY(mouse.getAbsoluteY() - widget.getAbsoluteY()); + widget.handleEvent(mouse); + return; + } + } + } + /** * Method that subclasses can override to handle window/screen resize * events. @@ -1072,6 +1095,10 @@ public abstract class TWidget implements Comparable { onMouseMotion(mouse); break; + case MOUSE_DOUBLE_CLICK: + onMouseDoubleClick(mouse); + break; + default: throw new IllegalArgumentException("Invalid mouse event type: " + mouse.getType()); diff --git a/src/jexer/bits/ColorTheme.java b/src/jexer/bits/ColorTheme.java index e55398a8..caf7b434 100644 --- a/src/jexer/bits/ColorTheme.java +++ b/src/jexer/bits/ColorTheme.java @@ -339,7 +339,6 @@ public final class ColorTheme { color.setBold(true); colors.put("tcheckbox.active", color); - // TRadioButton color = new CellAttributes(); color.setForeColor(Color.WHITE); @@ -437,9 +436,12 @@ public final class ColorTheme { color.setBold(false); colors.put("ttreeview.unreadable", color); color = new CellAttributes(); - color.setForeColor(Color.BLACK); + // color.setForeColor(Color.BLACK); + // color.setBackColor(Color.BLUE); + // color.setBold(true); + color.setForeColor(Color.WHITE); color.setBackColor(Color.BLUE); - color.setBold(true); + color.setBold(false); colors.put("ttreeview.inactive", color); // TList @@ -459,9 +461,12 @@ public final class ColorTheme { color.setBold(false); colors.put("tlist.unreadable", color); color = new CellAttributes(); - color.setForeColor(Color.BLACK); + // color.setForeColor(Color.BLACK); + // color.setBackColor(Color.BLUE); + // color.setBold(true); + color.setForeColor(Color.WHITE); color.setBackColor(Color.BLUE); - color.setBold(true); + color.setBold(false); colors.put("tlist.inactive", color); // TStatusBar diff --git a/src/jexer/event/TMouseEvent.java b/src/jexer/event/TMouseEvent.java index c29ebc35..e4b44833 100644 --- a/src/jexer/event/TMouseEvent.java +++ b/src/jexer/event/TMouseEvent.java @@ -52,7 +52,12 @@ public final class TMouseEvent extends TInputEvent { /** * Mouse button up. X and Y will have screen coordinates. */ - MOUSE_UP + MOUSE_UP, + + /** + * Mouse double-click. X and Y will have screen coordinates. + */ + MOUSE_DOUBLE_CLICK } /** -- 2.27.0