// 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_