Merge lp:~tpeeters/ubuntu-ui-toolkit/60-scectionScrolling into lp:ubuntu-ui-toolkit/staging

Proposed by Tim Peeters
Status: Merged
Approved by: Cris Dywan
Approved revision: 1798
Merged at revision: 1870
Proposed branch: lp:~tpeeters/ubuntu-ui-toolkit/60-scectionScrolling
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 1299 lines (+717/-150)
15 files modified
examples/ubuntu-ui-toolkit-gallery/PageHeaders.qml (+27/-0)
examples/ubuntu-ui-toolkit-gallery/Sections.qml (+62/-14)
src/Ubuntu/Components/1.3/Sections.qml (+0/-4)
src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHead.qml (+2/-3)
src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHeadStyle.qml (+122/-0)
src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml (+307/-36)
src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro (+1/-0)
src/Ubuntu/Components/Themes/Ambiance/qmldir (+1/-0)
tests/Gallery/gallery (+0/-6)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py (+11/-12)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml (+36/-4)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py (+25/-1)
tests/unit_x11/tst_components/tst_pagehead_sections.qml (+1/-1)
tests/unit_x11/tst_components/tst_pagehead_sections_bug1511839.qml (+1/-1)
tests/unit_x11/tst_components/tst_sections.qml (+121/-68)
To merge this branch: bzr merge lp:~tpeeters/ubuntu-ui-toolkit/60-scectionScrolling
Reviewer Review Type Date Requested Status
ubuntu-sdk-build-bot continuous-integration Approve
Cris Dywan Approve
PS Jenkins bot continuous-integration Pending
Review via email: mp+286330@code.launchpad.net

Commit message

Sections scrolling and keyboard navigation.

Description of the change

This branch disables focus handling for the Sections. We first need to land this MR so we can deal with the arrow keys properly: https://code.launchpad.net/~zsombi/ubuntu-ui-toolkit/list_item_focus/+merge/282671

To post a comment you must log in.
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

Feedback from Jamie:

- We need to change the margins on the left (and right) of the sections to 2gu.
- The gradient should be 2gu as well.
  . Can we adjust the height of the gradient so that it doesn't cover the underlines on each of the sections
  . We need to adjust the width of the gradient so that it's more obvious, we can barely see it. You'll need a spec for this…
  . Need to align the chevron on the overflow so that it aligns with the section labels
- One other thing. When you select a section it jumps to the centre of the screen, this feels a wee bit odd as you quickly lose a sense of where you are in the navigation. Can you lose this functionality please.
  . We'd suggest that the sections only shift if one is partially visible on the left or right edges and only enough so that you can display the full section.

Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

(Shift)Tab doesn't consistently switch between sections or from/ to sections - which is hard to tell in the first place as there's no focus ring - this branch was going to include that, which I asked to clarify before, but it doesn't.

Also, question, should the scroll arrows reveal instantly with no animation? It seems odd to me, but it probably is intentional, so just double-checking. UX is perfectly usable from my testing.

review: Needs Information
Revision history for this message
Tim Peeters (tpeeters) wrote :

This branch adds keyboard navigation, as it was in the prototype, with the left and right arrow keys. I will check with Jamie if that is the correct keyboard navigation. I will also ask the reveal arrow question.

Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

I think I covered all these, except the width of the gradient (for which you say I need a spec) it is not clear what you mean.

> Feedback from Jamie:
>
> - We need to change the margins on the left (and right) of the sections to
> 2gu.
> - The gradient should be 2gu as well.
> . Can we adjust the height of the gradient so that it doesn't cover the
> underlines on each of the sections
> . We need to adjust the width of the gradient so that it's more obvious, we
> can barely see it. You'll need a spec for this…
> . Need to align the chevron on the overflow so that it aligns with the
> section labels
> - One other thing. When you select a section it jumps to the centre of the
> screen, this feels a wee bit odd as you quickly lose a sense of where you are
> in the navigation. Can you lose this functionality please.
> . We'd suggest that the sections only shift if one is partially visible on
> the left or right edges and only enough so that you can display the full
> section.

Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jamie Young (jamiedawsonyoung) wrote :

Hi Christian & Tim, to answer your questions…

You should be able to tab between the sections (says Femma).

There's no focus ring on a section as they work more like view switchers (in a similar way to a list view). Please let us know if you need clarification on this.

Scroll arrows should appear with a short animation. I would use the "Fast" speed from the sdk.

Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Femma (femma) wrote :

Hi Christian & Tim,

We had a discussion and after some investigation the solution is as follows:
-When in the sections, use the arrow key to move between the sections.
-The section will have a focus ring around it and a select highlight.
-The views should switch when focused on a tab (without having to hit space or enter to activate)

Please let me know if you need further clarification.

> Hi Christian & Tim, to answer your questions…
>
> You should be able to tab between the sections (says Femma).
>
> There's no focus ring on a section as they work more like view switchers (in a
> similar way to a list view). Please let us know if you need clarification on
> this.
>
> Scroll arrows should appear with a short animation. I would use the "Fast"
> speed from the sdk.

Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
1796. By Tim Peeters

link bug

Revision history for this message
Cris Dywan (kalikiana) wrote :

+++ src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml 2016-02-25 16:54:54 +0000
+// FocusScope { }

Please lose that line.

=== added file 'tests/Gallery/gallery'
=== removed file 'tests/Gallery/gallery'

This looks a bit suspicious...

review: Needs Fixing
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

> +++ src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml 2016-02-25
> 16:54:54 +0000
> +// FocusScope { }
>
> Please lose that line.

done.

>
> === added file 'tests/Gallery/gallery'
> === removed file 'tests/Gallery/gallery'
>
> This looks a bit suspicious...

Right. I lost the file with a sync with another branch and I added it back again, which causes this message. The files are the same but I cannot convince bazaar not to show it in the diff.

1797. By Tim Peeters

sync staging

1798. By Tim Peeters

clean rogue // FocusScope { }

Revision history for this message
Cris Dywan (kalikiana) wrote :

Thanks!

