Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(415)

Side by Side Diff: views/focus/focus_search.cc

Issue 8588064: views: Move bubble, events, focus and layout to ui/views/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « views/focus/focus_search.h ('k') | views/focus/view_storage.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 #include "base/logging.h"
6 #include "views/focus/focus_manager.h"
7 #include "views/focus/focus_search.h"
8 #include "views/view.h"
9
10 namespace views {
11
12 FocusSearch::FocusSearch(View* root, bool cycle, bool accessibility_mode)
13 : root_(root),
14 cycle_(cycle),
15 accessibility_mode_(accessibility_mode) {
16 }
17
18 View* FocusSearch::FindNextFocusableView(View* starting_view,
19 bool reverse,
20 Direction direction,
21 bool check_starting_view,
22 FocusTraversable** focus_traversable,
23 View** focus_traversable_view) {
24 *focus_traversable = NULL;
25 *focus_traversable_view = NULL;
26
27 if (!root_->has_children()) {
28 NOTREACHED();
29 // Nothing to focus on here.
30 return NULL;
31 }
32
33 View* initial_starting_view = starting_view;
34 int starting_view_group = -1;
35 if (starting_view)
36 starting_view_group = starting_view->GetGroup();
37
38 if (!starting_view) {
39 // Default to the first/last child
40 starting_view = reverse ? root_->child_at(root_->child_count() - 1) :
41 root_->child_at(0);
42 // If there was no starting view, then the one we select is a potential
43 // focus candidate.
44 check_starting_view = true;
45 } else {
46 // The starting view should be a direct or indirect child of the root.
47 DCHECK(root_->Contains(starting_view));
48 }
49
50 View* v = NULL;
51 if (!reverse) {
52 v = FindNextFocusableViewImpl(starting_view, check_starting_view,
53 true,
54 (direction == DOWN) ? true : false,
55 starting_view_group,
56 focus_traversable,
57 focus_traversable_view);
58 } else {
59 // If the starting view is focusable, we don't want to go down, as we are
60 // traversing the view hierarchy tree bottom-up.
61 bool can_go_down = (direction == DOWN) && !IsFocusable(starting_view);
62 v = FindPreviousFocusableViewImpl(starting_view, check_starting_view,
63 true,
64 can_go_down,
65 starting_view_group,
66 focus_traversable,
67 focus_traversable_view);
68 }
69
70 // Don't set the focus to something outside of this view hierarchy.
71 if (v && v != root_ && !root_->Contains(v))
72 v = NULL;
73
74 // If |cycle_| is true, prefer to keep cycling rather than returning NULL.
75 if (cycle_ && !v && initial_starting_view) {
76 v = FindNextFocusableView(NULL, reverse, direction, check_starting_view,
77 focus_traversable, focus_traversable_view);
78 DCHECK(IsFocusable(v));
79 return v;
80 }
81
82 // Doing some sanity checks.
83 if (v) {
84 DCHECK(IsFocusable(v));
85 return v;
86 }
87 if (*focus_traversable) {
88 DCHECK(*focus_traversable_view);
89 return NULL;
90 }
91 // Nothing found.
92 return NULL;
93 }
94
95 bool FocusSearch::IsViewFocusableCandidate(View* v, int skip_group_id) {
96 return IsFocusable(v) &&
97 (v->IsGroupFocusTraversable() || skip_group_id == -1 ||
98 v->GetGroup() != skip_group_id);
99 }
100
101 bool FocusSearch::IsFocusable(View* v) {
102 if (accessibility_mode_)
103 return v && v->IsAccessibilityFocusableInRootView();
104
105 return v && v->IsFocusableInRootView();
106 }
107
108 View* FocusSearch::FindSelectedViewForGroup(View* view) {
109 if (view->IsGroupFocusTraversable() ||
110 view->GetGroup() == -1) // No group for that view.
111 return view;
112
113 View* selected_view = view->GetSelectedViewForGroup(view->GetGroup());
114 if (selected_view)
115 return selected_view;
116
117 // No view selected for that group, default to the specified view.
118 return view;
119 }
120
121 View* FocusSearch::GetParent(View* v) {
122 return root_->Contains(v) ? v->parent() : NULL;
123 }
124
125 // Strategy for finding the next focusable view:
126 // - keep going down the first child, stop when you find a focusable view or
127 // a focus traversable view (in that case return it) or when you reach a view
128 // with no children.
129 // - go to the right sibling and start the search from there (by invoking
130 // FindNextFocusableViewImpl on that view).
131 // - if the view has no right sibling, go up the parents until you find a parent
132 // with a right sibling and start the search from there.
133 View* FocusSearch::FindNextFocusableViewImpl(
134 View* starting_view,
135 bool check_starting_view,
136 bool can_go_up,
137 bool can_go_down,
138 int skip_group_id,
139 FocusTraversable** focus_traversable,
140 View** focus_traversable_view) {
141 if (check_starting_view) {
142 if (IsViewFocusableCandidate(starting_view, skip_group_id)) {
143 View* v = FindSelectedViewForGroup(starting_view);
144 // The selected view might not be focusable (if it is disabled for
145 // example).
146 if (IsFocusable(v))
147 return v;
148 }
149
150 *focus_traversable = starting_view->GetFocusTraversable();
151 if (*focus_traversable) {
152 *focus_traversable_view = starting_view;
153 return NULL;
154 }
155 }
156
157 // First let's try the left child.
158 if (can_go_down) {
159 if (starting_view->has_children()) {
160 View* v = FindNextFocusableViewImpl(starting_view->child_at(0),
161 true, false, true, skip_group_id,
162 focus_traversable,
163 focus_traversable_view);
164 if (v || *focus_traversable)
165 return v;
166 }
167 }
168
169 // Then try the right sibling.
170 View* sibling = starting_view->GetNextFocusableView();
171 if (sibling) {
172 View* v = FindNextFocusableViewImpl(sibling,
173 true, false, true, skip_group_id,
174 focus_traversable,
175 focus_traversable_view);
176 if (v || *focus_traversable)
177 return v;
178 }
179
180 // Then go up to the parent sibling.
181 if (can_go_up) {
182 View* parent = GetParent(starting_view);
183 while (parent) {
184 sibling = parent->GetNextFocusableView();
185 if (sibling) {
186 return FindNextFocusableViewImpl(sibling,
187 true, true, true,
188 skip_group_id,
189 focus_traversable,
190 focus_traversable_view);
191 }
192 parent = GetParent(parent);
193 }
194 }
195
196 // We found nothing.
197 return NULL;
198 }
199
200 // Strategy for finding the previous focusable view:
201 // - keep going down on the right until you reach a view with no children, if it
202 // it is a good candidate return it.
203 // - start the search on the left sibling.
204 // - if there are no left sibling, start the search on the parent (without going
205 // down).
206 View* FocusSearch::FindPreviousFocusableViewImpl(
207 View* starting_view,
208 bool check_starting_view,
209 bool can_go_up,
210 bool can_go_down,
211 int skip_group_id,
212 FocusTraversable** focus_traversable,
213 View** focus_traversable_view) {
214 // Let's go down and right as much as we can.
215 if (can_go_down) {
216 // Before we go into the direct children, we have to check if this view has
217 // a FocusTraversable.
218 *focus_traversable = starting_view->GetFocusTraversable();
219 if (*focus_traversable) {
220 *focus_traversable_view = starting_view;
221 return NULL;
222 }
223
224 if (starting_view->has_children()) {
225 View* view =
226 starting_view->child_at(starting_view->child_count() - 1);
227 View* v = FindPreviousFocusableViewImpl(view, true, false, true,
228 skip_group_id,
229 focus_traversable,
230 focus_traversable_view);
231 if (v || *focus_traversable)
232 return v;
233 }
234 }
235
236 // Then look at this view. Here, we do not need to see if the view has
237 // a FocusTraversable, since we do not want to go down any more.
238 if (check_starting_view &&
239 IsViewFocusableCandidate(starting_view, skip_group_id)) {
240 View* v = FindSelectedViewForGroup(starting_view);
241 // The selected view might not be focusable (if it is disabled for
242 // example).
243 if (IsFocusable(v))
244 return v;
245 }
246
247 // Then try the left sibling.
248 View* sibling = starting_view->GetPreviousFocusableView();
249 if (sibling) {
250 return FindPreviousFocusableViewImpl(sibling,
251 true, true, true,
252 skip_group_id,
253 focus_traversable,
254 focus_traversable_view);
255 }
256
257 // Then go up the parent.
258 if (can_go_up) {
259 View* parent = GetParent(starting_view);
260 if (parent)
261 return FindPreviousFocusableViewImpl(parent,
262 true, true, false,
263 skip_group_id,
264 focus_traversable,
265 focus_traversable_view);
266 }
267
268 // We found nothing.
269 return NULL;
270 }
271
272 } // namespace views
OLDNEW
« no previous file with comments | « views/focus/focus_search.h ('k') | views/focus/view_storage.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698