Skip to content

Commit 989e33c

Browse files
Add a button to selection toolbox to open mask editor (#3603)
Co-authored-by: bymyself <[email protected]>
1 parent b83f76d commit 989e33c

File tree

10 files changed

+123
-44
lines changed

10 files changed

+123
-44
lines changed

src/components/graph/SelectionToolbox.vue

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<ColorPickerButton />
1111
<BypassButton />
1212
<PinButton />
13+
<MaskEditorButton />
1314
<DeleteButton />
1415
<RefreshButton />
1516
<ExtensionCommandButton
@@ -24,18 +25,18 @@
2425
import Panel from 'primevue/panel'
2526
import { computed } from 'vue'
2627
28+
import BypassButton from '@/components/graph/selectionToolbox/BypassButton.vue'
2729
import ColorPickerButton from '@/components/graph/selectionToolbox/ColorPickerButton.vue'
30+
import DeleteButton from '@/components/graph/selectionToolbox/DeleteButton.vue'
2831
import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue'
32+
import ExtensionCommandButton from '@/components/graph/selectionToolbox/ExtensionCommandButton.vue'
33+
import MaskEditorButton from '@/components/graph/selectionToolbox/MaskEditorButton.vue'
34+
import PinButton from '@/components/graph/selectionToolbox/PinButton.vue'
35+
import RefreshButton from '@/components/graph/selectionToolbox/RefreshButton.vue'
2936
import { useExtensionService } from '@/services/extensionService'
3037
import { type ComfyCommandImpl, useCommandStore } from '@/stores/commandStore'
3138
import { useCanvasStore } from '@/stores/graphStore'
3239
33-
import BypassButton from './selectionToolbox/BypassButton.vue'
34-
import DeleteButton from './selectionToolbox/DeleteButton.vue'
35-
import ExtensionCommandButton from './selectionToolbox/ExtensionCommandButton.vue'
36-
import PinButton from './selectionToolbox/PinButton.vue'
37-
import RefreshButton from './selectionToolbox/RefreshButton.vue'
38-
3940
const commandStore = useCommandStore()
4041
const canvasStore = useCanvasStore()
4142
const extensionService = useExtensionService()
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<template>
2+
<Button
3+
v-show="isSingleImageNode"
4+
v-tooltip.top="{
5+
value: t('commands.Comfy_MaskEditor_OpenMaskEditor.label'),
6+
showDelay: 1000
7+
}"
8+
severity="secondary"
9+
text
10+
icon="pi pi-pencil"
11+
@click="openMaskEditor"
12+
/>
13+
</template>
14+
15+
<script setup lang="ts">
16+
import Button from 'primevue/button'
17+
import { computed } from 'vue'
18+
19+
import { t } from '@/i18n'
20+
import { useCommandStore } from '@/stores/commandStore'
21+
import { useCanvasStore } from '@/stores/graphStore'
22+
import { isImageNode, isLGraphNode } from '@/utils/litegraphUtil'
23+
24+
const commandStore = useCommandStore()
25+
const canvasStore = useCanvasStore()
26+
27+
const isSingleImageNode = computed(() => {
28+
const nodes = canvasStore.selectedItems.filter(isLGraphNode)
29+
return nodes.length === 1 && nodes.some(isImageNode)
30+
})
31+
32+
const openMaskEditor = () => {
33+
void commandStore.execute('Comfy.MaskEditor.OpenMaskEditor')
34+
}
35+
</script>

src/extensions/core/maskeditor.ts

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4912,6 +4912,45 @@ class KeyboardManager {
49124912
}
49134913
}
49144914

