// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_VIEWS_FOCUS_FOCUS_SEARCH_H_ #define UI_VIEWS_FOCUS_FOCUS_SEARCH_H_ #include "ui/views/view.h" namespace views { class FocusTraversable; // FocusSearch is an object that implements the algorithm to find the // next view to focus. class VIEWS_EXPORT FocusSearch { public: // The direction in which the focus traversal is going. // TODO (jcampan): add support for lateral (left, right) focus traversal. The // goal is to switch to focusable views on the same level when using the arrow // keys (ala Windows: in a dialog box, arrow keys typically move between the // dialog OK, Cancel buttons). enum Direction { UP = 0, DOWN }; // Constructor. // - |root| is the root of the view hierarchy to traverse. Focus will be // trapped inside. // - |cycle| should be true if you want FindNextFocusableView to cycle back // to the first view within this root when the traversal reaches // the end. If this is true, then if you pass a valid starting // view to FindNextFocusableView you will always get a valid view // out, even if it's the same view. // - |accessibility_mode| should be true if full keyboard accessibility is // needed and you want to check IsAccessibilityFocusable(), rather than // IsFocusable(). FocusSearch(View* root, bool cycle, bool accessibility_mode); virtual ~FocusSearch() {} // Finds the next view that should be focused and returns it. If a // FocusTraversable is found while searching for the focusable view, // returns NULL and sets |focus_traversable| to the FocusTraversable // and |focus_traversable_view| to the view associated with the // FocusTraversable. // // Return NULL if the end of the focus loop is reached, unless this object // was initialized with |cycle|=true, in which case it goes back to the // beginning when it reaches the end of the traversal. // - |starting_view| is the view that should be used as the starting point // when looking for the previous/next view. It may be NULL (in which case // the first/last view should be used depending if normal/reverse). // - |reverse| whether we should find the next (reverse is false) or the // previous (reverse is true) view. // - |direction| specifies whether we are traversing down (meaning we should // look into child views) or traversing up (don't look at child views). // - |check_starting_view| is true if starting_view may obtain the next focus. // - |focus_traversable| is set to the focus traversable that should be // traversed if one is found (in which case the call returns NULL). // - |focus_traversable_view| is set to the view associated with the // FocusTraversable set in the previous parameter (it is used as the // starting view when looking for the next focusable view). virtual View* FindNextFocusableView(View* starting_view, bool reverse, Direction direction, bool check_starting_view, FocusTraversable** focus_traversable, View** focus_traversable_view); protected: // Get the parent, but stay within the root. Returns NULL if asked for // the parent of |root_|. Subclasses can override this if they need custom // focus search behavior. virtual View* GetParent(View* v); // Returns true if |v| is contained within the hierarchy rooted at |root|. // Subclasses can override this if they need custom focus search behavior. virtual bool Contains(View* root, const View* v); View* root() const { return root_; } private: // Convenience method that returns true if a view is focusable and does not // belong to the specified group. bool IsViewFocusableCandidate(View* v, int skip_group_id); // Convenience method; returns true if a view is not NULL and is focusable // (checking IsAccessibilityFocusable() if |accessibility_mode_| is true). bool IsFocusable(View* v); // Returns the view selected for the group of the selected view. If the view // does not belong to a group or if no view is selected in the group, the // specified view is returned. View* FindSelectedViewForGroup(View* view); // Returns the next focusable view or view containing a FocusTraversable // (NULL if none was found), starting at the starting_view. // |check_starting_view|, |can_go_up| and |can_go_down| controls the // traversal of the views hierarchy. |skip_group_id| specifies a group_id, // -1 means no group. All views from a group are traversed in one pass. View* FindNextFocusableViewImpl(View* starting_view, bool check_starting_view, bool can_go_up, bool can_go_down, int skip_group_id, FocusTraversable** focus_traversable, View** focus_traversable_view); // Same as FindNextFocusableViewImpl but returns the previous focusable view. View* FindPreviousFocusableViewImpl(View* starting_view, bool check_starting_view, bool can_go_up, bool can_go_down, int skip_group_id, FocusTraversable** focus_traversable, View** focus_traversable_view); View* root_; bool cycle_; bool accessibility_mode_; DISALLOW_COPY_AND_ASSIGN(FocusSearch); }; } // namespace views #endif // UI_VIEWS_FOCUS_FOCUS_SEARCH_H_