double-click support
authorKevin Lamonte <kevin.lamonte@gmail.com>
Thu, 24 Aug 2017 01:06:49 +0000 (21:06 -0400)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Thu, 24 Aug 2017 01:06:49 +0000 (21:06 -0400)
src/jexer/TApplication.java
src/jexer/TEditorWidget.java
src/jexer/TEditorWindow.java
src/jexer/TList.java
src/jexer/TWidget.java
src/jexer/bits/ColorTheme.java
src/jexer/event/TMouseEvent.java

index 78a81ef85f7d59b261cb123e60774f3b93d46779..d74d6c5aa98c964e7ee737e3ea960aab0b79eebb 100644 (file)
@@ -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);
+        }
     }
 
     /**
index 823dea2d113c2d62b66e164dc06b2ce070e8cb69..3d8d57e16569c4d89dbcc8ae3867cb7e00f6a1ff 100644 (file)
@@ -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.
      *
index d474db2fa3e623e155c90a93183ac898b0a4b530..9f1ae67aeb8eec6151ef79cca8ba861e3a0b8ef4 100644 (file)
@@ -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());
     }
index 644c5647afafa5cb7ce81d3f3a75b3faa3908dd1..e47d7512e48cd175e480298daa6488824c84335b 100644 (file)
@@ -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.
      *
index 12e43444a6f085392903d4335fe6004fc72c6194..8833f8ff7d0668fb232222ef6fa032a232976be8 100644 (file)
@@ -980,6 +980,29 @@ public abstract class TWidget implements Comparable<TWidget> {
         }
     }
 
+    /**
+     * 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<TWidget> {
                 onMouseMotion(mouse);
                 break;
 
+            case MOUSE_DOUBLE_CLICK:
+                onMouseDoubleClick(mouse);
+                break;
+
             default:
                 throw new IllegalArgumentException("Invalid mouse event type: "
                     + mouse.getType());
index e55398a8235f38b4677f2dc9cd81edf514cdf735..caf7b434d59e16912025113754817dcdb4f8e96a 100644 (file)
@@ -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
index c29ebc3520d8db88dfd5107fd46aa50b598f5dd0..e4b44833fe4a0893e58de6c53df28858069a6ca8 100644 (file)
@@ -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
     }
 
     /**