diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-15 15:36:03 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-15 15:36:03 +0000 |
commit | 3da0bfd1d9974b55d3358aad5954836e9986ef4b (patch) | |
tree | fbe33a78ca5f6aba01b5544516c66c17953d6552 | |
parent | a20720983ddc7796ba3b93b3e57be2e5ba7f31a5 (diff) | |
download | chromium_src-3da0bfd1d9974b55d3358aad5954836e9986ef4b.zip chromium_src-3da0bfd1d9974b55d3358aad5954836e9986ef4b.tar.gz chromium_src-3da0bfd1d9974b55d3358aad5954836e9986ef4b.tar.bz2 |
Changes the tab close button to a dot, unless you're near the button
or the tab is selected.
I'm not to keen on the mouse near names, if you have better ideas
please say so.
BUG=45743
TEST=none
Review URL: http://codereview.chromium.org/2796006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49795 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/views/tabs/base_tab.cc | 98 | ||||
-rw-r--r-- | chrome/browser/views/tabs/base_tab.h | 14 | ||||
-rw-r--r-- | chrome/browser/views/tabs/side_tab.cc | 8 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab.cc | 26 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_strip.cc | 9 | ||||
-rw-r--r-- | views/controls/button/image_button.h | 19 | ||||
-rw-r--r-- | views/event.h | 6 | ||||
-rw-r--r-- | views/view.cc | 33 | ||||
-rw-r--r-- | views/view.h | 30 | ||||
-rw-r--r-- | views/widget/root_view.cc | 71 | ||||
-rw-r--r-- | views/widget/root_view.h | 24 |
11 files changed, 289 insertions, 49 deletions
diff --git a/chrome/browser/views/tabs/base_tab.cc b/chrome/browser/views/tabs/base_tab.cc index f128abc..04124ed 100644 --- a/chrome/browser/views/tabs/base_tab.cc +++ b/chrome/browser/views/tabs/base_tab.cc @@ -20,6 +20,7 @@ #include "gfx/canvas.h" #include "gfx/favicon_size.h" #include "gfx/font.h" +#include "gfx/skbitmap_operations.h" #include "grit/app_resources.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" @@ -48,20 +49,36 @@ static SkBitmap* close_button_p = NULL; static SkBitmap* crashed_fav_icon = NULL; -namespace { - //////////////////////////////////////////////////////////////////////////////// // TabCloseButton // // This is a Button subclass that causes middle clicks to be forwarded to the // parent View by explicitly not handling them in OnMousePressed. -class TabCloseButton : public views::ImageButton { +class BaseTab::TabCloseButton : public views::ImageButton { public: - explicit TabCloseButton(views::ButtonListener* listener) - : views::ImageButton(listener) { + TabCloseButton(BaseTab* tab, bool show_mini_dot) + : views::ImageButton(tab), + tab_(tab), + is_mouse_near_(!show_mini_dot), + color_(0) { } virtual ~TabCloseButton() {} + // Sets the color used to derive the background color. + void SetColor(SkColor color) { + if (color_ == color) + return; + + color_ = color; + // This is invoked from Paint, so we don't need to schedule a paint. + UpdateBackgroundImage(false); + } + + // Invoked when the selected state changes. + void SelectedStateChanged() { + UpdateBackgroundImage(true); + } + virtual bool OnMousePressed(const views::MouseEvent& event) { bool handled = ImageButton::OnMousePressed(event); // Explicitly mark midle-mouse clicks as non-handled to ensure the tab @@ -82,12 +99,63 @@ class TabCloseButton : public views::ImageButton { GetParent()->OnMouseExited(event); } + virtual void OnMouseNear(const views::MouseEvent& event) { + is_mouse_near_ = true; + UpdateBackgroundImage(true); + } + + virtual void OnMouseExitedNear(const views::MouseEvent& event) { + is_mouse_near_ = false; + UpdateBackgroundImage(true); + } + private: + // Returns the image to use for the background. + static const SkBitmap& GetBackgroundImage(SkColor color, bool is_mouse_near) { + // All tabs share the same color, so we cache the bitmaps. + static SkColor cached_color = 0; + static SkBitmap* near_image = NULL; + static SkBitmap* far_image = NULL; + if (!near_image || cached_color != color) { + cached_color = color; + if (!near_image) { + near_image = new SkBitmap(); + far_image = new SkBitmap(); + } + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + *near_image = SkBitmapOperations::CreateButtonBackground( + color, + *rb.GetBitmapNamed(IDR_TAB_CLOSE), + *rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK)); + *far_image = SkBitmapOperations::CreateButtonBackground( + color, + *rb.GetBitmapNamed(IDR_TAB_CLOSE), + *rb.GetBitmapNamed(IDR_TAB_CLOSE_DOT_MASK)); + } + return is_mouse_near ? *near_image : *far_image; + } + + // Should we use the near image? + bool use_near_image() const { return is_mouse_near_ || tab_->IsSelected(); } + + // Resets the background image. + void UpdateBackgroundImage(bool paint) { + set_background_image(GetBackgroundImage(color_, use_near_image())); + if (paint) + SchedulePaint(); + } + + BaseTab* tab_; + + // Is the mouse near the close button? + bool is_mouse_near_; + + // Color used to derive the background image from. + SkColor color_; + DISALLOW_COPY_AND_ASSIGN(TabCloseButton); }; -} // namespace - // static int BaseTab::close_button_width_ = 0; // static @@ -139,7 +207,7 @@ class BaseTab::FavIconCrashAnimation : public LinearAnimation, DISALLOW_COPY_AND_ASSIGN(FavIconCrashAnimation); }; -BaseTab::BaseTab(TabController* controller) +BaseTab::BaseTab(TabController* controller, bool show_mini_dot) : controller_(controller), closing_(false), dragging_(false), @@ -151,7 +219,7 @@ BaseTab::BaseTab(TabController* controller) BaseTab::InitResources(); // Add the Close Button. - TabCloseButton* close_button = new TabCloseButton(this); + TabCloseButton* close_button = new TabCloseButton(this, show_mini_dot); close_button_ = close_button; close_button->SetImage(views::CustomButton::BS_NORMAL, close_button_n); close_button->SetImage(views::CustomButton::BS_HOT, close_button_h); @@ -228,6 +296,10 @@ void BaseTab::StopPulse() { pulse_animation_.reset(NULL); } +void BaseTab::SelectedChanged() { + close_button_->SelectedStateChanged(); +} + bool BaseTab::IsSelected() const { return controller() ? controller()->IsTabSelected(this) : true; } @@ -334,6 +406,14 @@ void BaseTab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, SchedulePaint(); } +views::ImageButton* BaseTab::close_button() const { + return close_button_; +} + +void BaseTab::SetCloseButtonColor(SkColor color) { + close_button_->SetColor(color); +} + void BaseTab::PaintIcon(gfx::Canvas* canvas, int x, int y) { if (base::i18n::IsRTL()) { if (!data().favicon.isNull()) diff --git a/chrome/browser/views/tabs/base_tab.h b/chrome/browser/views/tabs/base_tab.h index e2ac34a..c0c9bde 100644 --- a/chrome/browser/views/tabs/base_tab.h +++ b/chrome/browser/views/tabs/base_tab.h @@ -32,7 +32,7 @@ class BaseTab : public AnimationDelegate, public views::ContextMenuController, public views::View { public: - explicit BaseTab(TabController* controller); + BaseTab(TabController* controller, bool show_mini_dot); ~BaseTab(); // Sets the data this tabs displays. Invokes DataChanged for subclasses to @@ -71,6 +71,10 @@ class BaseTab : public AnimationDelegate, theme_provider_ = provider; } + // Invoked when the selected state changes. Resets the image of the close + // button. + void SelectedChanged(); + // Returns true if the tab is selected. virtual bool IsSelected() const; @@ -104,7 +108,10 @@ class BaseTab : public AnimationDelegate, return hover_animation_.get(); } - views::ImageButton* close_button() const { return close_button_; } + views::ImageButton* close_button() const; + + // Sets the color used to derive the close button images. + void SetCloseButtonColor(SkColor color); // Paints the icon at the specified x-coordinate. void PaintIcon(gfx::Canvas* canvas, int x, int y); @@ -143,6 +150,7 @@ class BaseTab : public AnimationDelegate, private: // The animation object used to swap the favicon with the sad tab icon. class FavIconCrashAnimation; + class TabCloseButton; // Set the temporary offset for the favicon. This is used during the crash // animation. @@ -186,7 +194,7 @@ class BaseTab : public AnimationDelegate, scoped_refptr<AnimationContainer> animation_container_; - views::ImageButton* close_button_; + TabCloseButton* close_button_; // The current index of the loading animation. int loading_animation_frame_; diff --git a/chrome/browser/views/tabs/side_tab.cc b/chrome/browser/views/tabs/side_tab.cc index bad2b4e..c2448d2 100644 --- a/chrome/browser/views/tabs/side_tab.cc +++ b/chrome/browser/views/tabs/side_tab.cc @@ -13,7 +13,6 @@ #include "gfx/path.h" #include "gfx/skia_util.h" #include "grit/app_resources.h" -#include "grit/theme_resources.h" #include "views/controls/button/image_button.h" namespace { @@ -38,11 +37,8 @@ const int kPhantomTabIconAlpha = 100; // SideTab, public: SideTab::SideTab(TabController* controller) - : BaseTab(controller) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - close_button()->SetBackground(kTextColor, - rb.GetBitmapNamed(IDR_TAB_CLOSE), - rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK)); + : BaseTab(controller, false) { + SetCloseButtonColor(kTextColor); } SideTab::~SideTab() { diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc index ec34e42..db4fe0c 100644 --- a/chrome/browser/views/tabs/tab.cc +++ b/chrome/browser/views/tabs/tab.cc @@ -23,6 +23,7 @@ #include "grit/theme_resources.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "views/controls/button/image_button.h" +#include "views/widget/root_view.h" #include "views/widget/tooltip_manager.h" #include "views/widget/widget.h" #include "views/window/non_client_view.h" @@ -105,7 +106,7 @@ const char Tab::kViewClassName[] = "browser/tabs/Tab"; // Tab, public: Tab::Tab(TabController* controller) - : BaseTab(controller), + : BaseTab(controller, true), showing_icon_(false), showing_close_button_(false), close_button_color_(NULL), @@ -232,13 +233,7 @@ void Tab::Paint(gfx::Canvas* canvas) { PaintIcon(canvas); // If the close button color has changed, generate a new one. - if (!close_button_color_ || title_color != close_button_color_) { - close_button_color_ = title_color; - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - close_button()->SetBackground(close_button_color_, - rb.GetBitmapNamed(IDR_TAB_CLOSE), - rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK)); - } + SetCloseButtonColor(title_color); } void Tab::Layout() { @@ -286,6 +281,7 @@ void Tab::Layout() { // Size the Close button. showing_close_button_ = ShouldShowCloseBox(); + gfx::Insets near_insets; if (showing_close_button_) { int close_button_top = kTopPadding + kCloseButtonVertFuzz + @@ -295,10 +291,24 @@ void Tab::Layout() { close_button_top, close_button_width(), close_button_height()); close_button()->SetVisible(true); + int avail_width = width() - close_button()->bounds().right(); + if (avail_width > 0) { + View* root = GetRootView(); + if (root) { // Root is null when dragging. + // Enable mouse near events for the region from the top of the browser + // to the bottom of the tab. + gfx::Point loc; + ConvertPointToView(close_button(), GetRootView(), &loc); + near_insets.Set(loc.y(), close_button()->x(), + height() - close_button()->bounds().bottom(), + avail_width); + } + } } else { close_button()->SetBounds(0, 0, 0, 0); close_button()->SetVisible(false); } + close_button()->RegisterForMouseNearEvents(near_insets); int title_left = favicon_bounds_.right() + kFavIconTitleSpacing; int title_top = kTopPadding + (content_height - font_height()) / 2; diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index 77fb8eb..a1631fd 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -292,8 +292,13 @@ void TabStrip::SelectTabAt(int old_model_index, int new_model_index) { } if (old_model_index >= 0) { - GetTabAtTabDataIndex(ModelIndexToTabIndex(old_model_index))-> - StopMiniTabTitleAnimation(); + Tab* tab = GetTabAtTabDataIndex(ModelIndexToTabIndex(old_model_index)); + tab->StopMiniTabTitleAnimation(); + tab->SelectedChanged(); + } + if (new_model_index >= 0) { + GetTabAtTabDataIndex( + ModelIndexToTabIndex(new_model_index))->SelectedChanged(); } } diff --git a/views/controls/button/image_button.h b/views/controls/button/image_button.h index f65118a..c99c77f 100644 --- a/views/controls/button/image_button.h +++ b/views/controls/button/image_button.h @@ -18,6 +18,14 @@ namespace views { class ImageButton : public CustomButton { public: + enum HorizontalAlignment { ALIGN_LEFT = 0, + ALIGN_CENTER, + ALIGN_RIGHT, }; + + enum VerticalAlignment { ALIGN_TOP = 0, + ALIGN_MIDDLE, + ALIGN_BOTTOM }; + explicit ImageButton(ButtonListener* listener); virtual ~ImageButton(); @@ -29,13 +37,10 @@ class ImageButton : public CustomButton { const SkBitmap* image, const SkBitmap* mask); - enum HorizontalAlignment { ALIGN_LEFT = 0, - ALIGN_CENTER, - ALIGN_RIGHT, }; - - enum VerticalAlignment { ALIGN_TOP = 0, - ALIGN_MIDDLE, - ALIGN_BOTTOM }; + // Explicitly sets the background image. + void set_background_image(const SkBitmap& background) { + background_image_ = background; + } // Sets how the image is laid out within the button's bounds. void SetImageAlignment(HorizontalAlignment h_align, diff --git a/views/event.h b/views/event.h index 6f96a71..91c0a53 100644 --- a/views/event.h +++ b/views/event.h @@ -41,6 +41,8 @@ class Event { ET_MOUSE_MOVED, ET_MOUSE_ENTERED, ET_MOUSE_EXITED, + ET_MOUSE_NEAR, + ET_MOUSE_EXITED_NEAR, ET_KEY_PRESSED, ET_KEY_RELEASED, ET_MOUSEWHEEL, @@ -100,7 +102,9 @@ class Event { type_ == ET_MOUSE_MOVED || type_ == ET_MOUSE_ENTERED || type_ == ET_MOUSE_EXITED || - type_ == ET_MOUSEWHEEL; + type_ == ET_MOUSEWHEEL || + type_ == ET_MOUSE_NEAR || + type_ == ET_MOUSE_EXITED_NEAR; } #if defined(OS_WIN) diff --git a/views/view.cc b/views/view.cc index 012240a..988e76b 100644 --- a/views/view.cc +++ b/views/view.cc @@ -132,6 +132,21 @@ void View::SetBounds(const gfx::Rect& bounds) { } } +void View::RegisterForMouseNearEvents(const gfx::Insets& insets) { + RootView* root = GetRootView(); + if (insets.empty()) { + near_insets_.reset(NULL); + if (root) + root->UnregisterViewForNearNotification(this); + } else { + near_insets_.reset( + new gfx::Insets(insets.top(), insets.left(), insets.bottom(), + insets.right())); + if (root) + root->RegisterViewForNearNotification(this); + } +} + gfx::Rect View::GetLocalBounds(bool include_border) const { if (include_border || !border_.get()) return gfx::Rect(0, 0, width(), height()); @@ -537,7 +552,7 @@ void View::AddChildView(int index, View* v) { UpdateTooltip(); RootView* root = GetRootView(); if (root) - RegisterChildrenForVisibleBoundsNotification(root, v); + RegisterChildrenForRootNotifications(root, v); if (layout_manager_.get()) layout_manager_->ViewAdded(this, v); @@ -609,7 +624,7 @@ void View::DoRemoveChildView(View* a_view, RootView* root = GetRootView(); if (root) - UnregisterChildrenForVisibleBoundsNotification(root, a_view); + UnregisterChildrenForRootNotifications(root, a_view); a_view->PropagateRemoveNotifications(this); a_view->SetParent(NULL); @@ -1440,24 +1455,26 @@ ThemeProvider* View::GetThemeProvider() const { } // static -void View::RegisterChildrenForVisibleBoundsNotification( - RootView* root, View* view) { +void View::RegisterChildrenForRootNotifications(RootView* root, View* view) { DCHECK(root && view); if (view->GetNotifyWhenVisibleBoundsInRootChanges()) root->RegisterViewForVisibleBoundsNotification(view); + if (view->near_insets_.get()) + root->RegisterViewForNearNotification(view); for (int i = 0; i < view->GetChildViewCount(); ++i) - RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i)); + RegisterChildrenForRootNotifications(root, view->GetChildViewAt(i)); } // static -void View::UnregisterChildrenForVisibleBoundsNotification( +void View::UnregisterChildrenForRootNotifications( RootView* root, View* view) { DCHECK(root && view); if (view->GetNotifyWhenVisibleBoundsInRootChanges()) root->UnregisterViewForVisibleBoundsNotification(view); + if (view->near_insets_.get()) + root->UnregisterViewForNearNotification(view); for (int i = 0; i < view->GetChildViewCount(); ++i) - UnregisterChildrenForVisibleBoundsNotification(root, - view->GetChildViewAt(i)); + UnregisterChildrenForRootNotifications(root, view->GetChildViewAt(i)); } void View::AddDescendantToNotify(View* view) { diff --git a/views/view.h b/views/view.h index c0f6f07..a9012a5 100644 --- a/views/view.h +++ b/views/view.h @@ -178,6 +178,11 @@ class View : public AcceleratorTarget { void SetX(int x) { SetBounds(x, y(), width(), height()); } void SetY(int y) { SetBounds(x(), y, width(), height()); } + // Registers this view for mouse near events (OnMouseNear and + // OnMouseExitedNear). Mouse near events are sent for the extended rectangle + // defined by the bounds of this view + |insets|. + void RegisterForMouseNearEvents(const gfx::Insets& insets); + // Returns the left coordinate of the View, relative to the parent View, // which is the value of bounds_.x(). // @@ -686,6 +691,18 @@ class View : public AcceleratorTarget { // Default implementation does nothing. Override as needed. virtual void OnMouseExited(const MouseEvent& event); + // Sent when the mouse enters the rectangle defined by this views bounds and + // the insets passed to RegisterForMouseNearEvents. This is only sent for + // views that have explicitly registered for near notification + // (RegisterForMouseNearEvents). + virtual void OnMouseNear(const MouseEvent& event) {} + + // Sent when the mouse exits the rectangle defined by this views bounds and + // the insets passed to RegisterForMouseNearEvents. This is only sent for + // views that have explicitly registered for near notification + // (RegisterForMouseNearEvents). + virtual void OnMouseExitedNear(const MouseEvent& event) {} + // Set the MouseHandler for a drag session. // // A drag session is a stream of mouse events starting @@ -1176,11 +1193,11 @@ class View : public AcceleratorTarget { // Recursively descends through all descendant views, // registering/unregistering all views that want visible bounds in root - // view notification. - static void RegisterChildrenForVisibleBoundsNotification(RootView* root, - View* view); - static void UnregisterChildrenForVisibleBoundsNotification(RootView* root, - View* view); + // view notification and/or mouse near events. + static void RegisterChildrenForRootNotifications(RootView* root, View* view); + static void UnregisterChildrenForRootNotifications(RootView* root, + View* view); + // Adds/removes view to the list of descendants that are notified any time // this views location and possibly size are changed. @@ -1280,6 +1297,9 @@ class View : public AcceleratorTarget { // right-to-left locales for this View. bool flip_canvas_on_paint_for_rtl_ui_; + // Insets passed to RegisterForMouseNearEvents. + scoped_ptr<gfx::Insets> near_insets_; + // 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; diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc index 3ea101c..2a6798c 100644 --- a/views/widget/root_view.cc +++ b/views/widget/root_view.cc @@ -489,6 +489,33 @@ void RootView::OnMouseMoved(const MouseEvent& e) { mouse_move_handler_->OnMouseExited(exited_event); SetActiveCursor(NULL); } + + if (registered_near_views_.empty()) + return; + + std::set<View*> near_views; + GetViewsRegisteredForNearNotification(e, &near_views); + + MouseEvent exited_near_event(Event::ET_MOUSE_EXITED_NEAR, 0, 0, 0); + for (std::set<View*>::const_iterator i = near_views_.begin(); + i != near_views_.end(); ++i) { + if (near_views.find(*i) == near_views.end()) + (*i)->OnMouseExitedNear(exited_near_event); + } + + for (std::set<View*>::const_iterator i = near_views.begin(); + i != near_views.end(); ++i) { + if (near_views_.find(*i) == near_views_.end()) { + MouseEvent entered_event(Event::ET_MOUSE_ENTERED, + this, + *i, + e.location(), + 0); + (*i)->OnMouseNear(entered_event); + } + } + + near_views_.swap(near_views); } void RootView::ProcessOnMouseExited() { @@ -497,6 +524,8 @@ void RootView::ProcessOnMouseExited() { mouse_move_handler_->OnMouseExited(exited_event); mouse_move_handler_ = NULL; } + + SendMouseExitedNear(); } void RootView::SetMouseHandler(View *new_mh) { @@ -880,6 +909,14 @@ void RootView::UnregisterViewForVisibleBoundsNotification(View* view) { } } +void RootView::RegisterViewForNearNotification(View* view) { + registered_near_views_.insert(view); +} + +void RootView::UnregisterViewForNearNotification(View* view) { + registered_near_views_.erase(view); +} + void RootView::SetMouseLocationAndFlags(const MouseEvent& e) { last_mouse_event_flags_ = e.GetFlags(); last_mouse_event_x_ = e.x(); @@ -936,4 +973,38 @@ void RootView::SetActiveCursor(gfx::NativeCursor cursor) { #endif } +void RootView::GetViewsRegisteredForNearNotification( + const MouseEvent& e, + std::set<View*>* near_views) { + const gfx::Point& location = e.location(); + for (std::set<View*>::const_iterator i = registered_near_views_.begin(); + i != registered_near_views_.end(); ++i) { + View* view = *i; + DCHECK(view->near_insets_.get()); + const gfx::Insets& insets = *view->near_insets_; + gfx::Point view_loc(view->x() - insets.left(), + view->y() - insets.top()); + View::ConvertPointToView(view->GetParent(), this, &view_loc); + if (location.x() >= view_loc.x() && + location.y() >= view_loc.y() && + location.x() < view_loc.x() + (view->width() + insets.width()) && + location.y() < view_loc.y() + (view->height() + insets.height())) { + near_views->insert(view); + } + } +} + +void RootView::SendMouseExitedNear() { + if (near_views_.empty()) + return; + + MouseEvent exited_near_event(Event::ET_MOUSE_EXITED_NEAR, 0, 0, 0); + for (std::set<View*>::const_iterator i = near_views_.begin(); + i != near_views_.end(); ++i) { + (*i)->OnMouseExitedNear(exited_near_event); + } + + near_views_.clear(); +} + } // namespace views diff --git a/views/widget/root_view.h b/views/widget/root_view.h index 05887e1..ba1d5d22 100644 --- a/views/widget/root_view.h +++ b/views/widget/root_view.h @@ -5,6 +5,7 @@ #ifndef VIEWS_WIDGET_ROOT_VIEW_H_ #define VIEWS_WIDGET_ROOT_VIEW_H_ +#include <set> #include <string> #include "base/ref_counted.h" @@ -217,6 +218,10 @@ class RootView : public View, void RegisterViewForVisibleBoundsNotification(View* view); void UnregisterViewForVisibleBoundsNotification(View* view); + // Registers/unregisters the View for mouse near events. + void RegisterViewForNearNotification(View* view); + void UnregisterViewForNearNotification(View* view); + // Returns the next focusable view or view containing a FocusTraversable (NULL // if none was found), starting at the starting_view. // check_starting_view, can_go_up and can_go_down controls the traversal of @@ -258,6 +263,15 @@ class RootView : public View, // Sets the current cursor, or resets it to the last one if NULL is provided. void SetActiveCursor(gfx::NativeCursor cursor); + // Returns in |near_views| the set of views registered for mouse near events + // that overlap with the location of the specified event. + void GetViewsRegisteredForNearNotification(const MouseEvent& e, + std::set<View*>* near_views); + + // Sends OnMouseExitedNear to the set of views the mouse is near and empties + // the set. + void SendMouseExitedNear(); + // The view currently handing down - drag - up View* mouse_pressed_handler_; @@ -330,6 +344,16 @@ class RootView : public View, bool is_processing_paint_; #endif + // Set of views registered for mouse near events. + // NOTE: because views registered for near mouse events can overlap other + // views and extend outside the bounds of themselves and ancestors we store + // the registered views here and treat them separately. This is generally ok + // as there are a small set of views registered for near notification. + std::set<View*> registered_near_views_; + + // Set of views the mouse is currently near. + std::set<View*> near_views_; + DISALLOW_COPY_AND_ASSIGN(RootView); }; |