Merge lp:~aacid/unity8/filtergrid_bindingloop into lp:unity8

Proposed by Albert Astals Cid
Status: Superseded
Proposed branch: lp:~aacid/unity8/filtergrid_bindingloop
Merge into: lp:unity8
Diff against target: 887 lines (+328/-182)
13 files modified
cmake/modules/QmlTest.cmake (+16/-1)
qml/Components/FilterGrid.qml (+40/-23)
qml/Dash/Card.qml (+109/-89)
qml/Dash/CardCarousel.qml (+1/-1)
qml/Dash/CardFilterGrid.qml (+5/-10)
qml/Dash/CardHeader.qml (+42/-32)
qml/Dash/DashRenderer.qml (+1/-4)
qml/Dash/GenericScopeView.qml (+5/-10)
tests/qmltests/CMakeLists.txt (+1/-0)
tests/qmltests/Components/tst_FilterGrid.qml (+1/-1)
tests/qmltests/Dash/tst_Card.qml (+12/-10)
tests/qmltests/Dash/tst_CardBenchmark.qml (+94/-0)
tests/qmltests/Dash/tst_CardHeader.qml (+1/-1)
To merge this branch: bzr merge lp:~aacid/unity8/filtergrid_bindingloop
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+216145@code.launchpad.net

This proposal has been superseded by a proposal from 2014-04-16.

Commit message

Fix binding loop in FilterGrid height

To post a comment you must log in.
832. By Albert Astals Cid

A bit more of reog

833. By Albert Astals Cid

reog++

834. By Albert Astals Cid

reorg++

835. By Albert Astals Cid

don't need the id anymroe

836. By Albert Astals Cid

property rename

837. By Albert Astals Cid

