34 return detail::FocusHelpers::navigateFocus (current,
36 detail::FocusHelpers::NavigationDirection::forwards,
44 return detail::FocusHelpers::navigateFocus (current,
46 detail::FocusHelpers::NavigationDirection::backwards,
52 if (parentComponent !=
nullptr)
55 detail::FocusHelpers::findAllComponents (parentComponent,
59 if (! components.
empty())
60 return components.
front();
69 detail::FocusHelpers::findAllComponents (parentComponent,
80struct FocusTraverserTests final :
public UnitTest
83 :
UnitTest (
"FocusTraverser", UnitTestCategories::gui)
86 void runTest()
override
88 ScopedJuceInitialiser_GUI libraryInitialiser;
89 const MessageManagerLock mml;
91 beginTest (
"Basic traversal");
95 expect (traverser.getDefaultComponent (&parent) == &parent.children.front());
97 for (
auto iter = parent.children.begin(); iter != parent.children.end(); ++iter)
98 expect (traverser.getNextComponent (&(*iter)) == (iter ==
std::prev (parent.children.cend()) ? nullptr
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);
106 expect (
std::equal (allComponents.cbegin(), allComponents.cend(), parent.children.cbegin(),
107 [] (
const Component* c1,
const Component& c2) { return c1 == &c2; }));
110 beginTest (
"Disabled components are ignored");
112 checkIgnored ([] (Component& c) { c.setEnabled (
false); });
115 beginTest (
"Invisible components are ignored");
117 checkIgnored ([] (Component& c) { c.setVisible (
false); });
120 beginTest (
"Explicit focus order comes before unspecified");
122 TestComponent parent;
124 auto& explicitFocusComponent = parent.children[2];
126 explicitFocusComponent.setExplicitFocusOrder (1);
127 expect (traverser.getDefaultComponent (&parent) == &explicitFocusComponent);
129 expect (traverser.getAllComponents (&parent).front() == &explicitFocusComponent);
132 beginTest (
"Explicit focus order comparison");
134 checkComponentProperties ([
this] (Component& child) { child.setExplicitFocusOrder (getRandom().nextInt ({ 1, 100 })); },
135 [] (
const Component& c1,
const Component& c2) {
return c1.getExplicitFocusOrder()
136 <= c2.getExplicitFocusOrder(); });
139 beginTest (
"Left to right");
141 checkComponentProperties ([
this] (Component& child) { child.setTopLeftPosition (getRandom().nextInt ({ 0, 100 }), 0); },
142 [] (
const Component& c1,
const Component& c2) {
return c1.getX() <= c2.getX(); });
145 beginTest (
"Top to bottom");
147 checkComponentProperties ([
this] (Component& child) { child.setTopLeftPosition (0, getRandom().nextInt ({ 0, 100 })); },
148 [] (
const Component& c1,
const Component& c2) {
return c1.getY() <= c2.getY(); });
151 beginTest (
"Focus containers have their own focus");
155 TestComponent container;
156 container.setFocusContainerType (Component::FocusContainerType::focusContainer);
158 root.addAndMakeVisible (container);
160 expect (traverser.getDefaultComponent (&root) == &container);
161 expect (traverser.getNextComponent (&container) ==
nullptr);
162 expect (traverser.getPreviousComponent (&container) ==
nullptr);
164 expect (traverser.getDefaultComponent (&container) == &container.children.front());
166 for (
auto iter = container.children.begin(); iter != container.children.end(); ++iter)
167 expect (traverser.getNextComponent (&(*iter)) == (iter ==
std::prev (container.children.cend()) ? nullptr
170 for (
auto iter = container.children.rbegin(); iter != container.children.rend(); ++iter)
171 expect (traverser.getPreviousComponent (&(*iter)) == (iter ==
std::prev (container.children.rend()) ?
nullptr
174 expect (traverser.getAllComponents (&root).size() == 1);
176 auto allContainerComponents = traverser.getAllComponents (&container);
178 expect (
std::equal (allContainerComponents.cbegin(), allContainerComponents.cend(), container.children.cbegin(),
179 [] (
const Component* c1,
const Component& c2) { return c1 == &c2; }));
182 beginTest (
"Non-focus containers pass-through focus");
186 TestComponent container;
187 container.setFocusContainerType (Component::FocusContainerType::none);
189 root.addAndMakeVisible (container);
191 expect (traverser.getDefaultComponent (&root) == &container);
192 expect (traverser.getNextComponent (&container) == &container.children.front());
193 expect (traverser.getPreviousComponent (&container) ==
nullptr);
195 expect (traverser.getDefaultComponent (&container) == &container.children.front());
197 for (
auto iter = container.children.begin(); iter != container.children.end(); ++iter)
198 expect (traverser.getNextComponent (&(*iter)) == (iter ==
std::prev (container.children.cend()) ? nullptr
201 for (
auto iter = container.children.rbegin(); iter != container.children.rend(); ++iter)
202 expect (traverser.getPreviousComponent (&(*iter)) == (iter ==
std::prev (container.children.rend()) ? &container
205 expect (traverser.getAllComponents (&root).size() == container.children.size() + 1);
210 struct TestComponent final :
public Component
214 for (
auto& child : children)
215 addAndMakeVisible (child);
221 void checkComponentProperties (
std::function<
void (Component&)>&& childFn,
222 std::function<
bool (
const Component&,
const Component&)>&& testProperty)
224 TestComponent parent;
226 for (
auto& child : parent.children)
229 auto* comp = traverser.getDefaultComponent (&parent);
231 for (
const auto& child : parent.children)
233 expect (testProperty (*comp, child));
237 auto*
next = traverser.getNextComponent (comp);
242 expect (testProperty (*comp, *next));
247 void checkIgnored (
const std::function<
void(Component&)>& makeIgnored)
249 TestComponent parent;
251 auto iter = parent.children.begin();
261 auto allComponents = traverser.getAllComponents (&parent);
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());
267 FocusTraverser traverser;
270static FocusTraverserTests focusTraverserTests;
The base class for all JUCE user-interface objects.
Component * findFocusContainer() const
Returns the focus container for this component.
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.