// 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) } } } } } } }