Unity 8
PreviewImageGallery.qml
1 /*
2  * Copyright (C) 2014 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.4
18 import Ubuntu.Components 1.3
19 import "../../Components"
20 
21 /*! This preview widget shows a horizontal list of images.
22  * The URIs for the images should be an array in widgetData["sources"].
23  * Images fall back to widgetData["fallback"] if loading fails
24  */
25 
26 PreviewWidget {
27  id: root
28  implicitHeight: units.gu(22)
29 
30  property Item rootItem: QuickUtils.rootItem(root)
31 
32  ListView {
33  id: previewImageListView
34  objectName: "previewImageListView"
35  spacing: units.gu(1)
36  anchors.fill: parent
37  orientation: ListView.Horizontal
38  cacheBuffer: width * 3
39  model: root.widgetData["sources"]
40  clip: true
41  highlightMoveDuration: 0 // QTBUG-53460
42 
43  onCurrentIndexChanged: overlay.updateInitialItem()
44 
45  LazyImage {
46  objectName: "placeholderScreenshot"
47  anchors {
48  top: parent.top
49  bottom: parent.bottom
50  }
51  scaleTo: "height"
52  source: "broken_image"
53  initialWidth: units.gu(13)
54  visible: previewImageListView.count == 0
55  }
56 
57  delegate: LazyImage {
58  objectName: "previewImage" + index
59  anchors {
60  top: parent.top
61  bottom: parent.bottom
62  }
63  source: modelData || root.widgetData["fallback"] || ""
64  scaleTo: "height"
65  initialWidth: units.gu(13)
66  pressed: mouseArea.pressed
67 
68  MouseArea {
69  id: mouseArea
70  anchors.fill: parent
71  onClicked: {
72  previewImageListView.currentIndex = index;
73  overlay.updateInitialItem();
74  overlay.show();
75  }
76  }
77 
78  Connections {
79  target: sourceImage
80  // If modelData would change after failing to load it would not be
81  // reloaded since the source binding is destroyed by the source = fallback
82  // But at the moment the model never changes
83  onStatusChanged: if (sourceImage.status === Image.Error) sourceImage.source = widgetData["fallback"];
84  }
85  }
86  }
87 
88  PreviewOverlay {
89  id: overlay
90  objectName: "overlay"
91  parent: rootItem
92  anchors.fill: parent
93 
94  function updateInitialItem() {
95  initialX = rootItem.mapFromItem(previewImageListView.currentItem, 0, 0).x;
96  initialY = rootItem.mapFromItem(previewImageListView.currentItem, 0, 0).y;
97  initialWidth = previewImageListView.currentItem.width;
98  initialHeight = previewImageListView.currentItem.height;
99  }
100 
101  delegate: ListView {
102  id: overlayListView
103  objectName: "overlayListView"
104  anchors.fill: parent
105  orientation: ListView.Horizontal
106  highlightRangeMode: ListView.StrictlyEnforceRange
107  highlightMoveDuration: 0
108  snapMode: ListView.SnapOneItem
109  boundsBehavior: Flickable.DragAndOvershootBounds
110  model: root.widgetData["sources"]
111  currentIndex: previewImageListView.currentIndex
112 
113  onCurrentIndexChanged: {
114  // if the index changed while overlay is visible, it was from user interaction,
115  // let's update the index of the original listview
116  if (overlay.visible) {
117  previewImageListView.highlightMoveDuration = 0;
118  previewImageListView.highlightResizeDuration = 0;
119  previewImageListView.currentIndex = currentIndex;
120  previewImageListView.highlightMoveDuration = -1;
121  previewImageListView.highlightResizeDuration = -1;
122  }
123  }
124 
125  delegate: Image {
126  id: screenshot
127  anchors {
128  top: parent.top
129  bottom: parent.bottom
130  }
131  width: overlay.width
132  source: modelData || root.widgetData["fallback"] || ""
133  fillMode: Image.PreserveAspectFit
134  sourceSize { width: screenshot.width; height: screenshot.height }
135 
136  // If modelData would change after failing to load it would not be
137  // reloaded since the source binding is destroyed by the source = fallback
138  // But at the moment the model never changes
139  onStatusChanged: if (status === Image.Error) source = widgetData["fallback"];
140  }
141 
142  MouseArea {
143  anchors.fill: parent
144  onClicked: overlay.headerShown = !overlay.headerShown
145  }
146  }
147  }
148 }