Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Desktop] Add native win32 / linux custom window #2228

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/assets/images/Comfy_Logo_x256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ onMounted(() => {

if (isElectron()) {
document.addEventListener('contextmenu', showContextMenu)

// Enable CSS selectors
document.documentElement.dataset['platform'] = 'electron'
}
})
</script>
6 changes: 0 additions & 6 deletions src/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -765,16 +765,10 @@ audio.comfy-audio.empty-audio-widget {
padding: var(--comfy-tree-explorer-item-padding) !important;
}

/* [Desktop] Electron window specific styles */
.app-drag {
app-region: drag;
}

.no-drag {
app-region: no-drag;
}

.window-actions-spacer {
width: calc(100vw - env(titlebar-area-width, 100vw));
}
/* End of [Desktop] Electron window specific styles */
36 changes: 17 additions & 19 deletions src/components/MenuHamburger.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
<template>
<div
<Button
v-show="workspaceState.focusMode"
class="comfy-menu-hamburger no-drag"
class="comfy-menu-hamburger"
:style="positionCSS"
>
<Button
icon="pi pi-bars"
severity="secondary"
text
size="large"
v-tooltip="{ value: $t('menu.showMenu'), showDelay: 300 }"
:aria-label="$t('menu.showMenu')"
aria-live="assertive"
@click="exitFocusMode"
@contextmenu="showNativeMenu"
/>
<div v-show="menuSetting !== 'Bottom'" class="window-actions-spacer" />
</div>
icon="pi pi-bars"
severity="secondary"
text
size="large"
v-tooltip="{ value: $t('menu.showMenu'), showDelay: 300 }"
:aria-label="$t('menu.showMenu')"
aria-live="assertive"
@click="exitFocusMode"
@contextmenu="showNativeMenu"
/>
</template>

<script setup lang="ts">
Expand Down Expand Up @@ -50,13 +46,15 @@ const positionCSS = computed<CSSProperties>(() =>
// 'Bottom' menuSetting shows the hamburger button in the bottom right corner
// 'Disabled', 'Top' menuSetting shows the hamburger button in the top right corner
menuSetting.value === 'Bottom'
? { bottom: '0px', right: '0px' }
: { top: '0px', right: '0px' }
? { bottom: '0', right: '0' }
: { top: '0', right: 'calc(100% - env(titlebar-area-width, 100%))' }
)
</script>

<style scoped>
.comfy-menu-hamburger {
@apply pointer-events-auto fixed z-[9999] flex flex-row;
pointer-events: auto;
position: fixed;
z-index: 9999;
}
</style>
78 changes: 48 additions & 30 deletions src/components/topbar/TopMenubar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<div
ref="topMenuRef"
class="comfyui-menu flex items-center"
v-show="showTopMenu"
v-show="betaMenuEnabled && !workspaceState.focusMode"
:class="{ dropzone: isDropZone, 'dropzone-active': isDroppable }"
>
<h1 class="comfyui-logo mx-2 app-drag">ComfyUI</h1>
<h1 class="comfyui-logo mx-2">ComfyUI</h1>
<CommandMenubar />
<Divider layout="vertical" class="mx-2" />
<div class="flex-grow min-w-0 app-drag h-full">
<div class="flex-grow min-w-0">
<WorkflowTabs v-if="workflowTabsPosition === 'Topbar'" />
</div>
<div class="comfyui-menu-right" ref="menuRight"></div>
Expand All @@ -25,22 +25,12 @@
@click="workspaceState.focusMode = true"
@contextmenu="showNativeMenu"
/>
<div
v-show="menuSetting !== 'Bottom'"
class="window-actions-spacer flex-shrink-0"
/>
</div>
</teleport>

<!-- Virtual top menu for native window (drag handle) -->
<div
v-show="isNativeWindow && !showTopMenu"
class="fixed top-0 left-0 app-drag w-full h-[var(--comfy-topbar-height)]"
/>
</template>

