on xenial help sign in
Add emblem support in dash cards.
6ae8535Andrea Cimitan
plugins/Dash/CardCreator.js+186−146
@@ -138,10 +138,9 @@ var kOverlayLoaderCode = 'Loader { \n\
138 } \n\
138 } \n\
139 }\n';
139 }\n';
140
140
141−// %1 is used as anchors of row
141+// multiple row version of HeaderRowCode
142−// %2 is used as first child of the row
142+function kHeaderRowCodeGenerator() {
143−// %3 is used as second child of the row
143+var kHeaderRowCodeTemplate = 'Row { \n\
144−var kHeaderRow2Code = 'Row { \n\
145 id: row; \n\
144 id: row; \n\
146 objectName: "outerRow"; \n\
145 objectName: "outerRow"; \n\
147 property real margins: units.gu(1); \n\
146 property real margins: units.gu(1); \n\
@@ -149,58 +148,30 @@ var kHeaderRow2Code = 'Row { \n\
149 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
148 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
150 anchors { %1 } \n\
149 anchors { %1 } \n\
151 anchors.right: parent.right; \n\
150 anchors.right: parent.right; \n\
152− anchors.margins: margins;\n\
151+ anchors.margins: margins; \n\
152+ anchors.rightMargin: 0; \n\
153− data: [ %2\n\
153+ data: [ \n\
154− ,\n\
155− %3 \n\
154+ %2 \n\
156 ] \n\
155 ] \n\
157 }\n';
156 }\n';
157+ var args = Array.prototype.slice.call(arguments);
158+ var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(args.join(',\n'));
159+ return code;
160+}
158
161
159−// %1 is used as anchors of row
162+// multiple item version of kHeaderContainerCode
160−// %2 is used as first child of the row
163+function kHeaderContainerCodeGenerator() {
161−// %3 is used as second child of the row
164+ var headerContainerCodeTemplate = 'Item { \n\
162−// %4 is used as third child of the row
165+ id: headerTitleContainer; \n\
163−var kHeaderRow3Code = 'Row { \n\
166+ anchors { %1 } \n\
164− id: row; \n\
167+ width: parent.width - x; \n\
165− objectName: "outerRow"; \n\
168+ implicitHeight: %2; \n\
166− property real margins: units.gu(1); \n\
167− spacing: margins; \n\
168− height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
169− anchors { %1 } \n\
170− anchors.right: parent.right; \n\
171− anchors.margins: margins;\n\
172− data: [ %2\n\
169+ data: [ \n\
173− ,\n\
174 %3 \n\
170 %3 \n\
175− ,\n\
176− %4 \n\
177− ] \n\
178− }\n';
179−
180−// %1 is used as first child of the column
181−// %2 is used as second child of the column
182−var kHeaderColumnCode = 'Column { \n\
183− anchors.verticalCenter: parent.verticalCenter; \n\
184− spacing: units.dp(2); \n\
185− width: parent.width - x;\n\
186− data: [ %1\n\
187− ,\n\
188− %2 \n\
189− ] \n\
171+ ]\n\
190 }\n';
172 }\n';
191−
192−// multiple column version of kHeaderColumnCode.
193−function kHeaderColumnCodeGenerator() {
194− var headerColumnCodeTemplate = 'Column { \n\
195− anchors.verticalCenter: parent.verticalCenter; \n\
196− spacing: units.dp(2); \n\
197− width: parent.width - x;\n\
198− data: [ \n\
199− %1 \n\
200− ]\n\
201− }\n';
202 var args = Array.prototype.slice.call(arguments);
173 var args = Array.prototype.slice.call(arguments);
203− var code = headerColumnCodeTemplate.arg(args.join(',\n'));
174+ var code = headerContainerCodeTemplate.arg(args.shift()).arg(args.shift()).arg(args.join(',\n'));
204 return code;
175 return code;
205}
176}
206
177
@@ -224,7 +195,7 @@ var kMascotImageCode = 'Image { \n\
224 objectName: "mascotImage"; \n\
195 objectName: "mascotImage"; \n\
225 anchors { %1 } \n\
196 anchors { %1 } \n\
226 readonly property int maxSize: Math.max(width, height) * 4; \n\
197 readonly property int maxSize: Math.max(width, height) * 4; \n\
227− source: cardData && cardData["mascot"]; \n\
198+ source: cardData && cardData["mascot"] || ""; \n\
228 width: units.gu(6); \n\
199 width: units.gu(6); \n\
229 height: units.gu(5.625); \n\
200 height: units.gu(5.625); \n\
230 sourceSize { width: maxSize; height: maxSize } \n\
201 sourceSize { width: maxSize; height: maxSize } \n\
@@ -253,6 +224,22 @@ var kTitleLabelCode = 'Label { \n\
253 horizontalAlignment: root.headerAlignment; \n\
224 horizontalAlignment: root.headerAlignment; \n\
254 }\n';
225 }\n';
255
226
227+// %1 is used as extra anchors of emblemIcon
228+// %2 is used as color of emblemIcon
229+var kEmblemIconCode = 'Icon { \n\
230+ id: emblemIcon; \n\
231+ objectName: "emblemIcon"; \n\
232+ anchors { \n\
233+ bottom: titleLabel.baseline; \n\
234+ right: parent.right; \n\
235+ %1
236+ } \n\
237+ source: cardData && cardData["emblem"] || ""; \n\
238+ color: %2; \n\
239+ width: height; \n\
240+ height: source != "" ? titleLabel.font.pixelSize : 0; \n\
241+ }\n';
242+
256// %1 is used as anchors of touchdown effect
243// %1 is used as anchors of touchdown effect
257var kTouchdownCode = 'UbuntuShape { \n\
244var kTouchdownCode = 'UbuntuShape { \n\
258 id: touchdown; \n\
245 id: touchdown; \n\
@@ -269,6 +256,7 @@ var kSubtitleLabelCode = 'Label { \n\
269 id: subtitleLabel; \n\
256 id: subtitleLabel; \n\
270 objectName: "subtitleLabel"; \n\
257 objectName: "subtitleLabel"; \n\
271 anchors { %1 } \n\
258 anchors { %1 } \n\
259+ anchors.topMargin: units.dp(2); \n\
272 elide: Text.ElideRight; \n\
260 elide: Text.ElideRight; \n\
273 fontSize: "small"; \n\
261 fontSize: "small"; \n\
274 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
262 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
@@ -280,12 +268,13 @@ var kSubtitleLabelCode = 'Label { \n\
280 }\n';
268 }\n';
281
269
282// %1 is used as anchors of attributesRow
270// %1 is used as anchors of attributesRow
271+// %2 is used as color of attributesRow
283var kAttributesRowCode = 'CardAttributes { \n\
272var kAttributesRowCode = 'CardAttributes { \n\
284 id: attributesRow; \n\
273 id: attributesRow; \n\
285 objectName: "attributesRow"; \n\
274 objectName: "attributesRow"; \n\
286 anchors { %1 } \n\
275 anchors { %1 } \n\
287 color: %2; \n\
276 color: %2; \n\
288− model: cardData["attributes"]; \n\
277+ model: cardData && cardData["attributes"]; \n\
289 }\n';
278 }\n';
290
279
291// %1 is used as top anchor of summary
280// %1 is used as top anchor of summary
@@ -335,10 +324,11 @@ function cardString(template, components) {
335 var hasBackground = !isHorizontal && (template["card-background"] || components["background"] || artAndSummary);
324 var hasBackground = !isHorizontal && (template["card-background"] || components["background"] || artAndSummary);
336 var hasTitle = components["title"] || false;
325 var hasTitle = components["title"] || false;
337 var hasMascot = components["mascot"] || false;
326 var hasMascot = components["mascot"] || false;
327+ var hasEmblem = components["emblem"] && !(hasMascot && template["card-size"] === "small") || false;
338 var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
328 var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
339 var hasSubtitle = hasTitle && components["subtitle"] || false;
329 var hasSubtitle = hasTitle && components["subtitle"] || false;
340 var hasHeaderRow = hasMascot && hasTitle;
330 var hasHeaderRow = hasMascot && hasTitle;
341− var hasAttributes = hasTitle && components["attributes"] || false;
331+ var hasAttributes = hasTitle && components["attributes"]["field"] || false;
342
332
343 if (hasBackground) {
333 if (hasBackground) {
344 code += kBackgroundLoaderCode;
334 code += kBackgroundLoaderCode;
@@ -349,9 +339,9 @@ function cardString(template, components) {
349 code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
339 code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
350
340
351 var widthCode, heightCode;
341 var widthCode, heightCode;
352− var anchors;
342+ var artAnchors;
353 if (isHorizontal) {
343 if (isHorizontal) {
354− anchors = 'left: parent.left';
344+ artAnchors = 'left: parent.left';
355 if (hasMascot || hasTitle) {
345 if (hasMascot || hasTitle) {
356 widthCode = 'height * artShape.aspect'
346 widthCode = 'height * artShape.aspect'
357 heightCode = 'headerHeight + 2 * units.gu(1)';
347 heightCode = 'headerHeight + 2 * units.gu(1)';
@@ -362,12 +352,12 @@ function cardString(template, components) {
362 heightCode = 'units.gu(7.625)';
352 heightCode = 'units.gu(7.625)';
363 }
353 }
364 } else {
354 } else {
365− anchors = 'horizontalCenter: parent.horizontalCenter;';
355+ artAnchors = 'horizontalCenter: parent.horizontalCenter;';
366 widthCode = 'root.width'
356 widthCode = 'root.width'
367 heightCode = 'width / artShape.aspect';
357 heightCode = 'width / artShape.aspect';
368 }
358 }
369
359
370− code += kArtShapeHolderCode.arg(anchors).arg(widthCode).arg(heightCode);
360+ code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode);
371 } else {
361 } else {
372 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
362 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
373 }
363 }
@@ -404,6 +394,8 @@ function cardString(template, components) {
404 headerLeftAnchor = 'left: parent.left;\n';
394 headerLeftAnchor = 'left: parent.left;\n';
405 }
395 }
406
396
397+ var touchdownOnArtShape = !hasBackground && hasArt && !hasMascot && !hasSummary;
398+
407 if (hasHeaderRow) {
399 if (hasHeaderRow) {
408 code += 'readonly property int headerHeight: row.height;\n'
400 code += 'readonly property int headerHeight: row.height;\n'
409 } else if (hasMascot) {
401 } else if (hasMascot) {
@@ -424,191 +416,239 @@ function cardString(template, components) {
424 code += 'readonly property int headerHeight: 0;\n'
416 code += 'readonly property int headerHeight: 0;\n'
425 }
417 }
426
418
427− var mascotShapeCode = "";
419+ var mascotShapeCode = '';
428− var mascotCode = "";
420+ var mascotCode = '';
429 if (hasMascot) {
421 if (hasMascot) {
430 var useMascotShape = !hasBackground && !headerAsOverlay;
422 var useMascotShape = !hasBackground && !headerAsOverlay;
431− var anchors = "";
423+ var mascotAnchors = '';
432 if (!hasHeaderRow) {
424 if (!hasHeaderRow) {
433− anchors += headerLeftAnchor;
425+ mascotAnchors += headerLeftAnchor;
434− anchors += headerVerticalAnchors;
426+ mascotAnchors += headerVerticalAnchors;
435 if (!headerLeftAnchorHasMargin) {
427 if (!headerLeftAnchorHasMargin) {
436− anchors += 'leftMargin: units.gu(1);\n'
428+ mascotAnchors += 'leftMargin: units.gu(1);\n'
437 }
429 }
438 } else {
430 } else {
439− anchors = "verticalCenter: parent.verticalCenter;"
431+ mascotAnchors = 'verticalCenter: parent.verticalCenter;'
440 }
432 }
441
433
442 if (useMascotShape) {
434 if (useMascotShape) {
443− mascotShapeCode = kMascotShapeLoaderCode.arg(anchors);
435+ mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
444 }
436 }
445
437
446 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
438 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
447− mascotCode = kMascotImageCode.arg(anchors).arg(mascotImageVisible);
439+ mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
448 }
440 }
449
441
450 var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey")';
442 var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey")';
451
443
444+ var hasTitleContainer = hasTitle && (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes)));
452− var titleSubtitleCode = "";
445+ var titleSubtitleCode = '';
453 if (hasTitle) {
446 if (hasTitle) {
454− var color;
447+ var titleColor;
455 if (headerAsOverlay) {
448 if (headerAsOverlay) {
456− color = 'overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey")';
449+ titleColor = 'overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey")';
457 } else if (hasSummary) {
450 } else if (hasSummary) {
458− color = 'summary.color';
451+ titleColor = 'summary.color';
459 } else if (hasBackground) {
452 } else if (hasBackground) {
460− color = summaryColorWithBackground;
453+ titleColor = summaryColorWithBackground;
461 } else {
454 } else {
462− color = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
455+ titleColor = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
463 }
456 }
464
457
465 var titleAnchors;
458 var titleAnchors;
466 var subtitleAnchors;
459 var subtitleAnchors;
467 var attributesAnchors;
460 var attributesAnchors;
461+ var titleContainerAnchors;
462+ var titleRightAnchor;
463+
464+ var extraRightAnchor = '';
465+ var extraLeftAnchor = '';
466+ if (!touchdownOnArtShape) {
467+ extraRightAnchor = 'rightMargin: units.gu(1); \n';
468+ extraLeftAnchor = 'leftMargin: units.gu(1); \n';
469+ }
470+
468− if (hasMascot && (hasSubtitle || hasAttributes)) {
471+ if (hasMascot) {
469− // Using row + column
472+ titleContainerAnchors = 'verticalCenter: parent.verticalCenter; ';
473+ } else {
474+ titleContainerAnchors = 'right: parent.right; ';
475+ titleContainerAnchors += headerLeftAnchor;
476+ titleContainerAnchors += headerVerticalAnchors;
477+ if (!headerLeftAnchorHasMargin) {
478+ titleContainerAnchors += extraLeftAnchor;
479+ }
480+ }
481+ if (hasEmblem) {
482+ titleRightAnchor = 'right: emblemIcon.left; \n\
483+ rightMargin: emblemIcon.width > 0 ? units.gu(0.5) : 0; \n';
484+ } else {
485+ titleRightAnchor = 'right: parent.right; \n'
486+ titleRightAnchor += extraRightAnchor;
487+ }
488+
489+ if (hasTitleContainer) {
490+ // Using headerTitleContainer
491+ titleAnchors = titleRightAnchor;
470− titleAnchors = 'left: parent.left; right: parent.right';
492+ titleAnchors += 'left: parent.left; \n\
493+ top: parent.top;';
494+ subtitleAnchors = 'right: parent.right; \n\
495+ left: parent.left; \n';
471− subtitleAnchors = titleAnchors;
496+ subtitleAnchors += extraRightAnchor;
497+ if (hasSubtitle) {
498+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
499+ subtitleAnchors += 'top: titleLabel.bottom;\n';
500+ } else {
472− attributesAnchors = subtitleAnchors;
501+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
502+ }
473 } else if (hasMascot) {
503 } else if (hasMascot) {
474− // Using row + label
504+ // Using row + titleContainer
475− titleAnchors = 'verticalCenter: parent.verticalCenter;\n'
505+ titleAnchors = 'verticalCenter: parent.verticalCenter;\n';
476 } else {
506 } else {
477 if (headerAsOverlay) {
507 if (headerAsOverlay) {
478 // Using anchors to the overlay
508 // Using anchors to the overlay
509+ titleAnchors = titleRightAnchor;
479− titleAnchors = 'left: parent.left; \n\
510+ titleAnchors += 'left: parent.left; \n\
480− leftMargin: units.gu(1); \n\
511+ leftMargin: units.gu(1); \n\
481− right: parent.right; \n\
482− rightMargin: units.gu(1); \n\
483− top: overlayLoader.top; \n\
512+ top: overlayLoader.top; \n\
484− topMargin: units.gu(1);\n';
513+ topMargin: units.gu(1);\n';
485 } else {
514 } else {
486 // Using anchors to the mascot/parent
515 // Using anchors to the mascot/parent
487− titleAnchors = "right: parent.right;\n";
516+ titleAnchors = titleRightAnchor;
488− titleAnchors += "rightMargin: units.gu(1);\n";
489 titleAnchors += headerLeftAnchor;
517 titleAnchors += headerLeftAnchor;
490 titleAnchors += headerVerticalAnchors;
518 titleAnchors += headerVerticalAnchors;
491 if (!headerLeftAnchorHasMargin) {
519 if (!headerLeftAnchorHasMargin) {
492− titleAnchors += 'leftMargin: units.gu(1);\n'
520+ titleAnchors += extraLeftAnchor;
493 }
521 }
494 }
522 }
495 subtitleAnchors = 'left: titleLabel.left; \n\
523 subtitleAnchors = 'left: titleLabel.left; \n\
496− leftMargin: titleLabel.leftMargin; \n\
524+ leftMargin: titleLabel.leftMargin; \n';
497− right: titleLabel.right; \n\
525+ subtitleAnchors += extraRightAnchor;
498− rightMargin: titleLabel.rightMargin; \n\
526+ if (hasEmblem) {
499− top: titleLabel.bottom; \n\
527+ // using container
500− topMargin: units.dp(2);\n';
528+ subtitleAnchors += 'right: parent.right; \n';
529+ } else {
530+ subtitleAnchors += 'right: titleLabel.right; \n';
531+ }
532+
501 if (hasSubtitle) {
533 if (hasSubtitle) {
502− attributesAnchors = 'left: subtitleLabel.left; \n\
534+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
503− leftMargin: subtitleLabel.leftMargin; \n\
535+ subtitleAnchors += 'top: titleLabel.bottom;\n';
504− right: subtitleLabel.right; \n\
505− rightMargin: subtitleLabel.rightMargin; \n\
506− top: subtitleLabel.bottom; \n\
507− topMargin: units.dp(2);\n';
508 } else {
536 } else {
509− attributesAnchors = subtitleAnchors;
537+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
510 }
538 }
511 }
539 }
512
540
541+ // code for different elements
513 var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
542 var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
514− var titleCode = kTitleLabelCode.arg(titleAnchors).arg(color).arg(titleLabelVisibleExtra);
543+ var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra);
515− var subtitleCode = "";
544+ var subtitleCode;
545+ var attributesCode;
546+
547+ // code for the title container
548+ var containerCode = [];
549+ var containerHeight = 'titleLabel.height';
550+ containerCode.push(titleCode);
516 if (hasSubtitle) {
551 if (hasSubtitle) {
517− subtitleCode += kSubtitleLabelCode.arg(subtitleAnchors).arg(color);
552+ subtitleCode = kSubtitleLabelCode.arg(subtitleAnchors).arg(titleColor);
553+ containerCode.push(subtitleCode);
554+ containerHeight += ' + subtitleLabel.height';
555+ }
556+ if (hasEmblem) {
557+ containerCode.push(kEmblemIconCode.arg(extraRightAnchor).arg(titleColor));
558+ }
559+ if (hasAttributes) {
560+ attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(titleColor);
561+ containerCode.push(attributesCode);
562+ containerHeight += ' + attributesRow.height';
518 }
563 }
519
564
520− if (hasMascot && (hasSubtitle || hasAttributes)) {
565+ if (hasTitleContainer) {
521− // If using row + column wrap the code in the column
566+ // use container
522− titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(subtitleCode);
567+ titleSubtitleCode = kHeaderContainerCodeGenerator(titleContainerAnchors, containerHeight, containerCode);
523− if (hasSubtitle && hasAttributes) {
524− var attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(color);
525− titleSubtitleCode = kHeaderColumnCodeGenerator(titleCode, subtitleCode, attributesCode);
526− } else if (hasSubtitle) {
527− titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(subtitleCode);
528− } else if (hasAttributes) {
529− var attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(color);
530− titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(attributesCode);
531− }
532 } else {
568 } else {
569+ // no container
533 titleSubtitleCode = titleCode;
570 titleSubtitleCode = titleCode;
534 if (hasSubtitle) {
571 if (hasSubtitle) {
535− titleSubtitleCode = titleSubtitleCode + subtitleCode;
572+ titleSubtitleCode += subtitleCode;
536 }
573 }
537 if (hasAttributes) {
574 if (hasAttributes) {
538− var attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(color);
539− titleSubtitleCode = titleSubtitleCode + attributesCode;
575+ titleSubtitleCode += attributesCode;
540 }
576 }
541 }
577 }
542 }
578 }
543
579
544 if (hasHeaderRow) {
580 if (hasHeaderRow) {
581+ var rowCode = [mascotCode, titleSubtitleCode];
545− if (mascotShapeCode != "") {
582+ if (mascotShapeCode != '') {
546− code += kHeaderRow3Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotShapeCode).arg(mascotCode).arg(titleSubtitleCode);
583+ rowCode.unshift(mascotShapeCode);
547− } else {
548− code += kHeaderRow2Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotCode).arg(titleSubtitleCode);
549 }
584 }
585+ code += kHeaderRowCodeGenerator(headerVerticalAnchors + headerLeftAnchor, rowCode)
550 } else {
586 } else {
551 code += mascotShapeCode + mascotCode + titleSubtitleCode;
587 code += mascotShapeCode + mascotCode + titleSubtitleCode;
552 }
588 }
553
589
554 if (hasSummary) {
590 if (hasSummary) {
555 var summaryTopAnchor;
591 var summaryTopAnchor;
556− if (isHorizontal && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
592+ if (isHorizontal && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
557− else if (headerAsOverlay && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
593+ else if (headerAsOverlay && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
558− else if (hasHeaderRow) summaryTopAnchor = "row.bottom";
594+ else if (hasHeaderRow) summaryTopAnchor = 'row.bottom';
595+ else if (hasTitleContainer) summaryTopAnchor = 'headerTitleContainer.bottom';
559− else if (hasMascot) summaryTopAnchor = "mascotImage.bottom";
596+ else if (hasMascot) summaryTopAnchor = 'mascotImage.bottom';
560− else if (hasAttributes) summaryTopAnchor = "attributesRow.bottom";
597+ else if (hasAttributes) summaryTopAnchor = 'attributesRow.bottom';
561− else if (hasSubtitle) summaryTopAnchor = "subtitleLabel.bottom";
598+ else if (hasSubtitle) summaryTopAnchor = 'subtitleLabel.bottom';
562− else if (hasTitle) summaryTopAnchor = "titleLabel.bottom";
599+ else if (hasTitle) summaryTopAnchor = 'titleLabel.bottom';
563− else if (hasArt) summaryTopAnchor = "artShapeHolder.bottom";
600+ else if (hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
564− else summaryTopAnchor = "parent.top";
601+ else summaryTopAnchor = 'parent.top';
565−
602+
566− var color;
603+ var summaryColor;
567 if (hasBackground) {
604 if (hasBackground) {
568− color = summaryColorWithBackground;
605+ summaryColor = summaryColorWithBackground;
569 } else {
606 } else {
570− color = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
607+ summaryColor = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
571 }
608 }
572
609
573 var summaryTopMargin = (hasMascot || hasSubtitle || hasAttributes ? 'anchors.margins' : '0');
610 var summaryTopMargin = (hasMascot || hasSubtitle || hasAttributes ? 'anchors.margins' : '0');
574
611
575− code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color);
612+ code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);
576 }
613 }
577
614
578 var touchdownAnchors;
615 var touchdownAnchors;
579 if (hasBackground) {
616 if (hasBackground) {
580 touchdownAnchors = 'fill: backgroundLoader';
617 touchdownAnchors = 'fill: backgroundLoader';
581− } else if (hasArt && !hasMascot && !hasSummary) {
618+ } else if (touchdownOnArtShape) {
582 touchdownAnchors = 'fill: artShapeHolder';
619 touchdownAnchors = 'fill: artShapeHolder';
583 } else {
620 } else {
584 touchdownAnchors = 'fill: root'
621 touchdownAnchors = 'fill: root'
585 }
622 }
586 code += kTouchdownCode.arg(touchdownAnchors);
623 code += kTouchdownCode.arg(touchdownAnchors);
587
624
625+ var implicitHeight = 'implicitHeight: ';
588 if (hasSummary) {
626 if (hasSummary) {
589− code += 'implicitHeight: summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
627+ implicitHeight += 'summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
590 } else if (hasHeaderRow) {
628 } else if (hasHeaderRow) {
591− code += 'implicitHeight: row.y + row.height + units.gu(1);\n';
629+ implicitHeight += 'row.y + row.height + units.gu(1);\n';
592 } else if (hasMascot) {
630 } else if (hasMascot) {
593− code += 'implicitHeight: mascotImage.y + mascotImage.height;\n';
631+ implicitHeight += 'mascotImage.y + mascotImage.height;\n';
632+ } else if (hasTitleContainer) {
633+ implicitHeight += 'headerTitleContainer.y + headerTitleContainer.height + units.gu(1);\n';
594 } else if (hasAttributes) {
634 } else if (hasAttributes) {
595− code += 'implicitHeight: attributesRow.y + attributesRow.height + units.gu(1);\n';
635+ implicitHeight += 'attributesRow.y + attributesRow.height + units.gu(1);\n';
596 } else if (hasSubtitle) {
636 } else if (hasSubtitle) {
597− code += 'implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
637+ implicitHeight += 'subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
598 } else if (hasTitle) {
638 } else if (hasTitle) {
599− code += 'implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);\n';
639+ implicitHeight += 'titleLabel.y + titleLabel.height + units.gu(1);\n';
600 } else if (hasArt) {
640 } else if (hasArt) {
601− code += 'implicitHeight: artShapeHolder.height;\n';
641+ implicitHeight += 'artShapeHolder.height;\n';
602 }
642 }
603 // Close the AbstractButton
643 // Close the AbstractButton
604− code += '}\n';
644+ code += implicitHeight + '}\n';
605
645
606 return code;
646 return code;
607}
647}
608
648
609function createCardComponent(parent, template, components) {
649function createCardComponent(parent, template, components) {
610 var imports = 'import QtQuick 2.2; \n\
650 var imports = 'import QtQuick 2.2; \n\
611− import Ubuntu.Components 0.1; \n\
651+ import Ubuntu.Components 1.1; \n\
612 import Dash 0.1;\n';
652 import Dash 0.1;\n';
613 var card = cardString(template, components);
653 var card = cardString(template, components);
614 var code = imports + 'Component {\n' + card + '}\n';
654 var code = imports + 'Component {\n' + card + '}\n';
tests/mocks/Unity/fake_categories.cpp+6−2
@@ -109,11 +109,13 @@ Categories::data(const QModelIndex& index, int role) const
109 }
109 }
110 case RoleComponents:
110 case RoleComponents:
111 {
111 {
112− QVariantMap map, artMap;
112+ QVariantMap map, artMap, attributeMap;
113 artMap["aspect-ratio"] = "1.0";
113 artMap["aspect-ratio"] = "1.0";
114 artMap["field"] = "art";
114 artMap["field"] = "art";
115 map["art"] = artMap;
115 map["art"] = artMap;
116 map["title"] = "HOLA";
116 map["title"] = "HOLA";
117+ attributeMap["field"] = "attribute";
118+ map["attributes"] = attributeMap;
117 return map;
119 return map;
118 }
120 }
119 case RoleHeaderLink:
121 case RoleHeaderLink:
@@ -156,7 +158,7 @@ Categories::data(const QModelIndex& index, int role) const
156 }
158 }
157 case RoleComponents:
159 case RoleComponents:
158 {
160 {
159− QVariantMap map, artMap;
161+ QVariantMap map, artMap, attributeMap;
160 if (index.row() % 2 != 0) {
162 if (index.row() % 2 != 0) {
161 artMap["aspect-ratio"] = QString("1.%1").arg(index.row());
163 artMap["aspect-ratio"] = QString("1.%1").arg(index.row());
162 } else {
164 } else {
@@ -166,6 +168,8 @@ Categories::data(const QModelIndex& index, int role) const
166 map["art"] = artMap;
168 map["art"] = artMap;
167 map["title"] = "HOLA";
169 map["title"] = "HOLA";
168 map["subtitle"] = "HOLA";
170 map["subtitle"] = "HOLA";
171+ attributeMap["field"] = "attribute";
172+ map["attributes"] = attributeMap;
169 return map;
173 return map;
170 }
174 }
171 case RoleHeaderLink:
175 case RoleHeaderLink:
tests/plugins/Dash/cardcreator/1.res+4−6
@@ -61,12 +61,10 @@ Label {
61 id: titleLabel;
61 id: titleLabel;
62 objectName: "titleLabel";
62 objectName: "titleLabel";
63 anchors { right: parent.right;
63 anchors { right: parent.right;
64−rightMargin: units.gu(1);
65−left: parent.left;
64+ left: parent.left;
66−top: artShapeHolder.bottom;
65+ top: artShapeHolder.bottom;
67− topMargin: units.gu(1);
66+ topMargin: units.gu(1);
68−leftMargin: units.gu(1);
69− }
67+ }
70 elide: Text.ElideRight;
68 elide: Text.ElideRight;
71 fontSize: "small";
69 fontSize: "small";
72 wrapMode: Text.Wrap;
70 wrapMode: Text.Wrap;
tests/plugins/Dash/cardcreator/1.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
2−components: {"art":{"aspect-ratio":1.6,"field":"art"},"title":{"field":"title"}}
2+components: {"art":{"aspect-ratio":1.6,"field":"art"},"title":{"field":"title"},"attributes":{}}
3result: 1.res
3result: 1.res
tests/plugins/Dash/cardcreator/2.res+25−17
@@ -55,17 +55,19 @@ Row {
55 spacing: margins;
55 spacing: margins;
56 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
56 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
57 anchors { top: parent.top;
57 anchors { top: parent.top;
58− topMargin: units.gu(1);
58+ topMargin: units.gu(1);
59−left: parent.left;
59+ left: parent.left;
60− }
60+ }
61 anchors.right: parent.right;
61 anchors.right: parent.right;
62 anchors.margins: margins;
62 anchors.margins: margins;
63+ anchors.rightMargin: 0;
64+ data: [
63− data: [ Image {
65+Image {
64 id: mascotImage;
66 id: mascotImage;
65 objectName: "mascotImage";
67 objectName: "mascotImage";
66 anchors { verticalCenter: parent.verticalCenter; }
68 anchors { verticalCenter: parent.verticalCenter; }
67 readonly property int maxSize: Math.max(width, height) * 4;
69 readonly property int maxSize: Math.max(width, height) * 4;
68− source: cardData && cardData["mascot"];
70+ source: cardData && cardData["mascot"] || "";
69 width: units.gu(6);
71 width: units.gu(6);
70 height: units.gu(5.625);
72 height: units.gu(5.625);
71 sourceSize { width: maxSize; height: maxSize }
73 sourceSize { width: maxSize; height: maxSize }
@@ -74,16 +76,19 @@ left: parent.left;
74 verticalAlignment: Image.AlignVCenter;
76 verticalAlignment: Image.AlignVCenter;
75 visible: showHeader;
77 visible: showHeader;
76 }
78 }
77−
79+,Item {
78− ,
80+ id: headerTitleContainer;
79− Column {
80− anchors.verticalCenter: parent.verticalCenter;
81+ anchors { verticalCenter: parent.verticalCenter; }
81− spacing: units.dp(2);
82− width: parent.width - x;
82+ width: parent.width - x;
83+ implicitHeight: titleLabel.height + subtitleLabel.height;
84+ data: [
83− data: [ Label {
85+ Label {
84 id: titleLabel;
86 id: titleLabel;
85 objectName: "titleLabel";
87 objectName: "titleLabel";
88+ anchors { right: parent.right;
89+ rightMargin: units.gu(1);
86− anchors { left: parent.left; right: parent.right }
90+ left: parent.left;
91+ top: parent.top; }
87 elide: Text.ElideRight;
92 elide: Text.ElideRight;
88 fontSize: "small";
93 fontSize: "small";
89 wrapMode: Text.Wrap;
94 wrapMode: Text.Wrap;
@@ -95,12 +100,15 @@ left: parent.left;
95 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
100 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
96 horizontalAlignment: root.headerAlignment;
101 horizontalAlignment: root.headerAlignment;
97 }
102 }
98−
99− ,
100− Label {
103+ ,Label {
101 id: subtitleLabel;
104 id: subtitleLabel;
102 objectName: "subtitleLabel";
105 objectName: "subtitleLabel";
106+ anchors { right: parent.right;
103− anchors { left: parent.left; right: parent.right }
107+ left: parent.left;
108+ rightMargin: units.gu(1);
109+ top: titleLabel.bottom;
110+ }
111+ anchors.topMargin: units.dp(2);
104 elide: Text.ElideRight;
112 elide: Text.ElideRight;
105 fontSize: "small";
113 fontSize: "small";
106 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
114 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
tests/plugins/Dash/cardcreator/2.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
1template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
2−components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"}}
2+components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{}}
3result: 2.res
3result: 2.res
tests/plugins/Dash/cardcreator/3.res+9−12
@@ -61,12 +61,10 @@ Label {
61 id: titleLabel;
61 id: titleLabel;
62 objectName: "titleLabel";
62 objectName: "titleLabel";
63 anchors { right: parent.right;
63 anchors { right: parent.right;
64−rightMargin: units.gu(1);
65−left: parent.left;
64+ left: parent.left;
66−top: artShapeHolder.bottom;
65+ top: artShapeHolder.bottom;
67− topMargin: units.gu(1);
66+ topMargin: units.gu(1);
68−leftMargin: units.gu(1);
69− }
67+ }
70 elide: Text.ElideRight;
68 elide: Text.ElideRight;
71 fontSize: "small";
69 fontSize: "small";
72 wrapMode: Text.Wrap;
70 wrapMode: Text.Wrap;
@@ -82,12 +80,11 @@ Label {
82 id: subtitleLabel;
80 id: subtitleLabel;
83 objectName: "subtitleLabel";
81 objectName: "subtitleLabel";
84 anchors { left: titleLabel.left;
82 anchors { left: titleLabel.left;
85− leftMargin: titleLabel.leftMargin;
83+ leftMargin: titleLabel.leftMargin;
86− right: titleLabel.right;
84+ right: titleLabel.right;
87− rightMargin: titleLabel.rightMargin;
88− top: titleLabel.bottom;
85+ top: titleLabel.bottom;
86+ }
89− topMargin: units.dp(2);
87+ anchors.topMargin: units.dp(2);
90− }
91 elide: Text.ElideRight;
88 elide: Text.ElideRight;
92 fontSize: "small";
89 fontSize: "small";
93 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
90 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
tests/plugins/Dash/cardcreator/3.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
1template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
2−components: {"art":{"aspect-ratio":0.75,"field":"art"},"subtitle":{"field":"price"},"title":{"field":"title"}}
2+components: {"art":{"aspect-ratio":0.75,"field":"art"},"subtitle":{"field":"price"},"title":{"field":"title"},"attributes":{}}
3result: 3.res
3result: 3.res
tests/plugins/Dash/cardcreator/4.res+23−15
@@ -27,7 +27,9 @@ Row {
27}
27}
28 anchors.right: parent.right;
28 anchors.right: parent.right;
29 anchors.margins: margins;
29 anchors.margins: margins;
30+ anchors.rightMargin: 0;
31+data: [
30−data: [ Loader {
32+Loader {
31 id: mascotShapeLoader;
33 id: mascotShapeLoader;
32 objectName: "mascotShapeLoader";
34 objectName: "mascotShapeLoader";
33 asynchronous: root.asynchronous;
35 asynchronous: root.asynchronous;
@@ -39,13 +41,12 @@ data: [ Loader {
39 anchors { verticalCenter: parent.verticalCenter; }
41 anchors { verticalCenter: parent.verticalCenter; }
40 }
42 }
41
43
42−,
43−Image {
44+,Image {
44 id: mascotImage;
45 id: mascotImage;
45 objectName: "mascotImage";
46 objectName: "mascotImage";
46 anchors { verticalCenter: parent.verticalCenter; }
47 anchors { verticalCenter: parent.verticalCenter; }
47 readonly property int maxSize: Math.max(width, height) * 4;
48 readonly property int maxSize: Math.max(width, height) * 4;
48− source: cardData && cardData["mascot"];
49+ source: cardData && cardData["mascot"] || "";
49 width: units.gu(6);
50 width: units.gu(6);
50 height: units.gu(5.625);
51 height: units.gu(5.625);
51 sourceSize { width: maxSize; height: maxSize }
52 sourceSize { width: maxSize; height: maxSize }
@@ -55,15 +56,19 @@ Image {
55 visible: false;
56 visible: false;
56 }
57 }
57
58
58−,
59+,Item {
59−Column {
60+ id: headerTitleContainer;
60− anchors.verticalCenter: parent.verticalCenter;
61+ anchors { verticalCenter: parent.verticalCenter; }
61− spacing: units.dp(2);
62− width: parent.width - x;
62+ width: parent.width - x;
63+ implicitHeight: titleLabel.height + subtitleLabel.height;
64+ data: [
63−data: [ Label {
65+Label {
64 id: titleLabel;
66 id: titleLabel;
65 objectName: "titleLabel";
67 objectName: "titleLabel";
68+ anchors { right: parent.right;
69+ rightMargin: units.gu(1);
66− anchors { left: parent.left; right: parent.right }
70+ left: parent.left;
71+ top: parent.top; }
67 elide: Text.ElideRight;
72 elide: Text.ElideRight;
68 fontSize: "small";
73 fontSize: "small";
69 wrapMode: Text.Wrap;
74 wrapMode: Text.Wrap;
@@ -75,12 +80,15 @@ data: [ Label {
75 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
80 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
76 horizontalAlignment: root.headerAlignment;
81 horizontalAlignment: root.headerAlignment;
77 }
82 }
78−,
79−Label {
83+,Label {
80 id: subtitleLabel;
84 id: subtitleLabel;
81 objectName: "subtitleLabel";
85 objectName: "subtitleLabel";
86+ anchors { right: parent.right;
82− anchors { left: parent.left; right: parent.right }
87+ left: parent.left;
83−
88+ rightMargin: units.gu(1);
89+ top: titleLabel.bottom;
90+ }
91+ anchors.topMargin: units.dp(2);
84 elide: Text.ElideRight;
92 elide: Text.ElideRight;
85 fontSize: "small";
93 fontSize: "small";
86 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
94 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
tests/plugins/Dash/cardcreator/4.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2}
1template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2}
2−components: {"art":{"aspect-ratio":1},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"}}
2+components: {"art":{"aspect-ratio":1},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"},"attributes":{}}
3result: 4.res
3result: 4.res
tests/plugins/Dash/cardcreator/5.res+11−13
@@ -102,13 +102,12 @@ readonly property int headerHeight: titleLabel.height + subtitleLabel.height + s
102Label {
102Label {
103 id: titleLabel;
103 id: titleLabel;
104 objectName: "titleLabel";
104 objectName: "titleLabel";
105+ anchors { right: parent.right;
105− anchors { left: parent.left;
106+ left: parent.left;
106− leftMargin: units.gu(1);
107+ leftMargin: units.gu(1);
107− right: parent.right;
108− rightMargin: units.gu(1);
109− top: overlayLoader.top;
108+ top: overlayLoader.top;
110− topMargin: units.gu(1);
109+ topMargin: units.gu(1);
111− }
110+ }
112 elide: Text.ElideRight;
111 elide: Text.ElideRight;
113 fontSize: "small";
112 fontSize: "small";
114 wrapMode: Text.Wrap;
113 wrapMode: Text.Wrap;
@@ -124,12 +123,11 @@ Label {
124 id: subtitleLabel;
123 id: subtitleLabel;
125 objectName: "subtitleLabel";
124 objectName: "subtitleLabel";
126 anchors { left: titleLabel.left;
125 anchors { left: titleLabel.left;
127− leftMargin: titleLabel.leftMargin;
126+ leftMargin: titleLabel.leftMargin;
128− right: titleLabel.right;
127+ right: titleLabel.right;
129− rightMargin: titleLabel.rightMargin;
130− top: titleLabel.bottom;
128+ top: titleLabel.bottom;
129+ }
131− topMargin: units.dp(2);
130+ anchors.topMargin: units.dp(2);
132− }
133 elide: Text.ElideRight;
131 elide: Text.ElideRight;
134 fontSize: "small";
132 fontSize: "small";
135 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
133 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
tests/plugins/Dash/cardcreator/5.tst+1−1
@@ -1,3 +1,3 @@
1template: {"card-layout":"vertical","card-size":"medium","category-layout":"carousel","collapsed-rows":2,"overlay":true}
1template: {"card-layout":"vertical","card-size":"medium","category-layout":"carousel","collapsed-rows":2,"overlay":true}
2−components: {"art":{"aspect-ratio":1,"field":"art"},"subtitle":{"field":"artist"},"title":{"field":"title"}}
2+components: {"art":{"aspect-ratio":1,"field":"art"},"subtitle":{"field":"artist"},"title":{"field":"title"},"attributes":{}}
3result: 5.res
3result: 5.res
tests/plugins/Dash/cardcreator/6.res+97−44
@@ -13,57 +13,110 @@ AbstractButton {
13 property bool asynchronous: true;
13 property bool asynchronous: true;
14 property bool showHeader: true;
14 property bool showHeader: true;
15 implicitWidth: childrenRect.width;
15 implicitWidth: childrenRect.width;
16−onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artShapeLoader.item) artShapeLoader.item.borderSource = artShapeBorderSource; }
17−readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
18−Item {
19− id: artShapeHolder;
20− height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
21− width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
22− anchors { horizontalCenter: parent.horizontalCenter; }
23− Loader {
16+Loader {
24− id: artShapeLoader;
17+ id: backgroundLoader;
25− objectName: "artShapeLoader";
18+ objectName: "backgroundLoader";
26− active: cardData && cardData["art"] || false;
19+ anchors.fill: parent;
27− asynchronous: root.asynchronous;
20+ asynchronous: root.asynchronous;
28− visible: status == Loader.Ready;
21+ visible: status == Loader.Ready;
29− sourceComponent: UbuntuShape {
22+ sourceComponent: UbuntuShape {
30− id: artShape;
31− objectName: "artShape";
23+ objectName: "background";
32− radius: "medium";
24+ radius: "medium";
33− visible: image.status == Image.Ready;
25+ color: getColor(0) || "white";
34− readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
26+ gradientColor: getColor(1) || color;
35− readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
27+ anchors.fill: parent;
36− Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
28+ image: backgroundImage.source ? backgroundImage : null;
37− Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
29+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
38− function updateWidthHeightBindings() {
30+ property Image backgroundImage: Image {
39− if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
31+ objectName: "backgroundImage";
40− width = root.fixedArtShapeSize.width;
32+ source: {
41− height = root.fixedArtShapeSize.height;
33+ if (cardData && typeof cardData["background"] === "string") return cardData["background"];
42− } else {
34+ else if (template && typeof template["card-background"] === "string") return template["card-background"];
43− width = Qt.binding(function() { return !visible ? 0 : image.width });
35+ else return "";
44− height = Qt.binding(function() { return !visible ? 0 : image.height });
36+ }
37+ }
38+ function getColor(index) {
39+ if (cardData && typeof cardData["background"] === "object"
40+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
41+ return cardData["background"]["elements"][index];
42+ } else if (template && typeof template["card-background"] === "object"
43+ && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
44+ return template["card-background"]["elements"][index];
45+ } else return undefined;
46+ }
45− }
47+ }
46 }
48 }
47− image: Image {
49+readonly property size artShapeSize: Qt.size(-1, -1);
50+readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
51+Item {
52+ id: headerTitleContainer;
53+ anchors { right: parent.right; left: parent.left;
54+ top: parent.top;
55+ topMargin: units.gu(1);
56+ leftMargin: units.gu(1);
57+ }
58+ width: parent.width - x;
59+ implicitHeight: titleLabel.height + subtitleLabel.height;
60+ data: [
61+ Label {
62+ id: titleLabel;
48− objectName: "artImage";
63+ objectName: "titleLabel";
49− source: cardData && cardData["art"] || "";
64+ anchors { right: emblemIcon.left;
50− cache: true;
65+ rightMargin: emblemIcon.width > 0 ? units.gu(0.5) : 0;
51− asynchronous: root.asynchronous;
66+ left: parent.left;
52− fillMode: Image.PreserveAspectCrop;
67+ top: parent.top; }
53− width: root.width;
68+ elide: Text.ElideRight;
54− height: width / artShape.aspect;
69+ fontSize: "small";
55− }
70+ wrapMode: Text.Wrap;
56− }
71+ maximumLineCount: 2;
72+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
73+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
74+ visible: showHeader ;
75+ text: root.title;
76+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
77+ horizontalAlignment: root.headerAlignment;
57 }
78 }
79+,Label {
80+ id: subtitleLabel;
81+ objectName: "subtitleLabel";
82+ anchors { right: parent.right;
83+ left: parent.left;
84+ rightMargin: units.gu(1);
85+ top: titleLabel.bottom;
86+ }
87+ anchors.topMargin: units.dp(2);
88+ elide: Text.ElideRight;
89+ fontSize: "small";
90+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
91+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
92+ visible: titleLabel.visible && titleLabel.text;
93+ text: cardData && cardData["subtitle"] || "";
94+ font.weight: Font.Light;
95+ horizontalAlignment: root.headerAlignment;
96+ }
97+,Icon {
98+ id: emblemIcon;
99+ objectName: "emblemIcon";
100+ anchors {
101+ bottom: titleLabel.baseline;
102+ right: parent.right;
103+ rightMargin: units.gu(1);
58− }
104+ }
59−readonly property int headerHeight: 0;
105+ source: cardData && cardData["emblem"] || "";
106+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
107+ width: height;
108+ height: source != "" ? titleLabel.font.pixelSize : 0;
109+ }
110+
111+ ]
112+ }
60UbuntuShape {
113UbuntuShape {
61 id: touchdown;
114 id: touchdown;
62 objectName: "touchdown";
115 objectName: "touchdown";
63− anchors { fill: artShapeHolder }
116+ anchors { fill: backgroundLoader }
64 visible: root.pressed;
117 visible: root.pressed;
65 radius: "medium";
118 radius: "medium";
66 borderSource: "radius_pressed.sci"
119 borderSource: "radius_pressed.sci"
67}
120}
68−implicitHeight: artShapeHolder.height;
121+implicitHeight: headerTitleContainer.y + headerTitleContainer.height + units.gu(1);
69}
122}
tests/plugins/Dash/cardcreator/6.tst+2−2
@@ -1,3 +1,3 @@
1−template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
1+template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
2−components: {"art":{"aspect-ratio":1.6,"field":"art"}}
2+components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"subtitle":{"field":"author"},"title":{"field":"title"},"emblem":{"field":"source"},"attributes":{}}
3result: 6.res
3result: 6.res
tests/plugins/Dash/cardcreator/7.res+32−20
@@ -55,17 +55,19 @@ Row {
55 spacing: margins;
55 spacing: margins;
56 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
56 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
57 anchors { top: parent.top;
57 anchors { top: parent.top;
58− topMargin: units.gu(1);
58+ topMargin: units.gu(1);
59−left: parent.left;
59+ left: parent.left;
60− }
60+ }
61 anchors.right: parent.right;
61 anchors.right: parent.right;
62 anchors.margins: margins;
62 anchors.margins: margins;
63+ anchors.rightMargin: 0;
64+ data: [
63− data: [ Image {
65+Image {
64 id: mascotImage;
66 id: mascotImage;
65 objectName: "mascotImage";
67 objectName: "mascotImage";
66 anchors { verticalCenter: parent.verticalCenter; }
68 anchors { verticalCenter: parent.verticalCenter; }
67 readonly property int maxSize: Math.max(width, height) * 4;
69 readonly property int maxSize: Math.max(width, height) * 4;
68− source: cardData && cardData["mascot"];
70+ source: cardData && cardData["mascot"] || "";
69 width: units.gu(6);
71 width: units.gu(6);
70 height: units.gu(5.625);
72 height: units.gu(5.625);
71 sourceSize { width: maxSize; height: maxSize }
73 sourceSize { width: maxSize; height: maxSize }
@@ -75,16 +77,19 @@ left: parent.left;
75 visible: showHeader;
77 visible: showHeader;
76 }
78 }
77
79
78− ,
80+,Item {
79− Column {
81+ id: headerTitleContainer;
80− anchors.verticalCenter: parent.verticalCenter;
82+ anchors { verticalCenter: parent.verticalCenter; }
81− spacing: units.dp(2);
82− width: parent.width - x;
83+ width: parent.width - x;
84+ implicitHeight: titleLabel.height + subtitleLabel.height + attributesRow.height;
83− data: [
85+ data: [
84− Label {
86+ Label {
85 id: titleLabel;
87 id: titleLabel;
86 objectName: "titleLabel";
88 objectName: "titleLabel";
89+ anchors { right: parent.right;
90+ rightMargin: units.gu(1);
87− anchors { left: parent.left; right: parent.right }
91+ left: parent.left;
92+ top: parent.top; }
88 elide: Text.ElideRight;
93 elide: Text.ElideRight;
89 fontSize: "small";
94 fontSize: "small";
90 wrapMode: Text.Wrap;
95 wrapMode: Text.Wrap;
@@ -96,11 +101,15 @@ left: parent.left;
96 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
101 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
97 horizontalAlignment: root.headerAlignment;
102 horizontalAlignment: root.headerAlignment;
98 }
103 }
99−,
100−Label {
104+,Label {
101 id: subtitleLabel;
105 id: subtitleLabel;
102 objectName: "subtitleLabel";
106 objectName: "subtitleLabel";
107+ anchors { right: parent.right;
103− anchors { left: parent.left; right: parent.right }
108+ left: parent.left;
109+ rightMargin: units.gu(1);
110+ top: titleLabel.bottom;
111+ }
112+ anchors.topMargin: units.dp(2);
104 elide: Text.ElideRight;
113 elide: Text.ElideRight;
105 fontSize: "small";
114 fontSize: "small";
106 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
115 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
@@ -110,13 +119,16 @@ Label {
110 font.weight: Font.Light;
119 font.weight: Font.Light;
111 horizontalAlignment: root.headerAlignment;
120 horizontalAlignment: root.headerAlignment;
112 }
121 }
113−,
114−CardAttributes {
122+,CardAttributes {
115 id: attributesRow;
123 id: attributesRow;
116 objectName: "attributesRow";
124 objectName: "attributesRow";
125+ anchors { right: parent.right;
117− anchors { left: parent.left; right: parent.right }
126+ left: parent.left;
127+ rightMargin: units.gu(1);
128+ top: subtitleLabel.bottom;
129+ }
118 color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
130 color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
119− model: cardData["attributes"];
131+ model: cardData && cardData["attributes"];
120 }
132 }
121
133
122 ]
134 ]
tests/qmltests/Dash/CardHelpers.js+1
@@ -60,6 +60,7 @@ var fullMapping = ' \
60 "art": "art", \
60 "art": "art", \
61 "subtitle": "subtitle", \
61 "subtitle": "subtitle", \
62 "mascot": "mascot", \
62 "mascot": "mascot", \
63+ "emblem": "emblem", \
63 "overlayColor": "overlayColor", \
64 "overlayColor": "overlayColor", \
64 "summary": "summary", \
65 "summary": "summary", \
65 "attributes": "attributes" \
66 "attributes": "attributes" \
tests/qmltests/Dash/artwork/emblem.pngnew file

Binary file not shown.

tests/qmltests/Dash/tst_Card.qml+19−1
@@ -31,6 +31,7 @@ Rectangle {
31 {
31 {
32 "art": "../../../tests/qmltests/Dash/artwork/music-player-design.png",
32 "art": "../../../tests/qmltests/Dash/artwork/music-player-design.png",
33 "mascot": "../../../tests/qmltests/Dash/artwork/avatar.png",
33 "mascot": "../../../tests/qmltests/Dash/artwork/avatar.png",
34+ "emblem": "../../../tests/qmltests/Dash/artwork/emblem.png",
34 "title": "foo",
35 "title": "foo",
35 "subtitle": "bar",
36 "subtitle": "bar",
36 "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
37 "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
@@ -270,7 +271,7 @@ Rectangle {
270 { tag: "Large", width: units.gu(38), index: 2 },
271 { tag: "Large", width: units.gu(38), index: 2 },
271 { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
272 { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
272 { tag: "Tall", height: units.gu(38) / 0.7, size: "large", width: units.gu(38), index: 4 },
273 { tag: "Tall", height: units.gu(38) / 0.7, size: "large", width: units.gu(38), index: 4 },
273− { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) * 2 }, index: 0 },
274+ { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) }, index: 0 },
274 { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 },
275 { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 },
275 { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 },
276 { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 },
276 ]
277 ]
@@ -458,6 +459,23 @@ Rectangle {
458 tryCompareFunction(function() { return Qt.colorEqual(subtitle.color, fontColor); }, true);
459 tryCompareFunction(function() { return Qt.colorEqual(subtitle.color, fontColor); }, true);
459 }
460 }
460
461
462+ function test_emblemIcon_data() {
463+ return [
464+ { tag: "Art and summary", emblem: true, index: 0 },
465+ { tag: "Art and summary, small", emblem: false, index: 1 },
466+ { tag: "No header", emblem: false, index: 7 },
467+ { tag: "With background", emblem: true, index: 10 },
468+ ];
469+ }
470+
471+ function test_emblemIcon(data) {
472+ selector.selectedIndex = data.index;
473+ waitForRendering(card);
474+
475+ var emblemIcon = findChild(card, "emblemIcon");
476+ compare(emblemIcon !== null, data.emblem);
477+ }
478+
461 function test_mascotShape_data() {
479 function test_mascotShape_data() {
462 return [
480 return [
463 { tag: "Art and summary", shape: false, index: 0 },
481 { tag: "Art and summary", shape: false, index: 0 },