This commit is contained in:
2025-09-12 14:45:32 +08:00
parent 67728c5c55
commit 3401c8b737
4 changed files with 45 additions and 30 deletions

View File

@@ -1,3 +1,5 @@
import type { TWindowFormState } from '@/core/window/types/WindowFormTypes.ts'
/** 拖拽移动开始的回调 */ /** 拖拽移动开始的回调 */
type TDragStartCallback = (x: number, y: number) => void; type TDragStartCallback = (x: number, y: number) => void;
/** 拖拽移动中的回调 */ /** 拖拽移动中的回调 */
@@ -16,9 +18,6 @@ type TResizeDirection =
| 'bottom-left' | 'bottom-left'
| 'bottom-right'; | 'bottom-right';
/** 窗口状态 */
type TWindowState = 'default' | 'minimized' | 'maximized';
/** 元素边界 */ /** 元素边界 */
interface IElementRect { interface IElementRect {
/** 宽度 */ /** 宽度 */
@@ -88,7 +87,7 @@ interface IDraggableResizableOptions {
onResizeEnd?: (data: IResizeCallbackData) => void; onResizeEnd?: (data: IResizeCallbackData) => void;
/** 窗口状态改变回调 */ /** 窗口状态改变回调 */
onWindowStateChange?: (state: TWindowState) => void; onWindowStateChange?: (state: TWindowFormState) => void;
} }
/** 拖拽的范围边界 */ /** 拖拽的范围边界 */
@@ -124,7 +123,7 @@ export class DraggableResizableWindow {
private onResizeMove?: (data: IResizeCallbackData) => void; private onResizeMove?: (data: IResizeCallbackData) => void;
private onResizeEnd?: (data: IResizeCallbackData) => void; private onResizeEnd?: (data: IResizeCallbackData) => void;
private onWindowStateChange?: (state: TWindowState) => void; private onWindowStateChange?: (state: TWindowFormState) => void;
private isDragging = false; private isDragging = false;
private currentDirection: TResizeDirection | null = null; private currentDirection: TResizeDirection | null = null;
@@ -158,7 +157,7 @@ export class DraggableResizableWindow {
private mutationObserver: MutationObserver; private mutationObserver: MutationObserver;
private animationFrame?: number; private animationFrame?: number;
private state: TWindowState = 'default'; private _windowFormState: TWindowFormState = 'default';
/** 元素信息 */ /** 元素信息 */
private targetBounds: IElementRect; private targetBounds: IElementRect;
/** 最小化前的元素信息 */ /** 最小化前的元素信息 */
@@ -167,8 +166,8 @@ export class DraggableResizableWindow {
private targetPreMaximizedBounds?: IElementRect; private targetPreMaximizedBounds?: IElementRect;
private taskbarElementId: string; private taskbarElementId: string;
get windowState() { get windowFormState() {
return this.state; return this._windowFormState;
} }
constructor(options: IDraggableResizableOptions) { constructor(options: IDraggableResizableOptions) {
@@ -261,7 +260,7 @@ export class DraggableResizableWindow {
document.removeEventListener('mousemove', this.checkDragStart); document.removeEventListener('mousemove', this.checkDragStart);
document.removeEventListener('mouseup', this.cancelPendingDrag); document.removeEventListener('mouseup', this.cancelPendingDrag);
if (this.state === 'maximized') { if (this._windowFormState === 'maximized') {
const preRect = this.targetPreMaximizedBounds!; const preRect = this.targetPreMaximizedBounds!;
const rect = this.target.getBoundingClientRect(); const rect = this.target.getBoundingClientRect();
const relX = e.clientX / rect.width; const relX = e.clientX / rect.width;
@@ -583,9 +582,9 @@ export class DraggableResizableWindow {
// 最小化到任务栏 // 最小化到任务栏
public minimize() { public minimize() {
if (this.state === 'minimized') return; if (this._windowFormState === 'minimized') return;
this.targetPreMinimizeBounds = { ...this.targetBounds } this.targetPreMinimizeBounds = { ...this.targetBounds }
this.state = 'minimized'; this._windowFormState = 'minimized';
const taskbar = document.querySelector(this.taskbarElementId); const taskbar = document.querySelector(this.taskbarElementId);
if (!taskbar) throw new Error('任务栏元素未找到'); if (!taskbar) throw new Error('任务栏元素未找到');
@@ -603,9 +602,9 @@ export class DraggableResizableWindow {
/** 最大化 */ /** 最大化 */
public maximize() { public maximize() {
if (this.state === 'maximized') return; if (this._windowFormState === 'maximized') return;
this.targetPreMaximizedBounds = { ...this.targetBounds } this.targetPreMaximizedBounds = { ...this.targetBounds }
this.state = 'maximized'; this._windowFormState = 'maximized';
const rect = this.target.getBoundingClientRect(); const rect = this.target.getBoundingClientRect();
@@ -624,19 +623,19 @@ export class DraggableResizableWindow {
/** 恢复到默认窗体状态 */ /** 恢复到默认窗体状态 */
public restore(onComplete?: () => void) { public restore(onComplete?: () => void) {
if (this.state === 'default') return; if (this._windowFormState === 'default') return;
let b: IElementRect; let b: IElementRect;
if ((this.state as TWindowState) === 'minimized' && this.targetPreMinimizeBounds) { if ((this._windowFormState as TWindowFormState) === 'minimized' && this.targetPreMinimizeBounds) {
// 最小化恢复,恢复到最小化前的状态 // 最小化恢复,恢复到最小化前的状态
b = this.targetPreMinimizeBounds; b = this.targetPreMinimizeBounds;
} else if ((this.state as TWindowState) === 'maximized' && this.targetPreMaximizedBounds) { } else if ((this._windowFormState as TWindowFormState) === 'maximized' && this.targetPreMaximizedBounds) {
// 最大化恢复,恢复到最大化前的默认状态 // 最大化恢复,恢复到最大化前的默认状态
b = this.targetPreMaximizedBounds; b = this.targetPreMaximizedBounds;
} else { } else {
b = this.targetBounds; b = this.targetBounds;
} }
this.state = 'default'; this._windowFormState = 'default';
this.target.style.display = 'block'; this.target.style.display = 'block';
@@ -696,7 +695,7 @@ export class DraggableResizableWindow {
this.target.style.height = `${targetH}px`; this.target.style.height = `${targetH}px`;
this.applyPosition(targetX, targetY, true); this.applyPosition(targetX, targetY, true);
onComplete?.(); onComplete?.();
this.onWindowStateChange?.(this.state); this.onWindowStateChange?.(this._windowFormState);
} }
}; };
requestAnimationFrame(step); requestAnimationFrame(step);

View File

@@ -1,6 +1,15 @@
import type { IProcess } from '@/core/process/IProcess.ts' import type { IProcess } from '@/core/process/IProcess.ts'
import type { TWindowFormState } from '@/core/window/types/WindowFormTypes.ts'
export interface IWindowForm { export interface IWindowForm {
/** 窗体id */
get id(): string; get id(): string;
/** 窗体所属的进程 */
get proc(): IProcess | undefined; get proc(): IProcess | undefined;
/** 窗体元素 */
get windowFormEle(): HTMLElement;
/** 窗体状态 */
get windowFormState(): TWindowFormState;
/** 关闭窗体 */
closeWindowForm(): void;
} }

View File

@@ -14,8 +14,8 @@ export default class WindowFormImpl implements IWindowForm {
private dom: HTMLElement; private dom: HTMLElement;
private drw: DraggableResizableWindow; private drw: DraggableResizableWindow;
private pos: WindowFormPos = { x: 0, y: 0 }; private pos: WindowFormPos = { x: 0, y: 0 };
private width: number = 0; private width: number;
private height: number = 0; private height: number;
public get id() { public get id() {
return this._id; return this._id;
@@ -26,6 +26,12 @@ export default class WindowFormImpl implements IWindowForm {
private get desktopRootDom() { private get desktopRootDom() {
return XSystem.instance.desktopRootDom; return XSystem.instance.desktopRootDom;
} }
public get windowFormEle() {
return this.dom;
}
public get windowFormState() {
return this.drw.windowFormState
}
constructor(proc: IProcess, config: IWindowFormConfig) { constructor(proc: IProcess, config: IWindowFormConfig) {
this._procId = proc.id; this._procId = proc.id;
@@ -34,20 +40,21 @@ export default class WindowFormImpl implements IWindowForm {
x: config.left ?? 0, x: config.left ?? 0,
y: config.top ?? 0 y: config.top ?? 0
} }
this.width = config.width ?? 0; this.width = config.width ?? 200;
this.height = config.height ?? 0; this.height = config.height ?? 100;
this.createWindowFrom(); this.createWindowFrom();
} }
private createWindowFrom() { private createWindowFrom() {
this.dom = this.windowFormEle(); this.dom = this.createWindowFormEle();
this.dom.style.position = 'absolute'; this.dom.style.position = 'absolute';
this.dom.style.width = `${this.width}px`; this.dom.style.width = `${this.width}px`;
this.dom.style.height = `${this.height}px`; this.dom.style.height = `${this.height}px`;
this.dom.style.zIndex = '10'; this.dom.style.zIndex = '10';
const header = this.dom.querySelector('.title-bar') as HTMLElement; const header = this.dom.querySelector('.title-bar') as HTMLElement;
const content = this.dom.querySelector('.window-content') as HTMLElement;
this.drw = new DraggableResizableWindow({ this.drw = new DraggableResizableWindow({
target: this.dom, target: this.dom,
handle: header, handle: header,
@@ -67,13 +74,13 @@ export default class WindowFormImpl implements IWindowForm {
this.desktopRootDom.appendChild(this.dom); this.desktopRootDom.appendChild(this.dom);
} }
private closeWindowForm() { public closeWindowForm() {
this.drw.destroy(); this.drw.destroy();
this.desktopRootDom.removeChild(this.dom); this.desktopRootDom.removeChild(this.dom);
this.proc?.event.notifyEvent('onProcessWindowFormExit', this.id) this.proc?.event.notifyEvent('onProcessWindowFormExit', this.id)
} }
private windowFormEle() { private createWindowFormEle() {
const template = document.createElement('template'); const template = document.createElement('template');
template.innerHTML = ` template.innerHTML = `
<div class="window"> <div class="window">
@@ -85,10 +92,7 @@ export default class WindowFormImpl implements IWindowForm {
<div class="close btn" title="关闭">×</div> <div class="close btn" title="关闭">×</div>
</div> </div>
</div> </div>
<div class="window-content"> <div class="window-content"></div>
<p>这是一个纯静态的 Windows 风格窗体示例。</p>
<p>你可以在这里放置任何内容。</p>
</div>
</div> </div>
` `
const fragment = template.content.cloneNode(true) as DocumentFragment; const fragment = template.content.cloneNode(true) as DocumentFragment;
@@ -99,7 +103,7 @@ export default class WindowFormImpl implements IWindowForm {
windowElement.querySelector('.btn.maximize') windowElement.querySelector('.btn.maximize')
?.addEventListener('click', () => { ?.addEventListener('click', () => {
if (this.drw.windowState === 'maximized') { if (this.drw.windowFormState === 'maximized') {
this.drw.restore() this.drw.restore()
} else { } else {
this.drw.maximize() this.drw.maximize()

View File

@@ -5,3 +5,6 @@ export interface WindowFormPos {
x: number; x: number;
y: number; y: number;
} }
/** 窗口状态 */
export type TWindowFormState = 'default' | 'minimized' | 'maximized';