fix: adapt float ball position across rotations
This commit is contained in:
@@ -64,8 +64,14 @@ var ConfigValidator = {
|
|||||||
schemas: {
|
schemas: {
|
||||||
// 悬浮球核心配置
|
// 悬浮球核心配置
|
||||||
BALL_SIZE_DP: { type: "int", min: 20, max: 200, default: 45 },
|
BALL_SIZE_DP: { type: "int", min: 20, max: 200, default: 45 },
|
||||||
BALL_INIT_X: { type: "int", min: 0, max: 2000, default: 0 },
|
BALL_INIT_X: { type: "int", min: 0, max: 10000, default: 0 },
|
||||||
BALL_INIT_Y_DP: { type: "int", min: 0, max: 1000, default: 220 },
|
BALL_INIT_Y_DP: { type: "int", min: 0, max: 2000, default: 220 },
|
||||||
|
BALL_POS_SCREEN_W: { type: "int", min: 0, max: 10000, default: 0 },
|
||||||
|
BALL_POS_SCREEN_H: { type: "int", min: 0, max: 10000, default: 0 },
|
||||||
|
BALL_POS_X_RATIO: { type: "float", min: 0, max: 1, default: 0 },
|
||||||
|
BALL_POS_Y_RATIO: { type: "float", min: 0, max: 1, default: 0 },
|
||||||
|
BALL_POS_DOCKED: { type: "bool", default: false },
|
||||||
|
BALL_POS_DOCK_SIDE: { type: "enum", values: ["", "left", "right"], default: "" },
|
||||||
|
|
||||||
// 面板布局配置
|
// 面板布局配置
|
||||||
PANEL_COLS: { type: "int", min: 1, max: 6, default: 1 },
|
PANEL_COLS: { type: "int", min: 1, max: 6, default: 1 },
|
||||||
|
|||||||
@@ -19,17 +19,84 @@ FloatBallAppWM.prototype.loadPanelState = function(key) {
|
|||||||
// =======================【工具:位置持久化】======================
|
// =======================【工具:位置持久化】======================
|
||||||
FloatBallAppWM.prototype.savePos = function(x, y) {
|
FloatBallAppWM.prototype.savePos = function(x, y) {
|
||||||
try {
|
try {
|
||||||
this.config.BALL_INIT_X = Math.floor(x);
|
var di = this.getDockInfo ? this.getDockInfo() : { ballSize: this.dp(this.config.BALL_SIZE_DP || 45) };
|
||||||
this.config.BALL_INIT_Y_DP = Math.floor(y / this.state.density);
|
var sw = (this.state && this.state.screen) ? Number(this.state.screen.w || 0) : 0;
|
||||||
// # 节流保存
|
var sh = (this.state && this.state.screen) ? Number(this.state.screen.h || 0) : 0;
|
||||||
|
var ballSize = Number(di.ballSize || this.dp(this.config.BALL_SIZE_DP || 45));
|
||||||
|
var maxX = Math.max(0, sw - ballSize);
|
||||||
|
var maxY = Math.max(0, sh - ballSize);
|
||||||
|
|
||||||
|
var persistX = Math.floor(Number(x || 0));
|
||||||
|
var persistY = Math.floor(Number(y || 0));
|
||||||
|
var dockSide = "";
|
||||||
|
var docked = !!(this.state && this.state.docked);
|
||||||
|
|
||||||
|
// 吸边裁剪态下 Window x 可能是 screenW - visiblePx;持久化时改存“完整球”的逻辑坐标。
|
||||||
|
if (docked) {
|
||||||
|
dockSide = String(this.state.dockSide || "");
|
||||||
|
if (dockSide === "right" && sw > 0) persistX = maxX;
|
||||||
|
else if (dockSide === "left") persistX = 0;
|
||||||
|
} else if (sw > 0) {
|
||||||
|
persistX = this.clamp(persistX, 0, maxX);
|
||||||
|
}
|
||||||
|
if (sh > 0) persistY = this.clamp(persistY, 0, maxY);
|
||||||
|
|
||||||
|
this.config.BALL_INIT_X = persistX;
|
||||||
|
this.config.BALL_INIT_Y_DP = Math.floor(persistY / this.state.density);
|
||||||
|
|
||||||
|
// 新增位置元数据:用于不同分辨率/横竖屏之间按比例或按吸边侧恢复,避免横屏落在屏幕中间。
|
||||||
|
this.config.BALL_POS_SCREEN_W = sw;
|
||||||
|
this.config.BALL_POS_SCREEN_H = sh;
|
||||||
|
this.config.BALL_POS_X_RATIO = maxX > 0 ? (persistX / maxX) : 0;
|
||||||
|
this.config.BALL_POS_Y_RATIO = maxY > 0 ? (persistY / maxY) : 0;
|
||||||
|
this.config.BALL_POS_DOCKED = docked;
|
||||||
|
this.config.BALL_POS_DOCK_SIDE = dockSide;
|
||||||
|
|
||||||
return ConfigManager.saveSettings(this.config);
|
return ConfigManager.saveSettings(this.config);
|
||||||
} catch (e) { return false; }
|
} catch (e) { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FloatBallAppWM.prototype.loadSavedPos = function() {
|
FloatBallAppWM.prototype.loadSavedPos = function() {
|
||||||
// # 直接从 config 返回,因为 config 已经是持久化的
|
var di = this.getDockInfo ? this.getDockInfo() : { ballSize: this.dp(this.config.BALL_SIZE_DP || 45) };
|
||||||
|
var ballSize = Number(di.ballSize || this.dp(this.config.BALL_SIZE_DP || 45));
|
||||||
|
var sw = (this.state && this.state.screen) ? Number(this.state.screen.w || 0) : 0;
|
||||||
|
var sh = (this.state && this.state.screen) ? Number(this.state.screen.h || 0) : 0;
|
||||||
|
var maxX = Math.max(0, sw - ballSize);
|
||||||
|
var maxY = Math.max(0, sh - ballSize);
|
||||||
|
|
||||||
var x = Number(this.config.BALL_INIT_X || 0);
|
var x = Number(this.config.BALL_INIT_X || 0);
|
||||||
var y = this.dp(Number(this.config.BALL_INIT_Y_DP || 100));
|
var y = this.dp(Number(this.config.BALL_INIT_Y_DP || 100));
|
||||||
|
|
||||||
|
try {
|
||||||
|
var savedW = Number(this.config.BALL_POS_SCREEN_W || 0);
|
||||||
|
var savedH = Number(this.config.BALL_POS_SCREEN_H || 0);
|
||||||
|
var hasMeta = savedW > 0 && savedH > 0;
|
||||||
|
var docked = (typeof parseBooleanLike === "function") ? parseBooleanLike(this.config.BALL_POS_DOCKED, false) : !!this.config.BALL_POS_DOCKED;
|
||||||
|
var side = String(this.config.BALL_POS_DOCK_SIDE || "");
|
||||||
|
|
||||||
|
if (hasMeta && (savedW !== sw || savedH !== sh)) {
|
||||||
|
var xr = Number(this.config.BALL_POS_X_RATIO);
|
||||||
|
var yr = Number(this.config.BALL_POS_Y_RATIO);
|
||||||
|
if (isNaN(xr)) xr = 0;
|
||||||
|
if (isNaN(yr)) yr = 0;
|
||||||
|
x = Math.round(this.clamp(xr, 0, 1) * maxX);
|
||||||
|
y = Math.round(this.clamp(yr, 0, 1) * maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (docked || side === "left" || side === "right") {
|
||||||
|
if (side === "right") x = maxX;
|
||||||
|
else if (side === "left") x = 0;
|
||||||
|
} else if (!hasMeta && sw > sh && sw > 0) {
|
||||||
|
// 兼容旧版:只存了竖屏像素 x。横屏启动时旧的“右侧 x”会落在屏幕中部,这里按短边推断并贴回右边。
|
||||||
|
var portraitMaxXGuess = Math.max(0, Math.min(sw, sh) - ballSize);
|
||||||
|
if (x > Math.round(portraitMaxXGuess * 0.55) && x < Math.round(maxX * 0.85)) {
|
||||||
|
x = maxX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
x = this.clamp(Math.floor(x), 0, maxX);
|
||||||
|
y = this.clamp(Math.floor(y), 0, maxY);
|
||||||
return { x: x, y: y };
|
return { x: x, y: y };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -253,10 +253,9 @@ FloatBallAppWM.prototype.startAsync = function(entryProcInfo, closeRule) {
|
|||||||
|
|
||||||
if (self.L) self.L.updateConfig(self.config);
|
if (self.L) self.L.updateConfig(self.config);
|
||||||
|
|
||||||
self.state.loadedPos = self.loadSavedPos();
|
|
||||||
|
|
||||||
self.state.screen = self.getScreenSizePx();
|
self.state.screen = self.getScreenSizePx();
|
||||||
self.state.lastRotation = self.getRotation();
|
self.state.lastRotation = self.getRotation();
|
||||||
|
self.state.loadedPos = self.loadSavedPos();
|
||||||
|
|
||||||
self.createBallViews();
|
self.createBallViews();
|
||||||
self.state.ballLp = self.createBallLayoutParams();
|
self.state.ballLp = self.createBallLayoutParams();
|
||||||
|
|||||||
Reference in New Issue
Block a user