1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef UI_VIEWS_FOCUS_FOCUS_SEARCH_H_
6#define UI_VIEWS_FOCUS_FOCUS_SEARCH_H_
7
8#include "ui/views/view.h"
9
10namespace views {
11
12class FocusTraversable;
13
14// FocusSearch is an object that implements the algorithm to find the
15// next view to focus.
16class VIEWS_EXPORT FocusSearch {
17 public:
18  // The direction in which the focus traversal is going.
19  // TODO (jcampan): add support for lateral (left, right) focus traversal. The
20  // goal is to switch to focusable views on the same level when using the arrow
21  // keys (ala Windows: in a dialog box, arrow keys typically move between the
22  // dialog OK, Cancel buttons).
23  enum Direction {
24    UP = 0,
25    DOWN
26  };
27
28  // Constructor.
29  // - |root| is the root of the view hierarchy to traverse. Focus will be
30  //   trapped inside.
31  // - |cycle| should be true if you want FindNextFocusableView to cycle back
32  //           to the first view within this root when the traversal reaches
33  //           the end. If this is true, then if you pass a valid starting
34  //           view to FindNextFocusableView you will always get a valid view
35  //           out, even if it's the same view.
36  // - |accessibility_mode| should be true if full keyboard accessibility is
37  //   needed and you want to check IsAccessibilityFocusable(), rather than
38  //   IsFocusable().
39  FocusSearch(View* root, bool cycle, bool accessibility_mode);
40  virtual ~FocusSearch() {}
41
42  // Finds the next view that should be focused and returns it. If a
43  // FocusTraversable is found while searching for the focusable view,
44  // returns NULL and sets |focus_traversable| to the FocusTraversable
45  // and |focus_traversable_view| to the view associated with the
46  // FocusTraversable.
47  //
48  // Return NULL if the end of the focus loop is reached, unless this object
49  // was initialized with |cycle|=true, in which case it goes back to the
50  // beginning when it reaches the end of the traversal.
51  // - |starting_view| is the view that should be used as the starting point
52  //   when looking for the previous/next view. It may be NULL (in which case
53  //   the first/last view should be used depending if normal/reverse).
54  // - |reverse| whether we should find the next (reverse is false) or the
55  //   previous (reverse is true) view.
56  // - |direction| specifies whether we are traversing down (meaning we should
57  //   look into child views) or traversing up (don't look at child views).
58  // - |check_starting_view| is true if starting_view may obtain the next focus.
59  // - |focus_traversable| is set to the focus traversable that should be
60  //   traversed if one is found (in which case the call returns NULL).
61  // - |focus_traversable_view| is set to the view associated with the
62  //   FocusTraversable set in the previous parameter (it is used as the
63  //   starting view when looking for the next focusable view).
64  virtual View* FindNextFocusableView(View* starting_view,
65                                      bool reverse,
66                                      Direction direction,
67                                      bool check_starting_view,
68                                      FocusTraversable** focus_traversable,
69                                      View** focus_traversable_view);
70
71 protected:
72  // Get the parent, but stay within the root. Returns NULL if asked for
73  // the parent of |root_|. Subclasses can override this if they need custom
74  // focus search behavior.
75  virtual View* GetParent(View* v);
76
77  // Returns true if |v| is contained within the hierarchy rooted at |root|.
78  // Subclasses can override this if they need custom focus search behavior.
79  virtual bool Contains(View* root, const View* v);
80
81  View* root() const { return root_; }
82
83 private:
84  // Convenience method that returns true if a view is focusable and does not
85  // belong to the specified group.
86  bool IsViewFocusableCandidate(View* v, int skip_group_id);
87
88  // Convenience method; returns true if a view is not NULL and is focusable
89  // (checking IsAccessibilityFocusable() if |accessibility_mode_| is true).
90  bool IsFocusable(View* v);
91
92  // Returns the view selected for the group of the selected view. If the view
93  // does not belong to a group or if no view is selected in the group, the
94  // specified view is returned.
95  View* FindSelectedViewForGroup(View* view);
96
97  // Returns the next focusable view or view containing a FocusTraversable
98  // (NULL if none was found), starting at the starting_view.
99  // |check_starting_view|, |can_go_up| and |can_go_down| controls the
100  // traversal of the views hierarchy. |skip_group_id| specifies a group_id,
101  // -1 means no group. All views from a group are traversed in one pass.
102  View* FindNextFocusableViewImpl(View* starting_view,
103                                  bool check_starting_view,
104                                  bool can_go_up,
105                                  bool can_go_down,
106                                  int skip_group_id,
107                                  FocusTraversable** focus_traversable,
108                                  View** focus_traversable_view);
109
110  // Same as FindNextFocusableViewImpl but returns the previous focusable view.
111  View* FindPreviousFocusableViewImpl(View* starting_view,
112                                      bool check_starting_view,
113                                      bool can_go_up,
114                                      bool can_go_down,
115                                      int skip_group_id,
116                                      FocusTraversable** focus_traversable,
117                                      View** focus_traversable_view);
118
119  View* root_;
120  bool cycle_;
121  bool accessibility_mode_;
122
123  DISALLOW_COPY_AND_ASSIGN(FocusSearch);
124};
125
126}  // namespace views
127
128#endif  // UI_VIEWS_FOCUS_FOCUS_SEARCH_H_
129