<script setup lang="ts">
import { useEventBus } from '@vueuse/core'
import { useEventBus, useResizeObserver } from '@vueuse/core'
import Button from 'primevue/button'
import Divider from 'primevue/divider'
import { computed, onMounted, provide, ref } from 'vue'
Expand All @@ -59,20 +49,14 @@ const settingStore = useSettingStore()
const workflowTabsPosition = computed(() =>
settingStore.get('Comfy.Workflow.WorkflowTabsPosition')
)
const menuSetting = computed(() => settingStore.get('Comfy.UseNewMenu'))
const betaMenuEnabled = computed(() => menuSetting.value !== 'Disabled')
const betaMenuEnabled = computed(
() => settingStore.get('Comfy.UseNewMenu') !== 'Disabled'
)
const teleportTarget = computed(() =>
settingStore.get('Comfy.UseNewMenu') === 'Top'
? '.comfyui-body-top'
: '.comfyui-body-bottom'
)
const isNativeWindow = computed(
() =>
isElectron() && settingStore.get('Comfy-Desktop.WindowStyle') === 'custom'
)
const showTopMenu = computed(
() => betaMenuEnabled.value && !workspaceState.focusMode
)

const menuRight = ref<HTMLDivElement | null>(null)
// Menu-right holds legacy topbar elements attached by custom scripts
Expand All @@ -94,13 +78,20 @@ eventBus.on((event: string, payload: any) => {
}
})

onMounted(() => {
if (isElectron()) {
electronAPI().changeTheme({
height: topMenuRef.value.getBoundingClientRect().height
})
}
})
/** Height of titlebar on desktop. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don' think the resize observer is necessary after #2209 as the topbar menu height is now fixed.

if (isElectron()) {
let desktopHeight = 0

useResizeObserver(topMenuRef, (entries) => {
if (settingStore.get('Comfy.UseNewMenu') !== 'Top') return

const { height } = entries[0].contentRect
if (desktopHeight === height) return

electronAPI().changeTheme({ height })
desktopHeight = height
})
}
</script>

<style scoped>
Expand Down Expand Up @@ -136,3 +127,30 @@ onMounted(() => {
cursor: default;
}
</style>

<style lang="postcss">
/* Desktop: Custom window styling */
:root[data-platform='electron'] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we restoring the logo change? I don't think that is something we want to ship:

  1. Our current logo looks bad at icon scale.
  2. On-going new logo design.
    1. Taking up extra space on the menu bar with no extra benefit provided.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a summary of points elsewhere:
Design-wise, there is an expectation of an icon / logo in the top left corner. It's very hard to find any apps that do not have an icon of some kind as the top left part of their window. Apps with just text in the very top left corner feel incomplete or cut off.

.comfyui-logo {
@apply flex items-center gap-2 my-1 mx-1.5;

&::before {
@apply w-7 h-7 bg-[url('/assets/images/Comfy_Logo_x256.png')] bg-no-repeat bg-contain content-[''];
}
}

.comfyui-body-top {
.comfyui-menu {
app-region: drag;
padding-right: calc(100% - env(titlebar-area-width, 0));
}
}

button,
.p-menubar,
.comfyui-menu-right > *,
.actionbar {
app-region: no-drag;
}
}
</style>
6 changes: 3 additions & 3 deletions src/components/topbar/WorkflowTabs.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="workflow-tabs-container flex flex-row max-w-full">
<div class="workflow-tabs-container flex flex-row w-full">
<ScrollPanel
class="overflow-hidden no-drag"
class="overflow-hidden"
:pt:content="{
class: 'p-0 w-full',
onwheel: handleWheel
Expand All @@ -28,7 +28,7 @@
</ScrollPanel>
<Button
v-tooltip="{ value: $t('sideToolbar.newBlankWorkflow'), showDelay: 300 }"
class="new-blank-workflow-button flex-shrink-0 no-drag"
class="new-blank-workflow-button flex-shrink-0"
icon="pi pi-plus"
text
severity="secondary"
Expand Down
2 changes: 2 additions & 0 deletions src/constants/coreSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ export const CORE_SETTINGS: SettingParams[] = [
category: ['Comfy', 'Menu', 'UseNewMenu'],
defaultValue: 'Top',
name: 'Use new menu',
tooltip:
'(Desktop, Windows only): When using custom window style, only Top is supported',
type: 'combo',
options: ['Disabled', 'Top', 'Bottom'],
migrateDeprecatedValue: (value: string) => {
Expand Down
31 changes: 27 additions & 4 deletions src/extensions/core/electronAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { t } from '@/i18n'
import { app } from '@/scripts/app'
import { useDialogService } from '@/services/dialogService'
import { useSettingStore } from '@/stores/settingStore'
import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'

;(async () => {
Expand Down Expand Up @@ -39,17 +40,22 @@ import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
id: 'Comfy-Desktop.WindowStyle',
category: ['Comfy-Desktop', 'General', 'Window Style'],
name: 'Window Style',
tooltip: 'Choose custom option to hide the system title bar',
tooltip: "Custom: Replace the system title bar with ComfyUI's Top menu",
type: 'combo',
defaultValue: 'default',
options: ['default', 'custom'],
onChange: (
newValue: 'default' | 'custom',
oldValue: 'default' | 'custom'
oldValue?: 'default' | 'custom'
) => {
electronAPI.Config.setWindowStyle(newValue)
if (!oldValue) return

// Custom window mode requires the Top menu.
if (newValue === 'custom') {
useSettingStore().set('Comfy.UseNewMenu', 'Top')
}

onChangeRestartApp(newValue, oldValue)
electronAPI.Config.setWindowStyle(newValue)
}
}
],
Expand Down Expand Up @@ -188,4 +194,21 @@ import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
}
]
})

