diff options
-rw-r--r-- | chrome/browser/gtk/tabs/tab_renderer_gtk.cc | 40 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_renderer_gtk.h | 11 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.cc | 76 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.h | 11 |
4 files changed, 134 insertions, 4 deletions
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc index 7331c14..b6e9464 100644 --- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc @@ -10,6 +10,7 @@ #include "chrome/common/resource_bundle.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" +#include "skia/ext/image_operations.h" namespace { @@ -29,6 +30,9 @@ const int kUnselectedTitleColor = SkColorSetRGB(64, 64, 64); const int kCloseButtonVertFuzz = 0; const int kCloseButtonHorzFuzz = 5; +// How opaque to make the hover state (out of 1). +const double kHoverOpacity = 0.33; + // TODO(jhawkins): Move this code into ChromeFont and allow pulling out a // GdkFont*. GdkFont* load_default_font() { @@ -70,7 +74,8 @@ TabRendererGtk::TabRendererGtk() showing_download_icon_(false), showing_close_button_(false), fav_icon_hiding_offset_(0), - should_display_crashed_favicon_(false) { + should_display_crashed_favicon_(false), + hovering_(false) { InitResources(); } @@ -180,6 +185,11 @@ void TabRendererGtk::SetBounds(const gfx::Rect& bounds) { Layout(); } +bool TabRendererGtk::IsPointInBounds(const gfx::Point& coord) { + // TODO(jhawkins): Use a GdkRegion that better maps to the shape of the tab. + return bounds_.Contains(coord); +} + //////////////////////////////////////////////////////////////////////////////// // TabRendererGtk, protected: @@ -315,7 +325,13 @@ void TabRendererGtk::PaintTabBackground(ChromeCanvasPaint* canvas) { // the active representation for the dragged tab. PaintActiveTabBackground(canvas); } else { - PaintInactiveTabBackground(canvas); + // Draw our hover state. + // TODO(jhawkins): Hover animations. + if (hovering_) { + PaintHoverTabBackground(canvas, kHoverOpacity); + } else { + PaintInactiveTabBackground(canvas); + } } } @@ -333,6 +349,26 @@ void TabRendererGtk::PaintInactiveTabBackground(ChromeCanvasPaint* canvas) { bounds_.y()); } +void TabRendererGtk::PaintHoverTabBackground(ChromeCanvasPaint* canvas, + double opacity) { + bool is_otr = data_.off_the_record; + const TabImage& image = is_otr ? tab_inactive_otr_ : tab_inactive_; + + SkBitmap left = skia::ImageOperations::CreateBlendedBitmap( + *image.image_l, *tab_hover_.image_l, opacity); + SkBitmap center = skia::ImageOperations::CreateBlendedBitmap( + *image.image_c, *tab_hover_.image_c, opacity); + SkBitmap right = skia::ImageOperations::CreateBlendedBitmap( + *image.image_r, *tab_hover_.image_r, opacity); + + canvas->DrawBitmapInt(left, bounds_.x(), bounds_.y()); + canvas->TileImageInt(center, bounds_.x() + tab_active_.l_width, bounds_.y(), + bounds_.width() - tab_active_.l_width - tab_active_.r_width, + bounds_.height()); + canvas->DrawBitmapInt(right, + bounds_.x() + bounds_.width() - tab_active_.r_width, bounds_.y()); +} + void TabRendererGtk::PaintActiveTabBackground(ChromeCanvasPaint* canvas) { canvas->DrawBitmapInt(*tab_active_.image_l, bounds_.x(), bounds_.y()); canvas->TileImageInt(*tab_active_.image_c, diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.h b/chrome/browser/gtk/tabs/tab_renderer_gtk.h index 6a187d8..27dd00b 100644 --- a/chrome/browser/gtk/tabs/tab_renderer_gtk.h +++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.h @@ -59,6 +59,12 @@ class TabRendererGtk { // Paints the tab into |canvas|. void Paint(ChromeCanvasPaint* canvas); + // Checks whether |coord| is inside the bounds of the tab. + bool IsPointInBounds(const gfx::Point& coord); + + // Sets the hovering status of the tab. + void SetHovering(bool hovering) { hovering_ = hovering; } + protected: const gfx::Rect& title_bounds() const { return title_bounds_; } @@ -73,10 +79,10 @@ class TabRendererGtk { static int GetContentHeight(); // Paint various portions of the Tab - // TODO(jhawkins): Paint hover tab. void PaintTabBackground(ChromeCanvasPaint* canvas); void PaintInactiveTabBackground(ChromeCanvasPaint* canvas); void PaintActiveTabBackground(ChromeCanvasPaint* canvas); + void PaintHoverTabBackground(ChromeCanvasPaint* canvas, double opacity); void PaintLoadingAnimation(ChromeCanvasPaint* canvas); // Returns the number of favicon-size elements that can fit in the tab's @@ -163,6 +169,9 @@ class TabRendererGtk { // The bounds of this Tab. gfx::Rect bounds_; + // Set when the mouse is hovering over this tab and the tab is not selected. + bool hovering_; + DISALLOW_COPY_AND_ASSIGN(TabRendererGtk); }; diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc index e854d10..456ac81 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -5,6 +5,7 @@ #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" #include "base/gfx/gtk_util.h" +#include "base/gfx/point.h" #include "chrome/browser/browser.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/gfx/chrome_canvas.h" @@ -46,7 +47,8 @@ TabStripGtk::TabStripGtk(TabStripModel* model) current_selected_width_(TabGtk::GetStandardSize().width()), available_width_for_tabs_(-1), resize_layout_scheduled_(false), - model_(model) { + model_(model), + hover_index_(-1) { } TabStripGtk::~TabStripGtk() { @@ -70,6 +72,12 @@ void TabStripGtk::Init() { G_CALLBACK(OnExpose), this); g_signal_connect(G_OBJECT(tabstrip_.get()), "configure-event", G_CALLBACK(OnConfigure), this); + 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); + gtk_widget_add_events(tabstrip_.get(), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK); gtk_widget_show_all(tabstrip_.get()); bounds_ = GetInitialWidgetBounds(tabstrip_.get()); @@ -413,3 +421,69 @@ gboolean TabStripGtk::OnConfigure(GtkWidget* widget, GdkEventConfigure* event, tabstrip->Layout(); return TRUE; } + +// static +gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, + TabStripGtk* tabstrip) { + int old_hover_index = tabstrip->hover_index_; + tabstrip->hover_index_ = -1; + + gfx::Point coord(event->x, event->y); + // Get a rough estimate for which tab the mouse is over. + int index = std::floor( + event->x / (tabstrip->current_unselected_width_ + kTabHOffset)); + + if (index >= tabstrip->model_->count()) { + if (old_hover_index != -1) { + tabstrip->GetTabAt(old_hover_index)->SetHovering(false); + gtk_widget_queue_draw(tabstrip->tabstrip_.get()); + } + + return TRUE; + } + + // Tab hovering calcuation. + // Using the rough estimate tab index, we check the tab bounds in a smart + // order to reduce the number of tabs we need to check. If the tab at the + // estimated index is selected, check it first as it covers both tabs below + // it. Otherwise, check the tab to the left, then the estimated tab, and + // finally the tab to the right (tabs stack to the left.) + + if (tabstrip->model()->selected_index() == index && + tabstrip->GetTabAt(index)->IsPointInBounds(coord)) { + tabstrip->hover_index_ = index; + } else if (index > 0 && + tabstrip->GetTabAt(index - 1)->IsPointInBounds(coord)) { + tabstrip->hover_index_ = index - 1; + } else if (tabstrip->model()->selected_index() != index && + tabstrip->GetTabAt(index)->IsPointInBounds(coord)) { + tabstrip->hover_index_ = index; + } else if (index < tabstrip->model_->count() - 1 && + tabstrip->GetTabAt(index + 1)->IsPointInBounds(coord)) { + tabstrip->hover_index_ = index + 1; + } + + // Nothing to do if the indexes are the same. + if (tabstrip->hover_index_ != old_hover_index) { + if (tabstrip->hover_index_ != -1) + tabstrip->GetTabAt(tabstrip->hover_index_)->SetHovering(true); + + if (old_hover_index != -1) + tabstrip->GetTabAt(old_hover_index)->SetHovering(false); + + 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()) { + tabstrip->model()->SelectTabContentsAt(tabstrip->hover_index_, true); + } + + return TRUE; +} diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h index 2508300..b79aa325 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.h +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h @@ -70,6 +70,14 @@ class TabStripGtk : public TabStripModelObserver, static gboolean OnConfigure(GtkWidget* widget, GdkEventConfigure* event, TabStripGtk* tabstrip); + // motion-notify-event handler that handles mouse movement in the tabstrip. + static gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, + TabStripGtk* tabstrip); + + // button-press-event handler that handles mouse clicks. + static gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event, + TabStripGtk* tabstrip); + // Gets the number of Tabs in the collection. int GetTabCount() const; @@ -141,6 +149,9 @@ class TabStripGtk : public TabStripModelObserver, // Our model. TabStripModel* model_; + + // The index of the tab the mouse is currently over. -1 if not over a tab. + int hover_index_; }; #endif // CHROME_BROWSER_GTK_TAB_STRIP_GTK_H_ |