Add floating window mode for vnc

This commit is contained in:
赵一寰 2026-03-15 22:43:14 +08:00
parent f6cdaa8bce
commit f6ec924dd1

View File

@ -53,6 +53,8 @@ export class ClawComputerPanel extends LitElement {
private isResizing = false;
private resizeEdge = "";
private aspectRatio = 1;
// 记录拖拽开始时鼠标相对于拖拽句柄的位置(点 A
private dragAnchor = { x: 0, y: 0 };
@property({ type: Boolean }) enabled = false;
@ -381,11 +383,19 @@ export class ClawComputerPanel extends LitElement {
this.dragStart = { x: e.clientX, y: e.clientY };
const screen = this.shadowRoot?.querySelector(".screen") as HTMLDivElement | null;
if (screen) {
const dragHandle = this.shadowRoot?.querySelector(".drag-handle") as HTMLDivElement | null;
if (screen && dragHandle) {
// 拖拽过程中,暂时禁用 screen 内部所有元素的 pointer-events
// 这样即使鼠标移动到 VNC 窗口内部,也不会被 canvas 捕获
screen.classList.add("dragging");
// 记录鼠标相对于拖拽句柄的位置(点 A
const dragHandleRect = dragHandle.getBoundingClientRect();
this.dragAnchor = {
x: e.clientX - dragHandleRect.left,
y: e.clientY - dragHandleRect.top,
};
const rect = screen.getBoundingClientRect();
// 获取 claw-computer-panel 本身的尺寸
const hostRect = this.getBoundingClientRect();
@ -457,6 +467,42 @@ export class ClawComputerPanel extends LitElement {
height: this.initialRect.height,
};
} else {
// 检测是否超过 resizable-divider左边的分割线
// resizable-divider 就在我们左边,所以用我们自己的左边界作为判断依据
const hostRect = this.getBoundingClientRect();
// 检查鼠标是否超过了我们自己的左边界(即超过了 resizable-divider
if (e.clientX < hostRect.left) {
// 切换到悬浮模式
this.isFloating = true;
// 计算新的悬浮窗口位置,保持鼠标相对于拖拽句柄的位置(点 A
// 窗口的左上角 = 鼠标当前位置 - 锚点偏移
const newX = e.clientX - this.dragAnchor.x;
const newY = e.clientY - this.dragAnchor.y;
// 更新 floatingRect
this.floatingRect = {
x: newX,
y: newY,
width: this.initialRect.width,
height: this.initialRect.height,
};
// 更新 initialRect使其基于新的悬浮位置
this.initialRect = {
...this.initialRect,
x: newX,
y: newY,
};
// 更新 dragStart使其从当前位置继续拖拽
this.dragStart = { x: e.clientX, y: e.clientY };
return;
}
// 如果没有超过分割线,继续停靠模式的拖拽
// 每次都直接获取当前尺寸
const hostHeight = this.offsetHeight;
const screen = this.shadowRoot?.querySelector(".screen") as HTMLDivElement | null;
@ -558,6 +604,14 @@ export class ClawComputerPanel extends LitElement {
const dx = e.clientX - this.dragStart.x;
const dy = e.clientY - this.dragStart.y;
// 保持宽高比调整
// 只有在对角调整时才强制保持宽高比,或者在边缘调整时更新另一个维度?
// 用户说“悬浮模式的缩放我要求是不要改变窗口比例的,斜对角拖拽时以对角为固定点缩放,但是不能任意缩放”
// 所以应该始终保持比例?或者只在对角时?
// “斜对角拖拽时以对角为固定点缩放”暗示对角时必须保持比例。
// 单边拖拽通常只改变一个维度,这会破坏比例。
// 如果必须保持比例,单边拖拽也必须同时改变另一个维度。
let { x, y, width, height } = this.initialRect;
if (this.resizeEdge.includes("right")) {