mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-09 12:39:23 -03:00
fix(ui): cap lora widget height and enable wheel scroll in Node 2.0 mode (#959)
- Add 'Node 2.0: Maximum visible LoRA entries' setting (default 12) - Apply max-height to loras container in Vue mode to prevent unbounded growth - Add enableListWheelScroll: window capture-phase wheel hook so scroll inside the widget scrolls the list instead of zooming the canvas
This commit is contained in:
@@ -11,10 +11,10 @@ import {
|
||||
EMPTY_CONTAINER_HEIGHT
|
||||
} from "./loras_widget_utils.js";
|
||||
import { initDrag, createContextMenu, initHeaderDrag, initReorderDrag, handleKeyboardNavigation } from "./loras_widget_events.js";
|
||||
import { forwardMiddleMouseToCanvas, forwardWheelToCanvas } from "./utils.js";
|
||||
import { forwardMiddleMouseToCanvas, forwardWheelToCanvas, enableListWheelScroll } from "./utils.js";
|
||||
import { PreviewTooltip } from "./preview_tooltip.js";
|
||||
import { ensureLmStyles } from "./lm_styles_loader.js";
|
||||
import { getStrengthStepPreference } from "./settings.js";
|
||||
import { getStrengthStepPreference, getLoraWidgetMaxVisibleLoras } from "./settings.js";
|
||||
|
||||
export function addLorasWidget(node, name, opts, callback) {
|
||||
ensureLmStyles();
|
||||
@@ -29,6 +29,20 @@ export function addLorasWidget(node, name, opts, callback) {
|
||||
// Set initial height using CSS variables approach
|
||||
const defaultHeight = 200;
|
||||
|
||||
// In Vue/node-2.0 mode, cap the widget height so it shows at most N entries.
|
||||
// This prevents content from driving the node size beyond the cap.
|
||||
// canvas/legacy mode is unaffected.
|
||||
if (typeof LiteGraph !== 'undefined' && LiteGraph.vueNodesMode) {
|
||||
const maxLoras = getLoraWidgetMaxVisibleLoras();
|
||||
const gap = 5; // flex gap from .lm-loras-container CSS
|
||||
const maxH = CONTAINER_PADDING + HEADER_HEIGHT + maxLoras * LORA_ENTRY_HEIGHT + maxLoras * gap;
|
||||
container.style.maxHeight = `${maxH}px`;
|
||||
container.style.setProperty('--comfy-widget-max-height', `${maxH}px`);
|
||||
// Window capture-phase hook: scroll the widget instead of zooming the canvas
|
||||
// when the wheel is over a scrollable loras list.
|
||||
enableListWheelScroll(container);
|
||||
}
|
||||
|
||||
// Check if this is a randomizer node (lock button instead of drag handle)
|
||||
const isRandomizerNode = opts?.isRandomizerNode === true;
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ const NEW_TAB_ZOOM_LEVEL = 0.8;
|
||||
const STRENGTH_STEP_SETTING_ID = "loramanager.strength_step";
|
||||
const STRENGTH_STEP_DEFAULT = 0.05;
|
||||
|
||||
const LORA_WIDGET_MAX_VISIBLE_SETTING_ID = "loramanager.lora_widget_max_visible_loras";
|
||||
const LORA_WIDGET_MAX_VISIBLE_DEFAULT = 12;
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions
|
||||
// ============================================================================
|
||||
@@ -360,6 +363,32 @@ const getStrengthStepPreference = (() => {
|
||||
};
|
||||
})();
|
||||
|
||||
const getLoraWidgetMaxVisibleLoras = (() => {
|
||||
let settingsUnavailableLogged = false;
|
||||
|
||||
return () => {
|
||||
const settingManager = app?.extensionManager?.setting;
|
||||
if (!settingManager || typeof settingManager.get !== "function") {
|
||||
if (!settingsUnavailableLogged) {
|
||||
console.warn("LoRA Manager: settings API unavailable, using default max visible loras.");
|
||||
settingsUnavailableLogged = true;
|
||||
}
|
||||
return LORA_WIDGET_MAX_VISIBLE_DEFAULT;
|
||||
}
|
||||
|
||||
try {
|
||||
const value = settingManager.get(LORA_WIDGET_MAX_VISIBLE_SETTING_ID);
|
||||
return value ?? LORA_WIDGET_MAX_VISIBLE_DEFAULT;
|
||||
} catch (error) {
|
||||
if (!settingsUnavailableLogged) {
|
||||
console.warn("LoRA Manager: unable to read max visible loras setting, using default.", error);
|
||||
settingsUnavailableLogged = true;
|
||||
}
|
||||
return LORA_WIDGET_MAX_VISIBLE_DEFAULT;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
// ============================================================================
|
||||
// Register Extension with All Settings
|
||||
// ============================================================================
|
||||
@@ -463,6 +492,19 @@ app.registerExtension({
|
||||
tooltip: "Step size for adjusting LoRA strength via arrow buttons or keyboard (default: 0.05)",
|
||||
category: ["LoRA Manager", "LoRA Widget", "Strength Step"],
|
||||
},
|
||||
{
|
||||
id: LORA_WIDGET_MAX_VISIBLE_SETTING_ID,
|
||||
name: "Node 2.0: Maximum visible LoRA entries",
|
||||
type: "slider",
|
||||
attrs: {
|
||||
min: 3,
|
||||
max: 50,
|
||||
step: 1,
|
||||
},
|
||||
defaultValue: LORA_WIDGET_MAX_VISIBLE_DEFAULT,
|
||||
tooltip: "When using Node 2.0 rendering, limit the loras widget height to show at most this many entries (default: 12). Excess entries are accessible via scrollbar.",
|
||||
category: ["LoRA Manager", "LoRA Widget", "Max Visible"],
|
||||
},
|
||||
],
|
||||
async setup() {
|
||||
await loadWorkflowOptions();
|
||||
@@ -549,4 +591,5 @@ export {
|
||||
getUsageStatisticsPreference,
|
||||
getNewTabTemplatePreference,
|
||||
getStrengthStepPreference,
|
||||
getLoraWidgetMaxVisibleLoras,
|
||||
};
|
||||
|
||||
@@ -784,6 +784,51 @@ export function forwardWheelToCanvas(container, options = {}) {
|
||||
}, { passive: false });
|
||||
}
|
||||
|
||||
// Marks scrollable containers whose wheel scrolling must win over canvas zoom.
|
||||
const LM_WHEEL_CLASS = 'lm-wheel-scrollable';
|
||||
let lmWheelHookInstalled = false;
|
||||
|
||||
/**
|
||||
* Keep vertical wheel scrolling inside a scrollable widget container, even in
|
||||
* Nodes 2.0 / Vue mode where ComfyUI's wheel→zoom handler runs on the document
|
||||
* in the capture phase (outer than any container-level listener).
|
||||
* Installs a single capture-phase hook on `window` (the outermost dispatch
|
||||
* point). When the wheel is over a marked, scrollable element, we manually
|
||||
* scroll it and fully consume the event so canvas zoom never sees it.
|
||||
*/
|
||||
export function enableListWheelScroll(container) {
|
||||
if (!container) return;
|
||||
container.classList.add(LM_WHEEL_CLASS);
|
||||
|
||||
if (lmWheelHookInstalled) return;
|
||||
lmWheelHookInstalled = true;
|
||||
|
||||
window.addEventListener('wheel', (event) => {
|
||||
// Let pinch/zoom and horizontal gestures pass through.
|
||||
if (event.ctrlKey) return;
|
||||
if (Math.abs(event.deltaX) > Math.abs(event.deltaY)) return;
|
||||
|
||||
const target = event.target;
|
||||
if (!target || typeof target.closest !== 'function') return;
|
||||
const el = target.closest(`.${LM_WHEEL_CLASS}`);
|
||||
if (!el) return;
|
||||
|
||||
const canScrollY = el.scrollHeight > el.clientHeight + 1;
|
||||
if (!canScrollY) return;
|
||||
|
||||
// Translate deltaMode to approximate pixels.
|
||||
const unit = event.deltaMode === 1 ? 16
|
||||
: event.deltaMode === 2 ? el.clientHeight
|
||||
: 1;
|
||||
|
||||
el.scrollTop += event.deltaY * unit;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
}, { capture: true, passive: false });
|
||||
}
|
||||
|
||||
// Get connected Lora Pool node from pool_config input
|
||||
export function getConnectedPoolConfigNode(node) {
|
||||
if (!node?.inputs) {
|
||||
|
||||
Reference in New Issue
Block a user