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