[Development] [QtQuick] Views Version 2 from Qt CS; animated layout

Shawn Rutledge shawn.t.rutledge at gmail.com
Thu Jul 25 21:49:50 CEST 2013


On 25 July 2013 18:31, Alan Alpert <416365416c at gmail.com> wrote:
> On Thu, Jul 25, 2013 at 12:37 AM, Rutledge Shawn
> <Shawn.Rutledge at digia.com> wrote:
>>
>> On 24 Jul 2013, at 5:45 PM, Alan Alpert wrote:
>>
...
> Have you considered using the Positioner layouts for inspiration? They
> have a similar set of add/move/remove transitions to the view classes,
> and you don't need a special "positioner" property on Item to make use
> of them. Just reparenting items to a different positioner and using an
> add transition is enough for an animated change.

But reparenting is cumbersome: it typically needs to be done via a for
loop in JS, and takes time to run.  So it seems easier to assign a new
layout somewhere.  The loop to "take over" the layout management of
all the items will be in C++ at least.

When you are building a reusable container component of some sort, the
layout is sometimes just an implementation detail that you would
prefer to hide.  But you can't, if every item that you add to the
container is actually added to the layout inside the container
instead; then the items' parents are not the container, even though
the application author declared them that way.  Next thing you know,
you have to tell application authors that they can't trust the parent
property, and should refer to the container by ID.  Or else you have
to give up on layout classes and write the layout logic in JS just to
flatten the containment hierarchy.  For me this points to the
conclusion that layout should be a plug-in behavior rather than trying
to be the container.

> Repeaters have no children

OK you're right; I've forgotten some details since the last time the
problem I'm thinking of came up.  Maybe the problem was that there was
a container component written with the expectation that items would be
directly added to it, but the user put a Repeater inside instead.  The
container had a loop to iterate its children, and then it had to have
an extra test to ignore the repeater (the abnormal child).

The automatic reparenting is still arguably unintuitive.

> Also QtQuick can't depend
> on QtQuick.Layouts, so there's a technical and conceptual problem from
> that too.

That's not a real obstacle though; I can think of more than one way to solve it.

>> The current way is that the items must be children of the layout, so you can't switch layouts without reparenting all of the items.  That way could continue to work for the simple use case: if the layout has children then it will assign them to its own list of items-to-manage.
>
> Sounds like all you need is a convenient reparentAll() mechanism.

It would still be a procedural hackaround.  The more we stick to "what
you declare is what you get", the easier it is for designer tools and
such.

> Does a binding on the children: property work?

A binding to a list, so you can swap them?

> Delegates remembering their own selection state means that you lose
> selection state the moment the item goes offscreen. So that's
> unacceptable in a lot of cases. Selection is also about more than just
> click-to-select, some usecases require selection to be managed or
> controlled externally, which is where having a separate selection
> model that can also be interacted with in C++ (like the existing
> selection models) are ideal.

I agree.

>> Viewport {
>>     id: vp
>>     View {
>>         id: view
>>         model: ...
>>         delegate: Rectangle {
>>             id: del
>>             MouseArea {
>>                 anchors.fill: parent
>>                 onClicked: view.selection.toggle(del)
>>                 drag.target: del
>>             }
>>         }
>>         instantiator: ...
>>         layout: FlowLayout { anchors.fill: parent; spacing ? }
>>         controllers: [
>>             MultipleSelectionArea {
>>                 anchors.fill: view
>>                 target: view.selection
>>             }
>>             FlickArea {
>>                 anchors.fill: vp
>>                 target: vp
>>             }
>>         ]
>>     }
>> }
>>
>> • Every child of the view can see that its parent is the view itself: no interlopers (such as layout or repeater)
>>
>> • The view does NOT contain children other than the ones the user wants to see; so if you iterate the children you won't have to check the type of each
>
> This example does not actually include QQuickItem children at all
> (except that View is a child of the Viewport), making it hard to see
> either point. Any Item level parent relationship is being done custom
> by the View type, or not.

The delegates are not children of the View?  If that was a ListView,
they would be.

>> • There can be multiple controllers, to handle as many behaviors as we like
>
> How do they interact? Like if I specify two FlickAreas with different sizes?

If you mean that there are ways to shoot yourself in the foot, yeah
probably.  If you mean to divide up an item into regions using
multiple FlickAreas, then the events should be delivered to the right
instance based on location.

>> • A Flickable has two roles: it's a viewport, which is why it is normally the view's parent, and it also does the flicking.  This can be split up further as shown, but I'm not sure we gain much from writing the extra declarations.  The View could just have a Flickable as its parent.  But splitting it up like this makes the design principle more consistent: the view hierarchy resembles the scene graph, while the behaviors are implemented by independent controllers which are NOT in the view hierarchy.  The same logic could be extended to the MouseArea: if every Item had a controllers list (or if we had a habit of hiding controllers in the data property), we could say that a controller is never a visual child of an item.
>
> What about interaction items, like MouseArea and MultiPointTouchArea,
> which need to be in the visual hierarchy? It seems like a pointless
> complication to me that "every Item" can take on certain interaction
> behaviors by specifying controllers on it. It's much simpler to have
> those behaviors as separate items, which conceptually simplifies Item
> while also allowing the user greater manual control over the
> interaction of multiple 'controllers'.

Nesting Areas is a trial-and-error affair though.  The photosurface
example happens to work: you can drag items via the MouseArea and also
do pinch zooming and rotation via the PinchArea; but if you nest the
PinchArea and MouseArea the other way, it doesn't work anymore; or if
you stack them in either order it doesn't work.  I wouldn't be
surprised if the present arrangement stopped working or became
cumbersome to keep working at some point.  The example exists so that
we can remember which way is the one that happens to work, but it's
not a good example of how to make declarations in such a way that you
will intuitively understand why it works.

>> • MultipleSelectionArea would handle mouse and touch events which fall on any of the items in its target list, so dragging one drags them all.  If you drag somewhere else on its parent, then it would lasso-select items from the target.
>>
>> • The MultipleSelectionArea could handle slow drags, and the FlickArea could handle quick drags.  They could have minimum/maximumVelocity properties.  Or the MultipleSelectionArea's lasso behavior could be configured to handle mouse events only, not touch events.
>
> How do they communicate? They don't even have a reference to each other,

Events get delivered recursively anyway, so if one area rejects an
event based on velocity or some other property that is out of range,
the other area will get a shot at handling it.  But the list could be
treated as an order of precedence.  (And I'm not sure that's intuitive
enough, either.)  The list of controllers is just a brainstorm, but I
think it will be limiting to say that there is only one controller per
View.

> The problem with splitting them up like this has always been about how
> the communication is managed between components without unacceptable
> overhead. The biggest example being how the Instantiator, Layout and
> ViewPort need to work together to determine which items are on screen
> and need delegates. Might even need to also communicate with the
> controller to preload incoming items while scrolling. If everything
> goes through the View, like it seems to in your example, then it's
> still a big monolithic class that knows everything and we've just
> added more customizability to it (which might be enough, I don't
> know).

Well what architecture did you have in mind?  I wasn't able to be at
QtCS, so sorry if it's asking for too much repetition.  I agree that
decoupling is good.



More information about the Development mailing list