summaryrefslogtreecommitdiff
path: root/doc/src/declarative/focus.qdoc
blob: bb54852eb1f05aec927d4fd9f1e90442358ef774 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*!
\target qmlfocus
\page qmlfocus.html
\title Fluid UI Keyboard Focus 

When a key is pressed or released, a key event is generated and delivered to the
focused fluid UI \l Item.  To facilitate the construction of reusable components
and to address some of the cases unique to fluid UIs, the fluid UI atoms add a 
"realm" based extension to Qt's traditional keyboard focus model.

\section1 Key Handling Overview

When the user presses or releases a key, the following occurs:
\list 1
\o Qt receives the key action and generates a key event.
\o If the Qt widget containing the fluid UI scene has focus, the key event is delivered to the fluid UI scene.  Otherwise, regular Qt key handling continues.
\o The key event is delivered by the scene to the fluid UI \l Item with \e {active focus}.  If no fluid UI \l Item has \e {active focus}, the key event is \l {QEvent::ignore()}{ignored} and regular Qt key handling continues.
\o If the fluid UI \l Item with \e {active focus} accepts the key event, propagation stops.  Otherwise the event is "bubbled up", by recursively passing it to each \l Item's parent until either the event is accepted, or the root \l Item is reached.

If the \c {Rect} element in the following example has active focus and the \e A key is pressed, it will bubble up to the \c {KeyActions}.  However, pressing the \e B key will bubble up to the root item and thus subsequently be \l {QEvent::ignore()}{ignored}.

\code
Item {
    KeyActions {
        keyA: "print('Key A was pressed')"
        Rect {}
    }
}
\endcode

\o If the root \l Item is reached, the key event is \l {QEvent::ignore()}{ignored} and regular Qt key handling continues.

\endlist

\section1 Querying the Active Focus Item

Whether or not an \l Item has \e {active focus} can be queried through the 
read-only property \c {Item::activeFocus}.  For example, here we have a \l Text
element whose text is determined by whether or not it has \e {active focus}.

\code
Text {
    text: activeFocus ? "I have active focus!" : "I do not have active focus"
}
\endcode

\section1 Acquiring Focus and Focus Realms

An \l Item requests focus by setting the \c {Item::focus} property to true.  

For very simple cases simply setting the \c {Item::focus} property is sometimes
sufficient.  If we run the following example in the \c qmlviewer, we see that
the \c {<KeyActions/>} element has \e {active focus} and pressing the
\e A, \e B, or \e C keys modifies the text appropriately.

\table
\row
\o \code
    Rect {
        color: "lightsteelblue"; width: 240; height: 25
        Text { id: MyText }
        KeyActions {
            focus: true
            keyA: "MyText.text = 'Key A was pressed'"
            keyB: "MyText.text = 'Key B was pressed'"
            keyC: "MyText.text = 'Key C was pressed'"
        }
    }
\endcode
\o \image declarative-qmlfocus1.png
\endtable

However, were the above example to be used as a self-contained component, this
simple use of the \c {Item::focus} property is no longer sufficient.  The left
hand side of the following table shows what we would like to be able to write.
Here we create two instances of our previously defined component, and set the
second one to have focus.  The intention is that when the \e A, \e B, or \e C 
keys are pressed, the second of the two components receives the event and 
reponds accordingly.

\table
\row
\o \code
Rect {
    color: "red"; width: 240; height: 55
    MyWidget {}
    MyWidget { y: 30; focus: true }
}
\endcode
\o \code
Rect {
    color: "red"; width: 240; height: 55
    Rect {
        color: "lightsteelblue"; width: 240; height: 25
        Text { id: MyText }
        KeyActions {
            focus: true
            keyA: "MyText.text = 'Key A was pressed'"
            keyB: "MyText.text = 'Key B was pressed'"
            keyC: "MyText.text = 'Key C was pressed'"
        }
    }
    Rect {
        y: 30; focus: true
        color: "lightsteelblue"; width: 240; height: 25
        Text { id: MyText }
        KeyActions {
            focus: true
            keyA: "MyText.text = 'Key A was pressed'"
            keyB: "MyText.text = 'Key B was pressed'"
            keyC: "MyText.text = 'Key C was pressed'"
        }
    }
}
\endcode
\endtable

The right hand side of the example shows the expanded code - the equivalent QML
without the use of the component \c {MyWidget}.  From this, the problem is
evident - there are no less than three elements that have the \c {Item::focus} 
property set to true.  Ultimately only one element can have focus, and the 
system has to decide which on.  In this case the first appearance of the 
\c {Item::focus} property being set to true on line 4 is selected, and the value
of \c {Item::focus} in the other two instances is reverted back to false.  This
is exactly the opposite of what was wanted!

