mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-16 16:24:00 -04:00
107 lines
3.6 KiB
QML
107 lines
3.6 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import qs.Common
|
|
import qs.Services
|
|
|
|
// Page-control style workspace strip: a dot per workspace, the focused one stretched into a pill.
|
|
Item {
|
|
id: root
|
|
|
|
required property var model
|
|
property bool vertical: false
|
|
property real dotSize: Theme.spacingS
|
|
property real activeLength: dotSize * 2.5
|
|
property real gap: Theme.spacingXS
|
|
property color activeColor: Theme.primary
|
|
property color occupiedColor: Theme.surfaceTextMedium
|
|
property color emptyColor: Theme.surfaceTextAlpha
|
|
property color urgentColor: Theme.error
|
|
property bool animated: !SettingsData.reduceMotion
|
|
|
|
implicitWidth: strip.implicitWidth
|
|
implicitHeight: strip.implicitHeight
|
|
|
|
function indexAt(x, y) {
|
|
let closest = -1;
|
|
let closestDist = Infinity;
|
|
for (let i = 0; i < dots.count; i++) {
|
|
const item = dots.itemAt(i);
|
|
if (!item || root.model.isPlaceholder(root.model.workspaceList[i]))
|
|
continue;
|
|
const center = item.mapToItem(root, item.width / 2, item.height / 2);
|
|
const dist = root.vertical ? Math.abs(y - center.y) : Math.abs(x - center.x);
|
|
if (dist < closestDist) {
|
|
closestDist = dist;
|
|
closest = i;
|
|
}
|
|
}
|
|
return closest;
|
|
}
|
|
|
|
function entryAt(x, y) {
|
|
const index = indexAt(x, y);
|
|
return index < 0 ? null : root.model.workspaceList[index];
|
|
}
|
|
|
|
Grid {
|
|
id: strip
|
|
|
|
anchors.centerIn: parent
|
|
columns: root.vertical ? 1 : Math.max(1, dots.count)
|
|
spacing: root.gap
|
|
horizontalItemAlignment: Grid.AlignHCenter
|
|
verticalItemAlignment: Grid.AlignVCenter
|
|
|
|
Repeater {
|
|
id: dots
|
|
|
|
model: ScriptModel {
|
|
values: root.model.workspaceList
|
|
}
|
|
|
|
Rectangle {
|
|
id: dot
|
|
|
|
required property var modelData
|
|
|
|
readonly property var record: root.model.recordOf(modelData)
|
|
readonly property bool placeholder: root.model.isPlaceholder(modelData)
|
|
readonly property bool active: root.model.isActive(modelData)
|
|
readonly property bool occupied: root.model.isOccupied(modelData)
|
|
readonly property bool urgent: !placeholder && root.model.useNativeWorkspaces && CompositorService.workspaceUrgent(record, CompositorService.loadWorkspaceUrgent(record))
|
|
readonly property real length: active ? root.activeLength : root.dotSize
|
|
|
|
width: root.vertical ? root.dotSize : length
|
|
height: root.vertical ? length : root.dotSize
|
|
radius: root.dotSize / 2
|
|
color: active ? root.activeColor : urgent ? root.urgentColor : occupied ? root.occupiedColor : root.emptyColor
|
|
|
|
Behavior on width {
|
|
enabled: root.animated && !root.vertical
|
|
NumberAnimation {
|
|
duration: Theme.mediumDuration
|
|
easing.type: Theme.standardEasing
|
|
}
|
|
}
|
|
|
|
Behavior on height {
|
|
enabled: root.animated && root.vertical
|
|
NumberAnimation {
|
|
duration: Theme.mediumDuration
|
|
easing.type: Theme.standardEasing
|
|
}
|
|
}
|
|
|
|
Behavior on color {
|
|
enabled: root.animated
|
|
ColorAnimation {
|
|
duration: Theme.shortDuration
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|