Merge lp:~zsombi/ubuntu-ui-toolkit/configurableColumns into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri on 2015-08-10
Status: Merged
Approved by: Tim Peeters on 2015-08-14
Approved revision: 1612
Merged at revision: 1608
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/configurableColumns
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 742 lines (+507/-33)
9 files modified
components.api (+10/-0)
examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml (+20/-0)
src/Ubuntu/Components/1.3/AdaptivePageLayout.qml (+129/-19)
src/Ubuntu/Components/1.3/PageColumn.qml (+16/-11)
src/Ubuntu/Components/1.3/PageColumnsLayout.qml (+115/-0)
src/Ubuntu/Components/ComponentModule.pro (+3/-2)
src/Ubuntu/Components/qmldir (+2/-1)
tests/unit_x11/tst_components/tst_adaptivepagelayout.qml (+2/-0)
tests/unit_x11/tst_components/tst_adaptivepagelayout_configuration.qml (+210/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/configurableColumns
Reviewer Review Type Date Requested Status
Tim Peeters 2015-08-10 Approve on 2015-08-14
PS Jenkins bot continuous-integration Approve on 2015-08-14
Review via email: mp+267520@code.launchpad.net

Commit Message

Introducing column configuration into AdaptivePageLayout.

To post a comment you must log in.
Tim Peeters (tpeeters) wrote :

37 + PageColumnsLayout {
38 + when: layout.width > units.gu(80)
39 + PageColumn {
40 + maximumWidth: units.gu(60)
41 + minimumWidth: units.gu(20)
42 + preferredWidth: units.gu(40)
43 + }
44 + PageColumn {
45 + fillWidth: true
46 + }

Why do you set the minimumWidth and maximumWidth here? Do they do anything when preferredWidth, and fillWidth for the other column are set? As I see it that column will always be 40 gu wide.

Tim Peeters (tpeeters) wrote :

48 + // configure single column mode so we can only size it to minimum 20 GU
49 + PageColumnsLayout {
50 + when: true
51 + PageColumn {
52 + minimumWidth: units.gu(20)
53 + fillWidth: true
54 + }
55

I can resize the window to less than 20 GU. I don't know if we can do anything about that in this MR.

Tim Peeters (tpeeters) wrote :

73 + These defaults can be overridden throug the \l layouts property by defining the

throug +h

Tim Peeters (tpeeters) wrote :

75 + be activated. PageColumn configurations must appear in the same order as the
76 + columns appear in the layout, and each column must have a configuration object
77 + assigned.

Perhaps make this "..in the same order (from left to right) as the columns appear..."

"each column must have a configuration object assigned" is not clear to me and should be removed, except if you want to say something important there.

Tim Peeters (tpeeters) wrote :

At the end of the description that I quoted in the previous comment, can you add that the default is one column when none of the specified conditions is fulfilled?

Tim Peeters (tpeeters) wrote :

143 + /*!
144 + The property holds the different layout configurations overriding the default
145 + configurations. Defaults to an empty list.
146 + \sa PageColumnsLayout
147 + */
148 + property list<PageColumnsLayout> layouts

Let's mention the standard layouts that the APL will use when layouts is an empty list.

Tim Peeters (tpeeters) wrote :

254 + property PageColumn metrics: setDefaultMetrics()

getDefaultMetrics() would be a better name for the function.

Tim Peeters (tpeeters) wrote :

308 /*!
309 1-based value identifying the column the metrics to be applied to.
310 + \internal
311 */
312 - property int column
313 + property int __column

"protected" properties are always a bit messy in qml, and this one I think is not needed.

As I can see, the only place where it is used, is here:

    // default metrics
    Component {
        id: defaultMetrics
        PageColumn {
            fillWidth: __column == d.columns
            minimumWidth: d.defaultColumnWidth
        }
    }

in AdaptivePageLayout.

The default metrics is only used when there is no layout with a valid 'when'. So it defaults to defaultMetrics with one column, so fillWidth can always be true.

Tim Peeters (tpeeters) wrote :

Do we want the developer to always to have to explicitly set the preferredWidth for each column?
If not, we could use a usable default like 40gu instead of 0?

338 +
339 + /*!
340 + Specifies the preferred width of the column when the layout is initialized.
341 + Defaults to 0. Unless \l fillWidth is set, the value must be set. AdaptivePageLayout
342 + clamps the given value between \l minimumWidth and \l maximumWidth.
343 + */
344 + property real preferredWidth: 0

Tim Peeters (tpeeters) wrote :

407 + PageColumnsLayout {
408 + when: true
409 + PageColumn {
410 + fillWidth: true
411 + minimumWidth: units.gu(10)
412 + }
413 + }

the example in AdaptivePageLayout docs and PageColumnsLayout are *almost* the same, except in PageColumnsLayout you added the 1-column layout:

            PageColumnsLayout {
                when: true
                PageColumn {
                    fillWidth: true
                    minimumWidth: units.gu(10)
                }
            }

Is this intentional? Maybe we need to show the same example only once? If the default PageColumnLayout does not need to be specified, in the example where you leave it out you could add: // When the condition for the above layout does not match, the default fallback with a single column is used.

Tim Peeters (tpeeters) wrote :

In PageColumnsLayout docs, we should add that when none of the when properties evaluate to true, there is a fallback of a single column.

Tim Peeters (tpeeters) wrote :

461 + default property alias data: layout.__data
462 + property list<PageColumn> __data//: [PageColumn{}]

can we avoid to expose __data by wrapping it in another QtObject?

Tim Peeters (tpeeters) wrote :

542 +import QtQuick 2.4
543 +import QtTest 1.0

isn't QtTest included by Ubuntu.Test?

544 +import Ubuntu.Test 1.0
545 +import Ubuntu.Components 1.3
546 +import QtQuick.Layouts 1.1

Are you using QtQuick.Layouts in the test?

Tim Peeters (tpeeters) wrote :

338 +
339 + /*!
340 + Specifies the preferred width of the column when the layout is initialized.
341 + Defaults to 0. Unless \l fillWidth is set, the value must be set. AdaptivePageLayout
342 + clamps the given value between \l minimumWidth and \l maximumWidth.
343 + */
344 + property real preferredWidth: 0

It seems that it is not true that the value must be set, since in tst_adaptivepagelayout_configuration, there is:

626 + layouts: PageColumnsLayout {
627 + id: defaultLayout
628 + when: layout.width >= units.gu(60)
629 + PageColumn {
630 + minimumWidth: units.gu(40)
631 + maximumWidth: units.gu(40)
632 + }

Tim Peeters (tpeeters) wrote :

I am not totally convinced by the names PageColumnsLayout and PageColumn yet, but I haven't been able to come up with something better..

Zsombor Egri (zsombi) wrote :

> 37 + PageColumnsLayout {
> 38 + when: layout.width > units.gu(80)
> 39 + PageColumn {
> 40 + maximumWidth: units.gu(60)
> 41 + minimumWidth: units.gu(20)
> 42 + preferredWidth: units.gu(40)
> 43 + }
> 44 + PageColumn {
> 45 + fillWidth: true
> 46 + }
>
> Why do you set the minimumWidth and maximumWidth here? Do they do anything
> when preferredWidth, and fillWidth for the other column are set? As I see it
> that column will always be 40 gu wide.

Will be mostly usable when we have the column sizing...I will remove from there for now.

Zsombor Egri (zsombi) wrote :

> 48 + // configure single column mode so we can only size it to
> minimum 20 GU
> 49 + PageColumnsLayout {
> 50 + when: true
> 51 + PageColumn {
> 52 + minimumWidth: units.gu(20)
> 53 + fillWidth: true
> 54 + }
> 55
>
> I can resize the window to less than 20 GU. I don't know if we can do anything
> about that in this MR.

Yes, but if you check the content won't be sized less than 20GU. Btw, in the original, the window content does';t size less than 40GU... So this actually does something in this MR already!

Zsombor Egri (zsombi) wrote :

> 143 + /*!
> 144 + The property holds the different layout configurations
> overriding the default
> 145 + configurations. Defaults to an empty list.
> 146 + \sa PageColumnsLayout
> 147 + */
> 148 + property list<PageColumnsLayout> layouts
>
> Let's mention the standard layouts that the APL will use when layouts is an
> empty list.

It si mentioned in the component description.

Zsombor Egri (zsombi) wrote :

> 254 + property PageColumn metrics: setDefaultMetrics()
>
> getDefaultMetrics() would be a better name for the function.

I didn't wanted to change everything... but yes, I can do that.

Zsombor Egri (zsombi) wrote :

> 308 /*!
> 309 1-based value identifying the column the metrics to be applied
> to.
> 310 + \internal
> 311 */
> 312 - property int column
> 313 + property int __column
>
> "protected" properties are always a bit messy in qml, and this one I think is
> not needed.

Actually it is needed in the code below.

>
> As I can see, the only place where it is used, is here:
>
> // default metrics
> Component {
> id: defaultMetrics
> PageColumn {
> fillWidth: __column == d.columns
> minimumWidth: d.defaultColumnWidth
> }
> }
>
> in AdaptivePageLayout.
>
> The default metrics is only used when there is no layout with a valid 'when'.
> So it defaults to defaultMetrics with one column, so fillWidth can always be
> true.

No, this is also used when there's no layout there, so then both columns are using this. If both columns would fillWidth, they would proportionally resize when you resize the window. So it is needed.

Tim Peeters (tpeeters) wrote :

> > 48 + // configure single column mode so we can only size it
> to
> > minimum 20 GU
> > 49 + PageColumnsLayout {
> > 50 + when: true
> > 51 + PageColumn {
> > 52 + minimumWidth: units.gu(20)
> > 53 + fillWidth: true
> > 54 + }
> > 55
> >
> > I can resize the window to less than 20 GU. I don't know if we can do
> anything
> > about that in this MR.
>
> Yes, but if you check the content won't be sized less than 20GU. Btw, in the
> original, the window content does';t size less than 40GU... So this actually
> does something in this MR already!

Right. And Christian has a fix for it already :) https://code.launchpad.net/~ubuntu-sdk-team/ubuntu-ui-toolkit/minimumGallery/+merge/267548

Zsombor Egri (zsombi) wrote :

> Do we want the developer to always to have to explicitly set the
> preferredWidth for each column?
> If not, we could use a usable default like 40gu instead of 0?

If you read further, if you set minimumWidth, the preferredWidth will be clamped between mn and max automatically. So if it's 0, the minimum will be taken. This will be needed when resizable column comes anyway. So dev must then set min and max in order to avoid resizing.

But perhaps we can have 40GU, I don't have any specific requirement, if the min & max < preferred, the preferred will be clamped, but then you never know to which, min or max. If it is 0, then it will always take the min.
>
> 338 +
> 339 + /*!
> 340 + Specifies the preferred width of the column when the layout is
> initialized.
> 341 + Defaults to 0. Unless \l fillWidth is set, the value must be
> set. AdaptivePageLayout
> 342 + clamps the given value between \l minimumWidth and \l
> maximumWidth.
> 343 + */
> 344 + property real preferredWidth: 0

Zsombor Egri (zsombi) wrote :

> 407 + PageColumnsLayout {
> 408 + when: true
> 409 + PageColumn {
> 410 + fillWidth: true
> 411 + minimumWidth: units.gu(10)
> 412 + }
> 413 + }
>
> the example in AdaptivePageLayout docs and PageColumnsLayout are *almost* the
> same, except in PageColumnsLayout you added the 1-column layout:
>
> PageColumnsLayout {
> when: true
> PageColumn {
> fillWidth: true
> minimumWidth: units.gu(10)
> }
> }
>
> Is this intentional? Maybe we need to show the same example only once? If the
> default PageColumnLayout does not need to be specified, in the example where
> you leave it out you could add: // When the condition for the above layout
> does not match, the default fallback with a single column is used.

Yes, it is. It explains after the example.

Zsombor Egri (zsombi) wrote :

> 461 + default property alias data: layout.__data
> 462 + property list<PageColumn> __data//: [PageColumn{}]
>
> can we avoid to expose __data by wrapping it in another QtObject?
And we loose performance? Doesn't make any sense. Perhaps we move all these to c++, it's lot easier/nicer.

Zsombor Egri (zsombi) wrote :

> 542 +import QtQuick 2.4
> 543 +import QtTest 1.0
>
> isn't QtTest included by Ubuntu.Test?

QtQuick 2.4 is also included in Ubuntu.Components, buut that doesn't mean it exposes all QtQuick APIs... same applies here... haven't you noticed so far?
>
> 544 +import Ubuntu.Test 1.0
> 545 +import Ubuntu.Components 1.3
> 546 +import QtQuick.Layouts 1.1
>
> Are you using QtQuick.Layouts in the test?

Yes, you should read further...

Zsombor Egri (zsombi) wrote :

> 338 +
> 339 + /*!
> 340 + Specifies the preferred width of the column when the layout is
> initialized.
> 341 + Defaults to 0. Unless \l fillWidth is set, the value must be
> set. AdaptivePageLayout
> 342 + clamps the given value between \l minimumWidth and \l
> maximumWidth.
> 343 + */
> 344 + property real preferredWidth: 0
>
> It seems that it is not true that the value must be set, since in
> tst_adaptivepagelayout_configuration, there is:
>
> 626 + layouts: PageColumnsLayout {
> 627 + id: defaultLayout
> 628 + when: layout.width >= units.gu(60)
> 629 + PageColumn {
> 630 + minimumWidth: units.gu(40)
> 631 + maximumWidth: units.gu(40)
> 632 + }

Right, reformulated.

Zsombor Egri (zsombi) wrote :

> > > 48 + // configure single column mode so we can only size
> it
> > to
> > > minimum 20 GU
> > > 49 + PageColumnsLayout {
> > > 50 + when: true
> > > 51 + PageColumn {
> > > 52 + minimumWidth: units.gu(20)
> > > 53 + fillWidth: true
> > > 54 + }
> > > 55
> > >
> > > I can resize the window to less than 20 GU. I don't know if we can do
> > anything
> > > about that in this MR.
> >
> > Yes, but if you check the content won't be sized less than 20GU. Btw, in the
> > original, the window content does';t size less than 40GU... So this actually
> > does something in this MR already!
>
> Right. And Christian has a fix for it already :) https://code.launchpad.net
> /~ubuntu-sdk-team/ubuntu-ui-toolkit/minimumGallery/+merge/267548

That's not enough! That one really fixes the app size to be less than 40GU. Which is not good.

1604. By Zsombor Egri on 2015-08-12

remove minimum and maximum constraints of the column

1605. By Zsombor Egri on 2015-08-12

typo

1606. By Zsombor Egri on 2015-08-12

specify column ordering

1607. By Zsombor Egri on 2015-08-12

specifying default

1608. By Zsombor Egri on 2015-08-12

specify unmet layout condition

1609. By Zsombor Egri on 2015-08-12

reformulate preferredWidth

1610. By Zsombor Egri on 2015-08-12

staging merge

Tim Peeters (tpeeters) wrote :

/tmp/buildd/ubuntu-ui-toolkit-1.3.1584+15.10.20150730bzr1610pkg0vivid853/src/Ubuntu/Components/1.3/PageColumn.qml:54: warning: Unknown command '\fillWidth'
Makefile:282: recipe for target 'generate_docs' failed
make[4]: *** [generate_docs] Error 1
make[4]: Leaving directory '/tmp/buildd/ubuntu-ui-toolkit-1.3.1584+15.10.20150730bzr1610pkg0vivid853/documentation'
Makefile:260: recipe for target 'html_docs' failed
make[3]: *** [html_docs] Error 2

1611. By Zsombor Egri on 2015-08-14

documentation failure fix

1612. By Zsombor Egri on 2015-08-14

staging sync

Tim Peeters (tpeeters) wrote :

great :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2015-08-12 10:07:45 +0000
3+++ components.api 2015-08-14 05:48:25 +0000
4@@ -82,6 +82,8 @@
5 property bool onScreen
6 property bool running
7 Ubuntu.Components.AdaptivePageLayout 1.3: PageTreeNode
8+ readonly property int columns
9+ readonly property PageColumnsLayout layouts
10 function var addPageToCurrentColumn(var sourcePage, var page, var properties)
11 function var addPageToNextColumn(var sourcePage, var page, var properties)
12 function var removePages(var page)
13@@ -603,6 +605,14 @@
14 property Flickable flickable
15 readonly property PageHeadConfiguration head
16 property string title
17+Ubuntu.Components.PageColumn 1.3: QtObject
18+ property bool fillWidth
19+ property double maximumWidth
20+ property double minimumWidth
21+ property double preferredWidth
22+Ubuntu.Components.PageColumnsLayout 1.3: QtObject
23+ default readonly property PageColumn data
24+ property bool when
25 Ubuntu.Components.PageHeadConfiguration 1.1: Object
26 readonly property Action actions
27 property Action backAction
28
29=== modified file 'examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml'
30--- examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml 2015-08-07 13:48:39 +0000
31+++ examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml 2015-08-14 05:48:25 +0000
32@@ -37,6 +37,26 @@
33 anchors.fill: parent
34 primaryPage: mainPage
35
36+ layouts: [
37+ PageColumnsLayout {
38+ when: layout.width > units.gu(80)
39+ PageColumn {
40+ preferredWidth: units.gu(40)
41+ }
42+ PageColumn {
43+ fillWidth: true
44+ }
45+ },
46+ // configure single column mode so we can only size it to minimum 20 GU
47+ PageColumnsLayout {
48+ when: true
49+ PageColumn {
50+ minimumWidth: units.gu(20)
51+ fillWidth: true
52+ }
53+ }
54+ ]
55+
56 Page {
57 id: mainPage
58 title: "Ubuntu UI Toolkit"
59
60=== modified file 'src/Ubuntu/Components/1.3/AdaptivePageLayout.qml'
61--- src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-07-28 15:04:07 +0000
62+++ src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-08-14 05:48:25 +0000
63@@ -86,6 +86,67 @@
64 AdaptivePageLayout supports adaptive column handling. When the number of columns changes at
65 runtime the pages are automatically rearranged.
66
67+ By default the component splits the layout in two columns when the width of the
68+ layout exceeds 80 grid units. The first column is sized to 40 grid unit width and
69+ the second one to fill the rest of the remaining space. When the 80 grid unit breakpoint
70+ is reached, the component will switch from one column to two, and vice versa.
71+ These defaults can be overridden through the \l layouts property by defining the
72+ possible layouts, their column sizing and the breakpoints when the layouts should
73+ be activated. PageColumn configurations must appear in the same order (from left
74+ to right) as the columns appear in the layout. If none of the layouts condition
75+ is met, a one column layout will be used.
76+
77+ \qml
78+ import QtQuick 2.4
79+ import Ubuntu.Components 1.3
80+
81+ MainView {
82+ width: units.gu(100)
83+ height: units.gu(60)
84+
85+ AdaptivePageLayout {
86+ anchors.fill: parent
87+ primaryPage: page1
88+ layouts: PageColumnsLayout {
89+ when: width > units.gu(80)
90+ // column #0
91+ PageColumn {
92+ minimumWidth: units.gu(30)
93+ maximumWidth: units.gu(60)
94+ preferredWidth: units.gu(40)
95+ }
96+ // column #1
97+ PageColumn {
98+ fillWidth: true
99+ }
100+ }
101+
102+ Page {
103+ id: page1
104+ title: "Main page"
105+ Column {
106+ Button {
107+ text: "Add Page2 above " + page1.title
108+ onClicked: page1.pageStack.addPageToCurrentColumn(page1, page2)
109+ }
110+ Button {
111+ text: "Add Page3 next to " + page1.title
112+ onClicked: page1.pageStack.addPageToNextColumn(page1, page3)
113+ }
114+ }
115+ }
116+ Page {
117+ id: page2
118+ title: "Page #2"
119+ }
120+ Page {
121+ id: page3
122+ title: "Page #3"
123+ }
124+ }
125+ }
126+ \endqml
127+
128 \sa PageStack
129 */
130
131@@ -113,6 +174,20 @@
132 property Page primaryPage
133
134 /*!
135+ \qmlproperty int columns
136+ \readonly
137+ The property holds the number of columns shown in the layout.
138+ */
139+ readonly property alias columns: d.columns
140+
141+ /*!
142+ The property holds the different layout configurations overriding the default
143+ configurations. Defaults to an empty list.
144+ \sa PageColumnsLayout
145+ */
146+ property list<PageColumnsLayout> layouts
147+
148+ /*!
149 \qmlmethod Item addPageToCurrentColumn(Item sourcePage, var page[, var properties])
150 Adds a \c page to the column the \c sourcePage resides in and removes all pages
151 from the higher columns. \c page can be a Component or a file.
152@@ -168,7 +243,12 @@
153 */
154
155 Component.onCompleted: {
156- d.relayout();
157+ // check layout configuration
158+ if (layouts.length > 0) {
159+ d.prepareLayouts();
160+ } else {
161+ d.relayout();
162+ }
163 d.completed = true;
164 if (primaryPage) {
165 var wrapper = d.createWrapper(primaryPage);
166@@ -183,6 +263,13 @@
167 return;
168 }
169 }
170+ onLayoutsChanged: {
171+ if (d.completed) {
172+ // only deal with this if the layouts array changes after completion
173+ // to avoid unnecessary rendering
174+ d.prepareLayouts();
175+ }
176+ }
177
178 QtObject {
179 id: d
180@@ -190,7 +277,12 @@
181 property bool completed: false
182 property var tree: new Tree.Tree()
183
184- property int columns: layout.width >= units.gu(80) ? 2 : 1
185+ property int columns: !layout.layouts.length ?
186+ (layout.width >= units.gu(80) ? 2 : 1) :
187+ (activeLayout ? activeLayout.data.length : 1)
188+ property PageColumnsLayout activeLayout: null
189+ property list<PageColumnsLayout> prevLayouts
190+
191 /*! internal */
192 onColumnsChanged: {
193 if (columns <= 0) {
194@@ -201,7 +293,6 @@
195 }
196 property real defaultColumnWidth: units.gu(40)
197 onDefaultColumnWidthChanged: body.applyMetrics()
198- property list<ColumnMetrics> columnMetrics
199
200 function createWrapper(page, properties) {
201 var wrapperComponent = Qt.createComponent("PageWrapper.qml");
202@@ -301,6 +392,33 @@
203 }
204 }
205
206+ // prepares layout management, listens on layout condition changes and performs re-layouting
207+ function prepareLayouts() {
208+ // disconnect from the previous layouts
209+ for (var i = 0; i < prevLayouts.length; i++) {
210+ prevLayouts[i].whenChanged.disconnect(updateLayout);
211+ }
212+ prevLayouts = layouts;
213+ for (var i = 0; i < layouts.length; i++) {
214+ layouts[i].whenChanged.connect(updateLayout);
215+ }
216+ // first time evaluation
217+ updateLayout();
218+ }
219+
220+ // function called when one of the layout condition is satisfied
221+ function updateLayout() {
222+ var newLayout = null;
223+ for (var i = 0; i < layouts.length; i++) {
224+ // get the first affirmative condition
225+ if (layouts[i].when) {
226+ newLayout = layouts[i];
227+ break;
228+ }
229+ }
230+ d.activeLayout = newLayout;
231+ }
232+
233 // relayouts when column count changes
234 function relayout() {
235 if (body.children.length == d.columns) return;
236@@ -357,8 +475,8 @@
237 // default metrics
238 Component {
239 id: defaultMetrics
240- ColumnMetrics {
241- fillWidth: column == d.columns
242+ PageColumn {
243+ fillWidth: __column == d.columns
244 minimumWidth: d.defaultColumnWidth
245 }
246 }
247@@ -376,13 +494,11 @@
248 property PageWrapper pageWrapper
249 property int column
250 property alias config: subHeader.config
251- property ColumnMetrics metrics: setDefaultMetrics()
252+ property PageColumn metrics: getDefaultMetrics()
253
254 Layout.fillWidth: metrics.fillWidth
255 Layout.fillHeight: true
256- Layout.preferredWidth: metrics.maximumWidth > 0 ?
257- MathUtils.clamp(d.defaultColumnWidth, metrics.minimumWidth, metrics.maximumWidth) :
258- d.defaultColumnWidth
259+ Layout.preferredWidth: MathUtils.clamp(metrics.preferredWidth, metrics.minimumWidth, metrics.maximumWidth)
260 Layout.minimumWidth: metrics.minimumWidth
261 Layout.maximumWidth: metrics.maximumWidth
262
263@@ -488,9 +604,9 @@
264 return wrapper;
265 }
266
267- function setDefaultMetrics() {
268+ function getDefaultMetrics() {
269 var result = defaultMetrics.createObject(holder);
270- result.column = Qt.binding(function() { return holder.column + 1; });
271+ result.__column = Qt.binding(function() { return holder.column + 1; });
272 return result;
273 }
274 }
275@@ -545,15 +661,9 @@
276 for (var i = 0; i < children.length; i++) {
277 var holder = children[i];
278 // search for the column metrics
279- var metrics = null;
280- for (var j = 0; j < d.columnMetrics.length; j++) {
281- if (d.columnMetrics[j].column == (i + 1)) {
282- metrics = d.columnMetrics[j];
283- break;
284- }
285- }
286+ var metrics = d.activeLayout ? d.activeLayout.data[i] : null;
287 if (!metrics) {
288- metrics = holder.setDefaultMetrics();
289+ metrics = holder.getDefaultMetrics();
290 }
291 holder.metrics = metrics;
292 updateHeaderHeight(0);
293
294=== renamed file 'src/Ubuntu/Components/1.3/ColumnMetrics.qml' => 'src/Ubuntu/Components/1.3/PageColumn.qml'
295--- src/Ubuntu/Components/1.3/ColumnMetrics.qml 2015-06-24 16:16:13 +0000
296+++ src/Ubuntu/Components/1.3/PageColumn.qml 2015-08-14 05:48:25 +0000
297@@ -17,37 +17,42 @@
298 import QtQuick 2.4
299
300 /*!
301- \qmltype ColumnMetrics
302+ \qmltype PageColumn
303 \inqmlmodule Ubuntu.Components 1.3
304 \since Ubuntu.Components 1.3
305 \ingroup ubuntu
306- \brief Component configuring the metrics of a column in MultiColumnView.
307- \internal
308+ \brief Component configuring the metrics of a column in AdaptivePageLayout.
309
310 */
311 QtObject {
312 /*!
313 1-based value identifying the column the metrics to be applied to.
314+ \internal
315 */
316- property int column
317+ property int __column
318
319 /*!
320 Specifies whether the width of the column should fill the available space
321- of the MultiColumnView column or not. Defaults to \a false.
322+ of the AdaptivePageLayout column or not. Defaults to \a false.
323 */
324 property bool fillWidth: false
325
326 /*!
327- Specifies the minimum width of the column. If the value is greater than
328- \b MultiColumnView::defaultColumnWidth, the value will be set as width for
329- the column.
330+ Specifies the minimum width of the column. Defaults to 0.
331 */
332 property real minimumWidth: 0
333
334 /*!
335- Specifies the maximum width of the column. If the value is smaller than
336- \b MultiColumnView::defaultColumnWidth, the value will be set as width for
337- the column. A maximum value of 0 will be ignored.
338+ Specifies the maximum width of the column. A maximum value of 0 will be ignored.
339+ Defaults to the maximum positive value.
340 */
341 property real maximumWidth: Number.POSITIVE_INFINITY
342+
343+ /*!
344+ Specifies the preferred width of the column when the layout is initialized.
345+ Defaults to 0. AdaptivePageLayout clamps the given value between \l minimumWidth
346+ and \l maximumWidth. The value must be set if the \l fillWidth and \l minimumWidth
347+ are not set.
348+ */
349+ property real preferredWidth: 0
350 }
351
352=== added file 'src/Ubuntu/Components/1.3/PageColumnsLayout.qml'
353--- src/Ubuntu/Components/1.3/PageColumnsLayout.qml 1970-01-01 00:00:00 +0000
354+++ src/Ubuntu/Components/1.3/PageColumnsLayout.qml 2015-08-14 05:48:25 +0000
355@@ -0,0 +1,115 @@
356+/*
357+ * Copyright 2015 Canonical Ltd.
358+ *
359+ * This program is free software; you can redistribute it and/or modify
360+ * it under the terms of the GNU Lesser General Public License as published by
361+ * the Free Software Foundation; version 3.
362+ *
363+ * This program is distributed in the hope that it will be useful,
364+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
365+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
366+ * GNU Lesser General Public License for more details.
367+ *
368+ * You should have received a copy of the GNU Lesser General Public License
369+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
370+ */
371+
372+import QtQuick 2.4
373+
374+/*!
375+ \qmltype PageColumnsLayout
376+ \inqmlmodule Ubuntu.Components 1.3
377+ \since Ubuntu.Components 1.3
378+ \ingroup ubuntu
379+ \brief Component configuring a layout in an AdaptivePageLayout component.
380+
381+ The component specifies the column configuration of a specific layout. The layout
382+ will have as many columns as many PageColumn elements will be declared. The layout
383+ will be activated when the \l when property evaluates to \c true. There can be
384+ many layouts evaluated to true, only the first one evaluated to true in the
385+ \l AdaptivePageLayout::layouts list will be activated.
386+
387+ \qml
388+ import QtQuick 2.4
389+ import Ubuntu.Components 1.3
390+
391+ MainView {
392+ width: units.gu(100)
393+ height: units.gu(60)
394+
395+ AdaptivePageLayout {
396+ anchors.fill: parent
397+ primaryPage: page1
398+ layouts: [
399+ PageColumnsLayout {
400+ when: width > units.gu(80)
401+ // column #0
402+ PageColumn {
403+ minimumWidth: units.gu(30)
404+ maximumWidth: units.gu(60)
405+ preferredWidth: units.gu(40)
406+ }
407+ // column #1
408+ PageColumn {
409+ fillWidth: true
410+ }
411+ },
412+ PageColumnsLayout {
413+ when: true
414+ PageColumn {
415+ fillWidth: true
416+ minimumWidth: units.gu(10)
417+ }
418+ }
419+ ]
420+
421+ Page {
422+ id: page1
423+ title: "Main page"
424+ Column {
425+ Button {
426+ text: "Add Page2 above " + page1.title
427+ onClicked: page1.pageStack.addPageToCurrentColumn(page1, page2)
428+ }
429+ Button {
430+ text: "Add Page3 next to " + page1.title
431+ onClicked: page1.pageStack.addPageToNextColumn(page1, page3)
432+ }
433+ }
434+ }
435+ Page {
436+ id: page2
437+ title: "Page #2"
438+ }
439+ Page {
440+ id: page3
441+ title: "Page #3"
442+ }
443+ }
444+ }
445+ \endqml
446+ In the example above the second PageColumnLayout's condition is always set to
447+ true, which means that that the layout will be always active unless the first
448+ layout's condition evaluates to true. The layout overrides the single column
449+ minimumWidth default value. Note that \l PageColumn::fillWidth must be also set.
450+
451+ \note When none of the conditions is met, a single column layout will be used.
452+
453+ \sa PageColumn
454+ */
455+QtObject {
456+ id: layout
457+
458+ /*!
459+ Condition activating the layout. Defaults to false.
460+ */
461+ property bool when: false
462+
463+ /*!
464+ \qmlproperty list<PageColumn> data
465+ \default
466+ Default property holding the PageColumn elements configuring each column.
467+ */
468+ default property alias data: layout.__data
469+ property list<PageColumn> __data
470+}
471
472=== modified file 'src/Ubuntu/Components/ComponentModule.pro'
473--- src/Ubuntu/Components/ComponentModule.pro 2015-07-29 10:12:07 +0000
474+++ src/Ubuntu/Components/ComponentModule.pro 2015-08-14 05:48:25 +0000
475@@ -92,7 +92,6 @@
476 1.3/Button.qml \
477 1.3/Captions.qml \
478 1.3/CheckBox.qml \
479- 1.3/ColumnMetrics.qml \
480 1.3/ComboButton.qml \
481 1.3/CrossFadeImage.qml \
482 1.3/dateUtils.js \
483@@ -137,7 +136,9 @@
484 1.3/UbuntuListView.qml \
485 1.3/UbuntuNumberAnimation.qml \
486 1.3/ListItemPopover.qml \
487- 1.3/BottomEdgeHint.qml
488+ 1.3/BottomEdgeHint.qml \
489+ 1.3/PageColumn.qml \
490+ 1.3/PageColumnsLayout.qml
491
492 OTHER_FILES+= 1.3/CrossFadeImage.qdoc \
493 1.3/UbuntuListView11.qdoc \
494
495=== modified file 'src/Ubuntu/Components/qmldir'
496--- src/Ubuntu/Components/qmldir 2015-07-28 15:04:07 +0000
497+++ src/Ubuntu/Components/qmldir 2015-08-14 05:48:25 +0000
498@@ -108,6 +108,8 @@
499 ActionItem 1.3 1.3/ActionItem.qml
500 ActionList 1.3 1.3/ActionList.qml
501 AdaptivePageLayout 1.3 1.3/AdaptivePageLayout.qml
502+PageColumnsLayout 1.3 1.3/PageColumnsLayout.qml
503+PageColumn 1.3 1.3/PageColumn.qml
504 ToolbarItems 1.3 1.3/ToolbarItems.qml
505 ToolbarButton 1.3 1.3/ToolbarButton.qml
506 MainView 1.3 1.3/MainView.qml
507@@ -142,7 +144,6 @@
508 PullToRefresh 1.3 1.3/PullToRefresh.qml
509 UbuntuListView 1.3 1.3/UbuntuListView11.qml
510 Captions 1.3 1.3/Captions.qml
511-internal ColumnMetrics 1.3/ColumnMetrics.qml
512 MathUtils 1.3 1.3/mathUtils.js
513 internal ColorUtils 1.3/colorUtils.js
514 DateUtils 1.3 1.3/dateUtils.js
515
516=== modified file 'tests/unit_x11/tst_components/tst_adaptivepagelayout.qml'
517--- tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2015-07-29 12:04:44 +0000
518+++ tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2015-08-14 05:48:25 +0000
519@@ -88,6 +88,8 @@
520
521 function test_0_API() {
522 compare(defaults.primaryPage, null, "primaryPage not null by default");
523+ compare(defaults.layouts.length, 0, "no layouts by default");
524+ compare(defaults.columns, 1, "1 column as default");
525 }
526
527 function test_zzz_change_primaryPage() {
528
529=== added file 'tests/unit_x11/tst_components/tst_adaptivepagelayout_configuration.qml'
530--- tests/unit_x11/tst_components/tst_adaptivepagelayout_configuration.qml 1970-01-01 00:00:00 +0000
531+++ tests/unit_x11/tst_components/tst_adaptivepagelayout_configuration.qml 2015-08-14 05:48:25 +0000
532@@ -0,0 +1,210 @@
533+/*
534+ * Copyright 2015 Canonical Ltd.
535+ *
536+ * This program is free software; you can redistribute it and/or modify
537+ * it under the terms of the GNU Lesser General Public License as published by
538+ * the Free Software Foundation; version 3.
539+ *
540+ * This program is distributed in the hope that it will be useful,
541+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
542+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
543+ * GNU Lesser General Public License for more details.
544+ *
545+ * You should have received a copy of the GNU Lesser General Public License
546+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
547+ */
548+
549+import QtQuick 2.4
550+import QtTest 1.0
551+import Ubuntu.Test 1.0
552+import Ubuntu.Components 1.3
553+import QtQuick.Layouts 1.1
554+
555+MainView {
556+ id: root
557+ width: units.gu(120)
558+ height: units.gu(71)
559+
560+ property list<PageColumnsLayout> dynamicLayout: [
561+ PageColumnsLayout {
562+ when: layout.width >= units.gu(80)
563+ PageColumn {
564+ maximumWidth: units.gu(30)
565+ preferredWidth: units.gu(25)
566+ }
567+ PageColumn {
568+ fillWidth: true
569+ }
570+ PageColumn {
571+ preferredWidth: units.gu(20)
572+ fillWidth: true
573+ }
574+ },
575+ PageColumnsLayout {
576+ when: layout.width >= units.gu(30)
577+ PageColumn {
578+ maximumWidth: units.gu(30)
579+ preferredWidth: units.gu(25)
580+ }
581+ PageColumn {
582+ fillWidth: true
583+ }
584+ },
585+ PageColumnsLayout {
586+ when: true
587+ PageColumn {
588+ fillWidth: true
589+ minimumWidth: units.gu(20)
590+ }
591+ }
592+ ]
593+ property list<PageColumnsLayout> dynamicLayoutWrongOrder: [
594+ PageColumnsLayout {
595+ when: layout.width >= units.gu(30)
596+ PageColumn {
597+ maximumWidth: units.gu(30)
598+ preferredWidth: units.gu(25)
599+ }
600+ PageColumn {
601+ fillWidth: true
602+ }
603+ },
604+ PageColumnsLayout {
605+ when: layout.width >= units.gu(80)
606+ PageColumn {
607+ maximumWidth: units.gu(30)
608+ preferredWidth: units.gu(25)
609+ }
610+ PageColumn {
611+ fillWidth: true
612+ }
613+ PageColumn {
614+ preferredWidth: units.gu(20)
615+ fillWidth: true
616+ }
617+ },
618+ PageColumnsLayout {
619+ when: true
620+ PageColumn {
621+ fillWidth: true
622+ minimumWidth: units.gu(20)
623+ }
624+ }
625+ ]
626+
627+ AdaptivePageLayout {
628+ id: layout
629+ width: parent.width
630+ height: parent.height
631+
632+ primaryPage: page1
633+ layouts: PageColumnsLayout {
634+ id: defaultLayout
635+ when: layout.width >= units.gu(60)
636+ PageColumn {
637+ minimumWidth: units.gu(40)
638+ maximumWidth: units.gu(40)
639+ }
640+ PageColumn {
641+ fillWidth: true
642+ }
643+ }
644+
645+ Page {
646+ id: page1
647+ title: "Page1"
648+
649+ Column {
650+ anchors.centerIn: parent
651+ width: childrenRect.width
652+ Button {
653+ text: "Page 2 left"
654+ onTriggered: layout.addPageToCurrentColumn(page1, page2)
655+ }
656+ Button {
657+ text: "Page 3 right"
658+ onTriggered: layout.addPageToNextColumn(page1, page3);
659+ }
660+ }
661+ }
662+ Page {
663+ id: page2
664+ title: "Page2"
665+ }
666+ Page {
667+ id: page3
668+ title: "Page3"
669+ }
670+ Page {
671+ id: page4
672+ title: "Page4"
673+ }
674+ }
675+
676+ UbuntuTestCase {
677+ when: windowShown
678+
679+ function cleanup() {
680+ layout.layouts = defaultLayout;
681+ layout.width = root.width;
682+ waitForRendering(layout, 400);
683+ }
684+
685+ function test_columns_data() {
686+ return [
687+ {tag: "one column", width: units.gu(59), columns: 1},
688+ {tag: "two columns", width: units.gu(60), columns: 2},
689+ ];
690+ }
691+ function test_columns(data) {
692+ layout.width = data.width;
693+ compare(layout.columns, data.columns, "the number of columns is wrong");
694+ }
695+
696+ function test_update_layout_data() {
697+ return [
698+ {tag: "2 columns, proper order", width: units.gu(30), layout: dynamicLayout, columns: 2},
699+ {tag: "3 columns, proper order", width: units.gu(80), layout: dynamicLayout, columns: 3},
700+ {tag: "1 column, proper order", width: units.gu(29), layout: dynamicLayout, columns: 1},
701+ {tag: "2 columns, wrong order", width: units.gu(30), layout: dynamicLayoutWrongOrder, columns: 2},
702+ {tag: "2 columns, wrong order", width: units.gu(80), layout: dynamicLayoutWrongOrder, columns: 2},
703+ {tag: "1 column, wrong order", width: units.gu(29), layout: dynamicLayout, columns: 1},
704+ ];
705+ }
706+ function test_update_layout(data) {
707+ layout.layouts = data.layout;
708+ layout.width = data.width;
709+ waitForRendering(layout);
710+ compare(layout.columns, data.columns, "wrong columns in dynamic layout");
711+ }
712+
713+ function test_sizes_data() {
714+ return [
715+ {tag: "1 column sizes, default layout", width: units.gu(50), layout: defaultLayout, columns: 1,
716+ minimumWidths: [units.gu(40)], maximumWidths: [Number.POSITIVE_INFINITY], preferredWidths: [units.gu(40)], fillWidths: [true]},
717+ {tag: "2 column sizes, default layout", width: units.gu(60), layout: defaultLayout, columns: 2,
718+ minimumWidths: [units.gu(40), 0], maximumWidths: [units.gu(40), Number.POSITIVE_INFINITY], preferredWidths: [units.gu(40), 0], fillWidths: [false, true]},
719+ {tag: "2 column sizes, custom layout", width: units.gu(30), layout: dynamicLayout, columns: 2,
720+ minimumWidths: [0, 0], maximumWidths: [units.gu(30), Number.POSITIVE_INFINITY], preferredWidths: [units.gu(25), 0], fillWidths: [false, true]},
721+ {tag: "3 column sizes, custom layout", width: units.gu(80), layout: dynamicLayout, columns: 3,
722+ minimumWidths: [0, 0, 0], maximumWidths: [units.gu(30), Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY], preferredWidths: [units.gu(25), 0, units.gu(20)], fillWidths: [false, true, true]},
723+ {tag: "1 column sizes, custom layout", width: units.gu(29), layout: dynamicLayout, columns: 1,
724+ minimumWidths: [units.gu(20)], maximumWidths: [Number.POSITIVE_INFINITY], preferredWidths: [units.gu(20)], fillWidths: [true]},
725+ ];
726+ }
727+ function test_sizes(data) {
728+ layout.layouts = data.layout;
729+ layout.width = data.width;
730+ waitForRendering(layout);
731+ compare(layout.columns, data.columns, "columns mismatch");
732+ for (var i = 0; i < data.columns; i++) {
733+ var holder = findChild(layout, "ColumnHolder" + i);
734+ verify(holder, "Column #" + i + " not found");
735+ compare(holder.Layout.minimumWidth, data.minimumWidths[i], "minimum width mismatch for column #" + i);
736+ compare(holder.Layout.maximumWidth, data.maximumWidths[i], "maximum width mismatch for column #" + i);
737+ compare(holder.Layout.preferredWidth, data.preferredWidths[i], "preferred width mismatch for column #" + i);
738+ compare(holder.Layout.fillWidth, data.fillWidths[i], "fillWidth mismatch for column #" + i);
739+ }
740+ }
741+ }
742+}

Subscribers

People subscribed via source and target branches