shift-shell/components/mobileshell/qml/popups/actionbuttons/ActionButton.qml
Marco Allegretti a3173160e2 Render shell-owned icons with theme masks
Use masked Kirigami icons with explicit theme colors for shell controls so the Shift icon theme renders reliably across light and dark surfaces. Replace the status-bar battery helper with theme icon names so battery glyphs also come from org.shift.icons.

Give the app-thumbnail close affordance a symbolic white X on a dark circular backing so it remains visible over previews.
2026-05-17 08:57:06 +02:00

163 lines
4.8 KiB
QML

/*
* SPDX-FileCopyrightText: 2025 Micah Stanley <stanleymicah@proton.me>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls as Controls
import QtQuick.Layouts
import QtQuick.Effects
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.layershell 1.0 as LayerShell
Window {
id: root
readonly property int size: Kirigami.Units.gridUnit * 2
readonly property int margins: Math.round(Kirigami.Units.largeSpace * 0.5)
property int screenCorner: ActionButton.ScreenCorner.BottomRight
property int angle: 0
property string iconSource
property bool active: false
signal triggered()
enum ScreenCorner {
BottomRight,
BottomLeft,
TopLeft,
TopRight
}
// When the button is animating its disappearance, make sure it is transparent to inputs.
onActiveChanged: {
ShellUtil.setInputTransparent(root, !active)
if (active) {
root.visible = true;
root.raise();
hideButton.stop();
return;
}
hideButton.restart();
}
LayerShell.Window.scope: "overlay"
LayerShell.Window.margins.top: margins
LayerShell.Window.margins.bottom: margins
LayerShell.Window.margins.left: margins
LayerShell.Window.margins.right: margins
LayerShell.Window.layer: LayerShell.Window.LayerOverlay
LayerShell.Window.exclusionZone: -1
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
LayerShell.Window.anchors: {
if (screenCorner === ActionButton.ScreenCorner.TopLeft) {
return LayerShell.Window.AnchorTop | LayerShell.Window.AnchorLeft
} else if (screenCorner === ActionButton.ScreenCorner.BottomRight) {
return LayerShell.Window.AnchorBottom | LayerShell.Window.AnchorRight
} else if (screenCorner === ActionButton.ScreenCorner.BottomLeft) {
return LayerShell.Window.AnchorBottom | LayerShell.Window.AnchorLeft
} else {
return LayerShell.Window.AnchorTop | LayerShell.Window.AnchorRight
}
}
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
// Double the set button size to leave room for button scale animation.
width: size * 2
height: size * 2
visible: active
color: "transparent"
// Hide the root window after the button disappearing animation finishes.
Timer {
id: hideButton
interval: Kirigami.Units.longDuration
repeat: false
onTriggered: if (!active) root.visible = false;
}
Component.onCompleted: {
// Because the window surface area had to be made larger to accommodate the button scale animation,
// set the input region to the size of the actual button.
ShellUtil.setInputRegion(root, Qt.rect((root.width - size) / 2, (root.height - size) / 2, size, size));
ShellUtil.setInputTransparent(root, !active);
}
Controls.Control {
id: content
anchors.centerIn: parent
width: root.size
height: root.size
opacity: root.active ? 1 : 0
property double scale: !root.active ? 0.5 : (button.pressed ? 1.5 : 1)
Behavior on scale {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.OutBack
}
}
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.OutCirc
}
}
transform: Scale {
origin.x: root.size / 2
origin.y: root.size / 2
xScale: content.scale
yScale: content.scale
}
MobileShell.PanelBackground {
anchors.fill: parent
panelType: MobileShell.PanelBackground.PanelType.Popup
radius: root.size
}
Controls.AbstractButton {
id: button
anchors.fill: parent
MobileShell.HapticsEffect {
id: haptics
}
contentItem: Item {
Kirigami.Icon {
anchors.centerIn: parent
width: Kirigami.Units.iconSizes.small
height: Kirigami.Units.iconSizes.small
transformOrigin: Item.Center
rotation: root.angle
source: root.iconSource
isMask: true
color: Kirigami.Theme.textColor
}
}
onPressed: {
haptics.buttonVibrate();
}
onReleased: {
if (active) root.triggered();
}
}
}
}