/* * SPDX-License-Identifier: Apache-2.0 * Copyright (C) 2020 Raspberry Pi (Trading) Limited */ import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.0 import QtQuick.Controls.Material 2.2 ApplicationWindow { id: window visible: true width: imageWriter.isEmbeddedMode() ? -1 : 680 height: imageWriter.isEmbeddedMode() ? -1 : 420 minimumWidth: imageWriter.isEmbeddedMode() ? -1 : 680 maximumWidth: imageWriter.isEmbeddedMode() ? -1 : 680 minimumHeight: imageWriter.isEmbeddedMode() ? -1 : 420 maximumHeight: imageWriter.isEmbeddedMode() ? -1 : 420 title: qsTr("Raspberry Pi Imager v%1").arg(imageWriter.constantVersion()) FontLoader {id: roboto; source: "fonts/Roboto-Regular.ttf"} FontLoader {id: robotoLight; source: "fonts/Roboto-Light.ttf"} FontLoader {id: robotoBold; source: "fonts/Roboto-Bold.ttf"} onClosing: { if (progressBar.visible) { close.accepted = false quitpopup.openPopup() } } Shortcut { sequence: StandardKey.Quit context: Qt.ApplicationShortcut onActivated: { if (!progressBar.visible) { Qt.quit() } } } Shortcut { sequences: ["Shift+Ctrl+X", "Shift+Meta+X"] context: Qt.ApplicationShortcut onActivated: { optionspopup.openPopup() } } ColumnLayout { id: bg spacing: 0 Rectangle { implicitHeight: window.height/2 Image { id: image Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter fillMode: Image.PreserveAspectFit source: imageWriter.isEmbeddedMode() ? "icons/rpi2-hires.png" : "icons/rpi2.png" width: window.width height: window.height/2 } } Rectangle { color: "#c31c4a" implicitWidth: window.width implicitHeight: window.height/2 GridLayout { id: gridLayout rowSpacing: 25 anchors.fill: parent anchors.topMargin: 25 anchors.rightMargin: 50 anchors.leftMargin: 50 rows: 3 columns: 3 columnSpacing: 25 ColumnLayout { id: columnLayout spacing: 0 Layout.fillWidth: true Text { id: text1 color: "#ffffff" text: qsTr("Operating System") Layout.fillWidth: true Layout.preferredHeight: 17 Layout.preferredWidth: 100 font.pixelSize: 12 font.family: robotoBold.name font.bold: true horizontalAlignment: Text.AlignHCenter } Button { id: osbutton text: imageWriter.srcFileName() === "" ? qsTr("CHOOSE OS") : imageWriter.srcFileName() font.family: roboto.name spacing: 0 padding: 0 bottomPadding: 0 topPadding: 0 Layout.minimumHeight: 40 Layout.fillWidth: true onClicked: { ospopup.open() osswipeview.currentItem.forceActiveFocus() } Material.background: "#ffffff" Material.foreground: "#c51a4a" Accessible.ignored: ospopup.visible || dstpopup.visible Accessible.description: qsTr("Select this button to change the operating system") Accessible.onPressAction: clicked() } } ColumnLayout { id: columnLayout2 spacing: 0 Layout.fillWidth: true Text { id: text2 color: "#ffffff" text: qsTr("Storage") Layout.fillWidth: true Layout.preferredHeight: 17 Layout.preferredWidth: 100 font.pixelSize: 12 font.family: robotoBold.name font.bold: true horizontalAlignment: Text.AlignHCenter } Button { id: dstbutton text: qsTr("CHOOSE STORAGE") font.family: roboto.name Layout.minimumHeight: 40 Layout.preferredWidth: 100 Layout.fillWidth: true onClicked: { imageWriter.startDriveListPolling() dstpopup.open() dstlist.forceActiveFocus() } Material.background: "#ffffff" Material.foreground: "#c51a4a" Accessible.ignored: ospopup.visible || dstpopup.visible Accessible.description: qsTr("Select this button to change the destination SD card") Accessible.onPressAction: clicked() } } ColumnLayout { spacing: 0 Layout.fillWidth: true Text { text: " " Layout.preferredHeight: 17 Layout.preferredWidth: 100 } Button { id: writebutton text: qsTr("WRITE") font.family: roboto.name Layout.minimumHeight: 40 Layout.fillWidth: true Accessible.ignored: ospopup.visible || dstpopup.visible Accessible.description: qsTr("Select this button to start writing the image") enabled: false Material.background: "#ffffff" Material.foreground: "#c51a4a" onClicked: { if (!imageWriter.readyToWrite()) { return } if (!optionspopup.initialized && imageWriter.hasSavedCustomizationSettings()) { usesavedsettingspopup.openPopup() } else { confirmwritepopup.askForConfirmation() } } Accessible.onPressAction: clicked() } } ColumnLayout { id: columnLayout3 Layout.columnSpan: 3 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Text { id: progressText font.pointSize: 10 color: "white" font.family: robotoBold.name font.bold: true visible: false horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true } ProgressBar { id: progressBar Layout.fillWidth: true visible: false Material.background: "#d15d7d" } Button { id: cancelwritebutton text: qsTr("CANCEL WRITE") onClicked: { enabled = false progressText.text = qsTr("Cancelling...") imageWriter.cancelWrite() } Material.background: "#ffffff" Material.foreground: "#c51a4a" Layout.alignment: Qt.AlignRight visible: false font.family: roboto.name Accessible.onPressAction: clicked() } Button { id: cancelverifybutton text: qsTr("CANCEL VERIFY") onClicked: { enabled = false progressText.text = qsTr("Finalizing...") imageWriter.setVerifyEnabled(false) } Material.background: "#ffffff" Material.foreground: "#c51a4a" Layout.alignment: Qt.AlignRight visible: false font.family: roboto.name Accessible.onPressAction: clicked() } } } } } /* Popup for OS selection */ Popup { id: ospopup x: 50 y: 25 width: parent.width-100 height: parent.height-50 padding: 0 closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside property string categorySelected : "" // background of title Rectangle { color: "#f5f5f5" anchors.right: parent.right anchors.top: parent.top height: 35 width: parent.width } // line under title Rectangle { color: "#afafaf" width: parent.width y: 35 implicitHeight: 1 } Text { text: "X" anchors.right: parent.right anchors.top: parent.top anchors.rightMargin: 25 anchors.topMargin: 10 font.family: roboto.name font.bold: true MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: { ospopup.close() } } } ColumnLayout { spacing: 10 Text { text: qsTr("Operating System") horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter Layout.fillWidth: true Layout.topMargin: 10 font.family: roboto.name font.bold: true } Item { clip: true width: oslist.width height: oslist.height SwipeView { id: osswipeview interactive: false ListView { id: oslist model: osmodel currentIndex: -1 delegate: osdelegate width: window.width-100 height: window.height-100 boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "lightsteelblue"; radius: 5 } ScrollBar.vertical: ScrollBar { width: 10 policy: oslist.contentHeight > oslist.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded } Keys.onSpacePressed: { if (currentIndex != -1) selectOSitem(model.get(currentIndex), true) } Accessible.onPressAction: { if (currentIndex != -1) selectOSitem(model.get(currentIndex), true) } } } } } } Component { id: suboslist ListView { model: ListModel { ListElement { url: "" icon: "icons/ic_chevron_left_40px.svg" extract_size: 0 image_download_size: 0 extract_sha256: "" contains_multiple_files: false release_date: "" subitems_url: "internal://back" subitems: [] name: qsTr("Back") description: qsTr("Go back to main menu") tooltip: "" } } currentIndex: -1 delegate: osdelegate width: window.width-100 height: window.height-100 boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "lightsteelblue"; radius: 5 } ScrollBar.vertical: ScrollBar { width: 10 policy: parent.contentHeight > parent.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded } Keys.onSpacePressed: { if (currentIndex != -1) selectOSitem(model.get(currentIndex)) } Accessible.onPressAction: { if (currentIndex != -1) selectOSitem(model.get(currentIndex)) } } } ListModel { id: osmodel ListElement { url: "internal://format" icon: "icons/erase.png" extract_size: 0 image_download_size: 0 extract_sha256: "" contains_multiple_files: false release_date: "" subitems_url: "" subitems: [] name: qsTr("Erase") description: qsTr("Format card as FAT32") tooltip: "" } ListElement { url: "" icon: "icons/use_custom.png" name: qsTr("Use custom") description: qsTr("Select a custom .img from your computer") } Component.onCompleted: { if (imageWriter.isOnline()) { fetchOSlist(); } } } Component { id: osdelegate Item { width: window.width-100 height: image_download_size ? 100 : 60 Accessible.name: name+".\n"+description Rectangle { id: bgrect anchors.fill: parent color: "#f5f5f5" visible: mouseOver && parent.ListView.view.currentIndex !== index property bool mouseOver: false } Rectangle { id: borderrect implicitHeight: 1 implicitWidth: parent.width color: "#dcdcdc" y: parent.height } Row { leftPadding: 25 Column { width: 64 Image { source: icon == "icons/ic_build_48px.svg" ? "icons/cat_misc_utility_images.png": icon verticalAlignment: Image.AlignVCenter height: parent.parent.parent.height fillMode: Image.Pad } Text { text: " " // visible: !icon } } Column { width: parent.parent.width-64-50-25 Text { verticalAlignment: Text.AlignVCenter height: parent.parent.parent.height font.family: roboto.name textFormat: Text.RichText text: { var txt = "
"+name+"
" txt += ""+description+"" if (typeof(release_date) == "string" && release_date) txt += ""+description+" - "+sizeStr+"
" txt += "" if (mountpoints.length > 0) { txt += qsTr("Mounted as %1").arg(mountpoints.join(", "))+" " } txt += qsTr("[WRITE PROTECTED]")+"" } else { txt = ""+description+" - "+sizeStr+"
" if (mountpoints.length > 0) { txt += ""+qsTr("Mounted as %1").arg(mountpoints.join(", "))+"" } } return txt; } } } } MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor hoverEnabled: true onEntered: { dstbgrect.mouseOver = true } onExited: { dstbgrect.mouseOver = false } onClicked: { selectDstItem(model) } } } } MsgPopup { id: msgpopup } MsgPopup { id: quitpopup continueButton: false yesButton: true noButton: true title: qsTr("Are you sure you want to quit?") text: qsTr("Raspberry Pi Imager is still busy.