JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_KeyboardFocusTraverser.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29//==============================================================================
30namespace KeyboardFocusTraverserHelpers
31{
32 static bool isKeyboardFocusable (const Component* comp, const Component* container)
33 {
34 return comp->getWantsKeyboardFocus() && container->isParentOf (comp);
35 }
36
37 static Component* traverse (Component* current, Component* container,
38 detail::FocusHelpers::NavigationDirection direction)
39 {
40 if (auto* comp = detail::FocusHelpers::navigateFocus (current, container, direction,
42 {
43 if (isKeyboardFocusable (comp, container))
44 return comp;
45
46 return traverse (comp, container, direction);
47 }
48
49 return nullptr;
50 }
51}
52
54{
55 return KeyboardFocusTraverserHelpers::traverse (current, current->findKeyboardFocusContainer(),
56 detail::FocusHelpers::NavigationDirection::forwards);
57}
58
60{
61 return KeyboardFocusTraverserHelpers::traverse (current, current->findKeyboardFocusContainer(),
62 detail::FocusHelpers::NavigationDirection::backwards);
63}
64
66{
67 for (auto* comp : getAllComponents (parentComponent))
68 if (KeyboardFocusTraverserHelpers::isKeyboardFocusable (comp, parentComponent))
69 return comp;
70
71 return nullptr;
72}
73
75{
76 std::vector<Component*> components;
77 detail::FocusHelpers::findAllComponents (parentComponent,
78 components,
80
81 auto removePredicate = [parentComponent] (const Component* comp)
82 {
83 return ! KeyboardFocusTraverserHelpers::isKeyboardFocusable (comp, parentComponent);
84 };
85
86 components.erase (std::remove_if (std::begin (components), std::end (components), std::move (removePredicate)),
87 std::end (components));
88
89 return components;
90}
91
92
93//==============================================================================
94//==============================================================================
95#if JUCE_UNIT_TESTS
96
98{
100 : UnitTest ("KeyboardFocusTraverser", UnitTestCategories::gui)
101 {}
102
103 void runTest() override
104 {
105 ScopedJuceInitialiser_GUI libraryInitialiser;
106 const MessageManagerLock mml;
107
108 beginTest ("No child wants keyboard focus");
109 {
110 TestComponent parent;
111
112 expect (traverser.getDefaultComponent (&parent) == nullptr);
113 expect (traverser.getAllComponents (&parent).empty());
114 }
115
116 beginTest ("Single child wants keyboard focus");
117 {
118 TestComponent parent;
119
120 parent.children[5].setWantsKeyboardFocus (true);
121
122 auto* defaultComponent = traverser.getDefaultComponent (&parent);
123
124 expect (defaultComponent == &parent.children[5]);
125 expect (defaultComponent->getWantsKeyboardFocus());
126
127 expect (traverser.getNextComponent (defaultComponent) == nullptr);
128 expect (traverser.getPreviousComponent (defaultComponent) == nullptr);
129 expect (traverser.getAllComponents (&parent).size() == 1);
130 }
131
132 beginTest ("Multiple children want keyboard focus");
133 {
134 TestComponent parent;
135
136 Component* focusChildren[]
137 {
138 &parent.children[1],
139 &parent.children[9],
140 &parent.children[3],
141 &parent.children[5],
142 &parent.children[8],
143 &parent.children[0]
144 };
145
146 for (auto* focusChild : focusChildren)
147 focusChild->setWantsKeyboardFocus (true);
148
149 auto allComponents = traverser.getAllComponents (&parent);
150
151 for (auto* focusChild : focusChildren)
153
154 auto* componentToTest = traverser.getDefaultComponent (&parent);
155
156 for (;;)
157 {
158 expect (componentToTest->getWantsKeyboardFocus());
160
161 componentToTest = traverser.getNextComponent (componentToTest);
162
163 if (componentToTest == nullptr)
164 break;
165 }
166
167 int focusOrder = 1;
168 for (auto* focusChild : focusChildren)
169 focusChild->setExplicitFocusOrder (focusOrder++);
170
171 componentToTest = traverser.getDefaultComponent (&parent);
172
173 for (auto* focusChild : focusChildren)
174 {
175 expect (componentToTest == focusChild);
176 expect (componentToTest->getWantsKeyboardFocus());
177
178 componentToTest = traverser.getNextComponent (componentToTest);
179 }
180 }
181
182 beginTest ("Single nested child wants keyboard focus");
183 {
184 TestComponent parent;
185 Component grandparent;
186
187 grandparent.addAndMakeVisible (parent);
188
189 auto& focusChild = parent.children[5];
190
191 focusChild.setWantsKeyboardFocus (true);
192
193 expect (traverser.getDefaultComponent (&grandparent) == &focusChild);
194 expect (traverser.getDefaultComponent (&parent) == &focusChild);
195 expect (traverser.getNextComponent (&focusChild) == nullptr);
196 expect (traverser.getPreviousComponent (&focusChild) == nullptr);
197 expect (traverser.getAllComponents (&parent).size() == 1);
198 }
199
200 beginTest ("Multiple nested children want keyboard focus");
201 {
202 TestComponent parent;
203 Component grandparent;
204
205 grandparent.addAndMakeVisible (parent);
206
207 Component* focusChildren[]
208 {
209 &parent.children[1],
210 &parent.children[4],
211 &parent.children[5]
212 };
213
214 for (auto* focusChild : focusChildren)
215 focusChild->setWantsKeyboardFocus (true);
216
217 auto allComponents = traverser.getAllComponents (&parent);
218
219 expect (std::equal (allComponents.cbegin(), allComponents.cend(), focusChildren,
220 [] (const Component* c1, const Component* c2) { return c1 == c2; }));
221
222 const auto front = *focusChildren;
223 const auto back = *std::prev (std::end (focusChildren));
224
225 expect (traverser.getDefaultComponent (&grandparent) == front);
226 expect (traverser.getDefaultComponent (&parent) == front);
227 expect (traverser.getNextComponent (front) == *std::next (std::begin (focusChildren)));
228 expect (traverser.getPreviousComponent (back) == *std::prev (std::end (focusChildren), 2));
229
231
232 for (auto& p : otherParents)
233 {
234 grandparent.addAndMakeVisible (p);
235 p.setWantsKeyboardFocus (true);
236 }
237
238 expect (traverser.getDefaultComponent (&grandparent) == front);
239 expect (traverser.getDefaultComponent (&parent) == front);
240 expect (traverser.getNextComponent (back) == &otherParents.front());
241 expect (traverser.getNextComponent (&otherParents.back()) == nullptr);
242 expect (traverser.getAllComponents (&grandparent).size() == numElementsInArray (focusChildren) + otherParents.size());
243 expect (traverser.getAllComponents (&parent).size() == (size_t) numElementsInArray (focusChildren));
244
245 for (auto* focusChild : focusChildren)
246 focusChild->setWantsKeyboardFocus (false);
247
248 expect (traverser.getDefaultComponent (&grandparent) == &otherParents.front());
249 expect (traverser.getDefaultComponent (&parent) == nullptr);
250 expect (traverser.getAllComponents (&grandparent).size() == otherParents.size());
251 expect (traverser.getAllComponents (&parent).empty());
252 }
253 }
254
255private:
256 struct TestComponent final : public Component
257 {
258 TestComponent()
259 {
260 for (auto& child : children)
261 addAndMakeVisible (child);
262 }
263
265 };
266
267 KeyboardFocusTraverser traverser;
268};
269
271
272#endif
273
274} // namespace juce
T begin(T... args)
The base class for all JUCE user-interface objects.
bool isKeyboardFocusContainer() const noexcept
Returns true if this component has been marked as a keyboard focus container.
Component * findKeyboardFocusContainer() const
Returns the keyboard focus container for this component.
Component * getPreviousComponent(Component *current) override
Returns the component that should be given keyboard focus after the specified one when moving "backwa...
std::vector< Component * > getAllComponents(Component *parentComponent) override
Returns all of the components that can receive keyboard focus within the given parent component in tr...
Component * getNextComponent(Component *current) override
Returns the component that should be given keyboard focus after the specified one when moving "forwar...
Component * getDefaultComponent(Component *parentComponent) override
Returns the component that should receive keyboard focus by default within the given parent component...
This is a base class for classes that perform a unit test.
T end(T... args)
T equal(T... args)
T erase(T... args)
T find(T... args)
JUCE Namespace.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
T next(T... args)
T prev(T... args)
T remove_if(T... args)