Files

202 lines
8.0 KiB
QML

import QtQuick
import qs.Common
QtObject {
id: root
property string instanceId: ""
property var instanceData: null
property var screen: null
property real minWidth: 100
property real minHeight: 100
property bool forceSquare: false
property bool lockScreen: false
readonly property bool isInstance: instanceId !== "" && instanceData !== null
readonly property bool syncPositionAcrossScreens: instanceData?.config?.syncPositionAcrossScreens ?? false
readonly property string screenKey: SettingsData.getScreenDisplayName(screen)
readonly property string positionKey: syncPositionAcrossScreens ? "_synced" : screenKey
readonly property var storedPositions: SessionData.desktopWidgetInstancePositions[instanceId] ?? null
readonly property var anchorKeys: ({
x: "anchorX",
y: "anchorY"
})
readonly property int screenWidth: screen?.width ?? 1920
readonly property int screenHeight: screen?.height ?? 1080
function storedGeometry(key) {
if (!isInstance)
return undefined;
return storedPositions?.[positionKey]?.[key];
}
function anchoredPosition(anchor, offset, extent, size) {
switch (anchor) {
case "center":
return (extent - size) / 2 + offset;
case "end":
return extent - size - offset;
}
return offset;
}
function storedCoordinate(key, extent, size, fallback) {
const offset = storedGeometry(key);
if (offset === undefined)
return fallback;
return anchoredPosition(storedGeometry(anchorKeys[key]), syncPositionAcrossScreens ? offset * extent : offset, extent, size);
}
readonly property bool hasSavedPosition: storedGeometry("x") !== undefined
readonly property bool hasSavedSize: storedGeometry("width") !== undefined
property real defaultWidth: 280
property real defaultHeight: 180
property real defaultX: screenWidth / 2 - savedWidth / 2
property real defaultY: screenHeight / 2 - savedHeight / 2
readonly property real savedX: storedCoordinate("x", screenWidth, widgetWidth, defaultX)
readonly property real savedY: storedCoordinate("y", screenHeight, widgetHeight, defaultY)
readonly property real savedWidth: storedGeometry("width") ?? defaultWidth
readonly property real savedHeight: forceSquare ? savedWidth : (storedGeometry("height") ?? defaultHeight)
property real dragOverrideX: -1
property real dragOverrideY: -1
property real dragOverrideW: -1
property real dragOverrideH: -1
property bool squareSnapped: false
readonly property real effectiveX: dragOverrideX >= 0 ? dragOverrideX : savedX
readonly property real effectiveY: dragOverrideY >= 0 ? dragOverrideY : savedY
readonly property real effectiveW: dragOverrideW >= 0 ? dragOverrideW : savedWidth
readonly property real effectiveH: dragOverrideH >= 0 ? dragOverrideH : savedHeight
readonly property real widgetX: Math.max(0, Math.min(effectiveX, screenWidth - widgetWidth))
readonly property real widgetY: Math.max(0, Math.min(effectiveY, screenHeight - widgetHeight))
readonly property real widgetWidth: Math.max(minWidth, Math.min(effectiveW, screenWidth))
readonly property real widgetHeight: Math.max(minHeight, Math.min(effectiveH, screenHeight))
property var _gridSettingsTrigger: lockScreen ? SessionData.lockScreenWidgetGridSettings : SessionData.desktopWidgetGridSettings
readonly property int gridSize: {
void _gridSettingsTrigger;
return SessionData.getWidgetGridSetting(lockScreen, screenKey, "size", 40);
}
readonly property bool gridEnabled: {
void _gridSettingsTrigger;
return SessionData.getWidgetGridSetting(lockScreen, screenKey, "enabled", false);
}
function snapToGrid(value) {
return Math.round(value / gridSize) * gridSize;
}
function clearDragOverrides() {
dragOverrideX = -1;
dragOverrideY = -1;
dragOverrideW = -1;
dragOverrideH = -1;
squareSnapped = false;
}
function requestResize(width, height) {
if (width < minWidth || height < minHeight)
return;
if (width > screenWidth || height > screenHeight)
return;
dragOverrideW = width;
dragOverrideH = height;
}
function clearResize() {
dragOverrideW = -1;
dragOverrideH = -1;
}
function saveGeometry(updates) {
if (!isInstance)
return;
SessionData.updateDesktopWidgetInstancePosition(instanceId, positionKey, updates);
}
// Nearest of start edge, center and end edge wins, so a widget dropped near the right grows leftward.
function anchorFor(position, extent, size) {
const toStart = position;
const toCenter = Math.abs(position - (extent - size) / 2);
const toEnd = extent - size - position;
if (toCenter <= toStart && toCenter <= toEnd)
return "center";
return toEnd < toStart ? "end" : "start";
}
function anchoredOffset(anchor, position, extent, size) {
switch (anchor) {
case "center":
return position - (extent - size) / 2;
case "end":
return extent - size - position;
}
return position;
}
function savePosition(finalX, finalY) {
const anchorX = anchorFor(finalX, screenWidth, widgetWidth);
const anchorY = anchorFor(finalY, screenHeight, widgetHeight);
const offsetX = anchoredOffset(anchorX, finalX, screenWidth, widgetWidth);
const offsetY = anchoredOffset(anchorY, finalY, screenHeight, widgetHeight);
saveGeometry({
x: syncPositionAcrossScreens ? offsetX / screenWidth : offsetX,
y: syncPositionAcrossScreens ? offsetY / screenHeight : offsetY,
anchorX: anchorX === "start" ? undefined : anchorX,
anchorY: anchorY === "start" ? undefined : anchorY
});
}
function saveSize(finalW, finalH) {
const sizeVal = forceSquare ? Math.max(finalW, finalH) : finalW;
saveGeometry({
width: sizeVal,
height: forceSquare ? sizeVal : finalH
});
}
function saveDefaultGeometry(defaultWidth, defaultHeight) {
if (!hasSavedSize) {
const finalW = Math.max(minWidth, Math.min(defaultWidth, screenWidth));
const finalH = Math.max(minHeight, Math.min(defaultHeight, screenHeight));
saveSize(finalW, finalH);
}
if (hasSavedPosition)
return;
const finalX = Math.max(0, Math.min(screenWidth / 2 - widgetWidth / 2, screenWidth - widgetWidth));
const finalY = Math.max(0, Math.min(screenHeight / 2 - widgetHeight / 2, screenHeight - widgetHeight));
savePosition(finalX, finalY);
}
function dragMoveTo(startX, startY, dx, dy) {
let newX = Math.max(0, Math.min(startX + dx, screenWidth - widgetWidth));
let newY = Math.max(0, Math.min(startY + dy, screenHeight - widgetHeight));
if (!gridEnabled)
return Qt.point(newX, newY);
newX = Math.max(0, Math.min(snapToGrid(newX), screenWidth - widgetWidth));
newY = Math.max(0, Math.min(snapToGrid(newY), screenHeight - widgetHeight));
return Qt.point(newX, newY);
}
function dragResizeTo(startWidth, startHeight, dx, dy) {
let newW = Math.max(minWidth, Math.min(startWidth + dx, screenWidth - widgetX));
let newH = Math.max(minHeight, Math.min(startHeight + dy, screenHeight - widgetY));
if (gridEnabled) {
newW = Math.max(minWidth, snapToGrid(newW));
newH = Math.max(minHeight, snapToGrid(newH));
}
if (!forceSquare) {
squareSnapped = Math.abs(newW - newH) <= (gridEnabled ? gridSize / 2 : Theme.spacingL);
if (!squareSnapped)
return Qt.size(newW, newH);
}
const size = Math.max(newW, newH);
return Qt.size(Math.min(size, screenWidth - widgetX), Math.min(size, screenHeight - widgetY));
}
}