From 0c7374f17d11c4e90255b72629b0f0d4ec36165a Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Fri, 25 Oct 2024 07:25:18 +0200 Subject: [PATCH] :tada: Add experimental fixed-stroke-length mode --- docs/changelog.md | 1 + docs/config-files.md | 1 + src/main/app.ts | 1 + .../menu/input-methods/gesture-detector.ts | 30 +++++++++++++++++++ src/renderer/menu/menu.ts | 10 +++++++ 5 files changed, 43 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 8e6ca87a..4f609536 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -27,6 +27,7 @@ This changelog follows the rules of [Keep a Changelog](http://keepachangelog.com - **Support for base64 icons:** This allows you to directly embed base64 encoded images. This will be especially helpful for menus which are dynamically generated via some sort of API in the future. Use `"base64"` as the icon theme and provide the base64 encoded image as the `"icon"`. This will be a string starting with something like `"data:image/svg+xml;base64, ..."`. This even supports animated gifs! - **Version information in the sidebar:** The sidebar now shows some version information in the development tab. This includes the version of Kando, the version of Electron, and the currently used backend. - An option to the menu editor which **allows warping the mouse pointer to the center of the menu** when the menu is opened in centered mode. This allows to directly engage in turbo mode even if the menu is shown at the center of the screen. +- **An experimental Fixed-Stroke-Length Mode:** If you set `"menuOptions": {"fixedStrokeLength": }` to a value greater than 0, Marking Mode and Turbo will be disabled. Instead, submenus will be opened when the mouse is moved the given distance from the center of the menu. - **Adjustable fade-in and fade-out duration of the menu:** For now, it is only possible to change this via the `"menuOptions": {"fadeInDuration": 150}` and `"menuOptions": {"fadeOutDuration": 250}` properties in the `config.json` file. In the future, this will be exposed in the settings UI. - **Possibility to hide sidebar and editor buttons:** You can now add ```json diff --git a/docs/config-files.md b/docs/config-files.md index a41d4bc4..27ba91e5 100644 --- a/docs/config-files.md +++ b/docs/config-files.md @@ -54,6 +54,7 @@ Property | Default Value | Description `gestureMinStrokeAngle` | `20` | Smaller turns will not lead to selections (in degrees). `gestureJitterThreshold` | `10` | Smaller pointer movements will not be considered at all during gesture recognition (in pixels). `gesturePauseTimeout` | `100` | If the pointer is stationary for this many milliseconds, the current item will be selected during gesture recognition. +`fixedStrokeLength` | `0` | If set to a value greater than 0, items will be instantly selected if the mouse travelled more than `centerDeadZone` + `fixedStrokeLength` pixels in marking or turbo mode. Any other gesture detection based on angles or motion speed will be disabled in this case. `rmbSelectsParent` | `false` | If enabled, the parent of a selected item will be selected on a right mouse button click. Else the menu will be closed directly. ### The `editorOptions` Property diff --git a/src/main/app.ts b/src/main/app.ts index e89139dc..a6c6b597 100644 --- a/src/main/app.ts +++ b/src/main/app.ts @@ -134,6 +134,7 @@ export class KandoApp { gestureMinStrokeAngle: 20, gestureJitterThreshold: 10, gesturePauseTimeout: 100, + fixedStrokeLength: 0, rmbSelectsParent: false, }, editorOptions: { diff --git a/src/renderer/menu/input-methods/gesture-detector.ts b/src/renderer/menu/input-methods/gesture-detector.ts index 2cfe52ed..2de7856d 100644 --- a/src/renderer/menu/input-methods/gesture-detector.ts +++ b/src/renderer/menu/input-methods/gesture-detector.ts @@ -52,6 +52,20 @@ export class GestureDetector extends EventEmitter { */ public pauseTimeout = 100; + /** + * This is used if fixedStrokeLength is greater than zero to allow for distance-based + * selections. + */ + public centerDeadZone = 50; + + /** + * If set to a value greater than 0, items will be instantly selected if the mouse + * travelled more than centerDeadZone + fixedStrokeLength pixels in marking or turbo + * mode. Any other gesture detection based on angles or motion speed will be disabled in + * this case. + */ + public fixedStrokeLength = 0; + /** * This method detects the gestures. It should be called if the mouse pointer was moved * while the left mouse button is held down. Consider the diagram below: @@ -85,6 +99,22 @@ export class GestureDetector extends EventEmitter { const strokeLength = math.getLength(strokeDir); + // If fixedStrokeLength is set, we only need to check if the stroke is long enough. + if (this.fixedStrokeLength > 0) { + const minStrokeLength = this.fixedStrokeLength + this.centerDeadZone; + if (strokeLength > minStrokeLength) { + const idealCoords = { + x: this.strokeStart.x + (strokeDir.x / strokeLength) * minStrokeLength, + y: this.strokeStart.y + (strokeDir.y / strokeLength) * minStrokeLength, + }; + + this.reset(idealCoords); + this.emit('selection', idealCoords); + } + this.strokeEnd = coords; + return; + } + if (strokeLength > this.minStrokeLength) { // Calculate the vector E->M in the diagram above. const tipDir = { x: coords.x - this.strokeEnd.x, y: coords.y - this.strokeEnd.y }; diff --git a/src/renderer/menu/menu.ts b/src/renderer/menu/menu.ts index a995409d..3e276155 100644 --- a/src/renderer/menu/menu.ts +++ b/src/renderer/menu/menu.ts @@ -68,6 +68,14 @@ export class MenuOptions { */ gesturePauseTimeout = 100; + /** + * If set to a value greater than 0, items will be instantly selected if the mouse + * travelled more than centerDeadZone + fixedStrokeLength pixels in marking or turbo + * mode. Any other gesture detection based on angles or motion speed will be disabled in + * this case. + */ + fixedStrokeLength = 0; + /** * If enabled, the parent of a selected item will be selected on a right mouse button * click. Else the menu will be closed directly. @@ -392,6 +400,8 @@ export class Menu extends EventEmitter { this.pointerInput.gestureDetector.jitterThreshold = this.options.gestureJitterThreshold; this.pointerInput.gestureDetector.pauseTimeout = this.options.gesturePauseTimeout; + this.pointerInput.gestureDetector.fixedStrokeLength = this.options.fixedStrokeLength; + this.pointerInput.gestureDetector.centerDeadZone = this.options.centerDeadZone; } // --------------------------------------------------------------------- private methods