diff --git a/XmlData.xml b/XmlData.xml index 2758858..2f53b76 100644 --- a/XmlData.xml +++ b/XmlData.xml @@ -6,6 +6,7 @@ SingleNoPrint.svg WhiteBackground.png ExampleForeground.png + @@ -14,6 +15,7 @@ Single Image Single.svg WhiteBackground.png + @@ -22,6 +24,7 @@ Two Images Double.svg WhiteBackground.png + @@ -38,6 +41,7 @@ Four Images Four.svg WhiteBackground.png + @@ -45,10 +49,23 @@ + + Four Images Rotation + Four.svg + WhiteBackground.png + + + 0.0 + 10.0 + 20.0 + 30.0 + + Four Images with Background FourStars.svg StarsBackground.jpg + @@ -60,6 +77,7 @@ Four Images Border FourBorder.svg WhiteBackground.png + diff --git a/qml.qrc b/qml.qrc index 55d1423..1e93844 100644 --- a/qml.qrc +++ b/qml.qrc @@ -74,5 +74,9 @@ qml/content/PrinterPopup.qml images/ExampleForeground.png images/icon/SingleNoPrint.svg + qml/GalleryMenu.qml + qml/GalleryMenuForm.ui.qml + qml/content/DelegateGalleryItem.qml + qml/styles/RoundProgressBarStyle.qml diff --git a/qml/Application.qml b/qml/Application.qml index 5aca03a..71133f4 100644 --- a/qml/Application.qml +++ b/qml/Application.qml @@ -66,6 +66,7 @@ ApplicationWindow { onPrinterChanged: { flow.collageMenu.printer = printer + flow.galleryMenu.printer = printer } ApplicationFlow @@ -85,6 +86,11 @@ ApplicationWindow { applicationSettings.multiplePrints = mainMenu.settingsPopup.switchMultiplePrints.checked } + mainMenu.settingsPopup.switchPrintFromGallery.onCheckedChanged: + { + applicationSettings.printFromGallery = mainMenu.settingsPopup.switchPrintFromGallery.checked + } + mainMenu.settingsPopup.switchHideSnapshotSettings.onCheckedChanged: { applicationSettings.disableSnapshotSettingsPane = mainMenu.settingsPopup.switchHideSnapshotSettings.checked @@ -136,7 +142,12 @@ ApplicationWindow { applicationSettings.cameraName = mainMenu.settingsPopup.comboBoxCamera.currentText } - mainMenu.printerBusy: printer.busy + mainMenu.settingsPopup.switchEnableSettingsPassword.onCheckedChanged: + { + applicationSettings.enableSettingsPassword = mainMenu.settingsPopup.switchEnableSettingsPassword.checked + } + + mainMenu.printerBusy: printer ? printer.busy : false } Settings @@ -154,15 +165,19 @@ ApplicationWindow { property bool disableSnapshotSettingsPane: false property bool disableEffectPopup: false property string cameraName: "" + property bool printFromGallery: true + property bool enableSettingsPassword: true Component.onCompleted: { flow.mainMenu.settingsPopup.printerEnabled.checked = printEnable + flow.mainMenu.settingsPopup.switchPrintFromGallery.checked = printFromGallery flow.mainMenu.settingsPopup.switchMultiplePrints.checked = multiplePrints flow.mainMenu.settingsPinCode = password flow.mainMenu.settingsPopup.mirrorCamera.checked = cameraMirrored flow.mainMenu.settingsPopup.switchHideSnapshotSettings.checked = disableSnapshotSettingsPane flow.mainMenu.settingsPopup.switchHideEffectPopup.checked = disableEffectPopup + flow.mainMenu.settingsPopup.switchEnableSettingsPassword.checked = enableSettingsPassword flow.mainMenuModel.setShowPrintable(printEnable) flow.collageMenu.multiplePrints = multiplePrints flow.snapshotMenu.hideSnapshotSettingsPane = disableSnapshotSettingsPane diff --git a/qml/ApplicationFlow.qml b/qml/ApplicationFlow.qml index 42b1d2e..2975865 100644 --- a/qml/ApplicationFlow.qml +++ b/qml/ApplicationFlow.qml @@ -29,6 +29,11 @@ ApplicationFlowForm { mainMenu.selectedCollageName = "" } + mainMenu.onGalleryEnter: + { + state = "gallery" + } + snapshotMenu.onCaptured: { state = "imagePreview" @@ -79,6 +84,16 @@ ApplicationFlowForm { state = "collageSelection" } + collageMenu.collageImage.onCollageImagesChanged: + { + snapshotMenu.snapshotTimeoutEnable = (count == 0) + } + + galleryMenu.onExitGallery: + { + state = "collageSelection" + } + Behavior on slideValueCollageSelection { PropertyAnimation { duration: flow.animationDuration @@ -106,6 +121,13 @@ ApplicationFlowForm { easing.type: Easing.InOutQuad } } + + Behavior on slideValueGalleryMenu { + PropertyAnimation { + duration: flow.animationDuration + easing.type: Easing.InOutQuad + } + } } diff --git a/qml/ApplicationFlowForm.ui.qml b/qml/ApplicationFlowForm.ui.qml index dcad932..ba5d008 100644 --- a/qml/ApplicationFlowForm.ui.qml +++ b/qml/ApplicationFlowForm.ui.qml @@ -9,11 +9,13 @@ Item { property alias snapshotMenu: snapshotMenu property alias imagePreview: imagePreview property alias collageMenu: collageMenu + property alias galleryMenu: galleryMenu property real slideValueCollageSelection: 0.0 property real slideValueSnapshotMenu: 1.0 property real slideValuePreviewMenu: 1.0 property real slideValueCollageMenu: 1.0 + property real slideValueGalleryMenu: 1.0 MainMenu { id: mainMenu @@ -47,6 +49,16 @@ Item { width: root.width height: root.height } + + GalleryMenu + { + id: galleryMenu + x: root.width * slideValueGalleryMenu + y: 0 + width: root.width + height: root.height + } + states: [ State { name: "collageSelection" @@ -108,6 +120,33 @@ Item { target: snapshotMenu visible: false } + }, + State { + name: "gallery" + + PropertyChanges { + target: root + slideValueCollageSelection: -1.0 + slideValueSnapshotMenu: -1.0 + slideValuePreviewMenu: -1.0 + slideValueCollageMenu: -1.0 + slideValueGalleryMenu: 0.0 + } + + PropertyChanges { + target: snapshotMenu + visible: false + } + + PropertyChanges { + target: imagePreview + visible: false + } + + PropertyChanges { + target: collageMenu + visible: false + } } ] } diff --git a/qml/CollageMenu.qml b/qml/CollageMenu.qml index c3141c2..e7aa90a 100644 --- a/qml/CollageMenu.qml +++ b/qml/CollageMenu.qml @@ -12,9 +12,9 @@ CollageMenuForm { signal next signal exit - printButton.enabled: !printer.busy - property real printerHeight : printer.getPrintSize().height - property real printerWidth : printer.getPrintSize().width + printButton.enabled: printer ? !printer.busy : false + property real printerHeight : form.collageImage.imageModel ? form.collageImage.imageModel.collagePixelSize.height : 0 + property real printerWidth : form.collageImage.imageModel ? form.collageImage.imageModel.collagePixelSize.width : 0 printerRatio: printerHeight / printerWidth nextButton.onClicked: @@ -31,10 +31,11 @@ CollageMenuForm { var path = applicationSettings.foldername.toString() path = path.replace(/^(file:\/{2})/,""); var cleanPath = decodeURIComponent(path); - console.log(cleanPath) var filename = cleanPath + "/collage/Coll_"+ new Date().toLocaleString(locale, "dd_MM_yyyy_hh_mm_ss") + ".png" - collageRenderer.saveImage(filename, printer.getPrintSize()) - console.log("Collage rendered") + console.log("Save files to: " + filename) + collageRenderer.saveImage(filename, form.collageImage.imageModel.collagePixelSize) + console.log("Collage rendered width: " + Number(form.collageImage.imageModel.collagePixelSize.width).toString() + + " height: " + form.collageImage.imageModel.collagePixelSize.height) } collageRenderer.onSavingChanged: diff --git a/qml/CollageMenuForm.ui.qml b/qml/CollageMenuForm.ui.qml index efbd402..46c3dc2 100644 --- a/qml/CollageMenuForm.ui.qml +++ b/qml/CollageMenuForm.ui.qml @@ -35,8 +35,11 @@ Item { property double aimedRatio: printerRatio // SIZING - property double availableWidth: parent.width - rightMargin - leftMargin - property double availableHeight: parent.height - bottomMargin - topMargin + property double calculatedWidth: parent.width - rightMargin - leftMargin + property double calculatedHeight: parent.height - bottomMargin - topMargin + + property double availableWidth: calculatedWidth > 10 ? calculatedWidth : 10 + property double availableHeight: calculatedHeight > 10 ? calculatedHeight : 10 property bool parentIsLarge: parentRatio > aimedRatio diff --git a/qml/GalleryMenu.qml b/qml/GalleryMenu.qml new file mode 100644 index 0000000..bdec22c --- /dev/null +++ b/qml/GalleryMenu.qml @@ -0,0 +1,55 @@ +import QtQuick 2.5 +import Printer 1.0 + +GalleryMenuForm { + property alias foldermodel: galleryForm.foldermodel + signal exitGallery + property alias printer: galleryForm.printer + + id: galleryForm + + + scrollDownButton.onPressed: + { + scrollBar.increase() + } + + scrollUpButton.onPressed: + { + scrollBar.decrease() + } + + photosGrid.onCurrentIndexChanged: { + photoView.positionViewAtIndex(photosGrid.currentIndex, ListView.Contain) + } + + photoView.onCurrentIndexChanged: { + photosGrid.positionViewAtIndex(photoView.currentIndex, GridView.Contain) + } + + function resetGallery() + { + viewState = "inGrid" + } + + exitButton.onClicked: + { + exitGallery() + } + + photoButton.onClicked: + { + foldermodel.folder = applicationSettings.foldername + } + + collageButton.onClicked: + { + foldermodel.folder = applicationSettings.foldername + "/collage" + } +} + + +/*##^## Designer { + D{i:0;autoSize:true;height:480;width:640} +} + ##^##*/ diff --git a/qml/GalleryMenuForm.ui.qml b/qml/GalleryMenuForm.ui.qml new file mode 100644 index 0000000..a48b344 --- /dev/null +++ b/qml/GalleryMenuForm.ui.qml @@ -0,0 +1,260 @@ +import QtQuick 2.5 +import Qt.labs.folderlistmodel 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.0 +import QtQml.Models 2.2 +import Printer 1.0 +import "content" + +Item { + property alias foldermodel: folderModel + property alias scrollUpButton: scrollBarUpButton + property alias scrollDownButton: scrollBarDownButton + property alias scrollBar: galleryScrollbar + property alias photosGrid: photosGridView + property alias photoView: photosListView + property alias viewState: root.state + property alias exitButton: exitButton + property alias photoButton: photoButton + property alias collageButton: collageButton + property Printer printer + + Image { + id: root + anchors.fill: parent + + source: "../images/cardboard.png" + fillMode: Image.Tile + + property bool imageLoading: false + + Rectangle + { + id: sidebar + width: 150 + height: parent.height + color: "#4d60ea" + + ColumnLayout + { + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + + Button + { + id: photoButton + + Layout.alignment: Qt.AlignLeft + flat: true + implicitWidth: parent.width + implicitHeight: parent.height / 2 + + contentItem: Item { + anchors.fill: parent + + Text { + text: qsTr("Photos") + + color: "white" + font.family: "DejaVu Serif" + font.pixelSize: 50 + anchors.centerIn: parent + font.capitalization: Font.AllUppercase + + rotation: 270 + } + } + + + } + + Button + { + id: collageButton + + Layout.alignment: Qt.AlignLeft + flat: true + implicitWidth: parent.width + implicitHeight: parent.height / 2 + + contentItem: Item { + anchors.fill: parent + + Text { + text: qsTr("Collages") + + color: "white" + font.family: "DejaVu Serif" + font.pixelSize: 50 + anchors.centerIn: parent + font.capitalization: Font.AllUppercase + + rotation: 270 + } + } + } + } + } + + FolderListModel { + id: folderModel + folder: applicationSettings.foldername + nameFilters: ["*.jpg", "*.JPG", "*.png", "*.PNG"] + showDirs: false + sortReversed: true //show newest photo first + } + + DelegateModel { + id: visualModel + delegate: DelegateGalleryItem { + onPrintImage: + { + printerPopup.visible = true + printer.printImage(filename, 1) + printerPopup.visible = false + } + } + model: folderModel + } + + GridView { + id: photosGridView + + x: 0 + y: 0 + cellWidth: 320 + cellHeight: 306 + anchors.left: sidebar.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + model: visualModel.parts.grid + interactive: true + //displayMarginBeginning: 10000 + //displayMarginEnd: 10000 + + //rightMargin: 100 + + + /*Rectangle { + anchors.centerIn: parent + width: parent.width-10; height: parent.height-10 + color: "transparent" + border.color: "red" + border.width: 5 + }*/ + ScrollBar.vertical: ScrollBar { + id: galleryScrollbar + contentItem.implicitWidth: 50 + bottomPadding: 50 + topPadding: 50 + Button { + id: scrollBarUpButton + text: "\uE819" // icon-folder-open-empty + font.family: "fontello" + width: 50 + height: 50 + anchors.top: parent.top + font.pointSize: 30 + } + Button { + id: scrollBarDownButton + text: "\uE81C" // icon-folder-open-empty + font.family: "fontello" + anchors.bottom: parent.bottom + width: 50 + height: 50 + font.pointSize: 30 + } + } + } + + ListView { + id: photosListView + + width: root.width + height: root.height + orientation: Qt.Horizontal + model: visualModel.parts.list + interactive: false + + highlightRangeMode: ListView.StrictlyEnforceRange + snapMode: ListView.SnapOneItem + + /*Rectangle { + anchors.centerIn: parent + width: parent.width-10; height: parent.height-10 + color: "transparent" + border.color: "green" + border.width: 5 + }*/ + } + + NavigationButton { + id: exitButton + y: 515 + text: qsTr("Exit") + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.left: sidebar.right + anchors.leftMargin: 20 + forward: false + } + + PrinterPopup { + id: printerPopup + anchors.centerIn: parent + visible: false + isPrinting: true + } + + state: 'inGrid' + states: [ + State { + name: 'inGrid' + PropertyChanges { + target: photosGridView + interactive: true + visible: true + } + PropertyChanges { + target: photosListView + visible: false + } + }, + State { + name: 'fullscreen' + extend: 'inGrid' + PropertyChanges { + target: photosGridView + interactive: false + visible: false + } + PropertyChanges { + target: photosListView + visible: true + } + } + ] + + //MouseArea { + // anchors.fill: root + // z: root.state == 'inGrid' ? -1 : 0 + // onClicked: { + // root.state = 'inGrid' + // } + //} + } + + Item { + id: foreground + anchors.fill: parent + } +} + + +/*##^## Designer { + D{i:0;autoSize:true;height:480;width:640} +} + ##^##*/ diff --git a/qml/MainMenu.qml b/qml/MainMenu.qml index ed4a441..004f7f8 100644 --- a/qml/MainMenu.qml +++ b/qml/MainMenu.qml @@ -14,6 +14,7 @@ MainMenuForm { property bool collageIsPrintable: true state: "IconNotSelected" signal collageSelected + signal galleryEnter property real scrollPosition: 0.0 property real scrollDuration: 50000.0 @@ -39,6 +40,11 @@ MainMenuForm { collageSelected() } + galleryButton.onClicked: + { + galleryEnter() + } + backButton.onClicked: { state = "IconNotSelected" @@ -86,7 +92,7 @@ MainMenuForm { settingsButton.onClicked: { - if(applicationSettings.password.length == 0) + if(applicationSettings.password.length == 0 || applicationSettings.enableSettingsPassword == false) { settingsPopup.open() } diff --git a/qml/MainMenuForm.ui.qml b/qml/MainMenuForm.ui.qml index 6082210..37465bc 100644 --- a/qml/MainMenuForm.ui.qml +++ b/qml/MainMenuForm.ui.qml @@ -15,6 +15,7 @@ Item { property alias imageSlider: imageSlider property alias collageSelector: collageSelector property alias iconModel: collageSelector.iconModel + property alias galleryButton: galleryButton CollageSelector { id: collageSelector @@ -173,6 +174,15 @@ Item { anchors.rightMargin: 30 } + NavigationButton { + id: galleryButton + text: qsTr("Gallery") + anchors.bottom: parent.bottom + anchors.bottomMargin: 10 + anchors.right: parent.right + anchors.rightMargin: 30 + } + NavigationButton { id: backButton text: qsTr("Back") @@ -201,6 +211,11 @@ Item { target: settingsButton visible: true } + + PropertyChanges { + target: galleryButton + visible: true + } }, State { name: "IconSelected" @@ -229,6 +244,11 @@ Item { target: settingsButton visible: false } + + PropertyChanges { + target: galleryButton + visible: false + } } ] } diff --git a/qml/SettingsPopupForm.ui.qml b/qml/SettingsPopupForm.ui.qml index 2022220..ad7d5fe 100644 --- a/qml/SettingsPopupForm.ui.qml +++ b/qml/SettingsPopupForm.ui.qml @@ -5,7 +5,7 @@ import QtQuick.Layouts 1.10 Popup { id: popup width: 400 - height: 500 + height: 600 property alias switchHideSnapshotSettings: switchHideSnapshotSettings property alias switchHideEffectPopup: switchHideEffectPopup property alias switchMultiplePrints: switchMultiplePrints @@ -19,11 +19,13 @@ Popup { property alias buttonDeletePhotos: buttonDeletePhotos property alias buttonClose: buttonClose property alias switchPrinter: switchPrinter + property alias switchPrintFromGallery: switchPrintFromGallery property alias buttonCopyPhotos: buttonCopyPhotos property alias buttonSetTime: buttonSetTime property alias switchMirrorCamera: switchMirrorCamera property alias comboBoxPrinter: comboBoxPrinter property alias comboBoxCamera: comboBoxCamera + property alias switchEnableSettingsPassword: switchEnableSettingsPassword property alias versionText: labelVersionText.text Button { @@ -232,6 +234,22 @@ Popup { text: qsTr("enabled") } } + + Row { + id: printFromGallery + spacing: 5 + Label { + id: labelPrintFromGallery + text: qsTr("Allow prints from Gallery") + anchors.verticalCenter: switchPrintFromGallery.verticalCenter + horizontalAlignment: Text.AlignLeft + } + + Switch { + id: switchPrintFromGallery + text: qsTr("enabled") + } + } } } @@ -241,6 +259,23 @@ Popup { Column { spacing: 5 + Row + { + spacing: 5 + + Label { + id: labelEnableSettingsPassword + text: qsTr("Enable Settings Password:") + anchors.verticalCenter: switchEnableSettingsPassword.verticalCenter + horizontalAlignment: Text.AlignLeft + } + + Switch { + id: switchEnableSettingsPassword + text: qsTr("enabled") + } + } + Row { spacing: 5 diff --git a/qml/SnapshotMenu.qml b/qml/SnapshotMenu.qml index 1cae643..8cf5bea 100644 --- a/qml/SnapshotMenu.qml +++ b/qml/SnapshotMenu.qml @@ -4,11 +4,25 @@ import GPIO 1.0 SnapshotMenuForm { id: form + property bool snapshotTimeoutEnable : false + signal captured(string filename) signal abort countdown: snapshotSettings.countdown + Timer + { + id: snapshotTimeoutTimer + interval: 1000 * 60 * 10 //going inactive after 10 minutes + onTriggered: + { + console.log("Snapshot timeout return to main menu") + snapshotTimeoutTimer.stop() + abort() + } + } + cameraRenderer.onPhotoProcessingChanged: { console.log("photo processing: " + Boolean(cameraRenderer.photoProcessing).toString()) @@ -23,6 +37,19 @@ SnapshotMenuForm { value: 0.0 } + onSnapshotTimeoutEnableChanged: + { + if(state == "activated" && snapshotTimeoutEnable == true) + { + snapshotTimeoutTimer.start() + console.log("Snapshot timeout timer started") + } + else + { + snapshotTimeoutTimer.stop() + } + } + onStateChanged: { console.log("Snapshot menu state changed: " + state) @@ -32,6 +59,16 @@ SnapshotMenuForm { } else { + if(state == "activated" && snapshotTimeoutEnable == true) + { + snapshotTimeoutTimer.start() + console.log("Snapshot timeout timer started") + } + else + { + snapshotTimeoutTimer.stop() + } + shutterButton.reset() ledEnablePin.value = 1.0 } diff --git a/qml/content/CollageRenderer.qml b/qml/content/CollageRenderer.qml index d53bf4d..bf56f51 100644 --- a/qml/content/CollageRenderer.qml +++ b/qml/content/CollageRenderer.qml @@ -11,6 +11,7 @@ Item { property int imagesLoading : 0 signal collageFull(bool full) + signal collageImagesChanged(int count) Rectangle { @@ -57,10 +58,11 @@ Item { y: imageRect.y * backgroundRect.height + (renderer.height - backgroundRect.height) / 2 width: imageRect.width * backgroundRect.width height: imageRect.height * backgroundRect.height + transform: Rotation { origin.x: width/2; origin.y: height/2; axis { x: 0; y: 0; z: 1 } angle: imageRotation } Component.onCompleted: { - console.log("Picture placed at: " + Number(x).toString() + " " + Number(y).toString()) + console.log("Picture placed at: " + Number(x).toString() + " " + Number(y).toString() + " Rotation: " + Number(rotation).toString()) } onImageSourceChanged: @@ -132,6 +134,12 @@ Item { collageFull(full) console.log("Collage Full Changed to " + Boolean(full).toString()); } + + onCountImagePathSetChanged: + { + collageImagesChanged(count) + console.log("Images in model set: " + Number(count).toString()); + } } function saveImage(filename, size) @@ -155,8 +163,18 @@ Item { // TODO clip the image and bringing everything into right format... renderer.grabToImage(function(result) { - result.saveToFile(filename, Qt.size(backgroundRect.width, backgroundRect.height)); - savedFilename = filename; + if (result) { + console.log("Image grabbed with size " + result.image.width + "x" + result.image.height + " successfully"); + var success = result.saveToFile(filename); + if (success) { + console.log("Image saved successfully to " + filename); + savedFilename = filename; + } else { + console.log("Failed to save image to " + filename); + } + } else { + console.log("Failed to grab image"); + } saving = false; }, size); } diff --git a/qml/content/DelegateGalleryItem.qml b/qml/content/DelegateGalleryItem.qml new file mode 100644 index 0000000..2036d31 --- /dev/null +++ b/qml/content/DelegateGalleryItem.qml @@ -0,0 +1,288 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 +import QtQml 2.14 +import QtGraphicalEffects 1.0 +import QtQuick.Controls.Material 2.0 +import "../scripts/utils.js" as Script +import "../styles" as Style + +Package { + + signal printImage(string filename) + + Item { Package.name: 'grid' + id: gridDelegate + width: root.width; height: root.height + } + Item { Package.name: 'list' + id: fullDelegate + width: root.width; height: root.height + } + +// =================================================== + + Item { + width: 160; height: 153 + + Item { + id: photoWrapper + + x: 0; y: 0 + width: 280; height: 266 + + /*BorderImage { + anchors.fill: placeHolder + anchors { + leftMargin: -15 + topMargin: -10 + rightMargin: -15 + bottomMargin: -15 + } + source: '../../images/polaroid.svg.png' + border { + top: 25 + left: 25 + right: 25 + bottom: 65 + } + }*/ + + Rectangle { + id: placeHolder + + property int w: 280 + property int h: 180 + property double s: Script.calculateScale(w, h, photoWrapper.width) + + color: 'white' + anchors.centerIn: parent + antialiasing: true + width: w * s; height: h * s; z: -1 + visible: originalImage.status != Image.Ready + Rectangle { + color: "#878787" + antialiasing: true + anchors { + fill: parent + topMargin: 3 + bottomMargin: 3 + leftMargin: 3 + rightMargin: 3 + } + } + } + + BusyIndicator { + anchors.centerIn: parent + running: originalImage.status != Image.Ready + } + Image { + id: originalImage + + sourceSize.width: 256 //save memory + sourceSize.height: 256 + + asynchronous: true + cache: true + anchors.fill: photoWrapper + antialiasing: true + source: foldermodel.folder + "/" + fileName + + fillMode: Image.PreserveAspectFit + } + ProgressBar { + anchors.centerIn: parent + visible: hqImage.status == Image.Loading + value: hqImage.progress + //style: Style.RoundProgressBarStyle {} + } + Image { + id: hqImage + + sourceSize.width: 1024 + sourceSize.height: 1024 + + asynchronous: true + cache: false + anchors.fill: photoWrapper + antialiasing: true + source: "" + visible: false + fillMode: Image.PreserveAspectFit + + onSourceChanged: { + console.log("hqImage source:", source) + } + + Row { + id: printButtonRow + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + + spacing: 10 + + visible: applicationSettings.printFromGallery && applicationSettings.printEnable + + layer.enabled: true + layer.effect: Glow { + color: "black" + samples: 20 + spread: 0.3 + } + + Text { + id: textLabel + color: "#ffffff" + text: galleryForm.printer ? (!galleryForm.printer.busy ? qsTr("Print") : qsTr("Printer busy")) : qsTr("Printer busy") + font.family: "DejaVu Serif" + wrapMode: Text.WrapAnywhere + font.pixelSize: 64 + font.capitalization: Font.AllUppercase + } + + ToolButton { + id: printButton + text: "\uE802" // icon-print + font.family: "fontello" + font.pixelSize: 64 + enabled: galleryForm.printer ? !galleryForm.printer.busy : false + + scale: hovered ? 1.1 : 1 + + layer.enabled: true + layer.effect: Glow { + color: "black" + samples: 20 + spread: 0.3 + } + + onClicked: + { + console.log("Print image: " + hqImage.source) + printImage(hqImage.source) + root.state = 'inGrid' + galleryForm.exitGallery() + } + } + } + + NavigationButton + { + id: closeButton + + anchors.right: hqImage.right + anchors.top: hqImage.top + anchors.rightMargin: 20 + anchors.topMargin: 20 + + text: qsTr("Overview") + + onClicked: + { + + root.state = 'inGrid' + } + } + + BusyIndicator { + anchors.centerIn: parent + running: hqImage.status != Image.Ready + } + + } + + Binding { + target: root + property: "imageLoading" + value: (hqImage.status == Image.Loading) ? 1 : 0; + when: fullDelegate.ListView.isCurrentItem + restoreMode: Binding.RestoreBinding + } + + MouseArea { + anchors.fill: photoWrapper + z: root.state == 'inGrid' ? 0 : -1 + onClicked: { + gridDelegate.GridView.view.currentIndex = index; + if (root.state == 'inGrid') { + root.state = 'fullscreen' + } + } + } + + states: [ + State { + name: 'inGrid'; when: root.state == 'inGrid' || root.state == '' + ParentChange { + target: photoWrapper + parent: gridDelegate; + x: 10; y: 0 + } + PropertyChanges { + target: exitButton + visible: true + } + }, + State { + name: 'fullscreen'; when: root.state == 'fullscreen' + ParentChange { + target: photoWrapper + parent: fullDelegate + x: 0; y: 0; + width: root.width; height: root.height + } + PropertyChanges { + target: hqImage + source: gridDelegate.GridView.isCurrentItem + ? foldermodel.folder + "/" + fileName + : "" + visible: true + } + PropertyChanges { + target: exitButton + visible: false + } + } + ] + + onStateChanged: { + if(state == 'fullscreen' && gridDelegate.GridView.isCurrentItem) + console.log("State changed to 'fullscreen' for '"+fileName+"' record") + } + + transitions: [ + Transition { + from: 'inGrid'; to: 'fullscreen' + SequentialAnimation { + PauseAnimation { + duration: gridDelegate.GridView.isCurrentItem ? 0 : 600 + } + ParentAnimation { + target: photoWrapper; via: foreground + NumberAnimation { + targets: photoWrapper + properties: 'x,y,width,height,opacity' + duration: gridDelegate.GridView.isCurrentItem ? 600 : 1 + easing.type: Easing.OutQuart + } + } + } + }, + Transition { + from: 'fullscreen'; to: 'inGrid' + ParentAnimation { + target: photoWrapper; via: foreground + NumberAnimation { + targets: photoWrapper + properties: 'x,y,width,height,opacity' + duration: gridDelegate.GridView.isCurrentItem ? 600 : 1 + easing.type: Easing.OutQuart + } + } + } + ] + } + } +} diff --git a/qml/scripts/utils.js b/qml/scripts/utils.js index 53685f5..28c2993 100644 --- a/qml/scripts/utils.js +++ b/qml/scripts/utils.js @@ -1,3 +1,17 @@ +.pragma library + +function calculateScale(width, height, cellSize) { + var widthScale = (cellSize * 1.0) / width + var heightScale = (cellSize * 1.0) / height + var scale = 0 + + if (widthScale <= heightScale) { + scale = widthScale; + } else if (heightScale < widthScale) { + scale = heightScale; + } + return scale; +} function shuffle(model){ var currentIndex = model.count, temporaryValue, randomIndex; diff --git a/qml/styles/RoundProgressBarStyle.qml b/qml/styles/RoundProgressBarStyle.qml new file mode 100644 index 0000000..a087c7f --- /dev/null +++ b/qml/styles/RoundProgressBarStyle.qml @@ -0,0 +1,56 @@ +import QtQuick 2.5 +import QtQuick.Controls.Styles 1.4 +import QtGraphicalEffects 1.0 + +ProgressBarStyle +{ + panel : Rectangle { + color: "transparent" + implicitWidth: 80 + implicitHeight: implicitWidth + + Rectangle + { + id: outerRing + z: 0 + anchors.fill: parent + radius: Math.max(width, height) / 2 + color: "transparent" + border.color: "gray" + border.width: 8 + } + + Rectangle + { + id: innerRing + z: 1 + anchors.fill: parent + anchors.margins: (outerRing.border.width - border.width) / 2 + radius: outerRing.radius + color: "transparent" + border.color: "darkgray" + border.width: 4 + + ConicalGradient + { + source: innerRing + anchors.fill: parent + gradient: Gradient + { + GradientStop { position: 0.00; color: "white" } + GradientStop { position: control.value; color: "white" } + GradientStop { position: control.value + 0.01; color: "transparent" } + GradientStop { position: 1.00; color: "transparent" } + } + } + } + + Text + { + id: progressLabel + anchors.centerIn: parent + color: "gray" + text: (control.value * 100).toFixed() + "%" + } + } +} diff --git a/src/abstractprinter.h b/src/abstractprinter.h index 85e7b75..a71cf48 100644 --- a/src/abstractprinter.h +++ b/src/abstractprinter.h @@ -18,7 +18,6 @@ class AbstractPrinter : public QObject Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) public: explicit AbstractPrinter(QObject *parent = nullptr) : QObject(parent) {}; - Q_INVOKABLE virtual QSize getPrintSize() = 0; Q_INVOKABLE virtual bool printerOnline() = 0; virtual bool busy() = 0; signals: diff --git a/src/call_once.h b/src/call_once.h index d882c48..9be2c48 100644 --- a/src/call_once.h +++ b/src/call_once.h @@ -9,13 +9,13 @@ #include namespace CallOnce { - enum ECallOnce { - CO_Request, - CO_InProgress, - CO_Finished - }; +enum ECallOnce { + CO_Request, + CO_InProgress, + CO_Finished +}; - Q_GLOBAL_STATIC(QThreadStorage, once_flag) +Q_GLOBAL_STATIC(QThreadStorage, once_flag) } template @@ -32,7 +32,7 @@ inline static void qCallOnce(Function func, QBasicAtomicInt& flag) if (protectFlag == CO_Finished) return; if (protectFlag == CO_Request && flag.testAndSetRelaxed(protectFlag, - CO_InProgress)) { + CO_InProgress)) { func(); flag.fetchAndStoreRelease(CO_Finished); } diff --git a/src/collageiconmodel.cpp b/src/collageiconmodel.cpp index dd6c7df..2f670ce 100644 --- a/src/collageiconmodel.cpp +++ b/src/collageiconmodel.cpp @@ -138,11 +138,11 @@ void CollageIconModel::clear() QString CollageIconModel::getIconName(int index) { - if (index < 0 || index >= mIcons.count()) - return QString(); + if (index < 0 || index >= mIcons.count()) + return QString(); - const CollageIcon &icon = mIcons[index]; - return icon.name(); + const CollageIcon &icon = mIcons[index]; + return icon.name(); } bool CollageIconModel::showPrintable() const diff --git a/src/collageiconmodel.h b/src/collageiconmodel.h index acfd534..ae8a982 100644 --- a/src/collageiconmodel.h +++ b/src/collageiconmodel.h @@ -30,9 +30,9 @@ class CollageIconModel : public QAbstractListModel Q_PROPERTY(bool showPrintable READ showPrintable WRITE setShowPrintable NOTIFY showPrintableChanged) public: enum IconRoles { - NameRole = Qt::UserRole + 1, - IconRole, - PrintableRole + NameRole = Qt::UserRole + 1, + IconRole, + PrintableRole }; CollageIconModel(QObject *parent = 0); diff --git a/src/collageimagemodel.cpp b/src/collageimagemodel.cpp index 7085dce..e473e78 100644 --- a/src/collageimagemodel.cpp +++ b/src/collageimagemodel.cpp @@ -1,5 +1,7 @@ #include "collageimagemodel.h" #include "collagemodelfactory.h" +#include +#include CollageImageModel::CollageImageModel(QObject *parent) : QAbstractListModel(parent) { @@ -37,6 +39,12 @@ bool CollageImageModel::parseXml(const QDomNode& node) mLine = element.lineNumber(); return false; } + else + { + mErrorMsg = "at least one background nodes required"; + mLine = element.lineNumber(); + return false; + } QDomNodeList foregroundNode = element.elementsByTagName("foreground"); if(foregroundNode.count() == 1) @@ -50,6 +58,44 @@ bool CollageImageModel::parseXml(const QDomNode& node) return false; } + QDomElement sizeElement = element.firstChildElement("size"); + if(sizeElement.isElement()) + { + if(sizeElement.hasAttributes() && sizeElement.toElement().hasAttribute("width") && sizeElement.toElement().hasAttribute("height")) + { + bool ok; + QString x = sizeElement.toElement().attribute("width"); + mPixelSize.setWidth(x.toInt(&ok)); + if(!ok) + { + mErrorMsg = "size 'width' must be defined as float"; + mLine = sizeElement.lineNumber(); + return false; + } + + QString y = sizeElement.toElement().attribute("height"); + mPixelSize.setHeight(y.toInt(&ok)); + if(!ok) + { + mErrorMsg = "size 'height' must be defined as float"; + mLine = sizeElement.lineNumber(); + return false; + } + } + else + { + mErrorMsg = "size must be defined be 'width' and 'height' attributes"; + mLine = sizeElement.lineNumber(); + return false; + } + } + else + { + mErrorMsg = "at least one size nodes required"; + mLine = element.lineNumber(); + return false; + } + QDomNodeList imagesNode = element.elementsByTagName("images"); if(imagesNode.length() != 1) { @@ -72,7 +118,7 @@ bool CollageImageModel::parseXml(const QDomNode& node) for(int i = 0; i < imageNodes.length(); i++) { bool result; - CollageImage* image = new CollageImage(); + CollageImage* image = new CollageImage(mPixelSize); result = image->parseXml(imageNodes.item(i)); if(!result) { @@ -119,7 +165,7 @@ QHash CollageImageModel::roleNames() const { QHash roles; roles[ImageRectRole] = "imageRect"; - roles[RotationRole] = "rotation"; + roles[RotationRole] = "imageRotation"; roles[ImagePathRole] = "imagePath"; roles[BorderImageRole] = "borderImage"; roles[BorderRectRole] = "borderRect"; @@ -158,6 +204,7 @@ bool CollageImageModel::addImagePath(QUrl source, QString effect) } QModelIndex ii = index(i,0); emit dataChanged(ii, ii); + emit countImagePathSetChanged(countImagePathSet()); if(collageFull()) { emit collageFullChanged(true); @@ -177,6 +224,7 @@ void CollageImageModel::clearImagePathes() } emit collageFullChanged(false); + emit countImagePathSetChanged(0); emit dataChanged(this->index(0,0),this->index(rowCount()-1,0)); } @@ -212,6 +260,7 @@ bool CollageImageModel::clearImagePath(int index) } #endif emit dataChanged(this->index(0,0),this->index(rowCount()-1,0)); + emit countImagePathSetChanged(countImagePathSet()); return true; } else { @@ -231,6 +280,11 @@ bool CollageImageModel::collageFull() return false; } +QSize CollageImageModel::collagePixelSize() const +{ + return mPixelSize; +} + bool CollageImageModel::nextImageIsEffectSelectable() { if(!collageFull()) @@ -274,7 +328,7 @@ int CollageImageModel::countImagePathSet() const return currentCount; } -CollageImage::CollageImage(QObject *parent) : QObject(parent), mEffect("") +CollageImage::CollageImage(QSize collagePixelSize, QObject *parent) : QObject(parent), mEffect(""), mCollagePixelSize(collagePixelSize) { } @@ -370,6 +424,25 @@ bool CollageImage::parseXml(const QDomNode &node) return false; } + QDomNodeList rotationNode = element.elementsByTagName("rotation"); + if(rotationNode.count() == 1) + { + bool ok; + mAngle = rotationNode.item(0).toElement().text().toFloat(&ok); + if(!ok) + { + mErrorMsg = "rotation must be defined as float"; + mLine = rotationNode.item(0).lineNumber(); + return false; + } + } + else if(rotationNode.count() > 1) + { + mErrorMsg = "multiple rotations are defined"; + mLine = element.lineNumber(); + return false; + } + QDomNodeList borderImageNode = element.elementsByTagName("border"); if(borderImageNode.count() == 1) { @@ -389,10 +462,10 @@ bool CollageImage::parseXml(const QDomNode &node) if(borderMarginNode.count() == 1) { if(borderMarginNode.item(0).hasAttributes() && - borderMarginNode.item(0).toElement().hasAttribute("top") && - borderMarginNode.item(0).toElement().hasAttribute("left") && - borderMarginNode.item(0).toElement().hasAttribute("right") && - borderMarginNode.item(0).toElement().hasAttribute("bottom")) + borderMarginNode.item(0).toElement().hasAttribute("top") && + borderMarginNode.item(0).toElement().hasAttribute("left") && + borderMarginNode.item(0).toElement().hasAttribute("right") && + borderMarginNode.item(0).toElement().hasAttribute("bottom")) { bool ok; QString top = borderMarginNode.item(0).toElement().attribute("top"); @@ -540,25 +613,38 @@ bool CollageImage::validateBoundary() { //test position and size parameter bool result = true; - if(mImageRect.x() < 0 || mImageRect.x() > 1.0) + + // scale image rect to pixels + QRectF imageRect(mImageRect.x()*mCollagePixelSize.width(), mImageRect.y()*mCollagePixelSize.height(), mImageRect.width()*mCollagePixelSize.width(), mImageRect.height()*mCollagePixelSize.height()); + // get center of rect + QPointF center = imageRect.center(); + // rotate around center + QTransform transform; + transform.translate(center.x(), center.y()); + transform.rotate(mAngle); + transform.translate(-center.x(), -center.y()); + imageRect = transform.mapRect(imageRect); + qDebug() << "Bounding box of image: " << imageRect; + + // now check if image will fit into collage + if(imageRect.x() < -std::numeric_limits::epsilon()|| imageRect.x() > mCollagePixelSize.width()) { result = false; } - if(mImageRect.y() < 0 || mImageRect.x() > 1.0) + if(imageRect.y() < -std::numeric_limits::epsilon() || imageRect.y() > mCollagePixelSize.height()) { result = false; } - if((mImageRect.x() + mImageRect.width()) > 1.0 || mImageRect.width() < 0) + if((imageRect.x() + imageRect.width()) > (mCollagePixelSize.width() + std::numeric_limits::epsilon() )|| imageRect.width() < 0) { result = false; } - if((mImageRect.y() + mImageRect.height()) > 1.0 || mImageRect.height() < 0) + if((imageRect.y() + imageRect.height()) > (mCollagePixelSize.height() + std::numeric_limits::epsilon()) || imageRect.height() < 0) { result = false; } - //TODO: Validate Border - //TODO: Validate with rotation + //@TODO: Validate Border return result; } diff --git a/src/collageimagemodel.h b/src/collageimagemodel.h index c038818..633355f 100644 --- a/src/collageimagemodel.h +++ b/src/collageimagemodel.h @@ -21,7 +21,7 @@ class CollageImage : public QObject, public ModelParser Q_PROPERTY(QString effectPreset READ effectPreset CONSTANT) Q_PROPERTY(QString effect READ effect NOTIFY effectChanged) public: - CollageImage(QObject* parent = nullptr); + CollageImage(QSize collagePixelSize, QObject* parent = nullptr); bool parseXml(const QDomNode& node) override; QUrl imagePath() const; QRectF imageRect() const; @@ -47,15 +47,17 @@ class CollageImage : public QObject, public ModelParser bool mEffectSelectable = true; QString mEffectPreset = ""; QString mEffect = ""; + const QSize mCollagePixelSize; }; class CollageImageModel : public QAbstractListModel, public ModelParser { Q_OBJECT - Q_PROPERTY(QUrl backgroundImage READ backgroundImage NOTIFY backgroundImageChanged) - Q_PROPERTY(QUrl foregroundImage READ foregroundImage NOTIFY foregroundImageChanged) - Q_PROPERTY(int countImagePathSet READ countImagePathSet NOTIFY countImagePatchSetChanged) + Q_PROPERTY(QUrl backgroundImage READ backgroundImage) + Q_PROPERTY(QUrl foregroundImage READ foregroundImage) + Q_PROPERTY(int countImagePathSet READ countImagePathSet NOTIFY countImagePathSet) Q_PROPERTY(bool collageFull READ collageFull NOTIFY collageFullChanged) + Q_PROPERTY(QSize collagePixelSize READ collagePixelSize NOTIFY collagePixelSizeChanged) public: enum ImageRoles { ImagePathRole = Qt::UserRole + 1, @@ -81,16 +83,17 @@ class CollageImageModel : public QAbstractListModel, public ModelParser Q_INVOKABLE bool collageFull(); Q_INVOKABLE bool nextImageIsEffectSelectable(); Q_INVOKABLE QString nextImageEffectPreset(); + Q_INVOKABLE QSize collagePixelSize() const; int countImagePathSet() const; signals: - void backgroundImageChanged(const QUrl &image); - void foregroundImageChanged(const QUrl &image); - void countImagePatchSetChanged(const int &count); void collageFullChanged(bool full); + void countImagePathSetChanged(int count); + void collagePixelSizeChanged(QSize size); protected: QList mImages; QUrl mBackgroundImage; QUrl mForegroundImage; + QSize mPixelSize; }; #endif // COLLAGEIMAGEMODEL_H diff --git a/src/collagemodelfactory.cpp b/src/collagemodelfactory.cpp index a2eea51..5fab7d8 100644 --- a/src/collagemodelfactory.cpp +++ b/src/collagemodelfactory.cpp @@ -99,6 +99,7 @@ void CollageModelFactory::loadModels() { clearModels(); mStatus = Error; + qCritical("%s", QString("Parser Error: " + errorLineMsg()).toStdString().c_str()); errorMsgChanged(errorLineMsg()); statusChanged(mStatus); }else @@ -125,9 +126,9 @@ bool CollageModelFactory::parseXml(const QDomNode &node) if(rootElement.tagName() != "catalog") { - mErrorMsg = "Excepted 'catalog' root node"; - mLine = rootElement.lineNumber(); - return false; + mErrorMsg = "Excepted 'catalog' root node"; + mLine = rootElement.lineNumber(); + return false; } if(!rootElement.hasAttribute("version") || rootElement.attribute("version") != "1.0") diff --git a/src/fakeprinter.cpp b/src/fakeprinter.cpp index 58bf1d8..195646f 100644 --- a/src/fakeprinter.cpp +++ b/src/fakeprinter.cpp @@ -1,16 +1,13 @@ #include "fakeprinter.h" #include +#include +#include FakePrinter::FakePrinter(QObject *parent) : AbstractPrinter(parent) { QObject::connect(&mBusyTimer, SIGNAL(timeout()), this, SLOT(busyTimeout())); }; -QSize FakePrinter::getPrintSize() -{ - return QSize(3570,2380); //hard coded pixel size -} - bool FakePrinter::printerOnline() { return true; @@ -24,6 +21,11 @@ bool FakePrinter::busy() int FakePrinter::printImage(const QString &filename, int copyCount) { qDebug() << "Fake printer starts printing " << copyCount << " copies." << filename; + QTime dieTime= QTime::currentTime().addSecs(1); + while (QTime::currentTime() < dieTime) + { + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } mBusyTimer.start(1000 * 30); // 30 seconds; emit busyChanged(true); return 0; diff --git a/src/fakeprinter.h b/src/fakeprinter.h index 029b5ad..5e2d179 100644 --- a/src/fakeprinter.h +++ b/src/fakeprinter.h @@ -10,7 +10,6 @@ class FakePrinter : public AbstractPrinter, public PrinterList Q_OBJECT Q_INTERFACES(AbstractPrinter) public: - QSize getPrintSize() override; bool printerOnline() override; bool busy() override; int printImage(const QString &filename, int copyCount) override; diff --git a/src/fileio.cpp b/src/fileio.cpp index 6a45be5..533a2fb 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -13,7 +13,7 @@ QByteArray FileIO::read() } else { - file.setFileName(mSource.toLocalFile()); + file.setFileName(mSource.toLocalFile()); } if (!file.open(QIODevice::ReadOnly)) diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 2a8c096..00d7b05 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -140,7 +140,7 @@ void FileSystem::startCopyFilesToRemovableDrive() int progress = (100 * i + 1) / files.count(); qDebug() << "Copy file: " << imagePath + "/" + files[i] << " to: " << removableDrivePath + "/" + files[i] << " Progress: " << progress; if(QFile::exists(removableDrivePath + "/" + files[i])) - QFile::remove(removableDrivePath + "/" + files[i]); + QFile::remove(removableDrivePath + "/" + files[i]); if(!QFile::copy(imagePath + "/" + files[i], removableDrivePath + "/" + files[i])) { diff --git a/src/main.cpp b/src/main.cpp index 81e8228..dd55f16 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,79 @@ #include "fileio.h" #include "filesystem.h" #include "system.h" +#include + +//some constants to parameterize. +const qint64 LOG_FILE_LIMIT = 3000000; +const QString LOG_PATH = "/logs/"; +const QString LOG_FILENAME = "qtbooth.log"; + +//thread safety +QMutex mutex; + +void redirectDebugMessages(QtMsgType type, const QMessageLogContext & context, const QString & str) +{ + //thread safety + mutex.lock(); + QString txt; + + //prepend timestamp to every message + QString datetime = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); + //prepend a log level label to every message + switch (type) { + case QtDebugMsg: + txt = QString("[Debug*] "); + break; + case QtWarningMsg: + txt = QString("[Warning] "); + break; + case QtInfoMsg: + txt = QString("[Info] "); + break; + case QtCriticalMsg: + txt = QString("[Critical] "); + break; + case QtFatalMsg: + txt = QString("[Fatal] "); + } + + QDir dir; + + QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + LOG_PATH; + + if (!dir.exists(filePath)) + dir.mkpath(filePath); // You can check the success if needed + + filePath = filePath + LOG_FILENAME; + + QFile outFile(filePath); + + //if file reached the limit, rotate to filename.1 + if(outFile.size() > LOG_FILE_LIMIT){ + //roll the log file. + QFile::remove(filePath + ".1"); + QFile::rename(filePath, filePath + ".1"); + QFile::resize(filePath, 0); + } + + //write message + outFile.open(QIODevice::WriteOnly | QIODevice::Append); + QTextStream ts(&outFile); + ts << datetime << txt << context.file << str << endl; + + if(context.file != nullptr && context.line != 0) + { + std::cout << datetime.toStdString() << " - " << txt.toStdString() << " - " << context.file << "(" << context.line << ") - " << str.toStdString() << std::endl; + } + else + { + std::cout << datetime.toStdString() << " - " << txt.toStdString() << " - " << str.toStdString() << std::endl; + } + + //close fd + outFile.close(); + mutex.unlock(); +} int main(int argc, char *argv[]) { @@ -27,6 +100,8 @@ int main(int argc, char *argv[]) QGuiApplication::setOrganizationDomain("github.com"); QGuiApplication::setApplicationName("qtbooth"); + qInstallMessageHandler(redirectDebugMessages); + QFontDatabase fontDatabase; if (fontDatabase.addApplicationFont(":/font/fontello/fontello.ttf") == -1) qWarning() << "Failed to load fontello.ttf"; diff --git a/src/noprinter.cpp b/src/noprinter.cpp index 0253ffc..3378027 100644 --- a/src/noprinter.cpp +++ b/src/noprinter.cpp @@ -1,10 +1,5 @@ #include "noprinter.h" -QSize NoPrinter::getPrintSize() -{ - return QSize(3570,2380); //hard coded pixel size -} - bool NoPrinter::printerOnline() { return false; diff --git a/src/noprinter.h b/src/noprinter.h index 0cfd6c5..bf9cb74 100644 --- a/src/noprinter.h +++ b/src/noprinter.h @@ -9,7 +9,6 @@ class NoPrinter : public AbstractPrinter, public PrinterList Q_OBJECT Q_INTERFACES(AbstractPrinter) public: - QSize getPrintSize() override; bool printerOnline() override; bool busy() override; int printImage(const QString &filename, int copyCount) override; diff --git a/src/selphyprinter.cpp b/src/selphyprinter.cpp index dca7253..458dd7d 100644 --- a/src/selphyprinter.cpp +++ b/src/selphyprinter.cpp @@ -41,17 +41,21 @@ bool SelphyPrinter::printerOnline() } } - -QSize SelphyPrinter::getPrintSize() -{ - return QSize(3570,2380); //hard coded pixel size -} - int SelphyPrinter::printImage(const QString &filename, int copyCount) { if(mIp.length() > 0) { - QString imageMagickCommand = "convert " + filename + " -quality 100% " + filename + ".jpg"; + QString imageMagickCommand; + if(filename.endsWith(".jpg") || filename.endsWith(".jpg")) + { + imageMagickCommand = ":"; // file is already a JPG. No conversion to be done + } + else + { + // file is not a JPG. First convert to JPG. + imageMagickCommand = "convert " + filename + " -quality 100% " + filename + ".jpg && rm " + filename; + } + QString selphyCommand = "selphy -printer_ip=" + mIp + " " + filename + ".jpg"; QString printCommand = imageMagickCommand; for(int i = 0; i < copyCount; i++) @@ -68,7 +72,7 @@ int SelphyPrinter::printImage(const QString &filename, int copyCount) { emit busyChanged(true); mPrinterProcess.start("sh", shParameters); - qDebug() << shParameters; + qDebug() << "Runnings sh with parameters: " << shParameters; return 0; } else diff --git a/src/selphyprinter.h b/src/selphyprinter.h index cb13f45..8a400a0 100644 --- a/src/selphyprinter.h +++ b/src/selphyprinter.h @@ -10,7 +10,6 @@ class SelphyPrinter : public AbstractPrinter, public PrinterList Q_OBJECT Q_INTERFACES(AbstractPrinter) public: - Q_INVOKABLE QSize getPrintSize(); Q_INVOKABLE bool printerOnline(); bool busy(); public slots: diff --git a/src/standardprinter.cpp b/src/standardprinter.cpp index 4411792..3143e48 100644 --- a/src/standardprinter.cpp +++ b/src/standardprinter.cpp @@ -3,11 +3,6 @@ #include #include -QSize StandardPrinter::getPrintSize() -{ - return QSize(3570,2380); //hard coded pixel size @TODO -} - bool StandardPrinter::printerOnline() { return true; //cannot determine online state @TODO @@ -68,11 +63,11 @@ StandardPrinter *StandardPrinter::createInternal(const QString &name) auto printers = QPrinterInfo::availablePrinters(); for(auto printer: printers) { - if(printer.printerName() == name) - { + if(printer.printerName() == name) + { ptr = new StandardPrinter(printer); break; - } + } } return ptr; } diff --git a/src/standardprinter.h b/src/standardprinter.h index 0fd0c1e..a1ae9a9 100644 --- a/src/standardprinter.h +++ b/src/standardprinter.h @@ -11,7 +11,6 @@ class StandardPrinter : public AbstractPrinter, public PrinterList Application - + QML Photo Booth QML Photo Booth @@ -12,17 +12,22 @@ CollageMenuForm.ui - + Print Drucken - + + Save + Speichern + + + Next Photo Nächstes Foto - + Exit Zurück @@ -35,6 +40,24 @@ Lächeln + + DelegateGalleryItem + + + Print + Drucken + + + + Printer busy + Drucker beschâftigt + + + + Overview + Übersicht + + EffectList @@ -98,6 +121,24 @@ Gelbfilter + + GalleryMenuForm.ui + + + Photos + Fotos + + + + Collages + Collagen + + + + Exit + Zurück + + ImagePreviewForm.ui @@ -114,12 +155,17 @@ MainMenuForm.ui - + Continue Weiter - + + Gallery + Gallerie + + + Back Zurück @@ -159,8 +205,8 @@ SettingsPopup - - + + Time: Zeit: @@ -168,143 +214,160 @@ SettingsPopupForm.ui - + Close Schließen - + Settings Einstellungen - + Photos Fotos - + Camera Kamera - + Printer Drucker - + System System - + Copy photos to removable disk Kopiere Fotos auf USB Stick - + Delete all photos Alls Fotos löschen - + + Camera: + Kamera: + + + Mirror Camera Kamera spiegeln - + mirror spiegeln - + Snapshot Settings Schnappschusseinstellungen - + hide verstecken - + Effect Popup Effekte Popuo - + disable deaktivieren - + Enable Printing Druck aktivieren - - + + + + enabled aktiviert - + Printer: Drucker: - + Allow multiple prints Erlaube mehrere Ausdrucke - + + Allow prints from Gallery + Erlaube Drucken aus Gallery + + + + Enable Settings Password: + Aktiviere Einstellungspasswort: + + + Current time Eingestellte Zeit - + Set time Setze Zeit - + Language: Sprache: - + Window Mode: Fenster Modus: - + Window Fenster - + Fullscreen Vollbildschirm - + Copy layout templates from removable disk Kopiere Vorlage von USB Stick - + Shutdown Herunterfahren - + Restart Neustart - + Exit Photobooth Photobooth schließen