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 readonly property var cardWidth: {
84 switch (categoryLayout) {
86 case "vertical-journal":
87 if (template["card-layout"] === "horizontal") return units.gu(38);
88 switch (template["card-size"]) {
89 case "small": return units.gu(12);
90 case "large": return units.gu(38);
92 return units.gu(18.5);
94 case "horizontal-list":
95 return carouselTool.minimumTileWidth;
105 type:real \brief Height to be enforced on the card in this configuration.
107 If undefined, should use implicit height of the actual card.
109 readonly property var cardHeight: {
110 switch (categoryLayout) {
112 if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
113 return units.gu(18.5);
115 case "horizontal-list":
116 return cardLoader.item ? cardLoader.item.implicitHeight : 0
118 return cardWidth / (components ? components["art"]["aspect-ratio"] : 1)
121 case "vertical-journal":
128 type:real \brief Height of the card's header.
130 readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
131 property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
134 \brief Desired alignment of title
136 readonly property int titleAlignment: {
137 if (template["card-layout"] === "horizontal"
138 || (typeof components["title"] !== "object" &&
139 components["title"]["align"] !== "center")) return Text.AlignLeft;
141 var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"];
143 for (var key in keys) {
146 if (typeof components[key] === "string"
147 || typeof components[key]["field"] === "string") return Text.AlignLeft;
153 return Text.AlignHCenter;
159 property real minimumTileWidth: {
160 if (cardTool.viewWidth === undefined) return undefined;
161 if (cardTool.viewWidth <= units.gu(40)) return units.gu(18);
162 if (cardTool.viewWidth >= units.gu(128)) return units.gu(26);
163 return units.gu(18 + Math.round((cardTool.viewWidth - units.gu(40)) / units.gu(11)));
166 readonly property real pathItemCount: 4.8457 /// (848 / 175) reference values
168 property real realPathItemCount: {
169 var scaledMinimumTileWidth = minimumTileWidth / cardTool.carouselSelectedItemScaleFactor;
170 var tileWidth = Math.max(cardTool.viewWidth / pathItemCount, scaledMinimumTileWidth);
171 return Math.min(cardTool.viewWidth / tileWidth, pathItemCount);
177 property int numOfAttributes: 0
178 property var model: []
179 property bool hasAttributes: {
180 var attributes = components["attributes"];
181 var hasAttributesFlag = (attributes != undefined) && (attributes["field"] != undefined);
183 if (hasAttributesFlag) {
184 if (attributes["max-count"]) {
185 numOfAttributes = attributes["max-count"];
188 return hasAttributesFlag
191 onNumOfAttributesChanged: {
193 for (var i = 0; i < numOfAttributes; i++) {
194 model.push( {"value":"text"+(i+1), "icon":"image://theme/ok" } );
201 property var fields: ["art", "mascot", "title", "subtitle", "summary", "attributes"]
202 property var maxData: {
203 "art": Qt.resolvedUrl("graphics/pixel.png"),
204 "mascot": Qt.resolvedUrl("graphics/pixel.png"),
207 "summary": "—\n—\n—\n—\n—",
208 "attributes": attributesModel.model
210 sourceComponent: cardTool.cardComponent
212 item.objectName = "cardToolCard";
213 item.asynchronous = false;
214 item.template = Qt.binding(function() { return cardTool.template; });
215 item.components = Qt.binding(function() { return cardTool.components; });
216 item.width = Qt.binding(function() { return cardTool.cardWidth || item.implicitWidth; });
217 item.height = Qt.binding(function() { return cardTool.cardHeight || item.implicitHeight; });
220 target: cardLoader.item
221 onComponentsChanged: {
223 for (var k in cardLoader.fields) {
224 var component = cardLoader.item.components[cardLoader.fields[k]];
225 var key = cardLoader.fields[k];
226 if ((typeof component === "string" && component.length > 0) ||
227 (typeof component === "object" && component !== null
228 && typeof component["field"] === "string" && component["field"].length > 0)) {
229 data[key] = cardLoader.maxData[key];
232 cardLoader.item.cardData = data;