summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.cc40
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.h11
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.cc76
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.h11
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_