refactor: rename package to comfyui_touchpad_scroll_controller and update related files
handle two finger scrolling directly in this plugin as to not require others to work
This commit is contained in:
+1
-1
@@ -6,4 +6,4 @@ recursive-exclude * *.py[co]
|
||||
|
||||
recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
|
||||
|
||||
graft src/comfyui_scroll_over_textarea/web
|
||||
graft src/comfyui_touchpad_scroll_controller/web
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ComfyUI Scroll Over Textarea
|
||||
# ComfyUI Touchpad Scroll Controller
|
||||
|
||||
A ComfyUI extension to allow textarea elements to be scrolled over. Useful when using a trackpad in order to prevent accidental forward/back navigation (two fingers horizontally on a Mac) when scrolling around the UI.
|
||||
A ComfyUI extension that enhances touchpad navigation by redirecting two-finger scrolling over to the canvas, including over textareas. This can prevent accidental back/forward browser navigation when using horizontal touchpad gestures and provides smooth zooming and panning for Mac and other touchpad users.
|
||||
|
||||
> [!NOTE]
|
||||
> This projected was created with a [cookiecutter](https://github.com/Comfy-Org/cookiecutter-comfy-extension) template. It helps you start writing custom nodes without worrying about the Python setup.
|
||||
@@ -14,14 +14,20 @@ A ComfyUI extension to allow textarea elements to be scrolled over. Useful when
|
||||
|
||||
# Features
|
||||
|
||||
- A list of features
|
||||
- Optimizes touchpad two-finger scrolling behavior for ComfyUI canvas navigation
|
||||
- Prevents accidental browser back/forward navigation when using horizontal touchpad gestures
|
||||
- Redirects two-finger scrolling over textareas to pan the canvas instead (configurable in options)
|
||||
- Implements smoother touchpad-friendly zoom with ⌃+two-finger scroll or pinch gestures
|
||||
- Implements a finer-grained zooming experience with ⌃+⌘+two-finger scroll or pinch gestures
|
||||
- Customizable target selectors through settings
|
||||
- Toggle functionality on/off through the settings panel
|
||||
|
||||
## Develop
|
||||
|
||||
To install the dev dependencies and pre-commit (will run the ruff hook), do:
|
||||
|
||||
```bash
|
||||
cd comfyui_scroll_over_textarea
|
||||
cd ComfyUI/custom_nodes/comfyui_touchpad_scroll_controller
|
||||
pip install -e .[dev]
|
||||
pre-commit install
|
||||
```
|
||||
@@ -43,7 +49,7 @@ git push
|
||||
|
||||
## Writing custom nodes
|
||||
|
||||
An example custom node is located in [node.py](src/comfyui_scroll_over_textarea/nodes.py). To learn more, read the [docs](https://docs.comfy.org/essentials/custom_node_overview).
|
||||
An example custom node is located in [node.py](src/comfyui_touchpad_scroll_controller/nodes.py). To learn more, read the [docs](https://docs.comfy.org/essentials/custom_node_overview).
|
||||
|
||||
## Tests
|
||||
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
"""Top-level package for comfyui_scroll_over_textarea."""
|
||||
"""Top-level package for comfyui_touchpad_scroll_controller."""
|
||||
|
||||
__all__ = [
|
||||
"NODE_CLASS_MAPPINGS",
|
||||
@@ -10,7 +10,7 @@ __author__ = """Josh Whaley"""
|
||||
__email__ = "josh@whaleymail.net"
|
||||
__version__ = "0.1.0"
|
||||
|
||||
from .src.comfyui_scroll_over_textarea.nodes import NODE_CLASS_MAPPINGS
|
||||
from .src.comfyui_scroll_over_textarea.nodes import NODE_DISPLAY_NAME_MAPPINGS
|
||||
from .src.comfyui_touchpad_scroll_controller.nodes import NODE_CLASS_MAPPINGS
|
||||
from .src.comfyui_touchpad_scroll_controller.nodes import NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
WEB_DIRECTORY = "./web"
|
||||
|
||||
+7
-7
@@ -3,9 +3,9 @@ requires = ["setuptools>=70.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "comfyui_scroll_over_textarea"
|
||||
version = "0.1.0"
|
||||
description = "A ComfyUI extension to allow textarea elements to be scrolled over. Useful when using a trackpad in order to prevent accidental forward/back navigation (two fingers horizontally on a Mac) when scrolling around the UI."
|
||||
name = "comfyui_touchpad_scroll_controller"
|
||||
version = "0.2.0"
|
||||
description = "A ComfyUI extension that enhances touchpad navigation by redirecting two-finger scrolling over to the canvas, including over textareas. This can prevent accidental back/forward browser navigation when using horizontal touchpad gestures and provides smooth zooming and panning for Mac and other touchpad users."
|
||||
authors = [
|
||||
{name = "Josh Whaley", email = "josh@whaleymail.net"}
|
||||
]
|
||||
@@ -27,13 +27,13 @@ dev = [
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
bugs = "https://github.com/joreyaesh/comfyui_scroll_over_textarea/issues"
|
||||
homepage = "https://github.com/joreyaesh/comfyui_scroll_over_textarea"
|
||||
Repository = "https://github.com/joreyaesh/comfyui_scroll_over_textarea"
|
||||
bugs = "https://github.com/joreyaesh/comfyui_touchpad_scroll_controller/issues"
|
||||
homepage = "https://github.com/joreyaesh/comfyui_touchpad_scroll_controller"
|
||||
Repository = "https://github.com/joreyaesh/comfyui_touchpad_scroll_controller"
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "joreyaesh"
|
||||
DisplayName = "ComfyUI Scroll Over Textarea"
|
||||
DisplayName = "ComfyUI Touchpad Scroll Controller"
|
||||
Icon = ""
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
from inspect import cleandoc
|
||||
|
||||
|
||||
class ScrollOverTextareaDummyNode:
|
||||
class TouchpadScrollControllerDummyNode:
|
||||
"""
|
||||
An empty dummy node since this has changes only for the UI.
|
||||
|
||||
@@ -68,7 +68,7 @@ class ScrollOverTextareaDummyNode:
|
||||
|
||||
# A dictionary that contains all nodes you want to export with their names
|
||||
# NOTE: names should be globally unique
|
||||
NODE_CLASS_MAPPINGS = {"ScrollOverTextareaDummyNode": ScrollOverTextareaDummyNode}
|
||||
NODE_CLASS_MAPPINGS = {"TouchpadScrollControllerDummyNode": TouchpadScrollControllerDummyNode}
|
||||
|
||||
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {"ScrollOverTextareaDummyNode": "Scroll Over Textarea"}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {"TouchpadScrollControllerDummyNode": "Touchpad Scroll Controller Dummy Node"}
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Tests for `comfyui_scroll_over_textarea` package."""
|
||||
|
||||
import pytest
|
||||
from src.comfyui_scroll_over_textarea.nodes import ScrollOverTextareaDummyNode
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def example_node():
|
||||
"""Fixture to create an Example node instance."""
|
||||
return ScrollOverTextareaDummyNode()
|
||||
|
||||
|
||||
def test_example_node_initialization(example_node):
|
||||
"""Test that the node can be instantiated."""
|
||||
assert isinstance(example_node, ScrollOverTextareaDummyNode)
|
||||
|
||||
|
||||
def test_return_types():
|
||||
"""Test the node's metadata."""
|
||||
assert ScrollOverTextareaDummyNode.RETURN_TYPES == ()
|
||||
assert ScrollOverTextareaDummyNode.FUNCTION == "test"
|
||||
assert ScrollOverTextareaDummyNode.CATEGORY == "Dummy"
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Tests for `comfyui_touchpad_scroll_controller` package."""
|
||||
|
||||
import pytest
|
||||
from src.comfyui_touchpad_scroll_controller.nodes import (
|
||||
TouchpadScrollControllerDummyNode,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def example_node():
|
||||
"""Fixture to create an Example node instance."""
|
||||
return TouchpadScrollControllerDummyNode()
|
||||
|
||||
|
||||
def test_example_node_initialization(example_node):
|
||||
"""Test that the node can be instantiated."""
|
||||
assert isinstance(example_node, TouchpadScrollControllerDummyNode)
|
||||
|
||||
|
||||
def test_return_types():
|
||||
"""Test the node's metadata."""
|
||||
assert TouchpadScrollControllerDummyNode.RETURN_TYPES == ()
|
||||
assert TouchpadScrollControllerDummyNode.FUNCTION == "test"
|
||||
assert TouchpadScrollControllerDummyNode.CATEGORY == "Dummy"
|
||||
@@ -1,57 +0,0 @@
|
||||
import { app } from '../../../scripts/app.js';
|
||||
|
||||
app.registerExtension({
|
||||
name: 'ComfyUI Scroll Over Textarea',
|
||||
settings: [
|
||||
{
|
||||
id: 'comfyui_scroll_over_textarea.enable',
|
||||
name: 'Prevent Scrolling Within Textareas',
|
||||
type: 'boolean',
|
||||
defaultValue: true,
|
||||
onChange: (newVal, oldVal) => {
|
||||
updateTextareaScrollListener(newVal);
|
||||
},
|
||||
},
|
||||
],
|
||||
async setup() {
|
||||
console.log('ComfyUI Scroll Over Textarea Extension Loaded');
|
||||
const cb = (event) => {
|
||||
app.canvas.processMouseWheel(event);
|
||||
event.preventDefault();
|
||||
};
|
||||
app.canvas['_ignore_textarea_scroll_callback'] = cb;
|
||||
updateTextareaScrollListener();
|
||||
},
|
||||
async nodeCreated(node) {
|
||||
const enabled = app.extensionManager.setting.get(
|
||||
'comfyui_scroll_over_textarea.enable'
|
||||
);
|
||||
setTimeout(() => {
|
||||
updateTextareaScrollListener(enabled);
|
||||
}, 50);
|
||||
},
|
||||
});
|
||||
|
||||
function updateTextareaScrollListener(
|
||||
ignoreTextareaScroll = app.extensionManager.setting.get(
|
||||
'comfyui_scroll_over_textarea.enable'
|
||||
)
|
||||
) {
|
||||
const textareas = document.querySelectorAll('textarea.comfy-multiline-input');
|
||||
|
||||
textareas.forEach((textarea) => {
|
||||
if (app.canvas) {
|
||||
if (ignoreTextareaScroll) {
|
||||
textarea.addEventListener(
|
||||
'mousewheel',
|
||||
app.canvas['_ignore_textarea_scroll_callback']
|
||||
);
|
||||
} else {
|
||||
textarea.removeEventListener(
|
||||
'mousewheel',
|
||||
app.canvas['_ignore_textarea_scroll_callback']
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// @ts-ignore
|
||||
import { app } from '../../../scripts/app.js';
|
||||
|
||||
// Default selectors to target
|
||||
const defaultTargetSelectors = [
|
||||
'textarea.comfy-multiline-input',
|
||||
'.p-panel.p-component',
|
||||
];
|
||||
|
||||
app.registerExtension({
|
||||
name: 'ComfyUI Touchpad Scroll Controller',
|
||||
settings: [
|
||||
{
|
||||
id: 'comfyui_touchpad_scroll_controller.enableTextareas',
|
||||
name: 'Ignore Textarea Scroll',
|
||||
tooltip:
|
||||
'Ignore mouse wheel events on textareas and pass the event to the canvas.',
|
||||
type: 'boolean',
|
||||
defaultValue: true,
|
||||
onChange: (newVal, oldVal) => {
|
||||
updateScrollListener({ ignoreTextareaScroll: newVal });
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'comfyui_touchpad_scroll_controller.enableTouchpadScroll',
|
||||
name: 'Enable Touchpad Scroll Controller',
|
||||
tooltip:
|
||||
'Enable touchpad scroll controller. This will override the default mouse wheel behavior. NOTE: You may need to refresh the page after changing this setting.',
|
||||
type: 'boolean',
|
||||
defaultValue: true,
|
||||
onChange: (newVal, oldVal) => {
|
||||
updateScrollListener({ enableTouchpadScroll: newVal });
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'comfyui_touchpad_scroll_controller.selectors',
|
||||
name: 'Target Selectors (Comma Separated)',
|
||||
type: 'text',
|
||||
defaultValue: defaultTargetSelectors.join(', '),
|
||||
onChange: (newVal, oldVal) => {
|
||||
updateScrollListener({ targetSelectors: getTargetSelectors(newVal) });
|
||||
},
|
||||
},
|
||||
],
|
||||
async setup() {
|
||||
console.log('ComfyUI Touchpad Scroll Controller Extension Loaded');
|
||||
const cb = (event) => {
|
||||
app.canvas.processMouseWheel(event);
|
||||
event.preventDefault();
|
||||
};
|
||||
app.canvas['_ignore_textarea_scroll_callback'] = cb;
|
||||
updateScrollListener();
|
||||
},
|
||||
async nodeCreated(node) {
|
||||
const enabled = app.extensionManager.setting.get(
|
||||
'comfyui_touchpad_scroll_controller.enableTextareas'
|
||||
);
|
||||
setTimeout(() => {
|
||||
updateScrollListener(enabled);
|
||||
}, 50);
|
||||
},
|
||||
});
|
||||
|
||||
function getTargetSelectors(
|
||||
selectorString = app.extensionManager.setting.get(
|
||||
'comfyui_touchpad_scroll_controller.selectors'
|
||||
) || defaultTargetSelectors.join(', ')
|
||||
) {
|
||||
return selectorString
|
||||
.split(',')
|
||||
.map((selector) => selector.trim())
|
||||
.filter((selector) => selector.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ignoreTextareaScroll?: boolean; targetSelectors?: string[], enableTouchpadScroll?: boolean}} param0
|
||||
*/
|
||||
function updateScrollListener({
|
||||
ignoreTextareaScroll,
|
||||
targetSelectors,
|
||||
enableTouchpadScroll,
|
||||
} = {}) {
|
||||
const isTouchpadScrollEnabled =
|
||||
enableTouchpadScroll ??
|
||||
app.extensionManager.setting.get(
|
||||
'comfyui_touchpad_scroll_controller.enableTouchpadScroll'
|
||||
);
|
||||
if (!isTouchpadScrollEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smooth scrolling for touchpad
|
||||
*/
|
||||
// @ts-ignore
|
||||
window.LGraphCanvas.prototype.processMouseWheel = function (
|
||||
/** @type {WheelEvent}*/ event
|
||||
) {
|
||||
if (!this.graph || !this.allow_dragcanvas) return;
|
||||
|
||||
const { clientX: x, clientY: y } = event;
|
||||
if (this.viewport) {
|
||||
const [viewportX, viewportY, width, height] = this.viewport;
|
||||
const isInsideX = x >= viewportX && x < viewportX + width;
|
||||
const isInsideY = y >= viewportY && y < viewportY + height;
|
||||
if (!(isInsideX && isInsideY)) return;
|
||||
}
|
||||
|
||||
let scale = this.ds.scale;
|
||||
let { deltaX, deltaY } = event;
|
||||
|
||||
if (event.metaKey || event.ctrlKey) {
|
||||
let SCALE = event.ctrlKey ? 150 : 100;
|
||||
if (event.metaKey) SCALE *= -1 / 0.5;
|
||||
this.ds.changeScale(scale - deltaY / SCALE, [
|
||||
event.clientX,
|
||||
event.clientY,
|
||||
]);
|
||||
} else {
|
||||
this.ds.mouseDrag(-deltaX, -deltaY);
|
||||
}
|
||||
this.graph.change();
|
||||
|
||||
event.preventDefault();
|
||||
return false; // prevent default
|
||||
};
|
||||
|
||||
const selectors = targetSelectors || getTargetSelectors();
|
||||
const isTextareaScrollIgnored =
|
||||
ignoreTextareaScroll ??
|
||||
app.extensionManager.setting.get(
|
||||
'comfyui_touchpad_scroll_controller.enableTextareas'
|
||||
);
|
||||
|
||||
if (!isTouchpadScrollEnabled) {
|
||||
selectors.forEach((selector) => {
|
||||
const elements = document.querySelectorAll(selector);
|
||||
|
||||
elements.forEach((element) => {
|
||||
if (app.canvas) {
|
||||
if (isTextareaScrollIgnored) {
|
||||
element.addEventListener(
|
||||
'mousewheel',
|
||||
app.canvas['_ignore_textarea_scroll_callback']
|
||||
);
|
||||
} else {
|
||||
element.removeEventListener(
|
||||
'mousewheel',
|
||||
app.canvas['_ignore_textarea_scroll_callback']
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user