├── .gitignore ├── LICENSE ├── README.md ├── harbour-advanced-camera.desktop ├── harbour-advanced-camera.pro ├── harbour-advanced-camera.svg ├── icons ├── 108x108 │ └── harbour-advanced-camera.png ├── 128x128 │ └── harbour-advanced-camera.png ├── 172x172 │ └── harbour-advanced-camera.png └── 86x86 │ └── harbour-advanced-camera.png ├── qml ├── components │ ├── AboutMedia.qml │ ├── DockedListView.qml │ ├── IconSwitch.qml │ └── RoundButton.qml ├── cover │ └── CoverPage.qml ├── harbour-advanced-camera.qml ├── pages │ ├── AboutImage.qml │ ├── AboutVideo.qml │ ├── CameraUI.qml │ ├── GalleryUI.qml │ ├── GridOverlay.qml │ ├── Settings.qml │ ├── SettingsOverlay.qml │ └── VideoPlayer.qml └── pics │ ├── icon-camera-focus-continuous.png │ ├── icon-camera-focus-hyperfocal.png │ ├── icon-camera-focus-manual.png │ ├── icon-m-effect-aqua.svg │ ├── icon-m-effect-blackboard.svg │ ├── icon-m-effect-default.svg │ ├── icon-m-effect-emboss.svg │ ├── icon-m-effect-grayscale.svg │ ├── icon-m-effect-negative.svg │ ├── icon-m-effect-neon.svg │ ├── icon-m-effect-none.svg │ ├── icon-m-effect-posterize.svg │ ├── icon-m-effect-sepia.svg │ ├── icon-m-effect-sketch.svg │ ├── icon-m-effect-solarize.svg │ ├── icon-m-effect-whiteboard.svg │ ├── icon-m-effect.png │ ├── icon-m-iso-100.png │ ├── icon-m-iso-1600.png │ ├── icon-m-iso-200.png │ ├── icon-m-iso-3200.png │ ├── icon-m-iso-400.png │ ├── icon-m-iso-6400.png │ ├── icon-m-iso-800.png │ ├── icon-m-iso-auto.png │ ├── icon-m-iso-hjr.png │ ├── icon-m-resolution.png │ ├── icon-m-scene_mode_action.svg │ ├── icon-m-scene_mode_ar.svg │ ├── icon-m-scene_mode_asd.svg │ ├── icon-m-scene_mode_backlight.svg │ ├── icon-m-scene_mode_barcode.svg │ ├── icon-m-scene_mode_beach.svg │ ├── icon-m-scene_mode_candlelight.svg │ ├── icon-m-scene_mode_fireworks.svg │ ├── icon-m-scene_mode_flowers.svg │ ├── icon-m-scene_mode_hdr.svg │ ├── icon-m-scene_mode_landscape.svg │ ├── icon-m-scene_mode_large_aperture.svg │ ├── icon-m-scene_mode_night.svg │ ├── icon-m-scene_mode_night_portrait.svg │ ├── icon-m-scene_mode_none.svg │ ├── icon-m-scene_mode_party.svg │ ├── icon-m-scene_mode_portrait.svg │ ├── icon-m-scene_mode_small_aperture.svg │ ├── icon-m-scene_mode_snow.svg │ ├── icon-m-scene_mode_sports.svg │ ├── icon-m-scene_mode_spotlight.svg │ ├── icon-m-scene_mode_steady_photo.svg │ ├── icon-m-scene_mode_sunset.svg │ ├── icon-m-scene_mode_theatre.svg │ ├── icon-m-scene_mode_unknown.svg │ ├── icon-m-tele-lense-active.png │ ├── icon-m-tele-lense.png │ ├── icon-m-tele-lense.svg │ ├── icon-m-uwide-lense-active.png │ ├── icon-m-uwide-lense.png │ ├── icon-m-uwide-lense.svg │ ├── icon-m-wide-lense-active.png │ ├── icon-m-wide-lense.png │ └── icon-m-wide-lense.svg ├── resolution.svg ├── rpm ├── harbour-advanced-camera.changes ├── harbour-advanced-camera.changes.run.in ├── harbour-advanced-camera.spec └── harbour-advanced-camera.yaml ├── screenshots ├── screenshot1.png ├── screenshot2.png ├── screenshot3.png ├── screenshot4.png ├── screenshot5.png └── screenshot6.png ├── src ├── deviceinfo.cpp ├── deviceinfo.h ├── effectsmodel.cpp ├── effectsmodel.h ├── exifmodel.cpp ├── exifmodel.h ├── exposuremodel.cpp ├── exposuremodel.h ├── flashmodel.cpp ├── flashmodel.h ├── focusmodel.cpp ├── focusmodel.h ├── fsoperations.cpp ├── fsoperations.h ├── harbour-advanced-camera.cpp ├── isomodel.cpp ├── isomodel.h ├── metadatamodel.cpp ├── metadatamodel.h ├── resolutionmodel.cpp ├── resolutionmodel.h ├── resourcehandler.cpp ├── resourcehandler.h ├── storagemodel.cpp ├── storagemodel.h ├── wbmodel.cpp └── wbmodel.h └── translations ├── harbour-advanced-camera-de.ts ├── harbour-advanced-camera-es.ts ├── harbour-advanced-camera-fi.ts ├── harbour-advanced-camera-fr.ts ├── harbour-advanced-camera-it.ts ├── harbour-advanced-camera-pl.ts ├── harbour-advanced-camera-ru.ts ├── harbour-advanced-camera-sv.ts ├── harbour-advanced-camera-zh_CN.ts └── harbour-advanced-camera.ts /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /RPMS 3 | harbour-advanced-camera.pro.user 4 | debugfiles.list 5 | debuglinks.list 6 | debugsourcefiles.list 7 | debugsources.list 8 | documentation.list 9 | elfbins.list 10 | harbour-advanced-camera 11 | Makefile 12 | *.o 13 | *.qm 14 | moc_*.cpp 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # harbour-advanced-camera 2 | 3 | This is a camera application for Sailfish which exposes all available camera paramters to the user. 4 | 5 | The application is licensed under the GPLv2+, with some source files specifically licensed under the LGPLv2(.1)+ so they can be re-used. 6 | -------------------------------------------------------------------------------- /harbour-advanced-camera.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | X-Nemo-Application-Type=silica-qt5 4 | Icon=harbour-advanced-camera 5 | Exec=harbour-advanced-camera 6 | Name=Advanced Camera 7 | # translation example: 8 | # your app name in German locale (de) 9 | # 10 | # Remember to comment out the following line, if you do not want to use 11 | # a different app name in German locale (de). 12 | #Name[de]=harbour-advanced-camera 13 | Name[ru]=Улучшенная камера 14 | 15 | [X-Sailjail] 16 | Permissions=Audio;Location;RemovableMedia;Pictures;Videos 17 | OrganizationName=uk.co.piggz 18 | ApplicationName=AdvancedCamera 19 | -------------------------------------------------------------------------------- /harbour-advanced-camera.pro: -------------------------------------------------------------------------------- 1 | # NOTICE: 2 | # 3 | # Application name defined in TARGET has a corresponding QML filename. 4 | # If name defined in TARGET is changed, the following needs to be done 5 | # to match new name: 6 | # - corresponding QML filename must be changed 7 | # - desktop icon filename must be changed 8 | # - desktop filename must be changed 9 | # - icon definition filename in desktop file must be changed 10 | # - translation filenames have to be changed 11 | 12 | # The name of your application 13 | TARGET = harbour-advanced-camera 14 | 15 | CONFIG += sailfishapp 16 | 17 | QT += multimedia 18 | 19 | SOURCES += src/harbour-advanced-camera.cpp \ 20 | src/deviceinfo.cpp \ 21 | src/effectsmodel.cpp \ 22 | src/exifmodel.cpp \ 23 | src/exposuremodel.cpp \ 24 | src/isomodel.cpp \ 25 | src/metadatamodel.cpp \ 26 | src/resolutionmodel.cpp \ 27 | src/wbmodel.cpp \ 28 | src/focusmodel.cpp \ 29 | src/flashmodel.cpp \ 30 | src/fsoperations.cpp \ 31 | src/resourcehandler.cpp \ 32 | src/storagemodel.cpp 33 | 34 | DISTFILES += \ 35 | README.md \ 36 | qml/pics/icon-m-tele-lense-active.png \ 37 | qml/pics/icon-m-tele-lense.svg \ 38 | qml/pics/icon-m-uwide-lense-active.png \ 39 | qml/pics/icon-m-uwide-lense.svg \ 40 | qml/pics/icon-m-wide-lense-active.png \ 41 | qml/pics/icon-m-wide-lense.svg \ 42 | qml/components/AboutMedia.qml \ 43 | qml/pages/AboutImage.qml \ 44 | qml/pages/AboutVideo.qml \ 45 | rpm/harbour-advanced-camera.changes.run.in \ 46 | rpm/harbour-advanced-camera.spec \ 47 | translations/*.ts \ 48 | harbour-advanced-camera.desktop \ 49 | qml/harbour-advanced-camera.qml \ 50 | qml/components/DockedListView.qml \ 51 | qml/components/IconSwitch.qml \ 52 | qml/components/RoundButton.qml \ 53 | qml/cover/CoverPage.qml \ 54 | qml/pages/CameraUI.qml \ 55 | qml/pages/GalleryUI.qml \ 56 | qml/pages/Settings.qml \ 57 | qml/pages/SettingsOverlay.qml 58 | 59 | 60 | SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172 61 | 62 | # to disable building translations every time, comment out the 63 | # following CONFIG line 64 | CONFIG += sailfishapp_i18n 65 | 66 | # German translation is enabled as an example. If you aren't 67 | # planning to localize your app, remember to comment out the 68 | # following TRANSLATIONS line. And also do not forget to 69 | # modify the localized app name in the the .desktop file. 70 | TRANSLATIONS += translations/harbour-advanced-camera-de.ts \ 71 | translations/harbour-advanced-camera-es.ts \ 72 | translations/harbour-advanced-camera-fi.ts \ 73 | translations/harbour-advanced-camera-fr.ts \ 74 | translations/harbour-advanced-camera-sv.ts \ 75 | translations/harbour-advanced-camera-zh_CN.ts 76 | 77 | HEADERS += \ 78 | src/effectsmodel.h \ 79 | src/exifmodel.h \ 80 | src/exposuremodel.h \ 81 | src/isomodel.h \ 82 | src/metadatamodel.h \ 83 | src/resolutionmodel.h \ 84 | src/wbmodel.h \ 85 | src/focusmodel.h \ 86 | src/flashmodel.h \ 87 | src/fsoperations.h \ 88 | src/resourcehandler.h \ 89 | src/storagemodel.h 90 | 91 | LIBS += -ldl 92 | -------------------------------------------------------------------------------- /icons/108x108/harbour-advanced-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/icons/108x108/harbour-advanced-camera.png -------------------------------------------------------------------------------- /icons/128x128/harbour-advanced-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/icons/128x128/harbour-advanced-camera.png -------------------------------------------------------------------------------- /icons/172x172/harbour-advanced-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/icons/172x172/harbour-advanced-camera.png -------------------------------------------------------------------------------- /icons/86x86/harbour-advanced-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/icons/86x86/harbour-advanced-camera.png -------------------------------------------------------------------------------- /qml/components/AboutMedia.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Layouts 1.0 3 | import Sailfish.Silica 1.0 4 | 5 | Rectangle { 6 | id: mediaInfo 7 | color: "black" 8 | anchors.fill: parent 9 | 10 | property var file 11 | property var fileSize 12 | property var mediaModel 13 | property var mediaSize 14 | property var mediaDuration: "" 15 | 16 | SilicaListView { 17 | anchors.fill: parent 18 | anchors.margins: Theme.paddingSmall 19 | model: mediaModel 20 | header: PageHeader { 21 | title: file 22 | description: mediaDuration + " " + mediaSize + " " + fileSize 23 | } 24 | delegate: metaDelegate 25 | VerticalScrollDecorator { 26 | } 27 | } 28 | 29 | Component { 30 | id: metaDelegate 31 | DetailItem { 32 | label: qsTranslate("exifKey", model.name) 33 | value: model.value 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /qml/components/DockedListView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | 4 | DockedPanel { 5 | id: panel 6 | 7 | property alias model: listView.model 8 | property var selectedItem 9 | modal: true 10 | animationDuration: 250 11 | 12 | signal clicked(var value) 13 | 14 | width: parent.width / 2 15 | height: parent.height 16 | z: 99 17 | 18 | dock: Dock.Left 19 | clip: true 20 | 21 | Rectangle { 22 | anchors.fill: parent 23 | color: Theme.colorScheme === Theme.LightOnDark ? "black" : "white" 24 | opacity: 0.7 25 | 26 | SilicaListView { 27 | id: listView 28 | anchors.fill: parent 29 | VerticalScrollDecorator { 30 | } 31 | clip: true 32 | 33 | delegate: ListItem { 34 | width: ListView.view.width 35 | height: Theme.itemSizeSmall 36 | highlighted: value === selectedItem 37 | 38 | Label { 39 | anchors { 40 | left: parent.left 41 | leftMargin: Theme.horizontalPageMargin 42 | right: parent.right 43 | rightMargin: Theme.horizontalPageMargin 44 | verticalCenter: parent.verticalCenter 45 | } 46 | color: highlighted ? Theme.highlightColor : Theme.primaryColor 47 | text: name 48 | truncationMode: TruncationMode.Fade 49 | } 50 | onClicked: { 51 | panel.clicked(value) 52 | } 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /qml/components/IconSwitch.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | import Sailfish.Silica 1.0 3 | 4 | Item { 5 | id: iconSwitch 6 | property string icon1Source: "" 7 | property string icon2Source: "" 8 | property string button1Name: "" 9 | property string button2Name: "" 10 | signal clicked(var name) 11 | property bool _hilighted2: false 12 | 13 | height: width * 2 14 | 15 | RoundButton { 16 | id: icon1 17 | width: parent.width 18 | height: width 19 | z: 0 20 | icon.source: icon1Source 21 | 22 | onClicked: { 23 | _hilighted2 = false 24 | iconSwitch.clicked(button1Name) 25 | } 26 | } 27 | 28 | RoundButton { 29 | id: icon2 30 | width: parent.width 31 | height: width 32 | anchors.top: icon1.bottom 33 | z: 0 34 | icon.source: icon2Source 35 | 36 | onClicked: { 37 | _hilighted2 = true 38 | iconSwitch.clicked(button2Name) 39 | } 40 | } 41 | 42 | Rectangle { 43 | id: highlighter 44 | radius: width / 2 45 | width: parent.width 46 | height: width 47 | opacity: 0.5 48 | z: 1 49 | y: _hilighted2 ? parent.height / 2 : 0 50 | Behavior on y { 51 | NumberAnimation { 52 | duration: 100 53 | } 54 | } 55 | color: Theme.highlightBackgroundColor 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /qml/components/RoundButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | import Sailfish.Silica 1.0 3 | 4 | Item { 5 | id: button 6 | property string image: "" 7 | property alias icon: iconButton.icon 8 | property int size: Theme.itemSizeSmall 9 | property alias down: iconButton.down 10 | signal clicked 11 | signal pressed 12 | 13 | height: size 14 | width: size 15 | 16 | Rectangle { 17 | anchors.fill: parent 18 | radius: width / 2 19 | color: Theme.colorScheme === Theme.LightOnDark ? "black" : "white" 20 | opacity: 0.7 21 | 22 | IconButton { 23 | id: iconButton 24 | anchors.centerIn: parent 25 | anchors.fill: parent 26 | icon.anchors.fill: icon.parent 27 | icon.anchors.margins: Theme.paddingMedium 28 | icon.source: button.image 29 | icon.fillMode: Image.PreserveAspectFit 30 | onClicked: button.clicked() 31 | onPressed: button.pressed() 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /qml/cover/CoverPage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | 4 | CoverBackground { 5 | TextArea { 6 | id: label 7 | anchors.centerIn: parent 8 | color: Theme.primaryColor 9 | font.bold: true 10 | horizontalAlignment: Text.AlignHCenter 11 | readOnly: true 12 | width: parent.width - 2 * Theme.paddingSmall 13 | text: qsTr("Advanced Camera") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /qml/harbour-advanced-camera.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | import QtMultimedia 5.6 4 | import "pages" 5 | 6 | ApplicationWindow { 7 | id: window 8 | property bool loadingComplete: false; 9 | Settings { 10 | id: settings 11 | } 12 | 13 | Rectangle { 14 | parent: window 15 | anchors.fill: parent 16 | z: -1 17 | color: "black" 18 | } 19 | 20 | VideoOutput { 21 | id: captureView 22 | source: cameraUI.camera 23 | width: window.width 24 | height: window.height 25 | z: -1 26 | } 27 | 28 | initialPage: CameraUI { 29 | id: cameraUI 30 | } 31 | 32 | allowedOrientations: Orientation.All 33 | cover: Qt.resolvedUrl("cover/CoverPage.qml") 34 | 35 | Component.onCompleted: { 36 | loadingComplete = true; 37 | } 38 | 39 | onApplicationActiveChanged: { 40 | if (Qt.application.state == Qt.ApplicationActive) { 41 | cameraUI.camera.start(); 42 | } else { 43 | cameraUI.camera.stop(); 44 | } 45 | } 46 | 47 | Keys.onPressed: { 48 | console.log(event.key); 49 | if (event.isAutoRepeat) { 50 | return 51 | } 52 | if (event.key === Qt.Key_VolumeUp) { 53 | cameraUI.volUp(); 54 | } else if (event.key === Qt.Key_VolumeDown) { 55 | cameraUI.volDown(); 56 | } else if (event.key === Qt.Key_Camera) { 57 | console.log("Cmamera key"); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /qml/pages/AboutImage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | import QtMultimedia 5.6 4 | import uk.co.piggz.harbour_advanced_camera 1.0 5 | import "../components/" 6 | 7 | Page { 8 | id: pageImage 9 | property var filePath 10 | property var fileName 11 | 12 | // The effective value will be restricted by ApplicationWindow.allowedOrientations 13 | allowedOrientations: Orientation.All 14 | 15 | function sizeToStr(siz) { 16 | return siz.width + "x" + siz.height 17 | } 18 | 19 | Image { 20 | id: image 21 | visible: false 22 | source: filePath 23 | asynchronous: true 24 | onStatusChanged: { 25 | if (status === Image.Ready) { 26 | mediaAbout.mediaSize = sizeToStr(sourceSize) 27 | } 28 | } 29 | } 30 | 31 | ExifModel { 32 | id: modelExif 33 | source: filePath 34 | } 35 | 36 | AboutMedia { 37 | id: mediaAbout 38 | mediaModel: modelExif 39 | mediaSize: "" 40 | file: fileName 41 | fileSize: fsOperations.getFileSizeHuman(filePath) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /qml/pages/AboutVideo.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | import QtMultimedia 5.6 4 | import uk.co.piggz.harbour_advanced_camera 1.0 5 | import "../components/" 6 | 7 | Page { 8 | id: pageVideo 9 | property var filePath 10 | property var fileName 11 | 12 | // The effective value will be restricted by ApplicationWindow.allowedOrientations 13 | allowedOrientations: Orientation.All 14 | 15 | function sizeToStr(siz) { 16 | return siz.width + "x" + siz.height 17 | } 18 | 19 | function msToTime(millis) { 20 | return new Date(millis).toISOString().substr(11, 8) 21 | } 22 | 23 | MediaPlayer { 24 | id: mediaPlayer 25 | source: filePath 26 | autoPlay: false 27 | 28 | onStatusChanged: { 29 | if (status === MediaPlayer.Loaded) { 30 | mediaAbout.mediaSize = sizeToStr(metaData.resolution) 31 | } 32 | } 33 | 34 | onDurationChanged: { 35 | mediaAbout.mediaDuration = msToTime(duration) 36 | } 37 | 38 | Component.onCompleted: { 39 | modelVideo.setPlayer(mediaPlayer) 40 | } 41 | } 42 | 43 | MetadataModel { 44 | id: modelVideo 45 | } 46 | 47 | AboutMedia { 48 | id: mediaAbout 49 | mediaModel: modelVideo 50 | mediaSize: "" 51 | file: fileName 52 | fileSize: fsOperations.getFileSizeHuman(filePath) 53 | mediaDuration: "" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /qml/pages/GalleryUI.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | import Sailfish.Share 1.0 3 | import Sailfish.Silica 1.0 4 | import QtMultimedia 5.6 5 | import Nemo.Thumbnailer 1.0 6 | import uk.co.piggz.harbour_advanced_camera 1.0 7 | import "../components/" 8 | 9 | Page { 10 | id: galleryPage 11 | 12 | property var fileList: ({ 13 | 14 | }) 15 | property alias showButtons: btnClose.visible 16 | 17 | // The effective value will be restricted by ApplicationWindow.allowedOrientations 18 | allowedOrientations: Orientation.All 19 | 20 | backNavigation: false 21 | 22 | function isVideo(idx) { 23 | return fileList.get(idx).isVideo 24 | } 25 | 26 | function removeFile(idx) { 27 | var path = fileList.get(idx).filePath 28 | console.log("Removing", path) 29 | if (fsOperations.deleteFile(path)) { 30 | fileList.remove(idx) 31 | if (gallery.count === 0) { 32 | console.log("Closing empty gallery!") 33 | pageStack.pop() 34 | } 35 | } else { 36 | console.log("Error deleting file:", path) 37 | } 38 | } 39 | 40 | function getFileName(idx) { 41 | var fullPath = fileList.get(idx).filePath 42 | var lastSep = fullPath.lastIndexOf("/") 43 | var fileName = fullPath.substr(lastSep + 1, fullPath.length - lastSep) 44 | return fileName 45 | } 46 | 47 | RoundButton { 48 | id: btnClose 49 | 50 | visible: true 51 | icon.source: "image://theme/icon-m-close" 52 | size: Theme.itemSizeMedium 53 | 54 | anchors { 55 | top: parent.top 56 | topMargin: Theme.paddingMedium 57 | right: parent.right 58 | rightMargin: Theme.paddingMedium 59 | } 60 | 61 | onClicked: { 62 | console.log("Clicked close button") 63 | pageStack.pop() 64 | } 65 | } 66 | 67 | RoundButton { 68 | id: btnAbout 69 | 70 | visible: showButtons 71 | icon.source: "image://theme/icon-m-about" 72 | size: Theme.itemSizeMedium 73 | 74 | anchors { 75 | top: parent.top 76 | topMargin: Theme.paddingMedium 77 | left: parent.left 78 | leftMargin: Theme.paddingMedium 79 | } 80 | 81 | onClicked: { 82 | var filePath = fileList.get(gallery.currentIndex).filePath 83 | var mediaPage = isVideo(gallery.currentIndex) ? "AboutVideo.qml" : "AboutImage.qml" 84 | pageStack.push(Qt.resolvedUrl(mediaPage), { 85 | "filePath": filePath, 86 | "fileName": getFileName(gallery.currentIndex), 87 | }) 88 | } 89 | } 90 | 91 | RemorsePopup { 92 | id: remorse 93 | } 94 | 95 | Row { 96 | id: rowBottom 97 | 98 | visible: showButtons 99 | spacing: Theme.paddingMedium 100 | anchors { 101 | horizontalCenter: parent.horizontalCenter 102 | bottom: parent.bottom 103 | bottomMargin: Theme.paddingMedium 104 | } 105 | 106 | RoundButton { 107 | id: btnRemove 108 | 109 | icon.source: "image://theme/icon-m-delete" 110 | size: Theme.itemSizeMedium 111 | 112 | function showRemorseItem() { 113 | var deleteIndex = gallery.currentIndex 114 | remorse.execute(qsTr("Deleting %1").arg(getFileName( 115 | deleteIndex)), 116 | function () { 117 | removeFile(deleteIndex) 118 | }) 119 | } 120 | 121 | onClicked: { 122 | console.log("Clicked delete button") 123 | showRemorseItem() 124 | } 125 | } 126 | 127 | ShareAction { 128 | id: shareAction 129 | } 130 | 131 | RoundButton { 132 | id: btnShare 133 | 134 | icon.source: "image://theme/icon-m-share" 135 | size: Theme.itemSizeMedium 136 | 137 | onClicked: { 138 | var filePath = fileList.get(gallery.currentIndex).filePath 139 | var mimeType = isVideo(gallery.currentIndex) ? "video/mp4" : "image/jpeg" 140 | shareAction.resources = [filePath] 141 | shareAction.mimeType = mimeType 142 | shareAction.trigger() 143 | } 144 | } 145 | } 146 | 147 | SlideshowView { 148 | id: gallery 149 | 150 | clip: true 151 | width: parent.width 152 | height: parent.height 153 | z: -1 154 | 155 | model: fileList 156 | currentIndex: count - 1 157 | 158 | delegate: Rectangle { 159 | id: delegate 160 | width: parent.width 161 | height: parent.height 162 | color: 'black' 163 | 164 | Thumbnail { 165 | id: thumbnail 166 | 167 | sourceSize.width: parent.width 168 | sourceSize.height: parent.height 169 | anchors.fill: parent 170 | fillMode: Thumbnail.PreserveAspectFit 171 | source: filePath 172 | mimeType: isVideo ? "video/" : "image/" 173 | smooth: true 174 | 175 | MouseArea { 176 | anchors.fill: parent 177 | onClicked: { 178 | showButtons = !showButtons 179 | } 180 | } 181 | } 182 | 183 | RoundButton { 184 | id: btnPlay 185 | 186 | visible: isVideo 187 | anchors.centerIn: parent 188 | icon.source: "image://theme/icon-m-play" 189 | size: Theme.itemSizeMedium 190 | 191 | onClicked: { 192 | pageStack.push(Qt.resolvedUrl("VideoPlayer.qml"), { 193 | "videoFile": filePath 194 | }, PageStackAction.Immediate) 195 | } 196 | } 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /qml/pages/GridOverlay.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | 4 | Item { 5 | id: root 6 | 7 | property double aspect: 16.0 / 9.0 8 | visible: settings.global.gridMode != "none" 9 | anchors.centerIn: parent 10 | width: parent.height * aspect 11 | height: parent.height 12 | 13 | function horizontalLines(id) { 14 | if (id === "thirds") 15 | return [0.33, 0.66] 16 | if (id === "ambience") 17 | return [0.21, 0.79] 18 | return [] 19 | } 20 | 21 | function verticalLines(id) { 22 | if (id === "thirds") 23 | return [0.33, 0.66] 24 | if (id === "ambience") 25 | return [0.2333, 0.7666] 26 | return [] 27 | } 28 | 29 | Repeater { 30 | model: horizontalLines(settings.global.gridMode) 31 | 32 | delegate: Item { 33 | width: parent.width 34 | height: 5 35 | 36 | Rectangle { 37 | id: left 38 | width: parent.width / 2 39 | height: 5 40 | y: root.height * modelData 41 | 42 | color: "#88ffffff" 43 | } 44 | 45 | OpacityRampEffect { 46 | sourceItem: left 47 | direction: OpacityRamp.RightToLeft 48 | } 49 | 50 | Rectangle { 51 | id: right 52 | width: parent.width / 2 53 | height: 5 54 | y: root.height * modelData 55 | x: root.width / 2 56 | 57 | color: "#88ffffff" 58 | } 59 | 60 | OpacityRampEffect { 61 | sourceItem: right 62 | direction: OpacityRamp.LeftToRight 63 | } 64 | } 65 | } 66 | 67 | Repeater { 68 | model: verticalLines(settings.global.gridMode) 69 | 70 | delegate: Item { 71 | width: 5 72 | height: parent.height 73 | 74 | Rectangle { 75 | id: up 76 | width: 5 77 | height: parent.height / 2 78 | x: root.width * modelData 79 | 80 | color: "#88ffffff" 81 | } 82 | 83 | OpacityRampEffect { 84 | sourceItem: up 85 | direction: OpacityRamp.BottomToTop 86 | } 87 | 88 | Rectangle { 89 | id: bottom 90 | width: 5 91 | height: parent.height / 2 92 | x: root.width * modelData 93 | y: up.height 94 | 95 | color: "#88ffffff" 96 | } 97 | 98 | OpacityRampEffect { 99 | sourceItem: bottom 100 | direction: OpacityRamp.TopToBottom 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /qml/pages/Settings.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtMultimedia 5.4 3 | import Nemo.Configuration 1.0 4 | import Sailfish.Silica 1.0 5 | 6 | Item { 7 | property alias global: globalSettings 8 | property alias mode: modeSettings 9 | property alias jollaCamera: jollaCameraSettings 10 | 11 | property variant enabledCameras: [] //Calculated on startup and when disabledCameras changes 12 | 13 | ConfigurationGroup { 14 | id: globalSettings 15 | path: "/uk/co/piggz/harbour-advanced-camera" 16 | property int cameraCount: 0 //default to 0 and get populated on startup 17 | property string cameraId: "0" 18 | property string captureMode: "image" 19 | property bool swapZoomControl: false 20 | property string gridMode: "none" 21 | property int videoBitrate: 12800000 22 | property int audioBitrate: 128000 23 | property string storagePath: StandardPaths.home 24 | property bool locationMetadata: true 25 | property bool enableWideCameraButtons: true 26 | property string disabledCameras: "" 27 | property bool showManualControls: false 28 | 29 | ConfigurationGroup { 30 | id: modeSettings 31 | path: globalSettings.cameraId + "/" + globalSettings.captureMode 32 | 33 | property int effect: CameraImageProcessing.ColorFilterNone 34 | property int exposure: Camera.ExposureManual 35 | property int flash: Camera.FlashOff 36 | property int focus: CameraFocus.FocusContinuous 37 | property int iso: 0 38 | property string resolution: "" 39 | property int whiteBalance: CameraImageProcessing.WhiteBalanceAuto 40 | } 41 | } 42 | 43 | ConfigurationGroup { 44 | id: jollaCameraSettings 45 | path: "/apps/jolla-camera/" + globalSettings.cameraId + "/image" 46 | 47 | property string viewfinderResolution 48 | property string viewfinderResolution_16_9 49 | property string viewfinderResolution_4_3 50 | } 51 | 52 | function strToSize(siz) { 53 | var w = parseInt(siz.substring(0, siz.indexOf("x"))) 54 | var h = parseInt(siz.substring(siz.indexOf("x") + 1)) 55 | return Qt.size(w, h) 56 | } 57 | 58 | function sizeToStr(siz) { 59 | return siz.width + "x" + siz.height 60 | } 61 | 62 | //Return either the current mode resolution or default resolution for that mode 63 | function resolution(mode) { 64 | if (settings.global.captureMode === mode 65 | && settings.mode.resolution !== "") { 66 | var res = strToSize(settings.mode.resolution) 67 | if (modelResolution.isValidResolution(res, mode)) { 68 | return res 69 | } 70 | } 71 | return modelResolution.defaultResolution(mode) 72 | } 73 | 74 | function calculateEnabledCameras() 75 | { 76 | settings.enabledCameras = [] 77 | for (var i = 0; i < globalSettings.cameraCount; ++i) { 78 | if (settings.global.disabledCameras.indexOf("[" + QtMultimedia.availableCameras[i].deviceId + "]") == -1) { 79 | settings.enabledCameras.push(QtMultimedia.availableCameras[i].deviceId) 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /qml/pages/VideoPlayer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | import QtMultimedia 5.6 4 | import Nemo.KeepAlive 1.2 5 | import "../components/" 6 | 7 | Page { 8 | id: videoPage 9 | 10 | // The effective value will be restricted by ApplicationWindow.allowedOrientations 11 | allowedOrientations: Orientation.All 12 | 13 | backNavigation: false 14 | 15 | property string videoFile 16 | property double controlsOpacity: 1.0 17 | 18 | DisplayBlanking { 19 | preventBlanking: player.playbackState === MediaPlayer.PlayingState 20 | } 21 | 22 | Rectangle { 23 | anchors.fill: parent 24 | color: "black" 25 | 26 | MediaPlayer { 27 | id: player 28 | 29 | source: "file://" + videoFile 30 | autoPlay: true 31 | 32 | onPositionChanged: { 33 | seekSlider.value = position 34 | } 35 | 36 | onStopped: { 37 | pageStack.pop(null, true) 38 | } 39 | } 40 | 41 | VideoOutput { 42 | id: video 43 | 44 | anchors.fill: parent 45 | source: player 46 | fillMode: VideoOutput.PreserveAspectFit 47 | 48 | MouseArea { 49 | anchors.fill: parent 50 | onClicked: { 51 | controlsOpacity > 0 ? controlsOpacity = 0 : controlsOpacity = 1.0 52 | } 53 | } 54 | } 55 | 56 | Item { 57 | id: itemsControls 58 | anchors.fill: parent 59 | opacity: controlsOpacity 60 | 61 | Behavior on opacity { 62 | FadeAnimation { 63 | } 64 | } 65 | 66 | RoundButton { 67 | id: btnCloseVideo 68 | 69 | enabled: controlsOpacity > 0 70 | icon.source: "image://theme/icon-m-close" 71 | size: Theme.itemSizeMedium 72 | 73 | anchors { 74 | top: parent.top 75 | topMargin: Theme.paddingMedium 76 | right: parent.right 77 | rightMargin: Theme.paddingMedium 78 | } 79 | 80 | onClicked: { 81 | pageStack.pop(null, true) 82 | } 83 | } 84 | 85 | RoundButton { 86 | id: btnPlayPause 87 | 88 | enabled: controlsOpacity > 0 89 | icon.source: player.playbackState === MediaPlayer.PlayingState ? "image://theme/icon-m-pause" : "image://theme/icon-m-play" 90 | size: Theme.itemSizeMedium 91 | anchors.centerIn: parent 92 | 93 | onClicked: { 94 | if (player.playbackState === MediaPlayer.PausedState) { 95 | player.play() 96 | } else if (player.playbackState === MediaPlayer.PlayingState) { 97 | player.pause() 98 | } else if (player.playbackState === MediaPlayer.StoppedState) { 99 | player.seek(0) 100 | player.play() 101 | } 102 | } 103 | } 104 | 105 | Row { 106 | id: rowBottomVideo 107 | 108 | width: parent.width 109 | anchors { 110 | horizontalCenter: parent.horizontalCenter 111 | bottom: parent.bottom 112 | bottomMargin: Theme.paddingMedium 113 | } 114 | 115 | Slider { 116 | id: seekSlider 117 | 118 | width: parent.width 119 | anchors.verticalCenter: parent.verticalCenter 120 | minimumValue: 0 121 | maximumValue: player.duration > 0 ? player.duration : 1 122 | value: player.position 123 | stepSize: 0 124 | enabled: player.seekable && controlsOpacity > 0 125 | 126 | onReleased: { 127 | player.seek(value) 128 | } 129 | } 130 | } 131 | 132 | Timer { 133 | running: true 134 | interval: 333 135 | repeat: false 136 | onTriggered: controlsOpacity = 0 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /qml/pics/icon-camera-focus-continuous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-camera-focus-continuous.png -------------------------------------------------------------------------------- /qml/pics/icon-camera-focus-hyperfocal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-camera-focus-hyperfocal.png -------------------------------------------------------------------------------- /qml/pics/icon-camera-focus-manual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-camera-focus-manual.png -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-aqua.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-blackboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-default.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-emboss.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-grayscale.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-negative.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-neon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-none.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-posterize.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-sepia.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-sketch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-solarize.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect-whiteboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-effect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-effect.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-100.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-1600.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-1600.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-200.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-3200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-3200.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-400.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-6400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-6400.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-800.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-auto.png -------------------------------------------------------------------------------- /qml/pics/icon-m-iso-hjr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-iso-hjr.png -------------------------------------------------------------------------------- /qml/pics/icon-m-resolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-resolution.png -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_action.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_ar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_asd.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_backlight.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_barcode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_beach.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_candlelight.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_fireworks.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_flowers.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_hdr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_landscape.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_large_aperture.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_night.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_night_portrait.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_none.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_party.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_portrait.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_small_aperture.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_snow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_sports.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_spotlight.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_steady_photo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_sunset.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_theatre.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qml/pics/icon-m-scene_mode_unknown.svg: -------------------------------------------------------------------------------- 1 | ? -------------------------------------------------------------------------------- /qml/pics/icon-m-tele-lense-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-tele-lense-active.png -------------------------------------------------------------------------------- /qml/pics/icon-m-tele-lense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-tele-lense.png -------------------------------------------------------------------------------- /qml/pics/icon-m-tele-lense.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 39 | 40 | 61 | 63 | 64 | 66 | image/svg+xml 67 | 69 | 70 | 71 | 72 | 73 | 77 | 90 | 97 | 101 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /qml/pics/icon-m-uwide-lense-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-uwide-lense-active.png -------------------------------------------------------------------------------- /qml/pics/icon-m-uwide-lense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-uwide-lense.png -------------------------------------------------------------------------------- /qml/pics/icon-m-uwide-lense.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 29 | 46 | 47 | 68 | 70 | 71 | 73 | image/svg+xml 74 | 76 | 77 | 78 | 79 | 80 | 84 | 97 | 104 | 108 | 112 | 116 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /qml/pics/icon-m-wide-lense-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-wide-lense-active.png -------------------------------------------------------------------------------- /qml/pics/icon-m-wide-lense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/qml/pics/icon-m-wide-lense.png -------------------------------------------------------------------------------- /qml/pics/icon-m-wide-lense.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 39 | 40 | 61 | 63 | 64 | 66 | image/svg+xml 67 | 69 | 70 | 71 | 72 | 73 | 77 | 90 | 97 | 101 | 105 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /rpm/harbour-advanced-camera.changes: -------------------------------------------------------------------------------- 1 | # Rename this file as harbour-advanced-camera.changes to include changelog 2 | # entries in your RPM file. 3 | # 4 | # Add new changelog entries following the format below. 5 | # Add newest entries to the top of the list. 6 | # Separate entries from eachother with a blank line. 7 | # 8 | # Alternatively, if your changelog is automatically generated (e.g. with 9 | # the git-change-log command provided with Sailfish OS SDK), create a 10 | # harbour-advanced-camera.changes.run script to let mb2 run the required commands for you. 11 | 12 | # * date Author's Name version-release 13 | # - Summary of changes 14 | 15 | * Mon Oct 11 2021 Adam Pigg 0.9.5-1 16 | - Several improvements from Lukáš Karas: 17 | - Dont use an unsupported focus mode 18 | - Better viewfinder resolution selection 19 | - Update models when the camera changes 20 | - Simulate manual focus mode 21 | - Gallery media information view 22 | - Turn off GPS correctly 23 | - Manual exposure slider 24 | - Added settings to turn off telelense buttons 25 | - Added option to turn off manual exposure 26 | - Added optiont to enable/disable camera selection 27 | - Added current camera label 28 | -------------------------------------------------------------------------------- /rpm/harbour-advanced-camera.changes.run.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Rename this file as harbour-advanced-camera.changes.run to let mb2 automatically 4 | # generate changelog from well formatted Git commit messages and tag 5 | # annotations. 6 | 7 | git-change-log 8 | 9 | # Here are some basic examples how to change from the default behavior. Run 10 | # git-change-log --help inside the Sailfish OS SDK chroot or build engine to 11 | # learn all the options git-change-log accepts. 12 | 13 | # Use a subset of tags 14 | #git-change-log --tags refs/tags/my-prefix/* 15 | 16 | # Group entries by minor revision, suppress headlines for patch-level revisions 17 | #git-change-log --dense '/[0-9]\+\.[0-9\+$' 18 | 19 | # Trim very old changes 20 | #git-change-log --since 2014-04-01 21 | #echo '[ Some changelog entries trimmed for brevity ]' 22 | 23 | # Use the subjects (first lines) of tag annotations when no entry would be 24 | # included for a revision otherwise 25 | #git-change-log --auto-add-annotations 26 | -------------------------------------------------------------------------------- /rpm/harbour-advanced-camera.spec: -------------------------------------------------------------------------------- 1 | # 2 | # Do NOT Edit the Auto-generated Part! 3 | # Generated by: spectacle version 0.32 4 | # 5 | 6 | Name: harbour-advanced-camera 7 | 8 | # >> macros 9 | # << macros 10 | 11 | %{!?qtc_qmake:%define qtc_qmake %qmake} 12 | %{!?qtc_qmake5:%define qtc_qmake5 %qmake5} 13 | %{!?qtc_make:%define qtc_make make} 14 | %{?qtc_builddir:%define _builddir %qtc_builddir} 15 | Summary: Advanced camera 16 | Version: 0.9.8 17 | Release: 1 18 | Group: Qt/Qt 19 | License: GPLv2 20 | URL: http://github.com/piggz/harbour-advanced-camera 21 | Source0: %{name}-%{version}.tar.bz2 22 | Source100: harbour-advanced-camera.yaml 23 | Requires: sailfishsilica-qt5 >= 0.10.9 24 | BuildRequires: pkgconfig(sailfishapp) >= 1.0.2 25 | BuildRequires: pkgconfig(Qt5Core) 26 | BuildRequires: pkgconfig(Qt5Multimedia) 27 | BuildRequires: pkgconfig(Qt5Qml) 28 | BuildRequires: pkgconfig(Qt5Quick) 29 | BuildRequires: qt5-qttools-linguist 30 | BuildRequires: ssu-sysinfo-devel 31 | BuildRequires: libexif-devel 32 | BuildRequires: desktop-file-utils 33 | 34 | %description 35 | Advanced Camera (aka piggz-o-vision) is a community camera application for sailfish devices which utilises the latest features in 3.0.2 to query/set parameters supported by the device. 36 | 37 | Allows full control over: 38 | Effects 39 | Exposure/scene modes 40 | Focus mode 41 | Resolution 42 | White Balance 43 | Flash mode 44 | ISO 45 | 46 | Currently selected parameters are displayed on the buttons where possible. 47 | 48 | Tapping the screen sets the focus circle when in Auto/Macro/Continuous 49 | 50 | Hold the shutter button to focus and take an image when in Auto/Macro/Continuous focus mode, other modes take an instant image. 51 | 52 | Exposure mode will typically provide a HDR mode for taking HDR images. 53 | 54 | %if "%{?vendor}" == "chum" 55 | PackageName: Advanced Camera 56 | Type: desktop-application 57 | DeveloperName: Adam Pigg 58 | Categories: 59 | - Media 60 | - Video 61 | Custom: 62 | Repo: https://github.com/piggz/harbour-advanced-camera 63 | Icon: https://raw.githubusercontent.com/piggz/harbour-advanced-camera/master/harbour-advanced-camera.svg 64 | Screenshots: 65 | - https://github.com/piggz/harbour-advanced-camera/raw/master/screenshots/screenshot4.png 66 | - https://github.com/piggz/harbour-advanced-camera/raw/master/screenshots/screenshot5.png 67 | - https://github.com/piggz/harbour-advanced-camera/raw/master/screenshots/screenshot6.png 68 | Url: 69 | Homepage: https://github.com/piggz/harbour-advanced-camera 70 | Help: https://github.com/piggz/harbour-advanced-camera/discussions 71 | Bugtracker: https://github.com/piggz/harbour-advanced-camera/issues 72 | Donation: https://www.paypal.me/piggz 73 | %endif 74 | 75 | %prep 76 | %setup -q -n %{name}-%{version} 77 | 78 | # >> setup 79 | # << setup 80 | 81 | %build 82 | # >> build pre 83 | # << build pre 84 | 85 | %qtc_qmake5 86 | 87 | %qtc_make %{?_smp_mflags} 88 | 89 | # >> build post 90 | # << build post 91 | 92 | %install 93 | rm -rf %{buildroot} 94 | # >> install pre 95 | # << install pre 96 | %qmake5_install 97 | 98 | # >> install post 99 | # << install post 100 | 101 | desktop-file-install --delete-original \ 102 | --dir %{buildroot}%{_datadir}/applications \ 103 | %{buildroot}%{_datadir}/applications/*.desktop 104 | 105 | %files 106 | %defattr(-,root,root,-) 107 | %{_bindir} 108 | %{_datadir}/%{name} 109 | %{_datadir}/applications/%{name}.desktop 110 | %{_datadir}/icons/hicolor/*/apps/%{name}.png 111 | # >> files 112 | # << files 113 | -------------------------------------------------------------------------------- /rpm/harbour-advanced-camera.yaml: -------------------------------------------------------------------------------- 1 | Name: harbour-advanced-camera 2 | Summary: Advanced camera 3 | Version: 0.9.5 4 | Release: 1 5 | # The contents of the Group field should be one of the groups listed here: 6 | # https://github.com/mer-tools/spectacle/blob/master/data/GROUPS 7 | Group: Qt/Qt 8 | URL: http://github.com/piggz/harbour-advanced-camera 9 | License: GPLv2 10 | # This must be generated before uploading a package to a remote build service. 11 | # Usually this line does not need to be modified. 12 | Sources: 13 | - '%{name}-%{version}.tar.bz2' 14 | Description: | 15 | Better camera application 16 | Configure: none 17 | # The qtc5 builder inserts macros to allow QtCreator to have fine 18 | # control over qmake/make execution 19 | Builder: qtc5 20 | 21 | # This section specifies build dependencies that are resolved using pkgconfig. 22 | # This is the preferred way of specifying build dependencies for your package. 23 | PkgConfigBR: 24 | - sailfishapp >= 1.0.2 25 | - Qt5Core 26 | - Qt5Multimedia 27 | - Qt5Qml 28 | - Qt5Quick 29 | 30 | # Build dependencies without a pkgconfig setup can be listed here 31 | PkgBR: 32 | - qt5-qttools-linguist 33 | - ssu-sysinfo-devel 34 | - libexif-devel 35 | 36 | # Runtime dependencies which are not automatically detected 37 | Requires: 38 | - sailfishsilica-qt5 >= 0.10.9 39 | 40 | # All installed files 41 | Files: 42 | - '%{_bindir}' 43 | - '%{_datadir}/%{name}' 44 | - '%{_datadir}/applications/%{name}.desktop' 45 | - '%{_datadir}/icons/hicolor/*/apps/%{name}.png' 46 | 47 | # For more information about yaml and what's supported in Sailfish OS 48 | # build system, please see https://wiki.merproject.org/wiki/Spectacle 49 | -------------------------------------------------------------------------------- /screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/screenshots/screenshot1.png -------------------------------------------------------------------------------- /screenshots/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/screenshots/screenshot2.png -------------------------------------------------------------------------------- /screenshots/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/screenshots/screenshot3.png -------------------------------------------------------------------------------- /screenshots/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/screenshots/screenshot4.png -------------------------------------------------------------------------------- /screenshots/screenshot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/screenshots/screenshot5.png -------------------------------------------------------------------------------- /screenshots/screenshot6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piggz/harbour-advanced-camera/bc498a5e468baa3dd8b716777559164c25108c1b/screenshots/screenshot6.png -------------------------------------------------------------------------------- /src/deviceinfo.cpp: -------------------------------------------------------------------------------- 1 | #include "deviceinfo.h" 2 | #include 3 | #include 4 | 5 | DeviceInfo::DeviceInfo() 6 | { 7 | QLibrary lib; 8 | lib.setFileName("libssusysinfo.so.1"); 9 | if (lib.load()) { 10 | qDebug() << "libssusysinfo.so.1 loaded"; 11 | SsuAlloc allocFn = (SsuAlloc) lib.resolve("ssusysinfo_create"); 12 | SsuDelete deleteFn = (SsuDelete) lib.resolve("ssusysinfo_delete"); 13 | SsuManufacturer manufacturerFn = (SsuManufacturer) lib.resolve("ssusysinfo_device_manufacturer"); 14 | SsuModel modelFn = (SsuModel) lib.resolve("ssusysinfo_device_pretty_name"); 15 | 16 | if (allocFn && deleteFn && manufacturerFn && modelFn) { 17 | ssusysinfo_t *si = allocFn(); 18 | if (si) { 19 | m_manufacturer = manufacturerFn(si); 20 | qDebug() << "manufacturer:" << m_manufacturer; 21 | m_prettyModelName = modelFn(si); 22 | qDebug() << "prettyModelName:" << m_prettyModelName; 23 | deleteFn(si); 24 | } else { 25 | qWarning() << "Cannot allocate ssusysinfo_t!"; 26 | } 27 | } else { 28 | qWarning() << "Cannot resolve libssusysinfo methods!"; 29 | } 30 | 31 | lib.unload(); 32 | } else { 33 | qWarning() << "Unable to load libssusysinfo.so.1!"; 34 | } 35 | } 36 | 37 | QString DeviceInfo::manufacturer() const 38 | { 39 | return m_manufacturer; 40 | } 41 | 42 | QString DeviceInfo::prettyModelName() const 43 | { 44 | return m_prettyModelName; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/deviceinfo.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DEVICEINFO_H 3 | #define DEVICEINFO_H 4 | 5 | #include 6 | 7 | #include 8 | 9 | class DeviceInfo { 10 | public: 11 | DeviceInfo(); 12 | virtual ~DeviceInfo() = default; 13 | 14 | QString manufacturer() const; 15 | QString prettyModelName() const; 16 | 17 | private: 18 | typedef ssusysinfo_t* (*SsuAlloc)(); 19 | typedef char* (*SsuManufacturer)(ssusysinfo_t*); 20 | typedef char* (*SsuModel)(ssusysinfo_t*); 21 | typedef void (*SsuDelete)(ssusysinfo_t*); 22 | 23 | QString m_manufacturer; 24 | QString m_prettyModelName; 25 | }; 26 | 27 | #endif //DEVICEINFO_H 28 | -------------------------------------------------------------------------------- /src/effectsmodel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #include "effectsmodel.h" 20 | 21 | EffectsModel::EffectsModel() 22 | { 23 | } 24 | 25 | QHash EffectsModel::roleNames() const 26 | { 27 | QHash roles; 28 | roles[EffectName] = "name"; 29 | roles[EffectValue] = "value"; 30 | return roles; 31 | } 32 | 33 | int EffectsModel::rowCount(const QModelIndex &parent) const 34 | { 35 | Q_UNUSED(parent); 36 | return m_effects.size(); 37 | } 38 | 39 | QVariant EffectsModel::data(const QModelIndex &index, int role) const 40 | { 41 | QVariant v; 42 | 43 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 44 | return v; 45 | } 46 | 47 | if (role == EffectName) { 48 | v = m_effects[index.row()].second; 49 | } else if (role == EffectValue) { 50 | v = m_effects.at(index.row()).first; 51 | } 52 | 53 | return v; 54 | } 55 | 56 | void EffectsModel::setCamera(QObject *camera) 57 | { 58 | // even when m_camera instance is the same, deviceId could have changed and so available focus modes 59 | m_camera = camera->property("mediaObject").value(); 60 | 61 | beginResetModel(); 62 | m_effects.clear(); 63 | for (int c = (int)QCameraImageProcessing::ColorFilterNone; 64 | c <= (int)QCameraImageProcessing::ColorFilterNeon; c++) { 65 | if (m_camera->imageProcessing()->isColorFilterSupported((QCameraImageProcessing::ColorFilter)c)) { 66 | qDebug() << "Found support for" << (QCameraImageProcessing::ColorFilter)c; 67 | m_effects.push_back(std::make_pair((QCameraImageProcessing::ColorFilter)c, effectName((QCameraImageProcessing::ColorFilter)c))); 68 | } 69 | } 70 | endResetModel(); 71 | emit rowCountChanged(); 72 | 73 | if (m_effects.size() == 0) { 74 | qDebug() << "No effect modes found"; 75 | } 76 | } 77 | 78 | QString EffectsModel::effectName(QCameraImageProcessing::ColorFilter c) const 79 | { 80 | QString name; 81 | 82 | switch (c) { 83 | case QCameraImageProcessing::ColorFilterNone: 84 | name = tr("None"); 85 | break; 86 | case QCameraImageProcessing::ColorFilterAqua: 87 | name = tr("Aqua"); 88 | break; 89 | case QCameraImageProcessing::ColorFilterBlackboard: 90 | name = tr("Blackboard"); 91 | break; 92 | case QCameraImageProcessing::ColorFilterGrayscale: 93 | name = tr("Grayscale"); 94 | break; 95 | case QCameraImageProcessing::ColorFilterNegative: 96 | name = tr("Negative"); 97 | break; 98 | case QCameraImageProcessing::ColorFilterPosterize: 99 | name = tr("Posterize"); 100 | break; 101 | case QCameraImageProcessing::ColorFilterSepia: 102 | name = tr("Sepia"); 103 | break; 104 | case QCameraImageProcessing::ColorFilterSolarize: 105 | name = tr("Solarize"); 106 | break; 107 | case QCameraImageProcessing::ColorFilterWhiteboard: 108 | name = tr("Whiteboard"); 109 | break; 110 | case QCameraImageProcessing::ColorFilterEmboss: 111 | name = tr("Emboss"); 112 | break; 113 | case QCameraImageProcessing::ColorFilterSketch: 114 | name = tr("Sketch"); 115 | break; 116 | case QCameraImageProcessing::ColorFilterNeon: 117 | name = tr("Neon"); 118 | break; 119 | default: 120 | name = "Unknown"; 121 | break; 122 | } 123 | 124 | return name; 125 | } 126 | -------------------------------------------------------------------------------- /src/effectsmodel.h: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #ifndef EFFECTSMODEL_H 20 | #define EFFECTSMODEL_H 21 | 22 | #include 23 | #include 24 | 25 | class EffectsModel : public QAbstractListModel 26 | { 27 | Q_OBJECT 28 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 29 | 30 | public: 31 | 32 | enum EffectRoles { 33 | EffectName = Qt::UserRole + 1, 34 | EffectValue 35 | }; 36 | 37 | EffectsModel(); 38 | 39 | virtual QHash roleNames() const; 40 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 41 | virtual QVariant data(const QModelIndex &index, int role) const; 42 | 43 | Q_INVOKABLE void setCamera(QObject *camera); 44 | 45 | private: 46 | std::vector> m_effects; 47 | QCamera *m_camera = nullptr; 48 | 49 | QString effectName(QCameraImageProcessing::ColorFilter c) const; 50 | 51 | signals: 52 | void rowCountChanged(); 53 | }; 54 | 55 | #endif // EFFECTSMODEL_H 56 | -------------------------------------------------------------------------------- /src/exifmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "exifmodel.h" 2 | #include 3 | #include 4 | 5 | static void parseContent(ExifContent *content, void *userdata); 6 | static void parseEntry(ExifEntry *entry, void *userdata); 7 | 8 | typedef void (*ExifForEachEntry)(ExifContent*, ExifContentForeachEntryFunc, void*); 9 | typedef void (*ExifGetValue)(ExifEntry*, char*, int); 10 | typedef ExifIfd (*ExifGetIfd)(ExifContent*); 11 | typedef char* (*ExifGetTag)(ExifTag, ExifIfd); 12 | static ExifForEachEntry f_foreachentry; 13 | static ExifGetValue f_getvalue; 14 | static ExifGetIfd f_getifd; 15 | static ExifGetTag f_gettag; 16 | 17 | ExifModel::ExifModel() 18 | { 19 | } 20 | 21 | ExifModel::~ExifModel() 22 | { 23 | free(m_data); 24 | if (m_lib.isLoaded()) { 25 | m_lib.unload(); 26 | } 27 | } 28 | 29 | bool ExifModel::loadLibexif() 30 | { 31 | if (m_lib.isLoaded()) 32 | return true; 33 | 34 | m_lib.setFileName("libexif.so.12"); 35 | if (m_lib.load()) 36 | { 37 | f_fromfile = (ExifFromFile) m_lib.resolve("exif_data_new_from_file"); 38 | f_getvalue = (ExifGetValue) m_lib.resolve("exif_entry_get_value"); 39 | f_foreachentry = (ExifForEachEntry) m_lib.resolve("exif_content_foreach_entry"); 40 | f_foreachcontent = (ExifForEachContent) m_lib.resolve("exif_data_foreach_content"); 41 | f_getifd = (ExifGetIfd) m_lib.resolve("exif_content_get_ifd"); 42 | f_gettag = (ExifGetTag) m_lib.resolve("exif_tag_get_name_in_ifd"); 43 | f_dump = (ExifDump) m_lib.resolve("exif_data_dump"); 44 | } 45 | else { 46 | qWarning() << "Unable to load libexif.so.12!"; 47 | return false; 48 | } 49 | return true; 50 | } 51 | 52 | QHash ExifModel::roleNames() const 53 | { 54 | QHash roles; 55 | roles[ExifName] = "name"; 56 | roles[ExifValue] = "value"; 57 | return roles; 58 | } 59 | 60 | int ExifModel::rowCount(const QModelIndex &parent) const 61 | { 62 | Q_UNUSED(parent); 63 | return m_exif.count(); 64 | } 65 | 66 | QVariant ExifModel::data(const QModelIndex &index, int role) const 67 | { 68 | QVariant v; 69 | 70 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 71 | return v; 72 | } 73 | 74 | if (role == ExifValue) { 75 | v = m_exif.values().at(index.row()); 76 | } else if (role == ExifName) { 77 | v = m_exif.keys().at(index.row()); 78 | } 79 | 80 | return v; 81 | } 82 | 83 | void ExifModel::setSource(const QString &path) 84 | { 85 | if (!loadLibexif()) 86 | return; 87 | source = path; 88 | m_data = f_fromfile(path.toUtf8().data()); 89 | //f_dump(m_data); 90 | beginResetModel(); 91 | m_exif.clear(); 92 | f_foreachcontent(m_data, parseContent, nullptr); 93 | endResetModel(); 94 | } 95 | 96 | void parseContent(ExifContent *content, void *userdata) 97 | { 98 | Q_UNUSED(userdata); 99 | f_foreachentry(content, parseEntry, content); 100 | } 101 | 102 | void parseEntry(ExifEntry *entry, void *userdata) 103 | { 104 | ExifContent *content = static_cast(userdata); 105 | ExifIfd ifd = f_getifd(content); 106 | QString tag(f_gettag(entry->tag, ifd)); 107 | char bufValue[1024]; 108 | f_getvalue(entry, bufValue, 1024); 109 | m_exif.insert(tag, QString(bufValue)); 110 | } 111 | -------------------------------------------------------------------------------- /src/exifmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef EXIFMODEL_H 2 | #define EXIFMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | static QMap m_exif; 9 | 10 | class ExifModel : public QAbstractListModel 11 | { 12 | Q_OBJECT 13 | Q_PROPERTY(QString source READ getSource WRITE setSource) 14 | public: 15 | enum ExifRoles { 16 | ExifName = Qt::UserRole + 1, 17 | ExifValue 18 | }; 19 | 20 | ExifModel(); 21 | ~ExifModel(); 22 | bool loadLibexif(); 23 | QHash roleNames() const; 24 | int rowCount(const QModelIndex &parent) const; 25 | QVariant data(const QModelIndex &index, int role) const; 26 | QString getSource() const { return source; } 27 | void setSource(const QString &path); 28 | private: 29 | QString source; 30 | ExifData *m_data; 31 | QLibrary m_lib; 32 | typedef ExifData* (*ExifFromFile)(const char*); 33 | typedef void (*ExifForEachContent)(ExifData*, ExifDataForeachContentFunc, void*); 34 | typedef void (*ExifDump)(ExifData*); 35 | ExifFromFile f_fromfile; 36 | ExifForEachContent f_foreachcontent; 37 | ExifDump f_dump; 38 | }; 39 | 40 | #endif // EXIFMODEL_H 41 | -------------------------------------------------------------------------------- /src/exposuremodel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #include "exposuremodel.h" 20 | 21 | ExposureModel::ExposureModel() 22 | { 23 | } 24 | 25 | QHash ExposureModel::roleNames() const 26 | { 27 | QHash roles; 28 | roles[ExposureName] = "name"; 29 | roles[ExposureValue] = "value"; 30 | return roles; 31 | } 32 | 33 | int ExposureModel::rowCount(const QModelIndex &parent) const 34 | { 35 | Q_UNUSED(parent); 36 | return m_exposures.size(); 37 | } 38 | 39 | QVariant ExposureModel::data(const QModelIndex &index, int role) const 40 | { 41 | QVariant v; 42 | 43 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 44 | return v; 45 | } 46 | 47 | if (role == ExposureName) { 48 | v = m_exposures.at(index.row()).second; 49 | } else if (role == ExposureValue) { 50 | v = m_exposures.at(index.row()).first; 51 | } 52 | 53 | return v; 54 | } 55 | 56 | void ExposureModel::setCamera(QObject *camera) 57 | { 58 | // even when m_camera instance is the same, deviceId could have changed and so available focus modes 59 | m_camera = camera->property("mediaObject").value(); 60 | 61 | beginResetModel(); 62 | m_exposures.clear(); 63 | for (int c = (int)QCameraExposure::ExposureAuto; c <= (int)QCameraExposure::ExposureHDR; c++) { 64 | if (m_camera->exposure()->isExposureModeSupported((QCameraExposure::ExposureMode)c)) { 65 | qDebug() << "Found support for" << (QCameraExposure::ExposureMode)c; 66 | m_exposures.push_back(std::make_pair((QCameraExposure::ExposureMode)c, exposureName((QCameraExposure::ExposureMode)c))); 67 | } 68 | } 69 | endResetModel(); 70 | emit rowCountChanged(); 71 | 72 | if (m_exposures.size() == 0) { 73 | qDebug() << "No exposure modes found"; 74 | } 75 | } 76 | 77 | QString ExposureModel::exposureName(QCameraExposure::ExposureMode e) const 78 | { 79 | QString name; 80 | 81 | switch (e) { 82 | case QCameraExposure::ExposureAuto: 83 | name = tr("Automatic Scene Detection"); 84 | break; 85 | case QCameraExposure::ExposureAction: 86 | name = tr("Action"); 87 | break; 88 | case QCameraExposure::ExposureManual: 89 | name = tr("Off"); 90 | break; 91 | case QCameraExposure::ExposureAR: 92 | name = tr("Augmented Reality"); 93 | break; 94 | case QCameraExposure::ExposureBacklight: 95 | name = tr("Backlight"); 96 | break; 97 | case QCameraExposure::ExposureBarcode: 98 | name = tr("Barcode"); 99 | break; 100 | case QCameraExposure::ExposureBeach: 101 | name = tr("Beach"); 102 | break; 103 | case QCameraExposure::ExposureCandlelight: 104 | name = tr("Candlelight"); 105 | break; 106 | case QCameraExposure::ExposureFireworks: 107 | name = tr("Fireworks"); 108 | break; 109 | case QCameraExposure::ExposureFlowers: 110 | name = tr("Flowers"); 111 | break; 112 | case QCameraExposure::ExposureHDR: 113 | name = tr("HDR"); 114 | break; 115 | case QCameraExposure::ExposureLandscape: 116 | name = tr("Landscape"); 117 | break; 118 | case QCameraExposure::ExposureLargeAperture: 119 | name = tr("Large Aperture"); 120 | break; 121 | case QCameraExposure::ExposureNight: 122 | name = tr("Night"); 123 | break; 124 | case QCameraExposure::ExposureNightPortrait: 125 | name = tr("Night Portrait"); 126 | break; 127 | case QCameraExposure::ExposureParty: 128 | name = tr("Party"); 129 | break; 130 | case QCameraExposure::ExposurePortrait: 131 | name = tr("Portrait"); 132 | break; 133 | case QCameraExposure::ExposureSmallAperture: 134 | name = tr("Small Aperture"); 135 | break; 136 | case QCameraExposure::ExposureSnow: 137 | name = tr("Snow"); 138 | break; 139 | case QCameraExposure::ExposureSports: 140 | name = tr("Sports"); 141 | break; 142 | case QCameraExposure::ExposureSpotlight: 143 | name = tr("Spotlight"); 144 | break; 145 | case QCameraExposure::ExposureSteadyPhoto: 146 | name = tr("Steady Photo"); 147 | break; 148 | case QCameraExposure::ExposureSunset: 149 | name = tr("Sunset"); 150 | break; 151 | case QCameraExposure::ExposureTheatre: 152 | name = tr("Theatre"); 153 | break; 154 | 155 | default: 156 | name = "Unknown (" + QString::number(e) + ")"; 157 | } 158 | 159 | return name; 160 | } 161 | 162 | QString ExposureModel::iconName(QCameraExposure::ExposureMode e) const 163 | { 164 | QString name; 165 | 166 | switch (e) { 167 | case QCameraExposure::ExposureAuto: 168 | name = "asd"; 169 | break; 170 | case QCameraExposure::ExposureAction: 171 | name = "action"; 172 | break; 173 | case QCameraExposure::ExposureManual: 174 | name = "none"; 175 | break; 176 | case QCameraExposure::ExposureAR: 177 | name = "ar"; 178 | break; 179 | case QCameraExposure::ExposureBacklight: 180 | name = "backlight"; 181 | break; 182 | case QCameraExposure::ExposureBarcode: 183 | name = "barcode"; 184 | break; 185 | case QCameraExposure::ExposureBeach: 186 | name = "beach"; 187 | break; 188 | case QCameraExposure::ExposureCandlelight: 189 | name = "candlelight"; 190 | break; 191 | case QCameraExposure::ExposureFireworks: 192 | name = "fireworks"; 193 | break; 194 | case QCameraExposure::ExposureFlowers: 195 | name = "flowers"; 196 | break; 197 | case QCameraExposure::ExposureHDR: 198 | name = "hdr"; 199 | break; 200 | case QCameraExposure::ExposureLandscape: 201 | name = "landscape"; 202 | break; 203 | case QCameraExposure::ExposureLargeAperture: 204 | name = "large_aperture"; 205 | break; 206 | case QCameraExposure::ExposureNight: 207 | name = "night"; 208 | break; 209 | case QCameraExposure::ExposureNightPortrait: 210 | name = "night_portrait"; 211 | break; 212 | case QCameraExposure::ExposureParty: 213 | name = "party"; 214 | break; 215 | case QCameraExposure::ExposurePortrait: 216 | name = "portrait"; 217 | break; 218 | case QCameraExposure::ExposureSmallAperture: 219 | name = "small_aperture"; 220 | break; 221 | case QCameraExposure::ExposureSnow: 222 | name = "snow"; 223 | break; 224 | case QCameraExposure::ExposureSports: 225 | name = "sports"; 226 | break; 227 | case QCameraExposure::ExposureSpotlight: 228 | name = "spotlight"; 229 | break; 230 | case QCameraExposure::ExposureSteadyPhoto: 231 | name = "steady_photo"; 232 | break; 233 | case QCameraExposure::ExposureSunset: 234 | name = "sunset"; 235 | break; 236 | case QCameraExposure::ExposureTheatre: 237 | name = "theatre"; 238 | break; 239 | default: 240 | name = "unknown"; 241 | break; 242 | } 243 | 244 | return name; 245 | } 246 | -------------------------------------------------------------------------------- /src/exposuremodel.h: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #ifndef EXPOSUREMODEL_H 20 | #define EXPOSUREMODEL_H 21 | 22 | #include 23 | #include 24 | 25 | class ExposureModel : public QAbstractListModel 26 | { 27 | Q_OBJECT 28 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 29 | 30 | public: 31 | 32 | enum ExposureRoles { 33 | ExposureName = Qt::UserRole + 1, 34 | ExposureValue 35 | }; 36 | 37 | ExposureModel(); 38 | 39 | virtual QHash roleNames() const; 40 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 41 | virtual QVariant data(const QModelIndex &index, int role) const; 42 | 43 | Q_INVOKABLE void setCamera(QObject *camera); 44 | Q_INVOKABLE QString iconName(QCameraExposure::ExposureMode e) const; 45 | 46 | private: 47 | std::vector> m_exposures; 48 | QCamera *m_camera = nullptr; 49 | 50 | QString exposureName(QCameraExposure::ExposureMode e) const; 51 | 52 | signals: 53 | void rowCountChanged(); 54 | }; 55 | 56 | #endif // EFFECTSMODEL_H 57 | -------------------------------------------------------------------------------- /src/flashmodel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #include "flashmodel.h" 20 | 21 | FlashModel::FlashModel() 22 | { 23 | } 24 | 25 | QHash FlashModel::roleNames() const 26 | { 27 | QHash roles; 28 | roles[FlashName] = "name"; 29 | roles[FlashValue] = "value"; 30 | return roles; 31 | } 32 | 33 | int FlashModel::rowCount(const QModelIndex &parent) const 34 | { 35 | Q_UNUSED(parent); 36 | return m_flashModes.size(); 37 | } 38 | 39 | QVariant FlashModel::data(const QModelIndex &index, int role) const 40 | { 41 | QVariant v; 42 | 43 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 44 | return v; 45 | } 46 | 47 | if (role == FlashName) { 48 | v = m_flashModes.at(index.row()).second; 49 | } else if (role == FlashValue) { 50 | v = m_flashModes.at(index.row()).first; 51 | } 52 | 53 | return v; 54 | } 55 | 56 | void FlashModel::setCamera(QObject *camera) 57 | { 58 | // even when m_camera instance is the same, deviceId could have changed and so available focus modes 59 | m_camera = camera->property("mediaObject").value(); 60 | 61 | beginResetModel(); 62 | m_flashModes.clear(); 63 | for (int c = (int)QCameraExposure::FlashAuto; c <= (int)QCameraExposure::FlashManual; c++) { 64 | if (m_camera->exposure()->isFlashModeSupported((QCameraExposure::FlashMode)c) 65 | && flashName((QCameraExposure::FlashMode)c) != tr("Unknown")) { 66 | qDebug() << "Found support for" << (QCameraExposure::FlashMode)c; 67 | m_flashModes.push_back(std::make_pair((QCameraExposure::FlashMode)c, flashName((QCameraExposure::FlashMode)c))); 68 | } 69 | } 70 | endResetModel(); 71 | emit rowCountChanged(); 72 | 73 | if (m_flashModes.size() == 0) { 74 | qDebug() << "No flash modes found"; 75 | } 76 | } 77 | 78 | QString FlashModel::flashName(QCameraExposure::FlashMode flash) const 79 | { 80 | QString name; 81 | 82 | switch (flash) { 83 | case QCameraExposure::FlashAuto: 84 | name = tr("Auto"); 85 | break; 86 | case QCameraExposure::FlashOff: 87 | name = tr("Off"); 88 | break; 89 | case QCameraExposure::FlashOn: 90 | name = tr("On"); 91 | break; 92 | case QCameraExposure::FlashRedEyeReduction: 93 | name = tr("Red Eye Reduction"); 94 | break; 95 | case QCameraExposure::FlashFill: 96 | name = tr("Fill"); 97 | break; 98 | case QCameraExposure::FlashTorch: 99 | name = tr("Torch"); 100 | break; 101 | case QCameraExposure::FlashVideoLight: 102 | name = tr("Video Light"); 103 | break; 104 | case QCameraExposure::FlashSlowSyncFrontCurtain: 105 | name = tr("Slow Sync Front Curtain"); 106 | break; 107 | case QCameraExposure::FlashSlowSyncRearCurtain: 108 | name = tr("Slow Sync Rear Curtain"); 109 | break; 110 | case QCameraExposure::FlashManual: 111 | name = tr("Manual"); 112 | break; 113 | default: 114 | name = tr("Unknown"); 115 | break; 116 | } 117 | 118 | return name; 119 | } 120 | -------------------------------------------------------------------------------- /src/flashmodel.h: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #ifndef FLASHMODEL_H 20 | #define FLASHMODEL_H 21 | 22 | #include 23 | #include 24 | 25 | class FlashModel : public QAbstractListModel 26 | { 27 | Q_OBJECT 28 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 29 | 30 | public: 31 | 32 | enum FlashRoles { 33 | FlashName = Qt::UserRole + 1, 34 | FlashValue 35 | }; 36 | 37 | FlashModel(); 38 | 39 | virtual QHash roleNames() const; 40 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 41 | virtual QVariant data(const QModelIndex &index, int role) const; 42 | 43 | Q_INVOKABLE void setCamera(QObject *camera); 44 | 45 | private: 46 | std::vector> m_flashModes; 47 | 48 | QCamera *m_camera = nullptr; 49 | 50 | QString flashName(QCameraExposure::FlashMode flash) const; 51 | 52 | signals: 53 | void rowCountChanged(); 54 | }; 55 | 56 | #endif // FOCUSMODEL_H 57 | -------------------------------------------------------------------------------- /src/focusmodel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #include "focusmodel.h" 20 | 21 | FocusModel::FocusModel() 22 | { 23 | } 24 | 25 | QHash FocusModel::roleNames() const 26 | { 27 | QHash roles; 28 | roles[FocusName] = "name"; 29 | roles[FocusValue] = "value"; 30 | return roles; 31 | } 32 | 33 | int FocusModel::rowCount(const QModelIndex &parent) const 34 | { 35 | Q_UNUSED(parent); 36 | return m_focusModes.size(); 37 | } 38 | 39 | QVariant FocusModel::data(const QModelIndex &index, int role) const 40 | { 41 | QVariant v; 42 | 43 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 44 | return v; 45 | } 46 | 47 | if (role == FocusName) { 48 | v = m_focusModes.at(index.row()).second; 49 | } else if (role == FocusValue) { 50 | v = m_focusModes.at(index.row()).first; 51 | } 52 | 53 | return v; 54 | } 55 | 56 | void FocusModel::setCamera(QObject *camera) 57 | { 58 | // even when m_camera instance is the same, deviceId could have changed and so available focus modes 59 | m_camera = camera->property("mediaObject").value(); 60 | 61 | beginResetModel(); 62 | m_focusModes.clear(); 63 | for (int c = (int)QCameraFocus::ManualFocus; c <= (int)QCameraFocus::MacroFocus; c++) { 64 | if (m_camera->focus()->isFocusModeSupported((QCameraFocus::FocusMode)c) 65 | && focusName((QCameraFocus::FocusMode)c) != tr("Unknown")) { 66 | qDebug() << "Found support for" << (QCameraFocus::FocusMode)c; 67 | m_focusModes.push_back(std::make_pair((QCameraFocus::FocusMode)c, focusName((QCameraFocus::FocusMode)c))); 68 | } 69 | } 70 | // Add manual mode even if not supported as we simulate it (but FocusAuto needs to be supported) 71 | auto it = std::find_if( m_focusModes.begin(), m_focusModes.end(), 72 | [](const std::pair& element){ return element.first == QCameraFocus::ManualFocus;} ); 73 | 74 | if (it == std::end(m_focusModes) && m_camera->focus()->isFocusModeSupported(QCameraFocus::AutoFocus)) { 75 | m_focusModes.push_back(std::make_pair(QCameraFocus::ManualFocus, focusName(QCameraFocus::ManualFocus))); 76 | } 77 | endResetModel(); 78 | emit rowCountChanged(); 79 | 80 | if (m_focusModes.size() == 0) { 81 | qDebug() << "No focus modes found"; 82 | } 83 | } 84 | 85 | QString FocusModel::focusName(QCameraFocus::FocusMode focus) const 86 | { 87 | QString name; 88 | qDebug() << "Checking focus name: " << focus; 89 | 90 | switch (focus) { 91 | case QCameraFocus::ManualFocus: 92 | name = tr("Manual"); 93 | break; 94 | case QCameraFocus::HyperfocalFocus: 95 | name = tr("Hyperfocal"); 96 | break; 97 | case QCameraFocus::InfinityFocus: 98 | name = tr("Infinity"); 99 | break; 100 | case QCameraFocus::AutoFocus: 101 | name = tr("Auto"); 102 | break; 103 | case QCameraFocus::ContinuousFocus: 104 | name = tr("Continuous"); 105 | break; 106 | case QCameraFocus::MacroFocus: 107 | name = tr("Macro"); 108 | break; 109 | default: 110 | name = tr("Unknown"); 111 | break; 112 | } 113 | return name; 114 | } 115 | -------------------------------------------------------------------------------- /src/focusmodel.h: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #ifndef FOCUSMODEL_H 20 | #define FOCUSMODEL_H 21 | 22 | #include 23 | #include 24 | 25 | class FocusModel : public QAbstractListModel 26 | { 27 | Q_OBJECT 28 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 29 | 30 | public: 31 | 32 | enum FocusRoles { 33 | FocusName = Qt::UserRole + 1, 34 | FocusValue 35 | }; 36 | 37 | FocusModel(); 38 | 39 | virtual QHash roleNames() const; 40 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 41 | virtual QVariant data(const QModelIndex &index, int role) const; 42 | 43 | Q_INVOKABLE void setCamera(QObject *camera); 44 | 45 | private: 46 | std::vector> m_focusModes; 47 | QCamera *m_camera = nullptr; 48 | 49 | QString focusName(QCameraFocus::FocusMode focus) const; 50 | 51 | signals: 52 | void rowCountChanged(); 53 | }; 54 | 55 | #endif // FOCUSMODEL_H 56 | -------------------------------------------------------------------------------- /src/fsoperations.cpp: -------------------------------------------------------------------------------- 1 | #include "fsoperations.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | FSOperations::FSOperations(QObject *parent) : QObject(parent) 10 | { 11 | } 12 | 13 | bool FSOperations::deleteFile(const QString &path) 14 | { 15 | QFile f(path); 16 | return f.remove(); 17 | } 18 | 19 | QString FSOperations::writableLocation(const QString &type, const QString &baseDir) 20 | { 21 | QString dir; 22 | if (type == "image") { 23 | dir = baseDir + "/Pictures/AdvancedCam"; 24 | } else if (type == "video") { 25 | dir = baseDir + "/Videos/AdvancedCam"; 26 | } else { 27 | return QString(); 28 | } 29 | 30 | if (!createFolder(dir)) { 31 | qWarning() << "Unable to create" << dir << ", fallback to home dir!"; 32 | emit rescan("/media/sdcard"); 33 | return writableLocation(type, QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); 34 | } 35 | return dir; 36 | } 37 | 38 | bool FSOperations::createFolder(const QString &path) 39 | { 40 | QDir dir(path); 41 | if (!dir.exists()) { 42 | return dir.mkpath("."); 43 | } 44 | return true; 45 | } 46 | 47 | qint64 FSOperations::getFileSize(const QString &path) 48 | { 49 | QFileInfo info(path); 50 | if (info.exists()) 51 | return info.size(); 52 | return 0; 53 | } 54 | 55 | QString FSOperations::getFileSizeHuman(const QString &path) 56 | { 57 | float num = (float)getFileSize(path); 58 | QStringList list; 59 | list << "KiB" << "MiB" << "GiB" << "TiB"; 60 | 61 | QStringListIterator i(list); 62 | QString unit("B"); 63 | 64 | if (num < 1024.0) 65 | return QString().setNum(num, 'f', 0) + " " + unit; 66 | 67 | while(num >= 1024.0 && i.hasNext()) 68 | { 69 | unit = i.next(); 70 | num /= 1024.0; 71 | } 72 | return QString().setNum(num, 'f', 2) + " " + unit; 73 | } 74 | -------------------------------------------------------------------------------- /src/fsoperations.h: -------------------------------------------------------------------------------- 1 | #ifndef FSOPERATIONS_H 2 | #define FSOPERATIONS_H 3 | 4 | #include 5 | 6 | class FSOperations : public QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit FSOperations(QObject *parent = nullptr); 11 | Q_INVOKABLE bool deleteFile(const QString &path); 12 | Q_INVOKABLE QString writableLocation(const QString &type, const QString &baseDir); 13 | Q_INVOKABLE bool createFolder(const QString &path); 14 | Q_INVOKABLE qint64 getFileSize(const QString &path); 15 | Q_INVOKABLE QString getFileSizeHuman(const QString &path); 16 | signals: 17 | void rescan(const QString& dir); 18 | }; 19 | 20 | #endif // FSOPERATIONS_H 21 | -------------------------------------------------------------------------------- /src/harbour-advanced-camera.cpp: -------------------------------------------------------------------------------- 1 | #ifdef QT_QML_DEBUG 2 | #include 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include "deviceinfo.h" 13 | #include "effectsmodel.h" 14 | #include "exposuremodel.h" 15 | #include "isomodel.h" 16 | #include "resolutionmodel.h" 17 | #include "wbmodel.h" 18 | #include "focusmodel.h" 19 | #include "flashmodel.h" 20 | #include "fsoperations.h" 21 | #include "resourcehandler.h" 22 | #include "storagemodel.h" 23 | #include "exifmodel.h" 24 | #include "metadatamodel.h" 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | // SailfishApp::main() will display "qml/harbour-advanced-camera.qml", if you need more 29 | // control over initialization, you can use: 30 | // 31 | // - SailfishApp::application(int, char *[]) to get the QGuiApplication * 32 | // - SailfishApp::createView() to get a new QQuickView * instance 33 | // - SailfishApp::pathTo(QString) to get a QUrl to a resource file 34 | // - SailfishApp::pathToMainQml() to get a QUrl to the main QML file 35 | // 36 | // To display the view, call "show()" (will show fullscreen on device). 37 | 38 | QGuiApplication *app = SailfishApp::application(argc, argv); 39 | 40 | app->setOrganizationDomain("piggz.co.uk"); 41 | app->setOrganizationName("uk.co.piggz"); // needed for Sailjail 42 | app->setApplicationName("AdvancedCamera"); 43 | 44 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "EffectsModel"); 45 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "ExposureModel"); 46 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "IsoModel"); 47 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "ResolutionModel"); 48 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "WhiteBalanceModel"); 49 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "FocusModel"); 50 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "FlashModel"); 51 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "ExifModel"); 52 | qmlRegisterType("uk.co.piggz.harbour_advanced_camera", 1, 0, "MetadataModel"); 53 | 54 | ResolutionModel resolutionModel; 55 | QSortFilterProxyModel sortedResolutionModel; 56 | sortedResolutionModel.setSourceModel(&resolutionModel); 57 | sortedResolutionModel.setSortRole(ResolutionModel::ResolutionMpx); 58 | sortedResolutionModel.sort(0, Qt::DescendingOrder); 59 | 60 | QQuickView *view = SailfishApp::createView(); 61 | 62 | ResourceHandler handler; 63 | handler.acquire(); 64 | 65 | view->rootContext()->setContextProperty("modelResolution", &resolutionModel); 66 | view->rootContext()->setContextProperty("sortedModelResolution", &sortedResolutionModel); 67 | StorageModel storageModel; 68 | view->rootContext()->setContextProperty("modelStorage", &storageModel); 69 | FSOperations fsOperations; 70 | view->rootContext()->setContextProperty("fsOperations", &fsOperations); 71 | 72 | view->setSource(SailfishApp::pathTo("qml/harbour-advanced-camera.qml")); 73 | 74 | DeviceInfo deviceInfo; 75 | view->rootContext()->setContextProperty("CameraManufacturer", deviceInfo.manufacturer()); 76 | view->rootContext()->setContextProperty("CameraPrettyModelName", deviceInfo.prettyModelName()); 77 | 78 | QObject::connect(view, &QQuickView::focusObjectChanged, &handler, 79 | &ResourceHandler::handleFocusChange); 80 | QObject::connect(&fsOperations, &FSOperations::rescan, &storageModel, 81 | &StorageModel::scan); 82 | 83 | view->show(); 84 | 85 | return app->exec(); 86 | } 87 | -------------------------------------------------------------------------------- /src/isomodel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #include "isomodel.h" 20 | 21 | IsoModel::IsoModel() 22 | { 23 | } 24 | 25 | QHash IsoModel::roleNames() const 26 | { 27 | QHash roles; 28 | roles[IsoName] = "name"; 29 | roles[IsoValue] = "value"; 30 | return roles; 31 | } 32 | 33 | int IsoModel::rowCount(const QModelIndex &parent) const 34 | { 35 | Q_UNUSED(parent); 36 | return m_isoModes.size(); 37 | } 38 | 39 | QVariant IsoModel::data(const QModelIndex &index, int role) const 40 | { 41 | QVariant v; 42 | 43 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 44 | return v; 45 | } 46 | 47 | if (role == IsoName) { 48 | v = m_isoModes.at(index.row()).second; 49 | } else if (role == IsoValue) { 50 | v = m_isoModes.at(index.row()).first; 51 | } 52 | 53 | return v; 54 | } 55 | 56 | void IsoModel::setCamera(QObject *camera) 57 | { 58 | // even when m_camera instance is the same, deviceId could have changed and so available focus modes 59 | m_camera = camera->property("mediaObject").value(); 60 | 61 | beginResetModel(); 62 | m_isoModes.clear(); 63 | 64 | QList supportedIsoRange = m_camera->exposure()->supportedIsoSensitivities(); 65 | 66 | for (int i = 0; i < supportedIsoRange.count() ; i++) { 67 | m_isoModes.push_back(std::make_pair(i, isoName(supportedIsoRange[i]))); 68 | qDebug() << "Found support for" << isoName(supportedIsoRange[i]); 69 | } 70 | endResetModel(); 71 | emit rowCountChanged(); 72 | 73 | if (m_isoModes.size() == 0) { 74 | qDebug() << "No ISO modes found"; 75 | } 76 | } 77 | 78 | QString IsoModel::isoName(int iso) const 79 | { 80 | QString name; 81 | 82 | if (iso == 0) { 83 | name = tr("Auto ISO"); 84 | } else if (iso == 1) { 85 | name = "ISO_HJR"; 86 | } else { 87 | name = QString("ISO_%1").arg(iso); 88 | } 89 | return name; 90 | } 91 | -------------------------------------------------------------------------------- /src/isomodel.h: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #ifndef ISOMODEL_H 20 | #define ISOMODEL_H 21 | 22 | #include 23 | #include 24 | 25 | class IsoModel : public QAbstractListModel 26 | { 27 | Q_OBJECT 28 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 29 | 30 | public: 31 | 32 | enum IsoRoles { 33 | IsoName = Qt::UserRole + 1, 34 | IsoValue 35 | }; 36 | 37 | IsoModel(); 38 | 39 | virtual QHash roleNames() const; 40 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 41 | virtual QVariant data(const QModelIndex &index, int role) const; 42 | 43 | Q_INVOKABLE void setCamera(QObject *camera); 44 | 45 | private: 46 | std::vector> m_isoModes; 47 | 48 | QCamera *m_camera = nullptr; 49 | 50 | QString isoName(int iso) const; 51 | 52 | signals: 53 | void rowCountChanged(); 54 | }; 55 | 56 | #endif // EFFECTSMODEL_H 57 | -------------------------------------------------------------------------------- /src/metadatamodel.cpp: -------------------------------------------------------------------------------- 1 | #include "metadatamodel.h" 2 | 3 | MetadataModel::MetadataModel() 4 | { 5 | } 6 | 7 | QHash MetadataModel::roleNames() const 8 | { 9 | QHash roles; 10 | roles[MetadataName] = "name"; 11 | roles[MetadataValue] = "value"; 12 | return roles; 13 | } 14 | 15 | int MetadataModel::rowCount(const QModelIndex &parent) const 16 | { 17 | Q_UNUSED(parent); 18 | return m_data.count(); 19 | } 20 | 21 | QVariant MetadataModel::data(const QModelIndex &index, int role) const 22 | { 23 | QVariant v; 24 | 25 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 26 | return v; 27 | } 28 | 29 | if (role == MetadataValue) { 30 | v = m_data.values().at(index.row()); 31 | } else if (role == MetadataName) { 32 | v = m_data.keys().at(index.row()); 33 | } 34 | 35 | return v; 36 | } 37 | 38 | void MetadataModel::setPlayer(QObject *player) 39 | { 40 | QMediaPlayer* pl = qvariant_cast(player->property("mediaObject")); 41 | if (m_player != pl) 42 | m_player = pl; 43 | connect(m_player, &QMediaPlayer::metaDataAvailableChanged, this, &MetadataModel::getMetadata); 44 | } 45 | 46 | void MetadataModel::getMetadata(bool available) 47 | { 48 | Q_UNUSED(available); 49 | if (m_player->isMetaDataAvailable()) 50 | { 51 | QStringList meta (m_player->availableMetaData()); 52 | qDebug() << "Metadata available:" << meta; 53 | beginResetModel(); 54 | for (const QString &mdName : meta) 55 | m_data[mdName] = m_player->metaData(mdName); 56 | endResetModel(); 57 | if (m_data.count() == 0) 58 | qDebug() << "No metadata found!"; 59 | } 60 | else { 61 | qDebug() << "No metadata available!"; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/metadatamodel.h: -------------------------------------------------------------------------------- 1 | #ifndef METADATAMODEL_H 2 | #define METADATAMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class MetadataModel : public QAbstractListModel 10 | { 11 | Q_OBJECT 12 | public: 13 | enum MetadataRoles { 14 | MetadataName = Qt::UserRole + 1, 15 | MetadataValue 16 | }; 17 | MetadataModel(); 18 | QHash roleNames() const; 19 | int rowCount(const QModelIndex &parent) const; 20 | QVariant data(const QModelIndex &index, int role) const; 21 | Q_INVOKABLE void setPlayer(QObject *player); 22 | public slots: 23 | void getMetadata(bool available); 24 | private: 25 | QMap m_data; 26 | QMediaPlayer *m_player; 27 | }; 28 | 29 | #endif // METADATAMODEL_H 30 | -------------------------------------------------------------------------------- /src/resolutionmodel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #include "resolutionmodel.h" 20 | 21 | QSize ResolutionModel::sizeToRatio(const QSize &siz) const 22 | { 23 | int a = siz.width(); 24 | int b = siz.height(); 25 | int c = a % b; 26 | int gcd = 0; 27 | 28 | while (c > 0) { 29 | a = b; 30 | b = c; 31 | c = a % b; 32 | } 33 | 34 | gcd = b; 35 | return siz / gcd; 36 | } 37 | 38 | ResolutionModel::ResolutionModel() 39 | { 40 | } 41 | 42 | QHash ResolutionModel::roleNames() const 43 | { 44 | QHash roles; 45 | roles[ResolutionName] = "name"; 46 | roles[ResolutionValue] = "value"; 47 | return roles; 48 | } 49 | 50 | int ResolutionModel::rowCount(const QModelIndex &parent) const 51 | { 52 | Q_UNUSED(parent); 53 | return m_resolutions.size(); 54 | } 55 | 56 | QVariant ResolutionModel::data(const QModelIndex &index, int role) const 57 | { 58 | QVariant v; 59 | 60 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 61 | return v; 62 | } 63 | 64 | if (role == ResolutionName) { 65 | QSize r = sizeToRatio(m_resolutions.at(index.row()).second); 66 | v = QString("%1 (%2:%3)").arg(m_resolutions.at(index.row()).first).arg(r.width()).arg(r.height()); 67 | } else if (role == ResolutionValue) { 68 | v = m_resolutions.at(index.row()).second; 69 | } else if (role == ResolutionMpx) { 70 | v = m_resolutions.at(index.row()).second.width() * m_resolutions.at(index.row()).second.height(); 71 | } 72 | return v; 73 | } 74 | 75 | void ResolutionModel::setImageCapture(QObject *capture) 76 | { 77 | QCameraImageCapture *cap = nullptr; 78 | QList captures = capture->findChildren(); 79 | 80 | if (captures.count() > 0) { 81 | cap = captures[0]; //first will do! 82 | } 83 | 84 | if (cap) { 85 | m_supportedImageResolutions = cap->supportedResolutions(); 86 | if (!m_mode.isEmpty()) { 87 | setMode(m_mode); 88 | } 89 | } 90 | } 91 | 92 | void ResolutionModel::setVideoRecorder(QObject *capture) 93 | { 94 | QMediaRecorder *cap = nullptr; 95 | QList captures = capture->findChildren(); 96 | 97 | if (captures.count() > 0) { 98 | cap = captures[0]; //first will do! 99 | } 100 | 101 | if (cap) { 102 | m_supportedVideoResolutions = cap->supportedResolutions(); 103 | if (!m_mode.isEmpty()) { 104 | setMode(m_mode); 105 | } 106 | } 107 | } 108 | 109 | void ResolutionModel::setMode(const QString &mode) 110 | { 111 | m_mode = mode; 112 | beginResetModel(); 113 | m_resolutions.clear(); 114 | 115 | if (mode == "image") { 116 | for (int i = 0; i < m_supportedImageResolutions.count() ; i++) { 117 | m_resolutions.push_back(std::make_pair(QString("%1x%2").arg(m_supportedImageResolutions[i].width()).arg( 118 | m_supportedImageResolutions[i].height()), m_supportedImageResolutions[i])); 119 | } 120 | } else if (mode == "video") { 121 | for (int i = 0; i < m_supportedVideoResolutions.count() ; i++) { 122 | m_resolutions.push_back(std::make_pair(QString("%1x%2").arg(m_supportedVideoResolutions[i].width()).arg( 123 | m_supportedVideoResolutions[i].height()), m_supportedVideoResolutions[i])); 124 | } 125 | } 126 | 127 | endResetModel(); 128 | emit rowCountChanged(); 129 | 130 | if (m_resolutions.size() > 0) { 131 | qDebug() << "Supported " << mode << " resolutions:"; 132 | for(const auto &res: m_resolutions) { 133 | qDebug() << res.first; 134 | } 135 | } else { 136 | qWarning() << "No resolutions found"; 137 | } 138 | } 139 | 140 | QSize ResolutionModel::defaultResolution(const QString &mode) 141 | { 142 | if (mode == "video") { 143 | if (m_supportedVideoResolutions.count() > 0) { 144 | return m_supportedVideoResolutions.at(m_supportedVideoResolutions.count() - 1); 145 | } 146 | } else if (mode == "image") { 147 | if (m_supportedImageResolutions.count() > 0) { 148 | return m_supportedImageResolutions.at(m_supportedImageResolutions.count() - 1); 149 | } 150 | } 151 | return QSize(0, 0); 152 | } 153 | 154 | bool ResolutionModel::isValidResolution(const QSize &resolution, const QString &mode) 155 | { 156 | if (mode == "image") { 157 | return m_supportedImageResolutions.contains(resolution); 158 | } else if (mode == "video") { 159 | return m_supportedVideoResolutions.contains(resolution); 160 | } 161 | return false; 162 | } 163 | -------------------------------------------------------------------------------- /src/resolutionmodel.h: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #ifndef RESOLUTIONMODEL_H 20 | #define RESOLUTIONMODEL_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | class ResolutionModel : public QAbstractListModel 27 | { 28 | Q_OBJECT 29 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 30 | 31 | public: 32 | 33 | enum ResolutionRoles { 34 | ResolutionName = Qt::UserRole + 1, 35 | ResolutionValue, 36 | ResolutionMpx 37 | }; 38 | 39 | ResolutionModel(); 40 | 41 | virtual QHash roleNames() const; 42 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 43 | virtual QVariant data(const QModelIndex &index, int role) const; 44 | 45 | Q_INVOKABLE QSize sizeToRatio(const QSize &siz) const; 46 | Q_INVOKABLE void setImageCapture(QObject *camera); 47 | Q_INVOKABLE void setVideoRecorder(QObject *capture); 48 | Q_INVOKABLE void setMode(const QString &mode); 49 | Q_INVOKABLE QSize defaultResolution(const QString &mode); 50 | Q_INVOKABLE bool isValidResolution(const QSize &resolution, const QString &mode); 51 | 52 | private: 53 | std::vector> m_resolutions; 54 | QList m_supportedImageResolutions; 55 | QList m_supportedVideoResolutions; 56 | QString m_mode = "image"; 57 | 58 | signals: 59 | void rowCountChanged(); 60 | }; 61 | 62 | #endif // RESOLUTIONMODEL_H 63 | -------------------------------------------------------------------------------- /src/resourcehandler.cpp: -------------------------------------------------------------------------------- 1 | #include "resourcehandler.h" 2 | #include 3 | #include 4 | 5 | void grant_callback(resource_set_t *, uint32_t, void *) {} 6 | 7 | static resource_set_t *(*create_set)(const char *, uint32_t, uint32_t, uint32_t, 8 | resource_callback_t, void *); 9 | static int (*acquire_set)(resource_set_t *); 10 | static int (*release_set)(resource_set_t *); 11 | 12 | ResourceHandler::ResourceHandler(QObject *parent) : 13 | QObject(parent) 14 | { 15 | 16 | m_handle = dlopen ((sizeof(void*) == 8) ? "/usr/lib64/libresource-glib.so.0" : "/usr/lib/libresource-glib.so.0", RTLD_LAZY); 17 | 18 | if (m_handle) { 19 | create_set = (resource_set_t *(*)(const char *, uint32_t, uint32_t, uint32_t, resource_callback_t, 20 | void *))dlsym(m_handle, "resource_set_create"); 21 | if (!create_set) { 22 | qDebug() << dlerror(); 23 | } 24 | acquire_set = (int (*)(resource_set_t *))dlsym(m_handle, "resource_set_acquire"); 25 | if (!acquire_set) { 26 | qDebug() << dlerror(); 27 | } 28 | release_set = (int (*)(resource_set_t *))dlsym(m_handle, "resource_set_release"); 29 | if (!release_set) { 30 | qDebug() << dlerror(); 31 | } 32 | if (!create_set || !acquire_set || !release_set) { 33 | qDebug() << "Error in dlsym to one of the functions"; 34 | } else { 35 | qDebug() << "Creating resource set"; 36 | m_resource = create_set("player", RESOURCE_SCALE_BUTTON | RESOURCE_SNAP_BUTTON, 0, 0, 37 | &grant_callback, nullptr); 38 | } 39 | } else { 40 | qDebug() << "Unable to open libresource. Unable to use hardware keys"; 41 | } 42 | } 43 | 44 | void ResourceHandler::acquire() 45 | { 46 | if (acquire_set) { 47 | acquire_set(m_resource); 48 | } 49 | } 50 | 51 | void ResourceHandler::release() 52 | { 53 | if (release_set) { 54 | release_set(m_resource); 55 | } 56 | } 57 | 58 | void ResourceHandler::handleFocusChange(QObject *focus) 59 | { 60 | if (focus == nullptr) { 61 | release(); 62 | } else { 63 | acquire(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/resourcehandler.h: -------------------------------------------------------------------------------- 1 | #ifndef RESOURCEHANDLER_H 2 | #define RESOURCEHANDLER_H 3 | 4 | #include 5 | 6 | #define RESOURCE_BIT(b) (((uint32_t)1) << (b)) 7 | #define RESOURCE_SCALE_BUTTON RESOURCE_BIT( 10 ) 8 | #define RESOURCE_SNAP_BUTTON RESOURCE_BIT( 11 ) 9 | 10 | typedef struct resource_set_t resource_set_t; 11 | typedef void (*resource_callback_t)(resource_set_t *, uint32_t, void *); 12 | 13 | 14 | class ResourceHandler : public QObject 15 | { 16 | Q_OBJECT 17 | public: 18 | explicit ResourceHandler(QObject *parent = 0); 19 | 20 | public slots: 21 | void acquire(); 22 | void release(); 23 | void handleFocusChange(QObject *focus); 24 | 25 | private: 26 | resource_set_t *m_resource; 27 | void *m_handle = nullptr; 28 | }; 29 | 30 | #endif // RESOURCEHANDLER_H 31 | -------------------------------------------------------------------------------- /src/storagemodel.cpp: -------------------------------------------------------------------------------- 1 | #include "storagemodel.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | Storage::Storage(const QString &name, const QString &path) : 8 | m_name(name), m_path(path) 9 | { 10 | qDebug() << "Storage:" << name << path; 11 | } 12 | 13 | StorageModel::StorageModel() 14 | { 15 | scan(); 16 | } 17 | 18 | QHash StorageModel::roleNames() const 19 | { 20 | QHash roles; 21 | roles[StorageName] = "name"; 22 | roles[StoragePath] = "value"; 23 | return roles; 24 | } 25 | 26 | int StorageModel::rowCount(const QModelIndex &parent) const 27 | { 28 | Q_UNUSED(parent); 29 | return m_storage.size(); 30 | } 31 | 32 | QVariant StorageModel::data(const QModelIndex &index, int role) const 33 | { 34 | QVariant v; 35 | 36 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 37 | return v; 38 | } 39 | 40 | switch(role) { 41 | case StorageName: 42 | return m_storage[index.row()].name(); 43 | case StoragePath: 44 | return m_storage[index.row()].path(); 45 | default: 46 | return QVariant(); 47 | } 48 | } 49 | 50 | void StorageModel::scan() 51 | { 52 | qDebug() << "Scanning storage directories"; 53 | QString homeDir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); 54 | 55 | beginResetModel(); 56 | m_storage.clear(); 57 | m_storage.append(Storage(tr("Internal storage"), homeDir)); 58 | 59 | for (const QStorageInfo &storage : QStorageInfo::mountedVolumes()) { 60 | 61 | QString mountPoint = storage.rootPath(); 62 | 63 | // Sailfish OS specific mount point base for SD cards! 64 | if (storage.isValid() && 65 | storage.isReady() && 66 | (mountPoint.startsWith("/media") || 67 | mountPoint.startsWith("/run/media/") /* SFOS >= 2.2 */ ) 68 | ) { 69 | 70 | qDebug() << "Found storage:" << mountPoint; 71 | m_storage << Storage(QDir(mountPoint).dirName(), mountPoint); 72 | } 73 | } 74 | 75 | endResetModel(); 76 | emit rowCountChanged(); 77 | } 78 | -------------------------------------------------------------------------------- /src/storagemodel.h: -------------------------------------------------------------------------------- 1 | #ifndef STORAGEMODEL_H 2 | #define STORAGEMODEL_H 3 | 4 | #include 5 | #include 6 | 7 | class Storage 8 | { 9 | public: 10 | explicit Storage(const QString &name, const QString &path); 11 | QString name() const { return m_name; } 12 | QString path() const { return m_path; } 13 | private: 14 | QString m_name, m_path; 15 | }; 16 | 17 | class StorageModel : public QAbstractListModel 18 | { 19 | Q_OBJECT 20 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 21 | 22 | public: 23 | enum StorageRoles 24 | { 25 | StorageName = Qt::UserRole + 1, 26 | StoragePath 27 | }; 28 | 29 | StorageModel(); 30 | virtual QHash roleNames() const; 31 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 32 | virtual QVariant data(const QModelIndex &index, int role) const; 33 | Q_INVOKABLE QVariant getName(int index) const { return m_storage.at(index).name(); } 34 | Q_INVOKABLE QVariant getPath(int index) const { return m_storage.at(index).path(); } 35 | public slots: 36 | void scan(); 37 | private: 38 | QList m_storage; 39 | 40 | signals: 41 | void rowCountChanged(); 42 | 43 | }; 44 | 45 | #endif // STORAGEMODEL_H 46 | -------------------------------------------------------------------------------- /src/wbmodel.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #include "wbmodel.h" 20 | 21 | WbModel::WbModel() 22 | { 23 | } 24 | 25 | QHash WbModel::roleNames() const 26 | { 27 | QHash roles; 28 | roles[WbName] = "name"; 29 | roles[WbValue] = "value"; 30 | return roles; 31 | } 32 | 33 | int WbModel::rowCount(const QModelIndex &parent) const 34 | { 35 | Q_UNUSED(parent); 36 | return m_wbModes.size(); 37 | } 38 | 39 | QVariant WbModel::data(const QModelIndex &index, int role) const 40 | { 41 | QVariant v; 42 | 43 | if (!index.isValid() || index.row() > rowCount(index) || index.row() < 0) { 44 | return v; 45 | } 46 | 47 | if (role == WbName) { 48 | v = m_wbModes.at(index.row()).second; 49 | } else if (role == WbValue) { 50 | v = m_wbModes.at(index.row()).first; 51 | } 52 | 53 | return v; 54 | } 55 | 56 | void WbModel::setCamera(QObject *camera) 57 | { 58 | // even when m_camera instance is the same, deviceId could have changed and so available focus modes 59 | m_camera = camera->property("mediaObject").value(); 60 | 61 | beginResetModel(); 62 | m_wbModes.clear(); 63 | for (int c = (int)QCameraImageProcessing::WhiteBalanceAuto; 64 | c <= (int)QCameraImageProcessing::WhiteBalanceWarmFluorescent; c++) { 65 | if (m_camera->imageProcessing()->isWhiteBalanceModeSupported((QCameraImageProcessing::WhiteBalanceMode)c)) { 66 | qDebug() << "Found support for" << (QCameraImageProcessing::WhiteBalanceMode)c; 67 | m_wbModes.push_back(std::make_pair((QCameraImageProcessing::WhiteBalanceMode)c, wbName((QCameraImageProcessing::WhiteBalanceMode)c))); 68 | } 69 | } 70 | endResetModel(); 71 | emit rowCountChanged(); 72 | 73 | if (m_wbModes.size() == 0) { 74 | qDebug() << "No white balance modes found"; 75 | } 76 | } 77 | 78 | QString WbModel::wbName(QCameraImageProcessing::WhiteBalanceMode wb) const 79 | { 80 | QString name; 81 | 82 | switch (wb) { 83 | case QCameraImageProcessing::WhiteBalanceAuto: 84 | name = tr("Auto"); 85 | break; 86 | case QCameraImageProcessing::WhiteBalanceManual: 87 | name = tr("Manual"); 88 | break; 89 | case QCameraImageProcessing::WhiteBalanceSunlight: 90 | name = tr("Sunlight"); 91 | break; 92 | case QCameraImageProcessing::WhiteBalanceCloudy: 93 | name = tr("Cloudy"); 94 | break; 95 | case QCameraImageProcessing::WhiteBalanceShade: 96 | name = tr("Shade"); 97 | break; 98 | case QCameraImageProcessing::WhiteBalanceTungsten: 99 | name = tr("Tungsten"); 100 | break; 101 | case QCameraImageProcessing::WhiteBalanceFluorescent: 102 | name = tr("Fluorescent"); 103 | break; 104 | case QCameraImageProcessing::WhiteBalanceFlash: 105 | name = tr("Flash"); 106 | break; 107 | case QCameraImageProcessing::WhiteBalanceSunset: 108 | name = tr("Sunset"); 109 | break; 110 | case QCameraImageProcessing::WhiteBalanceWarmFluorescent: 111 | name = tr("Warm Fluorescent"); 112 | break; 113 | default: 114 | name = tr("Unknown"); 115 | break; 116 | } 117 | return name; 118 | } 119 | -------------------------------------------------------------------------------- /src/wbmodel.h: -------------------------------------------------------------------------------- 1 | /** 2 | harbour-advanced-camera C++ Camera Models 3 | Copyright (C) 2019 Adam Pigg (adam@piggz.co.uk) 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | **/ 19 | #ifndef WBMODEL_H 20 | #define WBMODEL_H 21 | 22 | #include 23 | #include 24 | 25 | class WbModel : public QAbstractListModel 26 | { 27 | Q_OBJECT 28 | Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged) 29 | 30 | public: 31 | 32 | enum WbRoles { 33 | WbName = Qt::UserRole + 1, 34 | WbValue 35 | }; 36 | 37 | WbModel(); 38 | 39 | virtual QHash roleNames() const; 40 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 41 | virtual QVariant data(const QModelIndex &index, int role) const; 42 | 43 | Q_INVOKABLE void setCamera(QObject *camera); 44 | 45 | private: 46 | std::vector> m_wbModes; 47 | QCamera *m_camera = nullptr; 48 | 49 | QString wbName(QCameraImageProcessing::WhiteBalanceMode wb) const; 50 | 51 | signals: 52 | void rowCountChanged(); 53 | }; 54 | 55 | #endif // EFFECTSMODEL_H 56 | --------------------------------------------------------------------------------