LMMS
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
29namespace FocusHelpers
30{
31 static int getOrder (const Component* c)
32 {
33 auto order = c->getExplicitFocusOrder();
34 return order > 0 ? order : std::numeric_limits<int>::max();
35 }
36
37 template <typename FocusContainerFn>
39 std::vector<Component*>& components,
40 FocusContainerFn isFocusContainer)
41 {
42 if (parent == nullptr || parent->getNumChildComponents() == 0)
43 return;
44
45 std::vector<Component*> localComponents;
46
47 for (auto* c : parent->getChildren())
48 if (c->isVisible() && c->isEnabled())
49 localComponents.push_back (c);
50
51 const auto compareComponents = [&] (const Component* a, const Component* b)
52 {
53 const auto getComponentOrderAttributes = [] (const Component* c)
54 {
55 return std::make_tuple (getOrder (c),
56 c->isAlwaysOnTop() ? 0 : 1,
57 c->getY(),
58 c->getX());
59 };
60
61 return getComponentOrderAttributes (a) < getComponentOrderAttributes (b);
62 };
63
64 // This will sort so that they are ordered in terms of explicit focus,
65 // always on top, left-to-right, and then top-to-bottom.
66 std::stable_sort (localComponents.begin(), localComponents.end(), compareComponents);
67
68 for (auto* c : localComponents)
69 {
70 components.push_back (c);
71
72 if (! (c->*isFocusContainer)())
73 findAllComponents (c, components, isFocusContainer);
74 }
75 }
76
78
79 template <typename FocusContainerFn>
81 Component* focusContainer,
82 NavigationDirection direction,
83 FocusContainerFn isFocusContainer)
84 {
85 if (focusContainer != nullptr)
86 {
87 std::vector<Component*> components;
88 findAllComponents (focusContainer, components, isFocusContainer);
89
90 const auto iter = std::find (components.cbegin(), components.cend(), current);
91
92 if (iter == components.cend())
93 return nullptr;
94
95 switch (direction)
96 {
98 if (iter != std::prev (components.cend()))
99 return *std::next (iter);
100
101 break;
102
104 if (iter != components.cbegin())
105 return *std::prev (iter);
106
107 break;
108 }
109 }
110
111 return nullptr;
112 }
113}
114
115//==============================================================================
125
135
137{
138 if (parentComponent != nullptr)
139 {
140 std::vector<Component*> components;
141 FocusHelpers::findAllComponents (parentComponent,
142 components,
144
145 if (! components.empty())
146 return components.front();
147 }
148
149 return nullptr;
150}
151
152std::vector<Component*> FocusTraverser::getAllComponents (Component* parentComponent)
153{
154 std::vector<Component*> components;
155 FocusHelpers::findAllComponents (parentComponent,
156 components,
158
159 return components;
160}
161
162//==============================================================================
163//==============================================================================
164#if JUCE_UNIT_TESTS
165
166struct FocusTraverserTests : public UnitTest
167{
168 FocusTraverserTests()
169 : UnitTest ("FocusTraverser", UnitTestCategories::gui)
170 {}
171
172 void runTest() override
173 {
174 ScopedJuceInitialiser_GUI libraryInitialiser;
175 const MessageManagerLock mml;
176
177 beginTest ("Basic traversal");
178 {
179 TestComponent parent;
180
181 expect (traverser.getDefaultComponent (&parent) == &parent.children.front());
182
183 for (auto iter = parent.children.begin(); iter != parent.children.end(); ++iter)
184 expect (traverser.getNextComponent (&(*iter)) == (iter == std::prev (parent.children.cend()) ? nullptr
185 : &(*std::next (iter))));
186
187 for (auto iter = parent.children.rbegin(); iter != parent.children.rend(); ++iter)
188 expect (traverser.getPreviousComponent (&(*iter)) == (iter == std::prev (parent.children.rend()) ? nullptr
189 : &(*std::next (iter))));
190 auto allComponents = traverser.getAllComponents (&parent);
191
192 expect (std::equal (allComponents.cbegin(), allComponents.cend(), parent.children.cbegin(),
193 [] (const Component* c1, const Component& c2) { return c1 == &c2; }));
194 }
195
196 beginTest ("Disabled components are ignored");
197 {
198 checkIgnored ([] (Component& c) { c.setEnabled (false); });
199 }
200
201 beginTest ("Invisible components are ignored");
202 {
203 checkIgnored ([] (Component& c) { c.setVisible (false); });
204 }
205
206 beginTest ("Explicit focus order comes before unspecified");
207 {
208 TestComponent parent;
209
210 auto& explicitFocusComponent = parent.children[2];
211
212 explicitFocusComponent.setExplicitFocusOrder (1);
213 expect (traverser.getDefaultComponent (&parent) == &explicitFocusComponent);
214
215 expect (traverser.getAllComponents (&parent).front() == &explicitFocusComponent);
216 }
217
218 beginTest ("Explicit focus order comparison");
219 {
220 checkComponentProperties ([this] (Component& child) { child.setExplicitFocusOrder (getRandom().nextInt ({ 1, 100 })); },
221 [] (const Component& c1, const Component& c2) { return c1.getExplicitFocusOrder()
222 <= c2.getExplicitFocusOrder(); });
223 }
224
225 beginTest ("Left to right");
226 {
227 checkComponentProperties ([this] (Component& child) { child.setTopLeftPosition (getRandom().nextInt ({ 0, 100 }), 0); },
228 [] (const Component& c1, const Component& c2) { return c1.getX() <= c2.getX(); });
229 }
230
231 beginTest ("Top to bottom");
232 {
233 checkComponentProperties ([this] (Component& child) { child.setTopLeftPosition (0, getRandom().nextInt ({ 0, 100 })); },
234 [] (const Component& c1, const Component& c2) { return c1.getY() <= c2.getY(); });
235 }
236
237 beginTest ("Focus containers have their own focus");
238 {
239 Component root;
240
241 TestComponent container;
242 container.setFocusContainerType (Component::FocusContainerType::focusContainer);
243
244 root.addAndMakeVisible (container);
245
246 expect (traverser.getDefaultComponent (&root) == &container);
247 expect (traverser.getNextComponent (&container) == nullptr);
248 expect (traverser.getPreviousComponent (&container) == nullptr);
249
250 expect (traverser.getDefaultComponent (&container) == &container.children.front());
251
252 for (auto iter = container.children.begin(); iter != container.children.end(); ++iter)
253 expect (traverser.getNextComponent (&(*iter)) == (iter == std::prev (container.children.cend()) ? nullptr
254 : &(*std::next (iter))));
255
256 for (auto iter = container.children.rbegin(); iter != container.children.rend(); ++iter)
257 expect (traverser.getPreviousComponent (&(*iter)) == (iter == std::prev (container.children.rend()) ? nullptr
258 : &(*std::next (iter))));
259
260 expect (traverser.getAllComponents (&root).size() == 1);
261
262 auto allContainerComponents = traverser.getAllComponents (&container);
263
264 expect (std::equal (allContainerComponents.cbegin(), allContainerComponents.cend(), container.children.cbegin(),
265 [] (const Component* c1, const Component& c2) { return c1 == &c2; }));
266 }
267
268 beginTest ("Non-focus containers pass-through focus");
269 {
270 Component root;
271
272 TestComponent container;
273 container.setFocusContainerType (Component::FocusContainerType::none);
274
275 root.addAndMakeVisible (container);
276
277 expect (traverser.getDefaultComponent (&root) == &container);
278 expect (traverser.getNextComponent (&container) == &container.children.front());
279 expect (traverser.getPreviousComponent (&container) == nullptr);
280
281 expect (traverser.getDefaultComponent (&container) == &container.children.front());
282
283 for (auto iter = container.children.begin(); iter != container.children.end(); ++iter)
284 expect (traverser.getNextComponent (&(*iter)) == (iter == std::prev (container.children.cend()) ? nullptr
285 : &(*std::next (iter))));
286
287 for (auto iter = container.children.rbegin(); iter != container.children.rend(); ++iter)
288 expect (traverser.getPreviousComponent (&(*iter)) == (iter == std::prev (container.children.rend()) ? &container
289 : &(*std::next (iter))));
290
291 expect (traverser.getAllComponents (&root).size() == container.children.size() + 1);
292 }
293 }
294
295private:
296 struct TestComponent : public Component
297 {
298 TestComponent()
299 {
300 for (auto& child : children)
301 addAndMakeVisible (child);
302 }
303
304 std::array<Component, 10> children;
305 };
306
307 void checkComponentProperties (std::function<void (Component&)>&& childFn,
308 std::function<bool (const Component&, const Component&)>&& testProperty)
309 {
310 TestComponent parent;
311
312 for (auto& child : parent.children)
313 childFn (child);
314
315 auto* comp = traverser.getDefaultComponent (&parent);
316
317 for (const auto& child : parent.children)
318 if (&child != comp)
319 expect (testProperty (*comp, child));
320
321 for (;;)
322 {
323 auto* next = traverser.getNextComponent (comp);
324
325 if (next == nullptr)
326 break;
327
328 expect (testProperty (*comp, *next));
329 comp = next;
330 }
331 }
332
333 void checkIgnored (const std::function<void(Component&)>& makeIgnored)
334 {
335 TestComponent parent;
336
337 auto iter = parent.children.begin();
338
339 makeIgnored (*iter);
340 expect (traverser.getDefaultComponent (&parent) == std::addressof (*std::next (iter)));
341
342 iter += 5;
343 makeIgnored (*iter);
344 expect (traverser.getNextComponent (std::addressof (*std::prev (iter))) == std::addressof (*std::next (iter)));
345 expect (traverser.getPreviousComponent (std::addressof (*std::next (iter))) == std::addressof (*std::prev (iter)));
346
347 auto allComponents = traverser.getAllComponents (&parent);
348
349 expect (std::find (allComponents.cbegin(), allComponents.cend(), &parent.children.front()) == allComponents.cend());
350 expect (std::find (allComponents.cbegin(), allComponents.cend(), std::addressof (*iter)) == allComponents.cend());
351 }
352
353 FocusTraverser traverser;
354};
355
356static FocusTraverserTests focusTraverserTests;
357
358#endif
359
360} // namespace juce
uint8_t a
Definition Spc_Cpu.h:141
Definition juce_Component.h:36
Component * findFocusContainer() const
Definition juce_Component.cpp:2894
bool isFocusContainer() const noexcept
Definition juce_Component.cpp:2870
std::vector< Component * > getAllComponents(Component *parentComponent) override
Definition juce_FocusTraverser.cpp:152
Component * getDefaultComponent(Component *parentComponent) override
Definition juce_FocusTraverser.cpp:136
Component * getPreviousComponent(Component *current) override
Definition juce_FocusTraverser.cpp:126
Component * getNextComponent(Component *current) override
Definition juce_FocusTraverser.cpp:116
Definition juce_UnitTest.h:70
static void c2(register WDL_FFT_COMPLEX *a)
Definition fft.c:270
static uintptr_t parent
Definition pugl.h:1644
#define jassert(expression)
static int JUCE_CDECL comp(const void *a, const void *b)
Definition lsp.c:298
Definition juce_FocusTraverser.cpp:30
NavigationDirection
Definition juce_FocusTraverser.cpp:77
@ backwards
Definition juce_FocusTraverser.cpp:77
@ forwards
Definition juce_FocusTraverser.cpp:77
static Component * navigateFocus(Component *current, Component *focusContainer, NavigationDirection direction, FocusContainerFn isFocusContainer)
Definition juce_FocusTraverser.cpp:80
static void findAllComponents(Component *parent, std::vector< Component * > &components, FocusContainerFn isFocusContainer)
Definition juce_FocusTraverser.cpp:38
static int getOrder(const Component *c)
Definition juce_FocusTraverser.cpp:31
Definition juce_UnitTestCategories.h:27
Definition carla_juce.cpp:31
GUI::ui_handle_t gui
Definition main.cpp:50
return c
Definition crypt.c:175
b
Definition crypt.c:628