summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 01:05:13 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 01:05:13 +0000
commite4eed283dccc643388bc7f211ff008611d5ce997 (patch)
treecd1ac97033792276dadb739b5066a8f7670a1145 /chrome/browser
parent1e744f200179976645ef75859569eaa475b820be (diff)
downloadchromium_src-e4eed283dccc643388bc7f211ff008611d5ce997.zip
chromium_src-e4eed283dccc643388bc7f211ff008611d5ce997.tar.gz
chromium_src-e4eed283dccc643388bc7f211ff008611d5ce997.tar.bz2
Reimplement the bookmark bar to use a GtkToolbar.
Add all bookmark buttons to a GtkToolbar. All bookmark buttons are draggable, though we don't accept drops yet since I still need to figure out how to communicate with the model. Review URL: http://codereview.chromium.org/63099 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13322 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.cc267
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.h56
2 files changed, 294 insertions, 29 deletions
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc
index 2342416..d1f49b7 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk.cc
@@ -7,13 +7,16 @@
#include "base/gfx/gtk_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/custom_button.h"
+#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
#include "chrome/common/gfx/text_elider.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
+#include "chrome/common/resource_bundle.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
namespace {
@@ -25,6 +28,11 @@ const int kBarPadding = 2;
// Maximum number of characters on a bookmark button.
const int kMaxCharsOnAButton = 15;
+// Our custom draging type for bookmarks.
+static GtkTargetEntry target_table[] = {
+ { "application/x-bookmark-toolbar-item", GTK_TARGET_SAME_APP, 0 }
+};
+
} // namespace
BookmarkBarGtk::BookmarkBarGtk(Profile* profile, Browser* browser)
@@ -35,6 +43,7 @@ BookmarkBarGtk::BookmarkBarGtk(Profile* profile, Browser* browser)
instructions_(NULL),
show_instructions_(true) {
Init(profile);
+ LoadNineboxImages();
SetProfile(profile);
}
@@ -43,6 +52,7 @@ BookmarkBarGtk::~BookmarkBarGtk() {
model_->RemoveObserver(this);
RemoveAllBookmarkButtons();
+ bookmark_toolbar_.Destroy();
container_.Destroy();
}
@@ -85,6 +95,30 @@ void BookmarkBarGtk::Init(Profile* profile) {
WideToUTF8(l10n_util::GetString(IDS_BOOKMARKS_NO_ITEMS)).c_str());
gtk_box_pack_start(GTK_BOX(bookmark_hbox_), instructions_,
FALSE, FALSE, 0);
+
+ bookmark_toolbar_.Own(gtk_toolbar_new());
+ g_signal_connect(G_OBJECT(bookmark_toolbar_.get()), "expose-event",
+ G_CALLBACK(&OnToolbarExpose), this);
+ gtk_box_pack_start(GTK_BOX(bookmark_hbox_), bookmark_toolbar_.get(),
+ TRUE, TRUE, 0);
+
+ gtk_drag_dest_set(bookmark_toolbar_.get(), GTK_DEST_DEFAULT_DROP,
+ target_table, G_N_ELEMENTS(target_table),
+ GDK_ACTION_MOVE);
+ g_signal_connect(bookmark_toolbar_.get(), "drag-motion",
+ G_CALLBACK(&OnToolbarDragMotion), this);
+ g_signal_connect(bookmark_toolbar_.get(), "drag-leave",
+ G_CALLBACK(&OnToolbarDragLeave), this);
+
+ gtk_box_pack_start(GTK_BOX(bookmark_hbox_), gtk_vseparator_new(),
+ FALSE, FALSE, 0);
+
+ other_bookmarks_button_ = new CustomContainerButton();
+ gtk_button_set_label(GTK_BUTTON(other_bookmarks_button_->widget()),
+ "Other bookmarks");
+ // TODO(erg): Hook up a popup menu to |other_bookmarks_button_|.
+ gtk_box_pack_start(GTK_BOX(bookmark_hbox_), other_bookmarks_button_->widget(),
+ FALSE, FALSE, 0);
}
void BookmarkBarGtk::AddBookmarkbarToBox(GtkWidget* box) {
@@ -119,10 +153,8 @@ void BookmarkBarGtk::Loaded(BookmarkModel* model) {
// Create a button for each of the children on the bookmark bar.
for (int i = 0; i < node->GetChildCount(); ++i) {
- CustomContainerButton* button = CreateBookmarkButton(node->GetChild(i));
- gtk_box_pack_start(GTK_BOX(bookmark_hbox_), button->widget(),
- FALSE, FALSE, 0);
- current_bookmark_buttons_.push_back(button);
+ GtkToolItem* item = CreateBookmarkToolItem(node->GetChild(i));
+ gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), item, -1);
}
show_instructions_ = (node->GetChildCount() == 0);
@@ -136,48 +168,64 @@ void BookmarkBarGtk::Loaded(BookmarkModel* model) {
}
void BookmarkBarGtk::RemoveAllBookmarkButtons() {
- for (std::vector<CustomContainerButton*>::const_iterator it =
- current_bookmark_buttons_.begin();
- it != current_bookmark_buttons_.end(); ++it) {
- delete *it;
- }
-
- current_bookmark_buttons_.clear();
+ gfx::RemoveAllChildren(bookmark_toolbar_.get());
}
bool BookmarkBarGtk::IsAlwaysShown() {
return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
}
-CustomContainerButton* BookmarkBarGtk::CreateBookmarkButton(
+GtkWidget* BookmarkBarGtk::CreateBookmarkButton(
BookmarkNode* node) {
- if (node->is_url()) {
- CustomContainerButton* button = new CustomContainerButton;
+ GtkWidget* button = gtk_button_new();
- gtk_widget_set_tooltip_text(button->widget(), BuildTooltip(node).c_str());
- gtk_button_set_label(GTK_BUTTON(button->widget()),
+ if (node->is_url()) {
+ gtk_widget_set_tooltip_text(button, BuildTooltip(node).c_str());
+ gtk_button_set_label(GTK_BUTTON(button),
WideToUTF8(node->GetTitle()).c_str());
// TODO(erg): Consider a soft maximum instead of this hard 15.
gtk_label_set_max_width_chars(
- GTK_LABEL(gtk_bin_get_child(GTK_BIN(button->widget()))),
+ GTK_LABEL(gtk_bin_get_child(GTK_BIN(button))),
kMaxCharsOnAButton);
+ gtk_widget_set_app_paintable(button, TRUE);
+ g_signal_connect(G_OBJECT(button), "expose-event",
+ G_CALLBACK(&OnButtonExpose), this);
+
+ // The tool item is also a source for dragging
+ gtk_drag_source_set(button, GDK_BUTTON1_MASK,
+ target_table, G_N_ELEMENTS(target_table),
+ GDK_ACTION_MOVE);
+ g_signal_connect(G_OBJECT(button), "drag-begin",
+ G_CALLBACK(&OnButtonDragBegin), this);
+ g_signal_connect(G_OBJECT(button), "drag-end",
+ G_CALLBACK(&OnButtonDragEnd), this);
+
// Connect to 'button-release-event' instead of 'clicked' because we need
// to access to the modifier keys and we do different things on each
// button.
- g_signal_connect(G_OBJECT(button->widget()), "button-release-event",
+ g_signal_connect(G_OBJECT(button), "button-press-event",
+ G_CALLBACK(OnButtonPressed), this);
+ g_signal_connect(G_OBJECT(button), "button-release-event",
G_CALLBACK(OnButtonReleased), this);
- GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);
- g_object_set_data(G_OBJECT(button->widget()), "bookmark-node", node);
-
- gtk_widget_show_all(button->widget());
-
- return button;
+ g_object_set_data(G_OBJECT(button), "bookmark-node", node);
} else {
NOTIMPLEMENTED();
- return NULL;
}
+
+ return button;
+}
+
+GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(BookmarkNode* node) {
+ GtkWidget* button = CreateBookmarkButton(node);
+
+ GtkToolItem* item = gtk_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(item), button);
+ gtk_widget_show_all(GTK_WIDGET(item));
+
+ return item;
}
std::string BookmarkBarGtk::BuildTooltip(BookmarkNode* node) {
@@ -186,9 +234,51 @@ std::string BookmarkBarGtk::BuildTooltip(BookmarkNode* node) {
return node->GetURL().possibly_invalid_spec();
}
+void BookmarkBarGtk::LoadNineboxImages() {
+ GdkPixbuf* images[9];
+ int i = 0;
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_TOP_LEFT_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_TOP_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_TOP_RIGHT_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_LEFT_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_CENTER_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_RIGHT_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_BOTTOM_LEFT_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_BOTTOM_H);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_BOTTOM_RIGHT_H);
+ nine_box_prelight_.reset(new NineBox(images));
+
+ i = 0;
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_TOP_LEFT_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_TOP_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_TOP_RIGHT_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_LEFT_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_CENTER_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_RIGHT_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_BOTTOM_LEFT_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_BOTTOM_P);
+ images[i++] = rb.LoadPixbuf(IDR_TEXTBUTTON_BOTTOM_RIGHT_P);
+ nine_box_active_.reset(new NineBox(images));
+}
+
+gboolean BookmarkBarGtk::OnButtonPressed(GtkWidget* sender,
+ GdkEventButton* event,
+ BookmarkBarGtk* bar) {
+ bar->ignore_button_release_ = false;
+ return FALSE;
+}
+
gboolean BookmarkBarGtk::OnButtonReleased(GtkWidget* sender,
GdkEventButton* event,
BookmarkBarGtk* bar) {
+ if (bar->ignore_button_release_) {
+ // Don't handle this message; it was a drag.
+ bar->ignore_button_release_ = false;
+ return FALSE;
+ }
+
gpointer user_data = g_object_get_data(G_OBJECT(sender), "bookmark-node");
BookmarkNode* node = static_cast<BookmarkNode*>(user_data);
DCHECK(node);
@@ -209,3 +299,130 @@ gboolean BookmarkBarGtk::OnButtonReleased(GtkWidget* sender,
// Allow other handlers to run so the button state is updated correctly.
return FALSE;
}
+
+// static
+gboolean BookmarkBarGtk::OnButtonExpose(GtkWidget* widget, GdkEventExpose* e,
+ BookmarkBarGtk* button) {
+ NineBox* nine_box = NULL;
+ if (GTK_WIDGET_STATE(widget) == GTK_STATE_PRELIGHT)
+ nine_box = button->nine_box_prelight_.get();
+ else if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
+ nine_box = button->nine_box_active_.get();
+
+ // Only draw theme graphics if we have some.
+ if (nine_box)
+ nine_box->RenderToWidget(widget);
+
+ // If we return FALSE from the function, the button paints itself.
+ // If we return TRUE, no children are painted.
+ // So we return TRUE and send the expose along directly to the child.
+ gtk_container_propagate_expose(GTK_CONTAINER(widget),
+ gtk_bin_get_child(GTK_BIN(widget)),
+ e);
+
+ return TRUE; // Prevent normal painting.
+}
+
+// static
+void BookmarkBarGtk::OnButtonDragBegin(GtkWidget* button,
+ GdkDragContext* drag_context,
+ BookmarkBarGtk* bar) {
+ // Signal to any future OnButtonReleased calls that we're dragging instead of
+ // pressing.
+ bar->ignore_button_release_ = true;
+
+ gpointer user_data = g_object_get_data(G_OBJECT(button), "bookmark-node");
+ BookmarkNode* node = static_cast<BookmarkNode*>(user_data);
+ DCHECK(node);
+
+ bar->dragged_node_ = node;
+ bar->toolbar_drop_item_ = NULL;
+
+ // Build a windowed representation for our button.
+ GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_widget_realize(window);
+
+ GtkWidget* frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
+ gtk_container_add(GTK_CONTAINER(window), frame);
+ gtk_widget_show(frame);
+
+ GtkWidget* floating_button = bar->CreateBookmarkButton(node);
+ gtk_container_add(GTK_CONTAINER(frame), floating_button);
+ gtk_widget_show(floating_button);
+
+ gint x, y;
+ gtk_widget_get_pointer(button, &x, &y);
+ gtk_drag_set_icon_widget(drag_context, window, x, y);
+
+ // Hide our node
+ gtk_widget_hide(button);
+}
+
+// static
+void BookmarkBarGtk::OnButtonDragEnd(GtkWidget* button,
+ GdkDragContext* drag_context,
+ BookmarkBarGtk* bar) {
+ // Cleanup everything from this drag
+ if (bar->toolbar_drop_item_) {
+ g_object_unref(bar->toolbar_drop_item_);
+ bar->toolbar_drop_item_ = NULL;
+ }
+
+ bar->dragged_node_ = NULL;
+
+ gtk_widget_show(button);
+}
+
+// static
+gboolean BookmarkBarGtk::OnToolbarExpose(GtkWidget* widget,
+ GdkEventExpose* event,
+ BookmarkBarGtk* bar) {
+ // A GtkToolbar's expose handler first draws a box. We don't want that so we
+ // need to propagate the expose event to all the container's children.
+ GList* children = gtk_container_get_children(GTK_CONTAINER(widget));
+ GList* start = children;
+ while (children) {
+ GList *next = children->next;
+ gtk_container_propagate_expose(GTK_CONTAINER(widget),
+ GTK_WIDGET(children->data),
+ event);
+ children = next;
+ }
+ g_list_free(children);
+
+ return TRUE;
+}
+
+// static
+gboolean BookmarkBarGtk::OnToolbarDragMotion(GtkToolbar* toolbar,
+ GdkDragContext* context,
+ gint x,
+ gint y,
+ guint time,
+ BookmarkBarGtk* bar) {
+ if (!bar->toolbar_drop_item_) {
+ bar->toolbar_drop_item_ = bar->CreateBookmarkToolItem(bar->dragged_node_);
+ g_object_ref_sink(GTK_OBJECT(bar->toolbar_drop_item_));
+ }
+
+ gdk_drag_status(context, GDK_ACTION_MOVE, time);
+ gint index = gtk_toolbar_get_drop_index(toolbar, x, y);
+ gtk_toolbar_set_drop_highlight_item(toolbar,
+ GTK_TOOL_ITEM(bar->toolbar_drop_item_),
+ index);
+ return TRUE;
+}
+
+// static
+gboolean BookmarkBarGtk::OnToolbarDragLeave(GtkToolbar* toolbar,
+ GdkDragContext* context,
+ guint time,
+ BookmarkBarGtk* bar) {
+ if (bar->toolbar_drop_item_) {
+ g_object_unref(bar->toolbar_drop_item_);
+ bar->toolbar_drop_item_ = NULL;
+ }
+
+ gtk_toolbar_set_drop_highlight_item(toolbar, NULL, 0);
+}
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.h b/chrome/browser/gtk/bookmark_bar_gtk.h
index 003bf4b..53f6beb 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.h
+++ b/chrome/browser/gtk/bookmark_bar_gtk.h
@@ -15,6 +15,7 @@
class Browser;
class CustomContainerButton;
+class NineBox;
class PageNavigator;
class Profile;
@@ -109,12 +110,41 @@ class BookmarkBarGtk : public BookmarkModelObserver {
}
private:
- CustomContainerButton* CreateBookmarkButton(BookmarkNode* node);
+ GtkWidget* CreateBookmarkButton(BookmarkNode* node);
+ GtkToolItem* CreateBookmarkToolItem(BookmarkNode* node);
std::string BuildTooltip(BookmarkNode* node);
+ void LoadNineboxImages();
+
+ // GtkButton callbacks
+ static gboolean OnButtonPressed(GtkWidget* sender,
+ GdkEventButton* event,
+ BookmarkBarGtk* bar);
static gboolean OnButtonReleased(GtkWidget* sender, GdkEventButton* event,
BookmarkBarGtk* bar);
+ static gboolean OnButtonExpose(GtkWidget* widget, GdkEventExpose* e,
+ BookmarkBarGtk* button);
+ static void OnButtonDragBegin(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ BookmarkBarGtk* bar);
+ static void OnButtonDragEnd(GtkWidget* button,
+ GdkDragContext* drag_context,
+ BookmarkBarGtk* bar);
+
+ // GtkToolbar callbacks
+ static gboolean OnToolbarExpose(GtkWidget* widget, GdkEventExpose* event,
+ BookmarkBarGtk* window);
+ static gboolean OnToolbarDragMotion(GtkToolbar* toolbar,
+ GdkDragContext* context,
+ gint x,
+ gint y,
+ guint time,
+ BookmarkBarGtk* bar);
+ static gboolean OnToolbarDragLeave(GtkToolbar* toolbar,
+ GdkDragContext* context,
+ guint time,
+ BookmarkBarGtk* bar);
Profile* profile_;
@@ -137,12 +167,30 @@ class BookmarkBarGtk : public BookmarkModelObserver {
// A GtkLabel to display when there are no bookmark buttons to display.
GtkWidget* instructions_;
+ // GtkToolbar which contains all the bookmark buttons.
+ OwnedWidgetGtk bookmark_toolbar_;
+
+ // The other bookmarks button.
+ CustomContainerButton* other_bookmarks_button_;
+
+ // Whether we should ignore the next button release event (because we were
+ // dragging).
+ bool ignore_button_release_;
+
+ // The BookmarkNode from the model being dragged. NULL when we aren't
+ // dragging.
+ BookmarkNode* dragged_node_;
+
+ // We create a GtkToolbarItem from |dragged_node_| for display.
+ GtkToolItem* toolbar_drop_item_;
+
// Whether we should show the instructional text in the bookmark bar.
bool show_instructions_;
- // Bookmark buttons. We keep these references so we can deallocate them
- // properly.
- std::vector<CustomContainerButton*> current_bookmark_buttons_;
+ // The theme graphics for when the mouse is over the button.
+ scoped_ptr<NineBox> nine_box_prelight_;
+ // The theme graphics for when the button is clicked.
+ scoped_ptr<NineBox> nine_box_active_;
};
#endif // CHROME_BROWSER_GTK_BOOKMARK_BAR_GTK_H_