diff options
author | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 01:05:13 +0000 |
---|---|---|
committer | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 01:05:13 +0000 |
commit | e4eed283dccc643388bc7f211ff008611d5ce997 (patch) | |
tree | cd1ac97033792276dadb739b5066a8f7670a1145 /chrome/browser | |
parent | 1e744f200179976645ef75859569eaa475b820be (diff) | |
download | chromium_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.cc | 267 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_bar_gtk.h | 56 |
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_ |