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.
5 #include "views/view.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop.h"
12 #include "base/utf_string_conversions.h"
13 #include "third_party/skia/include/core/SkRect.h"
14 #include "ui/base/accessibility/accessibility_types.h"
15 #include "ui/base/dragdrop/drag_drop_types.h"
16 #include "ui/gfx/canvas_skia.h"
17 #include "ui/gfx/compositor/compositor.h"
18 #include "ui/gfx/path.h"
19 #include "ui/gfx/transform.h"
20 #include "views/background.h"
21 #include "views/layout/layout_manager.h"
22 #include "views/views_delegate.h"
23 #include "views/widget/native_widget.h"
24 #include "views/widget/root_view.h"
25 #include "views/widget/tooltip_manager.h"
26 #include "views/widget/widget.h"
27 #include "views/window/window.h"
30 #include "base/win/scoped_gdi_object.h"
31 #include "views/accessibility/native_view_accessibility_win.h"
34 #include "ui/base/gtk/scoped_handle_gtk.h"
38 // Whether to use accelerated compositing when necessary (e.g. when a view has a
40 bool use_acceleration_when_possible
= true;
42 // Saves the drawing state, and restores the state when going out of scope.
45 explicit ScopedCanvas(gfx::Canvas
* canvas
) : canvas_(canvas
) {
53 void SetCanvas(gfx::Canvas
* canvas
) {
63 DISALLOW_COPY_AND_ASSIGN(ScopedCanvas
);
71 ViewsDelegate
* ViewsDelegate::views_delegate
= NULL
;
74 char View::kViewClassName
[] = "views/View";
76 ////////////////////////////////////////////////////////////////////////////////
79 // TO BE MOVED -----------------------------------------------------------------
81 void View::SetHotTracked(bool flag
) {
84 bool View::IsHotTracked() const {
88 // FATE TBD --------------------------------------------------------------------
90 Widget
* View::child_widget() {
94 // Creation and lifetime -------------------------------------------------------
101 accessibility_focusable_(false),
102 is_parent_owned_(true),
105 registered_for_visible_bounds_notification_(false),
109 flip_canvas_on_paint_for_rtl_ui_(false),
110 #if !defined(COMPOSITOR_2)
111 texture_id_(0), // TODO(sadrul): 0 can be a valid texture id.
113 texture_needs_updating_(true),
114 accelerator_registration_delayed_(false),
115 accelerator_focus_manager_(NULL
),
116 registered_accelerator_count_(0),
117 next_focusable_view_(NULL
),
118 previous_focusable_view_(NULL
),
119 context_menu_controller_(NULL
),
120 drag_controller_(NULL
) {
125 parent_
->RemoveChildView(this);
127 int c
= static_cast<int>(children_
.size());
129 children_
[c
]->SetParent(NULL
);
130 if (children_
[c
]->IsParentOwned())
135 if (native_view_accessibility_win_
.get())
136 native_view_accessibility_win_
->set_view(NULL
);
140 // Tree operations -------------------------------------------------------------
142 const Widget
* View::GetWidget() const {
143 // The root view holds a reference to this view hierarchy's Widget.
144 return parent_
? parent_
->GetWidget() : NULL
;
147 Widget
* View::GetWidget() {
148 return const_cast<Widget
*>(const_cast<const View
*>(this)->GetWidget());
151 void View::AddChildView(View
* view
) {
152 AddChildViewAt(view
, child_count());
155 void View::AddChildViewAt(View
* view
, int index
) {
156 CHECK(view
!= this) << "You cannot add a view as its own child";
158 // Remove the view from its current parent if any.
160 view
->parent()->RemoveChildView(view
);
162 // Sets the prev/next focus views.
163 InitFocusSiblings(view
, index
);
165 // Let's insert the view.
166 children_
.insert(children_
.begin() + index
, view
);
167 view
->SetParent(this);
169 for (View
* p
= this; p
; p
= p
->parent())
170 p
->ViewHierarchyChangedImpl(false, true, this, view
);
172 view
->PropagateAddNotifications(this, view
);
175 RegisterChildrenForVisibleBoundsNotification(view
);
177 if (layout_manager_
.get())
178 layout_manager_
->ViewAdded(this, view
);
181 void View::RemoveChildView(View
* view
) {
182 DoRemoveChildView(view
, true, true, false);
185 void View::RemoveAllChildViews(bool delete_views
) {
186 ViewVector::iterator iter
;
187 while ((iter
= children_
.begin()) != children_
.end())
188 DoRemoveChildView(*iter
, false, false, delete_views
);
192 const View
* View::GetChildViewAt(int index
) const {
193 return index
< child_count() ? children_
[index
] : NULL
;
196 View
* View::GetChildViewAt(int index
) {
198 const_cast<View
*>(const_cast<const View
*>(this)->GetChildViewAt(index
));
201 bool View::Contains(const View
* view
) const {
202 for (const View
* v
= view
; v
; v
= v
->parent_
) {
209 int View::GetIndexOf(const View
* view
) const {
210 ViewVector::const_iterator it
= std::find(children_
.begin(), children_
.end(),
212 return it
!= children_
.end() ? it
- children_
.begin() : -1;
215 // TODO(beng): remove
216 const Window
* View::GetWindow() const {
217 const Widget
* widget
= GetWidget();
218 return widget
? widget
->GetContainingWindow() : NULL
;
221 // TODO(beng): remove
222 Window
* View::GetWindow() {
223 return const_cast<Window
*>(const_cast<const View
*>(this)->GetWindow());
226 // TODO(beng): remove
227 bool View::ContainsNativeView(gfx::NativeView native_view
) const {
228 for (int i
= 0, count
= child_count(); i
< count
; ++i
) {
229 if (GetChildViewAt(i
)->ContainsNativeView(native_view
))
235 // TODO(beng): remove
236 RootView
* View::GetRootView() {
237 Widget
* widget
= GetWidget();
238 return widget
? widget
->GetRootView() : NULL
;
241 // Size and disposition --------------------------------------------------------
243 void View::SetBounds(int x
, int y
, int width
, int height
) {
244 SetBoundsRect(gfx::Rect(x
, y
, std::max(0, width
), std::max(0, height
)));
247 void View::SetBoundsRect(const gfx::Rect
& bounds
) {
248 if (bounds
== bounds_
) {
250 needs_layout_
= false;
257 gfx::Rect prev
= bounds_
;
262 void View::SetSize(const gfx::Size
& size
) {
263 SetBounds(x(), y(), size
.width(), size
.height());
266 void View::SetPosition(const gfx::Point
& position
) {
267 SetBounds(position
.x(), position
.y(), width(), height());
270 void View::SetX(int x
) {
271 SetBounds(x
, y(), width(), height());
274 void View::SetY(int y
) {
275 SetBounds(x(), y
, width(), height());
278 gfx::Rect
View::GetContentsBounds() const {
279 gfx::Rect
contents_bounds(GetLocalBounds());
282 border_
->GetInsets(&insets
);
283 contents_bounds
.Inset(insets
);
285 return contents_bounds
;
288 gfx::Rect
View::GetLocalBounds() const {
289 return gfx::Rect(0, 0, width(), height());
292 gfx::Insets
View::GetInsets() const {
295 border_
->GetInsets(&insets
);
299 gfx::Rect
View::GetVisibleBounds() {
300 if (!IsVisibleInRootView())
302 gfx::Rect
vis_bounds(0, 0, width(), height());
303 gfx::Rect ancestor_bounds
;
307 while (view
!= NULL
&& !vis_bounds
.IsEmpty()) {
308 root_x
+= view
->GetMirroredX();
310 vis_bounds
.Offset(view
->GetMirroredX(), view
->y());
311 View
* ancestor
= view
->parent();
312 if (ancestor
!= NULL
) {
313 ancestor_bounds
.SetRect(0, 0, ancestor
->width(),
315 vis_bounds
= vis_bounds
.Intersect(ancestor_bounds
);
316 } else if (!view
->GetWidget()) {
317 // If the view has no Widget, we're not visible. Return an empty rect.
322 if (vis_bounds
.IsEmpty())
324 // Convert back to this views coordinate system.
325 vis_bounds
.Offset(-root_x
, -root_y
);
329 gfx::Rect
View::GetScreenBounds() const {
331 View::ConvertPointToScreen(this, &origin
);
332 return gfx::Rect(origin
, size());
335 gfx::Size
View::GetPreferredSize() {
336 if (layout_manager_
.get())
337 return layout_manager_
->GetPreferredSize(this);
341 int View::GetBaseline() {
345 void View::SizeToPreferredSize() {
346 gfx::Size prefsize
= GetPreferredSize();
347 if ((prefsize
.width() != width()) || (prefsize
.height() != height()))
348 SetBounds(x(), y(), prefsize
.width(), prefsize
.height());
351 gfx::Size
View::GetMinimumSize() {
352 return GetPreferredSize();
355 int View::GetHeightForWidth(int w
) {
356 if (layout_manager_
.get())
357 return layout_manager_
->GetPreferredHeightForWidth(this, w
);
358 return GetPreferredSize().height();
361 void View::SetVisible(bool flag
) {
362 if (flag
!= is_visible_
) {
363 // If the tab is currently visible, schedule paint to
372 // This notifies all sub-views recursively.
373 PropagateVisibilityNotifications(this, flag
);
375 // If we are newly visible, schedule paint.
381 bool View::IsVisible() const {
385 bool View::IsVisibleInRootView() const {
386 return IsVisible() && parent() ? parent()->IsVisibleInRootView() : false;
389 void View::SetEnabled(bool state
) {
390 if (enabled_
!= state
) {
396 bool View::IsEnabled() const {
400 // Transformations -------------------------------------------------------------
402 const ui::Transform
& View::GetTransform() const {
403 static const ui::Transform
* no_op
= new ui::Transform
;
404 if (transform_
.get())
405 return *transform_
.get();
409 void View::SetTransform(const ui::Transform
& transform
) {
410 if (!transform
.HasChange()) {
411 if (!transform_
.get())
413 transform_
.reset(NULL
);
414 #if !defined(COMPOSITOR_2)
421 transform_
.reset(new ui::Transform(transform
));
422 // TODO: this needs to trigger a paint on the widget. It shouldn't use
423 // SchedulePaint as we don't want to mark the views dirty.
427 // RTL positioning -------------------------------------------------------------
429 gfx::Rect
View::GetMirroredBounds() const {
430 gfx::Rect
bounds(bounds_
);
431 bounds
.set_x(GetMirroredX());
435 gfx::Point
View::GetMirroredPosition() const {
436 return gfx::Point(GetMirroredX(), y());
439 int View::GetMirroredX() const {
440 return parent() ? parent()->GetMirroredXForRect(bounds_
) : x();
443 int View::GetMirroredXForRect(const gfx::Rect
& bounds
) const {
444 return base::i18n::IsRTL() ?
445 (width() - bounds
.x() - bounds
.width()) : bounds
.x();
448 int View::GetMirroredXInView(int x
) const {
449 return base::i18n::IsRTL() ? width() - x
: x
;
452 int View::GetMirroredXWithWidthInView(int x
, int w
) const {
453 return base::i18n::IsRTL() ? width() - x
- w
: x
;
456 // Layout ----------------------------------------------------------------------
458 void View::Layout() {
459 needs_layout_
= false;
461 // If we have a layout manager, let it handle the layout for us.
462 if (layout_manager_
.get())
463 layout_manager_
->Layout(this);
465 // Make sure to propagate the Layout() call to any children that haven't
466 // received it yet through the layout manager and need to be laid out. This
467 // is needed for the case when the child requires a layout but its bounds
468 // weren't changed by the layout manager. If there is no layout manager, we
469 // just propagate the Layout() call down the hierarchy, so whoever receives
470 // the call can take appropriate action.
471 for (int i
= 0, count
= child_count(); i
< count
; ++i
) {
472 View
* child
= GetChildViewAt(i
);
473 if (child
->needs_layout_
|| !layout_manager_
.get()) {
474 child
->needs_layout_
= false;
480 void View::InvalidateLayout() {
481 // Always invalidate up. This is needed to handle the case of us already being
482 // valid, but not our parent.
483 needs_layout_
= true;
485 parent_
->InvalidateLayout();
488 LayoutManager
* View::GetLayoutManager() const {
489 return layout_manager_
.get();
492 void View::SetLayoutManager(LayoutManager
* layout_manager
) {
493 if (layout_manager_
.get())
494 layout_manager_
->Uninstalled(this);
496 layout_manager_
.reset(layout_manager
);
497 if (layout_manager_
.get())
498 layout_manager_
->Installed(this);
501 // Attributes ------------------------------------------------------------------
503 std::string
View::GetClassName() const {
504 return kViewClassName
;
507 View
* View::GetAncestorWithClassName(const std::string
& name
) {
508 for (View
* view
= this; view
; view
= view
->parent()) {
509 if (view
->GetClassName() == name
)
515 const View
* View::GetViewByID(int id
) const {
517 return const_cast<View
*>(this);
519 for (int i
= 0, count
= child_count(); i
< count
; ++i
) {
520 const View
* view
= GetChildViewAt(i
)->GetViewByID(id
);
527 View
* View::GetViewByID(int id
) {
528 return const_cast<View
*>(const_cast<const View
*>(this)->GetViewByID(id
));
531 void View::SetID(int id
) {
535 int View::GetID() const {
539 void View::SetGroup(int gid
) {
540 // Don't change the group id once it's set.
541 DCHECK(group_
== -1 || group_
== gid
);
545 int View::GetGroup() const {
549 bool View::IsGroupFocusTraversable() const {
553 void View::GetViewsWithGroup(int group_id
, std::vector
<View
*>* out
) {
554 if (group_
== group_id
)
555 out
->push_back(this);
557 for (int i
= 0, count
= child_count(); i
< count
; ++i
)
558 GetChildViewAt(i
)->GetViewsWithGroup(group_id
, out
);
561 View
* View::GetSelectedViewForGroup(int group_id
) {
562 std::vector
<View
*> views
;
563 GetWidget()->GetRootView()->GetViewsWithGroup(group_id
, &views
);
564 return views
.empty() ? NULL
: views
[0];
567 // Coordinate conversion -------------------------------------------------------
570 void View::ConvertPointToView(const View
* src
,
573 ConvertPointToView(src
, dst
, point
, true);
577 void View::ConvertPointToWidget(const View
* src
, gfx::Point
* p
) {
581 src
->ConvertPointForAncestor(NULL
, p
);
585 void View::ConvertPointFromWidget(const View
* dest
, gfx::Point
* p
) {
589 dest
->ConvertPointFromAncestor(NULL
, p
);
593 void View::ConvertPointToScreen(const View
* src
, gfx::Point
* p
) {
597 // If the view is not connected to a tree, there's nothing we can do.
598 const Widget
* widget
= src
->GetWidget();
600 ConvertPointToWidget(src
, p
);
601 gfx::Rect r
= widget
->GetClientAreaScreenBounds();
602 p
->SetPoint(p
->x() + r
.x(), p
->y() + r
.y());
606 gfx::Rect
View::ConvertRectToParent(const gfx::Rect
& rect
) const {
607 if (!transform_
.get() || !transform_
->HasChange())
609 gfx::Rect x_rect
= rect
;
610 transform_
->TransformRect(&x_rect
);
614 // Painting --------------------------------------------------------------------
616 void View::SchedulePaint() {
617 SchedulePaintInRect(GetLocalBounds());
620 void View::SchedulePaintInRect(const gfx::Rect
& rect
) {
625 // Translate the requested paint rect to the parent's coordinate system
626 // then pass this notification up to the parent.
627 gfx::Rect paint_rect
= ConvertRectToParent(rect
);
628 paint_rect
.Offset(GetMirroredPosition());
629 parent_
->SchedulePaintInRect(paint_rect
);
633 void View::Paint(gfx::Canvas
* canvas
) {
637 ScopedCanvas
scoped_canvas(NULL
);
638 scoped_ptr
<gfx::Canvas
> texture_canvas
;
639 gfx::Rect texture_rect
;
641 #if !defined(COMPOSITOR_2)
642 if (use_acceleration_when_possible
&&
643 transform_
.get() && transform_
->HasChange()) {
644 // This view has a transformation. So this maintains its own canvas.
646 canvas_
.reset(gfx::Canvas::CreateCanvas(width(), height(), false));
648 if (ShouldPaintToTexture()) {
649 gfx::Rect dirty_rect
;
650 if (!texture_clip_rect_
.IsEmpty()) {
651 dirty_rect
= texture_clip_rect_
;
653 // TODO: clip against dirty rect of canvas (if canvas is non-null).
654 dirty_rect
= gfx::Rect(0, 0, width(), height());
656 if (dirty_rect
.IsEmpty())
660 texture_
.reset(GetCompositor()->CreateTexture());
662 if (!texture_needs_updating_
) {
663 // We don't need to be painted. Iterate over descendants in case one of
665 PaintToTexture(dirty_rect
);
669 texture_canvas
.reset(gfx::Canvas::CreateCanvas(dirty_rect
.width(),
670 dirty_rect
.height(), false));
671 texture_canvas
->AsCanvasSkia()->drawColor(
672 SK_ColorBLACK
, SkXfermode::kClear_Mode
);
673 texture_canvas
->TranslateInt(-dirty_rect
.x(), -dirty_rect
.y());
674 canvas
= texture_canvas
.get();
675 texture_rect
= dirty_rect
;
676 // TODO: set texture_needs_updating_ to false.
679 // We're going to modify the canvas, save its state first.
680 scoped_canvas
.SetCanvas(canvas
);
682 // Paint this View and its children, setting the clip rect to the bounds
683 // of this View and translating the origin to the local bounds' top left
686 // Note that the X (or left) position we pass to ClipRectInt takes into
687 // consideration whether or not the view uses a right-to-left layout so that
688 // we paint our view in its mirrored position if need be.
689 if (!canvas
->ClipRectInt(GetMirroredX(), y(),
690 width() - static_cast<int>(clip_x_
),
691 height() - static_cast<int>(clip_y_
))) {
694 // Non-empty clip, translate the graphics such that 0,0 corresponds to
695 // where this view is located (related to its parent).
696 canvas
->TranslateInt(GetMirroredX(), y());
698 if (transform_
.get() && transform_
->HasChange())
699 canvas
->Transform(*transform_
.get());
703 // If the View we are about to paint requested the canvas to be flipped, we
704 // should change the transform appropriately.
705 // The canvas mirroring is undone once the View is done painting so that we
706 // don't pass the canvas with the mirrored transform to Views that didn't
707 // request the canvas to be flipped.
709 ScopedCanvas
scoped(canvas
);
710 if (FlipCanvasOnPaintForRTLUI()) {
711 canvas
->TranslateInt(width(), 0);
712 canvas
->ScaleInt(-1, 1);
718 PaintChildren(canvas
);
720 #if !defined(COMPOSITOR_2)
721 if (canvas
== canvas_
.get()) {
722 texture_id_
= canvas
->GetTextureID();
724 // TODO(sadrul): Make sure the Widget's compositor tree updates itself?
727 if (texture_canvas
.get()) {
729 texture_canvas
->AsCanvasSkia()->getDevice()->accessBitmap(false),
730 texture_rect
.origin(),
736 ThemeProvider
* View::GetThemeProvider() const {
737 const Widget
* widget
= GetWidget();
738 return widget
? widget
->GetThemeProvider() : NULL
;
741 // Accelerated Painting --------------------------------------------------------
744 void View::set_use_acceleration_when_possible(bool use
) {
745 use_acceleration_when_possible
= use
;
748 // Input -----------------------------------------------------------------------
750 View
* View::GetEventHandlerForPoint(const gfx::Point
& point
) {
751 // Walk the child Views recursively looking for the View that most
752 // tightly encloses the specified point.
753 for (int i
= child_count() - 1; i
>= 0; --i
) {
754 View
* child
= GetChildViewAt(i
);
755 if (!child
->IsVisible())
758 gfx::Point
point_in_child_coords(point
);
759 View::ConvertPointToView(this, child
, &point_in_child_coords
);
760 if (child
->HitTest(point_in_child_coords
))
761 return child
->GetEventHandlerForPoint(point_in_child_coords
);
766 gfx::NativeCursor
View::GetCursor(const MouseEvent
& event
) {
768 static HCURSOR arrow
= LoadCursor(NULL
, IDC_ARROW
);
775 bool View::HitTest(const gfx::Point
& l
) const {
776 if (GetLocalBounds().Contains(l
)) {
777 if (HasHitTestMask()) {
779 GetHitTestMask(&mask
);
780 // TODO: can this use SkRegion's contains instead?
782 base::win::ScopedRegion
rgn(mask
.CreateNativeRegion());
783 return !!PtInRegion(rgn
, l
.x(), l
.y());
784 #elif defined(TOOLKIT_USES_GTK)
785 ui::ScopedRegion
rgn(mask
.CreateNativeRegion());
786 return gdk_region_point_in(rgn
.Get(), l
.x(), l
.y());
789 // No mask, but inside our bounds.
792 // Outside our bounds.
796 bool View::OnMousePressed(const MouseEvent
& event
) {
800 bool View::OnMouseDragged(const MouseEvent
& event
) {
804 void View::OnMouseReleased(const MouseEvent
& event
) {
807 void View::OnMouseCaptureLost() {
810 void View::OnMouseMoved(const MouseEvent
& event
) {
813 void View::OnMouseEntered(const MouseEvent
& event
) {
816 void View::OnMouseExited(const MouseEvent
& event
) {
819 #if defined(TOUCH_UI)
820 View::TouchStatus
View::OnTouchEvent(const TouchEvent
& event
) {
821 DVLOG(1) << "visited the OnTouchEvent";
822 return TOUCH_STATUS_UNKNOWN
;
826 void View::SetMouseHandler(View
*new_mouse_handler
) {
827 // It is valid for new_mouse_handler to be NULL
829 parent_
->SetMouseHandler(new_mouse_handler
);
832 bool View::OnKeyPressed(const KeyEvent
& event
) {
836 bool View::OnKeyReleased(const KeyEvent
& event
) {
840 bool View::OnMouseWheel(const MouseWheelEvent
& event
) {
844 TextInputClient
* View::GetTextInputClient() {
848 InputMethod
* View::GetInputMethod() {
849 Widget
* widget
= GetWidget();
850 return widget
? widget
->GetInputMethod() : NULL
;
853 // Accelerators ----------------------------------------------------------------
855 void View::AddAccelerator(const Accelerator
& accelerator
) {
856 if (!accelerators_
.get())
857 accelerators_
.reset(new std::vector
<Accelerator
>());
859 std::vector
<Accelerator
>::iterator iter
=
860 std::find(accelerators_
->begin(), accelerators_
->end(), accelerator
);
861 DCHECK(iter
== accelerators_
->end())
862 << "Registering the same accelerator multiple times";
864 accelerators_
->push_back(accelerator
);
865 RegisterPendingAccelerators();
868 void View::RemoveAccelerator(const Accelerator
& accelerator
) {
869 std::vector
<Accelerator
>::iterator iter
;
870 if (!accelerators_
.get() ||
871 ((iter
= std::find(accelerators_
->begin(), accelerators_
->end(),
872 accelerator
)) == accelerators_
->end())) {
873 NOTREACHED() << "Removing non-existing accelerator";
877 size_t index
= iter
- accelerators_
->begin();
878 accelerators_
->erase(iter
);
879 if (index
>= registered_accelerator_count_
) {
880 // The accelerator is not registered to FocusManager.
883 --registered_accelerator_count_
;
885 // Providing we are attached to a Widget and registered with a focus manager,
886 // we should de-register from that focus manager now.
887 if (GetWidget() && accelerator_focus_manager_
)
888 accelerator_focus_manager_
->UnregisterAccelerator(accelerator
, this);
891 void View::ResetAccelerators() {
892 if (accelerators_
.get())
893 UnregisterAccelerators(false);
896 bool View::AcceleratorPressed(const Accelerator
& accelerator
) {
900 // Focus -----------------------------------------------------------------------
902 bool View::HasFocus() {
903 FocusManager
* focus_manager
= GetFocusManager();
905 return focus_manager
->GetFocusedView() == this;
909 View
* View::GetNextFocusableView() {
910 return next_focusable_view_
;
913 const View
* View::GetNextFocusableView() const {
914 return next_focusable_view_
;
917 View
* View::GetPreviousFocusableView() {
918 return previous_focusable_view_
;
921 void View::SetNextFocusableView(View
* view
) {
922 view
->previous_focusable_view_
= this;
923 next_focusable_view_
= view
;
926 void View::SetFocusable(bool focusable
) {
927 focusable_
= focusable
;
930 bool View::IsFocusableInRootView() const {
931 return IsFocusable() && IsVisibleInRootView();
934 bool View::IsAccessibilityFocusableInRootView() const {
935 return (focusable_
|| accessibility_focusable_
) && IsEnabled() &&
936 IsVisibleInRootView();
939 void View::set_accessibility_focusable(bool accessibility_focusable
) {
940 accessibility_focusable_
= accessibility_focusable
;
943 FocusManager
* View::GetFocusManager() {
944 Widget
* widget
= GetWidget();
945 return widget
? widget
->GetFocusManager() : NULL
;
948 void View::RequestFocus() {
949 FocusManager
* focus_manager
= GetFocusManager();
950 if (focus_manager
&& IsFocusableInRootView())
951 focus_manager
->SetFocusedView(this);
954 bool View::SkipDefaultKeyEventProcessing(const KeyEvent
& event
) {
958 FocusTraversable
* View::GetFocusTraversable() {
962 FocusTraversable
* View::GetPaneFocusTraversable() {
966 // Tooltips --------------------------------------------------------------------
968 bool View::GetTooltipText(const gfx::Point
& p
, std::wstring
* tooltip
) {
972 bool View::GetTooltipTextOrigin(const gfx::Point
& p
, gfx::Point
* loc
) {
976 // Context menus ---------------------------------------------------------------
978 void View::SetContextMenuController(ContextMenuController
* menu_controller
) {
979 context_menu_controller_
= menu_controller
;
982 void View::ShowContextMenu(const gfx::Point
& p
, bool is_mouse_gesture
) {
983 if (!context_menu_controller_
)
986 context_menu_controller_
->ShowContextMenuForView(this, p
, is_mouse_gesture
);
989 // Drag and drop ---------------------------------------------------------------
991 void View::SetDragController(DragController
* drag_controller
) {
992 drag_controller_
= drag_controller
;
995 DragController
* View::GetDragController() {
996 return drag_controller_
;
999 bool View::GetDropFormats(
1001 std::set
<OSExchangeData::CustomFormat
>* custom_formats
) {
1005 bool View::AreDropTypesRequired() {
1009 bool View::CanDrop(const OSExchangeData
& data
) {
1010 // TODO(sky): when I finish up migration, this should default to true.
1014 void View::OnDragEntered(const DropTargetEvent
& event
) {
1017 int View::OnDragUpdated(const DropTargetEvent
& event
) {
1018 return ui::DragDropTypes::DRAG_NONE
;
1021 void View::OnDragExited() {
1024 int View::OnPerformDrop(const DropTargetEvent
& event
) {
1025 return ui::DragDropTypes::DRAG_NONE
;
1028 void View::OnDragDone() {
1032 bool View::ExceededDragThreshold(int delta_x
, int delta_y
) {
1033 return (abs(delta_x
) > GetHorizontalDragThreshold() ||
1034 abs(delta_y
) > GetVerticalDragThreshold());
1037 // Scrolling -------------------------------------------------------------------
1039 void View::ScrollRectToVisible(const gfx::Rect
& rect
) {
1040 // We must take RTL UI mirroring into account when adjusting the position of
1043 gfx::Rect
scroll_rect(rect
);
1044 scroll_rect
.Offset(GetMirroredX(), y());
1045 parent()->ScrollRectToVisible(scroll_rect
);
1049 int View::GetPageScrollIncrement(ScrollView
* scroll_view
,
1050 bool is_horizontal
, bool is_positive
) {
1054 int View::GetLineScrollIncrement(ScrollView
* scroll_view
,
1055 bool is_horizontal
, bool is_positive
) {
1059 ////////////////////////////////////////////////////////////////////////////////
1062 // Size and disposition --------------------------------------------------------
1064 void View::OnBoundsChanged(const gfx::Rect
& previous_bounds
) {
1067 void View::PreferredSizeChanged() {
1070 parent_
->ChildPreferredSizeChanged(this);
1073 bool View::NeedsNotificationWhenVisibleBoundsChange() const {
1077 void View::OnVisibleBoundsChanged() {
1080 // Tree operations -------------------------------------------------------------
1082 void View::ViewHierarchyChanged(bool is_add
, View
* parent
, View
* child
) {
1085 void View::VisibilityChanged(View
* starting_from
, bool is_visible
) {
1088 void View::NativeViewHierarchyChanged(bool attached
,
1089 gfx::NativeView native_view
,
1090 RootView
* root_view
) {
1091 FocusManager
* focus_manager
= GetFocusManager();
1092 if (!accelerator_registration_delayed_
&&
1093 accelerator_focus_manager_
&&
1094 accelerator_focus_manager_
!= focus_manager
) {
1095 UnregisterAccelerators(true);
1096 accelerator_registration_delayed_
= true;
1098 if (accelerator_registration_delayed_
&& attached
) {
1099 if (focus_manager
) {
1100 RegisterPendingAccelerators();
1101 accelerator_registration_delayed_
= false;
1106 // Painting --------------------------------------------------------------------
1108 void View::PaintChildren(gfx::Canvas
* canvas
) {
1109 for (int i
= 0, count
= child_count(); i
< count
; ++i
) {
1110 View
* child
= GetChildViewAt(i
);
1112 NOTREACHED() << "Should not have a NULL child View for index in bounds";
1115 child
->Paint(canvas
);
1119 void View::OnPaint(gfx::Canvas
* canvas
) {
1120 OnPaintBackground(canvas
);
1121 OnPaintFocusBorder(canvas
);
1122 OnPaintBorder(canvas
);
1125 void View::OnPaintBackground(gfx::Canvas
* canvas
) {
1126 if (background_
.get())
1127 background_
->Paint(canvas
, this);
1130 void View::OnPaintBorder(gfx::Canvas
* canvas
) {
1132 border_
->Paint(*this, canvas
);
1135 void View::OnPaintFocusBorder(gfx::Canvas
* canvas
) {
1136 if ((IsFocusable() || IsAccessibilityFocusableInRootView()) && HasFocus())
1137 canvas
->DrawFocusRect(0, 0, width(), height());
1140 // Accelerated Painting --------------------------------------------------------
1142 #if !defined(COMPOSITOR_2)
1143 void View::PaintComposite(ui::Compositor
* compositor
) {
1144 compositor
->SaveTransform();
1146 // TODO(sad): Push a transform matrix for the offset and bounds of the view?
1148 compositor
->DrawTextureWithTransform(texture_id_
, GetTransform());
1150 for (int i
= 0, count
= child_count(); i
< count
; ++i
) {
1151 View
* child
= GetChildViewAt(i
);
1152 child
->PaintComposite(compositor
);
1155 compositor
->RestoreTransform();
1158 void View::PaintComposite() {
1162 if (texture_
.get()) {
1163 // TODO: if dirty_region doesn't itersect bounds, return.
1164 ui::Transform transform
;
1165 GetTransformRelativeTo(NULL
, &transform
);
1166 texture_
->Draw(transform
);
1169 for (int i
= 0, count
= child_count(); i
< count
; ++i
)
1170 GetChildViewAt(i
)->PaintComposite();
1173 void View::PaintToTexture(const gfx::Rect
& dirty_region
) {
1177 if (ShouldPaintToTexture() && texture_needs_updating_
) {
1178 texture_clip_rect_
= dirty_region
;
1180 texture_clip_rect_
.SetRect(0, 0, 0, 0);
1182 // Forward to all children as a descendant may be dirty and have a texture.
1183 for (int i
= child_count() - 1; i
>= 0; --i
) {
1184 View
* child_view
= GetChildViewAt(i
);
1185 gfx::Rect
child_dirty_rect(child_view
->bounds().Intersect(dirty_region
));
1186 if (!child_dirty_rect
.IsEmpty()) {
1187 child_dirty_rect
.Offset(-child_view
->x(), -child_view
->y());
1188 GetChildViewAt(i
)->PaintToTexture(child_dirty_rect
);
1195 bool View::ShouldPaintToTexture() const {
1196 return use_acceleration_when_possible
&& transform_
.get() &&
1197 transform_
->HasChange() && GetCompositor();
1200 const ui::Compositor
* View::GetCompositor() const {
1201 return parent_
? parent_
->GetCompositor() : NULL
;
1204 ui::Compositor
* View::GetCompositor() {
1205 return parent_
? parent_
->GetCompositor() : NULL
;
1208 // Input -----------------------------------------------------------------------
1210 bool View::HasHitTestMask() const {
1214 void View::GetHitTestMask(gfx::Path
* mask
) const {
1218 // Focus -----------------------------------------------------------------------
1220 bool View::IsFocusable() const {
1221 return focusable_
&& IsEnabled() && IsVisible();
1224 void View::OnFocus() {
1225 // TODO(beng): Investigate whether it's possible for us to move this to
1227 // By default, we clear the native focus. This ensures that no visible native
1228 // view as the focus and that we still receive keyboard inputs.
1229 FocusManager
* focus_manager
= GetFocusManager();
1231 focus_manager
->ClearNativeFocus();
1233 // TODO(beng): Investigate whether it's possible for us to move this to
1235 // Notify assistive technologies of the focus change.
1236 GetWidget()->NotifyAccessibilityEvent(
1237 this, ui::AccessibilityTypes::EVENT_FOCUS
, true);
1240 void View::OnBlur() {
1243 void View::Focus() {
1253 // Tooltips --------------------------------------------------------------------
1255 void View::TooltipTextChanged() {
1256 Widget
* widget
= GetWidget();
1258 widget
->native_widget()->GetTooltipManager()->TooltipTextChanged(this);
1261 // Context menus ---------------------------------------------------------------
1263 gfx::Point
View::GetKeyboardContextMenuLocation() {
1264 gfx::Rect vis_bounds
= GetVisibleBounds();
1265 gfx::Point
screen_point(vis_bounds
.x() + vis_bounds
.width() / 2,
1266 vis_bounds
.y() + vis_bounds
.height() / 2);
1267 ConvertPointToScreen(this, &screen_point
);
1268 return screen_point
;
1271 // Drag and drop ---------------------------------------------------------------
1273 int View::GetDragOperations(const gfx::Point
& press_pt
) {
1274 return drag_controller_
?
1275 drag_controller_
->GetDragOperationsForView(this, press_pt
) :
1276 ui::DragDropTypes::DRAG_NONE
;
1279 void View::WriteDragData(const gfx::Point
& press_pt
, OSExchangeData
* data
) {
1280 DCHECK(drag_controller_
);
1281 drag_controller_
->WriteDragDataForView(this, press_pt
, data
);
1284 bool View::InDrag() {
1285 Widget
* widget
= GetWidget();
1286 return widget
? widget
->dragged_view() == this : false;
1289 ////////////////////////////////////////////////////////////////////////////////
1292 // DropInfo --------------------------------------------------------------------
1294 void View::DragInfo::Reset() {
1295 possible_drag
= false;
1296 start_pt
= gfx::Point();
1299 void View::DragInfo::PossibleDrag(const gfx::Point
& p
) {
1300 possible_drag
= true;
1304 // Tree operations -------------------------------------------------------------
1306 void View::DoRemoveChildView(View
* view
,
1307 bool update_focus_cycle
,
1308 bool update_tool_tip
,
1309 bool delete_removed_view
) {
1311 const ViewVector::iterator i
= find(children_
.begin(), children_
.end(), view
);
1312 scoped_ptr
<View
> view_to_be_deleted
;
1313 if (i
!= children_
.end()) {
1314 if (update_focus_cycle
) {
1315 // Let's remove the view from the focus traversal.
1316 View
* next_focusable
= view
->next_focusable_view_
;
1317 View
* prev_focusable
= view
->previous_focusable_view_
;
1319 prev_focusable
->next_focusable_view_
= next_focusable
;
1321 next_focusable
->previous_focusable_view_
= prev_focusable
;
1325 UnregisterChildrenForVisibleBoundsNotification(view
);
1326 view
->ResetTexture();
1327 view
->PropagateRemoveNotifications(this);
1328 view
->SetParent(NULL
);
1330 if (delete_removed_view
&& view
->IsParentOwned())
1331 view_to_be_deleted
.reset(view
);
1336 if (update_tool_tip
)
1339 if (layout_manager_
.get())
1340 layout_manager_
->ViewRemoved(this, view
);
1343 void View::SetParent(View
* parent
) {
1344 if (parent
!= parent_
)
1348 void View::PropagateRemoveNotifications(View
* parent
) {
1349 for (int i
= 0, count
= child_count(); i
< count
; ++i
)
1350 GetChildViewAt(i
)->PropagateRemoveNotifications(parent
);
1352 for (View
* v
= this; v
; v
= v
->parent())
1353 v
->ViewHierarchyChangedImpl(true, false, parent
, this);
1356 void View::PropagateAddNotifications(View
* parent
, View
* child
) {
1357 for (int i
= 0, count
= child_count(); i
< count
; ++i
)
1358 GetChildViewAt(i
)->PropagateAddNotifications(parent
, child
);
1359 ViewHierarchyChangedImpl(true, true, parent
, child
);
1362 void View::PropagateNativeViewHierarchyChanged(bool attached
,
1363 gfx::NativeView native_view
,
1364 RootView
* root_view
) {
1365 for (int i
= 0, count
= child_count(); i
< count
; ++i
)
1366 GetChildViewAt(i
)->PropagateNativeViewHierarchyChanged(attached
,
1369 NativeViewHierarchyChanged(attached
, native_view
, root_view
);
1372 void View::ViewHierarchyChangedImpl(bool register_accelerators
,
1376 if (register_accelerators
) {
1378 // If you get this registration, you are part of a subtree that has been
1379 // added to the view hierarchy.
1380 if (GetFocusManager()) {
1381 RegisterPendingAccelerators();
1383 // Delay accelerator registration until visible as we do not have
1384 // focus manager until then.
1385 accelerator_registration_delayed_
= true;
1389 UnregisterAccelerators(true);
1393 ViewHierarchyChanged(is_add
, parent
, child
);
1394 parent
->needs_layout_
= true;
1397 // Size and disposition --------------------------------------------------------
1399 void View::PropagateVisibilityNotifications(View
* start
, bool is_visible
) {
1400 for (int i
= 0, count
= child_count(); i
< count
; ++i
)
1401 GetChildViewAt(i
)->PropagateVisibilityNotifications(start
, is_visible
);
1402 VisibilityChangedImpl(start
, is_visible
);
1405 void View::VisibilityChangedImpl(View
* starting_from
, bool is_visible
) {
1407 RegisterPendingAccelerators();
1409 UnregisterAccelerators(true);
1410 VisibilityChanged(starting_from
, is_visible
);
1413 void View::BoundsChanged(const gfx::Rect
& previous_bounds
) {
1414 #if !defined(COMPOSITOR_2)
1416 canvas_
.reset(gfx::Canvas::CreateCanvas(width(), height(), false));
1421 // Paint the old bounds.
1422 if (base::i18n::IsRTL()) {
1423 gfx::Rect paint_rect
= previous_bounds
;
1424 paint_rect
.set_x(parent()->GetMirroredXForRect(paint_rect
));
1425 parent_
->SchedulePaintInRect(paint_rect
);
1427 parent_
->SchedulePaintInRect(previous_bounds
);
1431 parent_
->SchedulePaintInRect(GetMirroredBounds());
1433 // Previous bounds has no meaning to an orphan. This should only happen
1434 // when the View is a RootView.
1435 SchedulePaintInRect(gfx::Rect(0, 0, bounds_
.width(), bounds_
.height()));
1439 OnBoundsChanged(previous_bounds
);
1441 if (previous_bounds
.size() != size()) {
1442 needs_layout_
= false;
1446 if (NeedsNotificationWhenVisibleBoundsChange()) {
1447 OnVisibleBoundsChanged();
1450 // Notify interested Views that visible bounds within the root view may have
1452 if (descendants_to_notify_
.get()) {
1453 for (std::vector
<View
*>::iterator i
= descendants_to_notify_
->begin();
1454 i
!= descendants_to_notify_
->end(); ++i
) {
1455 (*i
)->OnVisibleBoundsChanged();
1461 void View::RegisterChildrenForVisibleBoundsNotification(View
* view
) {
1462 if (view
->NeedsNotificationWhenVisibleBoundsChange())
1463 view
->RegisterForVisibleBoundsNotification();
1464 for (int i
= 0; i
< view
->child_count(); ++i
)
1465 RegisterChildrenForVisibleBoundsNotification(view
->GetChildViewAt(i
));
1469 void View::UnregisterChildrenForVisibleBoundsNotification(View
* view
) {
1470 if (view
->NeedsNotificationWhenVisibleBoundsChange())
1471 view
->UnregisterForVisibleBoundsNotification();
1472 for (int i
= 0; i
< view
->child_count(); ++i
)
1473 UnregisterChildrenForVisibleBoundsNotification(view
->GetChildViewAt(i
));
1476 void View::RegisterForVisibleBoundsNotification() {
1477 if (registered_for_visible_bounds_notification_
)
1480 registered_for_visible_bounds_notification_
= true;
1481 View
* ancestor
= parent();
1483 ancestor
->AddDescendantToNotify(this);
1484 ancestor
= ancestor
->parent();
1488 void View::UnregisterForVisibleBoundsNotification() {
1489 if (!registered_for_visible_bounds_notification_
)
1491 registered_for_visible_bounds_notification_
= false;
1492 View
* ancestor
= parent();
1494 ancestor
->RemoveDescendantToNotify(this);
1495 ancestor
= ancestor
->parent();
1499 void View::AddDescendantToNotify(View
* view
) {
1501 if (!descendants_to_notify_
.get())
1502 descendants_to_notify_
.reset(new ViewVector
);
1503 descendants_to_notify_
->push_back(view
);
1506 void View::RemoveDescendantToNotify(View
* view
) {
1507 DCHECK(view
&& descendants_to_notify_
.get());
1508 ViewVector::iterator i
= find(descendants_to_notify_
->begin(),
1509 descendants_to_notify_
->end(),
1511 DCHECK(i
!= descendants_to_notify_
->end());
1512 descendants_to_notify_
->erase(i
);
1513 if (descendants_to_notify_
->empty())
1514 descendants_to_notify_
.reset();
1517 // Transformations -------------------------------------------------------------
1519 bool View::GetTransformRelativeTo(const View
* ancestor
,
1520 ui::Transform
* transform
) const {
1521 const View
* p
= this;
1523 while (p
&& p
!= ancestor
) {
1524 if (p
->transform_
.get())
1525 transform
->ConcatTransform(*p
->transform_
);
1526 transform
->ConcatTranslate(static_cast<float>(p
->GetMirroredX()),
1527 static_cast<float>(p
->y()));
1532 return p
== ancestor
;
1535 // Coordinate conversion -------------------------------------------------------
1538 void View::ConvertPointToView(const View
* src
,
1541 bool try_other_direction
) {
1546 if (src
== NULL
|| src
->Contains(dst
)) {
1547 dst
->ConvertPointFromAncestor(src
, point
);
1549 const Widget
* widget
= dst
->GetWidget();
1551 gfx::Rect b
= widget
->GetClientAreaScreenBounds();
1552 point
->SetPoint(point
->x() - b
.x(), point
->y() - b
.y());
1555 } else if (src
&& try_other_direction
) {
1556 if (!src
->ConvertPointForAncestor(dst
, point
)) {
1557 // |src| is not an ancestor of |dst|, and |dst| is not an ancestor of
1558 // |src| either. At this stage, |point| is in the widget's coordinate
1559 // system. So convert from the widget's to |dst|'s coordinate system now.
1560 ConvertPointFromWidget(dst
, point
);
1565 bool View::ConvertPointForAncestor(const View
* ancestor
,
1566 gfx::Point
* point
) const {
1567 ui::Transform trans
;
1568 // TODO(sad): Have some way of caching the transformation results.
1569 bool result
= GetTransformRelativeTo(ancestor
, &trans
);
1570 trans
.TransformPoint(point
);
1574 bool View::ConvertPointFromAncestor(const View
* ancestor
,
1575 gfx::Point
* point
) const {
1576 ui::Transform trans
;
1577 bool result
= GetTransformRelativeTo(ancestor
, &trans
);
1578 trans
.TransformPointReverse(point
);
1582 // Accelerated painting --------------------------------------------------------
1584 void View::ResetTexture() {
1585 #if defined(COMPOSITOR_2)
1587 for (int i
= child_count() - 1; i
>= 0; --i
)
1588 GetChildViewAt(i
)->ResetTexture();
1592 // Input -----------------------------------------------------------------------
1594 bool View::ProcessMousePressed(const MouseEvent
& event
, DragInfo
* drag_info
) {
1595 const bool enabled
= IsEnabled();
1596 int drag_operations
=
1597 (enabled
&& event
.IsOnlyLeftMouseButton() && HitTest(event
.location())) ?
1598 GetDragOperations(event
.location()) : 0;
1599 ContextMenuController
* context_menu_controller
= event
.IsRightMouseButton() ?
1600 context_menu_controller_
: 0;
1602 const bool result
= OnMousePressed(event
);
1603 // WARNING: we may have been deleted, don't use any View variables.
1608 if (drag_operations
!= ui::DragDropTypes::DRAG_NONE
) {
1609 drag_info
->PossibleDrag(event
.location());
1612 return !!context_menu_controller
|| result
;
1615 bool View::ProcessMouseDragged(const MouseEvent
& event
, DragInfo
* drag_info
) {
1616 // Copy the field, that way if we're deleted after drag and drop no harm is
1618 ContextMenuController
* context_menu_controller
= context_menu_controller_
;
1619 const bool possible_drag
= drag_info
->possible_drag
;
1620 if (possible_drag
&& ExceededDragThreshold(
1621 drag_info
->start_pt
.x() - event
.x(),
1622 drag_info
->start_pt
.y() - event
.y())) {
1623 if (!drag_controller_
||
1624 drag_controller_
->CanStartDragForView(
1625 this, drag_info
->start_pt
, event
.location()))
1626 DoDrag(event
, drag_info
->start_pt
);
1628 if (OnMouseDragged(event
))
1630 // Fall through to return value based on context menu controller.
1632 // WARNING: we may have been deleted.
1633 return (context_menu_controller
!= NULL
) || possible_drag
;
1636 void View::ProcessMouseReleased(const MouseEvent
& event
) {
1637 if (context_menu_controller_
&& event
.IsOnlyRightMouseButton()) {
1638 // Assume that if there is a context menu controller we won't be deleted
1639 // from mouse released.
1640 gfx::Point
location(event
.location());
1641 OnMouseReleased(event
);
1642 if (HitTest(location
)) {
1643 ConvertPointToScreen(this, &location
);
1644 ShowContextMenu(location
, true);
1647 OnMouseReleased(event
);
1649 // WARNING: we may have been deleted.
1652 #if defined(TOUCH_UI)
1653 View::TouchStatus
View::ProcessTouchEvent(const TouchEvent
& event
) {
1654 // TODO(rjkroege): Implement a grab scheme similar to as
1655 // as is found in MousePressed.
1656 return OnTouchEvent(event
);
1660 // Accelerators ----------------------------------------------------------------
1662 void View::RegisterPendingAccelerators() {
1663 if (!accelerators_
.get() ||
1664 registered_accelerator_count_
== accelerators_
->size()) {
1665 // No accelerators are waiting for registration.
1670 // The view is not yet attached to a widget, defer registration until then.
1674 accelerator_focus_manager_
= GetFocusManager();
1675 if (!accelerator_focus_manager_
) {
1676 // Some crash reports seem to show that we may get cases where we have no
1677 // focus manager (see bug #1291225). This should never be the case, just
1678 // making sure we don't crash.
1680 // TODO(jcampan): This fails for a view under NativeWidgetGtk with
1681 // TYPE_CHILD. (see http://crbug.com/21335) reenable
1682 // NOTREACHED assertion and verify accelerators works as
1689 // Only register accelerators if we are visible.
1690 if (!IsVisibleInRootView())
1692 std::vector
<Accelerator
>::const_iterator iter
;
1693 for (iter
= accelerators_
->begin() + registered_accelerator_count_
;
1694 iter
!= accelerators_
->end(); ++iter
) {
1695 accelerator_focus_manager_
->RegisterAccelerator(*iter
, this);
1697 registered_accelerator_count_
= accelerators_
->size();
1700 void View::UnregisterAccelerators(bool leave_data_intact
) {
1701 if (!accelerators_
.get())
1705 if (accelerator_focus_manager_
) {
1706 // We may not have a FocusManager if the window containing us is being
1707 // closed, in which case the FocusManager is being deleted so there is
1708 // nothing to unregister.
1709 accelerator_focus_manager_
->UnregisterAccelerators(this);
1710 accelerator_focus_manager_
= NULL
;
1712 if (!leave_data_intact
) {
1713 accelerators_
->clear();
1714 accelerators_
.reset();
1716 registered_accelerator_count_
= 0;
1720 // Focus -----------------------------------------------------------------------
1722 void View::InitFocusSiblings(View
* v
, int index
) {
1723 int child_count
= static_cast<int>(children_
.size());
1725 if (child_count
== 0) {
1726 v
->next_focusable_view_
= NULL
;
1727 v
->previous_focusable_view_
= NULL
;
1729 if (index
== child_count
) {
1730 // We are inserting at the end, but the end of the child list may not be
1731 // the last focusable element. Let's try to find an element with no next
1732 // focusable element to link to.
1733 View
* last_focusable_view
= NULL
;
1734 for (std::vector
<View
*>::iterator iter
= children_
.begin();
1735 iter
!= children_
.end(); ++iter
) {
1736 if (!(*iter
)->next_focusable_view_
) {
1737 last_focusable_view
= *iter
;
1741 if (last_focusable_view
== NULL
) {
1742 // Hum... there is a cycle in the focus list. Let's just insert ourself
1743 // after the last child.
1744 View
* prev
= children_
[index
- 1];
1745 v
->previous_focusable_view_
= prev
;
1746 v
->next_focusable_view_
= prev
->next_focusable_view_
;
1747 prev
->next_focusable_view_
->previous_focusable_view_
= v
;
1748 prev
->next_focusable_view_
= v
;
1750 last_focusable_view
->next_focusable_view_
= v
;
1751 v
->next_focusable_view_
= NULL
;
1752 v
->previous_focusable_view_
= last_focusable_view
;
1755 View
* prev
= children_
[index
]->GetPreviousFocusableView();
1756 v
->previous_focusable_view_
= prev
;
1757 v
->next_focusable_view_
= children_
[index
];
1759 prev
->next_focusable_view_
= v
;
1760 children_
[index
]->previous_focusable_view_
= v
;
1765 // System events ---------------------------------------------------------------
1767 void View::PropagateThemeChanged() {
1768 for (int i
= child_count() - 1; i
>= 0; --i
)
1769 GetChildViewAt(i
)->PropagateThemeChanged();
1773 void View::PropagateLocaleChanged() {
1774 for (int i
= child_count() - 1; i
>= 0; --i
)
1775 GetChildViewAt(i
)->PropagateLocaleChanged();
1779 // Tooltips --------------------------------------------------------------------
1781 void View::UpdateTooltip() {
1782 Widget
* widget
= GetWidget();
1783 // TODO(beng): The TooltipManager NULL check can be removed when we
1784 // consolidate Init() methods and make views_unittests Init() all
1785 // Widgets that it uses.
1786 if (widget
&& widget
->native_widget()->GetTooltipManager())
1787 widget
->native_widget()->GetTooltipManager()->UpdateTooltip();
1790 // Drag and drop ---------------------------------------------------------------
1792 void View::DoDrag(const MouseEvent
& event
, const gfx::Point
& press_pt
) {
1793 int drag_operations
= GetDragOperations(press_pt
);
1794 if (drag_operations
== ui::DragDropTypes::DRAG_NONE
)
1797 OSExchangeData data
;
1798 WriteDragData(press_pt
, &data
);
1800 // Message the RootView to do the drag and drop. That way if we're removed
1801 // the RootView can detect it and avoid calling us back.
1802 GetWidget()->RunShellDrag(this, data
, drag_operations
);
1805 // Debugging -------------------------------------------------------------------
1807 #if defined(TOUCH_DEBUG)
1808 std::string
View::PrintViewGraph(bool first
) {
1809 // 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19.
1810 const size_t kMaxPointerStringLength
= 19;
1815 result
.append("digraph {\n");
1817 // Node characteristics.
1818 char p
[kMaxPointerStringLength
];
1820 size_t baseNameIndex
= GetClassName().find_last_of('/');
1821 if (baseNameIndex
== std::string::npos
)
1826 // Information about current node.
1827 snprintf(p
, kMaxPointerStringLength
, "%p", this);
1828 result
.append(" N");
1830 result
.append(" [label=\"");
1831 result
.append(GetClassName().substr(baseNameIndex
).c_str());
1832 result
.append("\"");
1834 result
.append(", shape=box");
1835 #if defined(COMPOSITOR_2)
1840 result
.append(", color=green");
1841 result
.append("]\n");
1845 char pp
[kMaxPointerStringLength
];
1847 snprintf(pp
, kMaxPointerStringLength
, "%p", parent());
1848 result
.append(" N");
1849 result
.append(pp
+2);
1850 result
.append(" -> N");
1852 result
.append("\n");
1856 for (int i
= 0, count
= child_count(); i
< count
; ++i
)
1857 result
.append(GetChildViewAt(i
)->PrintViewGraph(false));
1860 result
.append("}\n");
1866 } // namespace views