Merge

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cmake/modules/QmlTest.cmake'
--- cmake/modules/QmlTest.cmake 2014-04-02 12:08:51 +0000
+++ cmake/modules/QmlTest.cmake 2014-04-16 15:47:25 +0000
@@ -58,7 +58,15 @@
5858
59endmacro(add_manual_qml_test)59endmacro(add_manual_qml_test)
6060
61macro(add_qml_benchmark SUBPATH COMPONENT_NAME ITERATIONS)
62 add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} ${ITERATIONS} ${ARGN})
63endmacro(add_qml_benchmark)
64
61macro(add_qml_test SUBPATH COMPONENT_NAME)65macro(add_qml_test SUBPATH COMPONENT_NAME)
66 add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} 0 ${ARGN})
67endmacro(add_qml_test)
68
69macro(add_qml_test_internal SUBPATH COMPONENT_NAME ITERATIONS)
62 set(options NO_ADD_TEST NO_TARGETS)70 set(options NO_ADD_TEST NO_TARGETS)
63 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)71 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)
6472
@@ -88,10 +96,17 @@
88 set(function_ARGS "")96 set(function_ARGS "")
89 endif()97 endif()
9098
99 if (${ITERATIONS} GREATER 0)
100 set(ITERATIONS_STRING "-iterations" ${ITERATIONS})
101 else()
102 set(ITERATIONS_STRING "")
103 endif()
104
91 set(qmltest_command105 set(qmltest_command
92 env ${qmltest_ENVIRONMENT}106 env ${qmltest_ENVIRONMENT}
93 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml107 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
94 ${qmltestrunner_imports}108 ${qmltestrunner_imports}
109 ${ITERATIONS_STRING}
95 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml110 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
96 -o -,txt111 -o -,txt
97 ${function_ARGS}112 ${function_ARGS}
@@ -114,7 +129,7 @@
114 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})129 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})
115 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)130 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)
116 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})131 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
117endmacro(add_qml_test)132endmacro(add_qml_test_internal)
118133
119macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)134macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
120 set(testCommand135 set(testCommand
121136
=== modified file 'qml/Components/FilterGrid.qml'
--- qml/Components/FilterGrid.qml 2014-04-08 13:32:59 +0000
+++ qml/Components/FilterGrid.qml 2014-04-16 15:47:25 +0000
@@ -28,10 +28,13 @@
28Item {28Item {
29 id: root29 id: root
3030
31 /* If true, the number of elements displayed will be limited by collapsedRowCount.31 QtObject {
32 If false, all elements will be displayed, effectively looking the same as a regular32 id: d
33 ResponsiveGridView. */33 /* If true, the number of elements displayed will be limited by collapsedRowCount.
34 property bool filter: true34 If false, all elements will be displayed, effectively looking the same as a regular
35 ResponsiveGridView. Manipulate this property through setFilter */
36 property bool filter: true
37 }
3538
36 /* Whether, when collapsed, a button should be displayed enabling the user to expand39 /* Whether, when collapsed, a button should be displayed enabling the user to expand
37 the grid to its full size. */40 the grid to its full size. */
@@ -66,29 +69,35 @@
66 property alias highlightIndex: iconTileGrid.highlightIndex69 property alias highlightIndex: iconTileGrid.highlightIndex
67 readonly property alias currentItem: iconTileGrid.currentItem70 readonly property alias currentItem: iconTileGrid.currentItem
6871
69 height: !filterAnimation.running ? childrenRect.height : height72 height: filter ? root.collapsedHeight : root.uncollapsedHeight
70 clip: filterAnimation.running73 clip: filterAnimation.running
7174
72 NumberAnimation {75 Behavior on height {
73 property bool filterEndValue76 id: heightBehaviour
74 id: filterAnimation77 enabled: false
75 target: root78 NumberAnimation {
76 property: "height"79 id: filterAnimation
77 to: filterEndValue ? root.collapsedHeight : root.uncollapsedHeight80 // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation
78 // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation81 // otherwise since both animations can run at the same time you'll get
79 // otherwise since both animations can run at the same time you'll get82 // some visual weirdness.
80 // some visual weirdness.83 duration: 200
81 duration: 20084 easing.type: Easing.InOutQuad
82 easing.type: Easing.InOutQuad85 onRunningChanged: {
83 onStopped: {86 if (!running) {
84 root.filter = filterEndValue;87 limitModel.filter = d.filter;
88 }
89 heightBehaviour.enabled = false;
90 }
85 }91 }
86 }92 }
8793
88 function startFilterAnimation(filter) {94 function setFilter(filter, animate) {
89 filterAnimation.filterEndValue = filter95 heightBehaviour.enabled = animate;
90 filterAnimation.start();96 d.filter = filter;
91 }97 if (!animate || !filter) {
98 limitModel.filter = filter;
99 }
100 }
92101
93 ResponsiveGridView {102 ResponsiveGridView {
94 id: iconTileGrid103 id: iconTileGrid
@@ -104,8 +113,16 @@
104 verticalSpacing: units.gu(2)113 verticalSpacing: units.gu(2)
105114
106 model: LimitProxyModel {115 model: LimitProxyModel {
116 id: limitModel
117 // We do have another filter property here because
118 // we can't directly use filter from the root since we need to decouple
119 // the real filtering with the animation since the closing animation
120 // i.e. filter=false we still need to not be filtering until
121 // t he animation finishes otherwise we hide the items when the animation
122 // is still running
123 property bool filter: true
107 model: root.model124 model: root.model
108 limit: (filter && !filterAnimation.running) ? rowsWhenCollapsed * iconTileGrid.columns : -1125 limit: filter ? rowsWhenCollapsed * iconTileGrid.columns : -1
109 }126 }
110 }127 }
111}128}
112129
=== modified file 'qml/Dash/Card.qml'
--- qml/Dash/Card.qml 2014-04-01 22:56:38 +0000
+++ qml/Dash/Card.qml 2014-04-16 15:47:25 +0000
@@ -25,47 +25,53 @@
25 property var components25 property var components
26 property var cardData26 property var cardData
2727
28 property alias fontScale: header.fontScale28 property real fontScale: 1.0
29 property alias headerAlignment: header.headerAlignment29 property int headerAlignment: Text.AlignLeft
30 property alias headerHeight: header.height30 readonly property int headerHeight: headerLoader.item ? headerLoader.item.height : 0
31 readonly property alias title: header.title31 property int fixedHeaderHeight: -1
32 readonly property string title: cardData && cardData["title"] || ""
3233
33 property bool showHeader: true34 property bool showHeader: true
3435
35 implicitWidth: childrenRect.width36 implicitWidth: childrenRect.width
36 implicitHeight: summary.y + summary.height + (summary.text && background.visible ? units.gu(1) : 0)37 implicitHeight: summary.y + summary.height + (summary.text && backgroundLoader.active ? units.gu(1) : 0)
3738
38 UbuntuShape {39 Loader {
39 id: background40 id: backgroundLoader
40 objectName: "background"41 objectName: "backgroundLoader"
41 radius: "medium"42
42 visible: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"]43 readonly property bool artAndSummary: components["art"]["field"] && components["summary"] || false
43 || artAndSummary)44 active: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"] || artAndSummary)
44 property bool artAndSummary: components["art"]["field"] && components["summary"] || false
45 color: getColor(0) || "white"
46 gradientColor: getColor(1) || color
47 anchors.fill: parent45 anchors.fill: parent
48 image: backgroundImage.source ? backgroundImage : null46
4947 sourceComponent: UbuntuShape {
50 property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b48 objectName: "background"
5149 radius: "medium"
52 property Image backgroundImage: Image {50 color: getColor(0) || "white"
53 objectName: "backgroundImage"51 gradientColor: getColor(1) || color
54 source: {52 anchors.fill: parent
55 if (cardData && typeof cardData["background"] === "string") return cardData["background"]53 image: backgroundImage.source ? backgroundImage : null
56 else if (template && typeof template["card-background"] === "string") return template["card-background"]54
57 else return ""55 property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
58 }56
59 }57 property Image backgroundImage: Image {
6058 objectName: "backgroundImage"
61 function getColor(index) {59 source: {
62 if (cardData && typeof cardData["background"] === "object"60 if (cardData && typeof cardData["background"] === "string") return cardData["background"]
63 && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {61 else if (template && typeof template["card-background"] === "string") return template["card-background"]
64 return cardData["background"]["elements"][index];62 else return ""
65 } else if (template && typeof template["card-background"] === "object"63 }
66 && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {64 }
67 return template["card-background"]["elements"][index];65
68 } else return undefined;66 function getColor(index) {
67 if (cardData && typeof cardData["background"] === "object"
68 && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
69 return cardData["background"]["elements"][index];
70 } else if (template && typeof template["card-background"] === "object"
71 && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
72 return template["card-background"]["elements"][index];
73 } else return undefined;
74 }
69 }75 }
70 }76 }
7177
@@ -111,7 +117,7 @@
111 function updateWidthHeightBindings() {117 function updateWidthHeightBindings() {
112 if (isHorizontal) {118 if (isHorizontal) {
113 width = Qt.binding(function() { return height * artShape.aspect });119 width = Qt.binding(function() { return height * artShape.aspect });
114 height = Qt.binding(function() { return header.height });120 height = Qt.binding(function() { return root.headerHeight });
115 } else {121 } else {
116 width = Qt.binding(function() { return root.width });122 width = Qt.binding(function() { return root.width });
117 height = Qt.binding(function() { return width / artShape.aspect });123 height = Qt.binding(function() { return width / artShape.aspect });
@@ -120,53 +126,58 @@
120 }126 }
121 }127 }
122128
123 ShaderEffect {129 Loader {
124 id: overlay130 id: overlayLoader
125 anchors {131 anchors {
126 left: artShape.left132 left: artShape.left
127 right: artShape.right133 right: artShape.right
128 bottom: artShape.bottom134 bottom: artShape.bottom
129 }135 }
130136 active: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
131 height: header.height137
132 opacity: header.opacity * 0.6138 sourceComponent: ShaderEffect {
133 visible: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false139 id: overlay
134140
135 property var source: ShaderEffectSource {141 height: headerLoader.item ? headerLoader.item.height : 0
136 id: shaderSource142 opacity: headerLoader.item ? headerLoader.item.opacity * 0.6 : 0
137 sourceItem: artShape143
138 onVisibleChanged: if (visible) scheduleUpdate()144 property var source: ShaderEffectSource {
139 live: false145 id: shaderSource
140 sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)146 sourceItem: artShape
147 onVisibleChanged: if (visible) scheduleUpdate()
148 live: false
149 sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
150 }
151
152 vertexShader: "
153 uniform highp mat4 qt_Matrix;
154 attribute highp vec4 qt_Vertex;
155 attribute highp vec2 qt_MultiTexCoord0;
156 varying highp vec2 coord;
157 void main() {
158 coord = qt_MultiTexCoord0;
159 gl_Position = qt_Matrix * qt_Vertex;
160 }"
161
162 fragmentShader: "
163 varying highp vec2 coord;
164 uniform sampler2D source;
165 uniform lowp float qt_Opacity;
166 void main() {
167 lowp vec4 tex = texture2D(source, coord);
168 gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
169 }"
141 }170 }
142
143 vertexShader: "
144 uniform highp mat4 qt_Matrix;
145 attribute highp vec4 qt_Vertex;
146 attribute highp vec2 qt_MultiTexCoord0;
147 varying highp vec2 coord;
148 void main() {
149 coord = qt_MultiTexCoord0;
150 gl_Position = qt_Matrix * qt_Vertex;
151 }"
152
153 fragmentShader: "
154 varying highp vec2 coord;
155 uniform sampler2D source;
156 uniform lowp float qt_Opacity;
157 void main() {
158 lowp vec4 tex = texture2D(source, coord);
159 gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
160 }"
161 }171 }
162172
163 CardHeader {173 Loader {
164 id: header174 id: headerLoader
165 objectName: "cardHeader"175 objectName: "cardHeaderLoader"
176
166 anchors {177 anchors {
167 top: {178 top: {
168 if (template) {179 if (template) {
169 if (template["overlay"]) return overlay.top;180 if (template["overlay"]) return overlayLoader.top;
170 if (template["card-layout"] === "horizontal") return artShape.top;181 if (template["card-layout"] === "horizontal") return artShape.top;
171 }182 }
172 return artShape.bottom;183 return artShape.bottom;
@@ -179,29 +190,38 @@
179 }190 }
180 right: parent.right191 right: parent.right
181 }192 }
182193 active: cardData && cardData["title"] || cardData && cardData["mascot"] || false
183 mascot: cardData && cardData["mascot"] || ""194
184 title: cardData && cardData["title"] || ""195 sourceComponent: CardHeader {
185 subtitle: cardData && cardData["subtitle"] || ""196 id: header
186197 objectName: "cardHeader"
187 titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal198
188199 mascot: cardData && cardData["mascot"] || ""
189 opacity: showHeader ? 1 : 0200 title: root.title
190 inOverlay: root.template && root.template["overlay"] === true201 subtitle: cardData && cardData["subtitle"] || ""
191 fontColor: inOverlay ? "white" : summary.color202
192 useMascotShape: !background.visible && !inOverlay203 titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
193204
194 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }205 opacity: showHeader ? 1 : 0
206 inOverlay: root.template && root.template["overlay"] === true
207 fontColor: inOverlay ? "white" : summary.color
208 useMascotShape: !backgroundLoader.active && !inOverlay
209 headerAlignment: root.headerAlignment
210 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight
211 fontScale: root.fontScale
212
213 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
214 }
195 }215 }
196216
197 Label {217 Label {
198 id: summary218 id: summary
199 objectName: "summaryLabel"219 objectName: "summaryLabel"
200 anchors {220 anchors {
201 top: header.visible ? header.bottom : artShape.bottom221 top: headerLoader.active ? headerLoader.bottom : artShape.bottom
202 left: parent.left222 left: parent.left
203 right: parent.right223 right: parent.right
204 margins: background.visible ? units.gu(1) : 0224 margins: backgroundLoader.active ? units.gu(1) : 0
205 topMargin: 0225 topMargin: 0
206 }226 }
207 wrapMode: Text.Wrap227 wrapMode: Text.Wrap
@@ -211,6 +231,6 @@
211 height: text ? implicitHeight : 0231 height: text ? implicitHeight : 0
212 fontSize: "small"232 fontSize: "small"
213 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.233 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
214 color: background.visible && background.luminance < 0.7 ? "white" : "grey"234 color: backgroundLoader.active && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"
215 }235 }
216}236}
217237
=== modified file 'qml/Dash/CardCarousel.qml'
--- qml/Dash/CardCarousel.qml 2014-03-17 10:38:03 +0000
+++ qml/Dash/CardCarousel.qml 2014-04-16 15:47:25 +0000
@@ -52,7 +52,7 @@
52 itemComponent: Card {52 itemComponent: Card {
53 id: card53 id: card
54 objectName: "carouselDelegate" + index54 objectName: "carouselDelegate" + index
55 headerHeight: carousel.headerHeight55 fixedHeaderHeight: carousel.headerHeight
56 cardData: model56 cardData: model
57 template: cardTool.template57 template: cardTool.template
58 components: cardTool.components58 components: cardTool.components
5959
=== modified file 'qml/Dash/CardFilterGrid.qml'
--- qml/Dash/CardFilterGrid.qml 2014-04-08 13:32:59 +0000
+++ qml/Dash/CardFilterGrid.qml 2014-04-16 15:47:25 +0000
@@ -29,8 +29,8 @@
29 currentItem: filterGrid.currentItem29 currentItem: filterGrid.currentItem
30 height: filterGrid.height30 height: filterGrid.height
3131
32 function startFilterAnimation(filter) {32 function setFilter(filter, animate) {
33 filterGrid.startFilterAnimation(filter)33 filterGrid.setFilter(filter, animate)
34 }34 }
3535
36 FilterGrid {36 FilterGrid {
@@ -41,18 +41,18 @@
41 delegateHeight: cardTool.cardHeight41 delegateHeight: cardTool.cardHeight
42 verticalSpacing: genericFilterGrid.verticalSpacing42 verticalSpacing: genericFilterGrid.verticalSpacing
43 model: genericFilterGrid.model43 model: genericFilterGrid.model
44 filter: genericFilterGrid.filter
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)44 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin45 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd46 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
48 delegate: Item {47 delegate: Loader {
48 asynchronous: true
49 width: filterGrid.cellWidth49 width: filterGrid.cellWidth
50 height: filterGrid.cellHeight50 height: filterGrid.cellHeight
51 Card {51 Card {
52 id: card52 id: card
53 width: cardTool.cardWidth53 width: cardTool.cardWidth
54 height: cardTool.cardHeight54 height: cardTool.cardHeight
55 headerHeight: cardTool.headerHeight55 fixedHeaderHeight: cardTool.headerHeight
56 anchors.horizontalCenter: parent.horizontalCenter56 anchors.horizontalCenter: parent.horizontalCenter
57 objectName: "delegate" + index57 objectName: "delegate" + index
58 cardData: model58 cardData: model
@@ -65,10 +65,5 @@
65 onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)65 onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)
66 }66 }
67 }67 }
68
69 onFilterChanged: {
70 genericFilterGrid.filter = filter
71 filter = Qt.binding(function() { return genericFilterGrid.filter })
72 }
73 }68 }
74}69}
7570
=== modified file 'qml/Dash/CardHeader.qml'
--- qml/Dash/CardHeader.qml 2014-03-17 11:42:38 +0000
+++ qml/Dash/CardHeader.qml 2014-04-16 15:47:25 +0000
@@ -19,9 +19,9 @@
1919
20Item {20Item {
21 id: root21 id: root
22 property alias mascot: mascotImage.source22 property url mascot: ""
23 property alias title: titleLabel.text23 property alias title: titleLabel.text
24 property alias subtitle: subtitleLabel.text24 property var subtitle
2525
26 property alias titleWeight: titleLabel.font.weight26 property alias titleWeight: titleLabel.font.weight
27 property alias titleSize: titleLabel.fontSize27 property alias titleSize: titleLabel.fontSize
@@ -35,8 +35,8 @@
35 property bool useMascotShape: true35 property bool useMascotShape: true
36 property color fontColor: Theme.palette.selected.backgroundText36 property color fontColor: Theme.palette.selected.backgroundText
3737
38 visible: mascotImage.status === Image.Ready || title38 visible: mascot != "" || title
39 height: row.height > 0 ? row.height + row.margins * 2 : 039 implicitHeight: row.height > 0 ? row.height + row.margins * 2 : 0
4040
41 Row {41 Row {
42 id: row42 id: row
@@ -44,7 +44,7 @@
4444
45 property real margins: units.gu(1)45 property real margins: units.gu(1)
4646
47 spacing: mascotShape.visible || mascotImage.visible || inOverlay ? margins : 047 spacing: mascotShapeLoader.active || mascotImageLoader.active || inOverlay ? margins : 0
48 anchors {48 anchors {
49 top: parent.top; left: parent.left; right: parent.right49 top: parent.top; left: parent.left; right: parent.right
50 margins: margins50 margins: margins
@@ -52,33 +52,40 @@
52 rightMargin: spacing52 rightMargin: spacing
53 }53 }
5454
55 UbuntuShape {55 Loader {
56 id: mascotShape56 id: mascotShapeLoader
57 objectName: "mascotShape"57 objectName: "mascotShapeLoader"
5858
59 active: useMascotShape && mascotImageLoader.item && mascotImageLoader.item.status === Image.Ready
60 visible: active
61 anchors.verticalCenter: parent.verticalCenter
59 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.62 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
60 width: units.gu(6)63 width: units.gu(6)
61 height: units.gu(5.625)64 height: units.gu(5.625)
62 anchors.verticalCenter: parent.verticalCenter
63 visible: useMascotShape && image && image.status === Image.Ready
64 readonly property int maxSize: Math.max(width, height) * 465 readonly property int maxSize: Math.max(width, height) * 4
6566
66 image: useMascotShape ? mascotImage : null67 sourceComponent: UbuntuShape {
68 image: mascotImageLoader.item
69 }
67 }70 }
6871
69 Image {72 Loader {
70 id: mascotImage73 id: mascotImageLoader
71 objectName: "mascotImage"74 active: root.mascot != ""
7275 visible: active && !useMascotShape && item.status === Image.Ready
73 width: source ? mascotShape.width : 0
74 height: mascotShape.height
75 anchors.verticalCenter: parent.verticalCenter76 anchors.verticalCenter: parent.verticalCenter
76 visible: !useMascotShape && status === Image.Ready77 sourceComponent: Image {
7778 objectName: "mascotImage"
78 sourceSize { width: mascotShape.maxSize; height: mascotShape.maxSize }79
79 fillMode: Image.PreserveAspectCrop80 source: root.mascot
80 horizontalAlignment: Image.AlignHCenter81 width: source ? mascotShapeLoader.width : 0
81 verticalAlignment: Image.AlignVCenter82 height: mascotShapeLoader.height
83
84 sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize }
85 fillMode: Image.PreserveAspectCrop
86 horizontalAlignment: Image.AlignHCenter
87 verticalAlignment: Image.AlignVCenter
88 }
82 }89 }
8390
84 Column {91 Column {
@@ -100,16 +107,19 @@
100 color: fontColor107 color: fontColor
101 }108 }
102109
103 Label {110 Loader {
104 id: subtitleLabel111 active: titleLabel.text && root.subtitle
105 objectName: "subtitleLabel"
106 anchors { left: parent.left; right: parent.right }112 anchors { left: parent.left; right: parent.right }
107 elide: Text.ElideRight113 sourceComponent: Label {
108 fontSize: "small"114 id: subtitleLabel
109 font.weight: Font.Light115 objectName: "subtitleLabel"
110 visible: titleLabel.text && text116 elide: Text.ElideRight
111 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)117 fontSize: "small"
112 color: fontColor118 font.weight: Font.Light
119 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
120 color: fontColor
121 text: root.subtitle
122 }
113 }123 }
114 }124 }
115 }125 }
116126
=== modified file 'qml/Dash/DashRenderer.qml'
--- qml/Dash/DashRenderer.qml 2014-04-08 13:32:59 +0000
+++ qml/Dash/DashRenderer.qml 2014-04-16 15:47:25 +0000
@@ -20,9 +20,6 @@
20 // Can the item be expanded?20 // Can the item be expanded?
21 property bool expandable: false21 property bool expandable: false
2222
23 // In case it can be expanded, should we filter it
24 property bool filter: true
25
26 property int collapsedHeight: height23 property int collapsedHeight: height
2724
28 property int margins: 025 property int margins: 0
@@ -58,6 +55,6 @@
58 /// @param itemY is y of the held delegate55 /// @param itemY is y of the held delegate
59 signal pressAndHold(int index, real itemY)56 signal pressAndHold(int index, real itemY)
6057
61 function startFilterAnimation(filter) {58 function setFilter(filter, animate) {
62 }59 }
63}60}
6461
=== modified file 'qml/Dash/GenericScopeView.qml'
--- qml/Dash/GenericScopeView.qml 2014-04-08 13:32:59 +0000
+++ qml/Dash/GenericScopeView.qml 2014-04-16 15:47:25 +0000
@@ -121,7 +121,7 @@
121 showDivider: false121 showDivider: false
122122
123 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false123 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
124 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true124 readonly property bool filtered: categoryView.expandedCategoryId != categoryId
125 readonly property string category: categoryId125 readonly property string category: categoryId
126 readonly property var item: rendererLoader.item126 readonly property var item: rendererLoader.item
127127
@@ -167,9 +167,7 @@
167 item.objectName = Qt.binding(function() { return categoryId })167 item.objectName = Qt.binding(function() { return categoryId })
168 if (item.expandable) {168 if (item.expandable) {
169 var shouldFilter = categoryId != categoryView.expandedCategoryId;169 var shouldFilter = categoryId != categoryView.expandedCategoryId;
170 if (shouldFilter != item.filter) {170 item.setFilter(shouldFilter, false /*animate*/);
171 item.filter = shouldFilter;
172 }
173 }171 }
174 updateDelegateCreationRange();172 updateDelegateCreationRange();
175 item.cardTool = cardTool;173 item.cardTool = cardTool;
@@ -218,11 +216,8 @@
218 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;216 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
219 var growingVisible = !shouldFilter && y + height < categoryView.height;217 var growingVisible = !shouldFilter && y + height < categoryView.height;
220 if (!previewListView.open || !shouldFilter) {218 if (!previewListView.open || !shouldFilter) {
221 if (shrinkingVisible || growingVisible) {219 var animate = shrinkingVisible || growingVisible;
222 item.startFilterAnimation(shouldFilter)220 item.setFilter(shouldFilter, animate)
223 } else {
224 item.filter = shouldFilter;
225 }
226 if (!shouldFilter && !previewListView.open) {221 if (!shouldFilter && !previewListView.open) {
227 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);222 categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
228 }223 }
@@ -241,7 +236,7 @@
241 // to the stable position and delete/create items without any reason236 // to the stable position and delete/create items without any reason
242 if (categoryView.contentY < categoryView.originY) {237 if (categoryView.contentY < categoryView.originY) {
243 return;238 return;
244 } else if (categoryView.contentY + categoryView.height > categoryView.contentHeight) {239 } else if (categoryView.contentHeight > categoryView.height && categoryView.contentY + categoryView.height > categoryView.contentHeight) {
245 return;240 return;
246 }241 }
247242
248243
=== modified file 'tests/qmltests/CMakeLists.txt'
--- tests/qmltests/CMakeLists.txt 2014-04-03 10:38:06 +0000
+++ tests/qmltests/CMakeLists.txt 2014-04-16 15:47:25 +0000
@@ -36,6 +36,7 @@
36add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})36add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
37add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})37add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
38add_qml_test(Dash Card)38add_qml_test(Dash Card)
39add_qml_benchmark(Dash CardBenchmark 1000)
39add_qml_test(Dash CardHeader)40add_qml_test(Dash CardHeader)
40add_qml_test(Dash CardTool)41add_qml_test(Dash CardTool)
41add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})42add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4243
=== modified file 'tests/qmltests/Components/tst_FilterGrid.qml'
--- tests/qmltests/Components/tst_FilterGrid.qml 2014-01-29 13:37:23 +0000
+++ tests/qmltests/Components/tst_FilterGrid.qml 2014-04-16 15:47:25 +0000
@@ -50,6 +50,7 @@
50 CheckBox {50 CheckBox {
51 id: filterCheckBox51 id: filterCheckBox
52 checked: true52 checked: true
53 onCheckedChanged: filterGrid.setFilter(checked, false /*animate*/)
53 }54 }
54 }55 }
55 }56 }
@@ -99,7 +100,6 @@
99 maximumNumberOfColumns: 3100 maximumNumberOfColumns: 3
100 collapsedRowCount:101 collapsedRowCount:
101 collapsedRowCountSelector.values[collapsedRowCountSelector.selectedIndex]102 collapsedRowCountSelector.values[collapsedRowCountSelector.selectedIndex]
102 filter: filterCheckBox.checked
103 minimumHorizontalSpacing: units.gu(1)103 minimumHorizontalSpacing: units.gu(1)
104 delegateWidth: units.gu(6)104 delegateWidth: units.gu(6)
105 delegateHeight: units.gu(6)105 delegateHeight: units.gu(6)
106106
=== modified file 'tests/qmltests/Dash/tst_Card.qml'
--- tests/qmltests/Dash/tst_Card.qml 2014-03-12 10:55:37 +0000
+++ tests/qmltests/Dash/tst_Card.qml 2014-04-16 15:47:25 +0000
@@ -182,11 +182,13 @@
182 when: windowShown182 when: windowShown
183183
184 property Item header: findChild(card, "cardHeader")184 property Item header: findChild(card, "cardHeader")
185 property Item headerLoader: findChild(card, "cardHeaderLoader")
185 property Item title: findChild(header, "titleLabel")186 property Item title: findChild(header, "titleLabel")
186 property Item art: findChild(card, "artShape")187 property Item art: findChild(card, "artShape")
187 property Item artImage: findChild(card, "artImage")188 property Item artImage: findChild(card, "artImage")
188 property Item summary: findChild(card, "summaryLabel")189 property Item summary: findChild(card, "summaryLabel")
189 property Item background: findChild(card, "background")190 property Item background: findChild(card, "background")
191 property Item backgroundLoader: findChild(card, "backgroundLoader")
190 property Item backgroundImage: findChild(card, "backgroundImage")192 property Item backgroundImage: findChild(card, "backgroundImage")
191193
192 function initTestCase() {194 function initTestCase() {
@@ -244,8 +246,8 @@
244 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },246 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
245 { tag: "Horizontal", width: units.gu(38), index: 5 },247 { tag: "Horizontal", width: units.gu(38), index: 5 },
246 // Make sure card ends with header when there's no summary248 // Make sure card ends with header when there's no summary
247 { tag: "NoSummary", height: function() { return header.y + header.height }, index: 6 },249 { tag: "NoSummary", height: function() { return headerLoader.y + headerLoader.height }, index: 6 },
248 { tag: "HorizontalNoSummary", height: function() { return header.height }, card_layout: "horizontal", index: 6 },250 { tag: "HorizontalNoSummary", height: function() { return headerLoader.height }, card_layout: "horizontal", index: 6 },
249 ]251 ]
250 }252 }
251253
@@ -288,7 +290,7 @@
288 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },290 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
289 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },291 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
290 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },292 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
291 { tag: "HorizontalWidth", width: function() { return header.x }, index: 5 },293 { tag: "HorizontalWidth", width: function() { return headerLoader.x }, index: 5 },
292 ]294 ]
293 }295 }
294296
@@ -332,7 +334,7 @@
332 function test_art_layout(data) {334 function test_art_layout(data) {
333 selector.selectedIndex = data.index;335 selector.selectedIndex = data.index;
334336
335 tryCompare(testCase.header, "x", data.left());337 tryCompare(testCase.headerLoader, "x", data.left());
336 }338 }
337339
338 function test_header_layout_data() {340 function test_header_layout_data() {
@@ -349,13 +351,13 @@
349 function test_header_layout(data) {351 function test_header_layout(data) {
350 selector.selectedIndex = data.index;352 selector.selectedIndex = data.index;
351353
352 tryCompareFunction(function() { return testCase.header.y === data.top() }, true);354 tryCompareFunction(function() { return testCase.headerLoader.y === data.top() }, true);
353 tryCompareFunction(function() { return testCase.header.x === data.left() }, true);355 tryCompareFunction(function() { return testCase.headerLoader.x === data.left() }, true);
354 }356 }
355357
356 function test_summary_layout_data() {358 function test_summary_layout_data() {
357 return [359 return [
358 { tag: "With header", top: function() { return header.y + header.height }, index: 0 },360 { tag: "With header", top: function() { return headerLoader.y + headerLoader.height }, index: 0 },
359 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },361 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
360 ]362 ]
361 }363 }
@@ -400,7 +402,7 @@
400402
401 waitForRendering(card);403 waitForRendering(card);
402404
403 tryCompare(background, "visible", data.visible);405 tryCompare(backgroundLoader, "active", data.visible);
404406
405 if (data.hasOwnProperty("color")) {407 if (data.hasOwnProperty("color")) {
406 tryCompare(background, "color", data.color);408 tryCompare(background, "color", data.color);
@@ -467,13 +469,13 @@
467 function test_mascotShape(data) {469 function test_mascotShape(data) {
468 selector.selectedIndex = data.index;470 selector.selectedIndex = data.index;
469471
470 var shape = findChild(card, "mascotShape");472 var shape = findChild(card, "mascotShapeLoader");
471 var image = findChild(card, "mascotImage");473 var image = findChild(card, "mascotImage");
472474
473 verify(shape, "Could not find shape.");475 verify(shape, "Could not find shape.");
474 verify(image, "Could not find image.");476 verify(image, "Could not find image.");
475477
476 tryCompare(shape, "visible", data.shape);478 tryCompare(shape, "active", data.shape);
477 tryCompare(image, "visible", !data.shape);479 tryCompare(image, "visible", !data.shape);
478 }480 }
479 }481 }
480482
=== added file 'tests/qmltests/Dash/tst_CardBenchmark.qml'
--- tests/qmltests/Dash/tst_CardBenchmark.qml 1970-01-01 00:00:00 +0000
+++ tests/qmltests/Dash/tst_CardBenchmark.qml 2014-04-16 15:47:25 +0000
@@ -0,0 +1,94 @@
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
17import QtQuick 2.0
18import QtTest 1.0
19import Ubuntu.Components 0.1
20import Unity.Test 0.1 as UT
21import "../../../qml/Dash"
22import "CardHelpers.js" as Helpers
23
24Rectangle {
25 id: root
26 width: units.gu(80)
27 height: units.gu(72)
28 color: "#88FFFFFF"
29
30 property string cardData: '
31 {
32 "art": "../../tests/qmltests/Dash/artwork/music-player-design.png",
33 "mascot": "../../tests/qmltests/Dash/artwork/avatar.png",
34 "title": "foo",
35 "subtitle": "bar",
36 "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
37 }'
38
39 property string currentModel: '{}'
40 property string cardTitleArtSubtitleMascotSummaryModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot", "summary": "summary" } }'
41 property string cardTitleArtSubtitleMascotModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot" } }'
42 property string cardTitleArtSubtitleModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle" } }'
43 property string cardTitleArtModel: '{ "components": { "title": "title", "art": "art" } }'
44 property string cardArtModel: '{ "components": { "art": "art" } }'
45 property string cardTitleModel: '{ "components": { "title": "title" } }'
46
47 CardTool {
48 id: cardTool
49 template: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['template'];
50 components: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['components'];
51 viewWidth: units.gu(48)
52 }
53
54 Repeater {
55 id: cardRepeater
56 model: 0
57 Card {
58 width: cardTool.cardWidth || implicitWidth
59 height: cardTool.cardHeight || implicitHeight
60
61 template: cardTool.template
62 components: cardTool.components
63 cardData: Helpers.mapData(root.cardData, components)
64 }
65 }
66
67 UT.UnityTestCase {
68 id: testCase
69 name: "CardBenchmark"
70
71 when: windowShown
72
73 function init() {
74 wait(1);
75 }
76
77 function benchmark_time_data() {
78 return [
79 { tag: "cardTitleArtSubtitleMascotSummaryModel", model: cardTitleArtSubtitleMascotSummaryModel },
80 { tag: "cardTitleArtSubtitleMascotModel", model: cardTitleArtSubtitleMascotModel },
81 { tag: "cardTitleArtSubtitleModel", model: cardTitleArtSubtitleModel },
82 { tag: "cardTitleArtModel", model: cardTitleArtModel },
83 { tag: "cardArtModel", model: cardArtModel },
84 { tag: "cardTitleModel", model: cardTitleModel },
85 ];
86 }
87
88 function benchmark_time(data) {
89 currentModel = data.model;
90 cardRepeater.model = 1;
91 cardRepeater.model = 0;
92 }
93 }
94}
095
=== modified file 'tests/qmltests/Dash/tst_CardHeader.qml'
--- tests/qmltests/Dash/tst_CardHeader.qml 2014-03-17 11:44:05 +0000
+++ tests/qmltests/Dash/tst_CardHeader.qml 2014-04-16 15:47:25 +0000
@@ -43,7 +43,7 @@
4343
44 when: windowShown44 when: windowShown
4545
46 property Item mascot: findChild(cardHeader, "mascotShape")46 property Item mascot: findChild(cardHeader, "mascotShapeLoader")
47 property Item titleLabel: findChild(cardHeader, "titleLabel")47 property Item titleLabel: findChild(cardHeader, "titleLabel")
48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")

Subscribers

People subscribed via source and target branches