nosignal-shell/modules/bar/popouts/kblayout/KbLayout.qml
2026-04-18 01:04:04 +10:00

210 lines
5.3 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Caelestia.Config
import qs.components
import qs.services
ColumnLayout {
id: root
function refresh() {
kb.refresh();
}
spacing: Tokens.spacing.small
width: Tokens.sizes.bar.kbLayoutWidth
Component.onCompleted: kb.start()
KbLayoutModel {
id: kb
}
StyledText {
Layout.topMargin: Tokens.padding.normal
Layout.rightMargin: Tokens.padding.small
text: qsTr("Keyboard Layouts")
font.weight: 500
}
ListView {
id: list
model: kb.visibleModel
Layout.fillWidth: true
Layout.rightMargin: Tokens.padding.small
Layout.topMargin: Tokens.spacing.small
clip: true
interactive: true
implicitHeight: Math.min(contentHeight, 320)
visible: kb.visibleModel.count > 0
spacing: Tokens.spacing.small
add: Transition {
NumberAnimation {
properties: "opacity"
from: 0
to: 1
duration: 140
}
NumberAnimation {
properties: "y"
duration: 180
easing.type: Easing.OutCubic
}
}
remove: Transition {
NumberAnimation {
properties: "opacity"
to: 0
duration: 100
}
}
move: Transition {
NumberAnimation {
properties: "y"
duration: 180
easing.type: Easing.OutCubic
}
}
displaced: Transition {
NumberAnimation {
properties: "y"
duration: 180
easing.type: Easing.OutCubic
}
}
delegate: Item {
id: kbDelegate
required property int layoutIndex
required property string label
readonly property bool isDisabled: layoutIndex > 3
width: list.width
height: Math.max(36, rowText.implicitHeight + Tokens.padding.small * 2)
ToolTip.visible: isDisabled && layer.containsMouse
ToolTip.text: "XKB limitation: maximum 4 layouts allowed"
StateLayer {
id: layer
onClicked: {
if (!kbDelegate.isDisabled)
kb.switchTo(kbDelegate.layoutIndex);
}
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
implicitHeight: parent.height - 4
radius: Tokens.rounding.full
enabled: !kbDelegate.isDisabled
}
StyledText {
id: rowText
anchors.verticalCenter: layer.verticalCenter
anchors.left: layer.left
anchors.right: layer.right
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
text: kbDelegate.label
elide: Text.ElideRight
opacity: kbDelegate.isDisabled ? 0.4 : 1.0
}
}
}
Rectangle {
visible: kb.activeLabel.length > 0
Layout.fillWidth: true
Layout.rightMargin: Tokens.padding.small
Layout.topMargin: Tokens.spacing.small
implicitHeight: 1
color: Colours.palette.m3onSurfaceVariant
opacity: 0.35
}
RowLayout {
id: activeRow
visible: kb.activeLabel.length > 0
Layout.fillWidth: true
Layout.rightMargin: Tokens.padding.small
Layout.topMargin: Tokens.spacing.small
spacing: Tokens.spacing.small
opacity: 1
scale: 1
MaterialIcon {
text: "keyboard"
color: Colours.palette.m3primary
}
StyledText {
Layout.fillWidth: true
text: kb.activeLabel
elide: Text.ElideRight
font.weight: 500
color: Colours.palette.m3primary
}
Connections {
function onActiveLabelChanged() {
if (!activeRow.visible)
return;
popIn.restart();
}
target: kb
}
SequentialAnimation {
id: popIn
running: false
ParallelAnimation {
NumberAnimation {
target: activeRow
property: "opacity"
to: 0.0
duration: 70
}
NumberAnimation {
target: activeRow
property: "scale"
to: 0.92
duration: 70
}
}
ParallelAnimation {
NumberAnimation {
target: activeRow
property: "opacity"
to: 1.0
duration: 160
easing.type: Easing.OutCubic
}
NumberAnimation {
target: activeRow
property: "scale"
to: 1.0
duration: 220
easing.type: Easing.OutBack
}
}
}
}
}