@@ -18,12 +18,13 @@
19// %1 is the template["card-background"]["elements"][0]
19// %1 is the template["card-background"]["elements"][0]
20// %2 is the template["card-background"]["elements"][1]
20// %2 is the template["card-background"]["elements"][1]
21+// %3 is whether the loader should be asynchronous or not
21−// %3 is the template["card-background"] string
22+// %4 is the template["card-background"] string
22var kBackgroundLoaderCode = 'Loader {\n\
23var kBackgroundLoaderCode = 'Loader {\n\
23 id: backgroundLoader; \n\
24 id: backgroundLoader; \n\
24 objectName: "backgroundLoader"; \n\
25 objectName: "backgroundLoader"; \n\
25 anchors.fill: parent; \n\
26 anchors.fill: parent; \n\
26− asynchronous: root.asynchronous; \n\
27+ asynchronous: %3; \n\
27 visible: status == Loader.Ready; \n\
28 visible: status == Loader.Ready; \n\
28 sourceComponent: UbuntuShape { \n\
29 sourceComponent: UbuntuShape { \n\
29 objectName: "background"; \n\
30 objectName: "background"; \n\
@@ -46,7 +47,7 @@ var kBackgroundLoaderCode = 'Loader {\n\
46 objectName: "backgroundImage"; \n\
47 objectName: "backgroundImage"; \n\
47 source: { \n\
48 source: { \n\
48 if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\
49 if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\
49− else return %3; \n\
50+ else return %4; \n\
52 function getColor(index) { \n\
53 function getColor(index) { \n\
@@ -63,8 +64,9 @@ var kBackgroundLoaderCode = 'Loader {\n\
63// %3 is used as image height
64// %3 is used as image height
64// %4 is used for artShapeSource.hideSource and inner Loader visible
65// %4 is used for artShapeSource.hideSource and inner Loader visible
65// %5 is used as aspect ratio fallback
66// %5 is used as aspect ratio fallback
67+// %6 is whether the loader should be asynchronous or not
66−// %6 is injected as code to artImage
68+// %7 is injected as code to artImage
67−// %7 is used as image fallback
69+// %8 is used as image fallback
68var kArtShapeHolderCode = 'Item { \n\
70var kArtShapeHolderCode = 'Item { \n\
69 id: artShapeHolder; \n\
71 id: artShapeHolder; \n\
70 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
72 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
@@ -73,9 +75,9 @@ var kArtShapeHolderCode = 'Item { \n\
73 Loader { \n\
75 Loader { \n\
74 id: artShapeLoader; \n\
76 id: artShapeLoader; \n\
75 objectName: "artShapeLoader"; \n\
77 objectName: "artShapeLoader"; \n\
76− readonly property string cardArt: cardData && cardData["art"] || %7; \n\
78+ readonly property string cardArt: cardData && cardData["art"] || %8; \n\
77 active: cardArt != ""; \n\
79 active: cardArt != ""; \n\
78− asynchronous: root.asynchronous; \n\
80+ asynchronous: %6; \n\
79 visible: status == Loader.Ready; \n\
81 visible: status == Loader.Ready; \n\
80 sourceComponent: Item { \n\
82 sourceComponent: Item { \n\
81 id: artShape; \n\
83 id: artShape; \n\
@@ -132,10 +134,10 @@ var kArtShapeHolderCode = 'Item { \n\
132 id: artImage; \n\
134 id: artImage; \n\
133 objectName: "artImage"; \n\
135 objectName: "artImage"; \n\
134 source: artShapeLoader.cardArt; \n\
136 source: artShapeLoader.cardArt; \n\
135− asynchronous: root.asynchronous; \n\
137+ asynchronous: %6; \n\
136 width: %2; \n\
138 width: %2; \n\
137 height: %3; \n\
139 height: %3; \n\
@@ -187,12 +189,14 @@ var kAudioButtonCode = 'AbstractButton { \n\
192+// %1 is whether the loader should be asynchronous or not
193+// %2 is the header height code
190var kOverlayLoaderCode = 'Loader { \n\
194var kOverlayLoaderCode = 'Loader { \n\
191 id: overlayLoader; \n\
195 id: overlayLoader; \n\
192− readonly property real overlayHeight: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
196+ readonly property real overlayHeight: %2 + units.gu(2); \n\
193 anchors.fill: artShapeHolder; \n\
197 anchors.fill: artShapeHolder; \n\
194 active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\
198 active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\
195− asynchronous: root.asynchronous; \n\
199+ asynchronous: %1; \n\
196 visible: showHeader && status == Loader.Ready; \n\
200 visible: showHeader && status == Loader.Ready; \n\
197 sourceComponent: UbuntuShapeOverlay { \n\
201 sourceComponent: UbuntuShapeOverlay { \n\
198 id: overlay; \n\
202 id: overlay; \n\
@@ -211,17 +215,19 @@ function kHeaderRowCodeGenerator() {
211 objectName: "outerRow"; \n\
215 objectName: "outerRow"; \n\
212 property real margins: units.gu(1); \n\
216 property real margins: units.gu(1); \n\
213 spacing: margins; \n\
217 spacing: margins; \n\
214− height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
218+ %2\
215 anchors { %1 } \n\
219 anchors { %1 } \n\
216 anchors.right: parent.right; \n\
220 anchors.right: parent.right; \n\
217 anchors.margins: margins; \n\
221 anchors.margins: margins; \n\
218 anchors.rightMargin: 0; \n\
222 anchors.rightMargin: 0; \n\
219 data: [ \n\
223 data: [ \n\
223 var args = Array.prototype.slice.call(arguments);
227 var args = Array.prototype.slice.call(arguments);
228+ var isCardTool = args.shift();
229+ var heightCode = isCardTool ? "" : "height: root.fixedHeaderHeight; \n";
224− var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(args.join(',\n'));
230+ var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(heightCode).arg(args.join(',\n'));
225 return code;
231 return code;
@@ -242,10 +248,11 @@ function kHeaderContainerCodeGenerator() {
244// %1 is used as anchors of mascotShapeLoader
250// %1 is used as anchors of mascotShapeLoader
251+// %2 is whether the loader should be asynchronous or not
245var kMascotShapeLoaderCode = 'Loader { \n\
252var kMascotShapeLoaderCode = 'Loader { \n\
246 id: mascotShapeLoader; \n\
253 id: mascotShapeLoader; \n\
247 objectName: "mascotShapeLoader"; \n\
254 objectName: "mascotShapeLoader"; \n\
248− asynchronous: root.asynchronous; \n\
255+ asynchronous: %2; \n\
249 active: mascotImage.status === Image.Ready; \n\
256 active: mascotImage.status === Image.Ready; \n\
250 visible: showHeader && active && status == Loader.Ready; \n\
257 visible: showHeader && active && status == Loader.Ready; \n\
251 width: units.gu(6); \n\
258 width: units.gu(6); \n\
@@ -275,6 +282,7 @@ var kMascotImageCode = 'CroppedImageMinimumSourceSize { \n\
275// %2 is used as color of titleLabel
282// %2 is used as color of titleLabel
276// %3 is used as extra condition for visible of titleLabel
283// %3 is used as extra condition for visible of titleLabel
277// %4 is used as title width
284// %4 is used as title width
285+// %5 is used as horizontal alignment
278var kTitleLabelCode = 'Label { \n\
286var kTitleLabelCode = 'Label { \n\
279 id: titleLabel; \n\
287 id: titleLabel; \n\
280 objectName: "titleLabel"; \n\
288 objectName: "titleLabel"; \n\
@@ -289,7 +297,7 @@ var kTitleLabelCode = 'Label { \n\
289 width: %4; \n\
297 width: %4; \n\
290 text: root.title; \n\
298 text: root.title; \n\
291 font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal; \n\
299 font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal; \n\
292− horizontalAlignment: root.titleAlignment; \n\
300+ horizontalAlignment: %5; \n\
295// %1 is used as extra anchors of emblemIcon
303// %1 is used as extra anchors of emblemIcon
@@ -409,7 +417,7 @@ function sanitizeColor(colorString) {
409 return colorString;
417 return colorString;
412−function cardString(template, components) {
420+function cardString(template, components, isCardTool) {
413 var code;
421 var code;
415 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
423 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
@@ -421,16 +429,16 @@ function cardString(template, components) {
421 property string backgroundShapeStyle: "inset"; \n\
429 property string backgroundShapeStyle: "inset"; \n\
422 property real fontScale: 1.0; \n\
430 property real fontScale: 1.0; \n\
423 property var scopeStyle: null; \n\
431 property var scopeStyle: null; \n\
424− property int titleAlignment: Text.AlignLeft; \n\
432+ %2\
425− property int fixedHeaderHeight: -1; \n\
426 property size fixedArtShapeSize: Qt.size(-1, -1); \n\
433 property size fixedArtShapeSize: Qt.size(-1, -1); \n\
427 readonly property string title: cardData && cardData["title"] || ""; \n\
434 readonly property string title: cardData && cardData["title"] || ""; \n\
428− property bool asynchronous: true; \n\
429 property bool showHeader: true; \n\
435 property bool showHeader: true; \n\
430 implicitWidth: childrenRect.width; \n\
436 implicitWidth: childrenRect.width; \n\
431 enabled: %1; \n\
437 enabled: %1; \n\
432 \n'.arg(templateInteractive);
438 \n'.arg(templateInteractive);
440+ code = code.arg(isCardTool ? "" : "property int fixedHeaderHeight: -1; \n");
434 var hasArt = components["art"] && components["art"]["field"] || false;
442 var hasArt = components["art"] && components["art"]["field"] || false;
435 var hasSummary = components["summary"] || false;
443 var hasSummary = components["summary"] || false;
436 var isConciergeMode = components["art"] && components["art"]["conciergeMode"] || false;
444 var isConciergeMode = components["art"] && components["art"]["conciergeMode"] || false;
@@ -447,6 +455,7 @@ function cardString(template, components) {
447 var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false;
455 var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false;
448 var hasSocialActions = hasTitle && components["socialActions"] || false;
456 var hasSocialActions = hasTitle && components["socialActions"] || false;
449 var isAudio = template["quick-preview-type"] === "audio";
457 var isAudio = template["quick-preview-type"] === "audio";
458+ var asynchronous = isCardTool ? "false" : "true";
451 code += 'signal action(var actionId);\n';
460 code += 'signal action(var actionId);\n';
452 if (isAudio) {
461 if (isAudio) {
@@ -481,7 +490,7 @@ function cardString(template, components) {
481 backgroundElements1 = '"%1"'.arg(element1);
490 backgroundElements1 = '"%1"'.arg(element1);
484− code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(templateCardBackground);
493+ code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(asynchronous).arg(templateCardBackground);
487 if (hasArt) {
496 if (hasArt) {
@@ -510,23 +519,31 @@ function cardString(template, components) {
510 if (isNaN(aspectRatio)) {
519 if (isNaN(aspectRatio)) {
511 aspectRatio = 1;
520 aspectRatio = 1;
513− var fallback = components["art"] && components["art"]["fallback"] || "";
522+ var fallback = !isCardTool && components["art"] && components["art"]["fallback"] || "";
514 fallback = encodeURI(fallback);
523 fallback = encodeURI(fallback);
515 var fallbackStatusCode = "";
524 var fallbackStatusCode = "";
516 var fallbackURICode = '""';
525 var fallbackURICode = '""';
517 if (fallback !== "") {
526 if (fallback !== "") {
518 // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode
527 // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode
519− // which in kArtShapeHolderCode is %7
528+ // which in kArtShapeHolderCode is %8
520− fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %7;';
529+ fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;';
521 fallbackURICode = 'decodeURI("%1")'.arg(fallback);
530 fallbackURICode = 'decodeURI("%1")'.arg(fallback);
523− code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode).arg(isConciergeMode ? "false" : "true").arg(aspectRatio).arg(fallbackStatusCode).arg(fallbackURICode);
532+ code += kArtShapeHolderCode.arg(artAnchors)
535+ .arg(isConciergeMode ? "false" : "true")
538+ .arg(fallbackStatusCode)
539+ .arg(fallbackURICode);
525 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
541 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
528 if (headerAsOverlay) {
544 if (headerAsOverlay) {
545+ var headerHeightCode = isCardTool ? "headerHeight" : "root.fixedHeaderHeight";
529− code += kOverlayLoaderCode;
546+ code += kOverlayLoaderCode.arg(asynchronous).arg(headerHeightCode);
532 var headerVerticalAnchors;
549 var headerVerticalAnchors;
@@ -608,11 +625,11 @@ function cardString(template, components) {
610 if (useMascotShape) {
627 if (useMascotShape) {
611− mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
628+ mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors).arg(asynchronous);
614 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
631 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
615− var fallback = components["mascot"] && components["mascot"]["fallback"] || "";
632+ var fallback = !isCardTool && components["mascot"] && components["mascot"]["fallback"] || "";
616 fallback = encodeURI(fallback);
633 fallback = encodeURI(fallback);
617 var fallbackStatusCode = "";
634 var fallbackStatusCode = "";
618 var fallbackURICode = '""';
635 var fallbackURICode = '""';
@@ -728,9 +745,24 @@ function cardString(template, components) {
748+ var titleAlignment = "Text.AlignHCenter";
749+ if (template["card-layout"] === "horizontal"
750+ || typeof components["title"] !== "object"
751+ || components["title"]["align"] === "left") titleAlignment = "Text.AlignLeft";
752+ var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"];
753+ for (var key in keys) {
756+ if (typeof components[key] === "string"
757+ || typeof components[key]["field"] === "string") titleAlignment = "Text.AlignLeft";
731 // code for different elements
763 // code for different elements
732 var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
764 var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
733− var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra).arg(titleWidth);
765+ var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra).arg(titleWidth).arg(titleAlignment);
734 var subtitleCode;
766 var subtitleCode;
735 var attributesCode;
767 var attributesCode;
@@ -772,7 +804,7 @@ function cardString(template, components) {
772 if (mascotShapeCode != '') {
804 if (mascotShapeCode != '') {
773 rowCode.unshift(mascotShapeCode);
805 rowCode.unshift(mascotShapeCode);
775− code += kHeaderRowCodeGenerator(headerVerticalAnchors + headerLeftAnchor, rowCode)
807+ code += kHeaderRowCodeGenerator(isCardTool, headerVerticalAnchors + headerLeftAnchor, rowCode)
777 code += mascotShapeCode + mascotCode + titleSubtitleCode;
809 code += mascotShapeCode + mascotCode + titleSubtitleCode;
@@ -796,7 +828,8 @@ function cardString(template, components) {
797 audioButtonAnchorsFill = 'undefined';
829 audioButtonAnchorsFill = 'undefined';
798 audioButtonWidth = 'height';
830 audioButtonWidth = 'height';
799− audioButtonHeight = '(root.fixedHeaderHeight > 0 ? root.fixedHeaderHeight : headerHeight) + 2 * units.gu(1)';
831+ audioButtonHeight = isCardTool ? 'headerHeight + 2 * units.gu(1)'
832+ : 'root.fixedHeaderHeight + 2 * units.gu(1)';
801 code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight);
834 code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight);
@@ -899,13 +932,13 @@ function cardString(template, components) {
899 return code;
932 return code;
902−function createCardComponent(parent, template, components, identifier) {
935+function createCardComponent(parent, template, components, isCardTool, identifier) {
903 var imports = 'import QtQuick 2.4; \n\
936 var imports = 'import QtQuick 2.4; \n\
904 import Ubuntu.Components 1.3; \n\
937 import Ubuntu.Components 1.3; \n\
905 import Ubuntu.Settings.Components 0.1; \n\
938 import Ubuntu.Settings.Components 0.1; \n\
906 import Dash 0.1;\n\
939 import Dash 0.1;\n\
907 import Utils 0.1;\n';
940 import Utils 0.1;\n';
908− var card = cardString(template, components);
941+ var card = cardString(template, components, isCardTool);
909 var code = imports + 'Component {\n' + card + '}\n';
942 var code = imports + 'Component {\n' + card + '}\n';