Unity 8
 All Classes Functions Properties
Card.qml
1 /*
2  * Copyright (C) 2013 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.0
18 import Ubuntu.Components 0.1
19 // For image://albumart and image://thumbnailer image providers
20 import Ubuntu.Thumbnailer 0.1
21 
22 AbstractButton {
23  id: root
24  property var template
25  property var components
26  property var cardData
27 
28  property real fontScale: 1.0
29  property int headerAlignment: Text.AlignLeft
30  readonly property int headerHeight: headerLoader.item ? headerLoader.item.height : 0
31  property int fixedHeaderHeight: -1
32  readonly property string title: cardData && cardData["title"] || ""
33 
34  property bool showHeader: true
35 
36  implicitWidth: childrenRect.width
37  implicitHeight: summary.y + summary.height + (summary.text && backgroundLoader.active ? units.gu(1) : 0)
38 
39  Loader {
40  id: backgroundLoader
41  objectName: "backgroundLoader"
42 
43  readonly property bool artAndSummary: components["art"]["field"] && components["summary"] || false
44  active: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"] || artAndSummary)
45  anchors.fill: parent
46 
47  sourceComponent: UbuntuShape {
48  objectName: "background"
49  radius: "medium"
50  color: getColor(0) || "white"
51  gradientColor: getColor(1) || color
52  anchors.fill: parent
53  image: backgroundImage.source ? backgroundImage : null
54 
55  property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
56 
57  property Image backgroundImage: Image {
58  objectName: "backgroundImage"
59  source: {
60  if (cardData && typeof cardData["background"] === "string") return cardData["background"]
61  else if (template && typeof template["card-background"] === "string") return template["card-background"]
62  else return ""
63  }
64  }
65 
66  function getColor(index) {
67  if (cardData && typeof cardData["background"] === "object"
68  && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
69  return cardData["background"]["elements"][index];
70  } else if (template && typeof template["card-background"] === "object"
71  && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
72  return template["card-background"]["elements"][index];
73  } else return undefined;
74  }
75  }
76  }
77 
78  UbuntuShape {
79  id: artShape
80  radius: "medium"
81  objectName: "artShape"
82  anchors.horizontalCenter: template && template["card-layout"] === "horizontal" ? undefined : parent.horizontalCenter
83  anchors.left: template && template["card-layout"] === "horizontal" ? parent.left : undefined
84  visible: cardData && cardData["art"] || false
85 
86  readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1
87  readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect
88 
89  Component.onCompleted: updateWidthHeightBindings();
90  onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings();
91 
92  function updateWidthHeightBindings() {
93  if (aspectSmallerThanImageAspect) {
94  width = Qt.binding(function() { return !visible ? 0 : image.width });
95  height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect });
96  } else {
97  width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect });
98  height = Qt.binding(function() { return !visible ? 0 : image.height });
99  }
100  }
101 
102  image: Image {
103  objectName: "artImage"
104  source: cardData && cardData["art"] || ""
105  cache: true
106  // FIXME uncomment when having investigated / fixed the crash
107  //sourceSize.width: width > height ? width : 0
108  //sourceSize.height: height > width ? height : 0
109  fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop
110 
111  readonly property real aspect: implicitWidth / implicitHeight
112  readonly property bool isHorizontal: template && template["card-layout"] === "horizontal"
113 
114  Component.onCompleted: updateWidthHeightBindings();
115  onIsHorizontalChanged: updateWidthHeightBindings();
116 
117  function updateWidthHeightBindings() {
118  if (isHorizontal) {
119  width = Qt.binding(function() { return height * artShape.aspect });
120  height = Qt.binding(function() { return root.headerHeight });
121  } else {
122  width = Qt.binding(function() { return root.width });
123  height = Qt.binding(function() { return width / artShape.aspect });
124  }
125  }
126  }
127  }
128 
129  Loader {
130  id: overlayLoader
131  anchors {
132  left: artShape.left
133  right: artShape.right
134  bottom: artShape.bottom
135  }
136  active: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
137 
138  sourceComponent: ShaderEffect {
139  id: overlay
140 
141  height: headerLoader.item ? headerLoader.item.height : 0
142  opacity: headerLoader.item ? headerLoader.item.opacity * 0.6 : 0
143 
144  property var source: ShaderEffectSource {
145  id: shaderSource
146  sourceItem: artShape
147  onVisibleChanged: if (visible) scheduleUpdate()
148  live: false
149  sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
150  }
151 
152  vertexShader: "
153  uniform highp mat4 qt_Matrix;
154  attribute highp vec4 qt_Vertex;
155  attribute highp vec2 qt_MultiTexCoord0;
156  varying highp vec2 coord;
157  void main() {
158  coord = qt_MultiTexCoord0;
159  gl_Position = qt_Matrix * qt_Vertex;
160  }"
161 
162  fragmentShader: "
163  varying highp vec2 coord;
164  uniform sampler2D source;
165  uniform lowp float qt_Opacity;
166  void main() {
167  lowp vec4 tex = texture2D(source, coord);
168  gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
169  }"
170  }
171  }
172 
173  Loader {
174  id: headerLoader
175  objectName: "cardHeaderLoader"
176 
177  anchors {
178  top: {
179  if (template) {
180  if (template["overlay"]) return overlayLoader.top;
181  if (template["card-layout"] === "horizontal") return artShape.top;
182  }
183  return artShape.bottom;
184  }
185  left: {
186  if (template) {
187  if (!template["overlay"] && template["card-layout"] === "horizontal") return artShape.right;
188  }
189  return parent.left;
190  }
191  right: parent.right
192  }
193  active: cardData && cardData["title"] || cardData && cardData["mascot"] || false
194 
195  sourceComponent: CardHeader {
196  id: header
197  objectName: "cardHeader"
198 
199  mascot: cardData && cardData["mascot"] || ""
200  title: root.title
201  subtitle: cardData && cardData["subtitle"] || ""
202 
203  titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
204 
205  opacity: showHeader ? 1 : 0
206  inOverlay: root.template && root.template["overlay"] === true
207  fontColor: inOverlay ? "white" : summary.color
208  useMascotShape: !backgroundLoader.active && !inOverlay
209  headerAlignment: root.headerAlignment
210  height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight
211  fontScale: root.fontScale
212 
213  Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
214  }
215  }
216 
217  Label {
218  id: summary
219  objectName: "summaryLabel"
220  anchors {
221  top: headerLoader.active ? headerLoader.bottom : artShape.bottom
222  left: parent.left
223  right: parent.right
224  margins: backgroundLoader.active ? units.gu(1) : 0
225  topMargin: 0
226  }
227  wrapMode: Text.Wrap
228  maximumLineCount: 5
229  elide: Text.ElideRight
230  text: cardData && cardData["summary"] || ""
231  height: text ? implicitHeight : 0
232  fontSize: "small"
233  // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
234  color: backgroundLoader.active && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"
235  }
236 }