shift-shell/containments/homescreens/folio/qml/private/WidgetResizeHandleFrame.qml
Devin Lin 674c5034ae animations: Use Kirigami units and speed up several of them
This converts many of the animation durations to Kirigami units so that
they can be controlled system wide. It also speeds up several of the
animation durations (ex. in folio) from 800ms to 400ms to improve the
feel and responsiveness of the shell.
2025-09-12 05:41:20 -04:00

239 lines
8 KiB
QML

// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import Qt5Compat.GraphicalEffects
import org.kde.kirigami as Kirigami
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
import '../delegate'
Item {
id: root
property Folio.HomeScreen folio
// given by parent:
property real widgetWidth
property real widgetHeight
property real widgetX
property real widgetY
property real widgetTopMargin
property real widgetBottomMargin
property real widgetLeftMargin
property real widgetRightMargin
property int widgetRow
property int widgetColumn
property int widgetGridWidth
property int widgetGridHeight
// filled here, given to parent:
// what the drag intends for the dimensions and position of the widget
property int widgetRowAfterDrag: 0
property int widgetColumnAfterDrag: 0
property int widgetGridWidthAfterDrag: 0
property int widgetGridHeightAfterDrag: 0
property var lockDrag: null
property alias handleContainer: handleContainer
signal widgetChangeAfterDrag(int widgetRow, int widgetColumn, int widgetGridWidth, int widgetGridHeight)
// solely used here:
property real startDragWidth: 0
property real startDragHeight: 0
property real startX: 0
property real startY: 0
property int startWidgetRow: 0
property int startWidgetColumn: 0
onWidgetWidthChanged: {
if (lockDrag === null) updateDimensions();
}
onWidgetHeightChanged: {
if (lockDrag === null) updateDimensions();
}
onWidgetXChanged: {
if (lockDrag === null) updateDimensions();
}
onWidgetYChanged: {
if (lockDrag === null) updateDimensions();
}
function updateDimensions() {
handleContainer.width = widgetWidth;
handleContainer.height = widgetHeight;
handleContainer.x = widgetX;
handleContainer.y = widgetY;
}
function startDrag() {
startDragWidth = handleContainer.width;
startDragHeight = handleContainer.height;
startX = handleContainer.x;
startY = handleContainer.y;
startWidgetRow = root.widgetRow;
startWidgetColumn = root.widgetColumn;
root.widgetChangeAfterDrag(startWidgetRow, startWidgetColumn, root.widgetGridWidth, root.widgetGridHeight);
}
function snapEdges() {
lockDrag = null;
// snaps the bounds to what we ended up at
widthAnim.to = widgetWidth;
widthAnim.restart();
heightAnim.to = widgetHeight;
heightAnim.restart();
xAnim.to = widgetX;
xAnim.restart();
yAnim.to = widgetY;
yAnim.restart();
}
function pressedHandler(orientation) {
if (root.lockDrag !== orientation) {
root.startDrag();
root.lockDrag = orientation;
}
}
function dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) {
if (root.lockDrag === orientation) {
// update the handle container dimensions and position
handleContainer.x = root.startX - leftEdgeDelta;
handleContainer.y = root.startY - topEdgeDelta;
handleContainer.width = root.startDragWidth + rightEdgeDelta + leftEdgeDelta;
handleContainer.height = root.startDragHeight + bottomEdgeDelta + topEdgeDelta;
// update the widget dimensions and position
const columnsMovedRight = Math.round((handleContainer.x - root.startX) / folio.HomeScreenState.pageCellWidth);
const rowsMovedDown = Math.round((handleContainer.y - root.startY) / folio.HomeScreenState.pageCellHeight);
const realWidgetWidth = handleContainer.width + widgetLeftMargin + widgetRightMargin;
const realWidgetHeight = handleContainer.height + widgetTopMargin + widgetBottomMargin;
const widgetRowAfterDrag = startWidgetRow + rowsMovedDown;
const widgetColumnAfterDrag = startWidgetColumn + columnsMovedRight;
const widgetGridWidthAfterDrag = Math.round(realWidgetWidth / folio.HomeScreenState.pageCellWidth);
const widgetGridHeightAfterDrag = Math.round(realWidgetHeight / folio.HomeScreenState.pageCellHeight);
root.widgetChangeAfterDrag(widgetRowAfterDrag, widgetColumnAfterDrag, widgetGridWidthAfterDrag, widgetGridHeightAfterDrag);
}
}
function releaseHandler(orientation) {
if (root.lockDrag === orientation) {
root.snapEdges();
}
}
Item {
id: handleContainer
NumberAnimation on width {
id: widthAnim
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
NumberAnimation on height {
id: heightAnim
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
NumberAnimation on x {
id: xAnim
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
NumberAnimation on y {
id: yAnim
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
Rectangle {
id: resizeOutline
color: 'transparent'
border.color: 'white'
radius: Kirigami.Units.cornerRadius
border.width: 1
anchors.fill: handleContainer
anchors.leftMargin: -root.widgetLeftMargin
anchors.rightMargin: -root.widgetRightMargin
anchors.topMargin: -root.widgetTopMargin
anchors.bottomMargin: -root.widgetBottomMargin
}
WidgetResizeHandle {
id: topHandle
orientation: WidgetHandlePosition.TopCenter
x: resizeOutline.x + Math.round(resizeOutline.width / 2) - Math.round(width / 2)
y: resizeOutline.y - Math.round(height / 2)
width: Math.round(Math.max(height, resizeOutline.width * 0.3)) + touchPadding * 2
onPressed: pressedHandler(orientation)
onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
onReleased: releaseHandler(orientation)
}
WidgetResizeHandle {
id: leftHandle
orientation: WidgetHandlePosition.LeftCenter
x: resizeOutline.x - (width / 2)
y: resizeOutline.y + (resizeOutline.height / 2) - (height / 2)
height: Math.round(Math.max(width, resizeOutline.height * 0.3)) + touchPadding * 2
onPressed: pressedHandler(orientation)
onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
onReleased: releaseHandler(orientation)
}
WidgetResizeHandle {
id: rightHandle
orientation: WidgetHandlePosition.RightCenter
x: resizeOutline.x + resizeOutline.width - (width / 2)
y: resizeOutline.y + (resizeOutline.height / 2) - (height / 2)
height: Math.round(Math.max(width, resizeOutline.height * 0.3)) + touchPadding * 2
onPressed: pressedHandler(orientation)
onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
onReleased: releaseHandler(orientation)
}
WidgetResizeHandle {
id: bottomHandle
orientation: WidgetHandlePosition.BottomCenter
x: resizeOutline.x + (resizeOutline.width / 2) - (width / 2)
y: resizeOutline.y + resizeOutline.height - (height / 2)
width: Math.round(Math.max(height, resizeOutline.width * 0.3)) + touchPadding * 2
onPressed: pressedHandler(orientation)
onDragEvent: (leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta) => dragHandler(orientation, leftEdgeDelta, rightEdgeDelta, topEdgeDelta, bottomEdgeDelta)
onReleased: releaseHandler(orientation)
}
}