mirror of https://github.com/qt/qtdoc.git
Remove PhotoViewer example
Fixes: QTBUG-113593 Change-Id: Idafd79a140067fac9c9f27440f4f43453e2e2ddf Pick-to: 6.5 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
3c0d43145d
commit
117382f261
|
@ -18,7 +18,6 @@ if(TARGET Qt6::Quick AND TARGET Qt6::QuickControls2)
|
|||
endif()
|
||||
if(TARGET Qt6::Quick AND TARGET Qt6::Network AND TARGET Qt6::QmlXmlListModel)
|
||||
qt_internal_add_example(rssnews)
|
||||
qt_internal_add_example(photoviewer)
|
||||
endif()
|
||||
if(TARGET Qt6::Quick AND TARGET Qt6::qsb AND TARGET Qt6::Pdf)
|
||||
qt_internal_add_example(photosurface)
|
||||
|
|
|
@ -20,8 +20,5 @@ qtHaveModule(quick) {
|
|||
qtHaveModule(xml) {
|
||||
SUBDIRS += rssnews
|
||||
}
|
||||
qtHaveModule(quickcontrols2) {
|
||||
SUBDIRS += photoviewer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(photoviewer LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/demos/photoviewer")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml QmlXmlListModel Quick)
|
||||
|
||||
qt_add_executable(photoviewer
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(photoviewer PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(photoviewer PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Qml
|
||||
Qt6::Quick
|
||||
Qt6::QmlXmlListModel
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(qmake_immediate_resource_files
|
||||
"PhotoViewerCore/AlbumDelegate.qml"
|
||||
"PhotoViewerCore/BusyIndicator.qml"
|
||||
"PhotoViewerCore/Button.qml"
|
||||
"PhotoViewerCore/EditableButton.qml"
|
||||
"PhotoViewerCore/PhotoDelegate.qml"
|
||||
"PhotoViewerCore/ProgressBar.qml"
|
||||
"PhotoViewerCore/RssModel.qml"
|
||||
"PhotoViewerCore/Tag.qml"
|
||||
"PhotoViewerCore/images/box-shadow.png"
|
||||
"PhotoViewerCore/images/busy.png"
|
||||
"PhotoViewerCore/images/cardboard.png"
|
||||
"PhotoViewerCore/script/script.mjs"
|
||||
"main.qml"
|
||||
)
|
||||
|
||||
qt_add_resources(photoviewer "qmake_immediate"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${qmake_immediate_resource_files}
|
||||
)
|
||||
|
||||
if(lupdate_only)
|
||||
target_sources(photoviewer PRIVATE
|
||||
*.qml
|
||||
PhotoViewerCore/*.qml
|
||||
PhotoViewerCore/script/*.js
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS photoviewer
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
|
@ -1,125 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
import QtQml.XmlListModel
|
||||
import QtQml.Models
|
||||
|
||||
Component {
|
||||
id: albumDelegate
|
||||
Package {
|
||||
|
||||
Item {
|
||||
Package.name: 'browser'
|
||||
GridView {
|
||||
id: photosGridView; model: visualModel.parts.grid; width: mainWindow.width; height: mainWindow.height - 21
|
||||
x: 0; y: 21; cellWidth: 160; cellHeight: 153; interactive: false
|
||||
onCurrentIndexChanged: photosListView.positionViewAtIndex(currentIndex, ListView.Contain)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Package.name: 'fullscreen'
|
||||
ListView {
|
||||
id: photosListView; model: visualModel.parts.list; orientation: Qt.Horizontal
|
||||
width: mainWindow.width; height: mainWindow.height; interactive: false
|
||||
onCurrentIndexChanged: photosGridView.positionViewAtIndex(currentIndex, GridView.Contain)
|
||||
highlightRangeMode: ListView.StrictlyEnforceRange; snapMode: ListView.SnapOneItem
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Package.name: 'album'
|
||||
id: albumWrapper; width: 210; height: 220
|
||||
|
||||
DelegateModel {
|
||||
id: visualModel; delegate: PhotoDelegate { }
|
||||
model: RssModel { id: rssModel; tags: tag }
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
id: busyIndicator
|
||||
anchors { centerIn: parent; verticalCenterOffset: -20 }
|
||||
on: rssModel.status != XmlListModel.Ready
|
||||
}
|
||||
|
||||
PathView {
|
||||
id: photosPathView; model: visualModel.parts.stack; pathItemCount: 5
|
||||
visible: !busyIndicator.visible
|
||||
anchors.centerIn: parent; anchors.verticalCenterOffset: -30
|
||||
path: Path {
|
||||
PathAttribute { name: 'z'; value: 9999.0 }
|
||||
PathLine { x: 1; y: 1 }
|
||||
PathAttribute { name: 'z'; value: 0.0 }
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: mainWindow.editMode ? photosModel.remove(index) : albumWrapper.state = 'inGrid'
|
||||
}
|
||||
|
||||
Tag {
|
||||
anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom; bottomMargin: 10 }
|
||||
frontLabel: tag; backLabel: qsTr("Remove"); flipped: mainWindow.editMode
|
||||
onTagChanged: function(tag) { rssModel.tags = tag }
|
||||
onBackClicked: if (mainWindow.editMode) photosModel.remove(index);
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: 'inGrid'
|
||||
PropertyChanges { target: photosGridView; interactive: true }
|
||||
PropertyChanges { target: albumsShade; opacity: 1 }
|
||||
PropertyChanges { target: backButton; onClicked: albumWrapper.state = ''; y: 6 }
|
||||
},
|
||||
State {
|
||||
name: 'fullscreen'; extend: 'inGrid'
|
||||
PropertyChanges { target: photosGridView; interactive: false }
|
||||
PropertyChanges { target: photosListView; interactive: true }
|
||||
PropertyChanges { target: photosShade; opacity: 1 }
|
||||
PropertyChanges { target: backButton; y: -backButton.height - 8 }
|
||||
}
|
||||
]
|
||||
|
||||
NumberAnimation {
|
||||
id: onAddAmination
|
||||
target: albumWrapper
|
||||
properties: "scale"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
GridView.onAdd: onAddAmination
|
||||
|
||||
SequentialAnimation {
|
||||
id: onRemoveAnimation
|
||||
PropertyAction {
|
||||
target: albumWrapper; property: "GridView.delayRemove"; value: true
|
||||
}
|
||||
NumberAnimation {
|
||||
target: albumWrapper; property: "scale"; from: 1.0; to: 0.0; easing.type: Easing.OutQuad
|
||||
}
|
||||
PropertyAction {
|
||||
target: albumWrapper; property: "GridView.delayRemove"; value: false
|
||||
}
|
||||
}
|
||||
GridView.onRemove: onRemoveAnimation
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: '*'; to: 'inGrid'
|
||||
SequentialAnimation {
|
||||
NumberAnimation { properties: 'opacity'; duration: 250 }
|
||||
PauseAnimation { duration: 350 }
|
||||
NumberAnimation { target: backButton; properties: "y"; duration: 200; easing.type: Easing.OutQuad }
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: 'inGrid'; to: '*'
|
||||
NumberAnimation { properties: "y,opacity"; easing.type: Easing.OutQuad; duration: 300 }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
|
||||
Image {
|
||||
id: container
|
||||
property bool on: false
|
||||
|
||||
source: "images/busy.png"; visible: container.on
|
||||
NumberAnimation on rotation { running: container.on; from: 0; to: 360; loops: Animation.Infinite; duration: 1200 }
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: container
|
||||
|
||||
property alias label: labelText.text
|
||||
property color tint: "transparent"
|
||||
signal clicked
|
||||
|
||||
width: labelText.width + 70 ; height: labelText.height + 18
|
||||
|
||||
BorderImage {
|
||||
anchors { fill: container; leftMargin: -6; topMargin: -6; rightMargin: -8; bottomMargin: -8 }
|
||||
source: 'images/box-shadow.png'
|
||||
border.left: 10; border.top: 10; border.right: 10; border.bottom: 10
|
||||
}
|
||||
|
||||
Image { anchors.fill: parent; source: "images/cardboard.png"; antialiasing: true }
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: container; color: container.tint; visible: container.tint != ""
|
||||
opacity: 0.25
|
||||
}
|
||||
|
||||
Text { id: labelText; font.pixelSize: 15; anchors.centerIn: parent }
|
||||
|
||||
MouseArea {
|
||||
anchors { fill: parent; leftMargin: -20; topMargin: -20; rightMargin: -20; bottomMargin: -20 }
|
||||
onClicked: container.clicked()
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: container
|
||||
|
||||
property string label
|
||||
signal clicked
|
||||
|
||||
width: textInput.width + 70 ; height: textInput.height + 18
|
||||
|
||||
BorderImage {
|
||||
anchors { fill: container; leftMargin: -6; topMargin: -6; rightMargin: -8; bottomMargin: -8 }
|
||||
source: 'images/box-shadow.png';
|
||||
border.left: 10; border.top: 10; border.right: 10; border.bottom: 10
|
||||
}
|
||||
|
||||
Image { anchors.fill: parent; source: "images/cardboard.png"; antialiasing: true }
|
||||
|
||||
TextInput {
|
||||
id: textInput; text: label; font.pixelSize: 15; anchors.centerIn: parent
|
||||
Keys.onReturnPressed: {
|
||||
container.label = textInput.text
|
||||
container.focus = true
|
||||
}
|
||||
Keys.onEnterPressed: {
|
||||
container.label = textInput.text
|
||||
container.focus = true
|
||||
}
|
||||
Keys.onEscapePressed: {
|
||||
textInput.text = container.label
|
||||
container.focus = true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: container; border.color: "steelblue"; border.width: 4
|
||||
color: "transparent"; visible: textInput.focus; antialiasing: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors { fill: parent; leftMargin: -20; topMargin: -20; rightMargin: -20; bottomMargin: -20 }
|
||||
onClicked: { textInput.forceActiveFocus(); Qt.inputMethod.show(); }
|
||||
}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
import "script/script.mjs" as Script
|
||||
|
||||
Package {
|
||||
Item { id: stackItem; Package.name: 'stack'; width: 160; height: 153; z: stackItem.PathView.z }
|
||||
Item { id: listItem; Package.name: 'list'; width: mainWindow.width + 40; height: 153 }
|
||||
Item { id: gridItem; Package.name: 'grid'; width: 160; height: 153 }
|
||||
|
||||
Item {
|
||||
width: 160; height: 153
|
||||
|
||||
Item {
|
||||
id: photoWrapper
|
||||
|
||||
property double randomAngle: Math.random() * (2 * 6 + 1) - 6
|
||||
property double randomAngle2: Math.random() * (2 * 6 + 1) - 6
|
||||
|
||||
x: 0; y: 0; width: 140; height: 133
|
||||
z: stackItem.PathView.z; rotation: photoWrapper.randomAngle
|
||||
|
||||
BorderImage {
|
||||
anchors {
|
||||
fill: originalImage.status == Image.Ready ? border : placeHolder
|
||||
leftMargin: -6; topMargin: -6; rightMargin: -8; bottomMargin: -8
|
||||
}
|
||||
source: 'images/box-shadow.png'
|
||||
border.left: 10; border.top: 10; border.right: 10; border.bottom: 10
|
||||
}
|
||||
Rectangle {
|
||||
id: placeHolder
|
||||
|
||||
property int w: 400
|
||||
property int h: 400
|
||||
property double s: Script.calculateScale(w, h, photoWrapper.width)
|
||||
|
||||
color: 'white'; anchors.centerIn: parent; antialiasing: true
|
||||
width: w * s; height: h * s; visible: originalImage.status != Image.Ready
|
||||
Rectangle {
|
||||
color: "#878787"; antialiasing: true
|
||||
anchors { fill: parent; topMargin: 3; bottomMargin: 3; leftMargin: 3; rightMargin: 3 }
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: border; color: 'white'; anchors.centerIn: parent; antialiasing: true
|
||||
width: originalImage.paintedWidth + 6; height: originalImage.paintedHeight + 6
|
||||
visible: !placeHolder.visible
|
||||
}
|
||||
BusyIndicator { anchors.centerIn: parent; on: originalImage.status != Image.Ready }
|
||||
Image {
|
||||
id: originalImage; antialiasing: true;
|
||||
source: link; cache: false
|
||||
fillMode: Image.PreserveAspectFit; width: photoWrapper.width; height: photoWrapper.height
|
||||
}
|
||||
Image {
|
||||
id: hqImage; antialiasing: true; source: ""; visible: false; cache: false
|
||||
fillMode: Image.PreserveAspectFit; width: photoWrapper.width; height: photoWrapper.height
|
||||
}
|
||||
Binding {
|
||||
target: mainWindow; property: "downloadProgress"; value: hqImage.progress
|
||||
when: listItem.ListView.isCurrentItem
|
||||
}
|
||||
Binding {
|
||||
target: mainWindow; property: "imageLoading"
|
||||
value: (hqImage.status == Image.Loading) ? 1 : 0; when: listItem.ListView.isCurrentItem
|
||||
}
|
||||
MouseArea {
|
||||
width: originalImage.paintedWidth; height: originalImage.paintedHeight; anchors.centerIn: originalImage
|
||||
onClicked: {
|
||||
if (albumWrapper.state == 'inGrid') {
|
||||
gridItem.GridView.view.currentIndex = index;
|
||||
albumWrapper.state = 'fullscreen'
|
||||
} else {
|
||||
gridItem.GridView.view.currentIndex = index;
|
||||
albumWrapper.state = 'inGrid'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: 'stacked'; when: albumWrapper.state == ''
|
||||
ParentChange { target: photoWrapper; parent: stackItem; x: 10; y: 10 }
|
||||
PropertyChanges { target: photoWrapper; opacity: stackItem.PathView.onPath ? 1.0 : 0.0 }
|
||||
},
|
||||
State {
|
||||
name: 'inGrid'; when: albumWrapper.state == 'inGrid'
|
||||
ParentChange { target: photoWrapper; parent: gridItem; x: 10; y: 10; rotation: photoWrapper.randomAngle2 }
|
||||
},
|
||||
State {
|
||||
name: 'fullscreen'; when: albumWrapper.state == 'fullscreen'
|
||||
ParentChange {
|
||||
target: photoWrapper; parent: listItem; x: 0; y: 0; rotation: 0
|
||||
width: mainWindow.width; height: mainWindow.height
|
||||
}
|
||||
PropertyChanges { target: border; opacity: 0 }
|
||||
PropertyChanges { target: hqImage; source: listItem.ListView.isCurrentItem ? link : ""; visible: true }
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: 'stacked'; to: 'inGrid'
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 10 * index }
|
||||
ParentAnimation {
|
||||
target: photoWrapper; via: foreground
|
||||
NumberAnimation {
|
||||
target: photoWrapper; properties: 'x,y,rotation,opacity'; duration: 600; easing.type: 'OutQuart'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: 'inGrid'; to: 'stacked'
|
||||
ParentAnimation {
|
||||
target: photoWrapper; via: foreground
|
||||
NumberAnimation { properties: 'x,y,rotation,opacity'; duration: 600; easing.type: 'OutQuart' }
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: 'inGrid'; to: 'fullscreen'
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: gridItem.GridView.isCurrentItem ? 0 : 600 }
|
||||
ParentAnimation {
|
||||
target: photoWrapper; via: foreground
|
||||
NumberAnimation {
|
||||
targets: [ photoWrapper, border ]
|
||||
properties: 'x,y,width,height,opacity,rotation'
|
||||
duration: gridItem.GridView.isCurrentItem ? 600 : 1; easing.type: 'OutQuart'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: 'fullscreen'; to: 'inGrid'
|
||||
ParentAnimation {
|
||||
target: photoWrapper; via: foreground
|
||||
NumberAnimation {
|
||||
targets: [ photoWrapper, border ]
|
||||
properties: 'x,y,width,height,rotation,opacity'
|
||||
duration: gridItem.GridView.isCurrentItem ? 600 : 1; easing.type: 'OutQuart'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: container
|
||||
|
||||
property real progress: 0
|
||||
|
||||
Behavior on opacity { NumberAnimation { duration: 600 } }
|
||||
|
||||
Rectangle { anchors.fill: parent; color: "black"; opacity: 0.5 }
|
||||
|
||||
Rectangle {
|
||||
id: fill; color: "white"; height: container.height
|
||||
width: container.width * container.progress
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQml.XmlListModel
|
||||
|
||||
XmlListModel {
|
||||
property string tags : ""
|
||||
|
||||
function encodeTags(x) { return encodeURIComponent(x.replace(' ',',')); }
|
||||
|
||||
source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+encodeTags(tags)+"&" : "")
|
||||
|
||||
query: "/feed/entry"
|
||||
|
||||
XmlListModelRole { name: "title"; elementName: "title"; attributeName: "" }
|
||||
XmlListModelRole { name: "link"; elementName: "link"; attributeName: "href" }
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
|
||||
Flipable {
|
||||
id: flipable
|
||||
|
||||
property alias frontLabel: frontButton.label
|
||||
property alias backLabel: backButton.label
|
||||
|
||||
property int angle: 0
|
||||
property int randomAngle: Math.random() * (2 * 6 + 1) - 6
|
||||
property bool flipped: false
|
||||
|
||||
signal frontClicked
|
||||
signal backClicked
|
||||
signal tagChanged(string tag)
|
||||
|
||||
front: EditableButton {
|
||||
id: frontButton; rotation: flipable.randomAngle
|
||||
anchors { centerIn: parent; verticalCenterOffset: -20 }
|
||||
onClicked: flipable.frontClicked()
|
||||
onLabelChanged: flipable.tagChanged(label)
|
||||
}
|
||||
|
||||
back: Button {
|
||||
id: backButton; tint: "red"; rotation: flipable.randomAngle
|
||||
anchors { centerIn: parent; verticalCenterOffset: -20 }
|
||||
onClicked: flipable.backClicked()
|
||||
}
|
||||
|
||||
transform: Rotation {
|
||||
origin.x: flipable.width / 2; origin.y: flipable.height / 2
|
||||
axis.x: 0; axis.y: 1; axis.z: 0
|
||||
angle: flipable.angle
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "back"; when: flipable.flipped
|
||||
PropertyChanges { target: flipable; angle: 180 }
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
ParallelAnimation {
|
||||
NumberAnimation { properties: "angle"; duration: 400 }
|
||||
SequentialAnimation {
|
||||
NumberAnimation { target: flipable; property: "scale"; to: 0.8; duration: 200 }
|
||||
NumberAnimation { target: flipable; property: "scale"; to: 1.0; duration: 200 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 371 B |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.3 KiB |
|
@ -1,15 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
export function calculateScale(width, height, cellSize) {
|
||||
var widthScale = (cellSize * 1.0) / width
|
||||
var heightScale = (cellSize * 1.0) / height
|
||||
var scale = 0
|
||||
|
||||
if (widthScale <= heightScale) {
|
||||
scale = widthScale;
|
||||
} else if (heightScale < widthScale) {
|
||||
scale = heightScale;
|
||||
}
|
||||
return scale;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 45 KiB |
|
@ -1,303 +0,0 @@
|
|||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\title Qt Quick Demo - Photo Viewer
|
||||
\ingroup qtquickdemos
|
||||
\example demos/photoviewer
|
||||
\brief A QML photo viewer that uses \l XmlListModel and \l XmlListModelRole
|
||||
to download Flickr feeds, and \l Package to display the photos in different
|
||||
views.
|
||||
\meta {tag} {demo,quick,quickcontrols,touch}
|
||||
|
||||
\image qtquick-demo-photoviewer-small.png
|
||||
|
||||
\e{Photo Viewer} demonstrates the following \l{Qt Quick} features:
|
||||
|
||||
\list
|
||||
\li Using custom QML types.
|
||||
\li Using Qt Quick Controls to create an application window.
|
||||
\li Using the \l Package type with a \l DelegateModel to provide
|
||||
delegates with a shared context to multiple views.
|
||||
\li Using XML list models to download Flickr feeds.
|
||||
\li Using the \l Flipable type to create labels with different text on
|
||||
the front and back.
|
||||
\li Using the \l PathView, \l Path, \l PathAttribute, and \l PathLine
|
||||
types to lay out photos on a path.
|
||||
\li Providing feedback to users while data is loading.
|
||||
\li Localizing applications.
|
||||
\endlist
|
||||
|
||||
\include examples-run.qdocinc
|
||||
|
||||
\section1 Using Custom Types
|
||||
|
||||
In the Photo Viewer app, we use the following custom types that are each
|
||||
defined in a separate .qml file:
|
||||
|
||||
\list
|
||||
\li \c AlbumDelegate.qml
|
||||
\li \c BusyIndicator.qml
|
||||
\li \c Button.qml
|
||||
\li \c EditableButton.qml
|
||||
\li \c PhotoDelegate.qml
|
||||
\li \c ProgressBar.qml
|
||||
\li \c RssModel.qml
|
||||
\li \c Tag.qml
|
||||
\endlist
|
||||
|
||||
To use the custom types, we add an import statement to the main QML file,
|
||||
\c main.qml, that imports the folder called \c PhotoViewerCore where the
|
||||
types are located:
|
||||
|
||||
\quotefromfile demos/photoviewer/main.qml
|
||||
\skipto PhotoViewerCore
|
||||
\printuntil "
|
||||
|
||||
\section1 Creating the Main Window
|
||||
|
||||
In \c main.qml, we use the \l ApplicationWindow Qt Quick Control to create the
|
||||
app main window:
|
||||
|
||||
\quotefromfile demos/photoviewer/main.qml
|
||||
\skipto ApplicationWindow
|
||||
\printuntil visible
|
||||
|
||||
We use a ListModel type with \l ListElement types to display photo albums:
|
||||
|
||||
\skipto ListModel
|
||||
\printuntil Prague
|
||||
\printuntil }
|
||||
|
||||
List elements are defined like other QML types except that they contain a
|
||||
collection of \e role definitions instead of properties. Roles both define
|
||||
how the data is accessed and include the data itself. For each list element,
|
||||
we use the \c tag role to specify the photos to download.
|
||||
|
||||
A \l DelegateModel type is used together with the \l Package type to provide
|
||||
delegates to multiple views. The \c model property holds the model providing
|
||||
data for the delegate model and the \c delegate property specifies the
|
||||
template defining each item instantiated by a view:
|
||||
|
||||
\printuntil DelegateModel
|
||||
|
||||
We use a \l GridView type to lay out the albums as a grid:
|
||||
|
||||
\printuntil }
|
||||
|
||||
The \c model property references the package name \c album that we specify
|
||||
in \c AlbumDelegate.qml. We use the \l Package type to allow the photos
|
||||
to move between different views. The \l Package contains the named items
|
||||
\c browser, \c fullscreen, and \c album:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
|
||||
\skipto Package
|
||||
\printuntil albumWrapper
|
||||
|
||||
The named items are used as the delegates by the views that reference the
|
||||
special \l {DelegateModel::parts} property to select the model that provides
|
||||
the chosen delegate.
|
||||
|
||||
We use a \l ListView type to lay out albums in other views:
|
||||
|
||||
\quotefromfile demos/photoviewer/main.qml
|
||||
\skipto ListView
|
||||
\printuntil }
|
||||
\skipto ListView
|
||||
\printuntil }
|
||||
|
||||
\section1 Displaying Photos
|
||||
|
||||
We use the \c PhotoDelegate custom type that is specified in
|
||||
\c PhotoDelegate.qml to display photos. We use a \l Package type to lay
|
||||
out the photos either in a stack, list, or a grid:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/PhotoDelegate.qml
|
||||
\skipto Package
|
||||
\printuntil gridItem
|
||||
|
||||
The photos are rotated at random angles by using the \c Math.random()
|
||||
JavaScript method:
|
||||
|
||||
\printuntil stackItem
|
||||
|
||||
We use a \l BorderImage type to create borders for the images:
|
||||
|
||||
\printuntil border.left
|
||||
\printuntil }
|
||||
|
||||
\section1 Downloading Flickr Feeds
|
||||
|
||||
In \c AlbumDelegate.qml, we use the \l DelegateModel to provide the
|
||||
\c PhotoDelegate delegate to the \c RssModel model:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
|
||||
\skipto DelegateModel
|
||||
\printuntil RssModel
|
||||
\printuntil }
|
||||
|
||||
In \c RssModel.qml, we use the \l XmlListModel type as a data source for
|
||||
\l Package objects to download photos from the selected feeds:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/RssModel.qml
|
||||
\skipto XmlListModel
|
||||
\printuntil encodeTags
|
||||
|
||||
We use the \c tags custom property to specify which photos to download. The
|
||||
\c encodeTags custom function uses the \c encodeURIComponent JavaScript
|
||||
method to ensure that the requests to the server are correctly formatted.
|
||||
|
||||
We use the \c source property to fetch photos that have the specified tags
|
||||
attached from public Flickr feeds:
|
||||
|
||||
\printuntil query
|
||||
|
||||
The \c query property specifies that the \l XmlListModel generates a model
|
||||
item for each feed entry.
|
||||
|
||||
We use the \l XmlListModelRole type to specify the model item attributes.
|
||||
Each model item has the \c title and \c link attributes that match the
|
||||
values of the corresponding feed entry:
|
||||
|
||||
\printuntil link
|
||||
|
||||
\section1 Creating Flipable Labels
|
||||
|
||||
When users select the \b Edit button, the album labels are flipped from
|
||||
their front side to their back side and the text on them changes from album
|
||||
name to \b Remove.
|
||||
|
||||
In \c AlbumDelegate.qml, we use the \c Tag custom type to specify the
|
||||
text to display on the front and back sides of album labels:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
|
||||
\skipto Tag
|
||||
\printuntil onBackClicked
|
||||
\printuntil }
|
||||
|
||||
The \c onTagChanged signal handler is used to change the tag based on
|
||||
which the model is populated. The \c onBackClicked signal handler is used to
|
||||
remove the album.
|
||||
|
||||
In \c Tag.qml, we use a \l Flipable type with custom properties and
|
||||
signals to create the labels:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/Tag.qml
|
||||
\skipto Flipable
|
||||
\printuntil tagChanged
|
||||
|
||||
The \c front property holds the \c EditableButton custom type that enables
|
||||
users to edit the label text:
|
||||
|
||||
\printuntil onLabelChanged
|
||||
\printuntil }
|
||||
|
||||
The \c back property holds the \c Button custom type that is used to remove
|
||||
the album:
|
||||
|
||||
\printuntil onClicked
|
||||
\printuntil }
|
||||
|
||||
\section1 Laying Out Photos on a Path
|
||||
|
||||
In \c AlbumDelegate.qml, we use a \l PathView type to lay out the photos
|
||||
provided by the \c visualModel.parts.stack model on a path that has the
|
||||
form of a stack:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
|
||||
\skipto PathView
|
||||
\printuntil 0.0
|
||||
\printuntil }
|
||||
\printuntil }
|
||||
|
||||
The \c path property holds the \l Path type that defines the path used by
|
||||
the \l PathView. The \l PathAttribute types are used to set a range of
|
||||
\c 0 to \c 9999 for the \c z attribute. This way, the path creates a stack
|
||||
of album photos. Because each \c PhotoDelegate is slightly rotated at a
|
||||
random angle, this results in a realistic-looking stack of photos.
|
||||
|
||||
\section1 Providing Feedback to Users
|
||||
|
||||
We use a busy indicator and a progress bar to indicate activity while
|
||||
Flickr feeds and photos are being loaded.
|
||||
|
||||
In \c AlbumDelegate.qml, we use the \c BusyIndicator custom type and the
|
||||
\c on custom property to display a rotating image while the Flickr feed is
|
||||
being loaded:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
|
||||
\skipto BusyIndicator
|
||||
\printuntil rssModel
|
||||
\printuntil }
|
||||
|
||||
In \c PhotoDelegate.qml, we use them to indicate activity while a photo is
|
||||
being loaded:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/PhotoDelegate.qml
|
||||
\skipto BusyIndicator
|
||||
\printuntil }
|
||||
|
||||
We define the \c BusyIndicator type in \c BusyIndicator.qml. We use an
|
||||
\l [QML] {Image} type to display an image and apply a \l NumberAnimation to
|
||||
its \c rotation property to rotate the image in an infinite loop:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/BusyIndicator.qml
|
||||
\skipto Image
|
||||
\printuntil }
|
||||
\printuntil }
|
||||
|
||||
In your apps, you can also use the \l BusyIndicator type from the
|
||||
\l {Qt Quick Controls} module.
|
||||
|
||||
In \c main.qml, we use the \c ProgressBar custom type to indicate progress
|
||||
while a high quality version of a photo is being opened on full screen:
|
||||
|
||||
\quotefromfile demos/photoviewer/main.qml
|
||||
\skipto ProgressBar
|
||||
\printuntil }
|
||||
|
||||
We define the \c ProgressBar type in \c ProgressBar.qml. We use a
|
||||
\l Rectangle type to create the progress bar and apply a \l NumberAnimation
|
||||
to its \c opacity property to change the color of the bar from black to
|
||||
white as data loading proceeds:
|
||||
|
||||
\quotefromfile demos/photoviewer/PhotoViewerCore/ProgressBar.qml
|
||||
\skipto Item
|
||||
\printuntil /^\}/
|
||||
|
||||
In your apps, you can also use the \l ProgressBar type from the
|
||||
\l {Qt Quick Controls} module.
|
||||
|
||||
\section1 Localizing Applications
|
||||
|
||||
The example application is translated into German and French. The translated
|
||||
strings are loaded at runtime according to the current locale.
|
||||
|
||||
We use a \l Column type in \c main.qml to position buttons for adding and
|
||||
editing albums and exiting the application:
|
||||
|
||||
\quotefromfile demos/photoviewer/main.qml
|
||||
\skipto Column
|
||||
\printuntil quit()
|
||||
\printuntil }
|
||||
\printuntil }
|
||||
|
||||
We use the \l[QML]{Qt::}{qsTr()} command to mark the button labels
|
||||
translatable.
|
||||
|
||||
We use the \c lupdate tool to generate the translation source files and
|
||||
the \c lrelease tool to convert the translated strings to the QM files used
|
||||
by the application at runtime. These files are stored in the \c i18n
|
||||
directory.
|
||||
|
||||
To make the application aware of the translations, we add code to the
|
||||
\c main() function in the \c {main.cpp} file. The code creates a
|
||||
\l QTranslator object, loads a translation according to the current locale
|
||||
at runtime, and installs the translator object into the application:
|
||||
|
||||
\quotefromfile demos/photoviewer/main.cpp
|
||||
\skipto main
|
||||
\printuntil app.installTranslator
|
||||
|
||||
\sa {QML Applications}
|
||||
*/
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de_DE">
|
||||
<context>
|
||||
<name>AlbumDelegate</name>
|
||||
<message>
|
||||
<location filename="../PhotoViewerCore/AlbumDelegate.qml" line="111"/>
|
||||
<source>Remove</source>
|
||||
<translation>Entfernen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="93"/>
|
||||
<source>Add</source>
|
||||
<translation>Zufügen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="102"/>
|
||||
<source>Edit</source>
|
||||
<translation>Bearbeiten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="107"/>
|
||||
<source>Quit</source>
|
||||
<translation>Verlassen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="122"/>
|
||||
<source>Back</source>
|
||||
<translation>Zurück</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en">
|
||||
</TS>
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="fr_FR">
|
||||
<context>
|
||||
<name>AlbumDelegate</name>
|
||||
<message>
|
||||
<location filename="../PhotoViewerCore/AlbumDelegate.qml" line="111"/>
|
||||
<source>Remove</source>
|
||||
<translation>Supprimer</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="93"/>
|
||||
<source>Add</source>
|
||||
<translation>Ajouter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="102"/>
|
||||
<source>Edit</source>
|
||||
<translation>Éditer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="107"/>
|
||||
<source>Quit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="122"/>
|
||||
<source>Back</source>
|
||||
<translation>Retour</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QTranslator>
|
||||
#include <QDebug>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QTranslator qtTranslator;
|
||||
if (qtTranslator.load(QLocale(), "qml", "_", ":/i18n/"))
|
||||
app.installTranslator(&qtTranslator);
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
|
||||
|
||||
return app.exec();
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import "PhotoViewerCore"
|
||||
|
||||
ApplicationWindow {
|
||||
id: mainWindow
|
||||
|
||||
visible: true
|
||||
|
||||
Rectangle {
|
||||
focus: true
|
||||
|
||||
Keys.onBackPressed: {
|
||||
event.accepted = true
|
||||
backButton.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
property real downloadProgress: 0
|
||||
property bool imageLoading: false
|
||||
property bool editMode: false
|
||||
|
||||
width: 800; height: 480; color: "#d5d6d8"
|
||||
|
||||
ListModel {
|
||||
id: photosModel
|
||||
ListElement { tag: "Flowers" }
|
||||
ListElement { tag: "Wildlife" }
|
||||
ListElement { tag: "Prague" }
|
||||
}
|
||||
|
||||
DelegateModel { id: albumVisualModel; model: photosModel; delegate: AlbumDelegate {} }
|
||||
|
||||
GridView {
|
||||
id: albumView; width: parent.width; height: parent.height; cellWidth: 210; cellHeight: 220
|
||||
model: albumVisualModel.parts.album; visible: albumsShade.opacity != 1.0
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 20; anchors { bottom: parent.bottom; right: parent.right; rightMargin: 20; bottomMargin: 20 }
|
||||
Button {
|
||||
id: newButton; label: qsTr("Add"); rotation: 3
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onClicked: {
|
||||
mainWindow.editMode = false
|
||||
photosModel.append( { tag: "" } )
|
||||
albumView.positionViewAtIndex(albumView.count - 1, GridView.Contain)
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: deleteButton; label: qsTr("Edit"); rotation: -2;
|
||||
onClicked: mainWindow.editMode = !mainWindow.editMode
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
Button {
|
||||
id: quitButton; label: qsTr("Quit"); rotation: -2;
|
||||
onClicked: Qt.quit()
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: albumsShade; color: mainWindow.color
|
||||
width: parent.width; height: parent.height; opacity: 0.0
|
||||
}
|
||||
|
||||
ListView { anchors.fill: parent; model: albumVisualModel.parts.browser; interactive: false }
|
||||
|
||||
Button {
|
||||
id: backButton
|
||||
label: qsTr("Back")
|
||||
rotation: 3
|
||||
x: parent.width - backButton.width - 6
|
||||
y: -backButton.height - 8
|
||||
visible: Qt.platform.os !== "android"
|
||||
}
|
||||
|
||||
Rectangle { id: photosShade; color: 'black'; width: parent.width; height: parent.height; opacity: 0; visible: opacity != 0.0 }
|
||||
|
||||
ListView { anchors.fill: parent; model: albumVisualModel.parts.fullscreen; interactive: false }
|
||||
|
||||
Item { id: foreground; anchors.fill: parent }
|
||||
|
||||
ProgressBar {
|
||||
progress: mainWindow.downloadProgress; width: parent.width; height: 4
|
||||
anchors.bottom: parent.bottom; opacity: mainWindow.imageLoading; visible: opacity != 0.0
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
TEMPLATE = app
|
||||
|
||||
QT += qml quick
|
||||
CONFIG += lrelease embed_translations
|
||||
|
||||
SOURCES += main.cpp
|
||||
|
||||
lupdate_only {
|
||||
SOURCES = *.qml \
|
||||
PhotoViewerCore/*.qml \
|
||||
PhotoViewerCore/script/*.js
|
||||
}
|
||||
|
||||
TRANSLATIONS += i18n/qml_fr.ts \
|
||||
i18n/qml_de.ts
|
||||
|
||||
EXTRA_TRANSLATIONS += i18n/qml_en.ts
|
||||
|
||||
RESOURCES += main.qml \
|
||||
PhotoViewerCore/AlbumDelegate.qml \
|
||||
PhotoViewerCore/BusyIndicator.qml \
|
||||
PhotoViewerCore/Button.qml \
|
||||
PhotoViewerCore/EditableButton.qml \
|
||||
PhotoViewerCore/PhotoDelegate.qml \
|
||||
PhotoViewerCore/ProgressBar.qml \
|
||||
PhotoViewerCore/RssModel.qml \
|
||||
PhotoViewerCore/Tag.qml \
|
||||
PhotoViewerCore/images/box-shadow.png \
|
||||
PhotoViewerCore/images/busy.png \
|
||||
PhotoViewerCore/images/cardboard.png \
|
||||
PhotoViewerCore/script/script.mjs \
|
||||
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/demos/photoviewer
|
||||
INSTALLS += target
|
|
@ -68,7 +68,6 @@ tst_examples::tst_examples()
|
|||
#ifdef QT_NO_XMLPATTERNS
|
||||
excludedDirs << "demos/twitter";
|
||||
excludedDirs << "demos/flickr";
|
||||
excludedDirs << "demos/photoviewer";
|
||||
excludedFiles << "snippets/qml/xmlrole.qml";
|
||||
excludedFiles << "particles/itemparticle/particleview.qml";
|
||||
excludedFiles << "views/visualdatamodel/slideshow.qml";
|
||||
|
|
Loading…
Reference in New Issue