OLD | NEW |
| (Empty) |
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 #include "views/view.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/debug/trace_event.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/stringprintf.h" | |
14 #include "base/utf_string_conversions.h" | |
15 #include "third_party/skia/include/core/SkRect.h" | |
16 #include "ui/base/accessibility/accessibility_types.h" | |
17 #include "ui/base/dragdrop/drag_drop_types.h" | |
18 #include "ui/gfx/canvas_skia.h" | |
19 #include "ui/gfx/compositor/compositor.h" | |
20 #include "ui/gfx/compositor/layer.h" | |
21 #include "ui/gfx/compositor/layer_animator.h" | |
22 #include "ui/gfx/interpolated_transform.h" | |
23 #include "ui/gfx/path.h" | |
24 #include "ui/gfx/point3.h" | |
25 #include "ui/gfx/transform.h" | |
26 #include "ui/views/context_menu_controller.h" | |
27 #include "ui/views/drag_controller.h" | |
28 #include "ui/views/layout/layout_manager.h" | |
29 #include "ui/views/widget/native_widget_private.h" | |
30 #include "ui/views/widget/root_view.h" | |
31 #include "ui/views/widget/tooltip_manager.h" | |
32 #include "ui/views/widget/widget.h" | |
33 #include "views/background.h" | |
34 #include "views/views_delegate.h" | |
35 | |
36 #if defined(OS_WIN) | |
37 #include "base/win/scoped_gdi_object.h" | |
38 #include "ui/views/accessibility/native_view_accessibility_win.h" | |
39 #endif | |
40 #if defined(TOOLKIT_USES_GTK) | |
41 #include "ui/base/gtk/scoped_handle_gtk.h" | |
42 #endif | |
43 | |
44 namespace { | |
45 | |
46 // Whether to use accelerated compositing when necessary (e.g. when a view has a | |
47 // transformation). | |
48 #if defined(VIEWS_COMPOSITOR) | |
49 bool use_acceleration_when_possible = true; | |
50 #else | |
51 bool use_acceleration_when_possible = false; | |
52 #endif | |
53 | |
54 // Saves the drawing state, and restores the state when going out of scope. | |
55 class ScopedCanvas { | |
56 public: | |
57 explicit ScopedCanvas(gfx::Canvas* canvas) : canvas_(canvas) { | |
58 if (canvas_) | |
59 canvas_->Save(); | |
60 } | |
61 ~ScopedCanvas() { | |
62 if (canvas_) | |
63 canvas_->Restore(); | |
64 } | |
65 void SetCanvas(gfx::Canvas* canvas) { | |
66 if (canvas_) | |
67 canvas_->Restore(); | |
68 canvas_ = canvas; | |
69 canvas_->Save(); | |
70 } | |
71 | |
72 private: | |
73 gfx::Canvas* canvas_; | |
74 | |
75 DISALLOW_COPY_AND_ASSIGN(ScopedCanvas); | |
76 }; | |
77 | |
78 // Returns the top view in |view|'s hierarchy. | |
79 const views::View* GetHierarchyRoot(const views::View* view) { | |
80 const views::View* root = view; | |
81 while (root && root->parent()) | |
82 root = root->parent(); | |
83 return root; | |
84 } | |
85 | |
86 } // namespace | |
87 | |
88 namespace views { | |
89 | |
90 // static | |
91 ViewsDelegate* ViewsDelegate::views_delegate = NULL; | |
92 | |
93 // static | |
94 const char View::kViewClassName[] = "views/View"; | |
95 | |
96 //////////////////////////////////////////////////////////////////////////////// | |
97 // View, public: | |
98 | |
99 // TO BE MOVED ----------------------------------------------------------------- | |
100 | |
101 void View::SetHotTracked(bool flag) { | |
102 } | |
103 | |
104 bool View::IsHotTracked() const { | |
105 return false; | |
106 } | |
107 | |
108 // Creation and lifetime ------------------------------------------------------- | |
109 | |
110 View::View() | |
111 : parent_owned_(true), | |
112 id_(0), | |
113 group_(-1), | |
114 parent_(NULL), | |
115 visible_(true), | |
116 enabled_(true), | |
117 painting_enabled_(true), | |
118 registered_for_visible_bounds_notification_(false), | |
119 clip_x_(0.0), | |
120 clip_y_(0.0), | |
121 needs_layout_(true), | |
122 flip_canvas_on_paint_for_rtl_ui_(false), | |
123 paint_to_layer_(false), | |
124 accelerator_registration_delayed_(false), | |
125 accelerator_focus_manager_(NULL), | |
126 registered_accelerator_count_(0), | |
127 next_focusable_view_(NULL), | |
128 previous_focusable_view_(NULL), | |
129 focusable_(false), | |
130 accessibility_focusable_(false), | |
131 context_menu_controller_(NULL), | |
132 drag_controller_(NULL) { | |
133 } | |
134 | |
135 View::~View() { | |
136 if (parent_) | |
137 parent_->RemoveChildView(this); | |
138 | |
139 for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) { | |
140 (*i)->parent_ = NULL; | |
141 if ((*i)->parent_owned()) | |
142 delete *i; | |
143 } | |
144 | |
145 #if defined(OS_WIN) | |
146 if (native_view_accessibility_win_.get()) | |
147 native_view_accessibility_win_->set_view(NULL); | |
148 #endif | |
149 } | |
150 | |
151 // Tree operations ------------------------------------------------------------- | |
152 | |
153 const Widget* View::GetWidget() const { | |
154 // The root view holds a reference to this view hierarchy's Widget. | |
155 return parent_ ? parent_->GetWidget() : NULL; | |
156 } | |
157 | |
158 Widget* View::GetWidget() { | |
159 return const_cast<Widget*>(const_cast<const View*>(this)->GetWidget()); | |
160 } | |
161 | |
162 void View::AddChildView(View* view) { | |
163 AddChildViewAt(view, child_count()); | |
164 } | |
165 | |
166 void View::AddChildViewAt(View* view, int index) { | |
167 CHECK_NE(view, this) << "You cannot add a view as its own child"; | |
168 | |
169 // If |view| has a parent, remove it from its parent. | |
170 View* parent = view->parent_; | |
171 if (parent) | |
172 parent->RemoveChildView(view); | |
173 | |
174 // Sets the prev/next focus views. | |
175 InitFocusSiblings(view, index); | |
176 | |
177 // Let's insert the view. | |
178 view->parent_ = this; | |
179 children_.insert(children_.begin() + index, view); | |
180 | |
181 for (View* v = this; v; v = v->parent_) | |
182 v->ViewHierarchyChangedImpl(false, true, this, view); | |
183 | |
184 view->PropagateAddNotifications(this, view); | |
185 UpdateTooltip(); | |
186 if (GetWidget()) | |
187 RegisterChildrenForVisibleBoundsNotification(view); | |
188 | |
189 if (layout_manager_.get()) | |
190 layout_manager_->ViewAdded(this, view); | |
191 | |
192 if (use_acceleration_when_possible) | |
193 ReorderLayers(); | |
194 | |
195 // Make sure the visibility of the child layers are correct. | |
196 // If any of the parent View is hidden, then the layers of the subtree | |
197 // rooted at |this| should be hidden. Otherwise, all the child layers should | |
198 // inherit the visibility of the owner View. | |
199 UpdateLayerVisibility(); | |
200 } | |
201 | |
202 void View::ReorderChildView(View* view, int index) { | |
203 DCHECK_EQ(view->parent_, this); | |
204 if (index < 0) | |
205 index = child_count() - 1; | |
206 else if (index >= child_count()) | |
207 return; | |
208 if (children_[index] == view) | |
209 return; | |
210 | |
211 const Views::iterator i(std::find(children_.begin(), children_.end(), view)); | |
212 DCHECK(i != children_.end()); | |
213 children_.erase(i); | |
214 | |
215 // Unlink the view first | |
216 View* next_focusable = view->next_focusable_view_; | |
217 View* prev_focusable = view->previous_focusable_view_; | |
218 if (prev_focusable) | |
219 prev_focusable->next_focusable_view_ = next_focusable; | |
220 if (next_focusable) | |
221 next_focusable->previous_focusable_view_ = prev_focusable; | |
222 | |
223 // Add it in the specified index now. | |
224 InitFocusSiblings(view, index); | |
225 children_.insert(children_.begin() + index, view); | |
226 | |
227 if (use_acceleration_when_possible) | |
228 ReorderLayers(); | |
229 } | |
230 | |
231 void View::RemoveChildView(View* view) { | |
232 DoRemoveChildView(view, true, true, false); | |
233 } | |
234 | |
235 void View::RemoveAllChildViews(bool delete_children) { | |
236 while (!children_.empty()) | |
237 DoRemoveChildView(children_.front(), false, false, delete_children); | |
238 UpdateTooltip(); | |
239 } | |
240 | |
241 bool View::Contains(const View* view) const { | |
242 for (const View* v = view; v; v = v->parent_) { | |
243 if (v == this) | |
244 return true; | |
245 } | |
246 return false; | |
247 } | |
248 | |
249 int View::GetIndexOf(const View* view) const { | |
250 Views::const_iterator i(std::find(children_.begin(), children_.end(), view)); | |
251 return i != children_.end() ? static_cast<int>(i - children_.begin()) : -1; | |
252 } | |
253 | |
254 // Size and disposition -------------------------------------------------------- | |
255 | |
256 void View::SetBounds(int x, int y, int width, int height) { | |
257 SetBoundsRect(gfx::Rect(x, y, std::max(0, width), std::max(0, height))); | |
258 } | |
259 | |
260 void View::SetBoundsRect(const gfx::Rect& bounds) { | |
261 if (bounds == bounds_) { | |
262 if (needs_layout_) { | |
263 needs_layout_ = false; | |
264 Layout(); | |
265 SchedulePaint(); | |
266 } | |
267 return; | |
268 } | |
269 | |
270 if (IsVisible()) { | |
271 // Paint where the view is currently. | |
272 SchedulePaintBoundsChanged( | |
273 bounds_.size() == bounds.size() ? SCHEDULE_PAINT_SIZE_SAME : | |
274 SCHEDULE_PAINT_SIZE_CHANGED); | |
275 } | |
276 | |
277 gfx::Rect prev = bounds_; | |
278 bounds_ = bounds; | |
279 BoundsChanged(prev); | |
280 } | |
281 | |
282 void View::SetSize(const gfx::Size& size) { | |
283 SetBounds(x(), y(), size.width(), size.height()); | |
284 } | |
285 | |
286 void View::SetPosition(const gfx::Point& position) { | |
287 SetBounds(position.x(), position.y(), width(), height()); | |
288 } | |
289 | |
290 void View::SetX(int x) { | |
291 SetBounds(x, y(), width(), height()); | |
292 } | |
293 | |
294 void View::SetY(int y) { | |
295 SetBounds(x(), y, width(), height()); | |
296 } | |
297 | |
298 gfx::Rect View::GetContentsBounds() const { | |
299 gfx::Rect contents_bounds(GetLocalBounds()); | |
300 if (border_.get()) { | |
301 gfx::Insets insets; | |
302 border_->GetInsets(&insets); | |
303 contents_bounds.Inset(insets); | |
304 } | |
305 return contents_bounds; | |
306 } | |
307 | |
308 gfx::Rect View::GetLocalBounds() const { | |
309 return gfx::Rect(gfx::Point(), size()); | |
310 } | |
311 | |
312 gfx::Insets View::GetInsets() const { | |
313 gfx::Insets insets; | |
314 if (border_.get()) | |
315 border_->GetInsets(&insets); | |
316 return insets; | |
317 } | |
318 | |
319 gfx::Rect View::GetVisibleBounds() const { | |
320 if (!IsVisibleInRootView()) | |
321 return gfx::Rect(); | |
322 gfx::Rect vis_bounds(0, 0, width(), height()); | |
323 gfx::Rect ancestor_bounds; | |
324 const View* view = this; | |
325 ui::Transform transform; | |
326 | |
327 while (view != NULL && !vis_bounds.IsEmpty()) { | |
328 transform.ConcatTransform(view->GetTransform()); | |
329 transform.ConcatTranslate(static_cast<float>(view->GetMirroredX()), | |
330 static_cast<float>(view->y())); | |
331 | |
332 vis_bounds = view->ConvertRectToParent(vis_bounds); | |
333 const View* ancestor = view->parent_; | |
334 if (ancestor != NULL) { | |
335 ancestor_bounds.SetRect(0, 0, ancestor->width(), ancestor->height()); | |
336 vis_bounds = vis_bounds.Intersect(ancestor_bounds); | |
337 } else if (!view->GetWidget()) { | |
338 // If the view has no Widget, we're not visible. Return an empty rect. | |
339 return gfx::Rect(); | |
340 } | |
341 view = ancestor; | |
342 } | |
343 if (vis_bounds.IsEmpty()) | |
344 return vis_bounds; | |
345 // Convert back to this views coordinate system. | |
346 transform.TransformRectReverse(&vis_bounds); | |
347 return vis_bounds; | |
348 } | |
349 | |
350 gfx::Rect View::GetScreenBounds() const { | |
351 gfx::Point origin; | |
352 View::ConvertPointToScreen(this, &origin); | |
353 return gfx::Rect(origin, size()); | |
354 } | |
355 | |
356 gfx::Size View::GetPreferredSize() { | |
357 if (layout_manager_.get()) | |
358 return layout_manager_->GetPreferredSize(this); | |
359 return gfx::Size(); | |
360 } | |
361 | |
362 int View::GetBaseline() const { | |
363 return -1; | |
364 } | |
365 | |
366 void View::SizeToPreferredSize() { | |
367 gfx::Size prefsize = GetPreferredSize(); | |
368 if ((prefsize.width() != width()) || (prefsize.height() != height())) | |
369 SetBounds(x(), y(), prefsize.width(), prefsize.height()); | |
370 } | |
371 | |
372 gfx::Size View::GetMinimumSize() { | |
373 return GetPreferredSize(); | |
374 } | |
375 | |
376 int View::GetHeightForWidth(int w) { | |
377 if (layout_manager_.get()) | |
378 return layout_manager_->GetPreferredHeightForWidth(this, w); | |
379 return GetPreferredSize().height(); | |
380 } | |
381 | |
382 void View::SetVisible(bool visible) { | |
383 if (visible != visible_) { | |
384 // If the View is currently visible, schedule paint to refresh parent. | |
385 // TODO(beng): not sure we should be doing this if we have a layer. | |
386 if (visible_) | |
387 SchedulePaint(); | |
388 | |
389 visible_ = visible; | |
390 | |
391 // This notifies all sub-views recursively. | |
392 PropagateVisibilityNotifications(this, visible_); | |
393 UpdateLayerVisibility(); | |
394 | |
395 // If we are newly visible, schedule paint. | |
396 if (visible_) | |
397 SchedulePaint(); | |
398 } | |
399 } | |
400 | |
401 bool View::IsVisible() const { | |
402 return visible_; | |
403 } | |
404 | |
405 bool View::IsVisibleInRootView() const { | |
406 return IsVisible() && parent_ ? parent_->IsVisibleInRootView() : false; | |
407 } | |
408 | |
409 void View::SetEnabled(bool enabled) { | |
410 if (enabled != enabled_) { | |
411 enabled_ = enabled; | |
412 OnEnabledChanged(); | |
413 } | |
414 } | |
415 | |
416 bool View::IsEnabled() const { | |
417 return enabled_; | |
418 } | |
419 | |
420 void View::OnEnabledChanged() { | |
421 SchedulePaint(); | |
422 } | |
423 | |
424 // Transformations ------------------------------------------------------------- | |
425 | |
426 const ui::Transform& View::GetTransform() const { | |
427 static const ui::Transform* no_op = new ui::Transform; | |
428 return layer() ? layer()->transform() : *no_op; | |
429 } | |
430 | |
431 void View::SetTransform(const ui::Transform& transform) { | |
432 if (!transform.HasChange()) { | |
433 if (layer()) { | |
434 layer()->SetTransform(transform); | |
435 if (!paint_to_layer_) | |
436 DestroyLayer(); | |
437 } else { | |
438 // Nothing. | |
439 } | |
440 } else { | |
441 if (!layer()) | |
442 CreateLayer(); | |
443 layer()->SetTransform(transform); | |
444 layer()->ScheduleDraw(); | |
445 } | |
446 } | |
447 | |
448 void View::SetPaintToLayer(bool paint_to_layer) { | |
449 paint_to_layer_ = paint_to_layer; | |
450 if (paint_to_layer_ && !layer()) { | |
451 CreateLayer(); | |
452 } else if (!paint_to_layer_ && layer()) { | |
453 DestroyLayer(); | |
454 } | |
455 } | |
456 | |
457 // RTL positioning ------------------------------------------------------------- | |
458 | |
459 gfx::Rect View::GetMirroredBounds() const { | |
460 gfx::Rect bounds(bounds_); | |
461 bounds.set_x(GetMirroredX()); | |
462 return bounds; | |
463 } | |
464 | |
465 gfx::Point View::GetMirroredPosition() const { | |
466 return gfx::Point(GetMirroredX(), y()); | |
467 } | |
468 | |
469 int View::GetMirroredX() const { | |
470 return parent_ ? parent_->GetMirroredXForRect(bounds_) : x(); | |
471 } | |
472 | |
473 int View::GetMirroredXForRect(const gfx::Rect& bounds) const { | |
474 return base::i18n::IsRTL() ? | |
475 (width() - bounds.x() - bounds.width()) : bounds.x(); | |
476 } | |
477 | |
478 int View::GetMirroredXInView(int x) const { | |
479 return base::i18n::IsRTL() ? width() - x : x; | |
480 } | |
481 | |
482 int View::GetMirroredXWithWidthInView(int x, int w) const { | |
483 return base::i18n::IsRTL() ? width() - x - w : x; | |
484 } | |
485 | |
486 // Layout ---------------------------------------------------------------------- | |
487 | |
488 void View::Layout() { | |
489 needs_layout_ = false; | |
490 | |
491 // If we have a layout manager, let it handle the layout for us. | |
492 if (layout_manager_.get()) | |
493 layout_manager_->Layout(this); | |
494 | |
495 // Make sure to propagate the Layout() call to any children that haven't | |
496 // received it yet through the layout manager and need to be laid out. This | |
497 // is needed for the case when the child requires a layout but its bounds | |
498 // weren't changed by the layout manager. If there is no layout manager, we | |
499 // just propagate the Layout() call down the hierarchy, so whoever receives | |
500 // the call can take appropriate action. | |
501 for (int i = 0, count = child_count(); i < count; ++i) { | |
502 View* child = child_at(i); | |
503 if (child->needs_layout_ || !layout_manager_.get()) { | |
504 child->needs_layout_ = false; | |
505 child->Layout(); | |
506 } | |
507 } | |
508 } | |
509 | |
510 void View::InvalidateLayout() { | |
511 // Always invalidate up. This is needed to handle the case of us already being | |
512 // valid, but not our parent. | |
513 needs_layout_ = true; | |
514 if (parent_) | |
515 parent_->InvalidateLayout(); | |
516 } | |
517 | |
518 LayoutManager* View::GetLayoutManager() const { | |
519 return layout_manager_.get(); | |
520 } | |
521 | |
522 void View::SetLayoutManager(LayoutManager* layout_manager) { | |
523 if (layout_manager_.get()) | |
524 layout_manager_->Uninstalled(this); | |
525 | |
526 layout_manager_.reset(layout_manager); | |
527 if (layout_manager_.get()) | |
528 layout_manager_->Installed(this); | |
529 } | |
530 | |
531 // Attributes ------------------------------------------------------------------ | |
532 | |
533 std::string View::GetClassName() const { | |
534 return kViewClassName; | |
535 } | |
536 | |
537 View* View::GetAncestorWithClassName(const std::string& name) { | |
538 for (View* view = this; view; view = view->parent_) { | |
539 if (view->GetClassName() == name) | |
540 return view; | |
541 } | |
542 return NULL; | |
543 } | |
544 | |
545 const View* View::GetViewByID(int id) const { | |
546 if (id == id_) | |
547 return const_cast<View*>(this); | |
548 | |
549 for (int i = 0, count = child_count(); i < count; ++i) { | |
550 const View* view = child_at(i)->GetViewByID(id); | |
551 if (view) | |
552 return view; | |
553 } | |
554 return NULL; | |
555 } | |
556 | |
557 View* View::GetViewByID(int id) { | |
558 return const_cast<View*>(const_cast<const View*>(this)->GetViewByID(id)); | |
559 } | |
560 | |
561 void View::SetGroup(int gid) { | |
562 // Don't change the group id once it's set. | |
563 DCHECK(group_ == -1 || group_ == gid); | |
564 group_ = gid; | |
565 } | |
566 | |
567 int View::GetGroup() const { | |
568 return group_; | |
569 } | |
570 | |
571 bool View::IsGroupFocusTraversable() const { | |
572 return true; | |
573 } | |
574 | |
575 void View::GetViewsInGroup(int group, Views* views) { | |
576 if (group_ == group) | |
577 views->push_back(this); | |
578 | |
579 for (int i = 0, count = child_count(); i < count; ++i) | |
580 child_at(i)->GetViewsInGroup(group, views); | |
581 } | |
582 | |
583 View* View::GetSelectedViewForGroup(int group) { | |
584 Views views; | |
585 GetWidget()->GetRootView()->GetViewsInGroup(group, &views); | |
586 return views.empty() ? NULL : views[0]; | |
587 } | |
588 | |
589 // Coordinate conversion ------------------------------------------------------- | |
590 | |
591 // static | |
592 void View::ConvertPointToView(const View* source, | |
593 const View* target, | |
594 gfx::Point* point) { | |
595 if (source == target) | |
596 return; | |
597 | |
598 // |source| can be NULL. | |
599 const View* root = GetHierarchyRoot(target); | |
600 if (source) { | |
601 CHECK_EQ(GetHierarchyRoot(source), root); | |
602 | |
603 if (source != root) | |
604 source->ConvertPointForAncestor(root, point); | |
605 } | |
606 | |
607 if (target != root) | |
608 target->ConvertPointFromAncestor(root, point); | |
609 | |
610 // API defines NULL |source| as returning the point in screen coordinates. | |
611 if (!source) { | |
612 *point = point->Subtract( | |
613 root->GetWidget()->GetClientAreaScreenBounds().origin()); | |
614 } | |
615 } | |
616 | |
617 // static | |
618 void View::ConvertPointToWidget(const View* src, gfx::Point* p) { | |
619 DCHECK(src); | |
620 DCHECK(p); | |
621 | |
622 src->ConvertPointForAncestor(NULL, p); | |
623 } | |
624 | |
625 // static | |
626 void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { | |
627 DCHECK(dest); | |
628 DCHECK(p); | |
629 | |
630 dest->ConvertPointFromAncestor(NULL, p); | |
631 } | |
632 | |
633 // static | |
634 void View::ConvertPointToScreen(const View* src, gfx::Point* p) { | |
635 DCHECK(src); | |
636 DCHECK(p); | |
637 | |
638 // If the view is not connected to a tree, there's nothing we can do. | |
639 const Widget* widget = src->GetWidget(); | |
640 if (widget) { | |
641 ConvertPointToWidget(src, p); | |
642 gfx::Rect r = widget->GetClientAreaScreenBounds(); | |
643 p->SetPoint(p->x() + r.x(), p->y() + r.y()); | |
644 } | |
645 } | |
646 | |
647 gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const { | |
648 gfx::Rect x_rect = rect; | |
649 GetTransform().TransformRect(&x_rect); | |
650 x_rect.Offset(GetMirroredPosition()); | |
651 return x_rect; | |
652 } | |
653 | |
654 gfx::Rect View::ConvertRectToWidget(const gfx::Rect& rect) const { | |
655 gfx::Rect x_rect = rect; | |
656 for (const View* v = this; v; v = v->parent_) | |
657 x_rect = v->ConvertRectToParent(x_rect); | |
658 return x_rect; | |
659 } | |
660 | |
661 // Painting -------------------------------------------------------------------- | |
662 | |
663 void View::SchedulePaint() { | |
664 SchedulePaintInRect(GetLocalBounds()); | |
665 } | |
666 | |
667 void View::SchedulePaintInRect(const gfx::Rect& rect) { | |
668 if (!IsVisible() || !painting_enabled_) | |
669 return; | |
670 | |
671 if (layer()) { | |
672 layer()->SchedulePaint(rect); | |
673 } else if (parent_) { | |
674 // Translate the requested paint rect to the parent's coordinate system | |
675 // then pass this notification up to the parent. | |
676 parent_->SchedulePaintInRect(ConvertRectToParent(rect)); | |
677 } | |
678 } | |
679 | |
680 void View::Paint(gfx::Canvas* canvas) { | |
681 TRACE_EVENT0("views", "View::Paint"); | |
682 | |
683 ScopedCanvas scoped_canvas(canvas); | |
684 | |
685 // Paint this View and its children, setting the clip rect to the bounds | |
686 // of this View and translating the origin to the local bounds' top left | |
687 // point. | |
688 // | |
689 // Note that the X (or left) position we pass to ClipRectInt takes into | |
690 // consideration whether or not the view uses a right-to-left layout so that | |
691 // we paint our view in its mirrored position if need be. | |
692 if (!canvas->ClipRect(gfx::Rect(GetMirroredX(), y(), | |
693 width() - static_cast<int>(clip_x_), | |
694 height() - static_cast<int>(clip_y_)))) { | |
695 return; | |
696 } | |
697 // Non-empty clip, translate the graphics such that 0,0 corresponds to | |
698 // where this view is located (related to its parent). | |
699 canvas->Translate(GetMirroredPosition()); | |
700 canvas->Transform(GetTransform()); | |
701 | |
702 PaintCommon(canvas); | |
703 } | |
704 | |
705 ThemeProvider* View::GetThemeProvider() const { | |
706 const Widget* widget = GetWidget(); | |
707 return widget ? widget->GetThemeProvider() : NULL; | |
708 } | |
709 | |
710 // Accelerated Painting -------------------------------------------------------- | |
711 | |
712 // static | |
713 void View::set_use_acceleration_when_possible(bool use) { | |
714 use_acceleration_when_possible = use; | |
715 } | |
716 | |
717 // static | |
718 bool View::get_use_acceleration_when_possible() { | |
719 return use_acceleration_when_possible; | |
720 } | |
721 | |
722 // Input ----------------------------------------------------------------------- | |
723 | |
724 View* View::GetEventHandlerForPoint(const gfx::Point& point) { | |
725 // Walk the child Views recursively looking for the View that most | |
726 // tightly encloses the specified point. | |
727 for (int i = child_count() - 1; i >= 0; --i) { | |
728 View* child = child_at(i); | |
729 if (!child->IsVisible()) | |
730 continue; | |
731 | |
732 gfx::Point point_in_child_coords(point); | |
733 View::ConvertPointToView(this, child, &point_in_child_coords); | |
734 if (child->HitTest(point_in_child_coords)) | |
735 return child->GetEventHandlerForPoint(point_in_child_coords); | |
736 } | |
737 return this; | |
738 } | |
739 | |
740 gfx::NativeCursor View::GetCursor(const MouseEvent& event) { | |
741 #if defined(OS_WIN) && !defined(USE_AURA) | |
742 static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW); | |
743 return arrow; | |
744 #else | |
745 return gfx::kNullCursor; | |
746 #endif | |
747 } | |
748 | |
749 bool View::HitTest(const gfx::Point& l) const { | |
750 if (GetLocalBounds().Contains(l)) { | |
751 if (HasHitTestMask()) { | |
752 gfx::Path mask; | |
753 GetHitTestMask(&mask); | |
754 #if defined(USE_AURA) | |
755 // TODO: should we use this every where? | |
756 SkRegion clip_region; | |
757 clip_region.setRect(0, 0, width(), height()); | |
758 SkRegion mask_region; | |
759 return mask_region.setPath(mask, clip_region) && | |
760 mask_region.contains(l.x(), l.y()); | |
761 #elif defined(OS_WIN) | |
762 base::win::ScopedRegion rgn(mask.CreateNativeRegion()); | |
763 return !!PtInRegion(rgn, l.x(), l.y()); | |
764 #elif defined(TOOLKIT_USES_GTK) | |
765 ui::ScopedRegion rgn(mask.CreateNativeRegion()); | |
766 return gdk_region_point_in(rgn.Get(), l.x(), l.y()); | |
767 #endif | |
768 } | |
769 // No mask, but inside our bounds. | |
770 return true; | |
771 } | |
772 // Outside our bounds. | |
773 return false; | |
774 } | |
775 | |
776 bool View::OnMousePressed(const MouseEvent& event) { | |
777 return false; | |
778 } | |
779 | |
780 bool View::OnMouseDragged(const MouseEvent& event) { | |
781 return false; | |
782 } | |
783 | |
784 void View::OnMouseReleased(const MouseEvent& event) { | |
785 } | |
786 | |
787 void View::OnMouseCaptureLost() { | |
788 } | |
789 | |
790 void View::OnMouseMoved(const MouseEvent& event) { | |
791 } | |
792 | |
793 void View::OnMouseEntered(const MouseEvent& event) { | |
794 } | |
795 | |
796 void View::OnMouseExited(const MouseEvent& event) { | |
797 } | |
798 | |
799 ui::TouchStatus View::OnTouchEvent(const TouchEvent& event) { | |
800 DVLOG(1) << "visited the OnTouchEvent"; | |
801 return ui::TOUCH_STATUS_UNKNOWN; | |
802 } | |
803 | |
804 void View::SetMouseHandler(View *new_mouse_handler) { | |
805 // It is valid for new_mouse_handler to be NULL | |
806 if (parent_) | |
807 parent_->SetMouseHandler(new_mouse_handler); | |
808 } | |
809 | |
810 bool View::OnKeyPressed(const KeyEvent& event) { | |
811 return false; | |
812 } | |
813 | |
814 bool View::OnKeyReleased(const KeyEvent& event) { | |
815 return false; | |
816 } | |
817 | |
818 bool View::OnMouseWheel(const MouseWheelEvent& event) { | |
819 return false; | |
820 } | |
821 | |
822 ui::TextInputClient* View::GetTextInputClient() { | |
823 return NULL; | |
824 } | |
825 | |
826 InputMethod* View::GetInputMethod() { | |
827 Widget* widget = GetWidget(); | |
828 return widget ? widget->GetInputMethod() : NULL; | |
829 } | |
830 | |
831 // Accelerators ---------------------------------------------------------------- | |
832 | |
833 void View::AddAccelerator(const ui::Accelerator& accelerator) { | |
834 if (!accelerators_.get()) | |
835 accelerators_.reset(new std::vector<ui::Accelerator>()); | |
836 | |
837 DCHECK(std::find(accelerators_->begin(), accelerators_->end(), accelerator) == | |
838 accelerators_->end()) | |
839 << "Registering the same accelerator multiple times"; | |
840 | |
841 accelerators_->push_back(accelerator); | |
842 RegisterPendingAccelerators(); | |
843 } | |
844 | |
845 void View::RemoveAccelerator(const ui::Accelerator& accelerator) { | |
846 if (!accelerators_.get()) { | |
847 NOTREACHED() << "Removing non-existing accelerator"; | |
848 return; | |
849 } | |
850 | |
851 std::vector<ui::Accelerator>::iterator i( | |
852 std::find(accelerators_->begin(), accelerators_->end(), accelerator)); | |
853 if (i == accelerators_->end()) { | |
854 NOTREACHED() << "Removing non-existing accelerator"; | |
855 return; | |
856 } | |
857 | |
858 size_t index = i - accelerators_->begin(); | |
859 accelerators_->erase(i); | |
860 if (index >= registered_accelerator_count_) { | |
861 // The accelerator is not registered to FocusManager. | |
862 return; | |
863 } | |
864 --registered_accelerator_count_; | |
865 | |
866 // Providing we are attached to a Widget and registered with a focus manager, | |
867 // we should de-register from that focus manager now. | |
868 if (GetWidget() && accelerator_focus_manager_) | |
869 accelerator_focus_manager_->UnregisterAccelerator(accelerator, this); | |
870 } | |
871 | |
872 void View::ResetAccelerators() { | |
873 if (accelerators_.get()) | |
874 UnregisterAccelerators(false); | |
875 } | |
876 | |
877 bool View::AcceleratorPressed(const ui::Accelerator& accelerator) { | |
878 return false; | |
879 } | |
880 | |
881 // Focus ----------------------------------------------------------------------- | |
882 | |
883 bool View::HasFocus() const { | |
884 const FocusManager* focus_manager = GetFocusManager(); | |
885 return focus_manager && (focus_manager->GetFocusedView() == this); | |
886 } | |
887 | |
888 View* View::GetNextFocusableView() { | |
889 return next_focusable_view_; | |
890 } | |
891 | |
892 const View* View::GetNextFocusableView() const { | |
893 return next_focusable_view_; | |
894 } | |
895 | |
896 View* View::GetPreviousFocusableView() { | |
897 return previous_focusable_view_; | |
898 } | |
899 | |
900 void View::SetNextFocusableView(View* view) { | |
901 view->previous_focusable_view_ = this; | |
902 next_focusable_view_ = view; | |
903 } | |
904 | |
905 bool View::IsFocusableInRootView() const { | |
906 return IsFocusable() && IsVisibleInRootView(); | |
907 } | |
908 | |
909 bool View::IsAccessibilityFocusableInRootView() const { | |
910 return (focusable_ || accessibility_focusable_) && IsEnabled() && | |
911 IsVisibleInRootView(); | |
912 } | |
913 | |
914 FocusManager* View::GetFocusManager() { | |
915 Widget* widget = GetWidget(); | |
916 return widget ? widget->GetFocusManager() : NULL; | |
917 } | |
918 | |
919 const FocusManager* View::GetFocusManager() const { | |
920 const Widget* widget = GetWidget(); | |
921 return widget ? widget->GetFocusManager() : NULL; | |
922 } | |
923 | |
924 void View::RequestFocus() { | |
925 FocusManager* focus_manager = GetFocusManager(); | |
926 if (focus_manager && IsFocusableInRootView()) | |
927 focus_manager->SetFocusedView(this); | |
928 } | |
929 | |
930 bool View::SkipDefaultKeyEventProcessing(const KeyEvent& event) { | |
931 return false; | |
932 } | |
933 | |
934 FocusTraversable* View::GetFocusTraversable() { | |
935 return NULL; | |
936 } | |
937 | |
938 FocusTraversable* View::GetPaneFocusTraversable() { | |
939 return NULL; | |
940 } | |
941 | |
942 // Tooltips -------------------------------------------------------------------- | |
943 | |
944 bool View::GetTooltipText(const gfx::Point& p, string16* tooltip) const { | |
945 return false; | |
946 } | |
947 | |
948 bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) const { | |
949 return false; | |
950 } | |
951 | |
952 // Context menus --------------------------------------------------------------- | |
953 | |
954 void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) { | |
955 if (!context_menu_controller_) | |
956 return; | |
957 | |
958 context_menu_controller_->ShowContextMenuForView(this, p, is_mouse_gesture); | |
959 } | |
960 | |
961 // Drag and drop --------------------------------------------------------------- | |
962 | |
963 bool View::GetDropFormats( | |
964 int* formats, | |
965 std::set<OSExchangeData::CustomFormat>* custom_formats) { | |
966 return false; | |
967 } | |
968 | |
969 bool View::AreDropTypesRequired() { | |
970 return false; | |
971 } | |
972 | |
973 bool View::CanDrop(const OSExchangeData& data) { | |
974 // TODO(sky): when I finish up migration, this should default to true. | |
975 return false; | |
976 } | |
977 | |
978 void View::OnDragEntered(const DropTargetEvent& event) { | |
979 } | |
980 | |
981 int View::OnDragUpdated(const DropTargetEvent& event) { | |
982 return ui::DragDropTypes::DRAG_NONE; | |
983 } | |
984 | |
985 void View::OnDragExited() { | |
986 } | |
987 | |
988 int View::OnPerformDrop(const DropTargetEvent& event) { | |
989 return ui::DragDropTypes::DRAG_NONE; | |
990 } | |
991 | |
992 void View::OnDragDone() { | |
993 } | |
994 | |
995 // static | |
996 bool View::ExceededDragThreshold(int delta_x, int delta_y) { | |
997 return (abs(delta_x) > GetHorizontalDragThreshold() || | |
998 abs(delta_y) > GetVerticalDragThreshold()); | |
999 } | |
1000 | |
1001 // Scrolling ------------------------------------------------------------------- | |
1002 | |
1003 void View::ScrollRectToVisible(const gfx::Rect& rect) { | |
1004 // We must take RTL UI mirroring into account when adjusting the position of | |
1005 // the region. | |
1006 if (parent_) { | |
1007 gfx::Rect scroll_rect(rect); | |
1008 scroll_rect.Offset(GetMirroredX(), y()); | |
1009 parent_->ScrollRectToVisible(scroll_rect); | |
1010 } | |
1011 } | |
1012 | |
1013 int View::GetPageScrollIncrement(ScrollView* scroll_view, | |
1014 bool is_horizontal, bool is_positive) { | |
1015 return 0; | |
1016 } | |
1017 | |
1018 int View::GetLineScrollIncrement(ScrollView* scroll_view, | |
1019 bool is_horizontal, bool is_positive) { | |
1020 return 0; | |
1021 } | |
1022 | |
1023 //////////////////////////////////////////////////////////////////////////////// | |
1024 // View, protected: | |
1025 | |
1026 // Size and disposition -------------------------------------------------------- | |
1027 | |
1028 void View::OnBoundsChanged(const gfx::Rect& previous_bounds) { | |
1029 } | |
1030 | |
1031 void View::PreferredSizeChanged() { | |
1032 InvalidateLayout(); | |
1033 if (parent_) | |
1034 parent_->ChildPreferredSizeChanged(this); | |
1035 } | |
1036 | |
1037 bool View::NeedsNotificationWhenVisibleBoundsChange() const { | |
1038 return false; | |
1039 } | |
1040 | |
1041 void View::OnVisibleBoundsChanged() { | |
1042 } | |
1043 | |
1044 // Tree operations ------------------------------------------------------------- | |
1045 | |
1046 void View::ViewHierarchyChanged(bool is_add, View* parent, View* child) { | |
1047 } | |
1048 | |
1049 void View::VisibilityChanged(View* starting_from, bool is_visible) { | |
1050 } | |
1051 | |
1052 void View::NativeViewHierarchyChanged(bool attached, | |
1053 gfx::NativeView native_view, | |
1054 internal::RootView* root_view) { | |
1055 FocusManager* focus_manager = GetFocusManager(); | |
1056 if (!accelerator_registration_delayed_ && | |
1057 accelerator_focus_manager_ && | |
1058 accelerator_focus_manager_ != focus_manager) { | |
1059 UnregisterAccelerators(true); | |
1060 accelerator_registration_delayed_ = true; | |
1061 } | |
1062 if (accelerator_registration_delayed_ && attached) { | |
1063 if (focus_manager) { | |
1064 RegisterPendingAccelerators(); | |
1065 accelerator_registration_delayed_ = false; | |
1066 } | |
1067 } | |
1068 } | |
1069 | |
1070 // Painting -------------------------------------------------------------------- | |
1071 | |
1072 void View::PaintChildren(gfx::Canvas* canvas) { | |
1073 TRACE_EVENT0("views", "View::PaintChildren"); | |
1074 for (int i = 0, count = child_count(); i < count; ++i) | |
1075 if (!child_at(i)->layer()) | |
1076 child_at(i)->Paint(canvas); | |
1077 } | |
1078 | |
1079 void View::OnPaint(gfx::Canvas* canvas) { | |
1080 TRACE_EVENT0("views", "View::OnPaint"); | |
1081 OnPaintBackground(canvas); | |
1082 OnPaintFocusBorder(canvas); | |
1083 OnPaintBorder(canvas); | |
1084 } | |
1085 | |
1086 void View::OnPaintBackground(gfx::Canvas* canvas) { | |
1087 if (background_.get()) { | |
1088 TRACE_EVENT2("views", "View::OnPaintBackground", | |
1089 "width", canvas->GetSkCanvas()->getDevice()->width(), | |
1090 "height", canvas->GetSkCanvas()->getDevice()->height()); | |
1091 background_->Paint(canvas, this); | |
1092 } | |
1093 } | |
1094 | |
1095 void View::OnPaintBorder(gfx::Canvas* canvas) { | |
1096 if (border_.get()) { | |
1097 TRACE_EVENT2("views", "View::OnPaintBorder", | |
1098 "width", canvas->GetSkCanvas()->getDevice()->width(), | |
1099 "height", canvas->GetSkCanvas()->getDevice()->height()); | |
1100 border_->Paint(*this, canvas); | |
1101 } | |
1102 } | |
1103 | |
1104 void View::OnPaintFocusBorder(gfx::Canvas* canvas) { | |
1105 if ((IsFocusable() || IsAccessibilityFocusableInRootView()) && HasFocus()) { | |
1106 TRACE_EVENT2("views", "views::OnPaintFocusBorder", | |
1107 "width", canvas->GetSkCanvas()->getDevice()->width(), | |
1108 "height", canvas->GetSkCanvas()->getDevice()->height()); | |
1109 canvas->DrawFocusRect(GetLocalBounds()); | |
1110 } | |
1111 } | |
1112 | |
1113 // Accelerated Painting -------------------------------------------------------- | |
1114 | |
1115 void View::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { | |
1116 // This method should not have the side-effect of creating the layer. | |
1117 if (layer()) | |
1118 layer()->SetFillsBoundsOpaquely(fills_bounds_opaquely); | |
1119 } | |
1120 | |
1121 bool View::SetExternalTexture(ui::Texture* texture) { | |
1122 DCHECK(texture); | |
1123 SetPaintToLayer(true); | |
1124 | |
1125 layer()->SetExternalTexture(texture); | |
1126 | |
1127 // Child views must not paint into the external texture. So make sure each | |
1128 // child view has its own layer to paint into. | |
1129 for (Views::iterator i = children_.begin(); i != children_.end(); ++i) | |
1130 (*i)->SetPaintToLayer(true); | |
1131 | |
1132 SchedulePaintInRect(GetLocalBounds()); | |
1133 return true; | |
1134 } | |
1135 | |
1136 void View::CalculateOffsetToAncestorWithLayer(gfx::Point* offset, | |
1137 ui::Layer** layer_parent) { | |
1138 if (layer()) { | |
1139 if (layer_parent) | |
1140 *layer_parent = layer(); | |
1141 return; | |
1142 } | |
1143 if (!parent_) | |
1144 return; | |
1145 | |
1146 offset->Offset(x(), y()); | |
1147 parent_->CalculateOffsetToAncestorWithLayer(offset, layer_parent); | |
1148 } | |
1149 | |
1150 void View::MoveLayerToParent(ui::Layer* parent_layer, | |
1151 const gfx::Point& point) { | |
1152 gfx::Point local_point(point); | |
1153 if (parent_layer != layer()) | |
1154 local_point.Offset(x(), y()); | |
1155 if (layer() && parent_layer != layer()) { | |
1156 parent_layer->Add(layer()); | |
1157 layer()->SetBounds(gfx::Rect(local_point.x(), local_point.y(), | |
1158 width(), height())); | |
1159 } else { | |
1160 for (int i = 0, count = child_count(); i < count; ++i) | |
1161 child_at(i)->MoveLayerToParent(parent_layer, local_point); | |
1162 } | |
1163 } | |
1164 | |
1165 void View::UpdateLayerVisibility() { | |
1166 if (!use_acceleration_when_possible) | |
1167 return; | |
1168 bool visible = IsVisible(); | |
1169 for (const View* v = parent_; visible && v && !v->layer(); v = v->parent_) | |
1170 visible = v->IsVisible(); | |
1171 | |
1172 UpdateChildLayerVisibility(visible); | |
1173 } | |
1174 | |
1175 void View::UpdateChildLayerVisibility(bool ancestor_visible) { | |
1176 if (layer()) { | |
1177 layer()->SetVisible(ancestor_visible && IsVisible()); | |
1178 } else { | |
1179 for (int i = 0, count = child_count(); i < count; ++i) | |
1180 child_at(i)->UpdateChildLayerVisibility(ancestor_visible && IsVisible()); | |
1181 } | |
1182 } | |
1183 | |
1184 void View::UpdateChildLayerBounds(const gfx::Point& offset) { | |
1185 if (layer()) { | |
1186 layer()->SetBounds(gfx::Rect(offset.x(), offset.y(), width(), height())); | |
1187 } else { | |
1188 for (int i = 0, count = child_count(); i < count; ++i) { | |
1189 gfx::Point new_offset(offset.x() + child_at(i)->x(), | |
1190 offset.y() + child_at(i)->y()); | |
1191 child_at(i)->UpdateChildLayerBounds(new_offset); | |
1192 } | |
1193 } | |
1194 } | |
1195 | |
1196 void View::OnPaintLayer(gfx::Canvas* canvas) { | |
1197 if (!layer() || !layer()->fills_bounds_opaquely()) | |
1198 canvas->GetSkCanvas()->drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode); | |
1199 PaintCommon(canvas); | |
1200 } | |
1201 | |
1202 void View::ReorderLayers() { | |
1203 View* v = this; | |
1204 while (v && !v->layer()) | |
1205 v = v->parent(); | |
1206 | |
1207 // Forward to widget in case we're in a NativeWidgetView. | |
1208 if (!v) { | |
1209 if (GetWidget()) | |
1210 GetWidget()->ReorderLayers(); | |
1211 } else { | |
1212 for (Views::const_iterator i(v->children_.begin()); | |
1213 i != v->children_.end(); | |
1214 ++i) | |
1215 (*i)->ReorderChildLayers(v->layer()); | |
1216 } | |
1217 } | |
1218 | |
1219 void View::ReorderChildLayers(ui::Layer* parent_layer) { | |
1220 if (layer()) { | |
1221 DCHECK_EQ(parent_layer, layer()->parent()); | |
1222 parent_layer->StackAtTop(layer()); | |
1223 } else { | |
1224 for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) | |
1225 (*i)->ReorderChildLayers(parent_layer); | |
1226 } | |
1227 } | |
1228 | |
1229 // Input ----------------------------------------------------------------------- | |
1230 | |
1231 bool View::HasHitTestMask() const { | |
1232 return false; | |
1233 } | |
1234 | |
1235 void View::GetHitTestMask(gfx::Path* mask) const { | |
1236 DCHECK(mask); | |
1237 } | |
1238 | |
1239 // Focus ----------------------------------------------------------------------- | |
1240 | |
1241 bool View::IsFocusable() const { | |
1242 return focusable_ && IsEnabled() && IsVisible(); | |
1243 } | |
1244 | |
1245 void View::OnFocus() { | |
1246 // TODO(beng): Investigate whether it's possible for us to move this to | |
1247 // Focus(). | |
1248 // By default, we clear the native focus. This ensures that no visible native | |
1249 // view as the focus and that we still receive keyboard inputs. | |
1250 FocusManager* focus_manager = GetFocusManager(); | |
1251 if (focus_manager) | |
1252 focus_manager->ClearNativeFocus(); | |
1253 | |
1254 // TODO(beng): Investigate whether it's possible for us to move this to | |
1255 // Focus(). | |
1256 // Notify assistive technologies of the focus change. | |
1257 GetWidget()->NotifyAccessibilityEvent( | |
1258 this, ui::AccessibilityTypes::EVENT_FOCUS, true); | |
1259 } | |
1260 | |
1261 void View::OnBlur() { | |
1262 } | |
1263 | |
1264 void View::Focus() { | |
1265 SchedulePaint(); | |
1266 OnFocus(); | |
1267 } | |
1268 | |
1269 void View::Blur() { | |
1270 SchedulePaint(); | |
1271 OnBlur(); | |
1272 } | |
1273 | |
1274 // Tooltips -------------------------------------------------------------------- | |
1275 | |
1276 void View::TooltipTextChanged() { | |
1277 Widget* widget = GetWidget(); | |
1278 // TooltipManager may be null if there is a problem creating it. | |
1279 if (widget && widget->native_widget_private()->GetTooltipManager()) { | |
1280 widget->native_widget_private()->GetTooltipManager()-> | |
1281 TooltipTextChanged(this); | |
1282 } | |
1283 } | |
1284 | |
1285 // Context menus --------------------------------------------------------------- | |
1286 | |
1287 gfx::Point View::GetKeyboardContextMenuLocation() { | |
1288 gfx::Rect vis_bounds = GetVisibleBounds(); | |
1289 gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2, | |
1290 vis_bounds.y() + vis_bounds.height() / 2); | |
1291 ConvertPointToScreen(this, &screen_point); | |
1292 return screen_point; | |
1293 } | |
1294 | |
1295 // Drag and drop --------------------------------------------------------------- | |
1296 | |
1297 int View::GetDragOperations(const gfx::Point& press_pt) { | |
1298 return drag_controller_ ? | |
1299 drag_controller_->GetDragOperationsForView(this, press_pt) : | |
1300 ui::DragDropTypes::DRAG_NONE; | |
1301 } | |
1302 | |
1303 void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) { | |
1304 DCHECK(drag_controller_); | |
1305 drag_controller_->WriteDragDataForView(this, press_pt, data); | |
1306 } | |
1307 | |
1308 bool View::InDrag() { | |
1309 Widget* widget = GetWidget(); | |
1310 return widget ? widget->dragged_view() == this : false; | |
1311 } | |
1312 | |
1313 // Debugging ------------------------------------------------------------------- | |
1314 | |
1315 #if !defined(NDEBUG) | |
1316 | |
1317 std::string View::PrintViewGraph(bool first) { | |
1318 return DoPrintViewGraph(first, this); | |
1319 } | |
1320 | |
1321 std::string View::DoPrintViewGraph(bool first, View* view_with_children) { | |
1322 // 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19. | |
1323 const size_t kMaxPointerStringLength = 19; | |
1324 | |
1325 std::string result; | |
1326 | |
1327 if (first) | |
1328 result.append("digraph {\n"); | |
1329 | |
1330 // Node characteristics. | |
1331 char p[kMaxPointerStringLength]; | |
1332 | |
1333 size_t baseNameIndex = GetClassName().find_last_of('/'); | |
1334 if (baseNameIndex == std::string::npos) | |
1335 baseNameIndex = 0; | |
1336 else | |
1337 baseNameIndex++; | |
1338 | |
1339 char bounds_buffer[512]; | |
1340 | |
1341 // Information about current node. | |
1342 base::snprintf(p, arraysize(bounds_buffer), "%p", view_with_children); | |
1343 result.append(" N"); | |
1344 result.append(p+2); | |
1345 result.append(" [label=\""); | |
1346 | |
1347 result.append(GetClassName().substr(baseNameIndex).c_str()); | |
1348 | |
1349 base::snprintf(bounds_buffer, | |
1350 arraysize(bounds_buffer), | |
1351 "\\n bounds: (%d, %d), (%dx%d)", | |
1352 this->bounds().x(), | |
1353 this->bounds().y(), | |
1354 this->bounds().width(), | |
1355 this->bounds().height()); | |
1356 result.append(bounds_buffer); | |
1357 | |
1358 if (layer() && !layer()->hole_rect().IsEmpty()) { | |
1359 base::snprintf(bounds_buffer, | |
1360 arraysize(bounds_buffer), | |
1361 "\\n hole bounds: (%d, %d), (%dx%d)", | |
1362 layer()->hole_rect().x(), | |
1363 layer()->hole_rect().y(), | |
1364 layer()->hole_rect().width(), | |
1365 layer()->hole_rect().height()); | |
1366 result.append(bounds_buffer); | |
1367 } | |
1368 | |
1369 if (GetTransform().HasChange()) { | |
1370 gfx::Point translation; | |
1371 float rotation; | |
1372 gfx::Point3f scale; | |
1373 if (ui::InterpolatedTransform::FactorTRS(GetTransform(), | |
1374 &translation, | |
1375 &rotation, | |
1376 &scale)) { | |
1377 if (translation != gfx::Point(0, 0)) { | |
1378 base::snprintf(bounds_buffer, | |
1379 arraysize(bounds_buffer), | |
1380 "\\n translation: (%d, %d)", | |
1381 translation.x(), | |
1382 translation.y()); | |
1383 result.append(bounds_buffer); | |
1384 } | |
1385 | |
1386 if (fabs(rotation) > 1e-5) { | |
1387 base::snprintf(bounds_buffer, | |
1388 arraysize(bounds_buffer), | |
1389 "\\n rotation: %3.2f", rotation); | |
1390 result.append(bounds_buffer); | |
1391 } | |
1392 | |
1393 if (scale.AsPoint() != gfx::Point(0, 0)) { | |
1394 base::snprintf(bounds_buffer, | |
1395 arraysize(bounds_buffer), | |
1396 "\\n scale: (%2.4f, %2.4f)", | |
1397 scale.x(), | |
1398 scale.y()); | |
1399 result.append(bounds_buffer); | |
1400 } | |
1401 } | |
1402 } | |
1403 | |
1404 result.append("\""); | |
1405 if (!parent_) | |
1406 result.append(", shape=box"); | |
1407 if (layer()) { | |
1408 if (layer()->texture()) | |
1409 result.append(", color=green"); | |
1410 else | |
1411 result.append(", color=red"); | |
1412 | |
1413 if (layer()->fills_bounds_opaquely()) | |
1414 result.append(", style=filled"); | |
1415 } | |
1416 result.append("]\n"); | |
1417 | |
1418 // Link to parent. | |
1419 if (parent_) { | |
1420 char pp[kMaxPointerStringLength]; | |
1421 | |
1422 base::snprintf(pp, kMaxPointerStringLength, "%p", parent_); | |
1423 result.append(" N"); | |
1424 result.append(pp+2); | |
1425 result.append(" -> N"); | |
1426 result.append(p+2); | |
1427 result.append("\n"); | |
1428 } | |
1429 | |
1430 // Children. | |
1431 for (int i = 0, count = view_with_children->child_count(); i < count; ++i) | |
1432 result.append(view_with_children->child_at(i)->PrintViewGraph(false)); | |
1433 | |
1434 if (first) | |
1435 result.append("}\n"); | |
1436 | |
1437 return result; | |
1438 } | |
1439 | |
1440 #endif | |
1441 | |
1442 //////////////////////////////////////////////////////////////////////////////// | |
1443 // View, private: | |
1444 | |
1445 // DropInfo -------------------------------------------------------------------- | |
1446 | |
1447 void View::DragInfo::Reset() { | |
1448 possible_drag = false; | |
1449 start_pt = gfx::Point(); | |
1450 } | |
1451 | |
1452 void View::DragInfo::PossibleDrag(const gfx::Point& p) { | |
1453 possible_drag = true; | |
1454 start_pt = p; | |
1455 } | |
1456 | |
1457 // Painting -------------------------------------------------------------------- | |
1458 | |
1459 void View::SchedulePaintBoundsChanged(SchedulePaintType type) { | |
1460 // If we have a layer and the View's size did not change, we do not need to | |
1461 // schedule any paints since the layer will be redrawn at its new location | |
1462 // during the next Draw() cycle in the compositor. | |
1463 if (!layer() || type == SCHEDULE_PAINT_SIZE_CHANGED) { | |
1464 // Otherwise, if the size changes or we don't have a layer then we need to | |
1465 // use SchedulePaint to invalidate the area occupied by the View. | |
1466 SchedulePaint(); | |
1467 } else if (parent_ && type == SCHEDULE_PAINT_SIZE_SAME) { | |
1468 // The compositor doesn't Draw() until something on screen changes, so | |
1469 // if our position changes but nothing is being animated on screen, then | |
1470 // tell the compositor to redraw the scene. We know layer() exists due to | |
1471 // the above if clause. | |
1472 layer()->ScheduleDraw(); | |
1473 } | |
1474 } | |
1475 | |
1476 void View::PaintCommon(gfx::Canvas* canvas) { | |
1477 if (!IsVisible() || !painting_enabled_) | |
1478 return; | |
1479 | |
1480 { | |
1481 // If the View we are about to paint requested the canvas to be flipped, we | |
1482 // should change the transform appropriately. | |
1483 // The canvas mirroring is undone once the View is done painting so that we | |
1484 // don't pass the canvas with the mirrored transform to Views that didn't | |
1485 // request the canvas to be flipped. | |
1486 ScopedCanvas scoped(canvas); | |
1487 if (FlipCanvasOnPaintForRTLUI()) { | |
1488 canvas->Translate(gfx::Point(width(), 0)); | |
1489 canvas->Scale(-1, 1); | |
1490 } | |
1491 | |
1492 OnPaint(canvas); | |
1493 } | |
1494 | |
1495 PaintChildren(canvas); | |
1496 } | |
1497 | |
1498 // Tree operations ------------------------------------------------------------- | |
1499 | |
1500 void View::DoRemoveChildView(View* view, | |
1501 bool update_focus_cycle, | |
1502 bool update_tool_tip, | |
1503 bool delete_removed_view) { | |
1504 DCHECK(view); | |
1505 const Views::iterator i(std::find(children_.begin(), children_.end(), view)); | |
1506 scoped_ptr<View> view_to_be_deleted; | |
1507 if (i != children_.end()) { | |
1508 if (update_focus_cycle) { | |
1509 // Let's remove the view from the focus traversal. | |
1510 View* next_focusable = view->next_focusable_view_; | |
1511 View* prev_focusable = view->previous_focusable_view_; | |
1512 if (prev_focusable) | |
1513 prev_focusable->next_focusable_view_ = next_focusable; | |
1514 if (next_focusable) | |
1515 next_focusable->previous_focusable_view_ = prev_focusable; | |
1516 } | |
1517 | |
1518 if (GetWidget()) | |
1519 UnregisterChildrenForVisibleBoundsNotification(view); | |
1520 view->PropagateRemoveNotifications(this); | |
1521 view->parent_ = NULL; | |
1522 view->UpdateLayerVisibility(); | |
1523 | |
1524 if (delete_removed_view && view->parent_owned()) | |
1525 view_to_be_deleted.reset(view); | |
1526 | |
1527 children_.erase(i); | |
1528 } | |
1529 | |
1530 if (update_tool_tip) | |
1531 UpdateTooltip(); | |
1532 | |
1533 if (layout_manager_.get()) | |
1534 layout_manager_->ViewRemoved(this, view); | |
1535 } | |
1536 | |
1537 void View::PropagateRemoveNotifications(View* parent) { | |
1538 for (int i = 0, count = child_count(); i < count; ++i) | |
1539 child_at(i)->PropagateRemoveNotifications(parent); | |
1540 | |
1541 for (View* v = this; v; v = v->parent_) | |
1542 v->ViewHierarchyChangedImpl(true, false, parent, this); | |
1543 } | |
1544 | |
1545 void View::PropagateAddNotifications(View* parent, View* child) { | |
1546 for (int i = 0, count = child_count(); i < count; ++i) | |
1547 child_at(i)->PropagateAddNotifications(parent, child); | |
1548 ViewHierarchyChangedImpl(true, true, parent, child); | |
1549 } | |
1550 | |
1551 void View::PropagateNativeViewHierarchyChanged(bool attached, | |
1552 gfx::NativeView native_view, | |
1553 internal::RootView* root_view) { | |
1554 for (int i = 0, count = child_count(); i < count; ++i) | |
1555 child_at(i)->PropagateNativeViewHierarchyChanged(attached, | |
1556 native_view, | |
1557 root_view); | |
1558 NativeViewHierarchyChanged(attached, native_view, root_view); | |
1559 } | |
1560 | |
1561 void View::ViewHierarchyChangedImpl(bool register_accelerators, | |
1562 bool is_add, | |
1563 View* parent, | |
1564 View* child) { | |
1565 if (register_accelerators) { | |
1566 if (is_add) { | |
1567 // If you get this registration, you are part of a subtree that has been | |
1568 // added to the view hierarchy. | |
1569 if (GetFocusManager()) { | |
1570 RegisterPendingAccelerators(); | |
1571 } else { | |
1572 // Delay accelerator registration until visible as we do not have | |
1573 // focus manager until then. | |
1574 accelerator_registration_delayed_ = true; | |
1575 } | |
1576 } else { | |
1577 if (child == this) | |
1578 UnregisterAccelerators(true); | |
1579 } | |
1580 } | |
1581 | |
1582 if (is_add && layer() && !layer()->parent()) { | |
1583 UpdateParentLayer(); | |
1584 } else if (!is_add && child == this) { | |
1585 // Make sure the layers beloning to the subtree rooted at |child| get | |
1586 // removed from layers that do not belong in the same subtree. | |
1587 OrphanLayers(); | |
1588 } | |
1589 | |
1590 ViewHierarchyChanged(is_add, parent, child); | |
1591 parent->needs_layout_ = true; | |
1592 } | |
1593 | |
1594 // Size and disposition -------------------------------------------------------- | |
1595 | |
1596 void View::PropagateVisibilityNotifications(View* start, bool is_visible) { | |
1597 for (int i = 0, count = child_count(); i < count; ++i) | |
1598 child_at(i)->PropagateVisibilityNotifications(start, is_visible); | |
1599 VisibilityChangedImpl(start, is_visible); | |
1600 } | |
1601 | |
1602 void View::VisibilityChangedImpl(View* starting_from, bool is_visible) { | |
1603 if (is_visible) | |
1604 RegisterPendingAccelerators(); | |
1605 else | |
1606 UnregisterAccelerators(true); | |
1607 VisibilityChanged(starting_from, is_visible); | |
1608 } | |
1609 | |
1610 void View::BoundsChanged(const gfx::Rect& previous_bounds) { | |
1611 if (IsVisible()) { | |
1612 // Paint the new bounds. | |
1613 SchedulePaintBoundsChanged( | |
1614 bounds_.size() == previous_bounds.size() ? SCHEDULE_PAINT_SIZE_SAME : | |
1615 SCHEDULE_PAINT_SIZE_CHANGED); | |
1616 } | |
1617 | |
1618 if (use_acceleration_when_possible) { | |
1619 if (layer()) { | |
1620 if (parent_) { | |
1621 gfx::Point offset; | |
1622 parent_->CalculateOffsetToAncestorWithLayer(&offset, NULL); | |
1623 offset.Offset(x(), y()); | |
1624 layer()->SetBounds(gfx::Rect(offset, size())); | |
1625 } else { | |
1626 layer()->SetBounds(bounds_); | |
1627 } | |
1628 // TODO(beng): this seems redundant with the SchedulePaint at the top of | |
1629 // this function. explore collapsing. | |
1630 if (previous_bounds.size() != bounds_.size() && | |
1631 !layer()->layer_updated_externally()) { | |
1632 // If our bounds have changed then we need to update the complete | |
1633 // texture. | |
1634 layer()->SchedulePaint(GetLocalBounds()); | |
1635 } | |
1636 } else { | |
1637 // If our bounds have changed, then any descendant layer bounds may | |
1638 // have changed. Update them accordingly. | |
1639 gfx::Point offset; | |
1640 CalculateOffsetToAncestorWithLayer(&offset, NULL); | |
1641 UpdateChildLayerBounds(offset); | |
1642 } | |
1643 } | |
1644 | |
1645 OnBoundsChanged(previous_bounds); | |
1646 | |
1647 if (previous_bounds.size() != size()) { | |
1648 needs_layout_ = false; | |
1649 Layout(); | |
1650 } | |
1651 | |
1652 if (NeedsNotificationWhenVisibleBoundsChange()) | |
1653 OnVisibleBoundsChanged(); | |
1654 | |
1655 // Notify interested Views that visible bounds within the root view may have | |
1656 // changed. | |
1657 if (descendants_to_notify_.get()) { | |
1658 for (Views::iterator i(descendants_to_notify_->begin()); | |
1659 i != descendants_to_notify_->end(); ++i) { | |
1660 (*i)->OnVisibleBoundsChanged(); | |
1661 } | |
1662 } | |
1663 } | |
1664 | |
1665 // static | |
1666 void View::RegisterChildrenForVisibleBoundsNotification(View* view) { | |
1667 if (view->NeedsNotificationWhenVisibleBoundsChange()) | |
1668 view->RegisterForVisibleBoundsNotification(); | |
1669 for (int i = 0; i < view->child_count(); ++i) | |
1670 RegisterChildrenForVisibleBoundsNotification(view->child_at(i)); | |
1671 } | |
1672 | |
1673 // static | |
1674 void View::UnregisterChildrenForVisibleBoundsNotification(View* view) { | |
1675 if (view->NeedsNotificationWhenVisibleBoundsChange()) | |
1676 view->UnregisterForVisibleBoundsNotification(); | |
1677 for (int i = 0; i < view->child_count(); ++i) | |
1678 UnregisterChildrenForVisibleBoundsNotification(view->child_at(i)); | |
1679 } | |
1680 | |
1681 void View::RegisterForVisibleBoundsNotification() { | |
1682 if (registered_for_visible_bounds_notification_) | |
1683 return; | |
1684 | |
1685 registered_for_visible_bounds_notification_ = true; | |
1686 for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_) | |
1687 ancestor->AddDescendantToNotify(this); | |
1688 } | |
1689 | |
1690 void View::UnregisterForVisibleBoundsNotification() { | |
1691 if (!registered_for_visible_bounds_notification_) | |
1692 return; | |
1693 | |
1694 registered_for_visible_bounds_notification_ = false; | |
1695 for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_) | |
1696 ancestor->RemoveDescendantToNotify(this); | |
1697 } | |
1698 | |
1699 void View::AddDescendantToNotify(View* view) { | |
1700 DCHECK(view); | |
1701 if (!descendants_to_notify_.get()) | |
1702 descendants_to_notify_.reset(new Views); | |
1703 descendants_to_notify_->push_back(view); | |
1704 } | |
1705 | |
1706 void View::RemoveDescendantToNotify(View* view) { | |
1707 DCHECK(view && descendants_to_notify_.get()); | |
1708 Views::iterator i(std::find( | |
1709 descendants_to_notify_->begin(), descendants_to_notify_->end(), view)); | |
1710 DCHECK(i != descendants_to_notify_->end()); | |
1711 descendants_to_notify_->erase(i); | |
1712 if (descendants_to_notify_->empty()) | |
1713 descendants_to_notify_.reset(); | |
1714 } | |
1715 | |
1716 // Transformations ------------------------------------------------------------- | |
1717 | |
1718 bool View::GetTransformRelativeTo(const View* ancestor, | |
1719 ui::Transform* transform) const { | |
1720 const View* p = this; | |
1721 | |
1722 while (p && p != ancestor) { | |
1723 transform->ConcatTransform(p->GetTransform()); | |
1724 transform->ConcatTranslate(static_cast<float>(p->GetMirroredX()), | |
1725 static_cast<float>(p->y())); | |
1726 | |
1727 p = p->parent_; | |
1728 } | |
1729 | |
1730 return p == ancestor; | |
1731 } | |
1732 | |
1733 // Coordinate conversion ------------------------------------------------------- | |
1734 | |
1735 bool View::ConvertPointForAncestor(const View* ancestor, | |
1736 gfx::Point* point) const { | |
1737 ui::Transform trans; | |
1738 // TODO(sad): Have some way of caching the transformation results. | |
1739 bool result = GetTransformRelativeTo(ancestor, &trans); | |
1740 gfx::Point3f p(*point); | |
1741 trans.TransformPoint(p); | |
1742 *point = p.AsPoint(); | |
1743 return result; | |
1744 } | |
1745 | |
1746 bool View::ConvertPointFromAncestor(const View* ancestor, | |
1747 gfx::Point* point) const { | |
1748 ui::Transform trans; | |
1749 bool result = GetTransformRelativeTo(ancestor, &trans); | |
1750 gfx::Point3f p(*point); | |
1751 trans.TransformPointReverse(p); | |
1752 *point = p.AsPoint(); | |
1753 return result; | |
1754 } | |
1755 | |
1756 // Accelerated painting -------------------------------------------------------- | |
1757 | |
1758 void View::CreateLayer() { | |
1759 // A new layer is being created for the view. So all the layers of the | |
1760 // sub-tree can inherit the visibility of the corresponding view. | |
1761 for (int i = 0, count = child_count(); i < count; ++i) | |
1762 child_at(i)->UpdateChildLayerVisibility(true); | |
1763 | |
1764 layer_.reset(new ui::Layer()); | |
1765 layer_->set_delegate(this); | |
1766 #if !defined(NDEBUG) | |
1767 layer_->set_name(GetClassName()); | |
1768 #endif | |
1769 | |
1770 UpdateParentLayers(); | |
1771 UpdateLayerVisibility(); | |
1772 | |
1773 // The new layer needs to be ordered in the layer tree according | |
1774 // to the view tree. Children of this layer were added in order | |
1775 // in UpdateParentLayers(). | |
1776 if (parent()) | |
1777 parent()->ReorderLayers(); | |
1778 } | |
1779 | |
1780 void View::UpdateParentLayers() { | |
1781 // Attach all top-level un-parented layers. | |
1782 if (layer() && !layer()->parent()) { | |
1783 UpdateParentLayer(); | |
1784 } else { | |
1785 for (int i = 0, count = child_count(); i < count; ++i) | |
1786 child_at(i)->UpdateParentLayers(); | |
1787 } | |
1788 } | |
1789 | |
1790 void View::UpdateParentLayer() { | |
1791 if (!layer()) | |
1792 return; | |
1793 | |
1794 ui::Layer* parent_layer = NULL; | |
1795 gfx::Point offset(x(), y()); | |
1796 | |
1797 // TODO(sad): The NULL check here for parent_ essentially is to check if this | |
1798 // is the RootView. Instead of doing this, this function should be made | |
1799 // virtual and overridden from the RootView. | |
1800 if (parent_) | |
1801 parent_->CalculateOffsetToAncestorWithLayer(&offset, &parent_layer); | |
1802 else if (!parent_ && GetWidget()) | |
1803 GetWidget()->CalculateOffsetToAncestorWithLayer(&offset, &parent_layer); | |
1804 | |
1805 ReparentLayer(offset, parent_layer); | |
1806 } | |
1807 | |
1808 void View::OrphanLayers() { | |
1809 if (layer()) { | |
1810 if (layer()->parent()) | |
1811 layer()->parent()->Remove(layer()); | |
1812 | |
1813 // The layer belonging to this View has already been orphaned. It is not | |
1814 // necessary to orphan the child layers. | |
1815 return; | |
1816 } | |
1817 for (int i = 0, count = child_count(); i < count; ++i) | |
1818 child_at(i)->OrphanLayers(); | |
1819 } | |
1820 | |
1821 void View::ReparentLayer(const gfx::Point& offset, ui::Layer* parent_layer) { | |
1822 layer_->SetBounds(gfx::Rect(offset.x(), offset.y(), width(), height())); | |
1823 DCHECK_NE(layer(), parent_layer); | |
1824 if (parent_layer) | |
1825 parent_layer->Add(layer()); | |
1826 layer_->SchedulePaint(GetLocalBounds()); | |
1827 MoveLayerToParent(layer(), gfx::Point()); | |
1828 } | |
1829 | |
1830 void View::DestroyLayer() { | |
1831 ui::Layer* new_parent = layer()->parent(); | |
1832 std::vector<ui::Layer*> children = layer()->children(); | |
1833 for (size_t i = 0; i < children.size(); ++i) { | |
1834 layer()->Remove(children[i]); | |
1835 if (new_parent) | |
1836 new_parent->Add(children[i]); | |
1837 } | |
1838 | |
1839 layer_.reset(); | |
1840 | |
1841 if (new_parent) | |
1842 ReorderLayers(); | |
1843 | |
1844 gfx::Point offset; | |
1845 CalculateOffsetToAncestorWithLayer(&offset, NULL); | |
1846 UpdateChildLayerBounds(offset); | |
1847 | |
1848 SchedulePaint(); | |
1849 } | |
1850 | |
1851 // Input ----------------------------------------------------------------------- | |
1852 | |
1853 bool View::ProcessMousePressed(const MouseEvent& event, DragInfo* drag_info) { | |
1854 const bool enabled = IsEnabled(); | |
1855 int drag_operations = | |
1856 (enabled && event.IsOnlyLeftMouseButton() && HitTest(event.location())) ? | |
1857 GetDragOperations(event.location()) : 0; | |
1858 ContextMenuController* context_menu_controller = event.IsRightMouseButton() ? | |
1859 context_menu_controller_ : 0; | |
1860 | |
1861 const bool result = OnMousePressed(event); | |
1862 // WARNING: we may have been deleted, don't use any View variables. | |
1863 | |
1864 if (!enabled) | |
1865 return result; | |
1866 | |
1867 if (drag_operations != ui::DragDropTypes::DRAG_NONE) { | |
1868 drag_info->PossibleDrag(event.location()); | |
1869 return true; | |
1870 } | |
1871 return !!context_menu_controller || result; | |
1872 } | |
1873 | |
1874 bool View::ProcessMouseDragged(const MouseEvent& event, DragInfo* drag_info) { | |
1875 // Copy the field, that way if we're deleted after drag and drop no harm is | |
1876 // done. | |
1877 ContextMenuController* context_menu_controller = context_menu_controller_; | |
1878 const bool possible_drag = drag_info->possible_drag; | |
1879 if (possible_drag && ExceededDragThreshold( | |
1880 drag_info->start_pt.x() - event.x(), | |
1881 drag_info->start_pt.y() - event.y())) { | |
1882 if (!drag_controller_ || | |
1883 drag_controller_->CanStartDragForView( | |
1884 this, drag_info->start_pt, event.location())) | |
1885 DoDrag(event, drag_info->start_pt); | |
1886 } else { | |
1887 if (OnMouseDragged(event)) | |
1888 return true; | |
1889 // Fall through to return value based on context menu controller. | |
1890 } | |
1891 // WARNING: we may have been deleted. | |
1892 return (context_menu_controller != NULL) || possible_drag; | |
1893 } | |
1894 | |
1895 void View::ProcessMouseReleased(const MouseEvent& event) { | |
1896 if (context_menu_controller_ && event.IsOnlyRightMouseButton()) { | |
1897 // Assume that if there is a context menu controller we won't be deleted | |
1898 // from mouse released. | |
1899 gfx::Point location(event.location()); | |
1900 OnMouseReleased(event); | |
1901 if (HitTest(location)) { | |
1902 ConvertPointToScreen(this, &location); | |
1903 ShowContextMenu(location, true); | |
1904 } | |
1905 } else { | |
1906 OnMouseReleased(event); | |
1907 } | |
1908 // WARNING: we may have been deleted. | |
1909 } | |
1910 | |
1911 ui::TouchStatus View::ProcessTouchEvent(const TouchEvent& event) { | |
1912 // TODO(rjkroege): Implement a grab scheme similar to as as is found in | |
1913 // MousePressed. | |
1914 return OnTouchEvent(event); | |
1915 } | |
1916 | |
1917 // Accelerators ---------------------------------------------------------------- | |
1918 | |
1919 void View::RegisterPendingAccelerators() { | |
1920 if (!accelerators_.get() || | |
1921 registered_accelerator_count_ == accelerators_->size()) { | |
1922 // No accelerators are waiting for registration. | |
1923 return; | |
1924 } | |
1925 | |
1926 if (!GetWidget()) { | |
1927 // The view is not yet attached to a widget, defer registration until then. | |
1928 return; | |
1929 } | |
1930 | |
1931 accelerator_focus_manager_ = GetFocusManager(); | |
1932 if (!accelerator_focus_manager_) { | |
1933 // Some crash reports seem to show that we may get cases where we have no | |
1934 // focus manager (see bug #1291225). This should never be the case, just | |
1935 // making sure we don't crash. | |
1936 | |
1937 // TODO(jcampan): This fails for a view under NativeWidgetGtk with | |
1938 // TYPE_CHILD. (see http://crbug.com/21335) reenable | |
1939 // NOTREACHED assertion and verify accelerators works as | |
1940 // expected. | |
1941 #if defined(OS_WIN) | |
1942 NOTREACHED(); | |
1943 #endif | |
1944 return; | |
1945 } | |
1946 // Only register accelerators if we are visible. | |
1947 if (!IsVisibleInRootView() || !GetWidget()->IsVisible()) | |
1948 return; | |
1949 for (std::vector<ui::Accelerator>::const_iterator i( | |
1950 accelerators_->begin() + registered_accelerator_count_); | |
1951 i != accelerators_->end(); ++i) { | |
1952 accelerator_focus_manager_->RegisterAccelerator(*i, this); | |
1953 } | |
1954 registered_accelerator_count_ = accelerators_->size(); | |
1955 } | |
1956 | |
1957 void View::UnregisterAccelerators(bool leave_data_intact) { | |
1958 if (!accelerators_.get()) | |
1959 return; | |
1960 | |
1961 if (GetWidget()) { | |
1962 if (accelerator_focus_manager_) { | |
1963 // We may not have a FocusManager if the window containing us is being | |
1964 // closed, in which case the FocusManager is being deleted so there is | |
1965 // nothing to unregister. | |
1966 accelerator_focus_manager_->UnregisterAccelerators(this); | |
1967 accelerator_focus_manager_ = NULL; | |
1968 } | |
1969 if (!leave_data_intact) { | |
1970 accelerators_->clear(); | |
1971 accelerators_.reset(); | |
1972 } | |
1973 registered_accelerator_count_ = 0; | |
1974 } | |
1975 } | |
1976 | |
1977 // Focus ----------------------------------------------------------------------- | |
1978 | |
1979 void View::InitFocusSiblings(View* v, int index) { | |
1980 int count = child_count(); | |
1981 | |
1982 if (count == 0) { | |
1983 v->next_focusable_view_ = NULL; | |
1984 v->previous_focusable_view_ = NULL; | |
1985 } else { | |
1986 if (index == count) { | |
1987 // We are inserting at the end, but the end of the child list may not be | |
1988 // the last focusable element. Let's try to find an element with no next | |
1989 // focusable element to link to. | |
1990 View* last_focusable_view = NULL; | |
1991 for (Views::iterator i(children_.begin()); i != children_.end(); ++i) { | |
1992 if (!(*i)->next_focusable_view_) { | |
1993 last_focusable_view = *i; | |
1994 break; | |
1995 } | |
1996 } | |
1997 if (last_focusable_view == NULL) { | |
1998 // Hum... there is a cycle in the focus list. Let's just insert ourself | |
1999 // after the last child. | |
2000 View* prev = children_[index - 1]; | |
2001 v->previous_focusable_view_ = prev; | |
2002 v->next_focusable_view_ = prev->next_focusable_view_; | |
2003 prev->next_focusable_view_->previous_focusable_view_ = v; | |
2004 prev->next_focusable_view_ = v; | |
2005 } else { | |
2006 last_focusable_view->next_focusable_view_ = v; | |
2007 v->next_focusable_view_ = NULL; | |
2008 v->previous_focusable_view_ = last_focusable_view; | |
2009 } | |
2010 } else { | |
2011 View* prev = children_[index]->GetPreviousFocusableView(); | |
2012 v->previous_focusable_view_ = prev; | |
2013 v->next_focusable_view_ = children_[index]; | |
2014 if (prev) | |
2015 prev->next_focusable_view_ = v; | |
2016 children_[index]->previous_focusable_view_ = v; | |
2017 } | |
2018 } | |
2019 } | |
2020 | |
2021 // System events --------------------------------------------------------------- | |
2022 | |
2023 void View::PropagateThemeChanged() { | |
2024 for (int i = child_count() - 1; i >= 0; --i) | |
2025 child_at(i)->PropagateThemeChanged(); | |
2026 OnThemeChanged(); | |
2027 } | |
2028 | |
2029 void View::PropagateLocaleChanged() { | |
2030 for (int i = child_count() - 1; i >= 0; --i) | |
2031 child_at(i)->PropagateLocaleChanged(); | |
2032 OnLocaleChanged(); | |
2033 } | |
2034 | |
2035 // Tooltips -------------------------------------------------------------------- | |
2036 | |
2037 void View::UpdateTooltip() { | |
2038 Widget* widget = GetWidget(); | |
2039 // TODO(beng): The TooltipManager NULL check can be removed when we | |
2040 // consolidate Init() methods and make views_unittests Init() all | |
2041 // Widgets that it uses. | |
2042 if (widget && widget->native_widget_private()->GetTooltipManager()) | |
2043 widget->native_widget_private()->GetTooltipManager()->UpdateTooltip(); | |
2044 } | |
2045 | |
2046 // Drag and drop --------------------------------------------------------------- | |
2047 | |
2048 void View::DoDrag(const MouseEvent& event, const gfx::Point& press_pt) { | |
2049 int drag_operations = GetDragOperations(press_pt); | |
2050 if (drag_operations == ui::DragDropTypes::DRAG_NONE) | |
2051 return; | |
2052 | |
2053 OSExchangeData data; | |
2054 WriteDragData(press_pt, &data); | |
2055 | |
2056 // Message the RootView to do the drag and drop. That way if we're removed | |
2057 // the RootView can detect it and avoid calling us back. | |
2058 GetWidget()->RunShellDrag(this, data, drag_operations); | |
2059 } | |
2060 | |
2061 } // namespace views | |
OLD | NEW |