diff options
author | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-06 22:03:00 +0000 |
---|---|---|
committer | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-06 22:03:00 +0000 |
commit | 29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c (patch) | |
tree | 6cc5dd709d48346ba0c6669f67263cbc714fbc9d /chrome/browser/gtk | |
parent | 901065b013787109038f232c0707b245af796599 (diff) | |
download | chromium_src-29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c.zip chromium_src-29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c.tar.gz chromium_src-29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c.tar.bz2 |
Clicking on a folder in the bookmark bar now shows its contents as a menu.
http://crbug.com/11250
Review URL: http://codereview.chromium.org/114005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15463 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r-- | chrome/browser/gtk/bookmark_bar_gtk.cc | 12 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_bar_gtk.h | 5 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.cc | 108 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.h | 22 |
4 files changed, 127 insertions, 20 deletions
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc index 6c3d85f..9f4f0ce 100644 --- a/chrome/browser/gtk/bookmark_bar_gtk.cc +++ b/chrome/browser/gtk/bookmark_bar_gtk.cc @@ -8,6 +8,7 @@ #include "app/resource_bundle.h" #include "base/gfx/gtk_util.h" #include "chrome/browser/bookmarks/bookmark_context_menu.h" +#include "chrome/browser/bookmarks/bookmark_menu_controller_gtk.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/browser.h" #include "chrome/browser/gtk/custom_button.h" @@ -353,6 +354,8 @@ GtkWidget* BookmarkBarGtk::CreateBookmarkButton( GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(BookmarkNode* node) { GtkWidget* button = CreateBookmarkButton(node); + g_object_set_data(G_OBJECT(button), "left-align-popup", + reinterpret_cast<void*>(true)); GtkToolItem* item = gtk_tool_item_new(); gtk_container_add(GTK_CONTAINER(item), button); @@ -537,7 +540,14 @@ gboolean BookmarkBarGtk::OnFolderButtonReleased(GtkWidget* sender, DCHECK(node); DCHECK(bar->page_navigator_); - NOTIMPLEMENTED() << "Flesh this out once I can make folders."; + bar->current_menu_.reset( + new BookmarkMenuController(bar->browser_, bar->profile_, + bar->page_navigator_, + GTK_WINDOW(gtk_widget_get_toplevel(sender)), + node, + 0, + false)); + bar->current_menu_->Popup(sender, event->button, event->time); // Allow other handlers to run so the button state is updated correctly. return FALSE; diff --git a/chrome/browser/gtk/bookmark_bar_gtk.h b/chrome/browser/gtk/bookmark_bar_gtk.h index 17f508f..8c02765 100644 --- a/chrome/browser/gtk/bookmark_bar_gtk.h +++ b/chrome/browser/gtk/bookmark_bar_gtk.h @@ -14,6 +14,7 @@ #include "chrome/browser/bookmarks/bookmark_model.h" class BookmarkContextMenu; +class BookmarkMenuController; class Browser; class CustomContainerButton; class PageNavigator; @@ -200,6 +201,10 @@ class BookmarkBarGtk : public BookmarkModelObserver { // The last displayed right click menu, or NULL if no menus have been // displayed yet. scoped_ptr<BookmarkContextMenu> current_context_menu_; + + // The last displayed left click menu, or NULL if no menus have been + // displayed yet. + scoped_ptr<BookmarkMenuController> current_menu_; }; #endif // CHROME_BROWSER_GTK_BOOKMARK_BAR_GTK_H_ diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc index fd63e44..6d12f26 100644 --- a/chrome/browser/gtk/menu_gtk.cc +++ b/chrome/browser/gtk/menu_gtk.cc @@ -6,10 +6,36 @@ #include "app/l10n_util.h" #include "base/logging.h" +#include "base/stl_util-inl.h" #include "base/string_util.h" #include "chrome/common/gtk_util.h" #include "skia/include/SkBitmap.h" +namespace { + +struct SetIconState { + bool found; + const SkBitmap* icon; + int id; +}; + +void SetIconImpl(GtkWidget* widget, void* raw) { + SetIconState* data = reinterpret_cast<SetIconState*>(raw); + int this_id = + reinterpret_cast<int>(g_object_get_data(G_OBJECT(widget), "menu-id")); + + if (this_id == data->id) { + GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(data->icon); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), + gtk_image_new_from_pixbuf(pixbuf)); + g_object_unref(pixbuf); + + data->found = true; + } +} + +} // namespace + MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, const MenuCreateMaterial* menu_data, GtkAccelGroup* accel_group) @@ -28,6 +54,7 @@ MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, bool load) } MenuGtk::~MenuGtk() { + STLDeleteElements(&children_); menu_.Destroy(); if (dummy_accel_group_) g_object_unref(dummy_accel_group_); @@ -36,15 +63,28 @@ MenuGtk::~MenuGtk() { void MenuGtk::AppendMenuItemWithLabel(int command_id, const std::string& label) { GtkWidget* menu_item = gtk_menu_item_new_with_label(label.c_str()); + AddMenuItemWithId(menu_item, command_id); +} - g_object_set_data(G_OBJECT(menu_item), "menu-id", - reinterpret_cast<void*>(command_id)); +void MenuGtk::AppendMenuItemWithIcon(int command_id, + const std::string& label, + const SkBitmap& icon) { + GtkWidget* menu_item = BuildMenuItemWithImage(label, icon); + AddMenuItemWithId(menu_item, command_id); +} - g_signal_connect(G_OBJECT(menu_item), "activate", - G_CALLBACK(OnMenuItemActivatedById), this); +MenuGtk* MenuGtk::AppendSubMenuWithIcon(int command_id, + const std::string& label, + const SkBitmap& icon) { + GtkWidget* menu_item = BuildMenuItemWithImage(label, icon); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item); + MenuGtk* submenu = new MenuGtk(delegate_, false); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu->menu_.get()); + children_.push_back(submenu); + + AddMenuItemWithId(menu_item, command_id); + + return submenu; } void MenuGtk::AppendSeparator() { @@ -82,6 +122,25 @@ void MenuGtk::Cancel() { gtk_menu_popdown(GTK_MENU(menu_.get())); } +bool MenuGtk::SetIcon(const SkBitmap& icon, int item_id) { + // First search items in this menu. + SetIconState state; + state.found = false; + state.icon = &icon; + state.id = item_id; + gtk_container_foreach(GTK_CONTAINER(menu_.get()), SetIconImpl, &state); + if (state.found) + return true; + + for (std::vector<MenuGtk*>::iterator it = children_.begin(); + it != children_.end(); ++it) { + if ((*it)->SetIcon(icon, item_id)) + return true; + } + + return false; +} + // static std::string MenuGtk::ConvertAcceleratorsFromWindowsStyle( const std::string& label) { @@ -178,6 +237,18 @@ void MenuGtk::BuildMenuIn(GtkWidget* menu, } } +GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label, + const SkBitmap& icon) { + GtkWidget* menu_item = gtk_image_menu_item_new_with_label(label.c_str()); + + GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), + gtk_image_new_from_pixbuf(pixbuf)); + g_object_unref(pixbuf); + + return menu_item; +} + void MenuGtk::BuildMenuFromDelegate() { // Note that the menu IDs start at 1, not 0. for (int i = 1; i <= delegate_->GetItemCount(); ++i) { @@ -186,26 +257,25 @@ void MenuGtk::BuildMenuFromDelegate() { if (delegate_->IsItemSeparator(i)) { menu_item = gtk_separator_menu_item_new(); } else if (delegate_->HasIcon(i)) { - menu_item = gtk_image_menu_item_new_with_label( - delegate_->GetLabel(i).c_str()); const SkBitmap* icon = delegate_->GetIcon(i); - GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(icon); - GtkWidget* widget = gtk_image_new_from_pixbuf(pixbuf); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), widget); - g_object_unref(pixbuf); + menu_item = BuildMenuItemWithImage(delegate_->GetLabel(i), *icon); } else { menu_item = gtk_menu_item_new_with_label(delegate_->GetLabel(i).c_str()); } - g_object_set_data(G_OBJECT(menu_item), "menu-id", - reinterpret_cast<void*>(i)); + AddMenuItemWithId(menu_item, i); + } +} + +void MenuGtk::AddMenuItemWithId(GtkWidget* menu_item, int id) { + g_object_set_data(G_OBJECT(menu_item), "menu-id", + reinterpret_cast<void*>(id)); - g_signal_connect(G_OBJECT(menu_item), "activate", - G_CALLBACK(OnMenuItemActivatedById), this); + g_signal_connect(G_OBJECT(menu_item), "activate", + G_CALLBACK(OnMenuItemActivatedById), this); - gtk_widget_show(menu_item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item); - } + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item); } // static diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h index 371ed58..b7afd67 100644 --- a/chrome/browser/gtk/menu_gtk.h +++ b/chrome/browser/gtk/menu_gtk.h @@ -7,6 +7,7 @@ #include <gtk/gtk.h> #include <string> +#include <vector> #include "chrome/browser/gtk/standard_menus.h" #include "chrome/common/owned_widget_gtk.h" @@ -48,6 +49,10 @@ class MenuGtk { // These methods are used to build the menu dynamically. void AppendMenuItemWithLabel(int command_id, const std::string& label); + void AppendMenuItemWithIcon(int command_id, const std::string& label, + const SkBitmap& icon); + MenuGtk* AppendSubMenuWithIcon(int command_id, const std::string& label, + const SkBitmap& icon); void AppendSeparator(); // Displays the menu. |timestamp| is the time of activation. The popup is @@ -67,6 +72,11 @@ class MenuGtk { // Closes the menu. void Cancel(); + // Sets an icon for an item with a given item_id. This method searches both + // this MenuGtk object and all child submenus. Returns false if the item with + // |item_id| is not found. + bool SetIcon(const SkBitmap& icon, int item_id); + // Change windows accelerator style to GTK style. (GTK uses _ for // accelerators. Windows uses & with && as an escape for &.) static std::string ConvertAcceleratorsFromWindowsStyle( @@ -79,10 +89,18 @@ class MenuGtk { const MenuCreateMaterial* menu_data, GtkAccelGroup* accel_group); + // Builds a GtkImageMenuItem. + GtkWidget* BuildMenuItemWithImage(const std::string& label, + const SkBitmap& icon); + // A function that creates a GtkMenu from |delegate_|. This function is not // recursive and does not support sub-menus. void BuildMenuFromDelegate(); + // Helper method that sets properties on a GtkMenuItem and then adds it to + // our internal |menu_|. + void AddMenuItemWithId(GtkWidget* menu_item, int id); + // Callback for when a menu item is clicked. Used when the menu is created // via a MenuCreateMaterial. static void OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu); @@ -116,6 +134,10 @@ class MenuGtk { // gtk_menu_popup() does not appear to take ownership of popup menus, so // MenuGtk explicitly manages the lifetime of the menu. OwnedWidgetGtk menu_; + + // MenuGtk instances of submenus; we keep references to these objects just to + // clean up during our destructor. + std::vector<MenuGtk*> children_; }; #endif // CHROME_BROWSER_GTK_MENU_GTK_H_ |