diff options
author | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 21:58:19 +0000 |
---|---|---|
committer | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 21:58:19 +0000 |
commit | 01a8de9777621f0f4bc3f270d680d134dd435612 (patch) | |
tree | 8f99c6dcb83c711a3fd3e2389400967f27a3b533 | |
parent | 02e80deede0729617aeb87128b1db3cd14b36d6b (diff) | |
download | chromium_src-01a8de9777621f0f4bc3f270d680d134dd435612.zip chromium_src-01a8de9777621f0f4bc3f270d680d134dd435612.tar.gz chromium_src-01a8de9777621f0f4bc3f270d680d134dd435612.tar.bz2 |
Implement mouse input handling for the close button in the Linux tabstrip.
Review URL: http://codereview.chromium.org/63136
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13382 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/gtk/tabs/tab_gtk.cc | 37 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_gtk.h | 15 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_renderer_gtk.cc | 20 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_renderer_gtk.h | 19 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.cc | 50 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.h | 8 |
6 files changed, 131 insertions, 18 deletions
diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc index 3cd6869..46823fe 100644 --- a/chrome/browser/gtk/tabs/tab_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_gtk.cc @@ -20,7 +20,8 @@ static const SkScalar kTabBottomCurveWidth = 3; TabGtk::TabGtk(TabDelegate* delegate) : TabRendererGtk(), delegate_(delegate), - closing_(false) { + closing_(false), + mouse_pressed_(false) { } TabGtk::~TabGtk() { @@ -33,6 +34,40 @@ bool TabGtk::IsPointInBounds(const gfx::Point& point) { return in_bounds; } +bool TabGtk::OnMotionNotify(const gfx::Point& point) { + CloseButtonState state; + if (close_button_bounds().Contains(point)) { + if (mouse_pressed_) { + state = BS_PUSHED; + } else { + state = BS_HOT; + } + } else { + state = BS_NORMAL; + } + + bool need_redraw = (close_button_state() != state); + set_close_button_state(state); + return need_redraw; +} + +bool TabGtk::OnMousePress() { + if (close_button_state() == BS_HOT) { + mouse_pressed_ = true; + set_close_button_state(BS_PUSHED); + return true; + } + + return false; +} + +void TabGtk::OnMouseRelease() { + mouse_pressed_ = false; + + if (close_button_state() == BS_PUSHED) + delegate_->CloseTab(this); +} + /////////////////////////////////////////////////////////////////////////////// // TabGtk, TabRendererGtk overrides: diff --git a/chrome/browser/gtk/tabs/tab_gtk.h b/chrome/browser/gtk/tabs/tab_gtk.h index 07a853e..b36aaf4 100644 --- a/chrome/browser/gtk/tabs/tab_gtk.h +++ b/chrome/browser/gtk/tabs/tab_gtk.h @@ -74,6 +74,18 @@ class TabGtk : public TabRendererGtk { // TabRendererGtk overrides: virtual bool IsSelected() const; + // Sent by the tabstrip when the mouse moves within this tab. Mouse is at + // |point|. Returns true if the tabstrip needs to be redrawn as a result + // of the motion. + bool OnMotionNotify(const gfx::Point& point); + + // Sent by the tabstrip when the mouse clicks within this tab. Returns true + // if the tabstrip needs to be redrawn as a result of the click. + bool OnMousePress(); + + // Sent by the tabstrip when the mouse click is released. + void OnMouseRelease(); + private: // Creates a clickable region of the tab's visual representation. Used for // hit-testing. Caller is responsible for destroying the region. @@ -86,6 +98,9 @@ class TabGtk : public TabRendererGtk { // True if the tab is being animated closed. bool closing_; + // Set if the mouse is pressed anywhere inside the tab. + bool mouse_pressed_; + DISALLOW_COPY_AND_ASSIGN(TabGtk); }; diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc index 2e22487..34388a5 100644 --- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc @@ -144,7 +144,8 @@ TabRendererGtk::TabRendererGtk() fav_icon_hiding_offset_(0), should_display_crashed_favicon_(false), hovering_(false), - loading_animation_(&loading_animation_data) { + loading_animation_(&loading_animation_data), + close_button_state_(BS_NORMAL) { InitResources(); } @@ -322,10 +323,25 @@ void TabRendererGtk::Paint(ChromeCanvasPaint* canvas) { title_bounds_.y(), title_bounds_.width(), title_bounds_.height()); - canvas->DrawBitmapInt(*close_button_.normal, + SkBitmap close_button = *close_button_.normal; + if (close_button_state_ == BS_HOT) + close_button = *close_button_.hot; + else if (close_button_state_ == BS_PUSHED) + close_button = *close_button_.pushed; + + canvas->DrawBitmapInt(close_button, close_button_bounds_.x(), close_button_bounds_.y()); } +void TabRendererGtk::SetHovering(bool hovering) { + hovering_ = hovering; + + // If the mouse is not hovering over the tab, the close button can't be + // highlighted. + if (!hovering) + close_button_state_ = BS_NORMAL; +} + void TabRendererGtk::Layout() { gfx::Rect local_bounds = bounds_; if (local_bounds.IsEmpty()) diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.h b/chrome/browser/gtk/tabs/tab_renderer_gtk.h index 07c7614..28fd233 100644 --- a/chrome/browser/gtk/tabs/tab_renderer_gtk.h +++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.h @@ -28,6 +28,13 @@ class TabRendererGtk { ANIMATION_LOADING }; + // Possible close button states + enum CloseButtonState { + BS_NORMAL, + BS_HOT, + BS_PUSHED + }; + class LoadingAnimation { public: struct Data { @@ -110,14 +117,21 @@ class TabRendererGtk { void Paint(ChromeCanvasPaint* canvas); // Sets the hovering status of the tab. - void SetHovering(bool hovering) { hovering_ = hovering; } + void SetHovering(bool hovering); protected: const gfx::Rect& title_bounds() const { return title_bounds_; } + const gfx::Rect& close_button_bounds() const { return close_button_bounds_; } + CloseButtonState close_button_state() const { return close_button_state_; } // Returns the title of the Tab. std::wstring GetTitle() const; + // Sets whether the close button should be highlighted or not. + void set_close_button_state(CloseButtonState state) { + close_button_state_ = state; + } + private: // Model data. We store this here so that we don't need to ask the underlying // model, which is tricky since instances of this object can outlive the @@ -221,6 +235,9 @@ class TabRendererGtk { // Set when the mouse is hovering over this tab and the tab is not selected. bool hovering_; + // The state of the close button as it relates to mouse input. + CloseButtonState close_button_state_; + // Contains the loading animation state. LoadingAnimation loading_animation_; diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc index ff4b636..0704de0 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -75,11 +75,14 @@ void TabStripGtk::Init() { g_signal_connect(G_OBJECT(tabstrip_.get()), "motion-notify-event", G_CALLBACK(OnMotionNotify), this); g_signal_connect(G_OBJECT(tabstrip_.get()), "button-press-event", - G_CALLBACK(OnButtonPress), this); + G_CALLBACK(OnMousePress), this); + g_signal_connect(G_OBJECT(tabstrip_.get()), "button-release-event", + G_CALLBACK(OnMouseRelease), this); g_signal_connect(G_OBJECT(tabstrip_.get()), "leave-notify-event", G_CALLBACK(OnLeaveNotify), this); gtk_widget_add_events(tabstrip_.get(), - GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK); + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK |GDK_LEAVE_NOTIFY_MASK); gtk_widget_show_all(tabstrip_.get()); bounds_ = GetInitialWidgetBounds(tabstrip_.get()); @@ -452,7 +455,7 @@ gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, int old_hover_index = tabstrip->hover_index_; tabstrip->hover_index_ = -1; - gfx::Point coord(event->x, event->y); + gfx::Point point(event->x, event->y); // Get a rough estimate for which tab the mouse is over. int index = event->x / (tabstrip->current_unselected_width_ + kTabHOffset); @@ -474,16 +477,16 @@ gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, // finally the tab to the right (tabs stack to the left.) if (tabstrip->model()->selected_index() == index && - tabstrip->GetTabAt(index)->IsPointInBounds(coord)) { + tabstrip->GetTabAt(index)->IsPointInBounds(point)) { tabstrip->hover_index_ = index; } else if (index > 0 && - tabstrip->GetTabAt(index - 1)->IsPointInBounds(coord)) { + tabstrip->GetTabAt(index - 1)->IsPointInBounds(point)) { tabstrip->hover_index_ = index - 1; } else if (tabstrip->model()->selected_index() != index && - tabstrip->GetTabAt(index)->IsPointInBounds(coord)) { + tabstrip->GetTabAt(index)->IsPointInBounds(point)) { tabstrip->hover_index_ = index; } else if (index < tab_count - 1 && - tabstrip->GetTabAt(index + 1)->IsPointInBounds(coord)) { + tabstrip->GetTabAt(index + 1)->IsPointInBounds(point)) { tabstrip->hover_index_ = index + 1; } @@ -498,16 +501,39 @@ gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, gtk_widget_queue_draw(tabstrip->tabstrip_.get()); } + // Forward the mouse movement to the tab. Used to handle close button input. + if (tabstrip->hover_index_ != -1) { + if (tabstrip->GetTabAt(tabstrip->hover_index_)->OnMotionNotify(point)) + gtk_widget_queue_draw(tabstrip->tabstrip_.get()); + } + return TRUE; } // static -gboolean TabStripGtk::OnButtonPress(GtkWidget* widget, GdkEventButton* event, - TabStripGtk* tabstrip) { - if (tabstrip->hover_index_ != -1 && - tabstrip->hover_index_ != tabstrip->model()->selected_index()) { +gboolean TabStripGtk::OnMousePress(GtkWidget* widget, GdkEventButton* event, + TabStripGtk* tabstrip) { + // TODO(jhawkins): Handle middle and right-click. + // TODO(jhawkins): Are there no gdk constants for event->button? + if (tabstrip->hover_index_ == -1 || event->button != 1) + return TRUE; + + if (tabstrip->GetTabAt(tabstrip->hover_index_)->OnMousePress()) + gtk_widget_queue_draw(tabstrip->tabstrip_.get()); + else if (tabstrip->hover_index_ != tabstrip->model()->selected_index()) tabstrip->model()->SelectTabContentsAt(tabstrip->hover_index_, true); - } + + return TRUE; +} + +// static +gboolean TabStripGtk::OnMouseRelease(GtkWidget* widget, GdkEventButton* event, + TabStripGtk* tabstrip) { + if (event->button != 1) + return TRUE; + + if (tabstrip->hover_index_ != -1) + tabstrip->GetTabAt(tabstrip->hover_index_)->OnMouseRelease(); return TRUE; } diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h index 6d8f17f..fbff765 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.h +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h @@ -85,8 +85,12 @@ class TabStripGtk : public TabStripModelObserver, TabStripGtk* tabstrip); // button-press-event handler that handles mouse clicks. - static gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event, - TabStripGtk* tabstrip); + static gboolean OnMousePress(GtkWidget* widget, GdkEventButton* event, + TabStripGtk* tabstrip); + + // button-release-event handler that handles mouse click releases. + static gboolean OnMouseRelease(GtkWidget* widget, GdkEventButton* event, + TabStripGtk* tabstrip); // leave-notify-event handler that signals when the mouse leaves the tabstrip. static gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event, |