// TODO: Replace monkey patch with API or replace UX.
// If the user changes frontend menu type, ensure custom window style is disabled.
const menuSetting = useSettingStore().settingsById['Comfy.UseNewMenu']
if (menuSetting) {
const { onChange } = menuSetting
menuSetting.onChange = (
newValue: 'Disabled' | 'Top' | 'Bottom',
oldValue?: 'Disabled' | 'Top' | 'Bottom'
) => {
const style = useSettingStore().get('Comfy-Desktop.WindowStyle')
if (oldValue === 'Top' && style === 'custom') {
useSettingStore().set('Comfy-Desktop.WindowStyle', 'default')
}
return onChange?.(newValue, oldValue)
}
}
})()
3 changes: 2 additions & 1 deletion src/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"Comfy-Desktop_WindowStyle": {
"name": "Window Style",
"tooltip": "Choose custom option to hide the system title bar",
"tooltip": "Custom: Replace the system title bar with ComfyUI's Top menu",
"options": {
"default": "default",
"custom": "custom"
Expand Down Expand Up @@ -261,6 +261,7 @@
},
"Comfy_UseNewMenu": {
"name": "Use new menu",
"tooltip": "(Desktop, Windows only): When using custom window style, only Top is supported",
"options": {
"Disabled": "Disabled",
"Top": "Top",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/fr/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@
"Bottom": "Bas",
"Disabled": "Désactivé",
"Top": "Haut"
}
},
"tooltip": "(Bureau, uniquement Windows): Lors de l'utilisation d'un style de fenêtre personnalisé, seul Top est pris en charge"
},
"Comfy_Validation_NodeDefs": {
"name": "Valider les définitions de nœuds (lent)",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/ja/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@
"Bottom": "下",
"Disabled": "無効",
"Top": "上"
}
},
"tooltip": "(デスクトップ、Windowsのみ): カスタムウィンドウスタイルを使用する場合、Topのみがサポートされます"
},
"Comfy_Validation_NodeDefs": {
"name": "ノード定義を検証(遅い)",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/ko/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@
"Bottom": "하단",
"Disabled": "비활성화",
"Top": "상단"
}
},
"tooltip": "(데스크톱, 윈도우 전용): 사용자 정의 창 스타일을 사용할 때는 Top만 지원됩니다"
},
"Comfy_Validation_NodeDefs": {
"name": "노드 정의 유효성 검사 (느림)",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/ru/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@
"Bottom": "Внизу",
"Disabled": "Отключено",
"Top": "Вверху"
}
},
"tooltip": "(Рабочий стол, только для Windows): При использовании пользовательского стиля окна поддерживается только верхняя часть"
},
"Comfy_Validation_NodeDefs": {
"name": "Проверка определений узлов (медленно)",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/zh/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@
"Bottom": "底部",
"Disabled": "禁用",
"Top": "顶部"
}
},
"tooltip": "(仅限桌面,Windows): 使用自定义窗口样式时,只支持顶部"
},
"Comfy_Validation_NodeDefs": {
"name": "校验节点定义(慢)",
Expand Down
Loading
Loading