Fix doubled control application (#7550)

With reactivity fixed, control widgets would apply twice. This is fixed
by using the litegraph implementation.

Also adds control widget support for combos

Followup to #7539.

Known Issue:
- Primitive node do not have litegraph callbacks properly setup. As a
result, they will display an updated value when modified by control
widgets. Fixing this will requires a larger, separate PR

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7550-Fix-doubled-control-application-2cb6d73d365081739a2fc40fdfb3630e)
by [Unito](https://www.unito.io)
This commit is contained in:
AustinMroz
2025-12-16 18:42:02 -08:00
committed by GitHub
parent fa37112caf
commit ab76d02823
14 changed files with 121 additions and 676 deletions

View File

@@ -0,0 +1,126 @@
<script setup lang="ts">
import Popover from 'primevue/popover'
import RadioButton from 'primevue/radiobutton'
import { computed, ref } from 'vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import type { ControlOptions } from '@/types/simplifiedWidget'
type ControlOption = {
description: string
mode: ControlOptions
icon?: string
text?: string
title: string
}
const popover = ref()
const settingStore = useSettingStore()
const toggle = (event: Event) => {
popover.value.toggle(event)
}
defineExpose({ toggle })
const controlOptions: ControlOption[] = [
{
mode: 'fixed',
icon: 'icon-[lucide--pencil-off]',
title: 'fixed',
description: 'fixedDesc'
},
{
mode: 'increment',
text: '+1',
title: 'increment',
description: 'incrementDesc'
},
{
mode: 'decrement',
text: '-1',
title: 'decrement',
description: 'decrementDesc'
},
{
mode: 'randomize',
icon: 'icon-[lucide--shuffle]',
title: 'randomize',
description: 'randomizeDesc'
}
]
const widgetControlMode = computed(() =>
settingStore.get('Comfy.WidgetControlMode')
)
const controlMode = defineModel<ControlOptions>()
</script>
<template>
<Popover
ref="popover"
class="bg-interface-panel-surface border border-interface-stroke rounded-lg"
>
<div class="w-113 max-w-md p-4 space-y-4">
<div class="text-sm text-muted-foreground leading-tight">
{{ $t('widgets.valueControl.header.prefix') }}
<span class="text-base-foreground font-medium">
{{
widgetControlMode === 'before'
? $t('widgets.valueControl.header.before')
: $t('widgets.valueControl.header.after')
}}
</span>
{{ $t('widgets.valueControl.header.postfix') }}
</div>
<div class="space-y-2">
<div
v-for="option in controlOptions"
:key="option.mode"
class="flex items-center justify-between py-2 gap-7"
>
<div class="flex items-center gap-2 flex-1 min-w-0">
<div
class="flex items-center justify-center w-8 h-8 rounded-lg flex-shrink-0 bg-secondary-background border border-border-subtle"
>
<i
v-if="option.icon"
:class="option.icon"
class="text-base text-base-foreground"
/>
<span
v-if="option.text"
class="text-xs font-normal text-base-foreground"
>
{{ option.text }}
</span>
</div>
<div class="flex flex-col gap-0.5 min-w-0 flex-1">
<div
class="text-sm font-normal text-base-foreground leading-tight"
>
<span>
{{ $t(`widgets.valueControl.${option.title}`) }}
</span>
</div>
<div
class="text-sm font-normal text-muted-foreground leading-tight"
>
{{ $t(`widgets.valueControl.${option.description}`) }}
</div>
</div>
</div>
<RadioButton
v-model="controlMode"
class="flex-shrink-0"
:input-id="option.mode"
:value="option.mode"
/>
</div>
</div>
</div>
</Popover>
</template>