Last active
December 31, 2025 05:04
-
-
Save JustLinuxUser/70b3b2d7ef36be0d91ce0224531b1c16 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 | |
| // 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