2 * Copyright (C) 2014 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 \brief Tool for introspecting Card properties.
23 Some properties of Cards we need to determine category-wide (like card sizes in grid),
24 so we should not do them per-Card but in the category renderer.
26 This component creates an invisible card filled with maximum mapped data and calculates
27 or measures card properties for this configuration.
34 \brief Number of cards.
39 \brief Width of the category view.
41 property real viewWidth
44 \brief Scaling factor of selected Carousel item.
46 readonly property real carouselSelectedItemScaleFactor: 1.38 // XXX assuming 1.38 carousel scaling factor for cards
49 \brief Template supplied for the category.
54 \brief Component mapping supplied for the category.
56 property var components
59 \brief The category layout for this card tool.
61 property string categoryLayout: {
62 var layout = template["category-layout"];
64 // carousel fallback mode to grid
65 if (layout === "carousel" && count <= Math.ceil(carouselTool.realPathItemCount)) layout = "grid";
69 property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components);
72 // Only way for the card below to actually be laid out completely.
73 // If invisible or in "data" array, some components are not taken into account.
79 type:real \brief Width to be enforced on the card in this configuration.
81 If undefined, should use implicit width of the actual card.
83 property var cardWidth: {
84 switch (categoryLayout) {
86 case "vertical-journal":
87 var size = template["card-size"];
88 if (template["card-layout"] === "horizontal") size = "large";
91 if (viewWidth <= units.gu(45)) return units.gu(12);
92 else return units.gu(14);
95 if (viewWidth >= units.gu(70)) return units.gu(42);
96 else return viewWidth - units.gu(2);
99 if (viewWidth <= units.gu(45)) return units.gu(18);
100 else if (viewWidth >= units.gu(70)) return units.gu(20);
101 else return units.gu(23);
103 case "horizontal-list":
104 return carouselTool.minimumTileWidth;
114 type:real \brief Height to be enforced on the card in this configuration.
116 If undefined, should use implicit height of the actual card.
118 readonly property var cardHeight: {
119 switch (categoryLayout) {
121 if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
122 return units.gu(18.5);
124 case "horizontal-list":
125 return cardLoader.item ? cardLoader.item.implicitHeight : 0
127 return cardWidth / (components ? components["art"]["aspect-ratio"] : 1)
130 case "vertical-journal":
137 type:real \brief Height of the card's header.
139 readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
140 property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
143 \brief Desired alignment of title
145 readonly property int titleAlignment: {
146 if (template["card-layout"] === "horizontal"
147 || typeof components["title"] !== "object"
148 || components["title"]["align"] === "left") return Text.AlignLeft;
150 var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"];
152 for (var key in keys) {
155 if (typeof components[key] === "string"
156 || typeof components[key]["field"] === "string") return Text.AlignLeft;
162 return Text.AlignHCenter;
168 property real minimumTileWidth: {
169 if (cardTool.viewWidth === undefined) return undefined;
170 if (cardTool.viewWidth <= units.gu(40)) return units.gu(18);
171 if (cardTool.viewWidth >= units.gu(128)) return units.gu(26);
172 return units.gu(18 + Math.round((cardTool.viewWidth - units.gu(40)) / units.gu(11)));
175 readonly property real pathItemCount: 4.8457 /// (848 / 175) reference values
177 property real realPathItemCount: {
178 var scaledMinimumTileWidth = minimumTileWidth / cardTool.carouselSelectedItemScaleFactor;
179 var tileWidth = Math.max(cardTool.viewWidth / pathItemCount, scaledMinimumTileWidth);
180 return Math.min(cardTool.viewWidth / tileWidth, pathItemCount);
186 property int numOfAttributes: 0
187 property var model: []
188 property bool hasAttributes: {
189 var attributes = components["attributes"];
190 var hasAttributesFlag = (attributes != undefined) && (attributes["field"] != undefined);
192 if (hasAttributesFlag) {
193 if (attributes["max-count"]) {
194 numOfAttributes = attributes["max-count"];
197 return hasAttributesFlag
200 onNumOfAttributesChanged: {
202 for (var i = 0; i < numOfAttributes; i++) {
203 model.push( {"value":"text"+(i+1), "icon":"image://theme/ok" } );
210 readonly property var fields: ["art", "mascot", "title", "subtitle", "summary", "attributes"]
211 readonly property var maxData: {
212 "art": Qt.resolvedUrl("graphics/pixel.png"),
213 "mascot": Qt.resolvedUrl("graphics/pixel.png"),
216 "summary": "—\n—\n—\n—\n—",
217 "attributes": attributesModel.model
219 sourceComponent: cardTool.cardComponent
221 item.objectName = "cardToolCard";
222 item.asynchronous = false;
223 item.components = Qt.binding(function() { return cardTool.components; });
224 item.width = Qt.binding(function() { return cardTool.cardWidth || item.implicitWidth; });
225 item.height = Qt.binding(function() { return cardTool.cardHeight || item.implicitHeight; });
229 onTemplateChanged: cardLoader.updateCardData();
230 onComponentsChanged: cardLoader.updateCardData();
232 function updateCardData() {
234 for (var k in fields) {
235 var component = cardTool.components[fields[k]];
237 if ((typeof component === "string" && component.length > 0) ||
238 (typeof component === "object" && component !== null
239 && typeof component["field"] === "string" && component["field"].length > 0)) {
240 data[key] = maxData[key];
243 item.cardData = data;