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_FocusTraverser.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//==============================================================================
31{
32 jassert (current != nullptr);
33
34 return detail::FocusHelpers::navigateFocus (current,
35 current->findFocusContainer(),
36 detail::FocusHelpers::NavigationDirection::forwards,
38}
39
41{
42 jassert (current != nullptr);
43
44 return detail::FocusHelpers::navigateFocus (current,
45 current->findFocusContainer(),
46 detail::FocusHelpers::NavigationDirection::backwards,
48}
49
51{
52 if (parentComponent != nullptr)
53 {
54 std::vector<Component*> components;
55 detail::FocusHelpers::findAllComponents (parentComponent,
56 components,
58
59 if (! components.empty())
60 return components.front();
61 }
62
63 return nullptr;
64}
65
67{
68 std::vector<Component*> components;
69 detail::FocusHelpers::findAllComponents (parentComponent,
70 components,
72
73 return components;
74}
75
76//==============================================================================
77//==============================================================================
78#if JUCE_UNIT_TESTS
79
81{
83 : UnitTest ("FocusTraverser", UnitTestCategories::gui)
84 {}
85
86 void runTest() override
87 {
88 ScopedJuceInitialiser_GUI libraryInitialiser;
89 const MessageManagerLock mml;
90
91 beginTest ("Basic traversal");
92 {
93 TestComponent parent;
94
95 expect (traverser.getDefaultComponent (&parent) == &parent.children.front());
96
97 for (auto iter = parent.children.begin(); iter != parent.children.end(); ++iter)
98 expect (traverser.getNextComponent (&(*iter)) == (iter == std::prev (parent.children.cend()) ? nullptr
99 : &(*std::next (iter))));
100
101 for (auto iter = parent.children.rbegin(); iter != parent.children.rend(); ++iter)
102 expect (traverser.getPreviousComponent (&(*iter)) == (iter == std::prev (parent.children.rend()) ? nullptr
103 : &(*std::next (iter))));
104 auto allComponents = traverser.getAllComponents (&parent);
105
106 expect (std::equal (allComponents.cbegin(), allComponents.cend(), parent.children.cbegin(),
107 [] (const Component* c1, const Component& c2) { return c1 == &c2; }));
108 }
109
110 beginTest ("Disabled components are ignored");
111 {
112 checkIgnored ([] (Component& c) { c.setEnabled (false); });
113 }
114
115 beginTest ("Invisible components are ignored");
116 {
117 checkIgnored ([] (Component& c) { c.setVisible (false); });
118 }
119
120 beginTest ("Explicit focus order comes before unspecified");
121 {
122 TestComponent parent;
123
124 auto& explicitFocusComponent = parent.children[2];
125
126 explicitFocusComponent.setExplicitFocusOrder (1);
127 expect (traverser.getDefaultComponent (&parent) == &explicitFocusComponent);
128
129 expect (traverser.getAllComponents (&parent).front() == &explicitFocusComponent);
130 }
131
132 beginTest ("Explicit focus order comparison");
133 {
134 checkComponentProperties ([this] (Component& child) { child.setExplicitFocusOrder (getRandom().nextInt ({ 1, 100 })); },
135 [] (const Component& c1, const Component& c2) { return c1.getExplicitFocusOrder()
136 <= c2.getExplicitFocusOrder(); });
137 }
138
139 beginTest ("Left to right");
140 {
141 checkComponentProperties ([this] (Component& child) { child.setTopLeftPosition (getRandom().nextInt ({ 0, 100 }), 0); },
142 [] (const Component& c1, const Component& c2) { return c1.getX() <= c2.getX(); });
143 }
144
145 beginTest ("Top to bottom");
146 {
147 checkComponentProperties ([this] (Component& child) { child.setTopLeftPosition (0, getRandom().nextInt ({ 0, 100 })); },
148 [] (const Component& c1, const Component& c2) { return c1.getY() <= c2.getY(); });
149 }
150
151 beginTest ("Focus containers have their own focus");
152 {
153 Component root;
154
155 TestComponent container;
156 container.setFocusContainerType (Component::FocusContainerType::focusContainer);
157
158 root.addAndMakeVisible (container);
159
160 expect (traverser.getDefaultComponent (&root) == &container);
161 expect (traverser.getNextComponent (&container) == nullptr);
162 expect (traverser.getPreviousComponent (&container) == nullptr);
163
164 expect (traverser.getDefaultComponent (&container) == &container.children.front());
165
166 for (auto iter = container.children.begin(); iter != container.children.end(); ++iter)
167 expect (traverser.getNextComponent (&(*iter)) == (iter == std::prev (container.children.cend()) ? nullptr
168 : &(*std::next (iter))));
169
170 for (auto iter = container.children.rbegin(); iter != container.children.rend(); ++iter)
171 expect (traverser.getPreviousComponent (&(*iter)) == (iter == std::prev (container.children.rend()) ? nullptr
172 : &(*std::next (iter))));
173
174 expect (traverser.getAllComponents (&root).size() == 1);
175
176 auto allContainerComponents = traverser.getAllComponents (&container);
177
178 expect (std::equal (allContainerComponents.cbegin(), allContainerComponents.cend(), container.children.cbegin(),
179 [] (const Component* c1, const Component& c2) { return c1 == &c2; }));
180 }
181
182 beginTest ("Non-focus containers pass-through focus");
183 {
184 Component root;
185
186 TestComponent container;
187 container.setFocusContainerType (Component::FocusContainerType::none);
188
189 root.addAndMakeVisible (container);
190
191 expect (traverser.getDefaultComponent (&root) == &container);
192 expect (traverser.getNextComponent (&container) == &container.children.front());
193 expect (traverser.getPreviousComponent (&container) == nullptr);
194
195 expect (traverser.getDefaultComponent (&container) == &container.children.front());
196
197 for (auto iter = container.children.begin(); iter != container.children.end(); ++iter)
198 expect (traverser.getNextComponent (&(*iter)) == (iter == std::prev (container.children.cend()) ? nullptr
199 : &(*std::next (iter))));
200
201 for (auto iter = container.children.rbegin(); iter != container.children.rend(); ++iter)
202 expect (traverser.getPreviousComponent (&(*iter)) == (iter == std::prev (container.children.rend()) ? &container
203 : &(*std::next (iter))));
204
205 expect (traverser.getAllComponents (&root).size() == container.children.size() + 1);
206 }
207 }
208
209private:
210 struct TestComponent final : public Component
211 {
212 TestComponent()
213 {
214 for (auto& child : children)
215 addAndMakeVisible (child);
216 }
217
219 };
220
221 void checkComponentProperties (std::function<void (Component&)>&& childFn,
222 std::function<bool (const Component&, const Component&)>&& testProperty)
223 {
224 TestComponent parent;
225
226 for (auto& child : parent.children)
227 childFn (child);
228
229 auto* comp = traverser.getDefaultComponent (&parent);
230
231 for (const auto& child : parent.children)
232 if (&child != comp)
233 expect (testProperty (*comp, child));
234
235 for (;;)
236 {
237 auto* next = traverser.getNextComponent (comp);
238
239 if (next == nullptr)
240 break;
241
242 expect (testProperty (*comp, *next));
243 comp = next;
244 }
245 }
246
247 void checkIgnored (const std::function<void(Component&)>& makeIgnored)
248 {
249 TestComponent parent;
250
251 auto iter = parent.children.begin();
252
253 makeIgnored (*iter);
254 expect (traverser.getDefaultComponent (&parent) == std::addressof (*std::next (iter)));
255
256 iter += 5;
257 makeIgnored (*iter);
258 expect (traverser.getNextComponent (std::addressof (*std::prev (iter))) == std::addressof (*std::next (iter)));
259 expect (traverser.getPreviousComponent (std::addressof (*std::next (iter))) == std::addressof (*std::prev (iter)));
260
261 auto allComponents = traverser.getAllComponents (&parent);
262
263 expect (std::find (allComponents.cbegin(), allComponents.cend(), &parent.children.front()) == allComponents.cend());
264 expect (std::find (allComponents.cbegin(), allComponents.cend(), std::addressof (*iter)) == allComponents.cend());
265 }
266
267 FocusTraverser traverser;
268};
269
271
272#endif
273
274} // namespace juce
T addressof(T... args)
The base class for all JUCE user-interface objects.
Component * findFocusContainer() const
Returns the focus container for this component.
@ none
The component will not act as a focus container.
@ focusContainer
The component will act as a top-level component within which focus is passed around.
bool isFocusContainer() const noexcept
Returns true if this component has been marked as a focus container.
std::vector< Component * > getAllComponents(Component *parentComponent) override
Returns all of the components that can receive focus within the given parent component in traversal o...
Component * getDefaultComponent(Component *parentComponent) override
Returns the component that should receive focus by default within the given parent component.
Component * getPreviousComponent(Component *current) override
Returns the component that should be given focus after the specified one when moving "backwards".
Component * getNextComponent(Component *current) override
Returns the component that should be given focus after the specified one when moving "forwards".
This is a base class for classes that perform a unit test.
T empty(T... args)
T equal(T... args)
T find(T... args)
T front(T... args)
#define jassert(expression)
Platform-independent assertion macro.
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
T next(T... args)
T prev(T... args)