170 lines
4.9 KiB
TypeScript
170 lines
4.9 KiB
TypeScript
import type { IDesktopAppIcon } from '@/core/desktop/types/IDesktopAppIcon.ts'
|
|
import {
|
|
computed,
|
|
nextTick,
|
|
onMounted,
|
|
onUnmounted,
|
|
reactive,
|
|
ref,
|
|
toRaw,
|
|
toRefs,
|
|
toValue,
|
|
useTemplateRef,
|
|
watch,
|
|
watchEffect,
|
|
} from 'vue'
|
|
import type { IGridTemplateParams } from '@/core/desktop/types/IGridTemplateParams.ts'
|
|
import { eventManager } from '@/core/events/EventManager.ts'
|
|
import { processManager } from '@/core/process/ProcessManager.ts'
|
|
|
|
export function useDesktopInit(containerStr: string) {
|
|
let container:HTMLElement
|
|
// 初始值
|
|
const gridTemplate = reactive<IGridTemplateParams>({
|
|
cellExpectWidth: 90,
|
|
cellExpectHeight: 110,
|
|
cellRealWidth: 90,
|
|
cellRealHeight: 110,
|
|
gapX: 4,
|
|
gapY: 4,
|
|
colCount: 1,
|
|
rowCount: 1
|
|
})
|
|
|
|
const ro = new ResizeObserver(entries => {
|
|
const entry= entries[0]
|
|
const containerRect = entry.contentRect
|
|
gridTemplate.colCount = Math.floor((containerRect.width + gridTemplate.gapX) / (gridTemplate.cellExpectWidth + gridTemplate.gapX));
|
|
gridTemplate.rowCount = Math.floor((containerRect.height + gridTemplate.gapY) / (gridTemplate.cellExpectHeight + gridTemplate.gapY));
|
|
|
|
const w = containerRect.width - (gridTemplate.gapX * (gridTemplate.colCount - 1))
|
|
const h = containerRect.height - (gridTemplate.gapY * (gridTemplate.rowCount - 1))
|
|
gridTemplate.cellRealWidth = Number((w / gridTemplate.colCount).toFixed(2))
|
|
gridTemplate.cellRealHeight = Number((h / gridTemplate.rowCount).toFixed(2))
|
|
})
|
|
|
|
const gridStyle = computed(() => ({
|
|
gridTemplateColumns: `repeat(${gridTemplate.colCount}, minmax(${gridTemplate.cellExpectWidth}px, 1fr))`,
|
|
gridTemplateRows: `repeat(${gridTemplate.rowCount}, minmax(${gridTemplate.cellExpectHeight}px, 1fr))`,
|
|
gap: `${gridTemplate.gapX}px ${gridTemplate.gapY}px`
|
|
}))
|
|
|
|
onMounted(() => {
|
|
container = document.querySelector(containerStr)!
|
|
ro.observe(container)
|
|
})
|
|
onUnmounted(() => {
|
|
ro.unobserve(container)
|
|
ro.disconnect()
|
|
})
|
|
|
|
// 有桌面图标的app
|
|
const appInfos = processManager.processInfos.filter(processInfo => !processInfo.isJustProcess)
|
|
const oldAppIcons: IDesktopAppIcon[] = JSON.parse(localStorage.getItem('desktopAppIconInfo') || '[]')
|
|
const appIcons: IDesktopAppIcon[] = appInfos.map((processInfo, index) => {
|
|
const oldAppIcon = oldAppIcons.find(oldAppIcon => oldAppIcon.name === processInfo.name)
|
|
|
|
// 左上角坐标原点,从上到下从左到右 索引从1开始
|
|
const x = index % gridTemplate.rowCount + 1
|
|
const y = Math.floor(index / gridTemplate.rowCount) + 1
|
|
|
|
return {
|
|
name: processInfo.name,
|
|
icon: processInfo.icon,
|
|
path: processInfo.startName,
|
|
x: oldAppIcon ? oldAppIcon.x : x,
|
|
y: oldAppIcon ? oldAppIcon.y : y
|
|
}
|
|
})
|
|
|
|
const appIconsRef = ref(appIcons)
|
|
const exceedApp = ref<IDesktopAppIcon[]>([])
|
|
|
|
watch(() => [gridTemplate.colCount, gridTemplate.rowCount], ([nCols, nRows], [oCols, oRows]) => {
|
|
// if (oCols == 1 && oRows == 1) return
|
|
if (oCols === nCols && oRows === nRows) return
|
|
const { appIcons, hideAppIcons } = rearrangeIcons(toRaw(appIconsRef.value), nCols, nRows)
|
|
appIconsRef.value = appIcons
|
|
exceedApp.value = hideAppIcons
|
|
})
|
|
|
|
eventManager.addEventListener('onDesktopAppIconPos', (iconInfo) => {
|
|
localStorage.setItem('desktopAppIconInfo', JSON.stringify(toValue(appIconsRef.value)))
|
|
})
|
|
|
|
return {
|
|
gridTemplate,
|
|
appIconsRef,
|
|
gridStyle
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 重新安排图标位置
|
|
* @param appIconInfos 图标信息
|
|
* @param maxCol 列数
|
|
* @param maxRow 行数
|
|
*/
|
|
function rearrangeIcons(
|
|
appIconInfos: IDesktopAppIcon[],
|
|
maxCol: number,
|
|
maxRow: number
|
|
): IRearrangeInfo {
|
|
const occupied = new Set<string>();
|
|
|
|
function key(x: number, y: number) {
|
|
return `${x},${y}`;
|
|
}
|
|
|
|
const appIcons: IDesktopAppIcon[] = []
|
|
const hideAppIcons: IDesktopAppIcon[] = []
|
|
const temp: IDesktopAppIcon[] = []
|
|
|
|
for (const appIcon of appIconInfos) {
|
|
const { x, y } = appIcon;
|
|
|
|
if (x <= maxCol && y <= maxRow) {
|
|
if (!occupied.has(key(x, y))) {
|
|
occupied.add(key(x, y))
|
|
appIcons.push({ ...appIcon, x, y })
|
|
}
|
|
} else {
|
|
temp.push(appIcon)
|
|
}
|
|
}
|
|
|
|
const max = maxCol * maxRow
|
|
for (const appIcon of temp) {
|
|
if (appIcons.length < max) {
|
|
// 最后格子也被占 → 从 (1,1) 开始找空位
|
|
let placed = false;
|
|
for (let c = 1; c <= maxCol; c++) {
|
|
for (let r = 1; r <= maxRow; r++) {
|
|
if (!occupied.has(key(c, r))) {
|
|
occupied.add(key(c, r));
|
|
appIcons.push({ ...appIcon, x: c, y: r });
|
|
placed = true;
|
|
break;
|
|
}
|
|
}
|
|
if (placed) break;
|
|
}
|
|
} else {
|
|
// 放不下了
|
|
hideAppIcons.push(appIcon)
|
|
}
|
|
}
|
|
|
|
return {
|
|
appIcons,
|
|
hideAppIcons
|
|
};
|
|
}
|
|
|
|
interface IRearrangeInfo {
|
|
/** 正常的桌面图标信息 */
|
|
appIcons: IDesktopAppIcon[];
|
|
/** 隐藏的桌面图标信息(超出屏幕显示的) */
|
|
hideAppIcons: IDesktopAppIcon[];
|
|
}
|