shift-shell/components/mobileshell/qml/components/MarqueeLabel.qml
Devin Lin a8b858dc3e Remove kirigami version in imports
This fixes potential issues stemming from pinning versions on Kirigami
qml api imports
2026-03-06 22:08:07 -05:00

119 lines
4.1 KiB
QML

// SPDX-FileCopyrightText: 2022 Yari Polla <skilvingr@gmail.com>
// SPDX-FileCopyrightText: 2025 Micah Stanley <stanleymicah@proton.me>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick 2.15
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Effects
import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PlasmaComponents
import Qt5Compat.GraphicalEffects
/**
* This is a simple marquee (flowing) label based on PlasmaComponents Label.
*/
OpacityMask {
id: root
height: row.height
// label values
required property string inputText
property font font
property var textFormat: Text.RichText
// properties for the marquee label scroll speed and wait duration
readonly property real scrollSpeed: 0.025
readonly property int waitDuration: 2000
readonly property string filteredText: inputText.replace(/\n/g, ' ') // remove new line characters
readonly property bool charactersOverflowing: txtMeter.advanceWidth > root.width // true when text is overflowing
// update animation values and text positions whenever the label overflows or changes
onFilteredTextChanged: if (root.charactersOverflowing) { textAnimationLoop.restart() }
onCharactersOverflowingChanged: if (charactersOverflowing) { row.scrollPosition = 0 }
Item {
id: rowContaner
anchors.fill: parent
height: row.height
opacity: 0 // we display with the opacity gradient below
// use two identical labels for scrolling so we can give the illusion of infinite scrolling
RowLayout {
id: row
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
property real scrollPosition: 0
transform: [
Translate {
x: row.scrollPosition
}
]
spacing: 32
PlasmaComponents.Label {
id: label
font: root.font
textFormat: root.textFormat
text: filteredText
Layout.alignment: Qt.AlignLeft
TextMetrics {
id: txtMeter
font: root.font
text: filteredText
}
}
PlasmaComponents.Label {
// hide this label when the text is not overflowing so the user never sees both labels
visible: textAnimationLoop.running
font: root.font
textFormat: root.textFormat
text: filteredText
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
}
}
}
// setting the gradient mask source
source: rowContaner
// if the label is overflowing, this animation in a loop smoothly scrolling thought the text
SequentialAnimation {
id: textAnimationLoop
running: root.charactersOverflowing && root.visible
onRunningChanged: row.scrollPosition = 0
loops: Animation.Infinite
PauseAnimation { duration: root.waitDuration }
NumberAnimation { target: row; property: "scrollPosition"; from: 0; to: -txtMeter.advanceWidth - row.spacing; duration: (txtMeter.advanceWidth + row.spacing) / root.scrollSpeed }
}
// gradient mask to smoothly fade the ends of the label when it is scrolling
maskSource: Rectangle {
id: mask
width: root.width
height: root.height
property real gradientPct: (Kirigami.Units.gridUnit * 0.35) / root.width
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0; color: row.scrollPosition == 0 || row.scrollPosition < -txtMeter.advanceWidth ? 'white' : 'transparent' } // remove the beginning of the gradient when at the start of the label so the front text is fully visible
GradientStop { position: 0 + mask.gradientPct; color: 'white' }
GradientStop { position: 1.0 - mask.gradientPct; color: 'white' }
GradientStop { position: 1.0; color: 'transparent' }
}
}
}