This problem is fundamentally one of visibility.  The \c {MyWidget} 
components each set their \c {KeyActions} as focused as that is all they can
do - they don't know how they are going to be used, but they do know that when
they're in use their \c {KeyActions} element is what needs focus.  Likewise
the code that uses the \c {MyWidget}'s sets the second \c {MyWidget} as
focused because, while it doesn't know exactly how the \c {MyWidget} is 
implemented, it knows that it wants the second one to be focused.  No one piece
of code knows everything about the other, which is exactly how it should be.

To solve this problem - allowing components to care about what they know about
and ignore everything else - the fluid UI atoms introduce a concept known as a 
\e {focus realm}.  For existing Qt users, a \e {focus realm} is like an 
automatic focus proxy.  A \e {focus realm} is created using the \l FocusRealm
element.

In the next example, a \l FocusRealm is added to the component, and the visual
result shown.

\table
\row
\o \code
FocusRealm {
    width: 240; height: 25
    Rect {
        color: "lightsteelblue"; width: 240; height: 25
        Text { id: MyText }
        KeyActions {
            focus: true
            keyA: "MyText.text = 'Key A was pressed'"
            keyB: "MyText.text = 'Key B was pressed'"
            keyC: "MyText.text = 'Key C was pressed'"
        }
    }
}
\endcode
\o \image declarative-qmlfocus2.png
\endtable

Conceptually \e {focus realms} are quite simple.  
\list
\o Within each \e {focus realm} one element may have \c {Item::focus} set to true.  If more than one \l Item has the \c {Item::focus} property set, the first is selected and the others are unset, just like when there are no \e {focus realms}. 
\o When a \e {focus realm} receives \e {active focus}, the contained element with \c {Item::focus} set (if any) also gets \e {active focus}.  If this element is
also a \l FocusRealm, the proxying behaviour continues.  Both the 
\e {focus realm} and the sub-focused item will have \c {Item::activeFocus} set.
\endlist

So far the example has the second component statically selected.  It is trivial
now to extend this component to make it clickable, and add it to the original
application.  We still set a one of the widgets as focused by default, but from
then on clicking the either one gives it focus.

\table
\row 
\o \code
Rect {
    color: "red"; width: 240; height: 55
    MyClickableWidget {}
    MyClickableWidget { y: 30; focus: true }
}
\endcode
\o \code
FocusRealm {
    id: Page; width: 240; height: 25
    MyWidget { focus: true }
    MouseRegion { anchors.fill: parent; onClicked: { Page.focus = true } }
}
\endcode
\endtable

\image declarative-qmlfocus3.png

When a fluid UI atom explicitly relinquishes focus (by setting its 
\c {Item::focus} property to false while it has \e {active focus}), the system 
does not automatically select another element to receive focus.  That is, it
is possible for there to be no currently \e {active focus}.

\section1 Advanced uses of Focus Realms

Focus realms allow focus to allocation to be easily partitioned.  Several 
fluid UI atoms use it to this effect.

\l ListView, for example, is itself a focus realm.  Generally this isn't 
noticable as \l ListView doesn't usually have manually added visual children.
By being a focus realm, \l ListView can focus the current list item without 
worrying about how that will effect the rest of the application.  This allows
the current item delegate to react to key presses.

This contrived example shows how this works.  Pressing the \c Return key will
print the name of the current list item.  

\table
\row
\o \code
Rect {
    color: "lightsteelblue"; width: 240; height: 320

    ListView {
        id: MyView; anchors.fill: parent; focus: true
        model: ListModel {
            ListElement { name: "Bob" }
            ListElement { name: "John" }
            ListElement { name: "Michael" }
        }
        delegate: FocusRealm {
            width: contents.width; height: contents.height
            Text { text: name }
            KeyActions { return: "print(name)"; focus: true }
        }
    }
}
\endcode
\o \image declarative-qmlfocus4.png
\endtable

While the example is simple, there's a lot going on behind the scenes.  Whenever
the current item changes, the \l ListView sets the delegate's \c {Item::focus}
property.  As the \l ListView is a \e {focus realm}, this doesn't effect the 
rest of the application.  However, if the \l ListView itself has 
\e {active focus} this causes the delegate itself to receive \e {active focus}.
In this example, the root element of the delegate is also a \e {focus realm},
which in turn gives \e {active focus} to the \c {<KeyActions/>} element that
actually performs the work of handling the \e {Return} key.

All of the fluid UI view classes, such as \l PathView and \l GridView, behave
in a similar mannor to allow key handling in their respective delegates.

\section1 Focus Panels

Traditional UIs are composed of many top-level windows.  Windows actually 
perform two tasks - they act as the visual bounds for a widget, and they segment
focus.  Each window has a separate focused widget, that becomes (to mix 
terminologies) the \e {active focus} widget when the window is the active 
window.

### Focus panels do basically the same thing.
*/