summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml285
1 files changed, 285 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml
new file mode 100644
index 0000000..05a21d1
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml
@@ -0,0 +1,285 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Column {
+ id: root
+
+ property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null
+ property bool contentLoaded: false
+ property int draggedIndex: -1
+ property int dropTargetIndex: -1
+ property bool suppressShiftAnimation: false
+ readonly property real tabItemSize: 128 + Theme.spacingXS
+
+ signal tabSwitched(int tabIndex)
+ signal tabClosed(int tabIndex)
+ signal newTabRequested
+
+ function hasUnsavedChangesForTab(tab) {
+ if (!tab)
+ return false;
+
+ if (tab.id === currentTab?.id) {
+ return root.parent?.hasUnsavedChanges ? root.parent.hasUnsavedChanges() : false;
+ }
+ return false;
+ }
+
+ spacing: Theme.spacingXS
+
+ Row {
+ width: parent.width
+ height: 36
+ spacing: Theme.spacingXS
+
+ ScrollView {
+ width: parent.width - newTabButton.width - Theme.spacingXS
+ height: parent.height
+ clip: true
+
+ ScrollBar.horizontal.visible: false
+ ScrollBar.vertical.visible: false
+
+ Row {
+ spacing: Theme.spacingXS
+
+ Repeater {
+ model: NotepadStorageService.tabs
+
+ delegate: Item {
+ id: delegateItem
+ required property int index
+ required property var modelData
+
+ readonly property bool isActive: NotepadStorageService.currentTabIndex === index
+ readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse
+ readonly property real tabWidth: 128
+ property bool longPressing: false
+ property bool dragging: false
+ property point dragStartPos: Qt.point(0, 0)
+ property int targetIndex: -1
+ property int originalIndex: -1
+ property real dragAxisOffset: 0
+
+ Timer {
+ id: longPressTimer
+ interval: 200
+ repeat: false
+ onTriggered: {
+ if (NotepadStorageService.tabs.length > 1) {
+ delegateItem.longPressing = true
+ }
+ }
+ }
+
+ readonly property real shiftOffset: {
+ if (root.draggedIndex < 0)
+ return 0
+ if (index === root.draggedIndex)
+ return 0
+ var dragIdx = root.draggedIndex
+ var dropIdx = root.dropTargetIndex
+ var myIdx = index
+ var shiftAmount = root.tabItemSize
+ if (dropIdx < 0)
+ return 0
+ if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx)
+ return -shiftAmount
+ if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx)
+ return shiftAmount
+ return 0
+ }
+
+ width: tabWidth
+ height: 32
+ z: dragging ? 100 : 0
+
+ transform: Translate {
+ x: shiftOffset
+ Behavior on x {
+ enabled: !root.suppressShiftAnimation
+ NumberAnimation {
+ duration: 150
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+
+ Item {
+ id: tabVisual
+ anchors.fill: parent
+ z: 1
+ layer.enabled: dragging
+ layer.smooth: true
+
+ transform: Translate {
+ x: dragging ? dragAxisOffset : 0
+ }
+
+ Rectangle {
+ id: tabRect
+ anchors.fill: parent
+ radius: Theme.cornerRadius
+ color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0)
+ border.width: isActive || dragging ? 0 : 1
+ border.color: dragging ? Theme.primary : Theme.outlineMedium
+ clip: true
+
+ Row {
+ id: tabContent
+ anchors.fill: parent
+ anchors.leftMargin: Theme.spacingM
+ anchors.rightMargin: Theme.spacingM
+ spacing: Theme.spacingXS
+
+ StyledText {
+ id: tabText
+ width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0)
+ text: {
+ var prefix = ""
+ if (hasUnsavedChangesForTab(modelData)) {
+ prefix = "● "
+ }
+ return prefix + (modelData.title || "Untitled")
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: isActive ? Theme.primary : Theme.surfaceText
+ font.weight: isActive ? Font.Medium : Font.Normal
+ elide: Text.ElideMiddle
+ maximumLineCount: 1
+ wrapMode: Text.NoWrap
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Rectangle {
+ id: tabCloseButton
+ width: 20
+ height: 20
+ radius: Theme.cornerRadius
+ color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
+ visible: NotepadStorageService.tabs.length > 1
+ anchors.verticalCenter: parent.verticalCenter
+
+ DankIcon {
+ name: "close"
+ size: 14
+ color: Theme.surfaceTextMedium
+ anchors.centerIn: parent
+ }
+
+ MouseArea {
+ id: closeMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ z: 100
+
+ onClicked: root.tabClosed(index)
+ }
+ }
+ }
+
+ Behavior on color {
+ ColorAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ id: tabMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ preventStealing: dragging || longPressing
+ cursorShape: dragging || longPressing ? Qt.ClosedHandCursor : Qt.PointingHandCursor
+ acceptedButtons: Qt.LeftButton
+
+ onPressed: mouse => {
+ if (mouse.button === Qt.LeftButton && NotepadStorageService.tabs.length > 1) {
+ delegateItem.dragStartPos = Qt.point(mouse.x, mouse.y)
+ longPressTimer.start()
+ }
+ }
+
+ onReleased: mouse => {
+ longPressTimer.stop()
+ var wasDragging = delegateItem.dragging
+ var didReorder = wasDragging && delegateItem.targetIndex >= 0 && delegateItem.targetIndex !== delegateItem.originalIndex
+
+ if (didReorder) {
+ root.suppressShiftAnimation = true
+ NotepadStorageService.reorderTab(delegateItem.originalIndex, delegateItem.targetIndex)
+ }
+
+ delegateItem.longPressing = false
+ delegateItem.dragging = false
+ delegateItem.dragAxisOffset = 0
+ delegateItem.targetIndex = -1
+ delegateItem.originalIndex = -1
+ root.draggedIndex = -1
+ root.dropTargetIndex = -1
+ if (didReorder) {
+ Qt.callLater(() => {
+ root.suppressShiftAnimation = false
+ })
+ }
+
+ if (wasDragging || mouse.button !== Qt.LeftButton)
+ return
+ root.tabSwitched(index)
+ }
+
+ onPositionChanged: mouse => {
+ if (delegateItem.longPressing && !delegateItem.dragging) {
+ var distance = Math.sqrt(Math.pow(mouse.x - delegateItem.dragStartPos.x, 2) + Math.pow(mouse.y - delegateItem.dragStartPos.y, 2))
+ if (distance > 5) {
+ delegateItem.dragging = true
+ delegateItem.targetIndex = index
+ delegateItem.originalIndex = index
+ root.draggedIndex = index
+ root.dropTargetIndex = index
+ }
+ }
+
+ if (!delegateItem.dragging)
+ return
+
+ var axisOffset = mouse.x - delegateItem.dragStartPos.x
+ delegateItem.dragAxisOffset = axisOffset
+
+ var itemSize = root.tabItemSize
+ var rawSlot = axisOffset / itemSize
+ var slotOffset = rawSlot >= 0
+ ? Math.floor(rawSlot + 0.4)
+ : Math.ceil(rawSlot - 0.4)
+ var tabCount = NotepadStorageService.tabs.length
+ var newTargetIndex = Math.max(0, Math.min(tabCount - 1, delegateItem.originalIndex + slotOffset))
+
+ if (newTargetIndex !== delegateItem.targetIndex) {
+ delegateItem.targetIndex = newTargetIndex
+ root.dropTargetIndex = newTargetIndex
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DankActionButton {
+ id: newTabButton
+ width: 32
+ height: 32
+ iconName: "add"
+ iconSize: Theme.iconSize - 4
+ iconColor: Theme.surfaceText
+ onClicked: root.newTabRequested()
+ }
+ }
+}