feat: hide capture button when 'On Run' mode is selected in webcam widget

- Add updateVueWidgetOptions to GraphNodeManager to update widget options
  and trigger Vue reactivity
- Implement capture button visibility toggle based on capture_on_queue value
- Default capture mode to 'Manually' (false)
- Use Vue watch to reactively hide/show capture button when mode changes
This commit is contained in:
Johnpaul
2025-11-26 17:38:38 +01:00
parent cfbb4c708f
commit 4b628724bd
2 changed files with 110 additions and 2 deletions

View File

@@ -75,6 +75,13 @@ export interface GraphNodeManager {
// Access to original LiteGraph nodes (non-reactive)
getNode(id: string): LGraphNode | undefined
// Update widget options (e.g., hidden, disabled) - triggers Vue reactivity
updateVueWidgetOptions(
nodeId: string,
widgetName: string,
options: Record<string, unknown>
): void
// Lifecycle methods
cleanup(): void
}
@@ -298,6 +305,35 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
}
}
/**
* Updates Vue state when widget options change (e.g., hidden, disabled)
*/
const updateVueWidgetOptions = (
nodeId: string,
widgetName: string,
options: Record<string, unknown>
): void => {
try {
const currentData = vueNodeData.get(nodeId)
if (!currentData?.widgets) return
const updatedWidgets = currentData.widgets.map((w) =>
w.name === widgetName
? { ...w, options: { ...w.options, ...options } }
: w
)
// Create a completely new object to ensure Vue reactivity triggers
const updatedData = {
...currentData,
widgets: updatedWidgets
}
vueNodeData.set(nodeId, updatedData)
} catch (error) {
// Ignore widget update errors to prevent cascade failures
}
}
/**
* Creates a wrapped callback for a widget that maintains LiteGraph/Vue sync
*/
@@ -624,6 +660,7 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
return {
vueNodeData,
getNode,
updateVueWidgetOptions,
cleanup
}
}

View File

@@ -58,9 +58,11 @@ import {
onMounted,
onUnmounted,
ref,
toRaw
toRaw,
watch
} from 'vue'
import { useVueNodeLifecycle } from '@/composables/graph/useVueNodeLifecycle'
import { t } from '@/i18n'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
@@ -70,6 +72,8 @@ import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
const { nodeManager } = useVueNodeLifecycle()
const props = defineProps<{
widget: SimplifiedWidget<string | number | undefined>
readonly?: boolean
@@ -149,7 +153,10 @@ function applyWidgetVisibility(
// Mutate in place to preserve object identity for serializeValue closure
widget.type = 'selectToggle'
widget.label = 'Capture Image'
widget.value = widget.value ?? false
// Default to false (Manual mode) - only set if undefined/null
if (widget.value === undefined || widget.value === null) {
widget.value = false
}
widget.options = {
...widget.options,
hidden,
@@ -196,6 +203,53 @@ function createActionWidget({
}
}
function updateCaptureButtonVisibility(isOnRunMode: boolean) {
withLitegraphNode((node) => {
// Update the LiteGraph widget options
const captureWidget = node.widgets?.find(
(w) => w.name === CAPTURE_WIDGET_NAME
)
if (captureWidget) {
captureWidget.options = {
...captureWidget.options,
hidden: isOnRunMode
}
}
// Update Vue state directly to trigger reactivity
nodeManager.value?.updateVueWidgetOptions(
String(node.id),
CAPTURE_WIDGET_NAME,
{ hidden: isOnRunMode }
)
app.graph.setDirtyCanvas(true, true)
})
}
// Computed to get capture_on_queue widget value from Vue state
const captureOnQueueValue = computed(() => {
const vueNodeData = nodeManager.value?.vueNodeData.get(props.nodeId)
const widget = vueNodeData?.widgets?.find(
(w) => w.name === 'capture_on_queue'
)
return widget?.value === true
})
function setupCaptureOnQueueWatcher() {
// Set initial visibility
updateCaptureButtonVisibility(captureOnQueueValue.value)
// Watch for changes using Vue reactivity
watch(
captureOnQueueValue,
(isOnRunMode) => {
updateCaptureButtonVisibility(isOnRunMode)
},
{ immediate: false }
)
}
function removeWidgetsByName(names: string[]) {
withLitegraphNode((node) => {
if (!node.widgets?.length) return
@@ -288,6 +342,12 @@ function setupSerializeValue() {
function showWidgets() {
withLitegraphNode((node) => {
// Get current capture_on_queue value to determine initial button visibility
const captureOnQueueWidget = node.widgets?.find(
(w) => w.name === 'capture_on_queue'
)
const isOnRunMode = captureOnQueueWidget?.value === true
updateNodeWidgets(node, (widgets) => {
const sanitizedWidgets = widgets
.map((widget) => applyWidgetVisibility(widget, false))
@@ -304,8 +364,19 @@ function showWidgets() {
onClick: () => captureImage(node)
})
// Hide capture button if in "On Run" mode
if (isOnRunMode) {
captureWidget.options = {
...captureWidget.options,
hidden: true
}
}
return [...sanitizedWidgets, captureWidget]
})
// Set up watcher to toggle capture button visibility when mode changes
setupCaptureOnQueueWatcher()
})
}