Upload DragonDisplayPicker.qml
This commit is contained in:
parent
1c9bc1e670
commit
9fcfe8c6c8
1 changed files with 203 additions and 0 deletions
203
app/gui/DragonDisplayPicker.qml
Normal file
203
app/gui/DragonDisplayPicker.qml
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
// DragonDisplayPicker.qml
|
||||||
|
//
|
||||||
|
// Multi-display picker component for streaming to a specific monitor on a remote host.
|
||||||
|
// Shows a modal overlay with a list of available displays and lets the user select one.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// DragonDisplayPicker {
|
||||||
|
// visible: showDisplayPicker
|
||||||
|
// anchors.fill: parent
|
||||||
|
// hostIP: pickerHostIP
|
||||||
|
// hostName: pickerHostName
|
||||||
|
// displays: pickerDisplays
|
||||||
|
// onDisplaySelected: function(idx) {
|
||||||
|
// showDisplayPicker = false
|
||||||
|
// dragonRelay.streamHostDisplay(pickerHostIP, idx)
|
||||||
|
// }
|
||||||
|
// onCancelled: { showDisplayPicker = false }
|
||||||
|
// }
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string hostIP: ""
|
||||||
|
property string hostName: ""
|
||||||
|
property var displays: [] // array of display maps
|
||||||
|
|
||||||
|
signal displaySelected(int displayIndex)
|
||||||
|
signal cancelled()
|
||||||
|
|
||||||
|
// ── Modal backdrop ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "rgba(0, 0, 0, 0.7)"
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.cancelled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Dialog box ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dialogBox
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: Math.min(parent.width - 48, 500)
|
||||||
|
height: Math.min(parent.height - 48, 400)
|
||||||
|
radius: 12
|
||||||
|
color: "#0f172a" // dark blue slate
|
||||||
|
border.color: "#374151"
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 20
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
|
// ── Title ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Select Display")
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.bold: true
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Host: %1 (%2)").arg(root.hostName).arg(root.hostIP)
|
||||||
|
font.pixelSize: 12
|
||||||
|
color: "#9ca3af"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Divider ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 1
|
||||||
|
color: "#374151"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Display list ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: displayList
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
spacing: 8
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
model: root.displays
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: displayList.width
|
||||||
|
height: 56
|
||||||
|
radius: 8
|
||||||
|
color: displayMouse.containsMouse ? "#374151" : "#1f2937"
|
||||||
|
border.color: displayMouse.containsMouse ? "#4b5563" : "transparent"
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: modelData.friendlyName || modelData.name
|
||||||
|
font.pixelSize: 14
|
||||||
|
font.bold: true
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("%1x%2").arg(modelData.width).arg(modelData.height)
|
||||||
|
font.pixelSize: 11
|
||||||
|
color: "#9ca3af"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
visible: modelData.isPrimary
|
||||||
|
width: primaryLabel.implicitWidth + 12
|
||||||
|
height: 20
|
||||||
|
radius: 4
|
||||||
|
color: "#10b981" // green
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: primaryLabel
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("Primary")
|
||||||
|
font.pixelSize: 10
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: displayMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: {
|
||||||
|
root.displaySelected(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty state message
|
||||||
|
Label {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("No displays available")
|
||||||
|
color: "#9ca3af"
|
||||||
|
font.pixelSize: 12
|
||||||
|
visible: displayList.count === 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Divider ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 1
|
||||||
|
color: "#374151"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Buttons ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: 12
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
flat: true
|
||||||
|
onClicked: root.cancelled()
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Select")
|
||||||
|
enabled: displayList.currentIndex >= 0
|
||||||
|
onClicked: {
|
||||||
|
if (displayList.currentIndex >= 0) {
|
||||||
|
root.displaySelected(displayList.currentIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue