@@ -0,0 +1,213 @@
1+AbstractButton {
2+ id: root;
3+ property var cardData;
4+ property string artShapeStyle: "inset";
5+ property string backgroundShapeStyle: "inset";
6+ property real fontScale: 1.0;
7+ property var scopeStyle: null;
8+ property int fixedHeaderHeight: -1;
9+ property size fixedArtShapeSize: Qt.size(-1, -1);
10+ readonly property string title: cardData && cardData["title"] || "";
11+ property bool asynchronous: true;
12+ property bool showHeader: true;
13+ implicitWidth: childrenRect.width;
14+ enabled: true;
15+
16+Loader {
17+ id: backgroundLoader;
18+ objectName: "backgroundLoader";
19+ anchors.fill: parent;
20+ asynchronous: root.asynchronous;
21+ visible: status == Loader.Ready;
22+ sourceComponent: UbuntuShape {
23+ objectName: "background";
24+ radius: "medium";
25+ aspect: {
26+ switch (root.backgroundShapeStyle) {
27+ case "inset": return UbuntuShape.Inset;
28+ case "shadow": return UbuntuShape.DropShadow;
29+ default:
30+ case "flat": return UbuntuShape.Flat;
31+ }
32+ }
33+ backgroundColor: getColor(0) || "white";
34+ secondaryBackgroundColor: getColor(1) || backgroundColor;
35+ backgroundMode: UbuntuShape.VerticalGradient;
36+ anchors.fill: parent;
37+ source: backgroundImage.source ? backgroundImage : null;
38+ property real luminance: Style.luminance(backgroundColor);
39+ property Image backgroundImage: Image {
40+ objectName: "backgroundImage";
41+ source: {
42+ if (cardData && typeof cardData["background"] === "string") return cardData["background"];
43+ else return "";
44+ }
45+ }
46+ function getColor(index) {
47+ if (cardData && typeof cardData["background"] === "object"
48+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
49+ return cardData["background"]["elements"][index];
50+ } else return index === 0 ? "#E9E9E9" : undefined;
51+ }
52+ }
53+ }
54+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
55+Item {
56+ id: artShapeHolder;
57+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
58+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
59+ anchors { horizontalCenter: parent.horizontalCenter; }
60+ Loader {
61+ id: artShapeLoader;
62+ objectName: "artShapeLoader";
63+ readonly property string cardArt: cardData && cardData["art"] || "";
64+ active: cardArt != "";
65+ asynchronous: root.asynchronous;
66+ visible: status == Loader.Ready;
67+ sourceComponent: Item {
68+ id: artShape;
69+ objectName: "artShape";
70+ visible: image.status == Image.Ready;
71+ readonly property alias image: artImage;
72+ ShaderEffectSource {
73+ id: artShapeSource;
74+ sourceItem: artImage;
75+ anchors.centerIn: parent;
76+ width: 1;
77+ height: 1;
78+ hideSource: true;
79+ }
80+ Loader {
81+ anchors.fill: parent;
82+ visible: true;
83+ sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
84+ Component {
85+ id: artShapeShapeComponent;
86+ UbuntuShape {
87+ source: artShapeSource;
88+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
89+ radius: "medium";
90+ aspect: {
91+ switch (root.artShapeStyle) {
92+ case "inset": return UbuntuShape.Inset;
93+ case "shadow": return UbuntuShape.DropShadow;
94+ default:
95+ case "flat": return UbuntuShape.Flat;
96+ }
97+ }
98+ }
99+ }
100+ Component {
101+ id: artShapeIconComponent;
102+ ProportionalShape { source: artShapeSource; aspect: UbuntuShape.DropShadow; }
103+ }
104+ }
105+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
106+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 1;
107+ Component.onCompleted: { updateWidthHeightBindings(); }
108+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
109+ function updateWidthHeightBindings() {
110+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
111+ width = root.fixedArtShapeSize.width;
112+ height = root.fixedArtShapeSize.height;
113+ } else {
114+ width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
115+ height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
116+ }
117+ }
118+ CroppedImageMinimumSourceSize {
119+ id: artImage;
120+ objectName: "artImage";
121+ source: artShapeLoader.cardArt;
122+ asynchronous: root.asynchronous;
123+ width: root.width;
124+ height: width / artShape.aspect;
125+ }
126+ }
127+ }
128+ }
129+readonly property int headerHeight: row.height;
130+Row {
131+ id: row;
132+ objectName: "outerRow";
133+ property real margins: units.gu(1);
134+ spacing: margins;
135+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
136+ anchors { top: artShapeHolder.bottom;
137+ topMargin: units.gu(1);
138+left: parent.left;
139+ }
140+ anchors.right: parent.right;
141+ anchors.margins: margins;
142+ anchors.rightMargin: 0;
143+ data: [
144+ CroppedImageMinimumSourceSize {
145+ id: mascotImage;
146+ objectName: "mascotImage";
147+ anchors { verticalCenter: parent.verticalCenter; }
148+ source: cardData && cardData["mascot"] || "";
149+ width: units.gu(6);
150+ height: units.gu(5.625);
151+ horizontalAlignment: Image.AlignHCenter;
152+ verticalAlignment: Image.AlignVCenter;
153+ visible: showHeader;
154+ }
155+,Item {
156+ id: headerTitleContainer;
157+ anchors { verticalCenter: parent.verticalCenter; }
158+ width: parent.width - x;
159+ implicitHeight: titleLabel.height + subtitleLabel.height;
160+ data: [
161+ Label {
162+ id: titleLabel;
163+ objectName: "titleLabel";
164+ anchors { right: parent.right;
165+rightMargin: units.gu(1);
166+left: parent.left;
167+ top: parent.top; }
168+ elide: Text.ElideRight;
169+ fontSize: "small";
170+ wrapMode: Text.Wrap;
171+ maximumLineCount: 2;
172+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
173+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white");
174+ visible: showHeader ;
175+ width: undefined;
176+ text: root.title;
177+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
178+ horizontalAlignment: Text.AlignLeft;
179+ }
180+,Label {
181+ id: subtitleLabel;
182+ objectName: "subtitleLabel";
183+ anchors { right: parent.right;
184+ left: parent.left;
185+rightMargin: units.gu(1);
186+top: titleLabel.bottom;
187+ }
188+ anchors.topMargin: units.dp(2);
189+ elide: Text.ElideRight;
190+ maximumLineCount: 1;
191+ fontSize: "x-small";
192+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
193+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white");
194+ visible: titleLabel.visible && titleLabel.text;
195+ text: cardData && cardData["subtitle"] || "";
196+ font.weight: Font.Light;
197+ }
198+
199+ ]
200+ }
201+
202+ ]
203+ }
204+UbuntuShape {
205+ id: touchdown;
206+ objectName: "touchdown";
207+ anchors { fill: backgroundLoader }
208+ visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
209+ radius: "medium";
210+ borderSource: "radius_pressed.sci"
211+ }
212+implicitHeight: row.y + row.height + units.gu(1);
213+}