@@ -0,0 +1,145 @@
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 size fixedArtShapeSize: Qt.size(-1, -1);
9+ readonly property string title: cardData && cardData["title"] || "";
10+ property bool showHeader: true;
11+ implicitWidth: childrenRect.width;
12+ enabled: true;
13+signal action(var actionId);
14+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
15+Item {
16+ id: artShapeHolder;
17+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
18+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
19+ anchors { horizontalCenter: parent.horizontalCenter; }
20+ Loader {
21+ id: artShapeLoader;
22+ objectName: "artShapeLoader";
23+ readonly property string cardArt: cardData && cardData["art"] || "";
24+ active: cardArt != "";
25+ asynchronous: false;
26+ visible: status == Loader.Ready;
27+ sourceComponent: Item {
28+ id: artShape;
29+ objectName: "artShape";
30+ visible: image.status == Image.Ready;
31+ readonly property alias image: artImage;
32+ ShaderEffectSource {
33+ id: artShapeSource;
34+ sourceItem: artImage;
35+ anchors.centerIn: parent;
36+ width: 1;
37+ height: 1;
38+ hideSource: true;
39+ }
40+ Loader {
41+ anchors.fill: parent;
42+ visible: true;
43+ sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
44+ Component {
45+ id: artShapeShapeComponent;
46+ UbuntuShape {
47+ source: artShapeSource;
48+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
49+ radius: "medium";
50+ aspect: {
51+ switch (root.artShapeStyle) {
52+ case "inset": return UbuntuShape.Inset;
53+ case "shadow": return UbuntuShape.DropShadow;
54+ default:
55+ case "flat": return UbuntuShape.Flat;
56+ }
57+ }
58+ }
59+ }
60+ Component {
61+ id: artShapeIconComponent;
62+ ProportionalShape { source: artShapeSource; aspect: UbuntuShape.DropShadow; }
63+ }
64+ }
65+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
66+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 0.75;
67+ Component.onCompleted: { updateWidthHeightBindings(); }
68+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
69+ function updateWidthHeightBindings() {
70+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
71+ width = root.fixedArtShapeSize.width;
72+ height = root.fixedArtShapeSize.height;
73+ } else {
74+ width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
75+ height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
76+ }
77+ }
78+ CroppedImageMinimumSourceSize {
79+ id: artImage;
80+ objectName: "artImage";
81+ source: artShapeLoader.cardArt;
82+ asynchronous: false;
83+ width: root.width;
84+ height: width / artShape.aspect;
85+ }
86+ }
87+ }
88+ }
89+readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
90+Label {
91+ id: titleLabel;
92+ objectName: "titleLabel";
93+ anchors { right: parent.right;
94+ left: parent.left;
95+ top: artShapeHolder.bottom;
96+ topMargin: units.gu(1);
97+ }
98+ elide: Text.ElideRight;
99+ fontSize: "small";
100+ wrapMode: Text.Wrap;
101+ maximumLineCount: 2;
102+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
103+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
104+ visible: showHeader ;
105+ width: undefined;
106+ text: root.title;
107+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
108+ horizontalAlignment: Text.AlignLeft;
109+ }
110+Label {
111+ id: subtitleLabel;
112+ objectName: "subtitleLabel";
113+ anchors { left: titleLabel.left;
114+ leftMargin: titleLabel.leftMargin;
115+ right: titleLabel.right;
116+ top: titleLabel.bottom;
117+ }
118+ anchors.topMargin: units.dp(2);
119+ elide: Text.ElideRight;
120+ maximumLineCount: 1;
121+ fontSize: "x-small";
122+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
123+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
124+ visible: titleLabel.visible && titleLabel.text;
125+ text: cardData && cardData["subtitle"] || "";
126+ font.weight: Font.Light;
127+ }
128+CardSocialActions {
129+ id: socialActionsRow;
130+ objectName: "socialActionsRow";
131+ anchors { top: subtitleLabel.bottom; left: parent.left; right: parent.right; topMargin: units.gu(1); }
132+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
133+ model: cardData && cardData["socialActions"];
134+ onClicked: root.action(actionId);
135+}
136+UbuntuShape {
137+ id: touchdown;
138+ objectName: "touchdown";
139+ anchors { fill: artShapeHolder }
140+ visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
141+ radius: "medium";
142+ borderSource: "radius_pressed.sci"
143+}
144+implicitHeight: socialActionsRow.y + socialActionsRow.height + units.gu(1);
145+}