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/>.
18 import Ubuntu.Components 1.3
22 \brief Tool for introspecting Card properties.
24 Some properties of Cards we need to determine category-wide (like card sizes in grid),
25 so we should not do them per-Card but in the category renderer.
27 This component creates an invisible card filled with maximum mapped data and calculates
28 or measures card properties for this configuration.
35 \brief Number of cards.
40 \brief Width of the category view.
42 property real viewWidth
45 \brief Template supplied for the category.
50 \brief Component mapping supplied for the category.
52 property var components
55 \brief The Scope this cardTool is representing
57 property string scopeId
60 \brief The Scope category this cardTool is representing
62 property string categoryId
65 \brief Scaling factor of selected Carousel item.
67 readonly property real carouselSelectedItemScaleFactor: 1.38 // XXX assuming 1.38 carousel scaling factor for cards
70 \brief The category layout for this card tool.
72 readonly property string categoryLayout: {
73 var layout = template["category-layout"];
75 // carousel fallback mode to grid
76 if (layout === "carousel" && count <= Math.ceil(carouselTool.realPathItemCount)) layout = "grid";
80 readonly property string artShapeStyle: {
81 return categoryLayout === "carousel" ? "shadow" : "flat"
84 // FIXME ? This seems like it should not be needed, but on Qt 5.4 + phone
85 // we are doing unneeded calls to getCardComponent with artShapeStyle and categoryLayout being empty
86 // Check when we move to newer Qts on the phone if we still need this
87 readonly property bool askForCardComponent: cardTool.template !== undefined &&
88 cardTool.components !== undefined &&
89 cardTool.artShapeStyle !== "" &&
90 cardTool.categoryLayout !== ""
92 property var cardComponent: askForCardComponent
93 ? CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, false, cardTool.artShapeStyle, cardTool.categoryLayout)
97 // Only way for the card below to actually be laid out completely.
98 // If invisible or in "data" array, some components are not taken into account.
103 // We have 3 view "widths"
107 readonly property bool isWideView: viewWidth >= units.gu(70)
108 readonly property bool isNarrowView: viewWidth <= units.gu(45)
111 type:real \brief Width to be enforced on the card in this configuration.
113 If -1, should use implicit width of the actual card.
115 readonly property real cardWidth: {
116 switch (categoryLayout) {
118 case "vertical-journal":
119 var size = template["card-size"];
120 if (template["card-layout"] === "horizontal") size = "large";
123 if (isNarrowView) return units.gu(12);
124 else return units.gu(14);
127 if (isWideView) return units.gu(42);
128 else return viewWidth - units.gu(2);
131 if (isNarrowView) return units.gu(18);
132 else if (isWideView) return units.gu(20);
133 else return units.gu(23);
135 case "horizontal-list":
136 return carouselTool.minimumTileWidth;
146 type:real \brief Height to be enforced on the card in this configuration.
148 If -1, should use implicit height of the actual card.
150 readonly property real cardHeight: {
151 switch (categoryLayout) {
153 if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
154 return units.gu(18.5);
156 case "horizontal-list":
157 return cardLoader.item ? cardLoader.item.implicitHeight : 0
159 return cardWidth / (components ? components["art"]["aspect-ratio"] : 1)
162 case "vertical-journal":
169 type:real \brief Height of the card's header.
171 readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
173 readonly property size artShapeSize: {
174 return cardLoader.item ? cardLoader.item.artShapeSize : Qt.size(0, 0)
180 readonly property real minimumTileWidth: {
181 if (cardTool.viewWidth === undefined) return undefined;
182 if (cardTool.viewWidth <= units.gu(40)) return units.gu(18);
183 if (cardTool.viewWidth >= units.gu(128)) return units.gu(26);
184 return units.gu(18 + Math.round((cardTool.viewWidth - units.gu(40)) / units.gu(11)));
187 readonly property real pathItemCount: 4.8457 /// (848 / 175) reference values
189 readonly property real realPathItemCount: {
190 var scaledMinimumTileWidth = minimumTileWidth / cardTool.carouselSelectedItemScaleFactor;
191 var tileWidth = Math.max(cardTool.viewWidth / pathItemCount, scaledMinimumTileWidth);
192 return Math.min(cardTool.viewWidth / tileWidth, pathItemCount);
198 property int numOfAttributes: 0
199 property var model: []
200 readonly property bool hasAttributes: {
201 var attributes = components["attributes"];
202 var hasAttributesFlag = (attributes != undefined) && (attributes["field"] != undefined);
204 if (hasAttributesFlag) {
205 if (attributes["max-count"]) {
206 numOfAttributes = attributes["max-count"];
209 return hasAttributesFlag
212 onNumOfAttributesChanged: {
214 for (var i = 0; i < numOfAttributes; i++) {
215 model.push( {"value":"text"+(i+1), "icon":"image://theme/ok" } );
221 id: socialActionsModel
222 property var model: []
223 readonly property bool hasActions: components["social-actions"] != undefined
225 onHasActionsChanged: {
228 model.push( {"id":"text", "icon":"image://theme/ok" } );
235 readonly property var cfields: ["art", "mascot", "title", "subtitle", "summary", "attributes", "social-actions"]
236 readonly property var dfields: ["art", "mascot", "title", "subtitle", "summary", "attributes", "socialActions"]
237 readonly property var maxData: {
238 "art": Qt.resolvedUrl("graphics/pixel.png"),
239 "mascot": Qt.resolvedUrl("graphics/pixel.png"),
242 "summary": "—\n—\n—\n—\n—",
243 "attributes": attributesModel.model,
244 "socialActions": socialActionsModel.model
246 sourceComponent: askForCardComponent
247 ? CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true, cardTool.artShapeStyle, cardTool.categoryLayout)
250 item.objectName = "cardToolCard";
251 item.width = Qt.binding(function() { return cardTool.cardWidth !== -1 ? cardTool.cardWidth : item.implicitWidth; });
252 item.height = Qt.binding(function() { return cardTool.cardHeight !== -1 ? cardTool.cardHeight : item.implicitHeight; });
256 onTemplateChanged: cardLoader.updateCardData();
257 onComponentsChanged: cardLoader.updateCardData();
259 function updateCardData() {
261 for (var k in cfields) {
262 var ckey = cfields[k];
263 var component = cardTool.components[ckey];
264 if ((typeof component === "string" && component.length > 0) ||
265 (typeof component === "object" && component !== null
266 && typeof component["field"] === "string" && component["field"].length > 0)) {
267 var dkey = dfields[k];
268 data[dkey] = maxData[dkey];
271 item.cardData = data;