diff options
27 files changed, 910 insertions, 779 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc index be81645..35bd86b 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc @@ -469,7 +469,7 @@ AutocompleteEditViewWin::AutocompleteEditViewWin( SetDefaultCharFormat(cf); // Set up context menu. - context_menu_.reset(new Menu(this, Menu::TOPLEFT, m_hWnd)); + context_menu_.reset(views::Menu::Create(this, views::Menu::TOPLEFT, m_hWnd)); if (popup_window_mode_) { context_menu_->AppendMenuItemWithLabel(IDS_COPY, l10n_util::GetString(IDS_COPY)); diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h index 6c74cc9..7b00044 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h @@ -44,7 +44,7 @@ class AutocompleteEditViewWin CWinTraits<WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NOHIDESEL> >, public CRichEditCommands<AutocompleteEditViewWin>, - public Menu::Delegate, + public views::Menu::Delegate, public AutocompleteEditView { public: struct State { @@ -424,7 +424,7 @@ class AutocompleteEditViewWin CHARRANGE saved_selection_for_focus_change_; // The context menu for the edit. - scoped_ptr<Menu> context_menu_; + scoped_ptr<views::Menu> context_menu_; // Font we're using. We keep a reference to make sure the font supplied to // the constructor doesn't go away before we do. diff --git a/chrome/browser/back_forward_menu_model_win.h b/chrome/browser/back_forward_menu_model_win.h index e1805cb..ed308df 100644 --- a/chrome/browser/back_forward_menu_model_win.h +++ b/chrome/browser/back_forward_menu_model_win.h @@ -13,7 +13,7 @@ class SkBitmap; class BackForwardMenuModelWin : public BackForwardMenuModel, - public Menu::Delegate { + public views::Menu::Delegate { public: BackForwardMenuModelWin(Browser* browser, ModelType model_type); diff --git a/chrome/browser/encoding_menu_controller_delegate.cc b/chrome/browser/encoding_menu_controller_delegate.cc index 6faac2d..6e45ec8 100644 --- a/chrome/browser/encoding_menu_controller_delegate.cc +++ b/chrome/browser/encoding_menu_controller_delegate.cc @@ -53,7 +53,7 @@ void EncodingMenuControllerDelegate::ExecuteCommand(int id) { } void EncodingMenuControllerDelegate::BuildEncodingMenu( - Profile* profile, Menu* encoding_menu) { + Profile* profile, views::Menu* encoding_menu) { typedef EncodingMenuController::EncodingMenuItemList EncodingMenuItemList; EncodingMenuItemList menuItems; EncodingMenuController controller; @@ -62,7 +62,7 @@ void EncodingMenuControllerDelegate::BuildEncodingMenu( for (EncodingMenuItemList::iterator it = menuItems.begin(); it != menuItems.end(); ++it) { - Menu::MenuItemType type = Menu::RADIO; + views::Menu::MenuItemType type = views::Menu::RADIO; int id = it->first; std::wstring &localized_title = it->second; @@ -70,7 +70,7 @@ void EncodingMenuControllerDelegate::BuildEncodingMenu( encoding_menu->AppendSeparator(); } else { if (id == IDC_ENCODING_AUTO_DETECT) { - type = Menu::CHECKBOX; + type = views::Menu::CHECKBOX; } encoding_menu->AppendMenuItem(id, localized_title, type); diff --git a/chrome/browser/encoding_menu_controller_delegate.h b/chrome/browser/encoding_menu_controller_delegate.h index f35a5e4..b052fc8a 100644 --- a/chrome/browser/encoding_menu_controller_delegate.h +++ b/chrome/browser/encoding_menu_controller_delegate.h @@ -14,7 +14,7 @@ class Profile; // Encapsulates logic about populating the encoding menu and making // sure the correct items are checked. -class EncodingMenuControllerDelegate : public Menu::Delegate { +class EncodingMenuControllerDelegate : public views::Menu::Delegate { public: explicit EncodingMenuControllerDelegate(Browser* browser); @@ -29,7 +29,7 @@ class EncodingMenuControllerDelegate : public Menu::Delegate { // is used in both the simple frame menu and in the page menu in the // toolbar. (And probably elsewhere in the future, hence the // dedicated delegate). - static void BuildEncodingMenu(Profile* profile, Menu* encoding_menu); + static void BuildEncodingMenu(Profile* profile, views::Menu* encoding_menu); private: Browser* browser_; diff --git a/chrome/browser/tab_contents/render_view_context_menu_win.cc b/chrome/browser/tab_contents/render_view_context_menu_win.cc index 87dce53..dbb1ead 100644 --- a/chrome/browser/tab_contents/render_view_context_menu_win.cc +++ b/chrome/browser/tab_contents/render_view_context_menu_win.cc @@ -14,7 +14,7 @@ RenderViewContextMenuWin::RenderViewContextMenuWin( const ContextMenuParams& params, HWND owner) : RenderViewContextMenu(tab_contents, params), - ALLOW_THIS_IN_INITIALIZER_LIST(menu_(this, Menu::TOPLEFT, owner)), + ALLOW_THIS_IN_INITIALIZER_LIST(menu_(this, views::Menu::TOPLEFT, owner)), sub_menu_(NULL) { InitMenu(params.node); } @@ -27,26 +27,26 @@ void RenderViewContextMenuWin::RunMenuAt(int x, int y) { } void RenderViewContextMenuWin::AppendMenuItem(int id) { - AppendItem(id, l10n_util::GetString(id), Menu::NORMAL); + AppendItem(id, l10n_util::GetString(id), views::Menu::NORMAL); } void RenderViewContextMenuWin::AppendMenuItem(int id, const std::wstring& label) { - AppendItem(id, label, Menu::NORMAL); + AppendItem(id, label, views::Menu::NORMAL); } void RenderViewContextMenuWin::AppendRadioMenuItem(int id, const std::wstring& label) { - AppendItem(id, label, Menu::RADIO); + AppendItem(id, label, views::Menu::RADIO); } void RenderViewContextMenuWin::AppendCheckboxMenuItem(int id, const std::wstring& label) { - AppendItem(id, label, Menu::CHECKBOX); + AppendItem(id, label, views::Menu::CHECKBOX); } void RenderViewContextMenuWin::AppendSeparator() { - Menu* menu = sub_menu_ ? sub_menu_ : &menu_; + views::Menu* menu = sub_menu_ ? sub_menu_ : &menu_; menu->AppendSeparator(); } @@ -66,8 +66,8 @@ void RenderViewContextMenuWin::FinishSubMenu() { void RenderViewContextMenuWin::AppendItem( int id, const std::wstring& label, - Menu::MenuItemType type) { - Menu* menu = sub_menu_ ? sub_menu_ : &menu_; + views::Menu::MenuItemType type) { + views::Menu* menu = sub_menu_ ? sub_menu_ : &menu_; menu->AppendMenuItem(id, label, type); } diff --git a/chrome/browser/tab_contents/render_view_context_menu_win.h b/chrome/browser/tab_contents/render_view_context_menu_win.h index bc9578e..5d64342 100644 --- a/chrome/browser/tab_contents/render_view_context_menu_win.h +++ b/chrome/browser/tab_contents/render_view_context_menu_win.h @@ -7,10 +7,10 @@ #include "chrome/browser/tab_contents/render_view_context_menu.h" #include "views/accelerator.h" -#include "views/controls/menu/menu.h" +#include "views/controls/menu/menu_win.h" class RenderViewContextMenuWin : public RenderViewContextMenu, - public Menu::Delegate{ + public views::Menu::Delegate { public: RenderViewContextMenuWin(TabContents* tab_contents, const ContextMenuParams& params, @@ -39,10 +39,12 @@ class RenderViewContextMenuWin : public RenderViewContextMenu, private: // Append the item to |sub_menu_| if it exists, or |menu_| otherwise. - void AppendItem(int id, const std::wstring& label, Menu::MenuItemType type); + void AppendItem(int id, + const std::wstring& label, + views::Menu::MenuItemType type); - Menu menu_; - Menu* sub_menu_; + views::MenuWin menu_; + views::Menu* sub_menu_; }; #endif // CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_WIN_H_ diff --git a/chrome/browser/task_manager_win.cc b/chrome/browser/task_manager_win.cc index 9fa0eba..d20d5a2 100644 --- a/chrome/browser/task_manager_win.cc +++ b/chrome/browser/task_manager_win.cc @@ -167,7 +167,7 @@ class TaskManagerViewImpl : public TaskManagerView, public views::TableViewObserver, public views::LinkController, public views::ContextMenuController, - public Menu::Delegate { + public views::Menu::Delegate { public: TaskManagerViewImpl(TaskManager* task_manager, TaskManagerModel* model); @@ -498,12 +498,13 @@ void TaskManagerViewImpl::ShowContextMenu(views::View* source, int y, bool is_mouse_gesture) { UpdateStatsCounters(); - Menu menu(this, Menu::TOPLEFT, source->GetWidget()->GetNativeView()); + scoped_ptr<views::Menu> menu(views::Menu::Create( + this, views::Menu::TOPLEFT, source->GetWidget()->GetNativeView())); for (std::vector<views::TableColumn>::iterator i = columns_.begin(); i != columns_.end(); ++i) { - menu.AppendMenuItem(i->id, i->title, Menu::CHECKBOX); + menu->AppendMenuItem(i->id, i->title, views::Menu::CHECKBOX); } - menu.RunMenuAt(x, y); + menu->RunMenuAt(x, y); } bool TaskManagerViewImpl::IsItemChecked(int id) const { diff --git a/chrome/browser/views/blocked_popup_container.cc b/chrome/browser/views/blocked_popup_container.cc index 47e5f8e..b94adb1 100644 --- a/chrome/browser/views/blocked_popup_container.cc +++ b/chrome/browser/views/blocked_popup_container.cc @@ -179,8 +179,8 @@ gfx::Size BlockedPopupContainerView::GetPreferredSize() { void BlockedPopupContainerView::ButtonPressed(views::Button* sender) { if (sender == popup_count_label_) { - launch_menu_.reset(new Menu(this, Menu::TOPLEFT, - container_->GetNativeView())); + launch_menu_.reset(views::Menu::Create(this, views::Menu::TOPLEFT, + container_->GetNativeView())); // Set items 1 .. popup_count as individual popups. size_t popup_count = container_->GetBlockedPopupCount(); @@ -191,7 +191,7 @@ void BlockedPopupContainerView::ButtonPressed(views::Button* sender) { // the value 0 as the nop command. launch_menu_->AppendMenuItem(i + 1, l10n_util::GetStringF(IDS_POPUP_TITLE_FORMAT, url, title), - Menu::NORMAL); + views::Menu::NORMAL); } // Set items (kImpossibleNumberOfPopups + 1) .. @@ -201,7 +201,8 @@ void BlockedPopupContainerView::ButtonPressed(views::Button* sender) { launch_menu_->AppendSeparator(); for (size_t i = 0; i < hosts.size(); ++i) { launch_menu_->AppendMenuItem(kImpossibleNumberOfPopups + i + 1, - l10n_util::GetStringF(IDS_POPUP_HOST_FORMAT, hosts[i]), Menu::NORMAL); + l10n_util::GetStringF(IDS_POPUP_HOST_FORMAT, hosts[i]), + views::Menu::NORMAL); } CPoint cursor_position; diff --git a/chrome/browser/views/blocked_popup_container.h b/chrome/browser/views/blocked_popup_container.h index 640bdd0..dcf7d8f 100644 --- a/chrome/browser/views/blocked_popup_container.h +++ b/chrome/browser/views/blocked_popup_container.h @@ -39,7 +39,7 @@ class ImageButton; // blocked. This view should only be used inside of BlockedPopupContainer. class BlockedPopupContainerView : public views::View, public views::ButtonListener, - public Menu::Delegate { + public views::Menu::Delegate { public: explicit BlockedPopupContainerView(BlockedPopupContainer* container); ~BlockedPopupContainerView(); @@ -79,7 +79,7 @@ class BlockedPopupContainerView : public views::View, views::ImageButton* close_button_; // Popup menu shown to user. - scoped_ptr<Menu> launch_menu_; + scoped_ptr<views::Menu> launch_menu_; DISALLOW_IMPLICIT_CONSTRUCTORS(BlockedPopupContainerView); }; diff --git a/chrome/browser/views/bookmark_bar_view.h b/chrome/browser/views/bookmark_bar_view.h index ccf787e..1986d2f 100644 --- a/chrome/browser/views/bookmark_bar_view.h +++ b/chrome/browser/views/bookmark_bar_view.h @@ -42,7 +42,7 @@ class BookmarkBarView : public views::View, public BookmarkModelObserver, public views::ViewMenuDelegate, public views::ButtonListener, - public Menu::Delegate, + public views::Menu::Delegate, public NotificationObserver, public views::ContextMenuController, public views::DragController, diff --git a/chrome/browser/views/bookmark_editor_view.cc b/chrome/browser/views/bookmark_editor_view.cc index 0aee8bc..835ba59 100644 --- a/chrome/browser/views/bookmark_editor_view.cc +++ b/chrome/browser/views/bookmark_editor_view.cc @@ -225,8 +225,8 @@ void BookmarkEditorView::ShowContextMenu(View* source, running_menu_for_root_ = (tree_model_->GetParent(tree_view_->GetSelectedNode()) == tree_model_->GetRoot()); - context_menu_.reset(new Menu(this, Menu::TOPLEFT, - GetWidget()->GetNativeView())); + context_menu_.reset(views::Menu::Create(this, views::Menu::TOPLEFT, + GetWidget()->GetNativeView())); context_menu_->AppendMenuItemWithLabel(IDS_EDIT, l10n_util::GetString(IDS_EDIT)); context_menu_->AppendMenuItemWithLabel( diff --git a/chrome/browser/views/bookmark_editor_view.h b/chrome/browser/views/bookmark_editor_view.h index 4ca3fde..754e5f8 100644 --- a/chrome/browser/views/bookmark_editor_view.h +++ b/chrome/browser/views/bookmark_editor_view.h @@ -40,7 +40,7 @@ class BookmarkEditorView : public BookmarkEditor, public views::DialogDelegate, public views::TextField::Controller, public views::ContextMenuController, - public Menu::Delegate, + public views::Menu::Delegate, public BookmarkModelObserver { FRIEND_TEST(BookmarkEditorViewTest, ChangeParent); FRIEND_TEST(BookmarkEditorViewTest, ChangeParentAndURL); @@ -243,7 +243,7 @@ class BookmarkEditorView : public BookmarkEditor, BookmarkNode* node_; // The context menu. - scoped_ptr<Menu> context_menu_; + scoped_ptr<views::Menu> context_menu_; // Mode used to create nodes from. BookmarkModel* bb_model_; diff --git a/chrome/browser/views/download_item_view.cc b/chrome/browser/views/download_item_view.cc index 7aa2a37..1e9554f 100644 --- a/chrome/browser/views/download_item_view.cc +++ b/chrome/browser/views/download_item_view.cc @@ -65,7 +65,7 @@ static const int kDisabledOnOpenDuration = 3000; // DownloadShelfContextMenuWin ------------------------------------------------- class DownloadShelfContextMenuWin : public DownloadShelfContextMenu, - public Menu::Delegate { + public views::Menu::Delegate { public: DownloadShelfContextMenuWin::DownloadShelfContextMenuWin( BaseDownloadItemModel* model, @@ -75,23 +75,27 @@ class DownloadShelfContextMenuWin : public DownloadShelfContextMenu, DCHECK(model); // The menu's anchor point is determined based on the UI layout. - Menu::AnchorPoint anchor_point; + views::Menu::AnchorPoint anchor_point; if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) - anchor_point = Menu::TOPRIGHT; + anchor_point = views::Menu::TOPRIGHT; else - anchor_point = Menu::TOPLEFT; + anchor_point = views::Menu::TOPLEFT; - Menu context_menu(this, anchor_point, window); - if (download_->state() == DownloadItem::COMPLETE) - context_menu.AppendMenuItem(OPEN_WHEN_COMPLETE, L"", Menu::NORMAL); - else - context_menu.AppendMenuItem(OPEN_WHEN_COMPLETE, L"", Menu::CHECKBOX); - context_menu.AppendMenuItem(ALWAYS_OPEN_TYPE, L"", Menu::CHECKBOX); - context_menu.AppendSeparator(); - context_menu.AppendMenuItem(SHOW_IN_FOLDER, L"", Menu::NORMAL); - context_menu.AppendSeparator(); - context_menu.AppendMenuItem(CANCEL, L"", Menu::NORMAL); - context_menu.RunMenuAt(point.x(), point.y()); + scoped_ptr<views::Menu> context_menu( + views::Menu::Create(this, anchor_point, window)); + if (download_->state() == DownloadItem::COMPLETE) { + context_menu->AppendMenuItem(OPEN_WHEN_COMPLETE, L"", + views::Menu::NORMAL); + } else { + context_menu->AppendMenuItem(OPEN_WHEN_COMPLETE, L"", + views::Menu::CHECKBOX); + } + context_menu->AppendMenuItem(ALWAYS_OPEN_TYPE, L"", views::Menu::CHECKBOX); + context_menu->AppendSeparator(); + context_menu->AppendMenuItem(SHOW_IN_FOLDER, L"", views::Menu::NORMAL); + context_menu->AppendSeparator(); + context_menu->AppendMenuItem(CANCEL, L"", views::Menu::NORMAL); + context_menu->RunMenuAt(point.x(), point.y()); } // Menu::Delegate implementation --------------------------------------------- diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index b3aa486..a438cdf 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -60,6 +60,7 @@ #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "grit/webkit_resources.h" +#include "views/controls/menu/menu_win.h" #include "views/controls/scrollbar/native_scroll_bar.h" #include "views/fill_layout.h" #include "views/view.h" @@ -1298,7 +1299,7 @@ void BrowserView::Init() { void BrowserView::InitSystemMenu() { HMENU system_menu = GetSystemMenu(frame_->GetNativeView(), FALSE); - system_menu_.reset(new Menu(system_menu)); + system_menu_.reset(new views::MenuWin(system_menu)); int insertion_index = std::max(0, system_menu_->ItemCount() - 1); // We add the menu items in reverse order so that insertion_index never needs // to change. @@ -1549,7 +1550,7 @@ void BrowserView::LoadAccelerators() { free(accelerators); } -void BrowserView::BuildMenuForTabStriplessWindow(Menu* menu, +void BrowserView::BuildMenuForTabStriplessWindow(views::Menu* menu, int insertion_index) { encoding_menu_delegate_.reset(new EncodingMenuControllerDelegate( browser_.get())); @@ -1560,7 +1561,7 @@ void BrowserView::BuildMenuForTabStriplessWindow(Menu* menu, } else { int command = kMenuLayout[i].command; if (command == IDC_ENCODING_MENU) { - Menu* encoding_menu = menu->AddSubMenu( + views::Menu* encoding_menu = menu->AddSubMenu( insertion_index, IDC_ENCODING_MENU, l10n_util::GetString(IDS_ENCODING_MENU)); @@ -1568,8 +1569,9 @@ void BrowserView::BuildMenuForTabStriplessWindow(Menu* menu, EncodingMenuControllerDelegate::BuildEncodingMenu(browser_->profile(), encoding_menu); } else if (command == IDC_ZOOM_MENU) { - Menu* zoom_menu = menu->AddSubMenu(insertion_index, IDC_ZOOM_MENU, - l10n_util::GetString(IDS_ZOOM_MENU)); + views::Menu* zoom_menu = + menu->AddSubMenu(insertion_index, IDC_ZOOM_MENU, + l10n_util::GetString(IDS_ZOOM_MENU)); zoom_menu->AppendMenuItemWithLabel( IDC_ZOOM_PLUS, l10n_util::GetString(IDS_ZOOM_PLUS)); diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index 40afbc5..c3e0734 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -25,10 +25,13 @@ class ExtensionShelf; class FullscreenExitBubble; class HtmlDialogUIDelegate; class InfoBarContainer; -class Menu; class StatusBubbleViews; class TabContentsContainerView; +namespace views { +class Menu; +} + /////////////////////////////////////////////////////////////////////////////// // BrowserView // @@ -316,7 +319,7 @@ class BrowserView : public BrowserWindow, void LoadAccelerators(); // Builds the correct menu for when we have minimal chrome. - void BuildMenuForTabStriplessWindow(Menu* menu, int insertion_index); + void BuildMenuForTabStriplessWindow(views::Menu* menu, int insertion_index); // Retrieves the command id for the specified Windows app command. int GetCommandIDForAppCommandID(int app_command_id) const; @@ -376,7 +379,7 @@ class BrowserView : public BrowserWindow, scoped_ptr<FullscreenExitBubble> fullscreen_bubble_; // Lazily created representation of the system menu. - scoped_ptr<Menu> system_menu_; + scoped_ptr<views::Menu> system_menu_; // The default favicon image. static SkBitmap default_favicon_; diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc index 104cb34..5162b98 100644 --- a/chrome/browser/views/toolbar_view.cc +++ b/chrome/browser/views/toolbar_view.cc @@ -583,28 +583,28 @@ gfx::Size BrowserToolbarView::GetPreferredSize() { } void BrowserToolbarView::RunPageMenu(const gfx::Point& pt, HWND hwnd) { - Menu::AnchorPoint anchor = Menu::TOPRIGHT; + views::Menu::AnchorPoint anchor = views::Menu::TOPRIGHT; if (UILayoutIsRightToLeft()) - anchor = Menu::TOPLEFT; + anchor = views::Menu::TOPLEFT; - Menu menu(this, anchor, hwnd); - menu.AppendMenuItemWithLabel(IDC_CREATE_SHORTCUTS, + scoped_ptr<views::Menu> menu(views::Menu::Create(this, anchor, hwnd)); + menu->AppendMenuItemWithLabel(IDC_CREATE_SHORTCUTS, l10n_util::GetString(IDS_CREATE_SHORTCUTS)); - menu.AppendSeparator(); - menu.AppendMenuItemWithLabel(IDC_CUT, l10n_util::GetString(IDS_CUT)); - menu.AppendMenuItemWithLabel(IDC_COPY, l10n_util::GetString(IDS_COPY)); - menu.AppendMenuItemWithLabel(IDC_PASTE, l10n_util::GetString(IDS_PASTE)); - menu.AppendSeparator(); - - menu.AppendMenuItemWithLabel(IDC_FIND, - l10n_util::GetString(IDS_FIND)); - menu.AppendMenuItemWithLabel(IDC_SAVE_PAGE, - l10n_util::GetString(IDS_SAVE_PAGE)); - menu.AppendMenuItemWithLabel(IDC_PRINT, l10n_util::GetString(IDS_PRINT)); - menu.AppendSeparator(); - - Menu* zoom_menu = menu.AppendSubMenu(IDC_ZOOM_MENU, - l10n_util::GetString(IDS_ZOOM_MENU)); + menu->AppendSeparator(); + menu->AppendMenuItemWithLabel(IDC_CUT, l10n_util::GetString(IDS_CUT)); + menu->AppendMenuItemWithLabel(IDC_COPY, l10n_util::GetString(IDS_COPY)); + menu->AppendMenuItemWithLabel(IDC_PASTE, l10n_util::GetString(IDS_PASTE)); + menu->AppendSeparator(); + + menu->AppendMenuItemWithLabel(IDC_FIND, + l10n_util::GetString(IDS_FIND)); + menu->AppendMenuItemWithLabel(IDC_SAVE_PAGE, + l10n_util::GetString(IDS_SAVE_PAGE)); + menu->AppendMenuItemWithLabel(IDC_PRINT, l10n_util::GetString(IDS_PRINT)); + menu->AppendSeparator(); + + views::Menu* zoom_menu = menu->AppendSubMenu( + IDC_ZOOM_MENU, l10n_util::GetString(IDS_ZOOM_MENU)); zoom_menu->AppendMenuItemWithLabel(IDC_ZOOM_PLUS, l10n_util::GetString(IDS_ZOOM_PLUS)); zoom_menu->AppendMenuItemWithLabel(IDC_ZOOM_NORMAL, @@ -613,7 +613,7 @@ void BrowserToolbarView::RunPageMenu(const gfx::Point& pt, HWND hwnd) { l10n_util::GetString(IDS_ZOOM_MINUS)); // Create encoding menu. - Menu* encoding_menu = menu.AppendSubMenu( + views::Menu* encoding_menu = menu->AppendSubMenu( IDC_ENCODING_MENU, l10n_util::GetString(IDS_ENCODING_MENU)); EncodingMenuControllerDelegate::BuildEncodingMenu(profile_, encoding_menu); @@ -629,8 +629,8 @@ void BrowserToolbarView::RunPageMenu(const gfx::Point& pt, HWND hwnd) { { IDC_TASK_MANAGER, IDS_TASK_MANAGER } }; // Append developer menu. - menu.AppendSeparator(); - Menu* developer_menu = menu.AppendSubMenu(IDC_DEVELOPER_MENU, + menu->AppendSeparator(); + views::Menu* developer_menu = menu->AppendSubMenu(IDC_DEVELOPER_MENU, l10n_util::GetString(IDS_DEVELOPER_MENU)); for (int i = 0; i < arraysize(developer_menu_materials); ++i) { if (developer_menu_materials[i].menu_id) { @@ -642,24 +642,24 @@ void BrowserToolbarView::RunPageMenu(const gfx::Point& pt, HWND hwnd) { } } - menu.AppendSeparator(); + menu->AppendSeparator(); - menu.AppendMenuItemWithLabel(IDC_REPORT_BUG, + menu->AppendMenuItemWithLabel(IDC_REPORT_BUG, l10n_util::GetString(IDS_REPORT_BUG)); - menu.RunMenuAt(pt.x(), pt.y()); + menu->RunMenuAt(pt.x(), pt.y()); } void BrowserToolbarView::RunAppMenu(const gfx::Point& pt, HWND hwnd) { - Menu::AnchorPoint anchor = Menu::TOPRIGHT; + views::Menu::AnchorPoint anchor = views::Menu::TOPRIGHT; if (UILayoutIsRightToLeft()) - anchor = Menu::TOPLEFT; + anchor = views::Menu::TOPLEFT; - Menu menu(this, anchor, hwnd); - menu.AppendMenuItemWithLabel(IDC_NEW_TAB, l10n_util::GetString(IDS_NEW_TAB)); - menu.AppendMenuItemWithLabel(IDC_NEW_WINDOW, - l10n_util::GetString(IDS_NEW_WINDOW)); - menu.AppendMenuItemWithLabel(IDC_NEW_INCOGNITO_WINDOW, - l10n_util::GetString(IDS_NEW_INCOGNITO_WINDOW)); + scoped_ptr<views::Menu> menu(views::Menu::Create(this, anchor, hwnd)); + menu->AppendMenuItemWithLabel(IDC_NEW_TAB, l10n_util::GetString(IDS_NEW_TAB)); + menu->AppendMenuItemWithLabel(IDC_NEW_WINDOW, + l10n_util::GetString(IDS_NEW_WINDOW)); + menu->AppendMenuItemWithLabel(IDC_NEW_INCOGNITO_WINDOW, + l10n_util::GetString(IDS_NEW_INCOGNITO_WINDOW)); // Enumerate profiles asynchronously and then create the parent menu item. // We will create the child menu items for this once the asynchronous call is @@ -667,44 +667,44 @@ void BrowserToolbarView::RunAppMenu(const gfx::Point& pt, HWND hwnd) { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); if (command_line.HasSwitch(switches::kEnableUserDataDirProfiles)) { profiles_helper_->GetProfiles(NULL); - profiles_menu_ = menu.AppendSubMenu(IDC_PROFILE_MENU, - l10n_util::GetString(IDS_PROFILE_MENU)); + profiles_menu_ = menu->AppendSubMenu( + IDC_PROFILE_MENU, l10n_util::GetString(IDS_PROFILE_MENU)); } - menu.AppendSeparator(); - menu.AppendMenuItemWithLabel(IDC_SHOW_BOOKMARK_BAR, - l10n_util::GetString(IDS_SHOW_BOOKMARK_BAR)); - menu.AppendMenuItemWithLabel(IDC_FULLSCREEN, - l10n_util::GetString(IDS_FULLSCREEN)); - menu.AppendSeparator(); - menu.AppendMenuItemWithLabel(IDC_SHOW_HISTORY, - l10n_util::GetString(IDS_SHOW_HISTORY)); - menu.AppendMenuItemWithLabel(IDC_SHOW_BOOKMARK_MANAGER, - l10n_util::GetString(IDS_BOOKMARK_MANAGER)); - menu.AppendMenuItemWithLabel(IDC_SHOW_DOWNLOADS, - l10n_util::GetString(IDS_SHOW_DOWNLOADS)); - menu.AppendSeparator(); + menu->AppendSeparator(); + menu->AppendMenuItemWithLabel(IDC_SHOW_BOOKMARK_BAR, + l10n_util::GetString(IDS_SHOW_BOOKMARK_BAR)); + menu->AppendMenuItemWithLabel(IDC_FULLSCREEN, + l10n_util::GetString(IDS_FULLSCREEN)); + menu->AppendSeparator(); + menu->AppendMenuItemWithLabel(IDC_SHOW_HISTORY, + l10n_util::GetString(IDS_SHOW_HISTORY)); + menu->AppendMenuItemWithLabel(IDC_SHOW_BOOKMARK_MANAGER, + l10n_util::GetString(IDS_BOOKMARK_MANAGER)); + menu->AppendMenuItemWithLabel(IDC_SHOW_DOWNLOADS, + l10n_util::GetString(IDS_SHOW_DOWNLOADS)); + menu->AppendSeparator(); #ifdef CHROME_PERSONALIZATION if (!Personalization::IsP13NDisabled()) { - menu.AppendMenuItemWithLabel(IDC_P13N_INFO, + menu->AppendMenuItemWithLabel(IDC_P13N_INFO, Personalization::GetMenuItemInfoText(browser())); } #endif - menu.AppendMenuItemWithLabel(IDC_CLEAR_BROWSING_DATA, - l10n_util::GetString(IDS_CLEAR_BROWSING_DATA)); - menu.AppendMenuItemWithLabel(IDC_IMPORT_SETTINGS, - l10n_util::GetString(IDS_IMPORT_SETTINGS)); - menu.AppendSeparator(); - menu.AppendMenuItemWithLabel(IDC_OPTIONS, l10n_util::GetStringF(IDS_OPTIONS, - l10n_util::GetString(IDS_PRODUCT_NAME))); - menu.AppendMenuItemWithLabel(IDC_ABOUT, l10n_util::GetStringF(IDS_ABOUT, - l10n_util::GetString(IDS_PRODUCT_NAME))); - menu.AppendMenuItemWithLabel(IDC_HELP_PAGE, - l10n_util::GetString(IDS_HELP_PAGE)); - menu.AppendSeparator(); - menu.AppendMenuItemWithLabel(IDC_EXIT, l10n_util::GetString(IDS_EXIT)); - - menu.RunMenuAt(pt.x(), pt.y()); + menu->AppendMenuItemWithLabel(IDC_CLEAR_BROWSING_DATA, + l10n_util::GetString(IDS_CLEAR_BROWSING_DATA)); + menu->AppendMenuItemWithLabel(IDC_IMPORT_SETTINGS, + l10n_util::GetString(IDS_IMPORT_SETTINGS)); + menu->AppendSeparator(); + menu->AppendMenuItemWithLabel(IDC_OPTIONS, l10n_util::GetStringF(IDS_OPTIONS, + l10n_util::GetString(IDS_PRODUCT_NAME))); + menu->AppendMenuItemWithLabel(IDC_ABOUT, l10n_util::GetStringF(IDS_ABOUT, + l10n_util::GetString(IDS_PRODUCT_NAME))); + menu->AppendMenuItemWithLabel(IDC_HELP_PAGE, + l10n_util::GetString(IDS_HELP_PAGE)); + menu->AppendSeparator(); + menu->AppendMenuItemWithLabel(IDC_EXIT, l10n_util::GetString(IDS_EXIT)); + + menu->RunMenuAt(pt.x(), pt.y()); // Menu is going away, so set the profiles menu pointer to NULL. profiles_menu_ = NULL; diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h index ad373d4..64feb34 100644 --- a/chrome/browser/views/toolbar_view.h +++ b/chrome/browser/views/toolbar_view.h @@ -202,7 +202,7 @@ class BrowserToolbarView : public views::View, TabContents* tab_; // Profiles menu to populate with profile names. - Menu* profiles_menu_; + views::Menu* profiles_menu_; // Helper class to enumerate profiles information on the file thread. scoped_refptr<GetProfilesHelper> profiles_helper_; diff --git a/chrome/common/temp_scaffolding_stubs.h b/chrome/common/temp_scaffolding_stubs.h index fe22906..eda42e8 100644 --- a/chrome/common/temp_scaffolding_stubs.h +++ b/chrome/common/temp_scaffolding_stubs.h @@ -247,6 +247,8 @@ class Window { class InputWindowDelegate { }; +namespace views { + class Menu { public: enum AnchorPoint { @@ -279,6 +281,8 @@ class Menu { void AppendDelegateMenuItem(int item_id) { NOTIMPLEMENTED(); } }; +} // namespace view + class BookmarkManagerView { public: static BookmarkManagerView* current() { diff --git a/views/controls/button/button_dropdown.cc b/views/controls/button/button_dropdown.cc index 157caf0..6c81c24 100644 --- a/views/controls/button/button_dropdown.cc +++ b/views/controls/button/button_dropdown.cc @@ -137,7 +137,7 @@ void ButtonDropDown::ShowDropDownMenu(HWND window) { if (menu_position.x() < left_bound) menu_position.set_x(left_bound); - Menu menu(menu_delegate_, anchor, window); + scoped_ptr<Menu> menu(Menu::Create(menu_delegate_, anchor, window)); // ID's for AppendMenu is 1-based because RunMenu will ignore the user // selection if id=0 is selected (0 = NO-OP) so we add 1 here and subtract 1 @@ -145,16 +145,16 @@ void ButtonDropDown::ShowDropDownMenu(HWND window) { int item_count = menu_delegate_->GetItemCount(); for (int i = 0; i < item_count; i++) { if (menu_delegate_->IsItemSeparator(i + 1)) { - menu.AppendSeparator(); + menu->AppendSeparator(); } else { if (menu_delegate_->HasIcon(i + 1)) - menu.AppendMenuItemWithIcon(i + 1, L"", SkBitmap()); + menu->AppendMenuItemWithIcon(i + 1, L"", SkBitmap()); else - menu.AppendMenuItem(i+1, L"", Menu::NORMAL); + menu->AppendMenuItem(i+1, L"", Menu::NORMAL); } } - menu.RunMenuAt(menu_position.x(), menu_position.y()); + menu->RunMenuAt(menu_position.x(), menu_position.y()); // Need to explicitly clear mouse handler so that events get sent // properly after the menu finishes running. If we don't do this, then diff --git a/views/controls/menu/menu.cc b/views/controls/menu/menu.cc index 1597da5..6a81d9c 100644 --- a/views/controls/menu/menu.cc +++ b/views/controls/menu/menu.cc @@ -4,353 +4,31 @@ #include "views/controls/menu/menu.h" -#include <atlbase.h> -#include <atlapp.h> -#include <atlwin.h> -#include <atlcrack.h> -#include <atlframe.h> -#include <atlmisc.h> -#include <string> - -#include "app/gfx/chrome_canvas.h" -#include "app/gfx/chrome_font.h" #include "app/l10n_util.h" -#include "app/l10n_util_win.h" -#include "base/gfx/rect.h" -#include "base/logging.h" -#include "base/stl_util-inl.h" -#include "base/string_util.h" -#include "views/accelerator.h" - -const SkBitmap* Menu::Delegate::kEmptyIcon = 0; - -// The width of an icon, including the pixels between the icon and -// the item label. -static const int kIconWidth = 23; -// Margins between the top of the item and the label. -static const int kItemTopMargin = 3; -// Margins between the bottom of the item and the label. -static const int kItemBottomMargin = 4; -// Margins between the left of the item and the icon. -static const int kItemLeftMargin = 4; -// Margins between the right of the item and the label. -static const int kItemRightMargin = 10; -// The width for displaying the sub-menu arrow. -static const int kArrowWidth = 10; - -// Current active MenuHostWindow. If NULL, no menu is active. -static MenuHostWindow* active_host_window = NULL; - -// The data of menu items needed to display. -struct Menu::ItemData { - std::wstring label; - SkBitmap icon; - bool submenu; -}; - -namespace { - -static int ChromeGetMenuItemID(HMENU hMenu, int pos) { - // The built-in Windows ::GetMenuItemID doesn't work for submenus, - // so here's our own implementation. - MENUITEMINFO mii = {0}; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_ID; - GetMenuItemInfo(hMenu, pos, TRUE, &mii); - return mii.wID; -} - -// MenuHostWindow ------------------------------------------------------------- - -// MenuHostWindow is the HWND the HMENU is parented to. MenuHostWindow is used -// to intercept right clicks on the HMENU and notify the delegate as well as -// for drawing icons. -// -class MenuHostWindow : public CWindowImpl<MenuHostWindow, CWindow, - CWinTraits<WS_CHILD>> { - public: - MenuHostWindow(Menu* menu, HWND parent_window) : menu_(menu) { - int extended_style = 0; - // If the menu needs to be created with a right-to-left UI layout, we must - // set the appropriate RTL flags (such as WS_EX_LAYOUTRTL) property for the - // underlying HWND. - if (menu_->delegate_->IsRightToLeftUILayout()) - extended_style |= l10n_util::GetExtendedStyles(); - Create(parent_window, gfx::Rect().ToRECT(), 0, 0, extended_style); - } - - ~MenuHostWindow() { - DestroyWindow(); - } - - DECLARE_FRAME_WND_CLASS(L"MenuHostWindow", NULL); - BEGIN_MSG_MAP(MenuHostWindow); - MSG_WM_RBUTTONUP(OnRButtonUp) - MSG_WM_MEASUREITEM(OnMeasureItem) - MSG_WM_DRAWITEM(OnDrawItem) - END_MSG_MAP(); - - private: - // NOTE: I really REALLY tried to use WM_MENURBUTTONUP, but I ran into - // two problems in using it: - // 1. It doesn't contain the coordinates of the mouse. - // 2. It isn't invoked for menuitems representing a submenu that have children - // menu items (not empty). - - void OnRButtonUp(UINT w_param, const CPoint& loc) { - int id; - if (menu_->delegate_ && FindMenuIDByLocation(menu_, loc, &id)) - menu_->delegate_->ShowContextMenu(menu_, id, loc.x, loc.y, true); - } - - void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* lpmis) { - Menu::ItemData* data = reinterpret_cast<Menu::ItemData*>(lpmis->itemData); - if (data != NULL) { - ChromeFont font; - lpmis->itemWidth = font.GetStringWidth(data->label) + kIconWidth + - kItemLeftMargin + kItemRightMargin - - GetSystemMetrics(SM_CXMENUCHECK); - if (data->submenu) - lpmis->itemWidth += kArrowWidth; - // If the label contains an accelerator, make room for tab. - if (data->label.find(L'\t') != std::wstring::npos) - lpmis->itemWidth += font.GetStringWidth(L" "); - lpmis->itemHeight = font.height() + kItemBottomMargin + kItemTopMargin; - } else { - // Measure separator size. - lpmis->itemHeight = GetSystemMetrics(SM_CYMENU) / 2; - lpmis->itemWidth = 0; - } - } - - void OnDrawItem(UINT wParam, DRAWITEMSTRUCT* lpdis) { - HDC hDC = lpdis->hDC; - COLORREF prev_bg_color, prev_text_color; - - // Set background color and text color - if (lpdis->itemState & ODS_SELECTED) { - prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT)); - prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } else { - prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_MENU)); - if (lpdis->itemState & ODS_DISABLED) - prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT)); - else - prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT)); - } - - if (lpdis->itemData) { - Menu::ItemData* data = - reinterpret_cast<Menu::ItemData*>(lpdis->itemData); - - // Draw the background. - HBRUSH hbr = CreateSolidBrush(GetBkColor(hDC)); - FillRect(hDC, &lpdis->rcItem, hbr); - DeleteObject(hbr); - - // Draw the label. - RECT rect = lpdis->rcItem; - rect.top += kItemTopMargin; - // Should we add kIconWidth only when icon.width() != 0 ? - rect.left += kItemLeftMargin + kIconWidth; - rect.right -= kItemRightMargin; - UINT format = DT_TOP | DT_SINGLELINE; - // Check whether the mnemonics should be underlined. - BOOL underline_mnemonics; - SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0); - if (!underline_mnemonics) - format |= DT_HIDEPREFIX; - ChromeFont font; - HGDIOBJ old_font = static_cast<HFONT>(SelectObject(hDC, font.hfont())); - int fontsize = font.FontSize(); - - // If an accelerator is specified (with a tab delimiting the rest of the - // label from the accelerator), we have to justify the fist part on the - // left and the accelerator on the right. - // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the - // window system UI font and will not hit here. - std::wstring label = data->label; - std::wstring accel; - std::wstring::size_type tab_pos = label.find(L'\t'); - if (tab_pos != std::wstring::npos) { - accel = label.substr(tab_pos); - label = label.substr(0, tab_pos); - } - DrawTextEx(hDC, const_cast<wchar_t*>(label.data()), - static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL); - if (!accel.empty()) - DrawTextEx(hDC, const_cast<wchar_t*>(accel.data()), - static_cast<int>(accel.size()), &rect, - format | DT_RIGHT, NULL); - SelectObject(hDC, old_font); +#include "third_party/skia/include/core/SkBitmap.h" - // Draw the icon after the label, otherwise it would be covered - // by the label. - if (data->icon.width() != 0 && data->icon.height() != 0) { - ChromeCanvas canvas(data->icon.width(), data->icon.height(), false); - canvas.drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode); - canvas.DrawBitmapInt(data->icon, 0, 0); - canvas.getTopPlatformDevice().drawToHDC(hDC, lpdis->rcItem.left + - kItemLeftMargin, lpdis->rcItem.top + (lpdis->rcItem.bottom - - lpdis->rcItem.top - data->icon.height()) / 2, NULL); - } - - } else { - // Draw the separator - lpdis->rcItem.top += (lpdis->rcItem.bottom - lpdis->rcItem.top) / 3; - DrawEdge(hDC, &lpdis->rcItem, EDGE_ETCHED, BF_TOP); - } - - SetBkColor(hDC, prev_bg_color); - SetTextColor(hDC, prev_text_color); - } - - bool FindMenuIDByLocation(Menu* menu, const CPoint& loc, int* id) { - int index = MenuItemFromPoint(NULL, menu->menu_, loc); - if (index != -1) { - *id = ChromeGetMenuItemID(menu->menu_, index); - return true; - } else { - for (std::vector<Menu*>::iterator i = menu->submenus_.begin(); - i != menu->submenus_.end(); ++i) { - if (FindMenuIDByLocation(*i, loc, id)) - return true; - } - } - return false; - } - - // The menu that created us. - Menu* menu_; - - DISALLOW_EVIL_CONSTRUCTORS(MenuHostWindow); -}; - -} // namespace +namespace views { bool Menu::Delegate::IsRightToLeftUILayout() const { return l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT; } const SkBitmap& Menu::Delegate::GetEmptyIcon() const { - if (kEmptyIcon == NULL) - kEmptyIcon = new SkBitmap(); - return *kEmptyIcon; + static const SkBitmap* empty_icon = new SkBitmap(); + return *empty_icon; } -Menu::Menu(Delegate* delegate, AnchorPoint anchor, HWND owner) +Menu::Menu(Delegate* delegate, AnchorPoint anchor) : delegate_(delegate), - menu_(CreatePopupMenu()), - anchor_(anchor), - owner_(owner), - is_menu_visible_(false), - owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL)) { - DCHECK(delegate_); + anchor_(anchor) { } Menu::Menu(Menu* parent) : delegate_(parent->delegate_), - menu_(CreatePopupMenu()), - anchor_(parent->anchor_), - owner_(parent->owner_), - is_menu_visible_(false), - owner_draw_(parent->owner_draw_) { -} - -Menu::Menu(HMENU hmenu) - : delegate_(NULL), - menu_(hmenu), - anchor_(TOPLEFT), - owner_(NULL), - is_menu_visible_(false), - owner_draw_(false) { - DCHECK(menu_); + anchor_(parent->anchor_) { } Menu::~Menu() { - STLDeleteContainerPointers(submenus_.begin(), submenus_.end()); - STLDeleteContainerPointers(item_data_.begin(), item_data_.end()); - DestroyMenu(menu_); -} - -UINT Menu::GetStateFlagsForItemID(int item_id) const { - // Use the delegate to get enabled and checked state. - UINT flags = - delegate_->IsCommandEnabled(item_id) ? MFS_ENABLED : MFS_DISABLED; - - if (delegate_->IsItemChecked(item_id)) - flags |= MFS_CHECKED; - - if (delegate_->IsItemDefault(item_id)) - flags |= MFS_DEFAULT; - - return flags; -} - -void Menu::AddMenuItemInternal(int index, - int item_id, - const std::wstring& label, - const SkBitmap& icon, - HMENU submenu, - MenuItemType type) { - DCHECK(type != SEPARATOR) << "Call AddSeparator instead!"; - - if (label.empty() && !delegate_) { - // No label and no delegate; don't add an empty menu. - // It appears under some circumstance we're getting an empty label - // (l10n_util::GetString(IDS_TASK_MANAGER) returns ""). This shouldn't - // happen, but I'm working over the crash here. - NOTREACHED(); - return; - } - - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_FTYPE | MIIM_ID; - if (submenu) { - mii.fMask |= MIIM_SUBMENU; - mii.hSubMenu = submenu; - } - - // Set the type and ID. - if (!owner_draw_) { - mii.fType = MFT_STRING; - mii.fMask |= MIIM_STRING; - } else { - mii.fType = MFT_OWNERDRAW; - } - - if (type == RADIO) - mii.fType |= MFT_RADIOCHECK; - - mii.wID = item_id; - - // Set the item data. - Menu::ItemData* data = new ItemData; - item_data_.push_back(data); - data->submenu = submenu != NULL; - - std::wstring actual_label(label.empty() ? - delegate_->GetLabel(item_id) : label); - - // Find out if there is a shortcut we need to append to the label. - views::Accelerator accelerator(0, false, false, false); - if (delegate_ && delegate_->GetAcceleratorInfo(item_id, &accelerator)) { - actual_label += L'\t'; - actual_label += accelerator.GetShortcutText(); - } - labels_.push_back(actual_label); - - if (owner_draw_) { - if (icon.width() != 0 && icon.height() != 0) - data->icon = icon; - else - data->icon = delegate_->GetIcon(item_id); - } else { - mii.dwTypeData = const_cast<wchar_t*>(labels_.back().c_str()); - } - - InsertMenuItem(menu_, index, TRUE, &mii); } void Menu::AppendMenuItem(int item_id, @@ -366,7 +44,7 @@ void Menu::AddMenuItem(int index, if (type == SEPARATOR) AddSeparator(index); else - AddMenuItemInternal(index, item_id, label, SkBitmap(), NULL, type); + AddMenuItemInternal(index, item_id, label, SkBitmap(), type); } Menu* Menu::AppendSubMenu(int item_id, const std::wstring& label) { @@ -383,19 +61,6 @@ Menu* Menu::AppendSubMenuWithIcon(int item_id, return AddSubMenuWithIcon(-1, item_id, label, icon); } -Menu* Menu::AddSubMenuWithIcon(int index, - int item_id, - const std::wstring& label, - const SkBitmap& icon) { - if (!owner_draw_ && icon.width() != 0 && icon.height() != 0) - owner_draw_ = true; - - Menu* submenu = new Menu(this); - submenus_.push_back(submenu); - AddMenuItemInternal(index, item_id, label, icon, submenu->menu_, NORMAL); - return submenu; -} - void Menu::AppendMenuItemWithLabel(int item_id, const std::wstring& label) { AddMenuItemWithLabel(-1, item_id, label); } @@ -417,14 +82,6 @@ void Menu::AppendSeparator() { AddSeparator(-1); } -void Menu::AddSeparator(int index) { - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_FTYPE; - mii.fType = MFT_SEPARATOR; - InsertMenuItem(menu_, index, TRUE, &mii); -} - void Menu::AppendMenuItemWithIcon(int item_id, const std::wstring& label, const SkBitmap& icon) { @@ -435,192 +92,10 @@ void Menu::AddMenuItemWithIcon(int index, int item_id, const std::wstring& label, const SkBitmap& icon) { - if (!owner_draw_) - owner_draw_ = true; - AddMenuItemInternal(index, item_id, label, icon, NULL, Menu::NORMAL); -} - -void Menu::EnableMenuItemByID(int item_id, bool enabled) { - UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED; - EnableMenuItem(menu_, item_id, MF_BYCOMMAND | enable_flags); + AddMenuItemInternal(index, item_id, label, icon, Menu::NORMAL); } -void Menu::EnableMenuItemAt(int index, bool enabled) { - UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED; - EnableMenuItem(menu_, index, MF_BYPOSITION | enable_flags); +Menu::Menu() : delegate_(NULL), anchor_(TOPLEFT) { } -void Menu::SetMenuLabel(int item_id, const std::wstring& label) { - MENUITEMINFO mii = {0}; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STRING; - mii.dwTypeData = const_cast<wchar_t*>(label.c_str()); - mii.cch = static_cast<UINT>(label.size()); - SetMenuItemInfo(menu_, item_id, false, &mii); -} - -DWORD Menu::GetTPMAlignFlags() const { - // The manner in which we handle the menu alignment depends on whether or not - // the menu is displayed within a mirrored view. If the UI is mirrored, the - // alignment needs to be fliped so that instead of aligning the menu to the - // right of the point, we align it to the left and vice versa. - DWORD align_flags = TPM_TOPALIGN; - switch (anchor_) { - case TOPLEFT: - if (delegate_->IsRightToLeftUILayout()) { - align_flags |= TPM_RIGHTALIGN; - } else { - align_flags |= TPM_LEFTALIGN; - } - break; - - case TOPRIGHT: - if (delegate_->IsRightToLeftUILayout()) { - align_flags |= TPM_LEFTALIGN; - } else { - align_flags |= TPM_RIGHTALIGN; - } - break; - - default: - NOTREACHED(); - return 0; - } - return align_flags; -} - -bool Menu::SetIcon(const SkBitmap& icon, int item_id) { - if (!owner_draw_) - owner_draw_ = true; - - const int num_items = GetMenuItemCount(menu_); - int sep_count = 0; - for (int i = 0; i < num_items; ++i) { - if (!(GetMenuState(menu_, i, MF_BYPOSITION) & MF_SEPARATOR)) { - if (ChromeGetMenuItemID(menu_, i) == item_id) { - item_data_[i - sep_count]->icon = icon; - // When the menu is running, we use SetMenuItemInfo to let Windows - // update the item information so that the icon being displayed - // could change immediately. - if (active_host_window) { - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_FTYPE | MIIM_DATA; - mii.fType = MFT_OWNERDRAW; - mii.dwItemData = - reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]); - SetMenuItemInfo(menu_, item_id, false, &mii); - } - return true; - } - } else { - ++sep_count; - } - } - - // Continue searching for the item in submenus. - for (size_t i = 0; i < submenus_.size(); ++i) { - if (submenus_[i]->SetIcon(icon, item_id)) - return true; - } - - return false; -} - -void Menu::SetMenuInfo() { - const int num_items = GetMenuItemCount(menu_); - int sep_count = 0; - for (int i = 0; i < num_items; ++i) { - MENUITEMINFO mii_info; - mii_info.cbSize = sizeof(mii_info); - // Get the menu's original type. - mii_info.fMask = MIIM_FTYPE; - GetMenuItemInfo(menu_, i, MF_BYPOSITION, &mii_info); - // Set item states. - if (!(mii_info.fType & MF_SEPARATOR)) { - const int id = ChromeGetMenuItemID(menu_, i); - - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_DATA | MIIM_STRING; - // We also need MFT_STRING for owner drawn items in order to let Windows - // handle the accelerators for us. - mii.fType = MFT_STRING; - if (owner_draw_) - mii.fType |= MFT_OWNERDRAW; - // If the menu originally has radiocheck type, we should follow it. - if (mii_info.fType & MFT_RADIOCHECK) - mii.fType |= MFT_RADIOCHECK; - mii.fState = GetStateFlagsForItemID(id); - - // Validate the label. If there is a contextual label, use it, otherwise - // default to the static label - std::wstring label; - if (!delegate_->GetContextualLabel(id, &label)) - label = labels_[i - sep_count]; - - if (owner_draw_) { - item_data_[i - sep_count]->label = label; - mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]); - } - mii.dwTypeData = const_cast<wchar_t*>(label.c_str()); - mii.cch = static_cast<UINT>(label.size()); - SetMenuItemInfo(menu_, i, true, &mii); - } else { - // Set data for owner drawn separators. Set dwItemData NULL to indicate - // a separator. - if (owner_draw_) { - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_FTYPE; - mii.fType = MFT_SEPARATOR | MFT_OWNERDRAW; - mii.dwItemData = NULL; - SetMenuItemInfo(menu_, i, true, &mii); - } - ++sep_count; - } - } - - for (size_t i = 0; i < submenus_.size(); ++i) - submenus_[i]->SetMenuInfo(); -} - -void Menu::RunMenuAt(int x, int y) { - SetMenuInfo(); - - delegate_->MenuWillShow(); - - // NOTE: we don't use TPM_RIGHTBUTTON here as it breaks selecting by way of - // press, drag, release. See bugs 718 and 8560. - UINT flags = - GetTPMAlignFlags() | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE; - is_menu_visible_ = true; - DCHECK(owner_); - // In order for context menus on menus to work, the context menu needs to - // share the same window as the first menu is parented to. - bool created_host = false; - if (!active_host_window) { - created_host = true; - active_host_window = new MenuHostWindow(this, owner_); - } - UINT selected_id = - TrackPopupMenuEx(menu_, flags, x, y, active_host_window->m_hWnd, NULL); - if (created_host) { - delete active_host_window; - active_host_window = NULL; - } - is_menu_visible_ = false; - - // Execute the chosen command - if (selected_id != 0) - delegate_->ExecuteCommand(selected_id); -} - -void Menu::Cancel() { - DCHECK(is_menu_visible_); - EndMenu(); -} - -int Menu::ItemCount() { - return GetMenuItemCount(menu_); -} +} // namespace views diff --git a/views/controls/menu/menu.h b/views/controls/menu/menu.h index 0be9126..e07d7e5 100644 --- a/views/controls/menu/menu.h +++ b/views/controls/menu/menu.h @@ -5,34 +5,17 @@ #ifndef CONTROLS_MENU_VIEWS_MENU_H_ #define CONTROLS_MENU_VIEWS_MENU_H_ -#include <windows.h> - -#include <vector> - #include "base/basictypes.h" +#include "base/gfx/native_widget_types.h" #include "views/controls/menu/controller.h" class SkBitmap; -namespace { -class MenuHostWindow; -} - namespace views { + class Accelerator; -} - -/////////////////////////////////////////////////////////////////////////////// -// -// Menu class -// -// A wrapper around a Win32 HMENU handle that provides convenient APIs for -// menu construction, display and subsequent command execution. -// -/////////////////////////////////////////////////////////////////////////////// -class Menu { - friend class MenuHostWindow; +class Menu { public: ///////////////////////////////////////////////////////////////////////////// // @@ -131,14 +114,8 @@ class Menu { } protected: - // Returns an empty icon. Will initialize kEmptyIcon if it hasn't been - // initialized. + // Returns an empty icon. const SkBitmap& GetEmptyIcon() const; - - private: - // Will be initialized to an icon of 0 width and 0 height when first using. - // An empty icon means we don't need to draw it. - static const SkBitmap* kEmptyIcon; }; // This class is a helper that simply wraps a controller and forwards all @@ -195,15 +172,18 @@ class Menu { // owner The window that the menu is being brought up relative // to. Not actually used for anything but must not be // NULL. - Menu(Delegate* delegate, AnchorPoint anchor, HWND owner); - // Alternatively, a Menu object can be constructed wrapping an existing - // HMENU. This can be used to use the convenience methods to insert - // menu items and manage label string ownership. However this kind of - // Menu object cannot use the delegate. - explicit Menu(HMENU hmenu); + Menu(Delegate* delegate, AnchorPoint anchor); + Menu(); virtual ~Menu(); + static Menu* Create(Delegate* delegate, + AnchorPoint anchor, + gfx::NativeView parent); + void set_delegate(Delegate* delegate) { delegate_ = delegate; } + Delegate* delegate() const { return delegate_; } + + AnchorPoint anchor() const { return anchor_; } // Adds an item to this menu. // item_id The id of the item, used to identify it in delegate callbacks @@ -234,10 +214,10 @@ class Menu { Menu* AppendSubMenuWithIcon(int item_id, const std::wstring& label, const SkBitmap& icon); - Menu* AddSubMenuWithIcon(int index, - int item_id, - const std::wstring& label, - const SkBitmap& icon); + virtual Menu* AddSubMenuWithIcon(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon) = 0; // This is a convenience for standard text label menu items where the label // is provided with this call. @@ -251,7 +231,7 @@ class Menu { // Adds a separator to this menu void AppendSeparator(); - void AddSeparator(int index); + virtual void AddSeparator(int index) = 0; // Appends a menu item with an icon. This is for the menu item which // needs an icon. Calling this function forces the Menu class to draw @@ -265,91 +245,47 @@ class Menu { const SkBitmap& icon); // Enables or disables the item with the specified id. - void EnableMenuItemByID(int item_id, bool enabled); - void EnableMenuItemAt(int index, bool enabled); + virtual void EnableMenuItemByID(int item_id, bool enabled) = 0; + virtual void EnableMenuItemAt(int index, bool enabled) = 0; // Sets menu label at specified index. - void SetMenuLabel(int item_id, const std::wstring& label); + virtual void SetMenuLabel(int item_id, const std::wstring& label) = 0; // Sets an icon for an item with a given item_id. Calling this function // also forces the Menu class to draw the menu, instead of relying on Windows. // Returns false if the item with |item_id| is not found. - bool SetIcon(const SkBitmap& icon, int item_id); + virtual bool SetIcon(const SkBitmap& icon, int item_id) = 0; // Shows the menu, blocks until the user dismisses the menu or selects an // item, and executes the command for the selected item (if any). // Warning: Blocking call. Will implicitly run a message loop. - void RunMenuAt(int x, int y); + virtual void RunMenuAt(int x, int y) = 0; // Cancels the menu. - virtual void Cancel(); + virtual void Cancel() = 0; // Returns the number of menu items. - int ItemCount(); + virtual int ItemCount() = 0; protected: - // The delegate that is being used to get information about the presentation. - Delegate* delegate_; - - private: - // The data of menu items needed to display. - struct ItemData; - explicit Menu(Menu* parent); - void AddMenuItemInternal(int index, - int item_id, - const std::wstring& label, - const SkBitmap& icon, - HMENU submenu, - MenuItemType type); - - // Sets menu information before displaying, including sub-menus. - void SetMenuInfo(); - - // Get all the state flags for the |fState| field of MENUITEMINFO for the - // item with the specified id. |delegate| is consulted if non-NULL about - // the state of the item in preference to |controller_|. - UINT GetStateFlagsForItemID(int item_id) const; - - // Gets the Win32 TPM alignment flags for the specified AnchorPoint. - DWORD GetTPMAlignFlags() const; - - // The Win32 Menu Handle we wrap - HMENU menu_; - - // The window that would receive WM_COMMAND messages when the user selects - // an item from the menu. - HWND owner_; + virtual void AddMenuItemInternal(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon, + MenuItemType type) = 0; - // This list is used to store the default labels for the menu items. - // We may use contextual labels when RunMenu is called, so we must save - // a copy of default ones here. - std::vector<std::wstring> labels_; - - // A flag to indicate whether this menu will be drawn by the Menu class. - // If it's true, all the menu items will be owner drawn. Otherwise, - // all the drawing will be done by Windows. - bool owner_draw_; + private: + // The delegate that is being used to get information about the presentation. + Delegate* delegate_; // How this popup menu should be aligned relative to the point it is run at. AnchorPoint anchor_; - // This list is to store the string labels and icons to display. It's used - // when owner_draw_ is true. We give MENUITEMINFO pointers to these - // structures to specify what we'd like to draw. If owner_draw_ is false, - // we only give MENUITEMINFO pointers to the labels_. - // The label member of the ItemData structure comes from either labels_ or - // the GetContextualLabel. - std::vector<ItemData*> item_data_; - - // Our sub-menus, if any. - std::vector<Menu*> submenus_; - - // Whether the menu is visible. - bool is_menu_visible_; - DISALLOW_COPY_AND_ASSIGN(Menu); }; +} // namespace views + #endif // CONTROLS_MENU_VIEWS_MENU_H_ diff --git a/views/controls/menu/menu_win.cc b/views/controls/menu/menu_win.cc new file mode 100644 index 0000000..9c85b54 --- /dev/null +++ b/views/controls/menu/menu_win.cc @@ -0,0 +1,565 @@ +// Copyright (c) 2006-2008 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_win.h" + +#include <atlbase.h> +#include <atlapp.h> +#include <atlwin.h> +#include <atlcrack.h> +#include <atlframe.h> +#include <atlmisc.h> +#include <string> + +#include "app/gfx/chrome_canvas.h" +#include "app/gfx/chrome_font.h" +#include "app/l10n_util.h" +#include "app/l10n_util_win.h" +#include "base/gfx/rect.h" +#include "base/logging.h" +#include "base/stl_util-inl.h" +#include "base/string_util.h" +#include "views/accelerator.h" + +namespace views { + +// The width of an icon, including the pixels between the icon and +// the item label. +static const int kIconWidth = 23; +// Margins between the top of the item and the label. +static const int kItemTopMargin = 3; +// Margins between the bottom of the item and the label. +static const int kItemBottomMargin = 4; +// Margins between the left of the item and the icon. +static const int kItemLeftMargin = 4; +// Margins between the right of the item and the label. +static const int kItemRightMargin = 10; +// The width for displaying the sub-menu arrow. +static const int kArrowWidth = 10; + +// Current active MenuHostWindow. If NULL, no menu is active. +static MenuHostWindow* active_host_window = NULL; + +// The data of menu items needed to display. +struct MenuWin::ItemData { + std::wstring label; + SkBitmap icon; + bool submenu; +}; + +namespace { + +static int ChromeGetMenuItemID(HMENU hMenu, int pos) { + // The built-in Windows ::GetMenuItemID doesn't work for submenus, + // so here's our own implementation. + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID; + GetMenuItemInfo(hMenu, pos, TRUE, &mii); + return mii.wID; +} + +// MenuHostWindow ------------------------------------------------------------- + +// MenuHostWindow is the HWND the HMENU is parented to. MenuHostWindow is used +// to intercept right clicks on the HMENU and notify the delegate as well as +// for drawing icons. +// +class MenuHostWindow : public CWindowImpl<MenuHostWindow, CWindow, + CWinTraits<WS_CHILD>> { + public: + MenuHostWindow(MenuWin* menu, HWND parent_window) : menu_(menu) { + int extended_style = 0; + // If the menu needs to be created with a right-to-left UI layout, we must + // set the appropriate RTL flags (such as WS_EX_LAYOUTRTL) property for the + // underlying HWND. + if (menu_->delegate()->IsRightToLeftUILayout()) + extended_style |= l10n_util::GetExtendedStyles(); + Create(parent_window, gfx::Rect().ToRECT(), 0, 0, extended_style); + } + + ~MenuHostWindow() { + DestroyWindow(); + } + + DECLARE_FRAME_WND_CLASS(L"MenuHostWindow", NULL); + BEGIN_MSG_MAP(MenuHostWindow); + MSG_WM_RBUTTONUP(OnRButtonUp) + MSG_WM_MEASUREITEM(OnMeasureItem) + MSG_WM_DRAWITEM(OnDrawItem) + END_MSG_MAP(); + + private: + // NOTE: I really REALLY tried to use WM_MENURBUTTONUP, but I ran into + // two problems in using it: + // 1. It doesn't contain the coordinates of the mouse. + // 2. It isn't invoked for menuitems representing a submenu that have children + // menu items (not empty). + + void OnRButtonUp(UINT w_param, const CPoint& loc) { + int id; + if (menu_->delegate() && FindMenuIDByLocation(menu_, loc, &id)) + menu_->delegate()->ShowContextMenu(menu_, id, loc.x, loc.y, true); + } + + void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* lpmis) { + MenuWin::ItemData* data = + reinterpret_cast<MenuWin::ItemData*>(lpmis->itemData); + if (data != NULL) { + ChromeFont font; + lpmis->itemWidth = font.GetStringWidth(data->label) + kIconWidth + + kItemLeftMargin + kItemRightMargin - + GetSystemMetrics(SM_CXMENUCHECK); + if (data->submenu) + lpmis->itemWidth += kArrowWidth; + // If the label contains an accelerator, make room for tab. + if (data->label.find(L'\t') != std::wstring::npos) + lpmis->itemWidth += font.GetStringWidth(L" "); + lpmis->itemHeight = font.height() + kItemBottomMargin + kItemTopMargin; + } else { + // Measure separator size. + lpmis->itemHeight = GetSystemMetrics(SM_CYMENU) / 2; + lpmis->itemWidth = 0; + } + } + + void OnDrawItem(UINT wParam, DRAWITEMSTRUCT* lpdis) { + HDC hDC = lpdis->hDC; + COLORREF prev_bg_color, prev_text_color; + + // Set background color and text color + if (lpdis->itemState & ODS_SELECTED) { + prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT)); + prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } else { + prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_MENU)); + if (lpdis->itemState & ODS_DISABLED) + prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT)); + else + prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT)); + } + + if (lpdis->itemData) { + MenuWin::ItemData* data = + reinterpret_cast<MenuWin::ItemData*>(lpdis->itemData); + + // Draw the background. + HBRUSH hbr = CreateSolidBrush(GetBkColor(hDC)); + FillRect(hDC, &lpdis->rcItem, hbr); + DeleteObject(hbr); + + // Draw the label. + RECT rect = lpdis->rcItem; + rect.top += kItemTopMargin; + // Should we add kIconWidth only when icon.width() != 0 ? + rect.left += kItemLeftMargin + kIconWidth; + rect.right -= kItemRightMargin; + UINT format = DT_TOP | DT_SINGLELINE; + // Check whether the mnemonics should be underlined. + BOOL underline_mnemonics; + SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0); + if (!underline_mnemonics) + format |= DT_HIDEPREFIX; + ChromeFont font; + HGDIOBJ old_font = static_cast<HFONT>(SelectObject(hDC, font.hfont())); + int fontsize = font.FontSize(); + + // If an accelerator is specified (with a tab delimiting the rest of the + // label from the accelerator), we have to justify the fist part on the + // left and the accelerator on the right. + // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the + // window system UI font and will not hit here. + std::wstring label = data->label; + std::wstring accel; + std::wstring::size_type tab_pos = label.find(L'\t'); + if (tab_pos != std::wstring::npos) { + accel = label.substr(tab_pos); + label = label.substr(0, tab_pos); + } + DrawTextEx(hDC, const_cast<wchar_t*>(label.data()), + static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL); + if (!accel.empty()) + DrawTextEx(hDC, const_cast<wchar_t*>(accel.data()), + static_cast<int>(accel.size()), &rect, + format | DT_RIGHT, NULL); + SelectObject(hDC, old_font); + + // Draw the icon after the label, otherwise it would be covered + // by the label. + if (data->icon.width() != 0 && data->icon.height() != 0) { + ChromeCanvas canvas(data->icon.width(), data->icon.height(), false); + canvas.drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode); + canvas.DrawBitmapInt(data->icon, 0, 0); + canvas.getTopPlatformDevice().drawToHDC(hDC, lpdis->rcItem.left + + kItemLeftMargin, lpdis->rcItem.top + (lpdis->rcItem.bottom - + lpdis->rcItem.top - data->icon.height()) / 2, NULL); + } + + } else { + // Draw the separator + lpdis->rcItem.top += (lpdis->rcItem.bottom - lpdis->rcItem.top) / 3; + DrawEdge(hDC, &lpdis->rcItem, EDGE_ETCHED, BF_TOP); + } + + SetBkColor(hDC, prev_bg_color); + SetTextColor(hDC, prev_text_color); + } + + bool FindMenuIDByLocation(MenuWin* menu, const CPoint& loc, int* id) { + int index = MenuItemFromPoint(NULL, menu->menu_, loc); + if (index != -1) { + *id = ChromeGetMenuItemID(menu->menu_, index); + return true; + } else { + for (std::vector<MenuWin*>::iterator i = menu->submenus_.begin(); + i != menu->submenus_.end(); ++i) { + if (FindMenuIDByLocation(*i, loc, id)) + return true; + } + } + return false; + } + + // The menu that created us. + MenuWin* menu_; + + DISALLOW_COPY_AND_ASSIGN(MenuHostWindow); +}; + +} // namespace + +// static +Menu* Menu::Create(Delegate* delegate, + AnchorPoint anchor, + gfx::NativeView parent) { + return new MenuWin(delegate, anchor, parent); +} + +MenuWin::MenuWin(Delegate* d, AnchorPoint anchor, HWND owner) + : Menu(d, anchor), + menu_(CreatePopupMenu()), + owner_(owner), + is_menu_visible_(false), + owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL)) { + DCHECK(delegate()); +} + +MenuWin::MenuWin(HMENU hmenu) + : Menu(NULL, TOPLEFT), + menu_(hmenu), + owner_(NULL), + is_menu_visible_(false), + owner_draw_(false) { + DCHECK(menu_); +} + +MenuWin::~MenuWin() { + STLDeleteContainerPointers(submenus_.begin(), submenus_.end()); + STLDeleteContainerPointers(item_data_.begin(), item_data_.end()); + DestroyMenu(menu_); +} + +Menu* MenuWin::AddSubMenuWithIcon(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon) { + MenuWin* submenu = new MenuWin(this); + submenus_.push_back(submenu); + AddMenuItemInternal(index, item_id, label, icon, submenu->menu_, NORMAL); + return submenu; +} + +void MenuWin::AddSeparator(int index) { + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE; + mii.fType = MFT_SEPARATOR; + InsertMenuItem(menu_, index, TRUE, &mii); +} + +void MenuWin::EnableMenuItemByID(int item_id, bool enabled) { + UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED; + EnableMenuItem(menu_, item_id, MF_BYCOMMAND | enable_flags); +} + +void MenuWin::EnableMenuItemAt(int index, bool enabled) { + UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED; + EnableMenuItem(menu_, index, MF_BYPOSITION | enable_flags); +} + +void MenuWin::SetMenuLabel(int item_id, const std::wstring& label) { + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING; + mii.dwTypeData = const_cast<wchar_t*>(label.c_str()); + mii.cch = static_cast<UINT>(label.size()); + SetMenuItemInfo(menu_, item_id, false, &mii); +} + +bool MenuWin::SetIcon(const SkBitmap& icon, int item_id) { + if (!owner_draw_) + owner_draw_ = true; + + const int num_items = GetMenuItemCount(menu_); + int sep_count = 0; + for (int i = 0; i < num_items; ++i) { + if (!(GetMenuState(menu_, i, MF_BYPOSITION) & MF_SEPARATOR)) { + if (ChromeGetMenuItemID(menu_, i) == item_id) { + item_data_[i - sep_count]->icon = icon; + // When the menu is running, we use SetMenuItemInfo to let Windows + // update the item information so that the icon being displayed + // could change immediately. + if (active_host_window) { + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_DATA; + mii.fType = MFT_OWNERDRAW; + mii.dwItemData = + reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]); + SetMenuItemInfo(menu_, item_id, false, &mii); + } + return true; + } + } else { + ++sep_count; + } + } + + // Continue searching for the item in submenus. + for (size_t i = 0; i < submenus_.size(); ++i) { + if (submenus_[i]->SetIcon(icon, item_id)) + return true; + } + + return false; +} + +void MenuWin::RunMenuAt(int x, int y) { + SetMenuInfo(); + + delegate()->MenuWillShow(); + + // NOTE: we don't use TPM_RIGHTBUTTON here as it breaks selecting by way of + // press, drag, release. See bugs 718 and 8560. + UINT flags = + GetTPMAlignFlags() | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE; + is_menu_visible_ = true; + DCHECK(owner_); + // In order for context menus on menus to work, the context menu needs to + // share the same window as the first menu is parented to. + bool created_host = false; + if (!active_host_window) { + created_host = true; + active_host_window = new MenuHostWindow(this, owner_); + } + UINT selected_id = + TrackPopupMenuEx(menu_, flags, x, y, active_host_window->m_hWnd, NULL); + if (created_host) { + delete active_host_window; + active_host_window = NULL; + } + is_menu_visible_ = false; + + // Execute the chosen command + if (selected_id != 0) + delegate()->ExecuteCommand(selected_id); +} + +void MenuWin::Cancel() { + DCHECK(is_menu_visible_); + EndMenu(); +} + +int MenuWin::ItemCount() { + return GetMenuItemCount(menu_); +} + +void MenuWin::AddMenuItemInternal(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon, + MenuItemType type) { + AddMenuItemInternal(index, item_id, label, icon, NULL, type); +} + +void MenuWin::AddMenuItemInternal(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon, + HMENU submenu, + MenuItemType type) { + DCHECK(type != SEPARATOR) << "Call AddSeparator instead!"; + + if (!owner_draw_ && !icon.empty()) + owner_draw_ = true; + + if (label.empty() && !delegate()) { + // No label and no delegate; don't add an empty menu. + // It appears under some circumstance we're getting an empty label + // (l10n_util::GetString(IDS_TASK_MANAGER) returns ""). This shouldn't + // happen, but I'm working over the crash here. + NOTREACHED(); + return; + } + + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_ID; + if (submenu) { + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = submenu; + } + + // Set the type and ID. + if (!owner_draw_) { + mii.fType = MFT_STRING; + mii.fMask |= MIIM_STRING; + } else { + mii.fType = MFT_OWNERDRAW; + } + + if (type == RADIO) + mii.fType |= MFT_RADIOCHECK; + + mii.wID = item_id; + + // Set the item data. + MenuWin::ItemData* data = new ItemData; + item_data_.push_back(data); + data->submenu = submenu != NULL; + + std::wstring actual_label(label.empty() ? + delegate()->GetLabel(item_id) : label); + + // Find out if there is a shortcut we need to append to the label. + views::Accelerator accelerator(0, false, false, false); + if (delegate() && delegate()->GetAcceleratorInfo(item_id, &accelerator)) { + actual_label += L'\t'; + actual_label += accelerator.GetShortcutText(); + } + labels_.push_back(actual_label); + + if (owner_draw_) { + if (icon.width() != 0 && icon.height() != 0) + data->icon = icon; + else + data->icon = delegate()->GetIcon(item_id); + } else { + mii.dwTypeData = const_cast<wchar_t*>(labels_.back().c_str()); + } + + InsertMenuItem(menu_, index, TRUE, &mii); +} + +MenuWin::MenuWin(MenuWin* parent) + : Menu(parent->delegate(), parent->anchor()), + menu_(CreatePopupMenu()), + owner_(parent->owner_), + is_menu_visible_(false), + owner_draw_(parent->owner_draw_) { +} + +void MenuWin::SetMenuInfo() { + const int num_items = GetMenuItemCount(menu_); + int sep_count = 0; + for (int i = 0; i < num_items; ++i) { + MENUITEMINFO mii_info; + mii_info.cbSize = sizeof(mii_info); + // Get the menu's original type. + mii_info.fMask = MIIM_FTYPE; + GetMenuItemInfo(menu_, i, MF_BYPOSITION, &mii_info); + // Set item states. + if (!(mii_info.fType & MF_SEPARATOR)) { + const int id = ChromeGetMenuItemID(menu_, i); + + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_DATA | MIIM_STRING; + // We also need MFT_STRING for owner drawn items in order to let Windows + // handle the accelerators for us. + mii.fType = MFT_STRING; + if (owner_draw_) + mii.fType |= MFT_OWNERDRAW; + // If the menu originally has radiocheck type, we should follow it. + if (mii_info.fType & MFT_RADIOCHECK) + mii.fType |= MFT_RADIOCHECK; + mii.fState = GetStateFlagsForItemID(id); + + // Validate the label. If there is a contextual label, use it, otherwise + // default to the static label + std::wstring label; + if (!delegate()->GetContextualLabel(id, &label)) + label = labels_[i - sep_count]; + + if (owner_draw_) { + item_data_[i - sep_count]->label = label; + mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]); + } + mii.dwTypeData = const_cast<wchar_t*>(label.c_str()); + mii.cch = static_cast<UINT>(label.size()); + SetMenuItemInfo(menu_, i, true, &mii); + } else { + // Set data for owner drawn separators. Set dwItemData NULL to indicate + // a separator. + if (owner_draw_) { + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE; + mii.fType = MFT_SEPARATOR | MFT_OWNERDRAW; + mii.dwItemData = NULL; + SetMenuItemInfo(menu_, i, true, &mii); + } + ++sep_count; + } + } + + for (size_t i = 0; i < submenus_.size(); ++i) + submenus_[i]->SetMenuInfo(); +} + +UINT MenuWin::GetStateFlagsForItemID(int item_id) const { + // Use the delegate to get enabled and checked state. + UINT flags = + delegate()->IsCommandEnabled(item_id) ? MFS_ENABLED : MFS_DISABLED; + + if (delegate()->IsItemChecked(item_id)) + flags |= MFS_CHECKED; + + if (delegate()->IsItemDefault(item_id)) + flags |= MFS_DEFAULT; + + return flags; +} + +DWORD MenuWin::GetTPMAlignFlags() const { + // The manner in which we handle the menu alignment depends on whether or not + // the menu is displayed within a mirrored view. If the UI is mirrored, the + // alignment needs to be fliped so that instead of aligning the menu to the + // right of the point, we align it to the left and vice versa. + DWORD align_flags = TPM_TOPALIGN; + switch (anchor()) { + case TOPLEFT: + if (delegate()->IsRightToLeftUILayout()) { + align_flags |= TPM_RIGHTALIGN; + } else { + align_flags |= TPM_LEFTALIGN; + } + break; + + case TOPRIGHT: + if (delegate()->IsRightToLeftUILayout()) { + align_flags |= TPM_LEFTALIGN; + } else { + align_flags |= TPM_RIGHTALIGN; + } + break; + + default: + NOTREACHED(); + return 0; + } + return align_flags; +} + +} // namespace views diff --git a/views/controls/menu/menu_win.h b/views/controls/menu/menu_win.h new file mode 100644 index 0000000..bea4c65 --- /dev/null +++ b/views/controls/menu/menu_win.h @@ -0,0 +1,129 @@ +// Copyright (c) 2006-2008 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_WIN_H_ +#define CONTROLS_MENU_VIEWS_MENU_WIN_H_ + +#include <vector> +#include <windows.h> + +#include "base/basictypes.h" +#include "views/controls/menu/menu.h" + +namespace views { + +namespace { +class MenuHostWindow; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Menu class +// +// A wrapper around a Win32 HMENU handle that provides convenient APIs for +// menu construction, display and subsequent command execution. +// +/////////////////////////////////////////////////////////////////////////////// +class MenuWin : public Menu { + friend class MenuHostWindow; + + public: + // Construct a Menu using the specified controller to determine command + // state. + // delegate A Menu::Delegate implementation that provides more + // information about the Menu presentation. + // anchor An alignment hint for the popup menu. + // owner The window that the menu is being brought up relative + // to. Not actually used for anything but must not be + // NULL. + MenuWin(Delegate* d, AnchorPoint anchor, HWND owner); + // Alternatively, a Menu object can be constructed wrapping an existing + // HMENU. This can be used to use the convenience methods to insert + // menu items and manage label string ownership. However this kind of + // Menu object cannot use the delegate. + explicit MenuWin(HMENU hmenu); + virtual ~MenuWin(); + + // Menu overrides. + virtual Menu* AddSubMenuWithIcon(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon); + virtual void AddSeparator(int index); + virtual void EnableMenuItemByID(int item_id, bool enabled); + virtual void EnableMenuItemAt(int index, bool enabled); + virtual void SetMenuLabel(int item_id, const std::wstring& label); + virtual bool SetIcon(const SkBitmap& icon, int item_id); + virtual void RunMenuAt(int x, int y); + virtual void Cancel(); + virtual int ItemCount(); + + protected: + virtual void AddMenuItemInternal(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon, + MenuItemType type); + + private: + // The data of menu items needed to display. + struct ItemData; + + void AddMenuItemInternal(int index, + int item_id, + const std::wstring& label, + const SkBitmap& icon, + HMENU submenu, + MenuItemType type); + + explicit MenuWin(MenuWin* parent); + + // Sets menu information before displaying, including sub-menus. + void SetMenuInfo(); + + // Get all the state flags for the |fState| field of MENUITEMINFO for the + // item with the specified id. |delegate| is consulted if non-NULL about + // the state of the item in preference to |controller_|. + UINT GetStateFlagsForItemID(int item_id) const; + + // Gets the Win32 TPM alignment flags for the specified AnchorPoint. + DWORD GetTPMAlignFlags() const; + + // The Win32 Menu Handle we wrap + HMENU menu_; + + // The window that would receive WM_COMMAND messages when the user selects + // an item from the menu. + HWND owner_; + + // This list is used to store the default labels for the menu items. + // We may use contextual labels when RunMenu is called, so we must save + // a copy of default ones here. + std::vector<std::wstring> labels_; + + // A flag to indicate whether this menu will be drawn by the Menu class. + // If it's true, all the menu items will be owner drawn. Otherwise, + // all the drawing will be done by Windows. + bool owner_draw_; + + // This list is to store the string labels and icons to display. It's used + // when owner_draw_ is true. We give MENUITEMINFO pointers to these + // structures to specify what we'd like to draw. If owner_draw_ is false, + // we only give MENUITEMINFO pointers to the labels_. + // The label member of the ItemData structure comes from either labels_ or + // the GetContextualLabel. + std::vector<ItemData*> item_data_; + + // Our sub-menus, if any. + std::vector<MenuWin*> submenus_; + + // Whether the menu is visible. + bool is_menu_visible_; + + DISALLOW_COPY_AND_ASSIGN(MenuWin); +}; + +} // namespace views + +#endif // CONTROLS_MENU_VIEWS_MENU_WIN_H_ diff --git a/views/controls/scrollbar/bitmap_scroll_bar.cc b/views/controls/scrollbar/bitmap_scroll_bar.cc index 18096fb..4fe8934 100644 --- a/views/controls/scrollbar/bitmap_scroll_bar.cc +++ b/views/controls/scrollbar/bitmap_scroll_bar.cc @@ -540,18 +540,19 @@ void BitmapScrollBar::ShowContextMenu(View* source, View::ConvertPointFromWidget(this, &temp_pt); context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y(); - Menu menu(this, Menu::TOPLEFT, GetWidget()->GetNativeView()); - menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere); - menu.AppendSeparator(); - menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart); - menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollEnd); - menu.AppendSeparator(); - menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageUp); - menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageDown); - menu.AppendSeparator(); - menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev); - menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext); - menu.RunMenuAt(x, y); + scoped_ptr<Menu> menu( + Menu::Create(this, Menu::TOPLEFT, GetWidget()->GetNativeView())); + menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere); + menu->AppendSeparator(); + menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart); + menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollEnd); + menu->AppendSeparator(); + menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageUp); + menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageDown); + menu->AppendSeparator(); + menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev); + menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext); + menu->RunMenuAt(x, y); } /////////////////////////////////////////////////////////////////////////////// diff --git a/views/controls/text_field.cc b/views/controls/text_field.cc index 08f982a..62762f4 100644 --- a/views/controls/text_field.cc +++ b/views/controls/text_field.cc @@ -24,7 +24,7 @@ #include "grit/generated_resources.h" #include "skia/ext/skia_utils_win.h" #include "views/controls/hwnd_view.h" -#include "views/controls/menu/menu.h" +#include "views/controls/menu/menu_win.h" #include "views/focus/focus_util_win.h" #include "views/views_delegate.h" #include "views/widget/widget.h" @@ -289,7 +289,7 @@ TextField::Edit::Edit(TextField* parent, bool draw_border) ole_interface.Attach(GetOleInterface()); text_object_model_ = ole_interface; - context_menu_.reset(new Menu(this, Menu::TOPLEFT, m_hWnd)); + context_menu_.reset(new MenuWin(this, Menu::TOPLEFT, m_hWnd)); context_menu_->AppendMenuItemWithLabel(IDS_UNDO, l10n_util::GetString(IDS_UNDO)); context_menu_->AppendSeparator(); diff --git a/views/views.vcproj b/views/views.vcproj index 0c336a6..bdc83a5 100644 --- a/views/views.vcproj +++ b/views/views.vcproj @@ -768,6 +768,14 @@ > </File> <File + RelativePath=".\controls\menu\menu_win.cc" + > + </File> + <File + RelativePath=".\controls\menu\menu_win.h" + > + </File> + <File RelativePath=".\controls\menu\view_menu_delegate.h" > </File> |