@@ -18,12 +18,13 @@
1818
1919// %1 is the template["card-background"]["elements"][0]
2020// %2 is the template["card-background"]["elements"][1]
21−// %3 is the template["card-background"] string
21+// %3 is whether the loader should be asynchronous or not
22+// %4 is the template["card-background"] string
2223var kBackgroundLoaderCode = 'Loader {\n\
2324 id: backgroundLoader; \n\
2425 objectName: "backgroundLoader"; \n\
2526 anchors.fill: parent; \n\
26− asynchronous: root.asynchronous; \n\
27+ asynchronous: %3; \n\
2728 visible: status == Loader.Ready; \n\
2829 sourceComponent: UbuntuShape { \n\
2930 objectName: "background"; \n\
@@ -46,7 +47,7 @@ var kBackgroundLoaderCode = 'Loader {\n\
4647 objectName: "backgroundImage"; \n\
4748 source: { \n\
4849 if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\
49− else return %3; \n\
50+ else return %4; \n\
5051 } \n\
5152 } \n\
5253 function getColor(index) { \n\
@@ -63,8 +64,9 @@ var kBackgroundLoaderCode = 'Loader {\n\
6364// %3 is used as image height
6465// %4 is used for artShapeSource.hideSource and inner Loader visible
6566// %5 is used as aspect ratio fallback
66−// %6 is injected as code to artImage
67−// %7 is used as image fallback
67+// %6 is whether the loader should be asynchronous or not
68+// %7 is injected as code to artImage
69+// %8 is used as image fallback
6870var kArtShapeHolderCode = 'Item { \n\
6971 id: artShapeHolder; \n\
7072 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
@@ -73,9 +75,9 @@ var kArtShapeHolderCode = 'Item { \n\
7375 Loader { \n\
7476 id: artShapeLoader; \n\
7577 objectName: "artShapeLoader"; \n\
76− readonly property string cardArt: cardData && cardData["art"] || %7; \n\
78+ readonly property string cardArt: cardData && cardData["art"] || %8; \n\
7779 active: cardArt != ""; \n\
78− asynchronous: root.asynchronous; \n\
80+ asynchronous: %6; \n\
7981 visible: status == Loader.Ready; \n\
8082 sourceComponent: Item { \n\
8183 id: artShape; \n\
@@ -132,10 +134,10 @@ var kArtShapeHolderCode = 'Item { \n\
132134 id: artImage; \n\
133135 objectName: "artImage"; \n\
134136 source: artShapeLoader.cardArt; \n\
135− asynchronous: root.asynchronous; \n\
137+ asynchronous: %6; \n\
136138 width: %2; \n\
137139 height: %3; \n\
138− %6 \n\
140+ %7 \n\
139141 } \n\
140142 } \n\
141143 } \n\
@@ -187,12 +189,14 @@ var kAudioButtonCode = 'AbstractButton { \n\
187189 } \n\
188190 }';
189191
192+// %1 is whether the loader should be asynchronous or not
193+// %2 is the header height code
190194var kOverlayLoaderCode = 'Loader { \n\
191195 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\
193197 anchors.fill: artShapeHolder; \n\
194198 active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\
195− asynchronous: root.asynchronous; \n\
199+ asynchronous: %1; \n\
196200 visible: showHeader && status == Loader.Ready; \n\
197201 sourceComponent: UbuntuShapeOverlay { \n\
198202 id: overlay; \n\
@@ -211,17 +215,19 @@ function kHeaderRowCodeGenerator() {
211215 objectName: "outerRow"; \n\
212216 property real margins: units.gu(1); \n\
213217 spacing: margins; \n\
214− height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
218+ %2\
215219 anchors { %1 } \n\
216220 anchors.right: parent.right; \n\
217221 anchors.margins: margins; \n\
218222 anchors.rightMargin: 0; \n\
219223 data: [ \n\
220− %2 \n\
224+ %3 \n\
221225 ] \n\
222226 }\n';
223227 var args = Array.prototype.slice.call(arguments);
224− var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(args.join(',\n'));
228+ var isCardTool = args.shift();
229+ var heightCode = isCardTool ? "" : "height: root.fixedHeaderHeight; \n";
230+ var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(heightCode).arg(args.join(',\n'));
225231 return code;
226232}
227233
@@ -242,10 +248,11 @@ function kHeaderContainerCodeGenerator() {
242248}
243249
244250// %1 is used as anchors of mascotShapeLoader
251+// %2 is whether the loader should be asynchronous or not
245252var kMascotShapeLoaderCode = 'Loader { \n\
246253 id: mascotShapeLoader; \n\
247254 objectName: "mascotShapeLoader"; \n\
248− asynchronous: root.asynchronous; \n\
255+ asynchronous: %2; \n\
249256 active: mascotImage.status === Image.Ready; \n\
250257 visible: showHeader && active && status == Loader.Ready; \n\
251258 width: units.gu(6); \n\
@@ -275,6 +282,7 @@ var kMascotImageCode = 'CroppedImageMinimumSourceSize { \n\
275282// %2 is used as color of titleLabel
276283// %3 is used as extra condition for visible of titleLabel
277284// %4 is used as title width
285+// %5 is used as horizontal alignment
278286var kTitleLabelCode = 'Label { \n\
279287 id: titleLabel; \n\
280288 objectName: "titleLabel"; \n\
@@ -289,7 +297,7 @@ var kTitleLabelCode = 'Label { \n\
289297 width: %4; \n\
290298 text: root.title; \n\
291299 font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal; \n\
292− horizontalAlignment: root.titleAlignment; \n\
300+ horizontalAlignment: %5; \n\
293301 }\n';
294302
295303// %1 is used as extra anchors of emblemIcon
@@ -409,7 +417,7 @@ function sanitizeColor(colorString) {
409417 return colorString;
410418}
411419
412−function cardString(template, components) {
420+function cardString(template, components, isCardTool) {
413421 var code;
414422
415423 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
@@ -421,16 +429,16 @@ function cardString(template, components) {
421429 property string backgroundShapeStyle: "inset"; \n\
422430 property real fontScale: 1.0; \n\
423431 property var scopeStyle: null; \n\
424− property int titleAlignment: Text.AlignLeft; \n\
425− property int fixedHeaderHeight: -1; \n\
432+ %2\
426433 property size fixedArtShapeSize: Qt.size(-1, -1); \n\
427434 readonly property string title: cardData && cardData["title"] || ""; \n\
428− property bool asynchronous: true; \n\
429435 property bool showHeader: true; \n\
430436 implicitWidth: childrenRect.width; \n\
431437 enabled: %1; \n\
432438 \n'.arg(templateInteractive);
433439
440+ code = code.arg(isCardTool ? "" : "property int fixedHeaderHeight: -1; \n");
441+
434442 var hasArt = components["art"] && components["art"]["field"] || false;
435443 var hasSummary = components["summary"] || false;
436444 var isConciergeMode = components["art"] && components["art"]["conciergeMode"] || false;
@@ -447,6 +455,7 @@ function cardString(template, components) {
447455 var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false;
448456 var hasSocialActions = hasTitle && components["socialActions"] || false;
449457 var isAudio = template["quick-preview-type"] === "audio";
458+ var asynchronous = isCardTool ? "false" : "true";
450459
451460 code += 'signal action(var actionId);\n';
452461 if (isAudio) {
@@ -481,7 +490,7 @@ function cardString(template, components) {
481490 backgroundElements1 = '"%1"'.arg(element1);
482491 }
483492 }
484− code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(templateCardBackground);
493+ code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(asynchronous).arg(templateCardBackground);
485494 }
486495
487496 if (hasArt) {
@@ -510,23 +519,31 @@ function cardString(template, components) {
510519 if (isNaN(aspectRatio)) {
511520 aspectRatio = 1;
512521 }
513− var fallback = components["art"] && components["art"]["fallback"] || "";
522+ var fallback = !isCardTool && components["art"] && components["art"]["fallback"] || "";
514523 fallback = encodeURI(fallback);
515524 var fallbackStatusCode = "";
516525 var fallbackURICode = '""';
517526 if (fallback !== "") {
518527 // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode
519− // which in kArtShapeHolderCode is %7
520− fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %7;';
528+ // which in kArtShapeHolderCode is %8
529+ fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;';
521530 fallbackURICode = 'decodeURI("%1")'.arg(fallback);
522531 }
523− code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode).arg(isConciergeMode ? "false" : "true").arg(aspectRatio).arg(fallbackStatusCode).arg(fallbackURICode);
532+ code += kArtShapeHolderCode.arg(artAnchors)
533+ .arg(widthCode)
534+ .arg(heightCode)
535+ .arg(isConciergeMode ? "false" : "true")
536+ .arg(aspectRatio)
537+ .arg(asynchronous)
538+ .arg(fallbackStatusCode)
539+ .arg(fallbackURICode);
524540 } else {
525541 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
526542 }
527543
528544 if (headerAsOverlay) {
529− code += kOverlayLoaderCode;
545+ var headerHeightCode = isCardTool ? "headerHeight" : "root.fixedHeaderHeight";
546+ code += kOverlayLoaderCode.arg(asynchronous).arg(headerHeightCode);
530547 }
531548
532549 var headerVerticalAnchors;
@@ -608,11 +625,11 @@ function cardString(template, components) {
608625 }
609626
610627 if (useMascotShape) {
611− mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
628+ mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors).arg(asynchronous);
612629 }
613630
614631 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
615− var fallback = components["mascot"] && components["mascot"]["fallback"] || "";
632+ var fallback = !isCardTool && components["mascot"] && components["mascot"]["fallback"] || "";
616633 fallback = encodeURI(fallback);
617634 var fallbackStatusCode = "";
618635 var fallbackURICode = '""';
@@ -728,9 +745,24 @@ function cardString(template, components) {
728745 }
729746 }
730747
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) {
754+ key = keys[key];
755+ try {
756+ if (typeof components[key] === "string"
757+ || typeof components[key]["field"] === "string") titleAlignment = "Text.AlignLeft";
758+ } catch (e) {
759+ continue;
760+ }
761+ }
762+
731763 // code for different elements
732764 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);
734766 var subtitleCode;
735767 var attributesCode;
736768
@@ -772,7 +804,7 @@ function cardString(template, components) {
772804 if (mascotShapeCode != '') {
773805 rowCode.unshift(mascotShapeCode);
774806 }
775− code += kHeaderRowCodeGenerator(headerVerticalAnchors + headerLeftAnchor, rowCode)
807+ code += kHeaderRowCodeGenerator(isCardTool, headerVerticalAnchors + headerLeftAnchor, rowCode)
776808 } else {
777809 code += mascotShapeCode + mascotCode + titleSubtitleCode;
778810 }
@@ -796,7 +828,8 @@ function cardString(template, components) {
796828 } else {
797829 audioButtonAnchorsFill = 'undefined';
798830 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)';
800833 }
801834 code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight);
802835 }
@@ -899,13 +932,13 @@ function cardString(template, components) {
899932 return code;
900933}
901934
902−function createCardComponent(parent, template, components, identifier) {
935+function createCardComponent(parent, template, components, isCardTool, identifier) {
903936 var imports = 'import QtQuick 2.4; \n\
904937 import Ubuntu.Components 1.3; \n\
905938 import Ubuntu.Settings.Components 0.1; \n\
906939 import Dash 0.1;\n\
907940 import Utils 0.1;\n';
908− var card = cardString(template, components);
941+ var card = cardString(template, components, isCardTool);
909942 var code = imports + 'Component {\n' + card + '}\n';
910943
911944 try {