mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-14 23:34:01 -04:00
147 lines
5.8 KiB
QML
147 lines
5.8 KiB
QML
import QtQuick
|
||
import qs.Common
|
||
import qs.Widgets
|
||
import qs.Modules.ControlCenter
|
||
import "../utils/widgets.js" as WidgetUtils
|
||
import "../../../Common/GridLayout.js" as GridUtils
|
||
|
||
DEditableGridSlot {
|
||
id: root
|
||
|
||
readonly property var widgetData: JSON.parse(json)
|
||
readonly property var sizeSpec: WidgetUtils.sizeSpec(widgetData, grid.columns, grid.maximumRows)
|
||
readonly property real cols: slot?.cols ?? 1
|
||
readonly property real rows: slot?.rows ?? 1
|
||
readonly property bool compact: cols <= 2 && rows === 1
|
||
readonly property bool small: WidgetUtils.isSmall(grid.layoutItems[index] ?? widgetData, rows)
|
||
readonly property var tileItem: tileLoader.item
|
||
// Edit chrome hugs a small tile's pill, not its slot.
|
||
readonly property real bodyInset: tileItem?.bodyInset ?? 0
|
||
// Small tiles resize from a virtual half row so growing them passes through full size first.
|
||
property real biasH: 0
|
||
readonly property real smallSpanLimit: (1 + CcMetrics.smallRowFraction) / 2
|
||
|
||
readonly property bool swallowed: dragging && grid.swallowPoint !== null
|
||
property real swallowProgress: swallowed ? 1 : 0
|
||
// Outlives the grid's point so the release animation can still use it.
|
||
property var swallowAnchor: null
|
||
|
||
onSwallowedChanged: {
|
||
if (swallowed)
|
||
swallowAnchor = grid.swallowPoint;
|
||
}
|
||
|
||
Behavior on swallowProgress {
|
||
enabled: CcMetrics.animationsEnabled
|
||
NumberAnimation {
|
||
duration: Theme.expressiveDurations.expressiveFastSpatial
|
||
easing.type: Easing.BezierSpline
|
||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||
}
|
||
}
|
||
|
||
transform: [
|
||
Scale {
|
||
origin.x: root.width / 2
|
||
origin.y: root.height / 2
|
||
xScale: 1 - root.swallowProgress * (1 - CcMetrics.trashSwallowScale)
|
||
yScale: xScale
|
||
},
|
||
// Gated so resting tiles don't track every layout animation.
|
||
Translate {
|
||
x: root.swallowProgress > 0 ? root.swallowProgress * ((root.swallowAnchor?.x ?? 0) - root.x - root.width / 2) : 0
|
||
y: root.swallowProgress > 0 ? root.swallowProgress * ((root.swallowAnchor?.y ?? 0) - root.y - root.height / 2) : 0
|
||
}
|
||
]
|
||
|
||
passthrough: tileItem?.passthrough ?? null
|
||
restCursor: widgetData.id === WidgetUtils.EDIT_ID ? Qt.PointingHandCursor : Qt.OpenHandCursor
|
||
raised: dragging || resizing || (tileItem?.memberDragging ?? false)
|
||
|
||
function reanchor(small) {
|
||
const shift = ((small ? CcMetrics.smallRowFraction : 1) - smallSpanLimit) * grid.cellWidth;
|
||
biasH += shift;
|
||
}
|
||
|
||
function spanOf(requested, bias = 0) {
|
||
return (requested + bias + CcMetrics.gridGap) / grid.cellWidth;
|
||
}
|
||
|
||
onClicked: {
|
||
if (widgetData.id === WidgetUtils.EDIT_ID)
|
||
root.grid.editRequested();
|
||
}
|
||
|
||
onPressAndHold: {
|
||
if (!editChrome.hasOptions)
|
||
return;
|
||
root.grid.configRequested(root.grid.savedIndex(root.index), root.widgetData, editChrome);
|
||
}
|
||
|
||
onResizeRequested: (requestedWidth, requestedHeight) => {
|
||
const step = sizeSpec.step;
|
||
const canShrink = WidgetUtils.canShrink(widgetData.id);
|
||
if (canShrink && root.small !== (spanOf(requestedHeight, biasH) < smallSpanLimit))
|
||
reanchor(!root.small);
|
||
const spanW = spanOf(requestedWidth);
|
||
const spanH = spanOf(requestedHeight, biasH);
|
||
let width = GridUtils.dimension(Math.round(spanW / step) * step, sizeSpec.minW, sizeSpec.maxW, sizeSpec.w, step);
|
||
let height = GridUtils.dimension(Math.round(spanH / step) * step, sizeSpec.minH, sizeSpec.maxH, sizeSpec.h, step);
|
||
const current = WidgetUtils.clampSize(widgetData, grid.columns, grid.maximumRows);
|
||
if (WidgetUtils.isSliderWidget(widgetData.id) && width < 2 && height < 2) {
|
||
if (width !== current.w && sizeSpec.maxH > 1)
|
||
height = 2;
|
||
else
|
||
width = Math.min(2, sizeSpec.maxW);
|
||
}
|
||
const changes = {};
|
||
if (width !== current.w)
|
||
changes.w = width;
|
||
if (height !== current.h)
|
||
changes.h = height;
|
||
const small = canShrink && height === 1 && spanH < smallSpanLimit;
|
||
if (small !== (widgetData.small === true))
|
||
changes.small = small;
|
||
grid.previewSize(index, changes);
|
||
}
|
||
|
||
CcTileLoader {
|
||
id: tileLoader
|
||
anchors.fill: parent
|
||
grid: root.grid
|
||
widgetData: root.widgetData
|
||
savedIndex: root.grid.savedIndex(root.index)
|
||
columns: root.cols
|
||
rows: root.rows
|
||
compact: root.compact
|
||
small: root.small
|
||
}
|
||
|
||
CcEditChrome {
|
||
id: editChrome
|
||
|
||
anchors.fill: parent
|
||
anchors.margins: -contentInset
|
||
anchors.topMargin: -contentInset + root.bodyInset
|
||
anchors.bottomMargin: -contentInset + root.bodyInset
|
||
z: 2
|
||
visible: root.grid.editMode
|
||
enabled: root.interactionEnabled
|
||
widgetData: root.widgetData
|
||
passthrough: root.passthrough
|
||
dragging: root.dragging
|
||
resizing: root.resizing
|
||
cornerRadius: root.small ? Theme.fullRadius(root.width, root.height - root.bodyInset * 2) : (root.tileItem?.bodyRadius ?? Theme.fullRadius(root.width, root.height))
|
||
sizeText: root.cols + "×" + (root.small ? CcMetrics.smallRowFraction : root.rows)
|
||
onResizeStarted: (px, py) => {
|
||
root.biasH = root.small ? CcMetrics.smallRowFraction * root.grid.cellWidth - CcMetrics.gridGap - root.height : 0;
|
||
root.beginResize(px, py);
|
||
}
|
||
onResizeMoved: (px, py) => root.resizeTo(px, py)
|
||
onResizeEnded: root.finishResize()
|
||
onResizeCanceled: root.cancelResize()
|
||
onRemoveRequested: root.grid.removeWidget(root.grid.savedIndex(root.index))
|
||
onConfigRequested: anchor => root.grid.configRequested(root.grid.savedIndex(root.index), root.widgetData, anchor)
|
||
}
|
||
}
|