diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-05 00:38:59 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-05 00:38:59 +0000 |
commit | 2df3cc9dfb4505948bd47b3ef8b8f180bffe30f9 (patch) | |
tree | 474ec6d896489a23c5b4cc6811751ec0d0e287ee /views | |
parent | d7f0642692c2ac6de15cd1e713e0c88dd740b58e (diff) | |
download | chromium_src-2df3cc9dfb4505948bd47b3ef8b8f180bffe30f9.zip chromium_src-2df3cc9dfb4505948bd47b3ef8b8f180bffe30f9.tar.gz chromium_src-2df3cc9dfb4505948bd47b3ef8b8f180bffe30f9.tar.bz2 |
Sort the methods in views into sections, and make .cc order match .h
This is the first phase of upgrading views::View to the V2 API.
BUG=none
TEST=none
TBR=sky
Review URL: http://codereview.chromium.org/6413001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73881 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/view.cc | 1809 | ||||
-rw-r--r-- | views/view.h | 1173 |
2 files changed, 1543 insertions, 1439 deletions
diff --git a/views/view.cc b/views/view.cc index a20de82..65fc624 100644 --- a/views/view.cc +++ b/views/view.cc @@ -44,33 +44,37 @@ char View::kViewClassName[] = "views/View"; // static const int View::kShowFolderDropMenuDelay = 400; -///////////////////////////////////////////////////////////////////////////// -// -// View - constructors, destructors, initialization -// -///////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// View, public: + +// TO BE MOVED ----------------------------------------------------------------- + +void View::SetHotTracked(bool flag) { +} + + +// Creation and lifetime ------------------------------------------------------- View::View() - : id_(0), + : enabled_(true), + id_(0), group_(-1), - enabled_(true), focusable_(false), accessibility_focusable_(false), - bounds_(0, 0, 0, 0), - needs_layout_(true), + is_parent_owned_(true), parent_(NULL), is_visible_(true), - is_parent_owned_(true), notify_when_visible_bounds_in_root_changes_(false), registered_for_visible_bounds_notification_(false), + needs_layout_(true), + flip_canvas_on_paint_for_rtl_ui_(false), accelerator_registration_delayed_(false), - next_focusable_view_(NULL), - previous_focusable_view_(NULL), accelerator_focus_manager_(NULL), registered_accelerator_count_(0), + next_focusable_view_(NULL), + previous_focusable_view_(NULL), context_menu_controller_(NULL), - drag_controller_(NULL), - flip_canvas_on_paint_for_rtl_ui_(false) { + drag_controller_(NULL) { } View::~View() { @@ -90,11 +94,119 @@ View::~View() { #endif } -///////////////////////////////////////////////////////////////////////////// -// -// View - sizing -// -///////////////////////////////////////////////////////////////////////////// +// Tree operations ------------------------------------------------------------- + +void View::AddChildView(View* v) { + AddChildView(static_cast<int>(child_views_.size()), v); +} + +void View::AddChildView(int index, View* v) { + CHECK(v != this) << "You cannot add a view as its own child"; + + // Remove the view from its current parent if any. + if (v->GetParent()) + v->GetParent()->RemoveChildView(v); + + // Sets the prev/next focus views. + InitFocusSiblings(v, index); + + // Let's insert the view. + child_views_.insert(child_views_.begin() + index, v); + v->SetParent(this); + + for (View* p = this; p; p = p->GetParent()) + p->ViewHierarchyChangedImpl(false, true, this, v); + + v->PropagateAddNotifications(this, v); + UpdateTooltip(); + RootView* root = GetRootView(); + if (root) + RegisterChildrenForVisibleBoundsNotification(root, v); + + if (layout_manager_.get()) + layout_manager_->ViewAdded(this, v); +} + +View* View::GetChildViewAt(int index) const { + return index < GetChildViewCount() ? child_views_[index] : NULL; +} + +void View::RemoveChildView(View* a_view) { + DoRemoveChildView(a_view, true, true, false); +} + +void View::RemoveAllChildViews(bool delete_views) { + ViewList::iterator iter; + while ((iter = child_views_.begin()) != child_views_.end()) { + DoRemoveChildView(*iter, false, false, delete_views); + } + UpdateTooltip(); +} + +int View::GetChildViewCount() const { + return static_cast<int>(child_views_.size()); +} + +bool View::HasChildView(View* a_view) { + return find(child_views_.begin(), + child_views_.end(), + a_view) != child_views_.end(); +} + +Widget* View::GetWidget() const { + // The root view holds a reference to this view hierarchy's Widget. + return parent_ ? parent_->GetWidget() : NULL; +} + +Window* View::GetWindow() const { + Widget* widget = GetWidget(); + return widget ? widget->GetWindow() : NULL; +} + +bool View::ContainsNativeView(gfx::NativeView native_view) const { + for (int i = 0, count = GetChildViewCount(); i < count; ++i) { + if (GetChildViewAt(i)->ContainsNativeView(native_view)) + return true; + } + return false; +} + +// Get the containing RootView +RootView* View::GetRootView() { + Widget* widget = GetWidget(); + return widget ? widget->GetRootView() : NULL; +} + +int View::GetChildIndex(const View* v) const { + for (int i = 0, count = GetChildViewCount(); i < count; i++) { + if (v == GetChildViewAt(i)) + return i; + } + return -1; +} + +bool View::IsParentOf(View* v) const { + DCHECK(v); + View* parent = v->GetParent(); + while (parent) { + if (this == parent) + return true; + parent = parent->GetParent(); + } + return false; +} + +#ifndef NDEBUG +void View::PrintViewHierarchy() { + PrintViewHierarchyImp(0); +} + +void View::PrintFocusHierarchy() { + PrintFocusHierarchyImp(0); +} +#endif + +// Size and disposition -------------------------------------------------------- gfx::Rect View::GetBounds(PositionMirroringSettings settings) const { gfx::Rect bounds(bounds_); @@ -108,12 +220,6 @@ gfx::Rect View::GetBounds(PositionMirroringSettings settings) const { return bounds; } -// y(), width() and height() are agnostic to the RTL UI layout of the -// parent view. x(), on the other hand, is not. -int View::GetX(PositionMirroringSettings settings) const { - return settings == IGNORE_MIRRORING_TRANSFORMATION ? x() : MirroredX(); -} - void View::SetBounds(const gfx::Rect& bounds) { if (bounds == bounds_) { if (needs_layout_) { @@ -137,6 +243,12 @@ void View::SetBounds(const gfx::Rect& bounds) { } } +// y(), width() and height() are agnostic to the RTL UI layout of the +// parent view. x(), on the other hand, is not. +int View::GetX(PositionMirroringSettings settings) const { + return settings == IGNORE_MIRRORING_TRANSFORMATION ? x() : MirroredX(); +} + gfx::Rect View::GetLocalBounds(bool include_border) const { if (include_border || !border_.get()) return gfx::Rect(0, 0, width(), height()); @@ -148,6 +260,49 @@ gfx::Rect View::GetLocalBounds(bool include_border) const { std::max(0, height() - insets.height())); } +gfx::Insets View::GetInsets() const { + gfx::Insets insets; + if (border_.get()) + border_->GetInsets(&insets); + return insets; +} + +gfx::Rect View::GetVisibleBounds() { + if (!IsVisibleInRootView()) + return gfx::Rect(); + gfx::Rect vis_bounds(0, 0, width(), height()); + gfx::Rect ancestor_bounds; + View* view = this; + int root_x = 0; + int root_y = 0; + while (view != NULL && !vis_bounds.IsEmpty()) { + root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION); + root_y += view->y(); + vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y()); + View* ancestor = view->GetParent(); + if (ancestor != NULL) { + ancestor_bounds.SetRect(0, 0, ancestor->width(), + ancestor->height()); + vis_bounds = vis_bounds.Intersect(ancestor_bounds); + } else if (!view->GetWidget()) { + // If the view has no Widget, we're not visible. Return an empty rect. + return gfx::Rect(); + } + view = ancestor; + } + if (vis_bounds.IsEmpty()) + return vis_bounds; + // Convert back to this views coordinate system. + vis_bounds.Offset(-root_x, -root_y); + return vis_bounds; +} + +gfx::Rect View::GetScreenBounds() const { + gfx::Point origin; + View::ConvertPointToScreen(this, &origin); + return gfx::Rect(origin, size()); +} + gfx::Point View::GetPosition() const { return gfx::Point(GetX(APPLY_MIRRORING_TRANSFORMATION), y()); } @@ -168,12 +323,6 @@ void View::SizeToPreferredSize() { SetBounds(x(), y(), prefsize.width(), prefsize.height()); } -void View::PreferredSizeChanged() { - InvalidateLayout(); - if (parent_) - parent_->ChildPreferredSizeChanged(this); -} - gfx::Size View::GetMinimumSize() { return GetPreferredSize(); } @@ -190,23 +339,56 @@ void View::DidChangeBounds(const gfx::Rect& previous, Layout(); } -void View::ScrollRectToVisible(const gfx::Rect& rect) { +void View::SetVisible(bool flag) { + if (flag != is_visible_) { + // If the tab is currently visible, schedule paint to + // refresh parent + if (IsVisible()) + SchedulePaint(); + + is_visible_ = flag; + + // This notifies all subviews recursively. + PropagateVisibilityNotifications(this, flag); + + // If we are newly visible, schedule paint. + if (IsVisible()) + SchedulePaint(); + } +} + +bool View::IsVisibleInRootView() const { View* parent = GetParent(); + if (IsVisible() && parent) + return parent->IsVisibleInRootView(); + else + return false; +} - // We must take RTL UI mirroring into account when adjusting the position of - // the region. - if (parent) { - gfx::Rect scroll_rect(rect); - scroll_rect.Offset(GetX(APPLY_MIRRORING_TRANSFORMATION), y()); - parent->ScrollRectToVisible(scroll_rect); +void View::SetEnabled(bool state) { + if (enabled_ != state) { + enabled_ = state; + SchedulePaint(); } } -///////////////////////////////////////////////////////////////////////////// -// -// View - layout -// -///////////////////////////////////////////////////////////////////////////// +bool View::IsEnabled() const { + return enabled_; +} + +// RTL positioning ------------------------------------------------------------- + +int View::MirroredX() const { + View* parent = GetParent(); + return parent ? parent->MirroredLeftPointForRect(bounds_) : x(); +} + +int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const { + return base::i18n::IsRTL() ? + (width() - bounds.x() - bounds.width()) : bounds.x(); +} + +// Layout ---------------------------------------------------------------------- void View::Layout() { needs_layout_ = false; @@ -253,87 +435,113 @@ void View::SetLayoutManager(LayoutManager* layout_manager) { layout_manager_->Installed(this); } -//////////////////////////////////////////////////////////////////////////////// -// -// View - Right-to-left UI layout -// -//////////////////////////////////////////////////////////////////////////////// +// Attributes ------------------------------------------------------------------ -int View::MirroredX() const { - View* parent = GetParent(); - return parent ? parent->MirroredLeftPointForRect(bounds_) : x(); +std::string View::GetClassName() const { + return kViewClassName; } -int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const { - return base::i18n::IsRTL() ? - (width() - bounds.x() - bounds.width()) : bounds.x(); +View* View::GetAncestorWithClassName(const std::string& name) { + for (View* view = this; view; view = view->GetParent()) { + if (view->GetClassName() == name) + return view; + } + return NULL; } -//////////////////////////////////////////////////////////////////////////////// -// -// View - states -// -//////////////////////////////////////////////////////////////////////////////// +View* View::GetViewByID(int id) const { + if (id == id_) + return const_cast<View*>(this); -bool View::IsEnabled() const { - return enabled_; + for (int i = 0, count = GetChildViewCount(); i < count; ++i) { + View* child = GetChildViewAt(i); + View* view = child->GetViewByID(id); + if (view) + return view; + } + return NULL; } -void View::SetEnabled(bool state) { - if (enabled_ != state) { - enabled_ = state; - SchedulePaint(); - } +void View::SetID(int id) { + id_ = id; } -void View::SetFocusable(bool focusable) { - focusable_ = focusable; +int View::GetID() const { + return id_; } -bool View::IsFocusableInRootView() const { - return IsFocusable() && IsVisibleInRootView(); +void View::SetGroup(int gid) { + // Don't change the group id once it's set. + DCHECK(group_ == -1 || group_ == gid); + group_ = gid; } -bool View::IsAccessibilityFocusableInRootView() const { - return (focusable_ || accessibility_focusable_) && IsEnabled() && - IsVisibleInRootView(); +int View::GetGroup() const { + return group_; } -FocusManager* View::GetFocusManager() { - Widget* widget = GetWidget(); - return widget ? widget->GetFocusManager() : NULL; +void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) { + if (group_ == group_id) + out->push_back(this); + + for (int i = 0, count = GetChildViewCount(); i < count; ++i) + GetChildViewAt(i)->GetViewsWithGroup(group_id, out); } -bool View::HasFocus() { - FocusManager* focus_manager = GetFocusManager(); - if (focus_manager) - return focus_manager->GetFocusedView() == this; - return false; +View* View::GetSelectedViewForGroup(int group_id) { + std::vector<View*> views; + GetRootView()->GetViewsWithGroup(group_id, &views); + if (views.size() > 0) + return views[0]; + else + return NULL; } -void View::Focus() { - // By default, we clear the native focus. This ensures that no visible native - // view as the focus and that we still receive keyboard inputs. - FocusManager* focus_manager = GetFocusManager(); - if (focus_manager) - focus_manager->ClearNativeFocus(); +// Coordinate conversion ------------------------------------------------------- - // Notify assistive technologies of the focus change. - NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS); +// static +void View::ConvertPointToView(const View* src, + const View* dst, + gfx::Point* point) { + ConvertPointToView(src, dst, point, true); } -void View::NotifyAccessibilityEvent(AccessibilityTypes::Event event_type) { - NotifyAccessibilityEvent(event_type, true); +// static +void View::ConvertPointToWidget(const View* src, gfx::Point* p) { + DCHECK(src); + DCHECK(p); + + gfx::Point offset; + for (const View* v = src; v; v = v->GetParent()) { + offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION)); + offset.set_y(offset.y() + v->y()); + } + p->SetPoint(p->x() + offset.x(), p->y() + offset.y()); } -void View::SetHotTracked(bool flag) { +// static +void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { + gfx::Point t; + ConvertPointToWidget(dest, &t); + p->SetPoint(p->x() - t.x(), p->y() - t.y()); } -///////////////////////////////////////////////////////////////////////////// -// -// View - painting -// -///////////////////////////////////////////////////////////////////////////// +// static +void View::ConvertPointToScreen(const View* src, gfx::Point* p) { + DCHECK(src); + DCHECK(p); + + // If the view is not connected to a tree, there's nothing we can do. + Widget* widget = src->GetWidget(); + if (widget) { + ConvertPointToWidget(src, p); + gfx::Rect r; + widget->GetBounds(&r, false); + p->SetPoint(p->x() + r.x(), p->y() + r.y()); + } +} + +// Painting -------------------------------------------------------------------- void View::SchedulePaint(const gfx::Rect& r, bool urgent) { if (!IsVisible()) @@ -373,15 +581,13 @@ void View::PaintFocusBorder(gfx::Canvas* canvas) { canvas->DrawFocusRect(0, 0, width(), height()); } -void View::PaintChildren(gfx::Canvas* canvas) { - for (int i = 0, count = GetChildViewCount(); i < count; ++i) { - View* child = GetChildViewAt(i); - if (!child) { - NOTREACHED() << "Should not have a NULL child View for index in bounds"; - continue; - } - child->ProcessPaint(canvas); - } +void View::PaintNow() { + if (!IsVisible()) + return; + + View* view = GetParent(); + if (view) + view->PaintNow(); } void View::ProcessPaint(gfx::Canvas* canvas) { @@ -425,20 +631,38 @@ void View::ProcessPaint(gfx::Canvas* canvas) { canvas->Restore(); } -void View::PaintNow() { - if (!IsVisible()) - return; +void View::PaintChildren(gfx::Canvas* canvas) { + for (int i = 0, count = GetChildViewCount(); i < count; ++i) { + View* child = GetChildViewAt(i); + if (!child) { + NOTREACHED() << "Should not have a NULL child View for index in bounds"; + continue; + } + child->ProcessPaint(canvas); + } +} - View* view = GetParent(); - if (view) - view->PaintNow(); +ThemeProvider* View::GetThemeProvider() const { + Widget* widget = GetWidget(); + return widget ? widget->GetThemeProvider() : NULL; } -gfx::Insets View::GetInsets() const { - gfx::Insets insets; - if (border_.get()) - border_->GetInsets(&insets); - return insets; +// Input ----------------------------------------------------------------------- + +View* View::GetViewForPoint(const gfx::Point& point) { + // Walk the child Views recursively looking for the View that most + // tightly encloses the specified point. + for (int i = GetChildViewCount() - 1; i >= 0; --i) { + View* child = GetChildViewAt(i); + if (!child->IsVisible()) + continue; + + gfx::Point point_in_child_coords(point); + View::ConvertPointToView(this, child, &point_in_child_coords); + if (child->HitTest(point_in_child_coords)) + return child->GetViewForPoint(point_in_child_coords); + } + return this; } gfx::NativeCursor View::GetCursorForPoint(Event::EventType event_type, @@ -467,309 +691,307 @@ bool View::HitTest(const gfx::Point& l) const { return false; } -void View::SetContextMenuController(ContextMenuController* menu_controller) { - context_menu_controller_ = menu_controller; +bool View::OnMousePressed(const MouseEvent& e) { + return false; } -void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) { - if (!context_menu_controller_) - return; +bool View::OnMouseDragged(const MouseEvent& e) { + return false; +} - context_menu_controller_->ShowContextMenu(this, p, is_mouse_gesture); +void View::OnMouseReleased(const MouseEvent& e, bool canceled) { } -///////////////////////////////////////////////////////////////////////////// -// -// View - tree -// -///////////////////////////////////////////////////////////////////////////// +void View::OnMouseMoved(const MouseEvent& e) { +} -bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) { - const bool enabled = IsEnabled(); - int drag_operations = - (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location())) ? - GetDragOperations(e.location()) : 0; - ContextMenuController* context_menu_controller = e.IsRightMouseButton() ? - context_menu_controller_ : 0; +void View::OnMouseEntered(const MouseEvent& e) { +} - const bool result = OnMousePressed(e); - // WARNING: we may have been deleted, don't use any View variables; +void View::OnMouseExited(const MouseEvent& e) { +} - if (!enabled) - return result; +#if defined(TOUCH_UI) +View::TouchStatus View::OnTouchEvent(const TouchEvent& event) { + DVLOG(1) << "visited the OnTouchEvent"; + return TOUCH_STATUS_UNKNOWN; +} +#endif - if (drag_operations != ui::DragDropTypes::DRAG_NONE) { - drag_info->PossibleDrag(e.location()); - return true; - } - return !!context_menu_controller || result; +void View::SetMouseHandler(View *new_mouse_handler) { + // It is valid for new_mouse_handler to be NULL + if (parent_) + parent_->SetMouseHandler(new_mouse_handler); } -bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) { - // Copy the field, that way if we're deleted after drag and drop no harm is - // done. - ContextMenuController* context_menu_controller = context_menu_controller_; - const bool possible_drag = drag_info->possible_drag; - if (possible_drag && ExceededDragThreshold(drag_info->start_pt.x() - e.x(), - drag_info->start_pt.y() - e.y())) { - if (!drag_controller_ || - drag_controller_->CanStartDrag(this, drag_info->start_pt, e.location())) - DoDrag(e, drag_info->start_pt); - } else { - if (OnMouseDragged(e)) - return true; - // Fall through to return value based on context menu controller. - } - // WARNING: we may have been deleted. - return (context_menu_controller != NULL) || possible_drag; +bool View::OnKeyPressed(const KeyEvent& e) { + return false; } -void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) { - if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) { - // Assume that if there is a context menu controller we won't be deleted - // from mouse released. - gfx::Point location(e.location()); - OnMouseReleased(e, canceled); - if (HitTest(location)) { - ConvertPointToScreen(this, &location); - ShowContextMenu(location, true); - } - } else { - OnMouseReleased(e, canceled); +bool View::OnKeyReleased(const KeyEvent& e) { + return false; +} + +bool View::OnMouseWheel(const MouseWheelEvent& e) { + return false; +} + +// Accelerators ---------------------------------------------------------------- + +void View::AddAccelerator(const Accelerator& accelerator) { + if (!accelerators_.get()) + accelerators_.reset(new std::vector<Accelerator>()); + + std::vector<Accelerator>::iterator iter = + std::find(accelerators_->begin(), accelerators_->end(), accelerator); + DCHECK(iter == accelerators_->end()) + << "Registering the same accelerator multiple times"; + + accelerators_->push_back(accelerator); + RegisterPendingAccelerators(); +} + +void View::RemoveAccelerator(const Accelerator& accelerator) { + std::vector<Accelerator>::iterator iter; + if (!accelerators_.get() || + ((iter = std::find(accelerators_->begin(), accelerators_->end(), + accelerator)) == accelerators_->end())) { + NOTREACHED() << "Removing non-existing accelerator"; + return; + } + + size_t index = iter - accelerators_->begin(); + accelerators_->erase(iter); + if (index >= registered_accelerator_count_) { + // The accelerator is not registered to FocusManager. + return; + } + --registered_accelerator_count_; + + RootView* root_view = GetRootView(); + if (!root_view) { + // We are not part of a view hierarchy, so there is nothing to do as we + // removed ourselves from accelerators_, we won't be registered when added + // to one. + return; + } + + // If accelerator_focus_manager_ is NULL then we did not registered + // accelerators so there is nothing to unregister. + if (accelerator_focus_manager_) { + accelerator_focus_manager_->UnregisterAccelerator(accelerator, this); } - // WARNING: we may have been deleted. } -#if defined(TOUCH_UI) -View::TouchStatus View::ProcessTouchEvent(const TouchEvent& e) { - // TODO(rjkroege): Implement a grab scheme similar to as - // as is found in MousePressed. - return OnTouchEvent(e); +void View::ResetAccelerators() { + if (accelerators_.get()) + UnregisterAccelerators(false); } -#endif -void View::AddChildView(View* v) { - AddChildView(static_cast<int>(child_views_.size()), v); +// Focus ----------------------------------------------------------------------- + +bool View::HasFocus() { + FocusManager* focus_manager = GetFocusManager(); + if (focus_manager) + return focus_manager->GetFocusedView() == this; + return false; } -void View::AddChildView(int index, View* v) { - CHECK(v != this) << "You cannot add a view as its own child"; +View* View::GetNextFocusableView() { + return next_focusable_view_; +} - // Remove the view from its current parent if any. - if (v->GetParent()) - v->GetParent()->RemoveChildView(v); +View* View::GetPreviousFocusableView() { + return previous_focusable_view_; +} - // Sets the prev/next focus views. - InitFocusSiblings(v, index); +void View::SetNextFocusableView(View* view) { + view->previous_focusable_view_ = this; + next_focusable_view_ = view; +} - // Let's insert the view. - child_views_.insert(child_views_.begin() + index, v); - v->SetParent(this); +void View::SetFocusable(bool focusable) { + focusable_ = focusable; +} - for (View* p = this; p; p = p->GetParent()) - p->ViewHierarchyChangedImpl(false, true, this, v); +bool View::IsFocusableInRootView() const { + return IsFocusable() && IsVisibleInRootView(); +} - v->PropagateAddNotifications(this, v); - UpdateTooltip(); - RootView* root = GetRootView(); - if (root) - RegisterChildrenForVisibleBoundsNotification(root, v); +bool View::IsAccessibilityFocusableInRootView() const { + return (focusable_ || accessibility_focusable_) && IsEnabled() && + IsVisibleInRootView(); +} - if (layout_manager_.get()) - layout_manager_->ViewAdded(this, v); +FocusManager* View::GetFocusManager() { + Widget* widget = GetWidget(); + return widget ? widget->GetFocusManager() : NULL; } -View* View::GetChildViewAt(int index) const { - return index < GetChildViewCount() ? child_views_[index] : NULL; +void View::RequestFocus() { + RootView* rv = GetRootView(); + if (rv && IsFocusableInRootView()) + rv->FocusView(this); } -int View::GetChildViewCount() const { - return static_cast<int>(child_views_.size()); +void View::WillGainFocus() { } -bool View::HasChildView(View* a_view) { - return find(child_views_.begin(), - child_views_.end(), - a_view) != child_views_.end(); +void View::DidGainFocus() { } -void View::RemoveChildView(View* a_view) { - DoRemoveChildView(a_view, true, true, false); +void View::WillLoseFocus() { } -void View::RemoveAllChildViews(bool delete_views) { - ViewList::iterator iter; - while ((iter = child_views_.begin()) != child_views_.end()) { - DoRemoveChildView(*iter, false, false, delete_views); - } - UpdateTooltip(); +// Tooltips -------------------------------------------------------------------- + +bool View::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) { + return false; } -void View::DoDrag(const MouseEvent& e, const gfx::Point& press_pt) { - int drag_operations = GetDragOperations(press_pt); - if (drag_operations == ui::DragDropTypes::DRAG_NONE) - return; +bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) { + return false; +} - OSExchangeData data; - WriteDragData(press_pt, &data); +// Context menus --------------------------------------------------------------- - // Message the RootView to do the drag and drop. That way if we're removed - // the RootView can detect it and avoid calling us back. - RootView* root_view = GetRootView(); - root_view->StartDragForViewFromMouseEvent(this, data, drag_operations); +void View::SetContextMenuController(ContextMenuController* menu_controller) { + context_menu_controller_ = menu_controller; } -void View::DoRemoveChildView(View* a_view, - bool update_focus_cycle, - bool update_tool_tip, - bool delete_removed_view) { -#ifndef NDEBUG - DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " << - "during a paint, this will seriously " << - "mess things up!"; -#endif - DCHECK(a_view); - const ViewList::iterator i = find(child_views_.begin(), - child_views_.end(), - a_view); - scoped_ptr<View> view_to_be_deleted; - if (i != child_views_.end()) { - if (update_focus_cycle) { - // Let's remove the view from the focus traversal. - View* next_focusable = a_view->next_focusable_view_; - View* prev_focusable = a_view->previous_focusable_view_; - if (prev_focusable) - prev_focusable->next_focusable_view_ = next_focusable; - if (next_focusable) - next_focusable->previous_focusable_view_ = prev_focusable; - } +void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) { + if (!context_menu_controller_) + return; - RootView* root = GetRootView(); - if (root) - UnregisterChildrenForVisibleBoundsNotification(root, a_view); - a_view->PropagateRemoveNotifications(this); - a_view->SetParent(NULL); + context_menu_controller_->ShowContextMenu(this, p, is_mouse_gesture); +} - if (delete_removed_view && a_view->IsParentOwned()) - view_to_be_deleted.reset(a_view); +// Drag and drop --------------------------------------------------------------- - child_views_.erase(i); - } +void View::SetDragController(DragController* drag_controller) { + drag_controller_ = drag_controller; +} - if (update_tool_tip) - UpdateTooltip(); +DragController* View::GetDragController() { + return drag_controller_; +} - if (layout_manager_.get()) - layout_manager_->ViewRemoved(this, a_view); +bool View::GetDropFormats( + int* formats, + std::set<OSExchangeData::CustomFormat>* custom_formats) { + return false; } -void View::PropagateRemoveNotifications(View* parent) { - for (int i = 0, count = GetChildViewCount(); i < count; ++i) - GetChildViewAt(i)->PropagateRemoveNotifications(parent); +bool View::AreDropTypesRequired() { + return false; +} - for (View* v = this; v; v = v->GetParent()) - v->ViewHierarchyChangedImpl(true, false, parent, this); +bool View::CanDrop(const OSExchangeData& data) { + // TODO(sky): when I finish up migration, this should default to true. + return false; } -void View::PropagateAddNotifications(View* parent, View* child) { - for (int i = 0, count = GetChildViewCount(); i < count; ++i) - GetChildViewAt(i)->PropagateAddNotifications(parent, child); - ViewHierarchyChangedImpl(true, true, parent, child); +void View::OnDragEntered(const DropTargetEvent& event) { } -bool View::IsFocusable() const { - return focusable_ && IsEnabled() && IsVisible(); +int View::OnDragUpdated(const DropTargetEvent& event) { + return ui::DragDropTypes::DRAG_NONE; } -void View::PropagateThemeChanged() { - for (int i = GetChildViewCount() - 1; i >= 0; --i) - GetChildViewAt(i)->PropagateThemeChanged(); - OnThemeChanged(); +void View::OnDragExited() { } -void View::PropagateLocaleChanged() { - for (int i = GetChildViewCount() - 1; i >= 0; --i) - GetChildViewAt(i)->PropagateLocaleChanged(); - OnLocaleChanged(); +int View::OnPerformDrop(const DropTargetEvent& event) { + return ui::DragDropTypes::DRAG_NONE; } -#ifndef NDEBUG -bool View::IsProcessingPaint() const { - return GetParent() && GetParent()->IsProcessingPaint(); +// static +bool View::ExceededDragThreshold(int delta_x, int delta_y) { + return (abs(delta_x) > GetHorizontalDragThreshold() || + abs(delta_y) > GetVerticalDragThreshold()); } -#endif -gfx::Point View::GetKeyboardContextMenuLocation() { - gfx::Rect vis_bounds = GetVisibleBounds(); - gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2, - vis_bounds.y() + vis_bounds.height() / 2); - ConvertPointToScreen(this, &screen_point); - return screen_point; +// Accessibility --------------------------------------------------------------- + +void View::NotifyAccessibilityEvent(AccessibilityTypes::Event event_type) { + NotifyAccessibilityEvent(event_type, true); } -bool View::HasHitTestMask() const { - return false; +bool View::GetAccessibleName(string16* name) { + DCHECK(name); + + if (accessible_name_.empty()) + return false; + *name = accessible_name_; + return true; } -void View::GetHitTestMask(gfx::Path* mask) const { - DCHECK(mask); +AccessibilityTypes::Role View::GetAccessibleRole() { + return AccessibilityTypes::ROLE_CLIENT; } -void View::ViewHierarchyChanged(bool is_add, - View* parent, - View* child) { +void View::SetAccessibleName(const string16& name) { + accessible_name_ = name; } -void View::ViewHierarchyChangedImpl(bool register_accelerators, - bool is_add, - View* parent, - View* child) { - if (register_accelerators) { - if (is_add) { - // If you get this registration, you are part of a subtree that has been - // added to the view hierarchy. - if (GetFocusManager()) { - RegisterPendingAccelerators(); - } else { - // Delay accelerator registration until visible as we do not have - // focus manager until then. - accelerator_registration_delayed_ = true; - } - } else { - if (child == this) - UnregisterAccelerators(true); - } +// Scrolling ------------------------------------------------------------------- + +void View::ScrollRectToVisible(const gfx::Rect& rect) { + View* parent = GetParent(); + + // We must take RTL UI mirroring into account when adjusting the position of + // the region. + if (parent) { + gfx::Rect scroll_rect(rect); + scroll_rect.Offset(GetX(APPLY_MIRRORING_TRANSFORMATION), y()); + parent->ScrollRectToVisible(scroll_rect); } +} - ViewHierarchyChanged(is_add, parent, child); - parent->needs_layout_ = true; +int View::GetPageScrollIncrement(ScrollView* scroll_view, + bool is_horizontal, bool is_positive) { + return 0; } -void View::PropagateVisibilityNotifications(View* start, bool is_visible) { - for (int i = 0, count = GetChildViewCount(); i < count; ++i) - GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible); - VisibilityChangedImpl(start, is_visible); +int View::GetLineScrollIncrement(ScrollView* scroll_view, + bool is_horizontal, bool is_positive) { + return 0; } -void View::VisibilityChangedImpl(View* starting_from, bool is_visible) { - if (is_visible) - RegisterPendingAccelerators(); - else - UnregisterAccelerators(true); - VisibilityChanged(starting_from, is_visible); +//////////////////////////////////////////////////////////////////////////////// +// View, protected: + +// Size and disposition -------------------------------------------------------- + +void View::PreferredSizeChanged() { + InvalidateLayout(); + if (parent_) + parent_->ChildPreferredSizeChanged(this); } -void View::VisibilityChanged(View* starting_from, bool is_visible) { +void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) { + if (notify_when_visible_bounds_in_root_changes_ == value) + return; + notify_when_visible_bounds_in_root_changes_ = value; + RootView* root = GetRootView(); + if (root) { + if (value) + root->RegisterViewForVisibleBoundsNotification(this); + else + root->UnregisterViewForVisibleBoundsNotification(this); + } } -void View::PropagateNativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view, - RootView* root_view) { - for (int i = 0, count = GetChildViewCount(); i < count; ++i) - GetChildViewAt(i)->PropagateNativeViewHierarchyChanged(attached, - native_view, - root_view); - NativeViewHierarchyChanged(attached, native_view, root_view); +bool View::GetNotifyWhenVisibleBoundsInRootChanges() { + return notify_when_visible_bounds_in_root_changes_; +} + +// Tree operations ------------------------------------------------------------- + +void View::ViewHierarchyChanged(bool is_add, View* parent, View* child) { +} + +void View::VisibilityChanged(View* starting_from, bool is_visible) { } void View::NativeViewHierarchyChanged(bool attached, @@ -790,202 +1012,196 @@ void View::NativeViewHierarchyChanged(bool attached, } } -void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) { - if (notify_when_visible_bounds_in_root_changes_ == value) - return; - notify_when_visible_bounds_in_root_changes_ = value; - RootView* root = GetRootView(); - if (root) { - if (value) - root->RegisterViewForVisibleBoundsNotification(this); - else - root->UnregisterViewForVisibleBoundsNotification(this); - } -} +// Painting -------------------------------------------------------------------- -bool View::GetNotifyWhenVisibleBoundsInRootChanges() { - return notify_when_visible_bounds_in_root_changes_; +#ifndef NDEBUG +bool View::IsProcessingPaint() const { + return GetParent() && GetParent()->IsProcessingPaint(); } +#endif -View* View::GetViewForPoint(const gfx::Point& point) { - // Walk the child Views recursively looking for the View that most - // tightly encloses the specified point. - for (int i = GetChildViewCount() - 1; i >= 0; --i) { - View* child = GetChildViewAt(i); - if (!child->IsVisible()) - continue; +// Input ----------------------------------------------------------------------- - gfx::Point point_in_child_coords(point); - View::ConvertPointToView(this, child, &point_in_child_coords); - if (child->HitTest(point_in_child_coords)) - return child->GetViewForPoint(point_in_child_coords); - } - return this; +bool View::HasHitTestMask() const { + return false; } -Widget* View::GetWidget() const { - // The root view holds a reference to this view hierarchy's Widget. - return parent_ ? parent_->GetWidget() : NULL; +void View::GetHitTestMask(gfx::Path* mask) const { + DCHECK(mask); } -Window* View::GetWindow() const { - Widget* widget = GetWidget(); - return widget ? widget->GetWindow() : NULL; +// Focus ----------------------------------------------------------------------- + +bool View::IsFocusable() const { + return focusable_ && IsEnabled() && IsVisible(); } -bool View::ContainsNativeView(gfx::NativeView native_view) const { - for (int i = 0, count = GetChildViewCount(); i < count; ++i) { - if (GetChildViewAt(i)->ContainsNativeView(native_view)) - return true; - } - return false; +void View::Focus() { + // By default, we clear the native focus. This ensures that no visible native + // view as the focus and that we still receive keyboard inputs. + FocusManager* focus_manager = GetFocusManager(); + if (focus_manager) + focus_manager->ClearNativeFocus(); + + // Notify assistive technologies of the focus change. + NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS); } -// Get the containing RootView -RootView* View::GetRootView() { +// Tooltips -------------------------------------------------------------------- + +void View::TooltipTextChanged() { Widget* widget = GetWidget(); - return widget ? widget->GetRootView() : NULL; + if (widget && widget->GetTooltipManager()) + widget->GetTooltipManager()->TooltipTextChanged(this); } -View* View::GetViewByID(int id) const { - if (id == id_) - return const_cast<View*>(this); +// Context menus --------------------------------------------------------------- - for (int i = 0, count = GetChildViewCount(); i < count; ++i) { - View* child = GetChildViewAt(i); - View* view = child->GetViewByID(id); - if (view) - return view; - } - return NULL; +gfx::Point View::GetKeyboardContextMenuLocation() { + gfx::Rect vis_bounds = GetVisibleBounds(); + gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2, + vis_bounds.y() + vis_bounds.height() / 2); + ConvertPointToScreen(this, &screen_point); + return screen_point; } -void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) { - if (group_ == group_id) - out->push_back(this); +// Drag and drop --------------------------------------------------------------- - for (int i = 0, count = GetChildViewCount(); i < count; ++i) - GetChildViewAt(i)->GetViewsWithGroup(group_id, out); +int View::GetDragOperations(const gfx::Point& press_pt) { + return drag_controller_ ? + drag_controller_->GetDragOperations(this, press_pt) : + ui::DragDropTypes::DRAG_NONE; } -View* View::GetSelectedViewForGroup(int group_id) { - std::vector<View*> views; - GetRootView()->GetViewsWithGroup(group_id, &views); - if (views.size() > 0) - return views[0]; - else - return NULL; +void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) { + DCHECK(drag_controller_); + drag_controller_->WriteDragData(this, press_pt, data); } -void View::SetID(int id) { - id_ = id; +void View::OnDragDone() { } -int View::GetID() const { - return id_; +bool View::InDrag() { + RootView* root_view = GetRootView(); + return root_view ? (root_view->GetDragView() == this) : false; } -void View::SetGroup(int gid) { - // Don't change the group id once it's set. - DCHECK(group_ == -1 || group_ == gid); - group_ = gid; -} +//////////////////////////////////////////////////////////////////////////////// +// View, private: -int View::GetGroup() const { - return group_; +// DropInfo -------------------------------------------------------------------- + +void View::DragInfo::Reset() { + possible_drag = false; + start_pt = gfx::Point(); } -void View::SetParent(View* parent) { - if (parent != parent_) - parent_ = parent; +void View::DragInfo::PossibleDrag(const gfx::Point& p) { + possible_drag = true; + start_pt = p; } -bool View::IsParentOf(View* v) const { - DCHECK(v); - View* parent = v->GetParent(); - while (parent) { - if (this == parent) - return true; - parent = parent->GetParent(); +// Tree operations ------------------------------------------------------------- + +void View::DoRemoveChildView(View* a_view, + bool update_focus_cycle, + bool update_tool_tip, + bool delete_removed_view) { +#ifndef NDEBUG + DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " << + "during a paint, this will seriously " << + "mess things up!"; +#endif + DCHECK(a_view); + const ViewList::iterator i = find(child_views_.begin(), + child_views_.end(), + a_view); + scoped_ptr<View> view_to_be_deleted; + if (i != child_views_.end()) { + if (update_focus_cycle) { + // Let's remove the view from the focus traversal. + View* next_focusable = a_view->next_focusable_view_; + View* prev_focusable = a_view->previous_focusable_view_; + if (prev_focusable) + prev_focusable->next_focusable_view_ = next_focusable; + if (next_focusable) + next_focusable->previous_focusable_view_ = prev_focusable; + } + + RootView* root = GetRootView(); + if (root) + UnregisterChildrenForVisibleBoundsNotification(root, a_view); + a_view->PropagateRemoveNotifications(this); + a_view->SetParent(NULL); + + if (delete_removed_view && a_view->IsParentOwned()) + view_to_be_deleted.reset(a_view); + + child_views_.erase(i); } - return false; + + if (update_tool_tip) + UpdateTooltip(); + + if (layout_manager_.get()) + layout_manager_->ViewRemoved(this, a_view); } -int View::GetChildIndex(const View* v) const { - for (int i = 0, count = GetChildViewCount(); i < count; i++) { - if (v == GetChildViewAt(i)) - return i; - } - return -1; +void View::SetParent(View* parent) { + if (parent != parent_) + parent_ = parent; } -/////////////////////////////////////////////////////////////////////////////// -// -// View - focus -// -/////////////////////////////////////////////////////////////////////////////// +void View::PropagateRemoveNotifications(View* parent) { + for (int i = 0, count = GetChildViewCount(); i < count; ++i) + GetChildViewAt(i)->PropagateRemoveNotifications(parent); -View* View::GetNextFocusableView() { - return next_focusable_view_; + for (View* v = this; v; v = v->GetParent()) + v->ViewHierarchyChangedImpl(true, false, parent, this); } -View* View::GetPreviousFocusableView() { - return previous_focusable_view_; +void View::PropagateAddNotifications(View* parent, View* child) { + for (int i = 0, count = GetChildViewCount(); i < count; ++i) + GetChildViewAt(i)->PropagateAddNotifications(parent, child); + ViewHierarchyChangedImpl(true, true, parent, child); } -void View::SetNextFocusableView(View* view) { - view->previous_focusable_view_ = this; - next_focusable_view_ = view; +void View::PropagateNativeViewHierarchyChanged(bool attached, + gfx::NativeView native_view, + RootView* root_view) { + for (int i = 0, count = GetChildViewCount(); i < count; ++i) + GetChildViewAt(i)->PropagateNativeViewHierarchyChanged(attached, + native_view, + root_view); + NativeViewHierarchyChanged(attached, native_view, root_view); } -void View::InitFocusSiblings(View* v, int index) { - int child_count = static_cast<int>(child_views_.size()); - - if (child_count == 0) { - v->next_focusable_view_ = NULL; - v->previous_focusable_view_ = NULL; - } else { - if (index == child_count) { - // We are inserting at the end, but the end of the child list may not be - // the last focusable element. Let's try to find an element with no next - // focusable element to link to. - View* last_focusable_view = NULL; - for (std::vector<View*>::iterator iter = child_views_.begin(); - iter != child_views_.end(); ++iter) { - if (!(*iter)->next_focusable_view_) { - last_focusable_view = *iter; - break; - } - } - if (last_focusable_view == NULL) { - // Hum... there is a cycle in the focus list. Let's just insert ourself - // after the last child. - View* prev = child_views_[index - 1]; - v->previous_focusable_view_ = prev; - v->next_focusable_view_ = prev->next_focusable_view_; - prev->next_focusable_view_->previous_focusable_view_ = v; - prev->next_focusable_view_ = v; +void View::ViewHierarchyChangedImpl(bool register_accelerators, + bool is_add, + View* parent, + View* child) { + if (register_accelerators) { + if (is_add) { + // If you get this registration, you are part of a subtree that has been + // added to the view hierarchy. + if (GetFocusManager()) { + RegisterPendingAccelerators(); } else { - last_focusable_view->next_focusable_view_ = v; - v->next_focusable_view_ = NULL; - v->previous_focusable_view_ = last_focusable_view; + // Delay accelerator registration until visible as we do not have + // focus manager until then. + accelerator_registration_delayed_ = true; } } else { - View* prev = child_views_[index]->GetPreviousFocusableView(); - v->previous_focusable_view_ = prev; - v->next_focusable_view_ = child_views_[index]; - if (prev) - prev->next_focusable_view_ = v; - child_views_[index]->previous_focusable_view_ = v; + if (child == this) + UnregisterAccelerators(true); } } -} -#ifndef NDEBUG -void View::PrintViewHierarchy() { - PrintViewHierarchyImp(0); + ViewHierarchyChanged(is_add, parent, child); + parent->needs_layout_ = true; } +#ifndef NDEBUG void View::PrintViewHierarchyImp(int indent) { std::wostringstream buf; int ind = indent; @@ -1007,11 +1223,6 @@ void View::PrintViewHierarchyImp(int indent) { GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2); } - -void View::PrintFocusHierarchy() { - PrintFocusHierarchyImp(0); -} - void View::PrintFocusHierarchyImp(int indent) { std::wostringstream buf; int ind = indent; @@ -1037,164 +1248,62 @@ void View::PrintFocusHierarchyImp(int indent) { } #endif -//////////////////////////////////////////////////////////////////////////////// -// -// View - accelerators -// -//////////////////////////////////////////////////////////////////////////////// - -void View::AddAccelerator(const Accelerator& accelerator) { - if (!accelerators_.get()) - accelerators_.reset(new std::vector<Accelerator>()); - - std::vector<Accelerator>::iterator iter = - std::find(accelerators_->begin(), accelerators_->end(), accelerator); - DCHECK(iter == accelerators_->end()) - << "Registering the same accelerator multiple times"; - - accelerators_->push_back(accelerator); - RegisterPendingAccelerators(); -} - -void View::RemoveAccelerator(const Accelerator& accelerator) { - std::vector<Accelerator>::iterator iter; - if (!accelerators_.get() || - ((iter = std::find(accelerators_->begin(), accelerators_->end(), - accelerator)) == accelerators_->end())) { - NOTREACHED() << "Removing non-existing accelerator"; - return; - } - - size_t index = iter - accelerators_->begin(); - accelerators_->erase(iter); - if (index >= registered_accelerator_count_) { - // The accelerator is not registered to FocusManager. - return; - } - --registered_accelerator_count_; - - RootView* root_view = GetRootView(); - if (!root_view) { - // We are not part of a view hierarchy, so there is nothing to do as we - // removed ourselves from accelerators_, we won't be registered when added - // to one. - return; - } - - // If accelerator_focus_manager_ is NULL then we did not registered - // accelerators so there is nothing to unregister. - if (accelerator_focus_manager_) { - accelerator_focus_manager_->UnregisterAccelerator(accelerator, this); - } -} - -void View::ResetAccelerators() { - if (accelerators_.get()) - UnregisterAccelerators(false); -} - -void View::RegisterPendingAccelerators() { - if (!accelerators_.get() || - registered_accelerator_count_ == accelerators_->size()) { - // No accelerators are waiting for registration. - return; - } - - RootView* root_view = GetRootView(); - if (!root_view) { - // We are not yet part of a view hierarchy, we'll register ourselves once - // added to one. - return; - } - - accelerator_focus_manager_ = GetFocusManager(); - if (!accelerator_focus_manager_) { - // Some crash reports seem to show that we may get cases where we have no - // focus manager (see bug #1291225). This should never be the case, just - // making sure we don't crash. - - // TODO(jcampan): This fails for a view under WidgetGtk with TYPE_CHILD. - // (see http://crbug.com/21335) reenable NOTREACHED assertion and - // verify accelerators works as expected. -#if defined(OS_WIN) - NOTREACHED(); -#endif - return; - } - // Only register accelerators if we are visible. - if (!IsVisibleInRootView()) - return; - std::vector<Accelerator>::const_iterator iter; - for (iter = accelerators_->begin() + registered_accelerator_count_; - iter != accelerators_->end(); ++iter) { - accelerator_focus_manager_->RegisterAccelerator(*iter, this); - } - registered_accelerator_count_ = accelerators_->size(); -} - -void View::UnregisterAccelerators(bool leave_data_intact) { - if (!accelerators_.get()) - return; - - RootView* root_view = GetRootView(); - if (root_view) { - if (accelerator_focus_manager_) { - // We may not have a FocusManager if the window containing us is being - // closed, in which case the FocusManager is being deleted so there is - // nothing to unregister. - accelerator_focus_manager_->UnregisterAccelerators(this); - accelerator_focus_manager_ = NULL; - } - if (!leave_data_intact) { - accelerators_->clear(); - accelerators_.reset(); - } - registered_accelerator_count_ = 0; - } -} - -int View::GetDragOperations(const gfx::Point& press_pt) { - return drag_controller_ ? - drag_controller_->GetDragOperations(this, press_pt) : - ui::DragDropTypes::DRAG_NONE; -} +// Size and disposition -------------------------------------------------------- -void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) { - DCHECK(drag_controller_); - drag_controller_->WriteDragData(this, press_pt, data); +void View::PropagateVisibilityNotifications(View* start, bool is_visible) { + for (int i = 0, count = GetChildViewCount(); i < count; ++i) + GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible); + VisibilityChangedImpl(start, is_visible); } -void View::OnDragDone() { +void View::VisibilityChangedImpl(View* starting_from, bool is_visible) { + if (is_visible) + RegisterPendingAccelerators(); + else + UnregisterAccelerators(true); + VisibilityChanged(starting_from, is_visible); } -bool View::InDrag() { - RootView* root_view = GetRootView(); - return root_view ? (root_view->GetDragView() == this) : false; +// static +void View::RegisterChildrenForVisibleBoundsNotification( + RootView* root, View* view) { + DCHECK(root && view); + if (view->GetNotifyWhenVisibleBoundsInRootChanges()) + root->RegisterViewForVisibleBoundsNotification(view); + for (int i = 0; i < view->GetChildViewCount(); ++i) + RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i)); } -bool View::GetAccessibleName(string16* name) { - DCHECK(name); - - if (accessible_name_.empty()) - return false; - *name = accessible_name_; - return true; +// static +void View::UnregisterChildrenForVisibleBoundsNotification( + RootView* root, View* view) { + DCHECK(root && view); + if (view->GetNotifyWhenVisibleBoundsInRootChanges()) + root->UnregisterViewForVisibleBoundsNotification(view); + for (int i = 0; i < view->GetChildViewCount(); ++i) + UnregisterChildrenForVisibleBoundsNotification(root, + view->GetChildViewAt(i)); } -AccessibilityTypes::Role View::GetAccessibleRole() { - return AccessibilityTypes::ROLE_CLIENT; +void View::AddDescendantToNotify(View* view) { + DCHECK(view); + if (!descendants_to_notify_.get()) + descendants_to_notify_.reset(new ViewList()); + descendants_to_notify_->push_back(view); } -void View::SetAccessibleName(const string16& name) { - accessible_name_ = name; +void View::RemoveDescendantToNotify(View* view) { + DCHECK(view && descendants_to_notify_.get()); + ViewList::iterator i = find(descendants_to_notify_->begin(), + descendants_to_notify_->end(), + view); + DCHECK(i != descendants_to_notify_->end()); + descendants_to_notify_->erase(i); + if (descendants_to_notify_->empty()) + descendants_to_notify_.reset(); } -// static -void View::ConvertPointToView(const View* src, - const View* dst, - gfx::Point* point) { - ConvertPointToView(src, dst, point, true); -} +// Coordinate conversion ------------------------------------------------------- // static void View::ConvertPointToView(const View* src, @@ -1238,202 +1347,194 @@ void View::ConvertPointToView(const View* src, } } -// static -void View::ConvertPointToWidget(const View* src, gfx::Point* p) { - DCHECK(src); - DCHECK(p); +// Input ----------------------------------------------------------------------- - gfx::Point offset; - for (const View* v = src; v; v = v->GetParent()) { - offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION)); - offset.set_y(offset.y() + v->y()); - } - p->SetPoint(p->x() + offset.x(), p->y() + offset.y()); -} +bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) { + const bool enabled = IsEnabled(); + int drag_operations = + (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location())) ? + GetDragOperations(e.location()) : 0; + ContextMenuController* context_menu_controller = e.IsRightMouseButton() ? + context_menu_controller_ : 0; -// static -void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { - gfx::Point t; - ConvertPointToWidget(dest, &t); - p->SetPoint(p->x() - t.x(), p->y() - t.y()); -} + const bool result = OnMousePressed(e); + // WARNING: we may have been deleted, don't use any View variables; -// static -void View::ConvertPointToScreen(const View* src, gfx::Point* p) { - DCHECK(src); - DCHECK(p); + if (!enabled) + return result; - // If the view is not connected to a tree, there's nothing we can do. - Widget* widget = src->GetWidget(); - if (widget) { - ConvertPointToWidget(src, p); - gfx::Rect r; - widget->GetBounds(&r, false); - p->SetPoint(p->x() + r.x(), p->y() + r.y()); + if (drag_operations != ui::DragDropTypes::DRAG_NONE) { + drag_info->PossibleDrag(e.location()); + return true; } + return !!context_menu_controller || result; } -gfx::Rect View::GetScreenBounds() const { - gfx::Point origin; - View::ConvertPointToScreen(this, &origin); - return gfx::Rect(origin, size()); -} - -///////////////////////////////////////////////////////////////////////////// -// -// View - event handlers -// -///////////////////////////////////////////////////////////////////////////// - -bool View::OnMousePressed(const MouseEvent& e) { - return false; -} - -bool View::OnMouseDragged(const MouseEvent& e) { - return false; -} - -void View::OnMouseReleased(const MouseEvent& e, bool canceled) { -} - -void View::OnMouseMoved(const MouseEvent& e) { -} - -void View::OnMouseEntered(const MouseEvent& e) { +bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) { + // Copy the field, that way if we're deleted after drag and drop no harm is + // done. + ContextMenuController* context_menu_controller = context_menu_controller_; + const bool possible_drag = drag_info->possible_drag; + if (possible_drag && ExceededDragThreshold(drag_info->start_pt.x() - e.x(), + drag_info->start_pt.y() - e.y())) { + if (!drag_controller_ || + drag_controller_->CanStartDrag(this, drag_info->start_pt, e.location())) + DoDrag(e, drag_info->start_pt); + } else { + if (OnMouseDragged(e)) + return true; + // Fall through to return value based on context menu controller. + } + // WARNING: we may have been deleted. + return (context_menu_controller != NULL) || possible_drag; } -void View::OnMouseExited(const MouseEvent& e) { +void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) { + if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) { + // Assume that if there is a context menu controller we won't be deleted + // from mouse released. + gfx::Point location(e.location()); + OnMouseReleased(e, canceled); + if (HitTest(location)) { + ConvertPointToScreen(this, &location); + ShowContextMenu(location, true); + } + } else { + OnMouseReleased(e, canceled); + } + // WARNING: we may have been deleted. } #if defined(TOUCH_UI) -View::TouchStatus View::OnTouchEvent(const TouchEvent& event) { - DVLOG(1) << "visited the OnTouchEvent"; - return TOUCH_STATUS_UNKNOWN; +View::TouchStatus View::ProcessTouchEvent(const TouchEvent& e) { + // TODO(rjkroege): Implement a grab scheme similar to as + // as is found in MousePressed. + return OnTouchEvent(e); } #endif -void View::SetMouseHandler(View *new_mouse_handler) { - // It is valid for new_mouse_handler to be NULL - if (parent_) - parent_->SetMouseHandler(new_mouse_handler); -} - -void View::SetVisible(bool flag) { - if (flag != is_visible_) { - // If the tab is currently visible, schedule paint to - // refresh parent - if (IsVisible()) - SchedulePaint(); - - is_visible_ = flag; - - // This notifies all subviews recursively. - PropagateVisibilityNotifications(this, flag); +// Accelerators ---------------------------------------------------------------- - // If we are newly visible, schedule paint. - if (IsVisible()) - SchedulePaint(); +void View::RegisterPendingAccelerators() { + if (!accelerators_.get() || + registered_accelerator_count_ == accelerators_->size()) { + // No accelerators are waiting for registration. + return; } -} - -bool View::IsVisibleInRootView() const { - View* parent = GetParent(); - if (IsVisible() && parent) - return parent->IsVisibleInRootView(); - else - return false; -} - -///////////////////////////////////////////////////////////////////////////// -// -// View - keyboard and focus -// -///////////////////////////////////////////////////////////////////////////// - -void View::RequestFocus() { - RootView* rv = GetRootView(); - if (rv && IsFocusableInRootView()) - rv->FocusView(this); -} - -void View::WillGainFocus() { -} - -void View::DidGainFocus() { -} - -void View::WillLoseFocus() { -} -bool View::OnKeyPressed(const KeyEvent& e) { - return false; -} - -bool View::OnKeyReleased(const KeyEvent& e) { - return false; -} - -bool View::OnMouseWheel(const MouseWheelEvent& e) { - return false; -} - -void View::SetDragController(DragController* drag_controller) { - drag_controller_ = drag_controller; -} - -DragController* View::GetDragController() { - return drag_controller_; -} + RootView* root_view = GetRootView(); + if (!root_view) { + // We are not yet part of a view hierarchy, we'll register ourselves once + // added to one. + return; + } -bool View::GetDropFormats( - int* formats, - std::set<OSExchangeData::CustomFormat>* custom_formats) { - return false; -} + accelerator_focus_manager_ = GetFocusManager(); + if (!accelerator_focus_manager_) { + // Some crash reports seem to show that we may get cases where we have no + // focus manager (see bug #1291225). This should never be the case, just + // making sure we don't crash. -bool View::AreDropTypesRequired() { - return false; + // TODO(jcampan): This fails for a view under WidgetGtk with TYPE_CHILD. + // (see http://crbug.com/21335) reenable NOTREACHED assertion and + // verify accelerators works as expected. +#if defined(OS_WIN) + NOTREACHED(); +#endif + return; + } + // Only register accelerators if we are visible. + if (!IsVisibleInRootView()) + return; + std::vector<Accelerator>::const_iterator iter; + for (iter = accelerators_->begin() + registered_accelerator_count_; + iter != accelerators_->end(); ++iter) { + accelerator_focus_manager_->RegisterAccelerator(*iter, this); + } + registered_accelerator_count_ = accelerators_->size(); } -bool View::CanDrop(const OSExchangeData& data) { - // TODO(sky): when I finish up migration, this should default to true. - return false; -} +void View::UnregisterAccelerators(bool leave_data_intact) { + if (!accelerators_.get()) + return; -void View::OnDragEntered(const DropTargetEvent& event) { + RootView* root_view = GetRootView(); + if (root_view) { + if (accelerator_focus_manager_) { + // We may not have a FocusManager if the window containing us is being + // closed, in which case the FocusManager is being deleted so there is + // nothing to unregister. + accelerator_focus_manager_->UnregisterAccelerators(this); + accelerator_focus_manager_ = NULL; + } + if (!leave_data_intact) { + accelerators_->clear(); + accelerators_.reset(); + } + registered_accelerator_count_ = 0; + } } -int View::OnDragUpdated(const DropTargetEvent& event) { - return ui::DragDropTypes::DRAG_NONE; -} +// Focus ----------------------------------------------------------------------- -void View::OnDragExited() { -} +void View::InitFocusSiblings(View* v, int index) { + int child_count = static_cast<int>(child_views_.size()); -int View::OnPerformDrop(const DropTargetEvent& event) { - return ui::DragDropTypes::DRAG_NONE; + if (child_count == 0) { + v->next_focusable_view_ = NULL; + v->previous_focusable_view_ = NULL; + } else { + if (index == child_count) { + // We are inserting at the end, but the end of the child list may not be + // the last focusable element. Let's try to find an element with no next + // focusable element to link to. + View* last_focusable_view = NULL; + for (std::vector<View*>::iterator iter = child_views_.begin(); + iter != child_views_.end(); ++iter) { + if (!(*iter)->next_focusable_view_) { + last_focusable_view = *iter; + break; + } + } + if (last_focusable_view == NULL) { + // Hum... there is a cycle in the focus list. Let's just insert ourself + // after the last child. + View* prev = child_views_[index - 1]; + v->previous_focusable_view_ = prev; + v->next_focusable_view_ = prev->next_focusable_view_; + prev->next_focusable_view_->previous_focusable_view_ = v; + prev->next_focusable_view_ = v; + } else { + last_focusable_view->next_focusable_view_ = v; + v->next_focusable_view_ = NULL; + v->previous_focusable_view_ = last_focusable_view; + } + } else { + View* prev = child_views_[index]->GetPreviousFocusableView(); + v->previous_focusable_view_ = prev; + v->next_focusable_view_ = child_views_[index]; + if (prev) + prev->next_focusable_view_ = v; + child_views_[index]->previous_focusable_view_ = v; + } + } } -// static -bool View::ExceededDragThreshold(int delta_x, int delta_y) { - return (abs(delta_x) > GetHorizontalDragThreshold() || - abs(delta_y) > GetVerticalDragThreshold()); -} +// System events --------------------------------------------------------------- -// Tooltips ----------------------------------------------------------------- -bool View::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) { - return false; +void View::PropagateThemeChanged() { + for (int i = GetChildViewCount() - 1; i >= 0; --i) + GetChildViewAt(i)->PropagateThemeChanged(); + OnThemeChanged(); } -bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) { - return false; +void View::PropagateLocaleChanged() { + for (int i = GetChildViewCount() - 1; i >= 0; --i) + GetChildViewAt(i)->PropagateLocaleChanged(); + OnLocaleChanged(); } -void View::TooltipTextChanged() { - Widget* widget = GetWidget(); - if (widget && widget->GetTooltipManager()) - widget->GetTooltipManager()->TooltipTextChanged(this); -} +// Tooltips -------------------------------------------------------------------- void View::UpdateTooltip() { Widget* widget = GetWidget(); @@ -1441,112 +1542,20 @@ void View::UpdateTooltip() { widget->GetTooltipManager()->UpdateTooltip(); } -std::string View::GetClassName() const { - return kViewClassName; -} - -View* View::GetAncestorWithClassName(const std::string& name) { - for (View* view = this; view; view = view->GetParent()) { - if (view->GetClassName() == name) - return view; - } - return NULL; -} - -gfx::Rect View::GetVisibleBounds() { - if (!IsVisibleInRootView()) - return gfx::Rect(); - gfx::Rect vis_bounds(0, 0, width(), height()); - gfx::Rect ancestor_bounds; - View* view = this; - int root_x = 0; - int root_y = 0; - while (view != NULL && !vis_bounds.IsEmpty()) { - root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION); - root_y += view->y(); - vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y()); - View* ancestor = view->GetParent(); - if (ancestor != NULL) { - ancestor_bounds.SetRect(0, 0, ancestor->width(), - ancestor->height()); - vis_bounds = vis_bounds.Intersect(ancestor_bounds); - } else if (!view->GetWidget()) { - // If the view has no Widget, we're not visible. Return an empty rect. - return gfx::Rect(); - } - view = ancestor; - } - if (vis_bounds.IsEmpty()) - return vis_bounds; - // Convert back to this views coordinate system. - vis_bounds.Offset(-root_x, -root_y); - return vis_bounds; -} - -int View::GetPageScrollIncrement(ScrollView* scroll_view, - bool is_horizontal, bool is_positive) { - return 0; -} - -int View::GetLineScrollIncrement(ScrollView* scroll_view, - bool is_horizontal, bool is_positive) { - return 0; -} - -ThemeProvider* View::GetThemeProvider() const { - Widget* widget = GetWidget(); - return widget ? widget->GetThemeProvider() : NULL; -} - -// static -void View::RegisterChildrenForVisibleBoundsNotification( - RootView* root, View* view) { - DCHECK(root && view); - if (view->GetNotifyWhenVisibleBoundsInRootChanges()) - root->RegisterViewForVisibleBoundsNotification(view); - for (int i = 0; i < view->GetChildViewCount(); ++i) - RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i)); -} - -// static -void View::UnregisterChildrenForVisibleBoundsNotification( - RootView* root, View* view) { - DCHECK(root && view); - if (view->GetNotifyWhenVisibleBoundsInRootChanges()) - root->UnregisterViewForVisibleBoundsNotification(view); - for (int i = 0; i < view->GetChildViewCount(); ++i) - UnregisterChildrenForVisibleBoundsNotification(root, - view->GetChildViewAt(i)); -} +// Drag and drop --------------------------------------------------------------- -void View::AddDescendantToNotify(View* view) { - DCHECK(view); - if (!descendants_to_notify_.get()) - descendants_to_notify_.reset(new ViewList()); - descendants_to_notify_->push_back(view); -} - -void View::RemoveDescendantToNotify(View* view) { - DCHECK(view && descendants_to_notify_.get()); - ViewList::iterator i = find(descendants_to_notify_->begin(), - descendants_to_notify_->end(), - view); - DCHECK(i != descendants_to_notify_->end()); - descendants_to_notify_->erase(i); - if (descendants_to_notify_->empty()) - descendants_to_notify_.reset(); -} - -// DropInfo -------------------------------------------------------------------- +void View::DoDrag(const MouseEvent& e, const gfx::Point& press_pt) { + int drag_operations = GetDragOperations(press_pt); + if (drag_operations == ui::DragDropTypes::DRAG_NONE) + return; -void View::DragInfo::Reset() { - possible_drag = false; - start_pt = gfx::Point(); -} + OSExchangeData data; + WriteDragData(press_pt, &data); -void View::DragInfo::PossibleDrag(const gfx::Point& p) { - possible_drag = true; - start_pt = p; + // Message the RootView to do the drag and drop. That way if we're removed + // the RootView can detect it and avoid calling us back. + RootView* root_view = GetRootView(); + root_view->StartDragForViewFromMouseEvent(this, data, drag_operations); } -} // namespace +} // namespace views diff --git a/views/view.h b/views/view.h index c003f1c..d13fcbb 100644 --- a/views/view.h +++ b/views/view.h @@ -150,20 +150,113 @@ class View : public AcceleratorTarget { }; #endif - // The view class name. - static char kViewClassName[]; - - View(); - virtual ~View(); + // TO BE MOVED --------------------------------------------------------------- + // TODO(beng): These methods are to be moved to other files/classes. + // TODO(beng): move to metrics.h // Returns the amount of time between double clicks, in milliseconds. static int GetDoubleClickTimeMS(); + // TODO(beng): move to metrics.h // Returns the amount of time to wait from hovering over a menu button until // showing the menu. static int GetMenuShowDelay(); - // Sizing functions + // TODO(beng): delete + // Set whether this view is hottracked. A disabled view cannot be hottracked. + // If flag differs from the current value, SchedulePaint is invoked. + virtual void SetHotTracked(bool flag); + + // TODO(beng): delete + // Returns whether the view is hot-tracked. + virtual bool IsHotTracked() const { return false; } + + // TODO(beng): delete + // Returns whether the view is pushed. + virtual bool IsPushed() const { return false; } + + // FATE TBD ------------------------------------------------------------------ + // TODO(beng): Figure out what these methods are for and delete them. + + // TODO(beng): this one isn't even google3-style. wth. + virtual Widget* child_widget() { return NULL; } + + // Creation and lifetime ----------------------------------------------------- + + View(); + virtual ~View(); + + // Set whether this view is owned by its parent. A view that is owned by its + // parent is automatically deleted when the parent is deleted. The default is + // true. Set to false if the view is owned by another object and should not + // be deleted by its parent. + void set_parent_owned(bool is_parent_owned) { + is_parent_owned_ = is_parent_owned; + } + + // Return whether a view is owned by its parent. + bool IsParentOwned() const { return is_parent_owned_; } + + // Tree operations ----------------------------------------------------------- + + // Add a child View. + void AddChildView(View* v); + + // Adds a child View at the specified position. + void AddChildView(int index, View* v); + + // Get the child View at the specified index. + View* GetChildViewAt(int index) const; + + // Remove a child view from this view. v's parent will change to NULL + void RemoveChildView(View *v); + + // Remove all child view from this view. If |delete_views| is true, the views + // are deleted, unless marked as not parent owned. + void RemoveAllChildViews(bool delete_views); + + // Get the number of child Views. + int GetChildViewCount() const; + + // Tests if this view has a given view as direct child. + bool HasChildView(View* a_view); + + // Get the Widget that hosts this View, if any. + virtual Widget* GetWidget() const; + + // Gets the Widget that most closely contains this View, if any. + // NOTE: almost all views displayed on screen have a Widget, but not + // necessarily a Window. This is due to widgets being able to create top + // level windows (as is done for popups, bubbles and menus). + virtual Window* GetWindow() const; + + // Returns true if the native view |native_view| is contained in the view + // hierarchy beneath this view. + virtual bool ContainsNativeView(gfx::NativeView native_view) const; + + // Get the containing RootView + virtual RootView* GetRootView(); + + // Get the parent View + View* GetParent() const { return parent_; } + + // Returns the index of the specified |view| in this view's children, or -1 + // if the specified view is not a child of this view. + int GetChildIndex(const View* v) const; + + // Returns true if the specified view is a direct or indirect child of this + // view. + bool IsParentOf(View* v) const; + +#ifndef NDEBUG + // Debug method that logs the view hierarchy to the output. + void PrintViewHierarchy(); + + // Debug method that logs the focus traversal hierarchy to the output. + void PrintFocusHierarchy(); +#endif + + // Size and disposition ------------------------------------------------------ // Get the bounds of the View, relative to the parent. Essentially, this // function returns the bounds_ rectangle. @@ -227,6 +320,22 @@ class View : public AcceleratorTarget { // include the area where the border (if any) is painted. gfx::Rect GetLocalBounds(bool include_border) const; + // Returns the insets of the current border. If there is no border an empty + // insets is returned. + virtual gfx::Insets GetInsets() const; + + // Returns the visible bounds of the receiver in the receivers coordinate + // system. + // + // When traversing the View hierarchy in order to compute the bounds, the + // function takes into account the mirroring setting for each View and + // therefore it will return the mirrored version of the visible bounds if + // need be. + gfx::Rect GetVisibleBounds(); + + // Return the bounds of the View in screen coordinate system. + gfx::Rect GetScreenBounds() const; + // Get the position of the View, relative to the parent. // // Note that if the parent uses right-to-left UI layout, then the mirrored @@ -277,69 +386,7 @@ class View : public AcceleratorTarget { // Returns whether the view is enabled. virtual bool IsEnabled() const; - // Set whether this view is hottracked. A disabled view cannot be hottracked. - // If flag differs from the current value, SchedulePaint is invoked. - virtual void SetHotTracked(bool flag); - - // Returns whether the view is hot-tracked. - virtual bool IsHotTracked() const { return false; } - - virtual Widget* child_widget() { return NULL; } - - // Returns whether the view is pushed. - virtual bool IsPushed() const { return false; } - - // Scrolls the specified region, in this View's coordinate system, to be - // visible. View's implementation passes the call onto the parent View (after - // adjusting the coordinates). It is up to views that only show a portion of - // the child view, such as Viewport, to override appropriately. - virtual void ScrollRectToVisible(const gfx::Rect& rect); - - // Layout functions - - // Lay out the child Views (set their bounds based on sizing heuristics - // specific to the current Layout Manager) - virtual void Layout(); - - // Mark this view and all parents to require a relayout. This ensures the - // next call to Layout() will propagate to this view, even if the bounds of - // parent views do not change. - void InvalidateLayout(); - - // Gets/Sets the Layout Manager used by this view to size and place its - // children. - // The LayoutManager is owned by the View and is deleted when the view is - // deleted, or when a new LayoutManager is installed. - LayoutManager* GetLayoutManager() const; - void SetLayoutManager(LayoutManager* layout); - - // Right-to-left UI layout functions - - // This method determines whether the gfx::Canvas object passed to - // View::Paint() needs to be transformed such that anything drawn on the - // canvas object during View::Paint() is flipped horizontally. - // - // By default, this function returns false (which is the initial value of - // |flip_canvas_on_paint_for_rtl_ui_|). View subclasses that need to paint on - // a flipped gfx::Canvas when the UI layout is right-to-left need to call - // EnableCanvasFlippingForRTLUI(). - bool FlipCanvasOnPaintForRTLUI() const { - return flip_canvas_on_paint_for_rtl_ui_ ? base::i18n::IsRTL() : false; - } - - // Enables or disables flipping of the gfx::Canvas during View::Paint(). - // Note that if canvas flipping is enabled, the canvas will be flipped only - // if the UI layout is right-to-left; that is, the canvas will be flipped - // only if base::i18n::IsRTL() returns true. - // - // Enabling canvas flipping is useful for leaf views that draw a bitmap that - // needs to be flipped horizontally when the UI layout is right-to-left - // (views::Button, for example). This method is helpful for such classes - // because their drawing logic stays the same and they can become agnostic to - // the UI directionality. - void EnableCanvasFlippingForRTLUI(bool enable) { - flip_canvas_on_paint_for_rtl_ui_ = enable; - } + // RTL positioning ----------------------------------------------------------- // Returns the mirrored X position for the view, relative to the parent. If // the parent view is not mirrored, this function returns bound_.left. @@ -386,96 +433,39 @@ class View : public AcceleratorTarget { return base::i18n::IsRTL() ? width() - x - w : x; } - // Painting functions - - // Mark the specified rectangle as dirty (needing repaint). If |urgent| is - // true, the view will be repainted when the current event processing is - // done. Otherwise, painting will take place as soon as possible. - virtual void SchedulePaint(const gfx::Rect& r, bool urgent); - - // Mark the entire View's bounds as dirty. Painting will occur as soon as - // possible. - virtual void SchedulePaint(); - - // Paint the receiving view. g is prepared such as it is in - // receiver's coordinate system. g's state is restored after this - // call so your implementation can change the graphics configuration - // - // Default implementation paints the background if it is defined - // - // Override this method when implementing a new control. - virtual void Paint(gfx::Canvas* canvas); - - // Paint the background if any. This method is called by Paint() and - // should rarely be invoked directly. - virtual void PaintBackground(gfx::Canvas* canvas); - - // Paint the border if any. This method is called by Paint() and - // should rarely be invoked directly. - virtual void PaintBorder(gfx::Canvas* canvas); - - // Paints the focus border (only if the view has the focus). - // This method is called by Paint() and should rarely be invoked directly. - // The default implementation paints a gray border around the view. Override - // it for custom focus effects. - virtual void PaintFocusBorder(gfx::Canvas* canvas); - - // Paint this View immediately. - virtual void PaintNow(); - - // Tree functions - - // Add a child View. - void AddChildView(View* v); + // Layout -------------------------------------------------------------------- - // Adds a child View at the specified position. - void AddChildView(int index, View* v); - - // Get the child View at the specified index. - View* GetChildViewAt(int index) const; - - // Remove a child view from this view. v's parent will change to NULL - void RemoveChildView(View *v); - - // Remove all child view from this view. If |delete_views| is true, the views - // are deleted, unless marked as not parent owned. - void RemoveAllChildViews(bool delete_views); - - // Get the number of child Views. - int GetChildViewCount() const; - - // Tests if this view has a given view as direct child. - bool HasChildView(View* a_view); - - // Returns the deepest descendant that contains the specified point. - virtual View* GetViewForPoint(const gfx::Point& point); - - // Get the Widget that hosts this View, if any. - virtual Widget* GetWidget() const; + // Lay out the child Views (set their bounds based on sizing heuristics + // specific to the current Layout Manager) + virtual void Layout(); - // Gets the Widget that most closely contains this View, if any. - // NOTE: almost all views displayed on screen have a Widget, but not - // necessarily a Window. This is due to widgets being able to create top - // level windows (as is done for popups, bubbles and menus). - virtual Window* GetWindow() const; + // TODO(beng): I think we should remove this. + // Mark this view and all parents to require a relayout. This ensures the + // next call to Layout() will propagate to this view, even if the bounds of + // parent views do not change. + void InvalidateLayout(); - // Returns true if the native view |native_view| is contained in the view - // hierarchy beneath this view. - virtual bool ContainsNativeView(gfx::NativeView native_view) const; + // Gets/Sets the Layout Manager used by this view to size and place its + // children. + // The LayoutManager is owned by the View and is deleted when the view is + // deleted, or when a new LayoutManager is installed. + LayoutManager* GetLayoutManager() const; + void SetLayoutManager(LayoutManager* layout); - // Get the containing RootView - virtual RootView* GetRootView(); + // Attributes ---------------------------------------------------------------- - // Get the parent View - View* GetParent() const { return parent_; } + // The view class name. + static char kViewClassName[]; - // Returns the index of the specified |view| in this view's children, or -1 - // if the specified view is not a child of this view. - int GetChildIndex(const View* v) const; + // Return the receiving view's class name. A view class is a string which + // uniquely identifies the view class. It is intended to be used as a way to + // find out during run time if a view can be safely casted to a specific view + // subclass. The default implementation returns kViewClassName. + virtual std::string GetClassName() const; - // Returns true if the specified view is a direct or indirect child of this - // view. - bool IsParentOf(View* v) const; + // Returns the first ancestor, starting at this, whose class name is |name|. + // Returns null if no ancestor has the class name |name|. + View* GetAncestorWithClassName(const std::string& name); // Recursively descends the view tree starting at this view, and returns // the first child that it encounters that has the given ID. @@ -510,120 +500,7 @@ class View : public AcceleratorTarget { // group. virtual View* GetSelectedViewForGroup(int group_id); - // Focus support - // - // Returns the view that should be selected next when pressing Tab. - View* GetNextFocusableView(); - - // Returns the view that should be selected next when pressing Shift-Tab. - View* GetPreviousFocusableView(); - - // Sets the component that should be selected next when pressing Tab, and - // makes the current view the precedent view of the specified one. - // Note that by default views are linked in the order they have been added to - // their container. Use this method if you want to modify the order. - // IMPORTANT NOTE: loops in the focus hierarchy are not supported. - void SetNextFocusableView(View* view); - - // Sets whether this view can accept the focus. - // Note that this is false by default so that a view used as a container does - // not get the focus. - virtual void SetFocusable(bool focusable); - - // Returns true if the view is focusable (IsFocusable) and visible in the root - // view. See also IsFocusable. - bool IsFocusableInRootView() const; - - // Return whether this view is focusable when the user requires full keyboard - // access, even though it may not be normally focusable. - bool IsAccessibilityFocusableInRootView() const; - - // Set whether this view can be made focusable if the user requires - // full keyboard access, even though it's not normally focusable. - // Note that this is false by default. - virtual void set_accessibility_focusable(bool accessibility_focusable) { - accessibility_focusable_ = accessibility_focusable; - } - - // Convenience method to retrieve the FocusManager associated with the - // Widget that contains this view. This can return NULL if this view is not - // part of a view hierarchy with a Widget. - virtual FocusManager* GetFocusManager(); - - // Sets a keyboard accelerator for that view. When the user presses the - // accelerator key combination, the AcceleratorPressed method is invoked. - // Note that you can set multiple accelerators for a view by invoking this - // method several times. - virtual void AddAccelerator(const Accelerator& accelerator); - - // Removes the specified accelerator for this view. - virtual void RemoveAccelerator(const Accelerator& accelerator); - - // Removes all the keyboard accelerators for this view. - virtual void ResetAccelerators(); - - // Called when a keyboard accelerator is pressed. - // Derived classes should implement desired behavior and return true if they - // handled the accelerator. - virtual bool AcceleratorPressed(const Accelerator& accelerator) { - return false; - } - - // Returns whether this view currently has the focus. - virtual bool HasFocus(); - - // Accessibility support - // TODO(ctguil): Move all this out to a AccessibleInfo wrapper class. - - // Notify the platform specific accessibility client of changes in the user - // interface. This will always raise native notifications. - virtual void NotifyAccessibilityEvent(AccessibilityTypes::Event event_type); - - // Raise an accessibility notification with an option to also raise a native - // notification. - virtual void NotifyAccessibilityEvent(AccessibilityTypes::Event event_type, - bool send_native_event); - - // Returns the MSAA default action of the current view. The string returned - // describes the default action that will occur when executing - // IAccessible::DoDefaultAction. For instance, default action of a button is - // 'Press'. - virtual string16 GetAccessibleDefaultAction() { return string16(); } - - // Returns a string containing the mnemonic, or the keyboard shortcut, for a - // given control. - virtual string16 GetAccessibleKeyboardShortcut() { - return string16(); - } - - // Returns a brief, identifying string, containing a unique, readable name of - // a given control. Sets the input string appropriately, and returns true if - // successful. - bool GetAccessibleName(string16* name); - - // Returns the accessibility role of the current view. The role is what - // assistive technologies (ATs) use to determine what behavior to expect from - // a given control. - virtual AccessibilityTypes::Role GetAccessibleRole(); - - // Returns the accessibility state of the current view. - virtual AccessibilityTypes::State GetAccessibleState() { - return 0; - } - - // Returns the current value associated with a view. - virtual string16 GetAccessibleValue() { return string16(); } - - // Assigns a string name to the given control. Needed as a View does not know - // which name will be associated with it until it is created to be a - // certain type. - void SetAccessibleName(const string16& name); - - // Returns an instance of the (platform-specific) accessibility interface for - // the View. - ViewAccessibility* GetViewAccessibility(); - - // Utility functions + // Coordinate conversion ----------------------------------------------------- // Note that the utility coordinate conversions functions always operate on // the mirrored position of the child Views if the parent View uses a @@ -652,10 +529,109 @@ class View : public AcceleratorTarget { // screen. This is useful for example when placing popup windows. static void ConvertPointToScreen(const View* src, gfx::Point* point); - // Return the bounds of the View in screen coordinate system. - gfx::Rect GetScreenBounds() const; + // Painting ------------------------------------------------------------------ + + // Mark the specified rectangle as dirty (needing repaint). If |urgent| is + // true, the view will be repainted when the current event processing is + // done. Otherwise, painting will take place as soon as possible. + virtual void SchedulePaint(const gfx::Rect& r, bool urgent); + + // Mark the entire View's bounds as dirty. Painting will occur as soon as + // possible. + virtual void SchedulePaint(); + + // Paint the receiving view. g is prepared such as it is in + // receiver's coordinate system. g's state is restored after this + // call so your implementation can change the graphics configuration + // + // Default implementation paints the background if it is defined + // + // Override this method when implementing a new control. + virtual void Paint(gfx::Canvas* canvas); + + // Paint the background if any. This method is called by Paint() and + // should rarely be invoked directly. + virtual void PaintBackground(gfx::Canvas* canvas); + + // Paint the border if any. This method is called by Paint() and + // should rarely be invoked directly. + virtual void PaintBorder(gfx::Canvas* canvas); + + // Paints the focus border (only if the view has the focus). + // This method is called by Paint() and should rarely be invoked directly. + // The default implementation paints a gray border around the view. Override + // it for custom focus effects. + virtual void PaintFocusBorder(gfx::Canvas* canvas); + + // Paint this View immediately. + virtual void PaintNow(); + + // This method is the main entry point to process paint for this + // view and its children. This method is called by the painting + // system. You should call this only if you want to draw a sub tree + // inside a custom graphics. + // To customize painting override either the Paint or PaintChildren method, + // not this one. + virtual void ProcessPaint(gfx::Canvas* canvas); - // Event Handlers + // Paint the View's child Views, in reverse order. + virtual void PaintChildren(gfx::Canvas* canvas); + + // The background object is owned by this object and may be NULL. + void set_background(Background* b) { background_.reset(b); } + const Background* background() const { return background_.get(); } + + // The border object is owned by this object and may be NULL. + void set_border(Border* b) { border_.reset(b); } + const Border* border() const { return border_.get(); } + + // Get the theme provider from the parent widget. + ThemeProvider* GetThemeProvider() const; + + // RTL painting -------------------------------------------------------------- + + // This method determines whether the gfx::Canvas object passed to + // View::Paint() needs to be transformed such that anything drawn on the + // canvas object during View::Paint() is flipped horizontally. + // + // By default, this function returns false (which is the initial value of + // |flip_canvas_on_paint_for_rtl_ui_|). View subclasses that need to paint on + // a flipped gfx::Canvas when the UI layout is right-to-left need to call + // EnableCanvasFlippingForRTLUI(). + bool FlipCanvasOnPaintForRTLUI() const { + return flip_canvas_on_paint_for_rtl_ui_ ? base::i18n::IsRTL() : false; + } + + // Enables or disables flipping of the gfx::Canvas during View::Paint(). + // Note that if canvas flipping is enabled, the canvas will be flipped only + // if the UI layout is right-to-left; that is, the canvas will be flipped + // only if base::i18n::IsRTL() returns true. + // + // Enabling canvas flipping is useful for leaf views that draw a bitmap that + // needs to be flipped horizontally when the UI layout is right-to-left + // (views::Button, for example). This method is helpful for such classes + // because their drawing logic stays the same and they can become agnostic to + // the UI directionality. + void EnableCanvasFlippingForRTLUI(bool enable) { + flip_canvas_on_paint_for_rtl_ui_ = enable; + } + + // Input --------------------------------------------------------------------- + + // Returns the deepest descendant that contains the specified point. + virtual View* GetViewForPoint(const gfx::Point& point); + + // Return the cursor that should be used for this view or NULL if + // the default cursor should be used. The provided point is in the + // receiver's coordinate system. The caller is responsible for managing the + // lifetime of the returned object, though that lifetime may vary from + // platform to platform. On Windows, the cursor is a shared resource but in + // Gtk, the framework destroys the returned cursor after setting it. + virtual gfx::NativeCursor GetCursorForPoint(Event::EventType event_type, + const gfx::Point& p); + + // Convenience to test whether a point is within this view's bounds + virtual bool HitTest(const gfx::Point& l) const; // This method is invoked when the user clicks on this view. // The provided event is in the receiver's coordinate system. @@ -739,6 +715,84 @@ class View : public AcceleratorTarget { // virtual void SetMouseHandler(View* new_mouse_handler); + // Invoked when a key is pressed or released. + // Subclasser should return true if the event has been processed and false + // otherwise. If the event has not been processed, the parent will be given a + // chance. + virtual bool OnKeyPressed(const KeyEvent& e); + virtual bool OnKeyReleased(const KeyEvent& e); + + // Invoked when the user uses the mousewheel. Implementors should return true + // if the event has been processed and false otherwise. This message is sent + // if the view is focused. If the event has not been processed, the parent + // will be given a chance. + virtual bool OnMouseWheel(const MouseWheelEvent& e); + + // Accelerators -------------------------------------------------------------- + + // Sets a keyboard accelerator for that view. When the user presses the + // accelerator key combination, the AcceleratorPressed method is invoked. + // Note that you can set multiple accelerators for a view by invoking this + // method several times. + virtual void AddAccelerator(const Accelerator& accelerator); + + // Removes the specified accelerator for this view. + virtual void RemoveAccelerator(const Accelerator& accelerator); + + // Removes all the keyboard accelerators for this view. + virtual void ResetAccelerators(); + + // TODO(beng): Move to an AcceleratorTarget override section. + // Called when a keyboard accelerator is pressed. + // Derived classes should implement desired behavior and return true if they + // handled the accelerator. + virtual bool AcceleratorPressed(const Accelerator& accelerator) { + return false; + } + + // Focus --------------------------------------------------------------------- + + // Returns whether this view currently has the focus. + virtual bool HasFocus(); + + // Returns the view that should be selected next when pressing Tab. + View* GetNextFocusableView(); + + // Returns the view that should be selected next when pressing Shift-Tab. + View* GetPreviousFocusableView(); + + // Sets the component that should be selected next when pressing Tab, and + // makes the current view the precedent view of the specified one. + // Note that by default views are linked in the order they have been added to + // their container. Use this method if you want to modify the order. + // IMPORTANT NOTE: loops in the focus hierarchy are not supported. + void SetNextFocusableView(View* view); + + // Sets whether this view can accept the focus. + // Note that this is false by default so that a view used as a container does + // not get the focus. + virtual void SetFocusable(bool focusable); + + // Returns true if the view is focusable (IsFocusable) and visible in the root + // view. See also IsFocusable. + bool IsFocusableInRootView() const; + + // Return whether this view is focusable when the user requires full keyboard + // access, even though it may not be normally focusable. + bool IsAccessibilityFocusableInRootView() const; + + // Set whether this view can be made focusable if the user requires + // full keyboard access, even though it's not normally focusable. + // Note that this is false by default. + virtual void set_accessibility_focusable(bool accessibility_focusable) { + accessibility_focusable_ = accessibility_focusable; + } + + // Convenience method to retrieve the FocusManager associated with the + // Widget that contains this view. This can return NULL if this view is not + // part of a view hierarchy with a Widget. + virtual FocusManager* GetFocusManager(); + // Request the keyboard focus. The receiving view will become the // focused view. virtual void RequestFocus(); @@ -770,20 +824,52 @@ class View : public AcceleratorTarget { return false; } - // Invoked when a key is pressed or released. - // Subclasser should return true if the event has been processed and false - // otherwise. If the event has not been processed, the parent will be given a - // chance. - virtual bool OnKeyPressed(const KeyEvent& e); - virtual bool OnKeyReleased(const KeyEvent& e); + // Subclasses that contain traversable children that are not directly + // accessible through the children hierarchy should return the associated + // FocusTraversable for the focus traversal to work properly. + virtual FocusTraversable* GetFocusTraversable() { return NULL; } - // Invoked when the user uses the mousewheel. Implementors should return true - // if the event has been processed and false otherwise. This message is sent - // if the view is focused. If the event has not been processed, the parent - // will be given a chance. - virtual bool OnMouseWheel(const MouseWheelEvent& e); + // Subclasses that can act as a "pane" must implement their own + // FocusTraversable to keep the focus trapped within the pane. + // If this method returns an object, any view that's a direct or + // indirect child of this view will always use this FocusTraversable + // rather than the one from the widget. + virtual FocusTraversable* GetPaneFocusTraversable() { return NULL; } - // Drag and drop functions. + // Tooltips ------------------------------------------------------------------ + + // Gets the tooltip for this View. If the View does not have a tooltip, + // return false. If the View does have a tooltip, copy the tooltip into + // the supplied string and return true. + // Any time the tooltip text that a View is displaying changes, it must + // invoke TooltipTextChanged. + // |p| provides the coordinates of the mouse (relative to this view). + virtual bool GetTooltipText(const gfx::Point& p, std::wstring* tooltip); + + // Returns the location (relative to this View) for the text on the tooltip + // to display. If false is returned (the default), the tooltip is placed at + // a default position. + virtual bool GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc); + + // Context menus ------------------------------------------------------------- + + // Sets the ContextMenuController. Setting this to non-null makes the View + // process mouse events. + void SetContextMenuController(ContextMenuController* menu_controller); + ContextMenuController* GetContextMenuController() { + return context_menu_controller_; + } + + // Provides default implementation for context menu handling. The default + // implementation calls the ShowContextMenu of the current + // ContextMenuController (if it is not NULL). Overridden in subclassed views + // to provide right-click menu display triggerd by the keyboard (i.e. for the + // Chrome toolbar Back and Forward buttons). No source needs to be specified, + // as it is always equal to the current View. + virtual void ShowContextMenu(const gfx::Point& p, + bool is_mouse_gesture); + + // Drag and drop ------------------------------------------------------------- // Set/get the DragController. See description of DragController for more // information. @@ -848,119 +934,66 @@ class View : public AcceleratorTarget { // delta_x and y are the distance the mouse was dragged. static bool ExceededDragThreshold(int delta_x, int delta_y); - // This method is the main entry point to process paint for this - // view and its children. This method is called by the painting - // system. You should call this only if you want to draw a sub tree - // inside a custom graphics. - // To customize painting override either the Paint or PaintChildren method, - // not this one. - virtual void ProcessPaint(gfx::Canvas* canvas); - - // Paint the View's child Views, in reverse order. - virtual void PaintChildren(gfx::Canvas* canvas); - - // Sets the ContextMenuController. Setting this to non-null makes the View - // process mouse events. - void SetContextMenuController(ContextMenuController* menu_controller); - ContextMenuController* GetContextMenuController() { - return context_menu_controller_; - } - - // Provides default implementation for context menu handling. The default - // implementation calls the ShowContextMenu of the current - // ContextMenuController (if it is not NULL). Overridden in subclassed views - // to provide right-click menu display triggerd by the keyboard (i.e. for the - // Chrome toolbar Back and Forward buttons). No source needs to be specified, - // as it is always equal to the current View. - virtual void ShowContextMenu(const gfx::Point& p, - bool is_mouse_gesture); - - // The background object is owned by this object and may be NULL. - void set_background(Background* b) { background_.reset(b); } - const Background* background() const { return background_.get(); } - - // The border object is owned by this object and may be NULL. - void set_border(Border* b) { border_.reset(b); } - const Border* border() const { return border_.get(); } - - // Returns the insets of the current border. If there is no border an empty - // insets is returned. - virtual gfx::Insets GetInsets() const; - - // Return the cursor that should be used for this view or NULL if - // the default cursor should be used. The provided point is in the - // receiver's coordinate system. The caller is responsible for managing the - // lifetime of the returned object, though that lifetime may vary from - // platform to platform. On Windows, the cursor is a shared resource but in - // Gtk, the framework destroys the returned cursor after setting it. - virtual gfx::NativeCursor GetCursorForPoint(Event::EventType event_type, - const gfx::Point& p); + // Accessibility ------------------------------------------------------------- + // TODO(ctguil): Move all this out to a AccessibleInfo wrapper class. - // Convenience to test whether a point is within this view's bounds - virtual bool HitTest(const gfx::Point& l) const; + // Notify the platform specific accessibility client of changes in the user + // interface. This will always raise native notifications. + virtual void NotifyAccessibilityEvent(AccessibilityTypes::Event event_type); - // Gets the tooltip for this View. If the View does not have a tooltip, - // return false. If the View does have a tooltip, copy the tooltip into - // the supplied string and return true. - // Any time the tooltip text that a View is displaying changes, it must - // invoke TooltipTextChanged. - // |p| provides the coordinates of the mouse (relative to this view). - virtual bool GetTooltipText(const gfx::Point& p, std::wstring* tooltip); + // Raise an accessibility notification with an option to also raise a native + // notification. + virtual void NotifyAccessibilityEvent(AccessibilityTypes::Event event_type, + bool send_native_event); - // Returns the location (relative to this View) for the text on the tooltip - // to display. If false is returned (the default), the tooltip is placed at - // a default position. - virtual bool GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc); + // Returns the MSAA default action of the current view. The string returned + // describes the default action that will occur when executing + // IAccessible::DoDefaultAction. For instance, default action of a button is + // 'Press'. + virtual string16 GetAccessibleDefaultAction() { return string16(); } - // Set whether this view is owned by its parent. A view that is owned by its - // parent is automatically deleted when the parent is deleted. The default is - // true. Set to false if the view is owned by another object and should not - // be deleted by its parent. - void set_parent_owned(bool is_parent_owned) { - is_parent_owned_ = is_parent_owned; + // Returns a string containing the mnemonic, or the keyboard shortcut, for a + // given control. + virtual string16 GetAccessibleKeyboardShortcut() { + return string16(); } - // Return whether a view is owned by its parent. - bool IsParentOwned() const { return is_parent_owned_; } + // Returns a brief, identifying string, containing a unique, readable name of + // a given control. Sets the input string appropriately, and returns true if + // successful. + bool GetAccessibleName(string16* name); - // Return the receiving view's class name. A view class is a string which - // uniquely identifies the view class. It is intended to be used as a way to - // find out during run time if a view can be safely casted to a specific view - // subclass. The default implementation returns kViewClassName. - virtual std::string GetClassName() const; + // Returns the accessibility role of the current view. The role is what + // assistive technologies (ATs) use to determine what behavior to expect from + // a given control. + virtual AccessibilityTypes::Role GetAccessibleRole(); - // Returns the first ancestor, starting at this, whose class name is |name|. - // Returns null if no ancestor has the class name |name|. - View* GetAncestorWithClassName(const std::string& name); + // Returns the accessibility state of the current view. + virtual AccessibilityTypes::State GetAccessibleState() { + return 0; + } - // Returns the visible bounds of the receiver in the receivers coordinate - // system. - // - // When traversing the View hierarchy in order to compute the bounds, the - // function takes into account the mirroring setting for each View and - // therefore it will return the mirrored version of the visible bounds if - // need be. - gfx::Rect GetVisibleBounds(); + // Returns the current value associated with a view. + virtual string16 GetAccessibleValue() { return string16(); } - // Subclasses that contain traversable children that are not directly - // accessible through the children hierarchy should return the associated - // FocusTraversable for the focus traversal to work properly. - virtual FocusTraversable* GetFocusTraversable() { return NULL; } + // Assigns a string name to the given control. Needed as a View does not know + // which name will be associated with it until it is created to be a + // certain type. + void SetAccessibleName(const string16& name); - // Subclasses that can act as a "pane" must implement their own - // FocusTraversable to keep the focus trapped within the pane. - // If this method returns an object, any view that's a direct or - // indirect child of this view will always use this FocusTraversable - // rather than the one from the widget. - virtual FocusTraversable* GetPaneFocusTraversable() { return NULL; } + // Returns an instance of the (platform-specific) accessibility interface for + // the View. + ViewAccessibility* GetViewAccessibility(); -#ifndef NDEBUG - // Debug method that logs the view hierarchy to the output. - void PrintViewHierarchy(); + // Scrolling ----------------------------------------------------------------- + // TODO(beng): Figure out if this can live somewhere other than View, i.e. + // closer to ScrollView. - // Debug method that logs the focus traversal hierarchy to the output. - void PrintFocusHierarchy(); -#endif + // Scrolls the specified region, in this View's coordinate system, to be + // visible. View's implementation passes the call onto the parent View (after + // adjusting the coordinates). It is up to views that only show a portion of + // the child view, such as Viewport, to override appropriately. + virtual void ScrollRectToVisible(const gfx::Rect& rect); // The following methods are used by ScrollView to determine the amount // to scroll relative to the visible bounds of the view. For example, a @@ -986,50 +1019,47 @@ class View : public AcceleratorTarget { virtual int GetLineScrollIncrement(ScrollView* scroll_view, bool is_horizontal, bool is_positive); - // Get the theme provider from the parent widget. - ThemeProvider* GetThemeProvider() const; - protected: - // Returns whether this view can accept focus. - // A view can accept focus if it's enabled, focusable and visible. - // This method is intended for views to use when calculating preferred size. - // The FocusManager and other places use IsFocusableInRootView. - virtual bool IsFocusable() const; + // Size and disposition ------------------------------------------------------ - // Called when the UI theme has changed, overriding allows individual Views to - // do special cleanup and processing (such as dropping resource caches). - // To dispatch a theme changed notification, call - // RootView::NotifyThemeChanged(). - virtual void OnThemeChanged() { } + // Called when the preferred size of a child view changed. This gives the + // parent an opportunity to do a fresh layout if that makes sense. + virtual void ChildPreferredSizeChanged(View* child) {} - // Called when the locale has changed, overriding allows individual Views to - // update locale-dependent strings. - // To dispatch a locale changed notification, call - // RootView::NotifyLocaleChanged(). - virtual void OnLocaleChanged() { } + // Invalidates the layout and calls ChildPreferredSizeChanged on the parent + // if there is one. Be sure to call View::PreferredSizeChanged when + // overriding such that the layout is properly invalidated. + virtual void PreferredSizeChanged(); -#ifndef NDEBUG - // Returns true if the View is currently processing a paint. - virtual bool IsProcessingPaint() const; -#endif + // Sets whether this view wants notification when its visible bounds relative + // to the root view changes. If true, this view is notified any time the + // origin of one its ancestors changes, or the portion of the bounds not + // obscured by ancestors changes. The default is false. + void SetNotifyWhenVisibleBoundsInRootChanges(bool value); + bool GetNotifyWhenVisibleBoundsInRootChanges(); - // Returns the location, in screen coordinates, to show the context menu at - // when the context menu is shown from the keyboard. This implementation - // returns the middle of the visible region of this view. - // - // This method is invoked when the context menu is shown by way of the - // keyboard. - virtual gfx::Point GetKeyboardContextMenuLocation(); + // Notification that this views visible bounds, relative to the RootView + // has changed. The visible bounds corresponds to the region of the + // view not obscured by other ancestors. + virtual void VisibleBoundsInRootChanged() {} - // Called by HitTest to see if this View has a custom hit test mask. If the - // return value is true, GetHitTestMask will be called to obtain the mask. - // Default value is false, in which case the View will hit-test against its - // bounds. - virtual bool HasHitTestMask() const; + // TODO(beng): eliminate in protected. + // Whether this view is enabled. + bool enabled_; - // Called by HitTest to retrieve a mask for hit-testing against. Subclasses - // override to provide custom shaped hit test regions. - virtual void GetHitTestMask(gfx::Path* mask) const; + // Attributes ---------------------------------------------------------------- + + // TODO(beng): Eliminate in protected + // The id of this View. Used to find this View. + int id_; + + // TODO(beng): Eliminate in protected + // The group of this view. Some view subclasses use this id to find other + // views of the same group. For example radio button uses this information + // to find other radio buttons. + int group_; + + // Tree operations ----------------------------------------------------------- // This method is invoked when the tree changes. // @@ -1064,29 +1094,31 @@ class View : public AcceleratorTarget { gfx::NativeView native_view, RootView* root_view); - // Called when the preferred size of a child view changed. This gives the - // parent an opportunity to do a fresh layout if that makes sense. - virtual void ChildPreferredSizeChanged(View* child) {} + // Painting ------------------------------------------------------------------ +#ifndef NDEBUG + // Returns true if the View is currently processing a paint. + virtual bool IsProcessingPaint() const; +#endif - // Invalidates the layout and calls ChildPreferredSizeChanged on the parent - // if there is one. Be sure to call View::PreferredSizeChanged when - // overriding such that the layout is properly invalidated. - virtual void PreferredSizeChanged(); + // Input --------------------------------------------------------------------- - // Views must invoke this when the tooltip text they are to display changes. - void TooltipTextChanged(); + // Called by HitTest to see if this View has a custom hit test mask. If the + // return value is true, GetHitTestMask will be called to obtain the mask. + // Default value is false, in which case the View will hit-test against its + // bounds. + virtual bool HasHitTestMask() const; - // Sets whether this view wants notification when its visible bounds relative - // to the root view changes. If true, this view is notified any time the - // origin of one its ancestors changes, or the portion of the bounds not - // obscured by ancestors changes. The default is false. - void SetNotifyWhenVisibleBoundsInRootChanges(bool value); - bool GetNotifyWhenVisibleBoundsInRootChanges(); + // Called by HitTest to retrieve a mask for hit-testing against. Subclasses + // override to provide custom shaped hit test regions. + virtual void GetHitTestMask(gfx::Path* mask) const; - // Notification that this views visible bounds, relative to the RootView - // has changed. The visible bounds corresponds to the region of the - // view not obscured by other ancestors. - virtual void VisibleBoundsInRootChanged() {} + // Focus --------------------------------------------------------------------- + + // Returns whether this view can accept focus. + // A view can accept focus if it's enabled, focusable and visible. + // This method is intended for views to use when calculating preferred size. + // The FocusManager and other places use IsFocusableInRootView. + virtual bool IsFocusable() const; // Sets the keyboard focus to this View. The correct way to set the focus is // to call RequestFocus() on the view. This method is called when the focus is @@ -1097,6 +1129,44 @@ class View : public AcceleratorTarget { // associated with them (so the root view gets the keyboard messages). virtual void Focus(); + // Whether the view can be focused. + bool focusable_; + + // Whether this view is focusable if the user requires full keyboard access, + // even though it may not be normally focusable. + bool accessibility_focusable_; + + // System events ------------------------------------------------------------- + + // Called when the UI theme has changed, overriding allows individual Views to + // do special cleanup and processing (such as dropping resource caches). + // To dispatch a theme changed notification, call + // RootView::NotifyThemeChanged(). + virtual void OnThemeChanged() { } + + // Called when the locale has changed, overriding allows individual Views to + // update locale-dependent strings. + // To dispatch a locale changed notification, call + // RootView::NotifyLocaleChanged(). + virtual void OnLocaleChanged() { } + + // Tooltips ------------------------------------------------------------------ + + // Views must invoke this when the tooltip text they are to display changes. + void TooltipTextChanged(); + + // Context menus ------------------------------------------------------------- + + // Returns the location, in screen coordinates, to show the context menu at + // when the context menu is shown from the keyboard. This implementation + // returns the middle of the visible region of this view. + // + // This method is invoked when the context menu is shown by way of the + // keyboard. + virtual gfx::Point GetKeyboardContextMenuLocation(); + + // Drag and drop ------------------------------------------------------------- + // These are cover methods that invoke the method of the same name on // the DragController. Subclasses may wish to override rather than install // a DragController. @@ -1118,24 +1188,6 @@ class View : public AcceleratorTarget { static int GetHorizontalDragThreshold(); static int GetVerticalDragThreshold(); - // The id of this View. Used to find this View. - int id_; - - // The group of this view. Some view subclasses use this id to find other - // views of the same group. For example radio button uses this information - // to find other radio buttons. - int group_; - - // Whether this view is enabled. - bool enabled_; - - // Whether the view can be focused. - bool focusable_; - - // Whether this view is focusable if the user requires full keyboard access, - // even though it may not be normally focusable. - bool accessibility_focusable_; - private: friend class RootView; friend class FocusManager; @@ -1160,30 +1212,7 @@ class View : public AcceleratorTarget { gfx::Point start_pt; }; - // Used to propagate theme changed notifications from the root view to all - // views in the hierarchy. - virtual void PropagateThemeChanged(); - - // Used to propagate locale changed notifications from the root view to all - // views in the hierarchy. - virtual void PropagateLocaleChanged(); - - // RootView invokes these. These in turn invoke the appropriate OnMouseXXX - // method. If a drag is detected, DoDrag is invoked. - bool ProcessMousePressed(const MouseEvent& e, DragInfo* drop_info); - bool ProcessMouseDragged(const MouseEvent& e, DragInfo* drop_info); - void ProcessMouseReleased(const MouseEvent& e, bool canceled); - -#if defined(TOUCH_UI) - // RootView will invoke this with incoming TouchEvents. Returns the - // the result of OnTouchEvent. - TouchStatus ProcessTouchEvent(const TouchEvent& e); -#endif - - // Starts a drag and drop operation originating from this view. This invokes - // WriteDragData to write the data and GetDragOperations to determine the - // supported drag operations. When done, OnDragDone is invoked. - void DoDrag(const MouseEvent& e, const gfx::Point& press_pt); + // Tree operations ----------------------------------------------------------- // Removes |view| from the hierarchy tree. If |update_focus_cycle| is true, // the next and previous focusable views of views pointing to this view are @@ -1205,9 +1234,6 @@ class View : public AcceleratorTarget { // Call ViewHierarchyChanged for all children void PropagateAddNotifications(View* parent, View* child); - // Call VisibilityChanged() recursively for all children. - void PropagateVisibilityNotifications(View* from, bool is_visible); - // Propagates NativeViewHierarchyChanged() notification through all the // children. void PropagateNativeViewHierarchyChanged(bool attached, @@ -1221,25 +1247,19 @@ class View : public AcceleratorTarget { View* parent, View* child); + // Actual implementation of PrintFocusHierarchy. + void PrintViewHierarchyImp(int indent); + void PrintFocusHierarchyImp(int indent); + + // Size and disposition ------------------------------------------------------ + + // Call VisibilityChanged() recursively for all children. + void PropagateVisibilityNotifications(View* from, bool is_visible); + // Registers/unregisters accelerators as necessary and calls // VisibilityChanged(). void VisibilityChangedImpl(View* starting_from, bool is_visible); - // This is the actual implementation for ConvertPointToView() - // Attempts a parent -> child conversion and then a - // child -> parent conversion if try_other_direction is true - static void ConvertPointToView(const View* src, - const View* dst, - gfx::Point* point, - bool try_other_direction); - - // Propagates UpdateTooltip() to the TooltipManager for the Widget. - // This must be invoked any time the View hierarchy changes in such a way - // the view under the mouse differs. For example, if the bounds of a View is - // changed, this is invoked. Similarly, as Views are added/removed, this - // is invoked. - void UpdateTooltip(); - // Recursively descends through all descendant views, // registering/unregistering all views that want visible bounds in root // view notification. @@ -1253,13 +1273,31 @@ class View : public AcceleratorTarget { void AddDescendantToNotify(View* view); void RemoveDescendantToNotify(View* view); - // Initialize the previous/next focusable views of the specified view relative - // to the view at the specified index. - void InitFocusSiblings(View* view, int index); + // Coordinate conersion ------------------------------------------------------ - // Actual implementation of PrintFocusHierarchy. - void PrintViewHierarchyImp(int indent); - void PrintFocusHierarchyImp(int indent); + // This is the actual implementation for ConvertPointToView() + // Attempts a parent -> child conversion and then a + // child -> parent conversion if try_other_direction is true + static void ConvertPointToView(const View* src, + const View* dst, + gfx::Point* point, + bool try_other_direction); + + // Input --------------------------------------------------------------------- + + // RootView invokes these. These in turn invoke the appropriate OnMouseXXX + // method. If a drag is detected, DoDrag is invoked. + bool ProcessMousePressed(const MouseEvent& e, DragInfo* drop_info); + bool ProcessMouseDragged(const MouseEvent& e, DragInfo* drop_info); + void ProcessMouseReleased(const MouseEvent& e, bool canceled); + +#if defined(TOUCH_UI) + // RootView will invoke this with incoming TouchEvents. Returns the + // the result of OnTouchEvent. + TouchStatus ProcessTouchEvent(const TouchEvent& e); +#endif + + // Accelerators -------------------------------------------------------------- // Registers this view's keyboard accelerators that are not registered to // FocusManager yet, if possible. @@ -1270,11 +1308,51 @@ class View : public AcceleratorTarget { // so it could be re-registered with other focus manager void UnregisterAccelerators(bool leave_data_intact); - // This View's bounds in the parent coordinate system. - gfx::Rect bounds_; + // Focus --------------------------------------------------------------------- - // Whether the view needs to be laid out. - bool needs_layout_; + // Initialize the previous/next focusable views of the specified view relative + // to the view at the specified index. + void InitFocusSiblings(View* view, int index); + + // System events ------------------------------------------------------------- + + // Used to propagate theme changed notifications from the root view to all + // views in the hierarchy. + virtual void PropagateThemeChanged(); + + // Used to propagate locale changed notifications from the root view to all + // views in the hierarchy. + virtual void PropagateLocaleChanged(); + + // Tooltips ------------------------------------------------------------------ + + // Propagates UpdateTooltip() to the TooltipManager for the Widget. + // This must be invoked any time the View hierarchy changes in such a way + // the view under the mouse differs. For example, if the bounds of a View is + // changed, this is invoked. Similarly, as Views are added/removed, this + // is invoked. + void UpdateTooltip(); + + // Drag and drop ------------------------------------------------------------- + + // Starts a drag and drop operation originating from this view. This invokes + // WriteDragData to write the data and GetDragOperations to determine the + // supported drag operations. When done, OnDragDone is invoked. + void DoDrag(const MouseEvent& e, const gfx::Point& press_pt); + + ////////////////////////////////////////////////////////////////////////////// + + // TODO(beng): move to metrics.h + // The default value for how long to wait (in ms) before showing a menu + // button on hover. This value is used if the OS doesn't supply one. + static const int kShowFolderDropMenuDelay; + + // Creation and lifetime ----------------------------------------------------- + + // Whether this view is owned by its parent. + bool is_parent_owned_; + + // Tree operations ----------------------------------------------------------- // This view's parent View* parent_; @@ -1283,12 +1361,34 @@ class View : public AcceleratorTarget { typedef std::vector<View*> ViewList; ViewList child_views_; + // Size and disposition ------------------------------------------------------ + + // This View's bounds in the parent coordinate system. + gfx::Rect bounds_; + + // Visible state + bool is_visible_; + + // See SetNotifyWhenVisibleBoundsInRootChanges. + bool notify_when_visible_bounds_in_root_changes_; + + // Whether or not RegisterViewForVisibleBoundsNotification on the RootView + // has been invoked. + bool registered_for_visible_bounds_notification_; + + // List of descendants wanting notification when their visible bounds change. + scoped_ptr<ViewList> descendants_to_notify_; + + // Layout -------------------------------------------------------------------- + + // Whether the view needs to be laid out. + bool needs_layout_; + // The View's LayoutManager defines the sizing heuristics applied to child // Views. The default is absolute positioning according to bounds_. scoped_ptr<LayoutManager> layout_manager_; - // Visible state - bool is_visible_; + // Painting ------------------------------------------------------------------ // Background scoped_ptr<Background> background_; @@ -1296,32 +1396,19 @@ class View : public AcceleratorTarget { // Border. scoped_ptr<Border> border_; - // Whether this view is owned by its parent. - bool is_parent_owned_; + // RTL painting -------------------------------------------------------------- - // See SetNotifyWhenVisibleBoundsInRootChanges. - bool notify_when_visible_bounds_in_root_changes_; + // Indicates whether or not the gfx::Canvas object passed to View::Paint() + // is going to be flipped horizontally (using the appropriate transform) on + // right-to-left locales for this View. + bool flip_canvas_on_paint_for_rtl_ui_; - // Whether or not RegisterViewForVisibleBoundsNotification on the RootView - // has been invoked. - bool registered_for_visible_bounds_notification_; + // Accelerators -------------------------------------------------------------- // true if when we were added to hierarchy we were without focus manager // attempt addition when ancestor chain changed. bool accelerator_registration_delayed_; - // List of descendants wanting notification when their visible bounds change. - scoped_ptr<ViewList> descendants_to_notify_; - - // Name for this view, which can be retrieved by accessibility APIs. - string16 accessible_name_; - - // Next view to be focused when the Tab key is pressed. - View* next_focusable_view_; - - // Next view to be focused when the Shift-Tab key combination is pressed. - View* previous_focusable_view_; - // Focus manager accelerators registered on. FocusManager* accelerator_focus_manager_; @@ -1331,24 +1418,32 @@ class View : public AcceleratorTarget { scoped_ptr<std::vector<Accelerator> > accelerators_; size_t registered_accelerator_count_; + // Focus --------------------------------------------------------------------- + + // Next view to be focused when the Tab key is pressed. + View* next_focusable_view_; + + // Next view to be focused when the Shift-Tab key combination is pressed. + View* previous_focusable_view_; + + // Context menus ------------------------------------------------------------- + // The menu controller. ContextMenuController* context_menu_controller_; -#if defined(OS_WIN) - // The accessibility implementation for this View. - scoped_refptr<ViewAccessibility> view_accessibility_; -#endif + // Drag and drop ------------------------------------------------------------- DragController* drag_controller_; - // Indicates whether or not the gfx::Canvas object passed to View::Paint() - // is going to be flipped horizontally (using the appropriate transform) on - // right-to-left locales for this View. - bool flip_canvas_on_paint_for_rtl_ui_; + // Accessibility ------------------------------------------------------------- - // The default value for how long to wait (in ms) before showing a menu - // button on hover. This value is used if the OS doesn't supply one. - static const int kShowFolderDropMenuDelay; + // Name for this view, which can be retrieved by accessibility APIs. + string16 accessible_name_; + +#if defined(OS_WIN) + // The accessibility implementation for this View. + scoped_refptr<ViewAccessibility> view_accessibility_; +#endif DISALLOW_COPY_AND_ASSIGN(View); }; |