summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml
blob: 0209e5f17cdf8330f23b37e8fddf1e7030e77093 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets

Rectangle {
    id: root

    required property string outputName
    required property var outputData
    required property real canvasScaleFactor
    required property point canvasOffset

    property bool isConnected: outputData?.connected ?? false
    property bool isDragging: false
    property point originalLogical: Qt.point(0, 0)
    property point snappedLogical: Qt.point(0, 0)
    property bool isValidPosition: true

    property var physSize: DisplayConfigState.getPhysicalSize(outputData)
    property var logicalSize: DisplayConfigState.getLogicalSize(outputData)

    x: isDragging ? x : (outputData?.logical?.x ?? 0) * canvasScaleFactor + canvasOffset.x
    y: isDragging ? y : (outputData?.logical?.y ?? 0) * canvasScaleFactor + canvasOffset.y
    width: logicalSize.w * canvasScaleFactor
    height: logicalSize.h * canvasScaleFactor
    radius: Theme.cornerRadius
    opacity: isConnected ? 1.0 : 0.5

    color: {
        if (!isConnected)
            return Theme.surfaceContainerHighest;
        if (!isValidPosition)
            return Theme.withAlpha(Theme.error, 0.3);
        if (isDragging)
            return Theme.withAlpha(Theme.primary, 0.4);
        if (dragArea.containsMouse)
            return Theme.withAlpha(Theme.primary, 0.2);
        return Theme.surfaceContainerHigh;
    }

    border.color: {
        if (!isConnected)
            return Theme.outline;
        if (!isValidPosition)
            return Theme.error;
        if (isDragging)
            return Theme.primary;
        if (CompositorService.getFocusedScreen()?.name === outputName)
            return Theme.primary;
        return Theme.outline;
    }
    border.width: isDragging ? 3 : 2
    z: isDragging ? 100 : (isConnected ? 1 : 0)

    Rectangle {
        id: snapPreview
        visible: root.isDragging && root.isValidPosition && SettingsData.displaySnapToEdge
        x: root.snappedLogical.x * root.canvasScaleFactor + root.canvasOffset.x - root.x
        y: root.snappedLogical.y * root.canvasScaleFactor + root.canvasOffset.y - root.y
        width: parent.width
        height: parent.height
        radius: Theme.cornerRadius
        color: "transparent"
        border.color: Theme.primary
        border.width: 2
        opacity: 0.6
    }

    Column {
        anchors.centerIn: parent
        spacing: 2

        DankIcon {
            name: root.isConnected ? "desktop_windows" : "desktop_access_disabled"
            size: Math.min(24, Math.min(root.width * 0.3, root.height * 0.25))
            color: root.isConnected ? (root.isValidPosition ? Theme.primary : Theme.error) : Theme.surfaceVariantText
            anchors.horizontalCenter: parent.horizontalCenter
        }

        StyledText {
            text: DisplayConfigState.getOutputDisplayName(root.outputData, root.outputName)
            font.pixelSize: Math.max(10, Math.min(14, root.width * 0.12))
            font.weight: Font.Medium
            color: root.isConnected ? Theme.surfaceText : Theme.surfaceVariantText
            horizontalAlignment: Text.AlignHCenter
            anchors.horizontalCenter: parent.horizontalCenter
            elide: Text.ElideMiddle
            width: Math.min(implicitWidth, root.width - 8)
        }

        StyledText {
            text: root.isConnected ? (root.physSize.w + "x" + root.physSize.h) : I18n.tr("Disconnected")
            font.pixelSize: Math.max(8, Math.min(11, root.width * 0.09))
            color: Theme.surfaceVariantText
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }

    MouseArea {
        id: dragArea
        anchors.fill: parent
        hoverEnabled: true
        enabled: root.isConnected
        cursorShape: !root.isConnected ? Qt.ArrowCursor : (root.isDragging ? Qt.ClosedHandCursor : Qt.OpenHandCursor)
        drag.target: root.isConnected ? root : null
        drag.axis: Drag.XAndYAxis
        drag.threshold: 0

        onPressed: mouse => {
            if (!root.isConnected)
                return;
            root.isDragging = true;
            root.originalLogical = Qt.point(root.outputData?.logical?.x ?? 0, root.outputData?.logical?.y ?? 0);
            root.snappedLogical = root.originalLogical;
            root.isValidPosition = true;
        }

        onPositionChanged: mouse => {
            if (!root.isDragging || !root.isConnected)
                return;
            let posX = Math.round((root.x - root.canvasOffset.x) / root.canvasScaleFactor);
            let posY = Math.round((root.y - root.canvasOffset.y) / root.canvasScaleFactor);

            const size = DisplayConfigState.getLogicalSize(root.outputData);

            const snapped = SettingsData.displaySnapToEdge ? DisplayConfigState.snapToEdges(root.outputName, posX, posY, size.w, size.h) : Qt.point(posX, posY);
            root.snappedLogical = snapped;
            root.isValidPosition = SettingsData.displaySnapToEdge ? !DisplayConfigState.checkOverlap(root.outputName, snapped.x, snapped.y, size.w, size.h) : true;
        }

        onReleased: {
            if (!root.isDragging || !root.isConnected)
                return;
            root.isDragging = false;

            const size = DisplayConfigState.getLogicalSize(root.outputData);
            const finalX = root.snappedLogical.x;
            const finalY = root.snappedLogical.y;

            if (SettingsData.displaySnapToEdge && DisplayConfigState.checkOverlap(root.outputName, finalX, finalY, size.w, size.h)) {
                root.isValidPosition = true;
                return;
            }

            if (finalX === root.originalLogical.x && finalY === root.originalLogical.y)
                return;

            DisplayConfigState.initOriginalOutputs();
            DisplayConfigState.backendUpdateOutputPosition(root.outputName, finalX, finalY);
            DisplayConfigState.setPendingChange(root.outputName, "position", {
                "x": finalX,
                "y": finalY
            });
        }
    }

    Drag.active: dragArea.drag.active && root.isConnected
}