summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-08 20:59:19 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-08 20:59:19 +0000
commit4bd23f35c4b4b7eab1796170789a8f00e7984972 (patch)
tree7808a313bbc7c4bf7b79717175dc29fc0b8557f1
parentd09b0922f3831944386850682b584e4dccf60357 (diff)
downloadchromium_src-4bd23f35c4b4b7eab1796170789a8f00e7984972.zip
chromium_src-4bd23f35c4b4b7eab1796170789a8f00e7984972.tar.gz
chromium_src-4bd23f35c4b4b7eab1796170789a8f00e7984972.tar.bz2
A new menu system for views.
This is all the functionality needed for the page, app menus and browser system menus. Review URL: http://codereview.chromium.org/119237 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17895 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/gfx/native_widget_types.h3
-rw-r--r--views/controls/menu/menu_2.cc62
-rw-r--r--views/controls/menu/menu_2.h148
-rw-r--r--views/controls/menu/native_menu_gtk.cc233
-rw-r--r--views/controls/menu/native_menu_gtk.h59
-rw-r--r--views/controls/menu/native_menu_win.cc346
-rw-r--r--views/controls/menu/native_menu_win.h140
-rw-r--r--views/controls/menu/simple_menu_model.cc129
-rw-r--r--views/controls/menu/simple_menu_model.h93
-rw-r--r--views/view.cc2
-rw-r--r--views/view.h2
-rw-r--r--views/views.gyp9
12 files changed, 1224 insertions, 2 deletions
diff --git a/base/gfx/native_widget_types.h b/base/gfx/native_widget_types.h
index b6361cf..9444a61 100644
--- a/base/gfx/native_widget_types.h
+++ b/base/gfx/native_widget_types.h
@@ -61,18 +61,21 @@ typedef HWND NativeWindow;
typedef HWND NativeEditView;
typedef HDC NativeDrawingContext;
typedef HCURSOR NativeCursor;
+typedef HMENU NativeMenu;
#elif defined(OS_MACOSX)
typedef NSView* NativeView;
typedef NSWindow* NativeWindow;
typedef NSTextField* NativeEditView;
typedef CGContext* NativeDrawingContext;
typedef void* NativeCursor;
+typedef void* NativeMenu;
#elif defined(OS_LINUX)
typedef GtkWidget* NativeView;
typedef GtkWindow* NativeWindow;
typedef GtkWidget* NativeEditView;
typedef cairo_surface_t* NativeDrawingContext;
typedef GdkCursor* NativeCursor;
+typedef GtkWidget* NativeMenu;
#endif
// Note: for test_shell we're packing a pointer into the NativeViewId. So, if
diff --git a/views/controls/menu/menu_2.cc b/views/controls/menu/menu_2.cc
new file mode 100644
index 0000000..7d2fa8a
--- /dev/null
+++ b/views/controls/menu/menu_2.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "views/controls/menu/menu_2.h"
+
+#include "base/compiler_specific.h"
+#include "views/controls/menu/menu_wrapper.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// Menu2Model, public:
+
+// static
+bool Menu2Model::GetModelAndIndexForCommandId(int command_id,
+ Menu2Model** model, int* index) {
+ int item_count = (*model)->GetItemCount();
+ for (int i = 0; i < item_count; ++i) {
+ if ((*model)->GetTypeAt(i) == TYPE_SUBMENU) {
+ Menu2Model* submenu_model = (*model)->GetSubmenuModelAt(i);
+ if (GetModelAndIndexForCommandId(command_id, &submenu_model, index)) {
+ *model = submenu_model;
+ return true;
+ }
+ }
+ if ((*model)->GetCommandIdAt(i) == command_id) {
+ *index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Menu2, public:
+
+Menu2::Menu2(Menu2Model* model, Menu2Delegate* delegate)
+ : model_(model),
+ delegate_(delegate),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ wrapper_(MenuWrapper::CreateWrapper(this))) {
+ Rebuild();
+}
+
+gfx::NativeMenu Menu2::GetNativeMenu() const {
+ return wrapper_->GetNativeMenu();
+}
+
+void Menu2::RunMenuAt(const gfx::Point& point, Alignment alignment) {
+ wrapper_->RunMenuAt(point, alignment);
+}
+
+void Menu2::Rebuild() {
+ wrapper_->Rebuild();
+}
+
+void Menu2::UpdateStates() {
+ wrapper_->UpdateStates();
+}
+
+} // namespace
diff --git a/views/controls/menu/menu_2.h b/views/controls/menu/menu_2.h
new file mode 100644
index 0000000..b50efd7
--- /dev/null
+++ b/views/controls/menu/menu_2.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef CONTROLS_MENU_VIEWS_MENU_2_H_
+#define CONTROLS_MENU_VIEWS_MENU_2_H_
+
+#include <string>
+
+#include "base/gfx/native_widget_types.h"
+
+namespace gfx {
+class Point;
+}
+class SkBitmap;
+
+namespace views {
+
+class Accelerator;
+class Menu2;
+class MenuWrapper;
+
+// The Menu2Model is an interface implemented by an object that provides the
+// content of a menu.
+class Menu2Model {
+ public:
+ virtual ~Menu2Model() {}
+
+ // The type of item.
+ enum ItemType {
+ TYPE_COMMAND,
+ TYPE_CHECK,
+ TYPE_RADIO,
+ TYPE_SEPARATOR,
+ TYPE_SUBMENU
+ };
+
+ // Returns true if any of the items within the model have icons. Not all
+ // platforms support icons in menus natively and so this is a hint for
+ // triggering a custom rendering mode.
+ virtual bool HasIcons() const = 0;
+
+ // Returns the index of the first item. This is 0 for most menus except the
+ // system menu on Windows. |native_menu| is the menu to locate the start index
+ // within. It is guaranteed to be reset to a clean default state.
+ // IMPORTANT: If the model implementation returns something _other_ than 0
+ // here, it must offset the values for |index| it passes to the
+ // methods below by this number - this is NOT done automatically!
+ virtual int GetFirstItemIndex(gfx::NativeMenu native_menu) const { return 0; }
+
+ // Returns the number of items in the menu.
+ virtual int GetItemCount() const = 0;
+
+ // Returns the type of item at the specified index.
+ virtual ItemType GetTypeAt(int index) const = 0;
+
+ // Returns the command id of the item at the specified index.
+ virtual int GetCommandIdAt(int index) const = 0;
+
+ // Returns the label of the item at the specified index.
+ virtual std::wstring GetLabelAt(int index) const = 0;
+
+ // Returns true if the label at the specified index can change over the course
+ // of the menu's lifetime. If this function returns true, the label of the
+ // menu item will be updated each time the menu is shown.
+ virtual bool IsLabelDynamicAt(int index) const = 0;
+
+ // Gets the acclerator information for the specified index, returning true if
+ // there is a shortcut accelerator for the item, false otherwise.
+ virtual bool GetAcceleratorAt(int index,
+ views::Accelerator* accelerator) const = 0;
+
+ // Returns the checked state of the item at the specified index.
+ virtual bool IsItemCheckedAt(int index) const = 0;
+
+ // Returns the id of the group of radio items that the item at the specified
+ // index belongs to.
+ virtual int GetGroupIdAt(int index) const = 0;
+
+ // Gets the icon for the item at the specified index, returning true if there
+ // is an icon, false otherwise.
+ virtual bool GetIconAt(int index, SkBitmap* icon) const = 0;
+
+ // Returns the enabled state of the item at the specified index.
+ virtual bool IsEnabledAt(int index) const = 0;
+
+ // Returns the model for the submenu at the specified index.
+ virtual Menu2Model* GetSubmenuModelAt(int index) const = 0;
+
+ // Retrieves the model and index that contains a specific command id. Returns
+ // true if an item with the specified command id is found. |model| is inout,
+ // and specifies the model to start searching from.
+ static bool GetModelAndIndexForCommandId(int command_id, Menu2Model** model,
+ int* index);
+};
+
+// The Menu2Delegate is an interface implemented by an object that performs
+// tasks that the Menu2 cannot itself.
+class Menu2Delegate {
+ public:
+ // Executes the command with the specified identifier.
+ virtual void ExecuteCommand(Menu2Model* model, int command_id) = 0;
+};
+
+// A menu. Populated from a model, and relies on a delegate to execute commands.
+class Menu2 {
+ public:
+ Menu2(Menu2Model* model, Menu2Delegate* delegate);
+ virtual ~Menu2() {}
+
+ // How the menu is aligned relative to the point it is shown at.
+ enum Alignment {
+ ALIGN_TOPLEFT,
+ ALIGN_TOPRIGHT
+ };
+
+ // Runs the menu at the specified point. This may or may not block, depending
+ // on the platform and type of menu in use.
+ void RunMenuAt(const gfx::Point& point, Alignment alignment);
+
+ // Called when the model supplying data to this menu has changed, and the menu
+ // must be rebuilt.
+ void Rebuild();
+
+ // Called when the states of the menu items in the menu should be refreshed
+ // from the model.
+ void UpdateStates();
+
+ // For submenus.
+ gfx::NativeMenu GetNativeMenu() const;
+
+ // Accessors.
+ Menu2Model* model() const { return model_; }
+ Menu2Delegate* delegate() const { return delegate_; }
+
+ private:
+ Menu2Model* model_;
+ Menu2Delegate* delegate_;
+
+ // The object that actually implements the menu.
+ MenuWrapper* wrapper_;
+
+ DISALLOW_COPY_AND_ASSIGN(Menu2);
+};
+
+} // namespace views
+
+#endif // CONTROLS_MENU_VIEWS_MENU_2_H_
diff --git a/views/controls/menu/native_menu_gtk.cc b/views/controls/menu/native_menu_gtk.cc
new file mode 100644
index 0000000..4221e6b
--- /dev/null
+++ b/views/controls/menu/native_menu_gtk.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "views/controls/menu/native_menu_gtk.h"
+
+#include "base/string_util.h"
+#include "base/time.h"
+#include "views/accelerator.h"
+#include "views/controls/menu/menu_2.h"
+
+namespace {
+// Data passed to the UpdateStateCallback from gtk_container_foreach.
+struct UpdateStateData {
+ // The model to retrieve state from.
+ views::Menu2Model* model;
+ // The index within said model.
+ int index;
+};
+
+// Data passed to the MenuPositionFunc from gtk_menu_popup
+struct Position {
+ // The point to run the menu at.
+ gfx::Point point;
+ // The alignment of the menu at that point.
+ views::Menu2::Alignment alignment;
+};
+
+std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) {
+ std::string ret;
+ ret.reserve(label.length());
+ for (size_t i = 0; i < label.length(); ++i) {
+ if ('&' == label[i]) {
+ if (i + 1 < label.length() && '&' == label[i + 1]) {
+ ret.push_back(label[i]);
+ ++i;
+ } else {
+ ret.push_back('_');
+ }
+ } else {
+ ret.push_back(label[i]);
+ }
+ }
+
+ return ret;
+}
+
+// Returns true if the menu item type specified can be executed as a command.
+bool MenuTypeCanExecute(views::Menu2Model::ItemType type) {
+ return type == views::Menu2Model::TYPE_COMMAND ||
+ type == views::Menu2Model::TYPE_CHECK ||
+ type == views::Menu2Model::TYPE_RADIO;
+}
+
+} // namespace
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeMenuGtk, public:
+
+NativeMenuGtk::NativeMenuGtk(Menu2Model* model,
+ Menu2Delegate* delegate)
+ : model_(model),
+ delegate_(delegate),
+ menu_(NULL) {
+}
+
+NativeMenuGtk::~NativeMenuGtk() {
+ gtk_widget_destroy(menu_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeMenuGtk, MenuWrapper implementation:
+
+void NativeMenuGtk::RunMenuAt(const gfx::Point& point, int alignment) {
+ Position position = { point, static_cast<Menu2::Alignment>(alignment) };
+ // TODO(beng): value of '1' will not work for context menus!
+ gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, MenuPositionFunc, &position, 1,
+ gtk_get_current_event_time());
+}
+
+void NativeMenuGtk::Rebuild() {
+ ResetMenu();
+
+ GtkRadioMenuItem* last_radio_item = NULL;
+ for (int i = 0; i < model_->GetItemCount(); ++i) {
+ Menu2Model::ItemType type = model_->GetTypeAt(i);
+ if (type == Menu2Model::TYPE_SEPARATOR)
+ AddSeparatorAt(i);
+ else
+ AddMenuItemAt(i, &last_radio_item);
+ }
+}
+
+void NativeMenuGtk::UpdateStates() {
+ UpdateStateData data = { model_, 0 };
+ gtk_container_foreach(GTK_CONTAINER(menu_), &UpdateStateCallback, &data);
+}
+
+gfx::NativeMenu NativeMenuGtk::GetNativeMenu() const {
+ return menu_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeMenuGtk, private:
+
+void NativeMenuGtk::AddSeparatorAt(int index) {
+ GtkWidget* separator = gtk_separator_menu_item_new();
+ gtk_widget_show(separator);
+ gtk_menu_append(menu_, separator);
+}
+
+void NativeMenuGtk::AddMenuItemAt(int index,
+ GtkRadioMenuItem** last_radio_item) {
+ GtkWidget* menu_item = NULL;
+ std::string label = ConvertAcceleratorsFromWindowsStyle(WideToUTF8(
+ model_->GetLabelAt(index)));
+
+ Menu2Model::ItemType type = model_->GetTypeAt(index);
+ switch (type) {
+ case Menu2Model::TYPE_CHECK:
+ menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
+ break;
+ case Menu2Model::TYPE_RADIO:
+ if (*last_radio_item) {
+ menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
+ *last_radio_item, label.c_str());
+ } else {
+ menu_item = gtk_radio_menu_item_new_with_mnemonic(NULL, label.c_str());
+ }
+ break;
+ case Menu2Model::TYPE_SUBMENU:
+ case Menu2Model::TYPE_COMMAND:
+ menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ // TODO(beng): icons
+
+ if (type == Menu2Model::TYPE_SUBMENU) {
+ // TODO(beng): we're leaking these objects right now... consider some other
+ // arrangement.
+ Menu2* submenu = new Menu2(model_->GetSubmenuModelAt(index), delegate_);
+ g_object_set_data(G_OBJECT(menu_item), "submenu", submenu);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
+ submenu->GetNativeMenu());
+ }
+
+ views::Accelerator accelerator(0, false, false, false);
+ if (model_->GetAcceleratorAt(index, &accelerator)) {
+ // TODO(beng): accelerators w/gtk_widget_add_accelerator.
+ }
+ g_object_set_data(G_OBJECT(menu_item), "position",
+ reinterpret_cast<void*>(index));
+ g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(CallActivate),
+ this);
+ gtk_widget_show(menu_item);
+ gtk_menu_append(menu_, menu_item);
+}
+
+// static
+void NativeMenuGtk::UpdateStateCallback(GtkWidget* menu_item, gpointer data) {
+ UpdateStateData* usd = reinterpret_cast<UpdateStateData*>(data);
+ gtk_widget_set_sensitive(menu_item, usd->model->IsEnabledAt(usd->index));
+ if (GTK_IS_CHECK_MENU_ITEM(menu_item)) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item),
+ usd->model->IsItemCheckedAt(usd->index));
+ }
+ // Recurse into submenus, too.
+ if (GTK_IS_MENU_ITEM(menu_item)) {
+ if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item))) {
+ Menu2* submenu =
+ reinterpret_cast<Menu2*>(g_object_get_data(G_OBJECT(menu_item),
+ "submenu"));
+ if (submenu)
+ submenu->UpdateStates();
+ }
+ }
+ ++usd->index;
+}
+
+void NativeMenuGtk::ResetMenu() {
+ if (menu_)
+ gtk_widget_destroy(menu_);
+ menu_ = gtk_menu_new();
+}
+
+// static
+void NativeMenuGtk::MenuPositionFunc(GtkMenu* menu,
+ int* x,
+ int* y,
+ gboolean* push_in,
+ void* data) {
+ Position* position = reinterpret_cast<Position*>(data);
+ // TODO(beng): RTL
+ *x = position->point.x();
+ *y = position->point.y();
+ if (position->alignment == Menu2::ALIGN_TOPRIGHT) {
+ GtkRequisition menu_req;
+ gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
+ *x -= menu_req.width;
+ }
+ *push_in = FALSE;
+}
+
+void NativeMenuGtk::OnActivate(GtkMenuItem* menu_item) {
+ int position = reinterpret_cast<int>(g_object_get_data(G_OBJECT(menu_item),
+ "position"));
+ if (model_->IsEnabledAt(position) &&
+ MenuTypeCanExecute(model_->GetTypeAt(position))) {
+ delegate_->ExecuteCommand(model_, model_->GetCommandIdAt(position));
+ }
+}
+
+// static
+void NativeMenuGtk::CallActivate(GtkMenuItem* menu_item,
+ NativeMenuGtk* native_menu) {
+ native_menu->OnActivate(menu_item);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MenuWrapper, public:
+
+// static
+MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) {
+ return new NativeMenuGtk(menu->model(), menu->delegate());
+}
+
+} // namespace views
diff --git a/views/controls/menu/native_menu_gtk.h b/views/controls/menu/native_menu_gtk.h
new file mode 100644
index 0000000..1c311b5
--- /dev/null
+++ b/views/controls/menu/native_menu_gtk.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef VIEWS_CONTROLS_MENU_NATIVE_MENU_GTK_H_
+#define VIEWS_CONTROLS_MENU_NATIVE_MENU_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include "views/controls/menu/menu_wrapper.h"
+
+namespace views {
+
+class Menu2Model;
+class Menu2Delegate;
+
+// A Gtk implementation of MenuWrapper.
+// TODO(beng): rename to MenuGtk once the old class is dead.
+class NativeMenuGtk : public MenuWrapper {
+ public:
+ NativeMenuGtk(Menu2Model* model,
+ Menu2Delegate* delegate);
+ virtual ~NativeMenuGtk();
+
+ // Overridden from MenuWrapper:
+ virtual void RunMenuAt(const gfx::Point& point, int alignment);
+ virtual void Rebuild();
+ virtual void UpdateStates();
+ virtual gfx::NativeMenu GetNativeMenu() const;
+
+ private:
+ void AddSeparatorAt(int index);
+ void AddMenuItemAt(int index, GtkRadioMenuItem** last_radio_item);
+
+ static void UpdateStateCallback(GtkWidget* menu_item, gpointer data);
+
+ void ResetMenu();
+
+ // Callback for gtk_menu_popup to position the menu.
+ static void MenuPositionFunc(GtkMenu* menu, int* x, int* y, gboolean* push_in,
+ void* data);
+
+ // Event handlers:
+ void OnActivate(GtkMenuItem* menu_item);
+
+ // Gtk signal handlers.
+ static void CallActivate(GtkMenuItem* menu_item, NativeMenuGtk* native_menu);
+
+ Menu2Model* model_;
+ Menu2Delegate* delegate_;
+
+ GtkWidget* menu_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeMenuGtk);
+};
+
+} // namespace views
+
+#endif // VIEWS_CONTROLS_MENU_NATIVE_MENU_GTK_H_
diff --git a/views/controls/menu/native_menu_win.cc b/views/controls/menu/native_menu_win.cc
new file mode 100644
index 0000000..fa2a5f7
--- /dev/null
+++ b/views/controls/menu/native_menu_win.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "views/controls/menu/native_menu_win.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "views/accelerator.h"
+#include "views/controls/menu/menu_2.h"
+
+namespace views {
+
+struct NativeMenuWin::ItemData {
+ // The Windows API requires that whoever creates the menus must own the
+ // strings used for labels, and keep them around for the lifetime of the
+ // created menu. So be it.
+ std::wstring label;
+
+ // Someone needs to own submenus, it may as well be us.
+ scoped_ptr<Menu2> submenu;
+};
+
+// TODO(beng): bring over owner draw from old menu system.
+class NativeMenuWin::MenuHostWindow {
+ public:
+ MenuHostWindow() {
+ RegisterClass();
+ hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName,
+ L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
+ SetProp(hwnd_, kMenuHostWindowKey, this);
+ }
+
+ ~MenuHostWindow() {
+ DestroyWindow(hwnd_);
+ }
+
+ HWND hwnd() const { return hwnd_; }
+
+ private:
+ static const wchar_t* kMenuHostWindowKey;
+ static const wchar_t* kWindowClassName;
+
+ void RegisterClass() {
+ static bool registered = false;
+ if (registered)
+ return;
+
+ WNDCLASSEX wcex = {0};
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc = &MenuHostWindowProc;
+ wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
+ wcex.lpszClassName = kWindowClassName;
+ ATOM clazz = RegisterClassEx(&wcex);
+ DCHECK(clazz);
+ registered = true;
+ }
+
+ bool ProcessWindowMessage(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* l_result) {
+ return false;
+ }
+
+ static LRESULT CALLBACK MenuHostWindowProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ MenuHostWindow* host =
+ reinterpret_cast<MenuHostWindow*>(GetProp(window, kMenuHostWindowKey));
+ LRESULT l_result = 0;
+ if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param,
+ &l_result)) {
+ return DefWindowProc(window, message, w_param, l_param);
+ }
+ return l_result;
+ }
+
+ HWND hwnd_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuHostWindow);
+};
+
+// static
+const wchar_t* NativeMenuWin::MenuHostWindow::kWindowClassName =
+ L"ViewsMenuHostWindow";
+
+const wchar_t* NativeMenuWin::MenuHostWindow::kMenuHostWindowKey =
+ L"__MENU_HOST_WINDOW__";
+
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeMenuWin, public:
+
+NativeMenuWin::NativeMenuWin(Menu2Model* model,
+ Menu2Delegate* delegate,
+ HWND system_menu_for)
+ : model_(model),
+ delegate_(delegate),
+ menu_(NULL),
+ owner_draw_(false),
+ system_menu_for_(system_menu_for),
+ first_item_index_(0) {
+}
+
+NativeMenuWin::~NativeMenuWin() {
+ STLDeleteContainerPointers(items_.begin(), items_.end());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeMenuWin, MenuWrapper implementation:
+
+void NativeMenuWin::RunMenuAt(const gfx::Point& point, int alignment) {
+ CreateHostWindow();
+ UpdateStates();
+ UINT flags = TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE;
+ flags |= GetAlignmentFlags(alignment);
+ UINT selected_command_id = TrackPopupMenuEx(menu_, flags, point.x(),
+ point.y(), host_window_->hwnd(),
+ NULL);
+ if (selected_command_id > 0) {
+ // Locate the correct delegate and model to notify about the selection.
+ // See comment in GetMenuForCommandId for details.
+ NativeMenuWin* menu = GetMenuForCommandId(selected_command_id);
+ menu->delegate_->ExecuteCommand(menu->model_, selected_command_id);
+ }
+}
+
+void NativeMenuWin::Rebuild() {
+ ResetNativeMenu();
+ owner_draw_ = model_->HasIcons();
+ first_item_index_ = model_->GetFirstItemIndex(GetNativeMenu());
+ for (int menu_index = first_item_index_;
+ menu_index < first_item_index_ + model_->GetItemCount(); ++menu_index) {
+ int model_index = menu_index - first_item_index_;
+ if (model_->GetTypeAt(model_index) == Menu2Model::TYPE_SEPARATOR)
+ AddSeparatorItemAt(menu_index, model_index);
+ else
+ AddMenuItemAt(menu_index, model_index);
+ }
+}
+
+void NativeMenuWin::UpdateStates() {
+ // A depth-first walk of the menu items, updating states.
+ for (int menu_index = first_item_index_;
+ menu_index < first_item_index_ + model_->GetItemCount(); ++menu_index) {
+ int model_index = menu_index - first_item_index_;
+ SetMenuItemState(menu_index, model_->IsEnabledAt(model_index),
+ model_->IsItemCheckedAt(model_index), false);
+ if (model_->IsLabelDynamicAt(model_index)) {
+ SetMenuItemLabel(menu_index, model_index,
+ model_->GetLabelAt(model_index));
+ }
+ Menu2* submenu = items_.at(model_index)->submenu.get();
+ if (submenu)
+ submenu->UpdateStates();
+ }
+}
+
+gfx::NativeMenu NativeMenuWin::GetNativeMenu() const {
+ return menu_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeMenuWin, private:
+
+bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const {
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_FTYPE;
+ GetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
+ return !!(mii.fType & MF_SEPARATOR);
+}
+
+void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA;
+ if (!owner_draw_)
+ mii.fType = MFT_STRING;
+ else
+ mii.fType = MFT_OWNERDRAW;
+ mii.dwItemData = reinterpret_cast<ULONG_PTR>(this);
+
+ ItemData* item_data = new ItemData;
+ Menu2Model::ItemType type = model_->GetTypeAt(model_index);
+ if (type == Menu2Model::TYPE_SUBMENU) {
+ item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index),
+ delegate_));
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = item_data->submenu->GetNativeMenu();
+ } else {
+ if (type == Menu2Model::TYPE_RADIO)
+ mii.fType |= MFT_RADIOCHECK;
+ mii.wID = model_->GetCommandIdAt(model_index);
+ }
+ items_.insert(items_.begin() + model_index, item_data);
+ UpdateMenuItemInfoForString(&mii, model_index,
+ model_->GetLabelAt(model_index));
+ InsertMenuItem(menu_, menu_index, TRUE, &mii);
+}
+
+void NativeMenuWin::AddSeparatorItemAt(int menu_index, int model_index) {
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_FTYPE;
+ mii.fType = MFT_SEPARATOR;
+ // Insert a dummy entry into our label list so we can index directly into it
+ // using item indices if need be.
+ items_.insert(items_.begin() + model_index, new ItemData);
+ InsertMenuItem(menu_, menu_index, TRUE, &mii);
+}
+
+void NativeMenuWin::SetMenuItemState(int menu_index, bool enabled, bool checked,
+ bool is_default) {
+ if (IsSeparatorItemAt(menu_index))
+ return;
+
+ UINT state = enabled ? MFS_ENABLED : MFS_DISABLED;
+ if (checked)
+ state |= MFS_CHECKED;
+ if (is_default)
+ state |= MFS_DEFAULT;
+
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE;
+ mii.fState = state;
+ SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
+}
+
+void NativeMenuWin::SetMenuItemLabel(int menu_index,
+ int model_index,
+ const std::wstring& label) {
+ if (IsSeparatorItemAt(menu_index))
+ return;
+
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ UpdateMenuItemInfoForString(&mii, model_index, label);
+ if (!owner_draw_)
+ SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
+}
+
+void NativeMenuWin::UpdateMenuItemInfoForString(
+ MENUITEMINFO* mii,
+ int model_index,
+ const std::wstring& label) {
+ std::wstring formatted = label;
+ Menu2Model::ItemType type = model_->GetTypeAt(model_index);
+ if (type != Menu2Model::TYPE_SUBMENU) {
+ // Add accelerator details to the label if provided.
+ views::Accelerator accelerator(0, false, false, false);
+ if (model_->GetAcceleratorAt(model_index, &accelerator)) {
+ formatted += L"\t";
+ formatted += accelerator.GetShortcutText();
+ }
+ }
+
+ // Update the owned string, since Windows will want us to keep this new
+ // version around.
+ items_[model_index]->label = formatted;
+
+ // Windows only requires a pointer to the label string if it's going to be
+ // doing the drawing.
+ if (!owner_draw_) {
+ mii->fMask |= MIIM_STRING;
+ mii->dwTypeData =
+ const_cast<wchar_t*>(items_.at(model_index)->label.c_str());
+ }
+}
+
+NativeMenuWin* NativeMenuWin::GetMenuForCommandId(UINT command_id) const {
+ // Menus can have nested submenus. In the views Menu system, each submenu is
+ // wrapped in a NativeMenu instance, which may have a different model and
+ // delegate from the parent menu. The trouble is, RunMenuAt is called on the
+ // parent NativeMenuWin, and so it's not possible to assume that we can just
+ // dispatch the command id returned by TrackPopupMenuEx to the parent's
+ // delegate. For this reason, we stow a pointer on every menu item we create
+ // to the NativeMenuWin that most closely contains it. Fortunately, Windows
+ // provides GetMenuItemInfo, which can walk down the menu item tree from
+ // the root |menu_| to find the data for a given item even if it's in a
+ // submenu.
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA;
+ GetMenuItemInfo(menu_, command_id, FALSE, &mii);
+ return reinterpret_cast<NativeMenuWin*>(mii.dwItemData);
+}
+
+UINT NativeMenuWin::GetAlignmentFlags(int alignment) const {
+ bool rtl = l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT;
+ UINT alignment_flags = TPM_TOPALIGN;
+ if (alignment == Menu2::ALIGN_TOPLEFT)
+ alignment_flags |= TPM_LEFTALIGN;
+ else if (alignment == Menu2::ALIGN_TOPRIGHT)
+ alignment_flags |= TPM_RIGHTALIGN;
+ return alignment_flags;
+}
+
+void NativeMenuWin::ResetNativeMenu() {
+ if (IsWindow(system_menu_for_)) {
+ if (menu_)
+ GetSystemMenu(system_menu_for_, TRUE);
+ menu_ = GetSystemMenu(system_menu_for_, FALSE);
+ } else {
+ if (menu_)
+ DestroyMenu(menu_);
+ menu_ = CreatePopupMenu();
+ }
+}
+
+void NativeMenuWin::CreateHostWindow() {
+ if (!host_window_.get())
+ host_window_.reset(new MenuHostWindow());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SystemMenuModel:
+
+SystemMenuModel::SystemMenuModel(SimpleMenuModel::Delegate* delegate)
+ : SimpleMenuModel(delegate) {
+}
+
+SystemMenuModel::~SystemMenuModel() {
+}
+
+int SystemMenuModel::GetFirstItemIndex(gfx::NativeMenu native_menu) const {
+ // We allow insertions before last item (Close).
+ return std::max(0, GetMenuItemCount(native_menu) - 1);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MenuWrapper, public:
+
+// static
+MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) {
+ return new NativeMenuWin(menu->model(), menu->delegate(), NULL);
+}
+
+} // namespace views
diff --git a/views/controls/menu/native_menu_win.h b/views/controls/menu/native_menu_win.h
new file mode 100644
index 0000000..df0aa63
--- /dev/null
+++ b/views/controls/menu/native_menu_win.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
+#define VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
+
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "views/controls/menu/menu_wrapper.h"
+#include "views/controls/menu/simple_menu_model.h"
+
+namespace views {
+
+class Menu2Delegate;
+class Menu2Model;
+
+// A Windows implementation of MenuWrapper.
+// TODO(beng): rename to MenuWin once the old class is dead.
+class NativeMenuWin : public MenuWrapper {
+ public:
+ // Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
+ // is non-NULL, the NativeMenuWin wraps the system menu for that window.
+ // The caller owns the model and the delegate.
+ NativeMenuWin(Menu2Model* model,
+ Menu2Delegate* delegate,
+ HWND system_menu_for);
+ virtual ~NativeMenuWin();
+
+ // Overridden from MenuWrapper:
+ virtual void RunMenuAt(const gfx::Point& point, int alignment);
+ virtual void Rebuild();
+ virtual void UpdateStates();
+ virtual gfx::NativeMenu GetNativeMenu() const;
+
+ private:
+ // IMPORTANT: Note about indices.
+ // Functions in this class deal in two index spaces:
+ // 1. menu_index - the index of an item within the actual Windows
+ // native menu.
+ // 2. model_index - the index of the item within our model.
+ // These two are most often but not always the same value! The
+ // notable exception is when this object is used to wrap the
+ // Windows System Menu. In this instance, the model indices start
+ // at 0, but the insertion index into the existing menu is not.
+ // It is important to take this into consideration when editing the
+ // code in the functions in this class.
+
+ // Returns true if the item at the specified index is a separator.
+ bool IsSeparatorItemAt(int menu_index) const;
+
+ // Add items. See note above about indices.
+ void AddMenuItemAt(int menu_index, int model_index);
+ void AddSeparatorItemAt(int menu_index, int model_index);
+
+ // Sets the state of the item at the specified index.
+ void SetMenuItemState(int menu_index,
+ bool enabled,
+ bool checked,
+ bool is_default);
+
+ // Sets the label of the item at the specified index.
+ void SetMenuItemLabel(int menu_index,
+ int model_index,
+ const std::wstring& label);
+
+ // Updates the local data structure with the correctly formatted version of
+ // |label| at the specified model_index, and adds string data to |mii| if
+ // the menu is not owner-draw. That's a mouthful. This function exists because
+ // of the peculiarities of the Windows menu API.
+ void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
+ int model_index,
+ const std::wstring& label);
+
+ // Returns the NativeMenuWin object that contains an item with the specified
+ // command id. This function must only be called from RunMenuAt!
+ NativeMenuWin* GetMenuForCommandId(UINT command_id) const;
+
+ // Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
+ // supplied alignment and the UI text direction.
+ UINT GetAlignmentFlags(int alignment) const;
+
+ // Resets the native menu stored in |menu_| by destroying any old menu then
+ // creating a new empty one.
+ void ResetNativeMenu();
+
+ // Creates the host window that receives notifications from the menu.
+ void CreateHostWindow();
+
+ // Our attached model and delegate.
+ Menu2Model* model_;
+ Menu2Delegate* delegate_;
+
+ HMENU menu_;
+
+ // True if the contents of menu items in this menu are drawn by the menu host
+ // window, rather than Windows.
+ bool owner_draw_;
+
+ // An object that collects all of the data associated with an individual menu
+ // item.
+ struct ItemData;
+ std::vector<ItemData*> items_;
+
+ // The window that receives notifications from the menu.
+ class MenuHostWindow;
+ scoped_ptr<MenuHostWindow> host_window_;
+
+ // The HWND this menu is the system menu for, or NULL if the menu is not a
+ // system menu.
+ HWND system_menu_for_;
+
+ // The index of the first item in the model in the menu.
+ int first_item_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
+};
+
+// A SimpleMenuModel subclass that allows the system menu for a window to be
+// wrapped.
+class SystemMenuModel : public SimpleMenuModel {
+ public:
+ explicit SystemMenuModel(Delegate* delegate);
+ virtual ~SystemMenuModel();
+
+ // Overridden from Menu2Model:
+ virtual int GetFirstItemIndex(gfx::NativeMenu native_menu) const;
+
+ protected:
+ // Overridden from SimpleMenuModel:
+ virtual int FlipIndex(int index) const { return GetItemCount() - index - 1; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SystemMenuModel);
+};
+
+} // namespace views
+
+#endif // VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
diff --git a/views/controls/menu/simple_menu_model.cc b/views/controls/menu/simple_menu_model.cc
new file mode 100644
index 0000000..243b144
--- /dev/null
+++ b/views/controls/menu/simple_menu_model.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "views/controls/menu/simple_menu_model.h"
+
+#include "app/l10n_util.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// SimpleMenuModel, public:
+
+SimpleMenuModel::SimpleMenuModel(Delegate* delegate) : delegate_(delegate) {
+}
+
+SimpleMenuModel::~SimpleMenuModel() {
+}
+
+void SimpleMenuModel::AddItem(int command_id, const std::wstring& label) {
+ Item item = { command_id, label, TYPE_COMMAND, -1, NULL };
+ items_.push_back(item);
+}
+
+void SimpleMenuModel::AddItemWithStringId(int command_id, int string_id) {
+ AddItem(command_id, l10n_util::GetString(string_id));
+}
+
+void SimpleMenuModel::AddSeparator() {
+ Item item = { -1, std::wstring(), TYPE_SEPARATOR, -1, NULL };
+ items_.push_back(item);
+}
+
+void SimpleMenuModel::AddCheckItem(int command_id, const std::wstring& label) {
+ Item item = { command_id, label, TYPE_CHECK, -1, NULL };
+ items_.push_back(item);
+}
+
+void SimpleMenuModel::AddCheckItemWithStringId(int command_id, int string_id) {
+ AddCheckItem(command_id, l10n_util::GetString(string_id));
+}
+
+void SimpleMenuModel::AddRadioItem(int command_id, const std::wstring& label,
+ int group_id) {
+ Item item = { command_id, label, TYPE_RADIO, group_id, NULL };
+ items_.push_back(item);
+}
+
+void SimpleMenuModel::AddRadioItemWithStringId(int command_id, int string_id,
+ int group_id) {
+ AddRadioItem(command_id, l10n_util::GetString(string_id), group_id);
+}
+
+void SimpleMenuModel::AddSubMenu(const std::wstring& label, Menu2Model* model) {
+ Item item = { -1, label, TYPE_SUBMENU, -1, model };
+ items_.push_back(item);
+}
+
+void SimpleMenuModel::AddSubMenuWithStringId(int string_id, Menu2Model* model) {
+ AddSubMenu(l10n_util::GetString(string_id), model);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SimpleMenuModel, Menu2Model implementation:
+
+bool SimpleMenuModel::HasIcons() const {
+ return false;
+}
+
+int SimpleMenuModel::GetItemCount() const {
+ return static_cast<int>(items_.size());
+}
+
+Menu2Model::ItemType SimpleMenuModel::GetTypeAt(int index) const {
+ return items_.at(FlipIndex(index)).type;
+}
+
+int SimpleMenuModel::GetCommandIdAt(int index) const {
+ return items_.at(FlipIndex(index)).command_id;
+}
+
+std::wstring SimpleMenuModel::GetLabelAt(int index) const {
+ if (IsLabelDynamicAt(index))
+ return delegate_->GetLabelForCommandId(GetCommandIdAt(index));
+ return items_.at(FlipIndex(index)).label;
+}
+
+bool SimpleMenuModel::IsLabelDynamicAt(int index) const {
+ if (delegate_)
+ return delegate_->IsLabelForCommandIdDynamic(GetCommandIdAt(index));
+ return false;
+}
+
+bool SimpleMenuModel::GetAcceleratorAt(int index,
+ views::Accelerator* accelerator) const {
+ if (delegate_) {
+ return delegate_->GetAcceleratorForCommandId(GetCommandIdAt(index),
+ accelerator);
+ }
+ return false;
+}
+
+bool SimpleMenuModel::IsItemCheckedAt(int index) const {
+ if (!delegate_)
+ return false;
+ return delegate_->IsCommandIdChecked(GetCommandIdAt(index));
+}
+
+int SimpleMenuModel::GetGroupIdAt(int index) const {
+ return items_.at(FlipIndex(index)).group_id;
+}
+
+bool SimpleMenuModel::GetIconAt(int index, SkBitmap* icon) const {
+ return false;
+}
+
+bool SimpleMenuModel::IsEnabledAt(int index) const {
+ int command_id = GetCommandIdAt(index);
+ // Submenus have a command id of -1, they should always be enabled.
+ if (!delegate_ || command_id == -1)
+ return true;
+ return delegate_->IsCommandIdEnabled(command_id);
+}
+
+Menu2Model* SimpleMenuModel::GetSubmenuModelAt(int index) const {
+ return items_.at(FlipIndex(index)).submenu;
+}
+
+} // namespace views
diff --git a/views/controls/menu/simple_menu_model.h b/views/controls/menu/simple_menu_model.h
new file mode 100644
index 0000000..dbab73f
--- /dev/null
+++ b/views/controls/menu/simple_menu_model.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef CONTROLS_MENU_VIEWS_SIMPLE_MENU_MODEL_H_
+#define CONTROLS_MENU_VIEWS_SIMPLE_MENU_MODEL_H_
+
+#include <vector>
+
+#include "views/controls/menu/menu_2.h"
+
+namespace views {
+
+// A simple Menu2Model implementation with an imperative API for adding menu
+// items. This makes it easy to construct fixed menus. Menus populated by
+// dynamic data sources may be better off implementing Menu2Model directly.
+// The breadth of Menu2Model is not exposed through this API.
+class SimpleMenuModel : public Menu2Model {
+ public:
+ class Delegate {
+ public:
+ // Methods for determining the state of specific command ids.
+ virtual bool IsCommandIdChecked(int command_id) const = 0;
+ virtual bool IsCommandIdEnabled(int command_id) const = 0;
+
+ // Gets the accelerator for the specified command id. Returns true if the
+ // command id has a valid accelerator, false otherwise.
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ views::Accelerator* accelerator) = 0;
+
+ // Some command ids have labels that change over time.
+ virtual bool IsLabelForCommandIdDynamic(int command_id) const = 0;
+ virtual std::wstring GetLabelForCommandId(int command_id) const = 0;
+ };
+
+ // The Delegate can be NULL, though if it is items can't be checked or
+ // disabled.
+ explicit SimpleMenuModel(Delegate* delegate);
+ virtual ~SimpleMenuModel();
+
+ // Methods for adding items to the model.
+ void AddItem(int command_id, const std::wstring& label);
+ void AddItemWithStringId(int command_id, int string_id);
+ void AddSeparator();
+ void AddCheckItem(int command_id, const std::wstring& label);
+ void AddCheckItemWithStringId(int command_id, int string_id);
+ void AddRadioItem(int command_id, const std::wstring& label, int group_id);
+ void AddRadioItemWithStringId(int command_id, int string_id, int group_id);
+ void AddSubMenu(const std::wstring& label, Menu2Model* model);
+ void AddSubMenuWithStringId(int string_id, Menu2Model* model);
+
+ // Overridden from Menu2Model:
+ virtual bool HasIcons() const;
+ virtual int GetItemCount() const;
+ virtual ItemType GetTypeAt(int index) const;
+ virtual int GetCommandIdAt(int index) const;
+ virtual std::wstring GetLabelAt(int index) const;
+ virtual bool IsLabelDynamicAt(int index) const;
+ virtual bool GetAcceleratorAt(int index,
+ views::Accelerator* accelerator) const;
+ virtual bool IsItemCheckedAt(int index) const;
+ virtual int GetGroupIdAt(int index) const;
+ virtual bool GetIconAt(int index, SkBitmap* icon) const;
+ virtual bool IsEnabledAt(int index) const;
+ virtual Menu2Model* GetSubmenuModelAt(int index) const;
+
+ protected:
+ // Some variants of this model (SystemMenuModel) relies on items to be
+ // inserted backwards. This is counter-intuitive for the API, so rather than
+ // forcing customers to insert things backwards, we return the indices
+ // backwards instead. That's what this method is for. By default, it just
+ // returns what it's passed.
+ virtual int FlipIndex(int index) const { return index; }
+
+ private:
+ struct Item {
+ int command_id;
+ std::wstring label;
+ ItemType type;
+ int group_id;
+ Menu2Model* submenu;
+ };
+ std::vector<Item> items_;
+
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleMenuModel);
+};
+
+} // namespace views
+
+#endif // CONTROLS_MENU_VIEWS_SIMPLE_MENU_MODEL_H_
diff --git a/views/view.cc b/views/view.cc
index 985064cd..0280aef 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -943,7 +943,7 @@ void View::RemoveAccelerator(const Accelerator& accelerator) {
return;
}
- int index = iter - accelerators_->begin();
+ size_t index = iter - accelerators_->begin();
accelerators_->erase(iter);
if (index >= registered_accelerator_count_) {
// The accelerator is not registered to FocusManager.
diff --git a/views/view.h b/views/view.h
index 967ce22..8075378 100644
--- a/views/view.h
+++ b/views/view.h
@@ -1180,7 +1180,7 @@ class View : public AcceleratorTarget {
// [0, registered_accelerator_count_) are already registered to FocusManager,
// and the rest are not yet.
scoped_ptr<std::vector<Accelerator> > accelerators_;
- int registered_accelerator_count_;
+ size_t registered_accelerator_count_;
// The menu controller.
ContextMenuController* context_menu_controller_;
diff --git a/views/views.gyp b/views/views.gyp
index 97caf78..c0e63c8 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -103,10 +103,19 @@
'controls/menu/controller.h',
'controls/menu/menu.cc',
'controls/menu/menu.h',
+ 'controls/menu/menu_2.cc',
+ 'controls/menu/menu_2.h',
'controls/menu/menu_gtk.cc',
'controls/menu/menu_gtk.h',
'controls/menu/menu_win.cc',
'controls/menu/menu_win.h',
+ 'controls/menu/menu_wrapper.h',
+ 'controls/menu/native_menu_gtk.cc',
+ 'controls/menu/native_menu_gtk.h',
+ 'controls/menu/native_menu_win.cc',
+ 'controls/menu/native_menu_win.h',
+ 'controls/menu/simple_menu_model.cc',
+ 'controls/menu/simple_menu_model.h',
'controls/menu/view_menu_delegate.h',
'controls/message_box_view.cc',
'controls/message_box_view.h',