Created
December 31, 2025 01:01
-
-
Save JustLinuxUser/a87567a654db7d0593c652f67a2e2e7a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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