diff --git a/app/gui/DragonDisplayPicker.qml b/app/gui/DragonDisplayPicker.qml new file mode 100644 index 0000000..65399ed --- /dev/null +++ b/app/gui/DragonDisplayPicker.qml @@ -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) + } + } + } + } + } + } +}