Skip to content

Commit 57892f3

Browse files
authored
feat: 新增「猫咪设置 > 窗口设置 > 窗口位置」配置项 (#764)
1 parent b59ec09 commit 57892f3

11 files changed

Lines changed: 138 additions & 13 deletions

File tree

src-tauri/src/core/setup/macos.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub fn platform(
5757
"window_did_resize" => {
5858
window_move_event();
5959

60-
if let Ok(size) = main_window.inner_size() {
60+
if let Ok(size) = main_window.outer_size() {
6161
let _ = main_window.emit_to(target, WINDOW_RESIZED_EVENT, size);
6262
}
6363
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { PhysicalPosition } from '@tauri-apps/api/dpi'
2+
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
3+
import { onMounted, ref, watch } from 'vue'
4+
5+
import { useCatStore } from '@/stores/cat'
6+
import { getCursorMonitor } from '@/utils/monitor'
7+
8+
const appWindow = getCurrentWebviewWindow()
9+
10+
export function useWindowPosition() {
11+
const catStore = useCatStore()
12+
const isMounted = ref(false)
13+
14+
const setWindowPosition = async () => {
15+
const monitor = await getCursorMonitor()
16+
17+
if (!monitor) return
18+
19+
const windowSize = await appWindow.outerSize()
20+
21+
switch (catStore.window.position) {
22+
case 'topLeft':
23+
return appWindow.setPosition(new PhysicalPosition(0, 0))
24+
case 'topRight':
25+
return appWindow.setPosition(new PhysicalPosition(monitor.size.width - windowSize.width, 0))
26+
case 'bottomLeft':
27+
return appWindow.setPosition(new PhysicalPosition(0, monitor.size.height - windowSize.height))
28+
default:
29+
return appWindow.setPosition(new PhysicalPosition(monitor.size.width - windowSize.width, monitor.size.height - windowSize.height))
30+
}
31+
}
32+
33+
onMounted(async () => {
34+
await setWindowPosition()
35+
36+
isMounted.value = true
37+
38+
appWindow.onScaleChanged(setWindowPosition)
39+
})
40+
41+
watch(() => catStore.window.position, setWindowPosition)
42+
43+
return {
44+
isMounted,
45+
setWindowPosition,
46+
}
47+
}

src/locales/en-US.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"windowRadius": "Window Radius",
2222
"opacity": "Opacity",
2323
"autoReleaseDelay": "Auto Release Delay",
24-
"hideOnHover": "Hide on Hover"
24+
"hideOnHover": "Hide on Hover",
25+
"position": "Window Position"
2526
},
2627
"hints": {
2728
"mirrorMode": "When enabled, the model will be mirrored horizontally.",
@@ -31,7 +32,14 @@
3132
"alwaysOnTop": "When enabled, the window stays above all other windows.",
3233
"windowSize": "Move mouse to window edge, or hold Shift and right-drag to resize.",
3334
"autoReleaseDelay": "On Windows, some system keys cannot capture release events and will auto-release after timeout.",
34-
"hideOnHover": "When enabled, the window hides when mouse hovers over it."
35+
"hideOnHover": "When enabled, the window hides when mouse hovers over it.",
36+
"position": "Takes effect after the app starts, or when this parameter, window size, model, or screen resolution changes."
37+
},
38+
"options": {
39+
"topLeft": "Top Left",
40+
"topRight": "Top Right",
41+
"bottomLeft": "Bottom Left",
42+
"bottomRight": "Bottom Right"
3543
}
3644
},
3745
"general": {

src/locales/pt-BR.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"windowRadius": "Raio da Janela",
2222
"opacity": "Opacidade",
2323
"autoReleaseDelay": "Atraso de Liberação Automática",
24-
"hideOnHover": "Ocultar ao Passar o Mouse"
24+
"hideOnHover": "Ocultar ao Passar o Mouse",
25+
"position": "Posição da Janela"
2526
},
2627
"hints": {
2728
"mirrorMode": "Quando ativado, o modelo será invertido horizontalmente.",
@@ -31,7 +32,14 @@
3132
"alwaysOnTop": "Quando ativado, a janela sempre ficará acima de outros aplicativos.",
3233
"windowSize": "Mova o mouse para a borda da janela ou segure Shift e arraste com o botão direito para redimensionar.",
3334
"autoReleaseDelay": "Devido ao Windows não capturar eventos de liberação de certas teclas de nível do sistema, elas serão automaticamente tratadas como liberadas após um tempo limite.",
34-
"hideOnHover": "Quando ativado, a janela será ocultada quando o mouse passar sobre ela."
35+
"hideOnHover": "Quando ativado, a janela será ocultada quando o mouse passar sobre ela.",
36+
"position": "Entra em vigor após inicializar o aplicativo ou quando este parâmetro, o tamanho da janela, o modelo ou a resolução de tela é alterado."
37+
},
38+
"options": {
39+
"topLeft": "Canto Superior Esquerdo",
40+
"topRight": "Canto Superior Direito",
41+
"bottomLeft": "Canto Inferior Esquerdo",
42+
"bottomRight": "Canto Inferior Direito"
3543
}
3644
},
3745
"general": {

src/locales/vi-VN.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"windowRadius": "Độ bo tròn cửa sổ",
2222
"opacity": "Độ mờ",
2323
"autoReleaseDelay": "Độ trễ tự động nhả phím",
24-
"hideOnHover": "Ẩn khi di chuột"
24+
"hideOnHover": "Ẩn khi di chuột",
25+
"position": "Vị trí cửa sổ"
2526
},
2627
"hints": {
2728
"mirrorMode": "Bật để lật ngang mô hình.",
@@ -31,7 +32,14 @@
3132
"alwaysOnTop": "Bật để cửa sổ luôn nằm trên ứng dụng khác.",
3233
"windowSize": "Di chuyển chuột đến mép cửa sổ hoặc giữ Shift và kéo chuột phải để thay đổi kích thước.",
3334
"autoReleaseDelay": "Do Windows không bắt được sự kiện nhả của một số phím hệ thống, các phím đó sẽ được tự động xem như đã nhả sau khi hết thời gian chờ.",
34-
"hideOnHover": "Khi bật, cửa sổ sẽ ẩn khi chuột di chuyển vào."
35+
"hideOnHover": "Khi bật, cửa sổ sẽ ẩn khi chuột di chuyển vào.",
36+
"position": "Có hiệu lực sau khi khởi động ứng dụng hoặc khi tham số này, kích thước cửa sổ, mô hình hoặc độ phân giải màn hình thay đổi."
37+
},
38+
"options": {
39+
"topLeft": "Góc trên cùng bên trái",
40+
"topRight": "Góc trên cùng bên phải",
41+
"bottomLeft": "Góc dưới cùng bên trái",
42+
"bottomRight": "Góc dưới cùng bên phải"
3543
}
3644
},
3745
"general": {

src/locales/zh-CN.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"windowRadius": "窗口圆角",
2222
"opacity": "不透明度",
2323
"autoReleaseDelay": "按键自动释放延迟",
24-
"hideOnHover": "鼠标移入隐藏"
24+
"hideOnHover": "鼠标移入隐藏",
25+
"position": "窗口位置"
2526
},
2627
"hints": {
2728
"mirrorMode": "启用后,模型将水平镜像翻转。",
@@ -31,7 +32,14 @@
3132
"alwaysOnTop": "启用后,窗口始终显示在其他应用程序上方。",
3233
"windowSize": "将鼠标移至窗口边缘,或按住 Shift 并右键拖动,也可以调整窗口大小。",
3334
"autoReleaseDelay": "由于 Windows 下部分系统级按键无法捕获释放事件,超时后将自动视为已释放。",
34-
"hideOnHover": "启用后,鼠标悬停在窗口上时,窗口会隐藏。"
35+
"hideOnHover": "启用后,鼠标悬停在窗口上时,窗口会隐藏。",
36+
"position": "应用启动后,或当此参数、窗口尺寸、模型、电脑分辨率发生变化时生效。"
37+
},
38+
"options": {
39+
"topLeft": "左上角",
40+
"topRight": "右上角",
41+
"bottomLeft": "左下角",
42+
"bottomRight": "右下角"
3543
}
3644
},
3745
"general": {

src/pages/main/index.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { useDevice } from '@/composables/useDevice'
1414
import { useGamepad } from '@/composables/useGamepad'
1515
import { useModel } from '@/composables/useModel'
1616
import { useSharedMenu } from '@/composables/useSharedMenu'
17+
import { useWindowPosition } from '@/composables/useWindowPosition'
1718
import { hideWindow, setAlwaysOnTop, setTaskbarVisibility, showWindow } from '@/plugins/window'
1819
import { useCatStore } from '@/stores/cat'
1920
import { useGeneralStore } from '@/stores/general.ts'
@@ -32,6 +33,7 @@ const generalStore = useGeneralStore()
3233
const resizing = ref(false)
3334
const backgroundImagePath = ref<string>()
3435
const { stickActive } = useGamepad()
36+
const { isMounted, setWindowPosition } = useWindowPosition()
3537
3638
onMounted(startListening)
3739
@@ -40,6 +42,8 @@ onUnmounted(handleDestroy)
4042
const debouncedResize = useDebounceFn(async () => {
4143
await handleResize()
4244
45+
await setWindowPosition()
46+
4347
resizing.value = false
4448
}, 100)
4549
@@ -52,7 +56,7 @@ useEventListener('resize', () => {
5256
watch(() => modelStore.currentModel, async (model) => {
5357
if (!model) return
5458
55-
handleLoad()
59+
await handleLoad()
5660
5761
const path = join(model.path, 'resources', 'background.png')
5862
@@ -76,6 +80,8 @@ watch(() => modelStore.currentModel, async (model) => {
7680
modelStore.supportKeys[fileName] = join(groupDir, file.name)
7781
}
7882
}
83+
84+
setWindowPosition()
7985
}, { deep: true, immediate: true })
8086
8187
watch([() => catStore.window.scale, modelSize], async ([scale, modelSize]) => {
@@ -145,6 +151,7 @@ function handleMouseMove(event: MouseEvent) {
145151

146152
<template>
147153
<div
154+
v-show="isMounted"
148155
class="relative size-screen overflow-hidden children:(absolute size-full)"
149156
:class="{ '-scale-x-100': catStore.model.mirror }"
150157
:style="{
@@ -174,7 +181,7 @@ function handleMouseMove(event: MouseEvent) {
174181
v-show="resizing"
175182
class="flex items-center justify-center bg-black"
176183
>
177-
<span class="text-center text-10vw text-white">
184+
<span class="text-center text-[10vw] text-white">
178185
{{ $t('pages.main.hints.redrawing') }}
179186
</span>
180187
</div>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script setup lang="ts">
2+
import { Select, SelectOption } from 'ant-design-vue'
3+
4+
import ProListItem from '@/components/pro-list-item/index.vue'
5+
import { useCatStore } from '@/stores/cat'
6+
7+
const catStore = useCatStore()
8+
</script>
9+
10+
<template>
11+
<ProListItem
12+
:description="$t('pages.preference.cat.hints.position')"
13+
:title="$t('pages.preference.cat.labels.position')"
14+
>
15+
<Select v-model:value="catStore.window.position">
16+
<SelectOption value="bottomRight">
17+
{{ $t('pages.preference.cat.options.bottomRight') }}
18+
</SelectOption>
19+
<SelectOption value="bottomLeft">
20+
{{ $t('pages.preference.cat.options.bottomLeft') }}
21+
</SelectOption>
22+
<SelectOption value="topLeft">
23+
{{ $t('pages.preference.cat.options.topLeft') }}
24+
</SelectOption>
25+
<SelectOption value="topRight">
26+
{{ $t('pages.preference.cat.options.topRight') }}
27+
</SelectOption>
28+
</Select>
29+
</ProListItem>
30+
</template>

src/pages/preference/components/cat/index.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<script setup lang="ts">
22
import { InputNumber, Slider, Switch } from 'ant-design-vue'
33
4+
import Position from './components/position/index.vue'
5+
46
import ProList from '@/components/pro-list/index.vue'
57
import ProListItem from '@/components/pro-list-item/index.vue'
68
import { useCatStore } from '@/stores/cat'
@@ -46,6 +48,8 @@ const catStore = useCatStore()
4648
</ProList>
4749

4850
<ProList :title="$t('pages.preference.cat.labels.windowSettings')">
51+
<Position />
52+
4953
<ProListItem
5054
:description="$t('pages.preference.cat.hints.passThrough')"
5155
:title="$t('pages.preference.cat.labels.passThrough')"

src/stores/cat.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface CatStore {
1616
opacity: number
1717
radius: number
1818
hideOnHover: boolean
19+
position: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
1920
}
2021
}
2122

@@ -61,6 +62,7 @@ export const useCatStore = defineStore('cat', () => {
6162
opacity: 100,
6263
radius: 0,
6364
hideOnHover: false,
65+
position: 'bottomRight',
6466
})
6567

6668
const init = () => {

0 commit comments

Comments
 (0)