mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-08 12:13:31 -04:00
3e4d2b4d46
* feat(control-center): add widget config overlay with showMountPath toggle for DiskUsage Introduces WidgetConfigOverlay and DiskUsageWidgetConfigMenu components, allowing users to toggle mount path visibility per DiskUsage widget in edit mode * refactor(control-center): use Theme.iconSizeLarge and Theme.fontSizeLarge for small tiles Standardize SmallDiskUsageButton and SmallBatteryButton sizing with Theme.iconSizeLarge and Theme.fontSizeLarge, and unify font weight to Font.Bold on both tile widgets. * fix(control-center): adjust SmallDiskUsageButton font size based on showMountPath * refactor(control-center): simplify DiskUsage config menu i18n strings Remove the redundant "Disk Usage Widget" title and the toggle description to reduce translatable strings
353 lines
9.5 KiB
QML
353 lines
9.5 KiB
QML
import QtQuick
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property bool editMode: false
|
|
property var widgetData: null
|
|
property int widgetIndex: -1
|
|
property bool isSlider: false
|
|
property Component widgetComponent: null
|
|
property real gridCellWidth: 100
|
|
property real gridCellHeight: 60
|
|
property int gridColumns: 4
|
|
property var gridLayout: null
|
|
|
|
z: dragArea.drag.active ? 10000 : 1
|
|
|
|
signal widgetMoved(int fromIndex, int toIndex)
|
|
signal removeWidget(int index)
|
|
signal toggleWidgetSize(int index)
|
|
signal configRequested(int index, var widgetData, var anchor)
|
|
|
|
width: {
|
|
const widgetWidth = widgetData?.width || 50;
|
|
if (widgetWidth <= 25)
|
|
return gridCellWidth;
|
|
else if (widgetWidth <= 50)
|
|
return gridCellWidth * 2;
|
|
else if (widgetWidth <= 75)
|
|
return gridCellWidth * 3;
|
|
else
|
|
return gridCellWidth * 4;
|
|
}
|
|
height: isSlider ? 16 : gridCellHeight
|
|
|
|
Rectangle {
|
|
id: dragIndicator
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
border.color: Theme.primary
|
|
border.width: dragArea.drag.active ? 2 : 0
|
|
radius: Theme.cornerRadius
|
|
opacity: dragArea.drag.active ? 0.8 : 1.0
|
|
z: dragArea.drag.active ? 10000 : 1
|
|
|
|
Behavior on border.width {
|
|
NumberAnimation {
|
|
duration: 150
|
|
}
|
|
}
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: 150
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: widgetLoader
|
|
anchors.fill: parent
|
|
sourceComponent: widgetComponent
|
|
property var widgetData: root.widgetData
|
|
property int widgetIndex: root.widgetIndex
|
|
property int globalWidgetIndex: root.widgetIndex
|
|
property int widgetWidth: root.widgetData?.width || 50
|
|
|
|
MouseArea {
|
|
id: editModeBlocker
|
|
anchors.fill: parent
|
|
enabled: root.editMode
|
|
acceptedButtons: Qt.AllButtons
|
|
onPressed: function (mouse) {
|
|
mouse.accepted = true;
|
|
}
|
|
onWheel: function (wheel) {
|
|
wheel.accepted = true;
|
|
}
|
|
z: 100
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: dragArea
|
|
anchors.fill: parent
|
|
enabled: editMode
|
|
cursorShape: editMode ? Qt.OpenHandCursor : Qt.PointingHandCursor
|
|
drag.target: editMode ? root : null
|
|
drag.axis: Drag.XAndYAxis
|
|
drag.smoothed: true
|
|
|
|
onPressed: function (mouse) {
|
|
if (editMode) {
|
|
cursorShape = Qt.ClosedHandCursor;
|
|
if (root.gridLayout && root.gridLayout.moveToTop) {
|
|
root.gridLayout.moveToTop(root);
|
|
}
|
|
}
|
|
}
|
|
|
|
onReleased: function (mouse) {
|
|
if (editMode) {
|
|
cursorShape = Qt.OpenHandCursor;
|
|
root.snapToGrid();
|
|
}
|
|
}
|
|
}
|
|
|
|
Drag.active: dragArea.drag.active
|
|
Drag.hotSpot.x: width / 2
|
|
Drag.hotSpot.y: height / 2
|
|
|
|
function swapIndices(i, j) {
|
|
if (i === j)
|
|
return;
|
|
const arr = SettingsData.controlCenterWidgets;
|
|
if (!arr || i < 0 || j < 0 || i >= arr.length || j >= arr.length)
|
|
return;
|
|
|
|
const copy = arr.slice();
|
|
const tmp = copy[i];
|
|
copy[i] = copy[j];
|
|
copy[j] = tmp;
|
|
|
|
SettingsData.set("controlCenterWidgets", copy);
|
|
}
|
|
|
|
function snapToGrid() {
|
|
if (!editMode || !gridLayout)
|
|
return;
|
|
const globalPos = root.mapToItem(gridLayout, 0, 0);
|
|
const cellWidth = gridLayout.width / gridColumns;
|
|
const cellHeight = gridCellHeight + Theme.spacingS;
|
|
|
|
const centerX = globalPos.x + (root.width / 2);
|
|
const centerY = globalPos.y + (root.height / 2);
|
|
|
|
let targetCol = Math.max(0, Math.floor(centerX / cellWidth));
|
|
let targetRow = Math.max(0, Math.floor(centerY / cellHeight));
|
|
|
|
targetCol = Math.min(targetCol, gridColumns - 1);
|
|
|
|
const newIndex = findBestInsertionIndex(targetRow, targetCol);
|
|
|
|
if (newIndex !== widgetIndex && newIndex >= 0 && newIndex < (SettingsData.controlCenterWidgets?.length || 0)) {
|
|
swapIndices(widgetIndex, newIndex);
|
|
}
|
|
}
|
|
|
|
function findBestInsertionIndex(targetRow, targetCol) {
|
|
const widgets = SettingsData.controlCenterWidgets || [];
|
|
const n = widgets.length;
|
|
if (!n || widgetIndex < 0 || widgetIndex >= n)
|
|
return -1;
|
|
|
|
function spanFor(width) {
|
|
const w = width ?? 50;
|
|
if (w <= 25)
|
|
return 1;
|
|
if (w <= 50)
|
|
return 2;
|
|
if (w <= 75)
|
|
return 3;
|
|
return 4;
|
|
}
|
|
|
|
const cols = gridColumns || 4;
|
|
|
|
let row = 0, col = 0;
|
|
let draggedOrigKey = null;
|
|
|
|
const pos = [];
|
|
|
|
for (let i = 0; i < n; i++) {
|
|
const span = Math.min(spanFor(widgets[i].width), cols);
|
|
|
|
if (col + span > cols) {
|
|
row++;
|
|
col = 0;
|
|
}
|
|
|
|
const startCol = col;
|
|
const centerKey = row * cols + (startCol + (span - 1) / 2);
|
|
|
|
if (i === widgetIndex) {
|
|
draggedOrigKey = centerKey;
|
|
} else {
|
|
pos.push({
|
|
index: i,
|
|
row,
|
|
startCol,
|
|
span,
|
|
centerKey
|
|
});
|
|
}
|
|
|
|
col += span;
|
|
if (col >= cols) {
|
|
row++;
|
|
col = 0;
|
|
}
|
|
}
|
|
|
|
if (pos.length === 0)
|
|
return -1;
|
|
|
|
const centerColCoord = targetCol + 0.5;
|
|
const targetKey = targetRow * cols + centerColCoord;
|
|
|
|
for (let k = 0; k < pos.length; k++) {
|
|
const p = pos[k];
|
|
if (p.row === targetRow && centerColCoord >= p.startCol && centerColCoord < (p.startCol + p.span)) {
|
|
return p.index;
|
|
}
|
|
}
|
|
|
|
let lo = 0, hi = pos.length - 1;
|
|
if (targetKey <= pos[0].centerKey)
|
|
return pos[0].index;
|
|
if (targetKey >= pos[hi].centerKey)
|
|
return pos[hi].index;
|
|
|
|
while (lo <= hi) {
|
|
const mid = (lo + hi) >> 1;
|
|
const mk = pos[mid].centerKey;
|
|
if (targetKey < mk)
|
|
hi = mid - 1;
|
|
else if (targetKey > mk)
|
|
lo = mid + 1;
|
|
else
|
|
return pos[mid].index;
|
|
}
|
|
const movingUp = (draggedOrigKey != null) ? (targetKey < draggedOrigKey) : false;
|
|
return (movingUp ? pos[lo].index : pos[hi].index);
|
|
}
|
|
|
|
Rectangle {
|
|
id: removeButton
|
|
width: 16
|
|
height: 16
|
|
radius: 8
|
|
color: Theme.error
|
|
anchors.top: parent.top
|
|
anchors.right: parent.right
|
|
anchors.margins: -4
|
|
visible: editMode
|
|
z: 10
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "close"
|
|
size: 12
|
|
color: Theme.primaryText
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: removeWidget(widgetIndex)
|
|
}
|
|
}
|
|
|
|
SizeControls {
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
anchors.margins: -6
|
|
visible: editMode
|
|
z: 10
|
|
currentSize: root.widgetData?.width || 50
|
|
isSlider: root.isSlider
|
|
widgetIndex: root.widgetIndex
|
|
onSizeChanged: newSize => {
|
|
var widgets = SettingsData.controlCenterWidgets.slice();
|
|
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
|
widgets[widgetIndex].width = newSize;
|
|
SettingsData.set("controlCenterWidgets", widgets);
|
|
}
|
|
}
|
|
}
|
|
|
|
readonly property bool hasConfigMenu: widgetData?.id === "diskUsage"
|
|
|
|
Rectangle {
|
|
id: configButton
|
|
width: 16
|
|
height: 16
|
|
radius: 8
|
|
color: Theme.primary
|
|
anchors.top: removeButton.top
|
|
anchors.right: removeButton.left
|
|
anchors.rightMargin: 4
|
|
visible: editMode && root.hasConfigMenu
|
|
z: 10
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "settings"
|
|
size: 12
|
|
color: Theme.primaryText
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.configRequested(root.widgetIndex, root.widgetData, configButton)
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: dragHandle
|
|
width: 16
|
|
height: 12
|
|
radius: 2
|
|
color: Theme.primary
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.margins: 4
|
|
visible: editMode
|
|
z: 15
|
|
opacity: dragArea.drag.active ? 1.0 : 0.7
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "drag_indicator"
|
|
size: 10
|
|
color: Theme.primaryText
|
|
}
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: 150
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: editMode ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
|
radius: Theme.cornerRadius
|
|
border.color: "transparent"
|
|
border.width: 0
|
|
z: -1
|
|
|
|
Behavior on color {
|
|
ColorAnimation {
|
|
duration: Theme.shortDuration
|
|
}
|
|
}
|
|
}
|
|
}
|