| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- import QtQuick 2.15
- import QtQuick.Controls 2.15
- import QtQuick.Layouts 1.15
- import DuneWeaver 1.0
- import "../components"
- import "../components" as Components
- Page {
- id: page
- property string patternName: ""
- property string patternPath: ""
- property string patternPreview: ""
- property var backend: null
- property bool showAddedFeedback: false
- // Playlist model for selecting which playlist to add to
- PlaylistModel {
- id: playlistModel
- }
- Rectangle {
- anchors.fill: parent
- color: Components.ThemeManager.backgroundColor
- }
-
- ColumnLayout {
- anchors.fill: parent
- spacing: 0
-
- // Header
- Rectangle {
- Layout.fillWidth: true
- Layout.preferredHeight: 50
- color: Components.ThemeManager.surfaceColor
- // Bottom border
- Rectangle {
- anchors.bottom: parent.bottom
- width: parent.width
- height: 1
- color: Components.ThemeManager.borderColor
- }
-
- RowLayout {
- anchors.fill: parent
- anchors.margins: 10
-
- ConnectionStatus {
- backend: page.backend
- Layout.rightMargin: 8
- }
-
- Button {
- text: "← Back"
- font.pixelSize: 14
- flat: true
- onClicked: stackView.pop()
- contentItem: Text {
- text: parent.text
- font: parent.font
- color: Components.ThemeManager.textPrimary
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- }
- }
-
- Label {
- text: patternName
- Layout.fillWidth: true
- elide: Label.ElideRight
- font.pixelSize: 16
- font.bold: true
- color: Components.ThemeManager.textPrimary
- }
- }
- }
-
- // Content - Side by side layout
- Item {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- Row {
- anchors.fill: parent
- spacing: 0
-
- // Left side - Pattern Preview (60% of width)
- Rectangle {
- width: parent.width * 0.6
- height: parent.height
- color: Components.ThemeManager.previewBackground
- Image {
- anchors.fill: parent
- anchors.margins: 10
- source: patternPreview ? "file:///" + patternPreview : ""
- fillMode: Image.PreserveAspectFit
- Rectangle {
- anchors.fill: parent
- color: Components.ThemeManager.placeholderBackground
- visible: parent.status === Image.Error || parent.source == ""
- Column {
- anchors.centerIn: parent
- spacing: 10
- Text {
- text: "○"
- font.pixelSize: 48
- color: Components.ThemeManager.placeholderText
- anchors.horizontalCenter: parent.horizontalCenter
- }
- Text {
- text: "No Preview Available"
- color: Components.ThemeManager.textSecondary
- font.pixelSize: 14
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
- }
- }
- }
-
- // Divider
- Rectangle {
- width: 1
- height: parent.height
- color: Components.ThemeManager.borderColor
- }
- // Right side - Controls (40% of width)
- Rectangle {
- width: parent.width * 0.4 - 1
- height: parent.height
- color: Components.ThemeManager.surfaceColor
-
- Column {
- anchors.fill: parent
- anchors.margins: 10
- spacing: 15
-
- // Play Button - FIRST AND PROMINENT
- Rectangle {
- width: parent.width
- height: 50
- radius: 8
- color: playMouseArea.pressed ? "#1e40af" : (backend ? "#2563eb" : "#9ca3af")
- Text {
- anchors.centerIn: parent
- text: "▶ Play Pattern"
- color: "white"
- font.pixelSize: 16
- font.bold: true
- }
- MouseArea {
- id: playMouseArea
- anchors.fill: parent
- enabled: backend !== null
- onClicked: {
- if (backend) {
- var preExecution = "adaptive"
- if (centerRadio.checked) preExecution = "clear_center"
- else if (perimeterRadio.checked) preExecution = "clear_perimeter"
- else if (noneRadio.checked) preExecution = "none"
- backend.executePattern(patternName, preExecution)
- }
- }
- }
- }
- // Add to Playlist Button
- Rectangle {
- width: parent.width
- height: 45
- radius: 8
- color: addToPlaylistArea.pressed ? "#065f46" : "#059669"
- Row {
- anchors.centerIn: parent
- spacing: 8
- Text {
- text: showAddedFeedback ? "✓" : "♪"
- font.pixelSize: 16
- color: "white"
- }
- Text {
- text: showAddedFeedback ? "Added!" : "Add to Playlist"
- color: "white"
- font.pixelSize: 14
- font.bold: true
- }
- }
- MouseArea {
- id: addToPlaylistArea
- anchors.fill: parent
- enabled: backend !== null && !showAddedFeedback
- onClicked: {
- playlistModel.refresh() // Refresh playlist list
- playlistSelectorPopup.open()
- }
- }
- }
- // Pre-Execution Options
- Rectangle {
- width: parent.width
- height: 160 // Increased height to fit all options
- radius: 8
- color: Components.ThemeManager.cardColor
- border.color: Components.ThemeManager.borderColor
- border.width: 1
- Column {
- id: preExecColumn
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: parent.top
- anchors.margins: 8 // Reduced margins to save space
- spacing: 6 // Reduced spacing
- Label {
- text: "Pre-Execution"
- font.pixelSize: 12
- font.bold: true
- color: Components.ThemeManager.textPrimary
- }
-
- RadioButton {
- id: adaptiveRadio
- text: "Adaptive"
- checked: true
- font.pixelSize: 10
- contentItem: Text {
- text: parent.text
- font: parent.font
- color: Components.ThemeManager.textPrimary
- verticalAlignment: Text.AlignVCenter
- leftPadding: parent.indicator.width + parent.spacing
- }
- }
- RadioButton {
- id: centerRadio
- text: "Clear Center"
- font.pixelSize: 10
- contentItem: Text {
- text: parent.text
- font: parent.font
- color: Components.ThemeManager.textPrimary
- verticalAlignment: Text.AlignVCenter
- leftPadding: parent.indicator.width + parent.spacing
- }
- }
- RadioButton {
- id: perimeterRadio
- text: "Clear Edge"
- font.pixelSize: 10
- contentItem: Text {
- text: parent.text
- font: parent.font
- color: Components.ThemeManager.textPrimary
- verticalAlignment: Text.AlignVCenter
- leftPadding: parent.indicator.width + parent.spacing
- }
- }
- RadioButton {
- id: noneRadio
- text: "None"
- font.pixelSize: 10
- contentItem: Text {
- text: parent.text
- font: parent.font
- color: Components.ThemeManager.textPrimary
- verticalAlignment: Text.AlignVCenter
- leftPadding: parent.indicator.width + parent.spacing
- }
- }
- }
- }
-
- // Pattern Info
- Rectangle {
- width: parent.width
- height: 80
- radius: 8
- color: Components.ThemeManager.cardColor
- border.color: Components.ThemeManager.borderColor
- border.width: 1
- Column {
- id: infoColumn
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: parent.top
- anchors.margins: 10
- spacing: 6
- Label {
- text: "Pattern Info"
- font.pixelSize: 14
- font.bold: true
- color: Components.ThemeManager.textPrimary
- }
- Label {
- text: "Name: " + patternName
- font.pixelSize: 11
- color: Components.ThemeManager.textSecondary
- elide: Text.ElideRight
- width: parent.width
- }
- Label {
- text: "Type: Sand Pattern"
- font.pixelSize: 11
- color: Components.ThemeManager.textSecondary
- }
- }
- }
- }
- }
- }
- }
- }
- // ==================== Playlist Selector Popup ====================
- Popup {
- id: playlistSelectorPopup
- modal: true
- x: (parent.width - width) / 2
- y: (parent.height - height) / 2
- width: 320
- height: Math.min(400, 120 + playlistModel.rowCount() * 50)
- closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
- background: Rectangle {
- color: Components.ThemeManager.surfaceColor
- radius: 16
- border.color: Components.ThemeManager.borderColor
- border.width: 1
- }
- contentItem: ColumnLayout {
- anchors.fill: parent
- anchors.margins: 15
- spacing: 10
- Label {
- text: "Add to Playlist"
- font.pixelSize: 18
- font.bold: true
- color: Components.ThemeManager.textPrimary
- Layout.alignment: Qt.AlignHCenter
- }
- // Playlist list
- ListView {
- Layout.fillWidth: true
- Layout.fillHeight: true
- clip: true
- model: playlistModel
- spacing: 6
- delegate: Rectangle {
- width: ListView.view.width
- height: 45
- radius: 8
- color: playlistItemArea.pressed ? Components.ThemeManager.selectedBackground : Components.ThemeManager.cardColor
- border.color: Components.ThemeManager.borderColor
- border.width: 1
- RowLayout {
- anchors.fill: parent
- anchors.margins: 12
- spacing: 10
- Text {
- text: "♪"
- font.pixelSize: 16
- color: "#2196F3"
- }
- Label {
- text: model.name
- font.pixelSize: 14
- color: Components.ThemeManager.textPrimary
- Layout.fillWidth: true
- elide: Text.ElideRight
- }
- Label {
- text: model.itemCount + " patterns"
- font.pixelSize: 11
- color: Components.ThemeManager.textTertiary
- }
- }
- MouseArea {
- id: playlistItemArea
- anchors.fill: parent
- onClicked: {
- if (backend) {
- backend.addPatternToPlaylist(model.name, patternName)
- }
- playlistSelectorPopup.close()
- }
- }
- }
- }
- // Empty state
- Column {
- Layout.fillWidth: true
- Layout.fillHeight: true
- spacing: 10
- visible: playlistModel.rowCount() === 0
- Item { Layout.fillHeight: true }
- Text {
- text: "♪"
- font.pixelSize: 32
- color: Components.ThemeManager.placeholderText
- anchors.horizontalCenter: parent.horizontalCenter
- }
- Label {
- text: "No playlists yet"
- anchors.horizontalCenter: parent.horizontalCenter
- color: Components.ThemeManager.textSecondary
- font.pixelSize: 14
- }
- Label {
- text: "Create a playlist first"
- anchors.horizontalCenter: parent.horizontalCenter
- color: Components.ThemeManager.textTertiary
- font.pixelSize: 12
- }
- Item { Layout.fillHeight: true }
- }
- // Cancel button
- Rectangle {
- Layout.fillWidth: true
- Layout.preferredHeight: 40
- radius: 8
- color: cancelArea.pressed ? Components.ThemeManager.buttonBackgroundHover : Components.ThemeManager.cardColor
- border.color: Components.ThemeManager.borderColor
- border.width: 1
- Text {
- anchors.centerIn: parent
- text: "Cancel"
- color: Components.ThemeManager.textPrimary
- font.pixelSize: 14
- }
- MouseArea {
- id: cancelArea
- anchors.fill: parent
- onClicked: playlistSelectorPopup.close()
- }
- }
- }
- }
- // ==================== Backend Signal Handlers ====================
- Connections {
- target: backend
- function onPatternAddedToPlaylist(success, message) {
- if (success) {
- // Show feedback
- showAddedFeedback = true
- feedbackTimer.start()
- }
- }
- }
- Timer {
- id: feedbackTimer
- interval: 2000 // Show "Added!" for 2 seconds
- onTriggered: showAddedFeedback = false
- }
- }
|