review: Approve
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/ubuntu-ui-toolkit-gallery/PageHeaders.qml'
2--- examples/ubuntu-ui-toolkit-gallery/PageHeaders.qml 2016-01-13 16:07:58 +0000
3+++ examples/ubuntu-ui-toolkit-gallery/PageHeaders.qml 2016-02-26 10:16:56 +0000
4@@ -44,8 +44,35 @@
5 iconName: "edit"
6 text: "Edit"
7 onTriggered: page.header = editHeader
8+ },
9+ Action {
10+ iconName: standardHeader.extension === sections
11+ ? "media-playback-stop"
12+ : "filters"
13+ text: "Sections"
14+ onTriggered: {
15+ if (standardHeader.extension) {
16+ standardHeader.extension = null;
17+ } else {
18+ standardHeader.extension = sections;
19+ }
20+ }
21 }
22 ]
23+
24+ Sections {
25+ id: sections
26+ visible: standardHeader.extension === sections
27+ anchors {
28+ left: parent.left
29+ right: parent.right
30+ bottom: parent.bottom
31+ }
32+ model: ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
33+ "ten", "eleven", "twelve", "thirteen"]
34+ }
35+
36+
37 }
38
39 PageHeader {
40
41=== modified file 'examples/ubuntu-ui-toolkit-gallery/Sections.qml'
42--- examples/ubuntu-ui-toolkit-gallery/Sections.qml 2015-10-23 14:46:16 +0000
43+++ examples/ubuntu-ui-toolkit-gallery/Sections.qml 2016-02-26 10:16:56 +0000
44@@ -22,10 +22,39 @@
45 id: sectionsTemplate
46
47 header: PageHeader {
48+ id: h
49 title: sectionsTemplate.title
50- sections.model: ["first", "second", "third"]
51+ extension: Sections {
52+ anchors {
53+ left: parent.left
54+ right: parent.right
55+ bottom: parent.bottom
56+ }
57+ model: h.showManySections ? sectionsTemplate.manyActions
58+ : sectionsTemplate.fewActions
59+ }
60+ property bool showManySections: false
61+ trailingActionBar.actions: [
62+ Action {
63+ iconName: h.showManySections ? "view-collapse" : "view-expand"
64+ text: h.showManySections ? "less" : "more"
65+ onTriggered: h.showManySections = !h.showManySections;
66+ }
67+ ]
68 }
69
70+ property list<Action> fewActions: [
71+ Action { text: "One" },
72+ Action { text: "Two" },
73+ Action { text: "Three" }
74+ ]
75+
76+ property var manyActions: [
77+ "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
78+ "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
79+ "sixteen", "seventeen", "eighteen", "nineteen", "twenty"
80+ ]
81+
82 TemplateSection {
83 title: "Sections"
84 className: "Sections"
85@@ -34,19 +63,38 @@
86 title: i18n.tr("Enabled")
87
88 Sections {
89- actions: [
90- Action { text: "one" },
91- Action { text: "two" },
92- Action { text: "three" }
93- ]
94- }
95- }
96- TemplateRow {
97- title: i18n.tr("Disabled")
98-
99- Sections {
100- model: ["one", "two", "three"]
101- enabled: false
102+ actions: sectionsTemplate.fewActions
103+ }
104+ }
105+ TemplateRow {
106+ title: i18n.tr("Disabled")
107+
108+ Sections {
109+ model: sectionsTemplate.fewActions
110+ enabled: false
111+ }
112+ }
113+ }
114+
115+ TemplateSection {
116+ title: "Scrollable sections"
117+ className: "Sections"
118+
119+ TemplateRow {
120+ title: i18n.tr("Enabled")
121+
122+ Sections {
123+ model: sectionsTemplate.manyActions
124+ width: parent.width
125+ }
126+ }
127+ TemplateRow {
128+ title: i18n.tr("Disabled")
129+
130+ Sections {
131+ model: sectionsTemplate.manyActions
132+ enabled: false
133+ width: parent.width
134 }
135 }
136 }
137
138=== modified file 'src/Ubuntu/Components/1.3/Sections.qml'
139--- src/Ubuntu/Components/1.3/Sections.qml 2015-12-08 21:38:59 +0000
140+++ src/Ubuntu/Components/1.3/Sections.qml 2016-02-26 10:16:56 +0000
141@@ -80,10 +80,6 @@
142 */
143 property var model: actions
144 onModelChanged: {
145- if (model && model.length > 3) {
146- // FIXME: Make the Sections scrollable for more than 3 sections.
147- console.warn("It is not YET recommended or supported to use more than three sections.");
148- }
149 if (internal.done) {
150 if (!model || model.length === 0) {
151 selectedIndex = -1;
152
153=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHead.qml'
154--- src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHead.qml 2015-12-08 22:05:42 +0000
155+++ src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHead.qml 2016-02-26 10:16:56 +0000
156@@ -25,14 +25,13 @@
157 */
158 StyledItem {
159 id: sections
160- styleName: "SectionsStyle"
161+ styleName: "SectionsForPageHeadStyle"
162
163 property list<Action> actions
164 property var model: actions
165 onModelChanged: {
166 if (model && model.length > 3) {
167- // FIXME: Make the Sections scrollable for more than 3 sections.
168- console.warn("It is not YET recommended or supported to use more than three sections.");
169+ console.warn("PageHeadSections does not support more than 3 sections. Use PageHeader and Sections instead.");
170 }
171 }
172 property int selectedIndex: model ? 0 : -1
173
174=== added file 'src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHeadStyle.qml'
175--- src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHeadStyle.qml 1970-01-01 00:00:00 +0000
176+++ src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsForPageHeadStyle.qml 2016-02-26 10:16:56 +0000
177@@ -0,0 +1,122 @@
178+/*
179+ * Copyright 2016 Canonical Ltd.
180+ *
181+ * This program is free software; you can redistribute it and/or modify
182+ * it under the terms of the GNU Lesser General Public License as published by
183+ * the Free Software Foundation; version 3.
184+ *
185+ * This program is distributed in the hope that it will be useful,
186+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
187+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
188+ * GNU Lesser General Public License for more details.
189+ *
190+ * You should have received a copy of the GNU Lesser General Public License
191+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
192+ */
193+import QtQuick 2.4
194+import Ubuntu.Components 1.3
195+
196+Item {
197+ id: sectionsStyle
198+
199+ implicitWidth: sectionsRow.width
200+ implicitHeight: units.gu(4)
201+
202+ enabled: styledItem.enabled
203+
204+ /*!
205+ The foreground color of unselected sections.
206+ */
207+ property color sectionColor: enabled
208+ ? theme.palette.normal.backgroundTertiaryText
209+ : theme.palette.disabled.backgroundTertiaryText
210+
211+ /*!
212+ The foreground color of the selected section.
213+ */
214+ property color selectedSectionColor: enabled
215+ ? theme.palette.selected.backgroundTertiaryText
216+ : theme.palette.selectedDisabled.backgroundTertiaryText
217+
218+ /*!
219+ The background color for the pressed section button.
220+ */
221+ property color pressedBackgroundColor: theme.palette.highlighted.background
222+
223+ /*!
224+ The font size for the text in the buttons.
225+ */
226+ property int textSize: Label.Small
227+
228+ /*!
229+ The spacing on the left and right sides of the label
230+ inside a section button.
231+ */
232+ property real horizontalLabelSpacing: units.gu(2)
233+
234+ /*!
235+ The height of the bar underlining the sections.
236+ */
237+ property real underlineHeight: units.dp(2)
238+
239+ Row {
240+ id: sectionsRow
241+ anchors {
242+ top: parent.top
243+ bottom: parent.bottom
244+ horizontalCenter: parent.horizontalCenter
245+ }
246+ width: childrenRect.width
247+
248+ Repeater {
249+ id: sectionsRepeater
250+ model: styledItem.model
251+ objectName: "sections_repeater"
252+ AbstractButton {
253+ id: sectionButton
254+ anchors {
255+ top: parent ? parent.top : undefined
256+ bottom: parent ? parent.bottom : undefined
257+ }
258+ objectName: "section_button_" + index
259+ width: label.width + 2 * sectionsStyle.horizontalLabelSpacing
260+ height: sectionsRow.height
261+ property bool selected: index === styledItem.selectedIndex
262+ onClicked: styledItem.selectedIndex = index
263+
264+ // Background pressed highlight
265+ Rectangle {
266+ visible: parent.pressed
267+ anchors.fill: parent
268+ color: sectionsStyle.pressedBackgroundColor
269+ }
270+
271+ // Section title
272+ Label {
273+ id: label
274+ objectName: "section_button_label_" + index
275+ // modelData may be either a string, or an Action
276+ text: modelData.hasOwnProperty("text") ? modelData.text : modelData
277+ textSize: sectionsStyle.textSize
278+ anchors.centerIn: parent
279+ color: sectionButton.selected ?
280+ sectionsStyle.selectedSectionColor :
281+ sectionsStyle.sectionColor
282+ }
283+
284+ // Section title underline
285+ Rectangle {
286+ anchors {
287+ bottom: parent.bottom
288+ left: parent.left
289+ right: parent.right
290+ }
291+ height: sectionsStyle.underlineHeight
292+ color: sectionButton.selected ?
293+ sectionsStyle.selectedSectionColor :
294+ sectionsStyle.sectionColor
295+ }
296+ }
297+ }
298+ }
299+}
300
301=== modified file 'src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml'
302--- src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml 2016-01-27 15:17:56 +0000
303+++ src/Ubuntu/Components/Themes/Ambiance/1.3/SectionsStyle.qml 2016-02-26 10:16:56 +0000
304@@ -15,28 +15,33 @@
305 */
306 import QtQuick 2.4
307 import Ubuntu.Components 1.3
308+import QtGraphicalEffects 1.0
309+import Ubuntu.Components.Private 1.3
310
311 Item {
312 id: sectionsStyle
313
314- implicitWidth: sectionsRow.width
315+ implicitWidth: sectionsListView.contentWidth + 2 * listViewContainer.listViewMargins
316 implicitHeight: units.gu(4)
317
318- enabled: styledItem.enabled
319-
320 /*!
321 The foreground color of unselected sections.
322 */
323 property color sectionColor: enabled
324- ? theme.palette.normal.backgroundTertiaryText
325- : theme.palette.disabled.backgroundTertiaryText
326+ ? theme.palette.normal.backgroundTertiaryText
327+ : theme.palette.disabled.backgroundTertiaryText
328+
329+ /*!
330+ The foreground color of underline rectangle of unselected sections.
331+ */
332+ property color underlineColor: theme.palette.normal.base
333
334 /*!
335 The foreground color of the selected section.
336 */
337 property color selectedSectionColor: enabled
338- ? theme.palette.selected.backgroundTertiaryText
339- : theme.palette.selectedDisabled.backgroundTertiaryText
340+ ? theme.palette.selected.backgroundTertiaryText
341+ : theme.palette.selectedDisabled.backgroundTertiaryText
342
343 /*!
344 The background color for the pressed section button.
345@@ -44,9 +49,9 @@
346 property color pressedBackgroundColor: theme.palette.highlighted.background
347
348 /*!
349- The font size for the text in the buttons.
350+ The size of text in the buttons.
351 */
352- property int textSize: Label.Small
353+ property int textSize: Label.Medium
354
355 /*!
356 The spacing on the left and right sides of the label
357@@ -59,30 +64,132 @@
358 */
359 property real underlineHeight: units.dp(2)
360
361- Row {
362- id: sectionsRow
363- anchors {
364- top: parent.top
365- bottom: parent.bottom
366- horizontalCenter: parent.horizontalCenter
367- }
368- width: childrenRect.width
369-
370- Repeater {
371- id: sectionsRepeater
372+ // We don't clip listview on purpose, so we have to clip here to prevent Sections element
373+ // from painting outside its area.
374+ clip: true
375+
376+ //This item is needed for the OpacityMask feature. It is needed to make sure that when we
377+ //bring a list element into view, that element won't be covered by the opacity mask. So we
378+ //disable clipping on the list but we give it margins. This way when an item is repositioned
379+ //to be within the listview, that item will not be positioned under the opacity mask. (which is
380+ //what would have happened if the listview were filling the parent)
381+ Item {
382+ id: listViewContainer
383+ anchors.fill: parent
384+
385+ property real listViewMargins: units.gu(2)
386+
387+ //We need to set this to 0.0 when OpacityMask will draw this listview for us.
388+ //we don't set visible: false because we still want to get the input events!
389+ opacity: 1.0
390+
391+ ListView {
392+ id: sectionsListView
393+ objectName: "sections_listview"
394+
395+ property bool animateContentX: false
396+ activeFocusOnTab: false // FIXME: Enable proper focus handling
397+
398+ // Position the selected item correctly.
399+ // For a scrollable ListView, if the item was already fully visible,
400+ // no repositioning is needed. If the item was (partially) invisible,
401+ // position it so that it becomes fully visible.
402+ // If the ListView is not scrollable, the first item will be aligned with
403+ // the left of the ListView.
404+ function positionItem(item) {
405+ if (item !== null) {
406+ //stop the flick before doing computations
407+ if (moving) {
408+ return;
409+ }
410+ if (dragging || flicking) {
411+ cancelFlick();
412+ }
413+ if (contentXAnim.running) {
414+ contentXAnim.stop();
415+ }
416+
417+ contentXAnim.from = contentX;
418+ //make sure we don't overshoot bounds
419+ if (sectionsListView.contentWidth <= sectionsListView.width) {
420+ // No scrolling, position the sections on the left.
421+ contentXAnim.to = originX;
422+ } else {
423+ // Position the selected Item so that it is fully visible.
424+ contentXAnim.to = MathUtils.clamp(contentX, originX, originX + contentWidth - width);
425+ }
426+ if (contentXAnim.from !== contentXAnim.to) {
427+ contentXAnim.start();
428+ }
429+ }
430+ }
431+
432+ anchors {
433+ fill: parent
434+ leftMargin: listViewContainer.listViewMargins
435+ rightMargin: listViewContainer.listViewMargins
436+ }
437+
438+ //this is just to disable keyboard navigation to avoid messing with contentX/contentWidth while
439+ //the view is moving
440+ focus: !moving
441+
442+ onWidthChanged: positionItem(currentItem)
443+ //make sure that the currentItem is in the middle when everything is initialized
444+ Component.onCompleted: positionItem(currentItem)
445+
446+ orientation: ListView.Horizontal
447+ boundsBehavior: Flickable.StopAtBounds
448+
449 model: styledItem.model
450- objectName: "sections_repeater"
451- AbstractButton {
452+
453+ //We need this to make sure that we have delegates for the whole width, since we have
454+ //clip disabled.
455+ displayMarginBeginning: listViewContainer.listViewMargins
456+ displayMarginEnd: listViewContainer.listViewMargins
457+
458+ currentIndex: styledItem.selectedIndex
459+ onCurrentIndexChanged: {
460+ styledItem.selectedIndex = currentIndex;
461+ }
462+ onCurrentItemChanged: {
463+ //adjust contentX so that the item is kept in the middle
464+ //don't use ListView.ApplyRange because that does an awkward animation when you select an item
465+ //*while* the current item is outside of screen
466+ positionItem(currentItem);
467+ }
468+
469+ highlightFollowsCurrentItem: false
470+ highlight: Item {
471+ //show the highlight on top of the delegate
472+ z: 2
473+ x: sectionsListView.currentItem ? sectionsListView.currentItem.x : -width
474+ width: sectionsListView.currentItem ? sectionsListView.currentItem.width : 0
475+ height: sectionsListView.currentItem ? sectionsListView.currentItem.height : 0
476+
477+ Rectangle {
478+ anchors {
479+ bottom: parent.bottom
480+ left: parent.left
481+ right: parent.right
482+ }
483+ height: sectionsStyle.underlineHeight
484+ color: sectionsStyle.selectedSectionColor
485+ }
486+ Behavior on x { UbuntuNumberAnimation {} }
487+ }
488+
489+ delegate: AbstractButton {
490 id: sectionButton
491- anchors {
492- top: parent ? parent.top : undefined
493- bottom: parent ? parent.bottom : undefined
494- }
495+ activeFocusOnTab: false
496 objectName: "section_button_" + index
497 width: label.width + 2 * sectionsStyle.horizontalLabelSpacing
498- height: sectionsRow.height
499+ height: sectionsStyle.height
500 property bool selected: index === styledItem.selectedIndex
501- onClicked: styledItem.selectedIndex = index
502+ onClicked: {
503+ styledItem.selectedIndex = index;
504+ sectionsListView.forceActiveFocus();
505+ }
506
507 // Background pressed highlight
508 Rectangle {
509@@ -98,25 +205,189 @@
510 // modelData may be either a string, or an Action
511 text: modelData.hasOwnProperty("text") ? modelData.text : modelData
512 textSize: sectionsStyle.textSize
513- anchors.centerIn: parent
514+ font.weight: Font.Light
515+ anchors {
516+ baseline: underline.bottom
517+ baselineOffset: -units.gu(2)
518+ horizontalCenter: parent.horizontalCenter
519+ }
520+
521 color: sectionButton.selected ?
522 sectionsStyle.selectedSectionColor :
523 sectionsStyle.sectionColor
524+
525+ Behavior on color {
526+ ColorAnimation { duration: UbuntuAnimation.SlowDuration }
527+ }
528 }
529
530 // Section title underline
531 Rectangle {
532+ id: underline
533 anchors {
534 bottom: parent.bottom
535 left: parent.left
536 right: parent.right
537 }
538 height: sectionsStyle.underlineHeight
539- color: sectionButton.selected ?
540- sectionsStyle.selectedSectionColor :
541- sectionsStyle.sectionColor
542- }
543- }
544- }
545- }
546+ color: sectionsStyle.underlineColor
547+ }
548+ }
549+
550+ SmoothedAnimation {
551+ id: contentXAnim
552+ target: sectionsListView
553+ property: "contentX"
554+ duration: UbuntuAnimation.FastDuration
555+ velocity: units.gu(10)
556+ }
557+ }
558+ }
559+
560+ MouseArea {
561+ // Detect hovering over the left and right areas to show the scrolling chevrons.
562+ id: hoveringArea
563+
564+ property real iconsDisabledOpacity: 0.3
565+
566+ property bool hoveringLeft: false
567+ property bool hoveringRight: false
568+
569+ function checkHovering(mouse) {
570+ if (mouse.x < listViewContainer.listViewMargins) {
571+ if (!hoveringLeft) hoveringLeft = true;
572+ } else if (mouse.x > width - listViewContainer.listViewMargins) {
573+ if (!hoveringRight) hoveringRight = true;
574+ } else {
575+ hoveringLeft = false;
576+ hoveringRight = false;
577+ }
578+ }
579+
580+ anchors.fill: parent
581+ hoverEnabled: true
582+
583+ onPositionChanged: checkHovering(mouse)
584+ onExited: {
585+ hoveringLeft = false;
586+ hoveringRight = false;
587+ }
588+ onPressed: {
589+ if (!hoveringLeft && !hoveringRight) {
590+ mouse.accepted = false;
591+ }
592+ }
593+ onClicked: {
594+ // positionViewAtIndex() does not provide animation
595+ if (contentXAnim.running) contentXAnim.stop();
596+ var newContentX = sectionsListView.contentX + (sectionsListView.width * (hoveringLeft ? -1 : 1));
597+ contentXAnim.from = sectionsListView.contentX;
598+ // make sure we don't overshoot bounds
599+ contentXAnim.to = MathUtils.clamp(
600+ newContentX,
601+ sectionsListView.originX,
602+ sectionsListView.originX + sectionsListView.contentWidth - sectionsListView.width);
603+ contentXAnim.start();
604+ }
605+
606+ Icon {
607+ id: leftHoveringIcon
608+ anchors {
609+ left: parent.left
610+ leftMargin: (listViewContainer.listViewMargins - width) / 2
611+ bottom: parent.bottom
612+ bottomMargin: units.gu(2)
613+ }
614+ width: units.gu(1)
615+ height: units.gu(1)
616+ visible: false
617+ rotation: 180
618+ opacity: visible
619+ ? sectionsListView.atXBeginning ? hoveringArea.iconsDisabledOpacity : 1.0
620+ : 0.0
621+ name: "chevron"
622+ Behavior on opacity {
623+ UbuntuNumberAnimation {
624+ duration: UbuntuAnimation.FastDuration
625+ }
626+ }
627+ }
628+
629+ Icon {
630+ id: rightHoveringIcon
631+ anchors {
632+ right: parent.right
633+ rightMargin: (listViewContainer.listViewMargins - width) / 2
634+ bottom: parent.bottom
635+ bottomMargin: units.gu(2)
636+ }
637+ width: units.gu(1)
638+ height: units.gu(1)
639+ visible: false
640+ opacity: visible
641+ ? sectionsListView.atXEnd ? hoveringArea.iconsDisabledOpacity : 1.0
642+ : 0.0
643+ name: "chevron"
644+ Behavior on opacity {
645+ UbuntuNumberAnimation {
646+ duration: UbuntuAnimation.FastDuration
647+ }
648+ }
649+ }
650+ }
651+
652+ LinearGradient {
653+ id: gradient
654+
655+ visible: false
656+ anchors.fill: parent
657+ start: Qt.point(0,0)
658+ end: Qt.point(width,0)
659+
660+ property real gradientWidth: listViewContainer.listViewMargins / gradient.width
661+ //the width is gradientWidth, but we want the gradient to actually start/finish at gradientSplitPosition
662+ //just to leave some margin.
663+ property real gradientSplitPosition: 2/3 * gradientWidth
664+
665+ gradient: Gradient {
666+ //left gradient
667+ GradientStop { position: 0.0 ; color: Qt.rgba(1,1,1,0) }
668+ GradientStop { position: gradient.gradientSplitPosition ; color: Qt.rgba(1,1,1,0) }
669+ GradientStop { position: gradient.gradientWidth; color: Qt.rgba(1,1,1,1) }
670+ //right gradient
671+ GradientStop { position: 1.0 - gradient.gradientWidth; color: Qt.rgba(1,1,1,1) }
672+ GradientStop { position: 1.0 - gradient.gradientSplitPosition; color: Qt.rgba(1,1,1,0) }
673+ GradientStop { position: 1.0; color: Qt.rgba(1,1,1,0) }
674+ }
675+
676+ Rectangle {
677+ // full opacity for the underline at the bottom in the mask below
678+ anchors {
679+ left: parent.left
680+ right: parent.right
681+ bottom: parent.bottom
682+ }
683+ height: sectionsStyle.underlineHeight
684+ color: "white"
685+ }
686+ }
687+
688+ OpacityMask {
689+ id: mask
690+ anchors.fill: parent
691+ visible: false
692+ source: listViewContainer
693+ maskSource: gradient
694+ }
695+
696+ states: [
697+ State {
698+ name: "hovering"
699+ when: hoveringArea.containsMouse
700+ PropertyChanges { target: mask; visible: true }
701+ PropertyChanges { target: listViewContainer; opacity: 0.0 }
702+ PropertyChanges { target: leftHoveringIcon; visible: true; }
703+ PropertyChanges { target: rightHoveringIcon; visible: true; }
704+ }
705+ ]
706 }
707
708=== modified file 'src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro'
709--- src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2016-01-22 19:42:49 +0000
710+++ src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2016-02-26 10:16:56 +0000
711@@ -119,6 +119,7 @@
712 1.3/BottomEdgeStyle.qml \
713 1.3/FocusShape.qml \
714 1.3/SectionsForPageHead.qml \
715+ 1.3/SectionsForPageHeadStyle.qml \
716 $$ARTWORK_FILES
717
718 load(ubuntu_qml_module)
719
720=== modified file 'src/Ubuntu/Components/Themes/Ambiance/qmldir'
721--- src/Ubuntu/Components/Themes/Ambiance/qmldir 2016-01-13 14:25:22 +0000
722+++ src/Ubuntu/Components/Themes/Ambiance/qmldir 2016-02-26 10:16:56 +0000
723@@ -89,3 +89,4 @@
724 BottomEdgeStyle 1.3 ./1.3/BottomEdgeStyle.qml
725 ToolbarStyle 1.3 ./1.3/ToolbarStyle.qml
726 internal SectionsForPageHead ./1.3/SectionsForPageHead.qml
727+internal SectionsForPageHeadStyle ./1.3/SectionsForPageHeadStyle.qml
728
729=== added file 'tests/Gallery/gallery'
730--- tests/Gallery/gallery 1970-01-01 00:00:00 +0000
731+++ tests/Gallery/gallery 2016-02-26 10:16:56 +0000
732@@ -0,0 +1,6 @@
733+#!/bin/bash
734+
735+. `dirname ${BASH_SOURCE[0]}`/../../export_modules_dir.sh || exit 1
736+
737+SCRIPT_DIRECTORY=`dirname $0`
738+QT_LOGGING_CONF=$SCRIPT_DIRECTORY/gallery-logging.config $BUILD_DIR/ubuntu-ui-toolkit-launcher/ubuntu-ui-toolkit-launcher $@ $SCRIPT_DIRECTORY/../../examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml
739
740=== removed file 'tests/Gallery/gallery'
741--- tests/Gallery/gallery 2016-02-04 12:02:52 +0000
742+++ tests/Gallery/gallery 1970-01-01 00:00:00 +0000
743@@ -1,6 +0,0 @@
744-#!/bin/bash
745-
746-. `dirname ${BASH_SOURCE[0]}`/../../export_modules_dir.sh || exit 1
747-
748-SCRIPT_DIRECTORY=`dirname $0`
749-QT_LOGGING_CONF=$SCRIPT_DIRECTORY/gallery-logging.config $BUILD_DIR/ubuntu-ui-toolkit-launcher/ubuntu-ui-toolkit-launcher $@ $SCRIPT_DIRECTORY/../../examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml
750
751=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py'
752--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py 2015-05-28 15:38:53 +0000
753+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_sections.py 2016-02-26 10:16:56 +0000
754@@ -1,6 +1,6 @@
755 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
756 #
757-# Copyright (C) 2015 Canonical Ltd.
758+# Copyright (C) 2016 Canonical Ltd.
759 #
760 # This program is free software; you can redistribute it and/or modify
761 # it under the terms of the GNU Lesser General Public License as published by
762@@ -27,15 +27,9 @@
763 class Sections(_common.UbuntuUIToolkitCustomProxyObjectBase):
764 """Sections Autopilot custom proxy object."""
765
766- def _get_section_button(self, section_index):
767- try:
768- object_name = "section_button_" + str(section_index)
769- button = self.select_single(objectName=object_name)
770- except dbus.StateNotFoundError:
771- raise _common.ToolkitException(
772- 'Button not found in Sections.')
773-
774- return button
775+ def __init__(self, *args):
776+ super().__init__(*args)
777+ self.listview = self.select_single(objectName='sections_listview')
778
779 @autopilot_logging.log_action(logger.info)
780 def click_section_button(self, section_index):
781@@ -45,5 +39,10 @@
782 :raise ToolkitException: If there is no section button with that index.
783
784 """
785- button = self._get_section_button(section_index)
786- self.pointing_device.click_object(button)
787+ button_object_name = 'section_button_' + str(section_index)
788+ try:
789+ self.listview.click_element(button_object_name)
790+ except _common.ToolkitException:
791+ raise _common.ToolkitException(
792+ 'Button with section index ' + str(section_index) +
793+ ' not found in Sections.')
794
795=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml'
796--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml 2015-05-28 15:48:42 +0000
797+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.SectionsTestCase.qml 2016-02-26 10:16:56 +0000
798@@ -1,5 +1,5 @@
799 /*
800- * Copyright 2015 Canonical Ltd.
801+ * Copyright 2016 Canonical Ltd.
802 *
803 * This program is free software; you can redistribute it and/or modify
804 * it under the terms of the GNU Lesser General Public License as published by
805@@ -22,12 +22,16 @@
806 height: units.gu(60)
807 objectName: "mainView"
808 Page {
809- title: "Sections test"
810+ id: page
811+ header: PageHeader {
812+ title: "Sections test"
813+ }
814 Label {
815 id: label
816 objectName: "label"
817 anchors {
818- top: parent.top
819+ top: page.header.bottom
820+ topMargin: units.gu(2)
821 horizontalCenter: parent.horizontalCenter
822 }
823 text: "Section " + sections.selectedIndex + " is selected."
824@@ -35,8 +39,36 @@
825 Sections {
826 id: sections
827 objectName: "sections"
828- anchors.centerIn: parent
829+ anchors {
830+ horizontalCenter: parent.horizontalCenter
831+ top: label.bottom
832+ topMargin: units.gu(4)
833+ }
834 model: [ "first", "second", "third" ]
835 }
836+ Label {
837+ id: moreLabel
838+ objectName: "scrolling_label"
839+ anchors {
840+ centerIn: parent
841+ }
842+ text: "Scrollable section " + moreSections.selectedIndex + " is selected."
843+ }
844+ Sections {
845+ id: moreSections
846+ objectName: "scrolling_sections"
847+ anchors {
848+ horizontalCenter: parent.horizontalCenter
849+ top: moreLabel.bottom
850+ topMargin: units.gu(4)
851+ left: parent.left
852+ right: parent.right
853+ }
854+ model: ["one", "two", "three", "four", "five", "six",
855+ "seven", "eight", "nine", "ten", "eleven", "twelve",
856+ "thirteen", "fourteen", "fifteen", "sixteen",
857+ "seventeen", "eighteen", "nineteen", "twenty"
858+ ]
859+ }
860 }
861 }
862
863=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py'
864--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py 2015-11-11 17:37:14 +0000
865+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_sections.py 2016-02-26 10:16:56 +0000
866@@ -29,21 +29,45 @@
867 def setUp(self):
868 super().setUp()
869 self.sections = self.app.select_single(objectName='sections')
870+ self.scrollingSections = self.app.select_single(objectName='scrolling_sections')
871 self.label = self.app.select_single(objectName='label')
872+ self.scrollingLabel = self.app.select_single(objectName='scrolling_label')
873 self.assertEqual(self.label.text, 'Section 0 is selected.')
874+ self.assertEqual(self.scrollingLabel.text, 'Scrollable section 0 is selected.')
875
876 def test_custom_proxy_object(self):
877 self.assertIsInstance(self.sections, ubuntuuitoolkit.Sections)
878 self.assertTrue(self.sections.visible)
879+ self.assertIsInstance(self.scrollingSections, ubuntuuitoolkit.Sections)
880+ self.assertTrue(self.scrollingSections.visible)
881
882 def test_click_section_button(self):
883 self.sections.click_section_button(2)
884 self.assertEqual(self.label.text, 'Section 2 is selected.')
885
886+ def test_click_visible_scrolling_section_button(self):
887+ self.scrollingSections.click_section_button(2)
888+ self.assertEqual(self.scrollingLabel.text, 'Scrollable section 2 is selected.')
889+
890+ def test_scroll_and_click_section_button(self):
891+ # scroll forward and click:
892+ self.scrollingSections.click_section_button(15)
893+ self.assertEqual(self.scrollingLabel.text, 'Scrollable section 15 is selected.')
894+ # scroll back and click:
895+ self.scrollingSections.click_section_button(1)
896+ self.assertEqual(self.scrollingLabel.text, 'Scrollable section 1 is selected.')
897+
898 def test_click_unexisting_section_button(self):
899 error = self.assertRaises(
900 ubuntuuitoolkit.ToolkitException,
901 self.sections.click_section_button, 3)
902 self.assertEqual(
903 str(error),
904- 'Button not found in Sections.')
905+ 'Button with section index 3 not found in Sections.')
906+
907+ error = self.assertRaises(
908+ ubuntuuitoolkit.ToolkitException,
909+ self.scrollingSections.click_section_button, 20)
910+ self.assertEqual(
911+ str(error),
912+ 'Button with section index 20 not found in Sections.')
913
914=== modified file 'tests/unit_x11/tst_components/tst_pagehead_sections.qml'
915--- tests/unit_x11/tst_components/tst_pagehead_sections.qml 2015-12-08 14:26:27 +0000
916+++ tests/unit_x11/tst_components/tst_pagehead_sections.qml 2016-02-26 10:16:56 +0000
917@@ -136,7 +136,7 @@
918 }
919
920 function test_warn_when_too_many_sections() {
921- ignoreWarning("It is not YET recommended or supported to use more than three sections.")
922+ ignoreWarning("PageHeadSections does not support more than 3 sections. Use PageHeader and Sections instead.");
923 page.head.sections.model = ["red", "orange", "yellow", "green"];
924 }
925 }
926
927=== modified file 'tests/unit_x11/tst_components/tst_pagehead_sections_bug1511839.qml'
928--- tests/unit_x11/tst_components/tst_pagehead_sections_bug1511839.qml 2015-11-02 15:20:42 +0000
929+++ tests/unit_x11/tst_components/tst_pagehead_sections_bug1511839.qml 2016-02-26 10:16:56 +0000
930@@ -62,7 +62,7 @@
931
932 function test_bug1511839() {
933 for (var i = 0; i < stack.currentPage.head.sections.model.length; i++) {
934- verifySelectedSection(i, false);
935+ verifySelectedSection(i, false, "Section " + i + " is selected.");
936 }
937 }
938
939
940=== modified file 'tests/unit_x11/tst_components/tst_sections.qml'
941--- tests/unit_x11/tst_components/tst_sections.qml 2015-12-08 21:35:11 +0000
942+++ tests/unit_x11/tst_components/tst_sections.qml 2016-02-26 10:16:56 +0000
943@@ -20,27 +20,34 @@
944
945 Rectangle {
946 id: root
947- width: 400
948- height: 600
949+ width: units.gu(60)
950+ height: units.gu(75)
951 color: "white"
952
953 property list<Action> actionList: [
954 Action {
955- text: "first";
956+ text: "action 0";
957 onTriggered: label.text = "First action triggered.";
958 },
959 Action {
960- text: "second";
961+ text: "action 1";
962 onTriggered: label.text = "Second action triggered.";
963 },
964 Action {
965- text: "third";
966+ text: "action 2";
967 onTriggered: label.text = "Third action triggered.";
968 }
969 ]
970
971 property var stringList: [
972- "string one", "string two", "string three"
973+ "string zero", "string one", "string two"
974+ ]
975+
976+ property var longStringList: [
977+ "one", "two", "three", "four", "five", "six", "seven",
978+ "eight", "nine", "ten", "eleven", "twelve", "thirteen",
979+ "fourteen", "fifteen", "sixteen", "seventeen",
980+ "eighteen", "nineteen", "twenty"
981 ]
982
983 Column {
984@@ -53,41 +60,15 @@
985 }
986 spacing: units.gu(2)
987
988- Label {
989- anchors.horizontalCenter: parent.horizontalCenter
990- text: "Sections with actions"
991- }
992- Label {
993- anchors.left: parent.left
994- text: "actions in-line:"
995- textSize: Label.Small
996- }
997 Sections {
998 // Not used in the tests below, but added here to
999 // verify that the Actions can be defined directly
1000 // inside the list of actions.
1001 actions: [
1002- Action { text: "1" },
1003- Action { text: "2" }
1004+ Action { text: "inline action 0" },
1005+ Action { text: "inline action 1" }
1006 ]
1007- }
1008- Label {
1009- anchors.left: parent.left
1010- text: "enabled:"
1011- textSize: Label.Small
1012- }
1013- Sections {
1014- id: enabledSections
1015- actions: root.actionList
1016- }
1017- Label {
1018- text: "disabled:"
1019- textSize: Label.Small
1020- }
1021- Sections {
1022- id: disabledSections
1023- actions: root.actionList
1024- enabled: false
1025+ width: parent.width
1026 }
1027 Rectangle {
1028 anchors {
1029@@ -96,7 +77,7 @@
1030 margins: units.gu(2)
1031 }
1032 color: UbuntuColors.blue
1033- height: units.gu(10)
1034+ height: units.gu(5)
1035 Label {
1036 id: label
1037 anchors.centerIn: parent
1038@@ -104,24 +85,24 @@
1039 color: "white"
1040 }
1041 }
1042- Label {
1043- anchors.horizontalCenter: parent.horizontalCenter
1044- text: "Sections with strings"
1045- }
1046- Label {
1047- anchors.left: parent.left
1048- text: "enabled:"
1049- textSize: Label.Small
1050+ Sections {
1051+ id: enabledSections
1052+ actions: root.actionList
1053+ }
1054+ Sections {
1055+ id: disabledSections
1056+ actions: root.actionList
1057+ enabled: false
1058+ }
1059+ Sections {
1060+ id: noSelectionSections
1061+ actions: root.actionList
1062+ selectedIndex: -1
1063 }
1064 Sections {
1065 id: enabledStringSections
1066 model: root.stringList
1067 }
1068- Label {
1069- anchors.left: parent.left
1070- text: "disabled:"
1071- textSize: Label.Small
1072- }
1073 Sections {
1074 id: disabledStringSections
1075 model: root.stringList
1076@@ -133,17 +114,25 @@
1077 property bool action1Triggered: false;
1078 property bool action2Triggered: false;
1079 property Action action0: Action {
1080+ text: "action0"
1081 onTriggered: selectedIndexSections.action0Triggered = true;
1082 }
1083 property Action action1: Action {
1084+ text: "action1 (selected)"
1085 onTriggered: selectedIndexSections.action1Triggered = true;
1086 }
1087 property Action action2: Action {
1088+ text: "action2"
1089 onTriggered: selectedIndexSections.action2Triggered = true;
1090 }
1091 actions: [action0, action1, action2]
1092 selectedIndex: 1
1093 }
1094+ Sections {
1095+ id: scrollingSections
1096+ model: root.longStringList
1097+ width: parent.width
1098+ }
1099 }
1100
1101 UbuntuTestCase {
1102@@ -176,8 +165,8 @@
1103 }
1104
1105 function get_number_of_section_buttons(sections) {
1106- var repeater = findChild(sections, "sections_repeater");
1107- return repeater.count;
1108+ var listview = findChild(sections, "sections_listview");
1109+ return listview.count;
1110 }
1111
1112 // return the index of the selected section button,
1113@@ -224,28 +213,31 @@
1114
1115 function check_selected_section(sections, index, name) {
1116 var v = sections.selectedIndex;
1117- compare(v, index, "selectedIndex "+v+" does not match "+index);
1118+ compare(v, index, "selectedIndex " + v + " does not match " + index);
1119 v = get_selected_section_button_index(sections);
1120- compare(v, index, "selected button index "+v+" does not match "+index);
1121+ compare(v, index, "selected button index " + v + " does not match " + index);
1122 if (v === -1) return;
1123 var w = get_selected_section_button_text(sections);
1124- compare(w, name, "selected button text \'"+w+"\' does not match \'"+name+"\'");
1125+ compare(w, name, "selected button text \'" + w + "\' does not match \'" + name + "\'");
1126 }
1127
1128 // in each test function below, test the desired behavior
1129 // for both enabledSections and disabledSections.
1130
1131 function test_0_first_section_initially_selected_actions_enabled() {
1132- check_selected_section(enabledSections, 0, "first");
1133+ check_selected_section(enabledSections, 0, "action 0");
1134 }
1135 function test_0_first_section_initially_selected_actions_disabled() {
1136- check_selected_section(disabledSections, 0, "first");
1137+ check_selected_section(disabledSections, 0, "action 0");
1138 }
1139 function test_0_first_section_initially_selected_strings_enabled() {
1140- check_selected_section(enabledStringSections, 0, "string one");
1141+ check_selected_section(enabledStringSections, 0, "string zero");
1142 }
1143 function test_0_first_section_initially_selected_strings_disabled() {
1144- check_selected_section(disabledStringSections, 0, "string one");
1145+ check_selected_section(disabledStringSections, 0, "string zero");
1146+ }
1147+ function test_0_no_selected_section_initalization() {
1148+ check_selected_section(noSelectionSections, -1, "");
1149 }
1150
1151 function test_number_of_section_buttons() {
1152@@ -258,7 +250,7 @@
1153
1154 function test_click_to_select_section_and_trigger_action() {
1155 var index = 2;
1156- var name = "third";
1157+ var name = "action 2";
1158 click_section_button(enabledSections, name);
1159 wait_for_animation(enabledSections);
1160 check_selected_section(enabledSections, index, name);
1161@@ -268,12 +260,12 @@
1162
1163 function test_click_disabled_section_action() {
1164 var index = 2;
1165- var name = "third";
1166+ var name = "action 2";
1167 click_section_button(disabledSections, name);
1168 wait_for_animation(disabledSections);
1169 // first button should still be selected:
1170 index = 0;
1171- name = "first";
1172+ name = "action 0";
1173 check_selected_section(disabledSections, index, name);
1174 var text = "No action triggered.";
1175 compare(label.text, text, "Clicking disabled button triggered something.");
1176@@ -281,25 +273,25 @@
1177
1178 function test_click_to_select_section_string() {
1179 var index = 2;
1180- var name = "string three";
1181+ var name = "string two";
1182 click_section_button(enabledStringSections, name);
1183 wait_for_animation(enabledStringSections);
1184 check_selected_section(enabledStringSections, index, name);
1185 }
1186
1187 function test_click_disabled_section_string() {
1188- var name = "string three";
1189+ var name = "string two";
1190 click_section_button(disabledStringSections, name);
1191 wait_for_animation(disabledStringSections);
1192 // first button should still be selected:
1193 var index = 0;
1194- name = "string one";
1195+ name = "string zero";
1196 check_selected_section(disabledStringSections, index, name);
1197 }
1198
1199 function test_set_selectedIndex_to_select_section_and_trigger_action_enabled() {
1200 var index = 1;
1201- var name = "second";
1202+ var name = "action 1";
1203 enabledSections.selectedIndex = index;
1204 wait_for_animation(enabledSections);
1205 check_selected_section(enabledSections, index, name);
1206@@ -309,7 +301,7 @@
1207
1208 function test_set_selectedIndex_to_select_section_and_trigger_action_disabled() {
1209 var index = 2;
1210- var name = "third";
1211+ var name = "action 2";
1212 disabledSections.selectedIndex = index;
1213 wait_for_animation(disabledSections);
1214 check_selected_section(disabledSections, index, name);
1215@@ -320,7 +312,7 @@
1216
1217 function test_set_selectedIndex_to_select_section_string_enabled() {
1218 var index = 1;
1219- var name = "string two";
1220+ var name = "string one";
1221 enabledStringSections.selectedIndex = index;
1222 wait_for_animation(enabledStringSections);
1223 check_selected_section(enabledStringSections, index, name);
1224@@ -328,7 +320,7 @@
1225
1226 function test_set_selectedIndex_to_select_section_string_disabled() {
1227 var index = 2;
1228- var name = "string three";
1229+ var name = "string two";
1230 disabledStringSections.selectedIndex = index;
1231 check_selected_section(disabledStringSections, index, name);
1232 }
1233@@ -371,5 +363,66 @@
1234 selectedIndexSections.actions = originalActions;
1235 wait_for_animation(selectedIndexSections);
1236 }
1237+
1238+ function test_keyboard_navigation_data() {
1239+ return [
1240+ { tag: "actions",
1241+ item: enabledSections,
1242+ initialButton: root.actionList[0].text,
1243+ initialIndex: 0
1244+ },
1245+ { tag: "strings",
1246+ item: enabledStringSections,
1247+ initialButton: root.stringList[0],
1248+ initialIndex: 0
1249+ },
1250+ { tag: "scrolling",
1251+ item: scrollingSections,
1252+ initialButton: root.longStringList[0],
1253+ initialIndex: 0
1254+ }
1255+ ];
1256+ }
1257+
1258+ function test_keyboard_navigation(data) {
1259+ var sections = data.item;
1260+ var initialButtonName = data.initialButton;
1261+ click_section_button(sections, initialButtonName);
1262+ wait_for_animation(sections);
1263+ compare(sections.selectedIndex, data.initialIndex,
1264+ "Clicking the initial button does not select section "+data.initialIndex);
1265+ var numberOfSections = sections.model.length;
1266+ var i = sections.selectedIndex;
1267+
1268+ // Sections has focus because it was just clicked on,
1269+ // so we can use keyboard navigation.
1270+ while (i < numberOfSections - 1) {
1271+ i++;
1272+ keyClick(Qt.Key_Right);
1273+ wait_for_animation(sections);
1274+ compare(sections.selectedIndex, i,
1275+ "Could not navigate to index " + i + " using right key.");
1276+ }
1277+
1278+ // Navigated to the last section. Right key should do nothing now.
1279+ keyClick(Qt.Key_Right);
1280+ wait_for_animation(sections);
1281+ compare(sections.selectedIndex, i,
1282+ "Using right key navigates beyond the last section.");
1283+
1284+ while (i > 0) {
1285+ i--;
1286+ keyClick(Qt.Key_Left);
1287+ wait_for_animation(sections);
1288+ compare(sections.selectedIndex, i,
1289+ "Could not navigate back to index " + i + " using left key.");
1290+ }
1291+
1292+ // Navigated back to the beginning. Left key should do nothing now.
1293+ keyClick(Qt.Key_Left);
1294+ wait_for_animation(sections);
1295+ compare(sections.selectedIndex, i,
1296+ "Using left key navigates beyond the first section.");
1297+ }
1298 }
1299 }

Subscribers

People subscribed via source and target branches