Unity 8
 All Classes Functions
CardTool.qml
1 /*
2  * Copyright (C) 2014 Canonical, Ltd.
3  *
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.
7  *
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.
12  *
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/>.
15  */
16 
17 import QtQuick 2.0
18 import Dash 0.1
19 
20 /*!
21  \brief Tool for introspecting Card properties.
22 
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.
25 
26  This component creates an invisible card filled with maximum mapped data and calculates
27  or measures card properties for this configuration.
28  */
29 
30 Item {
31  id: cardTool
32 
33  /*!
34  \brief Number of cards.
35  */
36  property int count
37 
38  /*!
39  \brief Width of the category view.
40  */
41  property real viewWidth
42 
43  /*!
44  \brief Scaling factor of selected Carousel item.
45  */
46  readonly property real carouselSelectedItemScaleFactor: 1.38 // XXX assuming 1.38 carousel scaling factor for cards
47 
48  /*!
49  \brief Template supplied for the category.
50  */
51  property var template
52 
53  /*!
54  \brief Component mapping supplied for the category.
55  */
56  property var components
57 
58  /*!
59  \brief The category layout for this card tool.
60  */
61  property string categoryLayout: {
62  var layout = template["category-layout"];
63 
64  // carousel fallback mode to grid
65  if (layout === "carousel" && count <= Math.ceil(carouselTool.realPathItemCount)) layout = "grid";
66  return layout;
67  }
68 
69  property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components);
70 
71  // FIXME: Saviq
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.
74  width: 0
75  height: 0
76  clip: true
77 
78  /*!
79  type:real \brief Width to be enforced on the card in this configuration.
80 
81  If undefined, should use implicit width of the actual card.
82  */
83  readonly property var cardWidth: {
84  switch (categoryLayout) {
85  case "grid":
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);
91  }
92  return units.gu(18.5);
93  case "carousel":
94  case "horizontal-list":
95  return carouselTool.minimumTileWidth;
96  case undefined:
97  case "organic-grid":
98  case "journal":
99  default:
100  return undefined;
101  }
102  }
103 
104  /*!
105  type:real \brief Height to be enforced on the card in this configuration.
106 
107  If undefined, should use implicit height of the actual card.
108  */
109  readonly property var cardHeight: {
110  switch (categoryLayout) {
111  case "journal":
112  if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
113  return units.gu(18.5);
114  case "grid":
115  case "horizontal-list":
116  return cardLoader.item ? cardLoader.item.implicitHeight : 0
117  case "carousel":
118  return cardWidth / (components ? components["art"]["aspect-ratio"] : 1)
119  case undefined:
120  case "organic-grid":
121  case "vertical-journal":
122  default:
123  return undefined;
124  }
125  }
126 
127  /*!
128  type:real \brief Height of the card's header.
129  */
130  readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
131  property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
132 
133  /*!
134  \brief Desired alignment of header components.
135  */
136  readonly property int headerAlignment: {
137  var subtitle = components["subtitle"];
138  var price = components["price"];
139  var summary = components["summary"];
140 
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"])
144 
145  var isOnlyTextComponent = !hasSubtitle && !hasPrice && !hasSummary;
146  if (!isOnlyTextComponent) return Text.AlignLeft;
147 
148  return (template["card-layout"] === "horizontal") ? Text.AlignLeft : Text.AlignHCenter;
149  }
150 
151  QtObject {
152  id: carouselTool
153 
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)));
159  }
160 
161  readonly property real pathItemCount: 4.8457 /// (848 / 175) reference values
162 
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);
167  }
168  }
169 
170  Item {
171  id: attributesModel
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"];
177  }
178  }
179  return 0;
180  }
181  property var model: []
182 
183  onNumOfAttributesChanged: {
184  model = []
185  for (var i = 0; i < numOfAttributes; i++) {
186  model.push( {"value":"text"+(i+1), "icon":"image://theme/ok" } );
187  }
188  }
189  }
190 
191  Loader {
192  id: cardLoader
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"),
197  "title": "—\n—",
198  "subtitle": "—",
199  "summary": "—\n—\n—\n—\n—",
200  "attributes": attributesModel.model
201  }
202  sourceComponent: cardTool.cardComponent
203  onLoaded: {
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; });
210  }
211  Connections {
212  target: cardLoader.item
213  onComponentsChanged: {
214  var data = {};
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];
222  }
223  }
224  cardLoader.item.cardData = data;
225  }
226  }
227  }
228 }