Skip to content

Instantly share code, notes, and snippets.

@JustLinuxUser
Last active December 31, 2025 05:04
Show Gist options
  • Select an option

  • Save JustLinuxUser/70b3b2d7ef36be0d91ce0224531b1c16 to your computer and use it in GitHub Desktop.

Select an option

Save JustLinuxUser/70b3b2d7ef36be0d91ce0224531b1c16 to your computer and use it in GitHub Desktop.
import QtQuick
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
// TODO: ScrollMode enum
Item {
id: root
// normal NText properties
// we can add as many as nessesary
required property string text
property color color: Color.mOnSurface
property real pointSize: Style.fontSizeS
property bool applyUiScale: false
property real fontWeight: Style.fontWeightMedium
// special properties
property real maxWidth: Infinity
property string scrollMode: "never"
// animation controls
// TODO: Take into account the animation speed
property real waitBeforeScrolling: 1000
property real scrollCycleDuration: Math.max(4000, root.text.length * 120)
property real resettingDuration: 300
property real scrollerSpacing: 50
clip: true
implicitHeight: titleText.height
enum ScrollState {
None = 0,
Scrolling = 1,
Resetting = 2
}
property int state: ScrollText.ScrollState.None
Timer {
id: scrollTimer
interval: root.waitBeforeScrolling
onTriggered: {
root.state = ScrollText.ScrollState.Scrolling;
root.updateState();
}
}
MouseArea {
id: hoverArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onEntered: root.updateState()
onExited: root.updateState()
}
function ensureReset() {
if (state === ScrollText.ScrollState.Scrolling)
state = ScrollText.ScrollState.Resetting;
}
function updateState() {
if (titleText.contentWidth <= root.maxWidth || scrollMode === "never") {
state = ScrollText.ScrollState.None;
return;
}
if (scrollMode === "always") {
if (hoverArea.containsMouse) {
ensureReset();
} else {
scrollTimer.restart();
}
} else if (scrollMode === "hover") {
if (hoverArea.containsMouse)
state = ScrollText.ScrollState.Scrolling;
else
ensureReset();
}
}
RowLayout {
id: scrollContainer
height: parent.height
x: 0
spacing: root.scrollerSpacing
NText {
id: titleText
text: root.text
color: root.color
pointSize: root.pointSize
applyUiScale: root.applyUiScale
font.weight: root.fontWeight
onTextChanged: {
// reset state
root.implicitWidth = Math.min(root.maxWidth, this.contentWidth);
root.state = ScrollText.ScrollState.None;
scrollContainer.x = 0;
scrollTimer.restart();
}
}
NText {
text: root.text
color: root.color
pointSize: root.pointSize
applyUiScale: root.applyUiScale
font.weight: root.fontWeight
visible: root.state === ScrollText.ScrollState.Scrolling
}
NumberAnimation on x {
running: root.state === ScrollText.ScrollState.Resetting
to: 0
duration: root.resettingDuration
easing.type: Easing.OutQuad
onFinished: {
root.state = ScrollText.ScrollState.None;
root.updateState();
}
}
NumberAnimation on x {
running: root.state === ScrollText.ScrollState.Scrolling
from: 0
to: -(titleText.contentWidth + scrollContainer.spacing)
duration: root.scrollCycleDuration
loops: Animation.Infinite
easing.type: Easing.Linear
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment