Skip to content

Instantly share code, notes, and snippets.

@JustLinuxUser
Created December 31, 2025 01:01
Show Gist options
  • Select an option

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

Select an option

Save JustLinuxUser/a87567a654db7d0593c652f67a2e2e7a to your computer and use it in GitHub Desktop.
import QtQuick
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
Item {
id: scrollText
property string text
property color textColor
property real fontSize
property real maxWidth
property string scrollMode
property bool needsScroll: false
clip: true
implicitHeight: titleText.height
property bool isScrolling: false
property bool isResetting: false
// Hidden text for measurements
NText {
id: titleMetrics
visible: false
text: scrollText.text
applyUiScale: false
pointSize: scrollText.fontSize
font.weight: Style.fontWeightMedium
onContentWidthChanged: () => {
scrollText.needsScroll = titleMetrics.contentWidth > scrollText.maxWidth;
scrollText.implicitWidth = Math.min(scrollText.maxWidth, this.contentWidth);
scrollText.updateState();
}
}
Timer {
id: scrollTimer
interval: 1000
onTriggered: {
if (scrollText.scrollMode === "always" && scrollText.needsScroll) {
scrollText.isScrolling = true;
scrollText.isResetting = false;
}
}
}
MouseArea {
id: hoverArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
cursorShape: Qt.ArrowCursor
}
function updateState() {
if (scrollMode === "never") {
isScrolling = false;
isResetting = false;
} else if (scrollMode === "always") {
if (needsScroll) {
if (hoverArea.containsMouse) {
isScrolling = false;
isResetting = true;
} else {
scrollTimer.restart();
}
}
} else if (scrollMode === "hover") {
isScrolling = hoverArea.containsMouse && needsScroll;
isResetting = !hoverArea.containsMouse && needsScroll;
}
}
onWidthChanged: updateState()
Component.onCompleted: updateState()
Connections {
target: hoverArea
function onContainsMouseChanged() {
scrollText.updateState();
}
}
Item {
id: scrollContainer
height: parent.height
property real scrollX: 0
x: scrollX
RowLayout {
spacing: 50
NText {
id: titleText
text: scrollText.text
color: scrollText.textColor
pointSize: scrollText.fontSize
applyUiScale: false
font.weight: Style.fontWeightMedium
onTextChanged: {
scrollText.isScrolling = false;
scrollText.isResetting = false;
scrollContainer.scrollX = 0;
if (scrollText.needsScroll)
scrollTimer.restart();
}
}
NText {
text: scrollText.text
color: scrollText.textColor
pointSize: scrollText.fontSize
applyUiScale: false
font.weight: Style.fontWeightMedium
visible: scrollText.needsScroll && scrollText.isScrolling
}
}
NumberAnimation on scrollX {
running: scrollText.isResetting
to: 0
duration: 300
easing.type: Easing.OutQuad
onFinished: scrollText.isResetting = false
}
NumberAnimation on scrollX {
running: scrollText.isScrolling && !scrollText.isResetting
from: 0
to: -(titleMetrics.contentWidth + 50)
duration: Math.max(4000, scrollText.text.length * 120)
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