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 header components.
136 readonly property int headerAlignment: {
137 var subtitle = components["subtitle"];
138 var price = components["price"];
139 var summary = components["summary"];
141 var hasSubtitle = subtitle && (typeof subtitle === "string" || subtitle["field"])
142 var hasPrice = price && (typeof price === "string" || subtitle["field"]);
143 var hasSummary = summary && (typeof summary === "string" || summary["field"])
145 var isOnlyTextComponent = !hasSubtitle && !hasPrice && !hasSummary;
146 if (!isOnlyTextComponent) return Text.AlignLeft;
148 return (template["card-layout"] === "horizontal") ? Text.AlignLeft : Text.AlignHCenter;
154 property real minimumTileWidth: {
155 if (cardTool.viewWidth === undefined) return undefined;
156 if (cardTool.viewWidth <= units.gu(40)) return units.gu(18);
157 if (cardTool.viewWidth >= units.gu(128)) return units.gu(26);
158 return units.gu(18 + Math.round((cardTool.viewWidth - units.gu(40)) / units.gu(11)));
161 readonly property real pathItemCount: 4.8457 /// (848 / 175) reference values
163 property real realPathItemCount: {
164 var scaledMinimumTileWidth = minimumTileWidth / cardTool.carouselSelectedItemScaleFactor;
165 var tileWidth = Math.max(cardTool.viewWidth / pathItemCount, scaledMinimumTileWidth);
166 return Math.min(cardTool.viewWidth / tileWidth, pathItemCount);
172 property int numOfAttributes: {
173 var attributes = components["attributes"];
174 if ((attributes != undefined) && attributes["field"]) {
175 if (attributes["max-count"]) {
176 return attributes["max-count"];
181 property var model: []
183 onNumOfAttributesChanged: {
185 for (var i = 0; i < numOfAttributes; i++) {
186 model.push( {"value":"text"+(i+1), "icon":"image://theme/ok" } );
193 property var fields: ["art", "mascot", "title", "subtitle", "summary", "attributes"]
194 property var maxData: {
195 "art": Qt.resolvedUrl("graphics/pixel.png"),
196 "mascot": Qt.resolvedUrl("graphics/pixel.png"),
199 "summary": "—\n—\n—\n—\n—",
200 "attributes": attributesModel.model
202 sourceComponent: cardTool.cardComponent
204 item.objectName = "cardToolCard";
205 item.asynchronous = false;
206 item.template = Qt.binding(function() { return cardTool.template; });
207 item.components = Qt.binding(function() { return cardTool.components; });
208 item.width = Qt.binding(function() { return cardTool.cardWidth || item.implicitWidth; });
209 item.height = Qt.binding(function() { return cardTool.cardHeight || item.implicitHeight; });
212 target: cardLoader.item
213 onComponentsChanged: {
215 for (var k in cardLoader.fields) {
216 var component = cardLoader.item.components[cardLoader.fields[k]];
217 var key = cardLoader.fields[k];
218 if ((typeof component === "string" && component.length > 0) ||
219 (typeof component === "object" && component !== null
220 && typeof component["field"] === "string" && component["field"].length > 0)) {
221 data[key] = cardLoader.maxData[key];
224 cardLoader.item.cardData = data;