4915+
// Function to open the mask editor
4916+
function openMaskEditor(): void {
4917+
const useNewEditor = app.extensionManager.setting.get(
4918+
'Comfy.MaskEditor.UseNewEditor'
4919+
)
4920+
if (useNewEditor) {
4921+
const dlg = MaskEditorDialog.getInstance() as any
4922+
if (dlg?.isOpened && !dlg.isOpened()) {
4923+
dlg.show()
4924+
}
4925+
} else {
4926+
const dlg = MaskEditorDialogOld.getInstance() as any
4927+
if (dlg?.isOpened && !dlg.isOpened()) {
4928+
dlg.show()
4929+
}
4930+
}
4931+
}
4932+
4933+
// Check if the dialog is already opened
4934+
function isOpened(): boolean {
4935+
const useNewEditor = app.extensionManager.setting.get(
4936+
'Comfy.MaskEditor.UseNewEditor'
4937+
)
4938+
if (useNewEditor) {
4939+
return MaskEditorDialog.instance?.isOpened?.() ?? false
4940+
} else {
4941+
return (MaskEditorDialogOld.instance as any)?.isOpened?.() ?? false
4942+
}
4943+
}
4944+
4945+
// Ensure boolean return type for context predicate
4946+
const context_predicate = (): boolean => {
4947+
return !!(
4948+
ComfyApp.clipspace &&
4949+
ComfyApp.clipspace.imgs &&
4950+
ComfyApp.clipspace.imgs.length > 0
4951+
)
4952+
}
4953+
49154954
app.registerExtension({
49164955
name: 'Comfy.MaskEditor',
49174956
settings: [
@@ -4951,50 +4990,33 @@ app.registerExtension({
49514990
experimental: true
49524991
}
49534992
],
4954-
init(app) {
4955-
// Create function before assignment
4956-
function openMaskEditor(): void {
4957-
const useNewEditor = app.extensionManager.setting.get(
4958-
'Comfy.MaskEditor.UseNewEditor'
4959-
)
4960-
if (useNewEditor) {
4961-
const dlg = MaskEditorDialog.getInstance() as any
4962-
if (dlg?.isOpened && !dlg.isOpened()) {
4963-
dlg.show()
4964-
}
4965-
} else {
4966-
const dlg = MaskEditorDialogOld.getInstance() as any
4967-
if (dlg?.isOpened && !dlg.isOpened()) {
4968-
dlg.show()
4969-
}
4970-
}
4971-
}
4993+
commands: [
4994+
{
4995+
id: 'Comfy.MaskEditor.OpenMaskEditor',
4996+
icon: 'pi pi-pencil',
4997+
label: 'Open Mask Editor for Selected Node',
4998+
function: () => {
4999+
const selectedNodes = app.canvas.selected_nodes
5000+
if (!selectedNodes || Object.keys(selectedNodes).length !== 1) return
5001+
5002+
const selectedNode = selectedNodes[Object.keys(selectedNodes)[0]]
5003+
if (
5004+
!selectedNode.imgs?.length &&
5005+
selectedNode.previewMediaType !== 'image'
5006+
)
5007+
return
49725008

4973-
// Check if the dialog is already opened
4974-
function isOpened(): boolean {
4975-
const useNewEditor = app.extensionManager.setting.get(
4976-
'Comfy.MaskEditor.UseNewEditor'
4977-
)
4978-
if (useNewEditor) {
4979-
return MaskEditorDialog.instance?.isOpened?.() ?? false
4980-
} else {
4981-
return (MaskEditorDialogOld.instance as any)?.isOpened?.() ?? false
5009+
ComfyApp.copyToClipspace(selectedNode)
5010+
// @ts-expect-error clipspace_return_node is an extension property added at runtime
5011+
ComfyApp.clipspace_return_node = selectedNode
5012+
openMaskEditor()
49825013
}
49835014
}
4984-
4985-
// Assign the created function
5015+
],
5016+
init() {
49865017
ComfyApp.open_maskeditor = openMaskEditor
49875018
ComfyApp.maskeditor_is_opended = isOpened
49885019

4989-
// Ensure boolean return type
4990-
const context_predicate = (): boolean => {
4991-
return !!(
4992-
ComfyApp.clipspace &&
4993-
ComfyApp.clipspace.imgs &&
4994-
ComfyApp.clipspace.imgs.length > 0
4995-
)
4996-
}
4997-
49985020
ClipspaceDialog.registerButton(
49995021
'MaskEditor',
50005022
context_predicate,

src/locales/en/commands.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Comfy_Canvas_ToggleSelectedNodes_Pin": {
7272
"label": "Pin/Unpin Selected Nodes"
7373
},
74+
"Comfy_MaskEditor_OpenMaskEditor": {
75+
"label": "Open Mask Editor for Selected Node"
76+
},
7477
"Comfy_Canvas_ZoomIn": {
7578
"label": "Zoom In"
7679
},

src/locales/es/commands.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Comfy_Canvas_ToggleSelected_Pin": {
7272
"label": "Anclar/Desanclar elementos seleccionados"
7373
},
74+
"Comfy_MaskEditor_OpenMaskEditor": {
75+
"label": "Abrir editor de máscara para el nodo seleccionado"
76+
},
7477
"Comfy_Canvas_ZoomIn": {
7578
"label": "Acercar"
7679
},

src/locales/fr/commands.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Comfy_Canvas_ToggleSelected_Pin": {
7272
"label": "Épingler/Désépingler les éléments sélectionnés"
7373
},
74+
"Comfy_MaskEditor_OpenMaskEditor": {
75+
"label": "Ouvrir l'éditeur de masque pour le nœud sélectionné"
76+
},
7477
"Comfy_Canvas_ZoomIn": {
7578
"label": "Zoom avant"
7679
},

src/locales/ja/commands.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Comfy_Canvas_ToggleSelected_Pin": {
7272
"label": "選択したアイテムのピン留め/ピン留め解除"
7373
},
74+
"Comfy_MaskEditor_OpenMaskEditor": {
75+
"label": "選択したノードのマスクエディタを開く"
76+
},
7477
"Comfy_Canvas_ZoomIn": {
7578
"label": "ズームイン"
7679
},

src/locales/ko/commands.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Comfy_Canvas_ToggleSelected_Pin": {
7272
"label": "선택한 항목 고정/고정 해제"
7373
},
74+
"Comfy_MaskEditor_OpenMaskEditor": {
75+
"label": "선택한 노드 마스크 편집기 열기"
76+
},
7477
"Comfy_Canvas_ZoomIn": {
7578
"label": "확대"
7679
},

src/locales/ru/commands.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Comfy_Canvas_ToggleSelected_Pin": {
7272
"label": "Закрепить/Открепить выбранных нод"
7373
},
74+
"Comfy_MaskEditor_OpenMaskEditor": {
75+
"label": "Открыть редактор масок для выбранной ноды"
76+
},
7477
"Comfy_Canvas_ZoomIn": {
7578
"label": "Увеличить"
7679
},

src/locales/zh/commands.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Comfy_Canvas_ToggleSelected_Pin": {
7272
"label": "固定/取消固定选中项"
7373
},
74+
"Comfy_MaskEditor_OpenMaskEditor": {
75+
"label": "打开选中节点的遮罩编辑器"
76+
},
7477
"Comfy_Canvas_ZoomIn": {
7578
"label": "放大"
7679
},

0 commit comments

Comments
 (0)