diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-20 03:58:11 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-20 03:58:11 +0000 |
commit | 8cd89cca063a2087ff9cf2ed89989c5a0024da09 (patch) | |
tree | 01fa2dff81256910b82d15186367c5d2efa5e185 /views/controls/menu/menu_item_view.cc | |
parent | a99f0ce8b398b3f0b159834eb0068dc7597edc68 (diff) | |
download | chromium_src-8cd89cca063a2087ff9cf2ed89989c5a0024da09.zip chromium_src-8cd89cca063a2087ff9cf2ed89989c5a0024da09.tar.gz chromium_src-8cd89cca063a2087ff9cf2ed89989c5a0024da09.tar.bz2 |
Splits the menu classes into individual files in anticipation of
porting them.
BUG=none
TEST=make sure to thorougly test bookmark menus on windows.
Review URL: http://codereview.chromium.org/173091
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23801 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/controls/menu/menu_item_view.cc')
-rw-r--r-- | views/controls/menu/menu_item_view.cc | 729 |
1 files changed, 729 insertions, 0 deletions
diff --git a/views/controls/menu/menu_item_view.cc b/views/controls/menu/menu_item_view.cc new file mode 100644 index 0000000..69c57a2 --- /dev/null +++ b/views/controls/menu/menu_item_view.cc @@ -0,0 +1,729 @@ +// 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_item_view.h" + +#if defined(OS_WIN) +#include <windows.h> +#include <uxtheme.h> +#include <Vssym32.h> +#endif + +#include "app/gfx/canvas.h" +#include "app/l10n_util.h" +#include "grit/app_strings.h" +#include "views/controls/menu/menu_controller.h" +#include "views/controls/menu/submenu_view.h" + +#if defined(OS_WIN) +#include "app/l10n_util_win.h" +#include "base/gfx/native_theme.h" +#include "base/win_util.h" +#endif + +// 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 used if the menu doesn't have icons. +static const int kItemNoIconTopMargin = 1; +static const int kItemNoIconBottomMargin = 3; + +// Margins between the left of the item and the icon. +static const int kItemLeftMargin = 4; + +// Padding between the label and submenu arrow. +static const int kLabelToArrowPadding = 10; + +// Padding between the arrow and the edge. +static const int kArrowToEdgePadding = 5; + +// Padding between the icon and label. +static const int kIconToLabelPadding = 8; + +// Padding between the gutter and label. +static const int kGutterToLabel = 5; + +// Size of the check. This comes from the OS. +static int check_width; +static int check_height; + +// Size of the submenu arrow. This comes from the OS. +static int arrow_width; +static int arrow_height; + +// Width of the gutter. Only used if render_gutter is true. +static int gutter_width; + +// Margins between the right of the item and the label. +static int item_right_margin; + +// X-coordinate of where the label starts. +static int label_start; + +// Height of the separator. +static int separator_height; + +// Whether or not the gutter should be rendered. The gutter is specific to +// Vista. +static bool render_gutter = false; + +// Preferred height of menu items. Reset every time a menu is run. +static int pref_menu_h; + +// Are mnemonics shown? This is updated before the menus are shown. +static bool show_mnemonics; + +using gfx::NativeTheme; + +namespace views { + +namespace { + +// Returns the font menus are to use. +gfx::Font GetMenuFont() { +#if defined(OS_WIN) + NONCLIENTMETRICS metrics; + win_util::GetNonClientMetrics(&metrics); + + l10n_util::AdjustUIFont(&(metrics.lfMenuFont)); + HFONT font = CreateFontIndirect(&metrics.lfMenuFont); + DLOG_ASSERT(font); + return gfx::Font::CreateFont(font); +#else + return gfx::Font(); +#endif +} + +// Calculates all sizes that we can from the OS. +// +// This is invoked prior to Running a menu. +void UpdateMenuPartSizes(bool has_icons) { +#if defined(OS_WIN) + HDC dc = GetDC(NULL); + RECT bounds = { 0, 0, 200, 200 }; + SIZE check_size; + if (NativeTheme::instance()->GetThemePartSize( + NativeTheme::MENU, dc, MENU_POPUPCHECK, MC_CHECKMARKNORMAL, &bounds, + TS_TRUE, &check_size) == S_OK) { + check_width = check_size.cx; + check_height = check_size.cy; + } else { + check_width = GetSystemMetrics(SM_CXMENUCHECK); + check_height = GetSystemMetrics(SM_CYMENUCHECK); + } + + SIZE arrow_size; + if (NativeTheme::instance()->GetThemePartSize( + NativeTheme::MENU, dc, MENU_POPUPSUBMENU, MSM_NORMAL, &bounds, + TS_TRUE, &arrow_size) == S_OK) { + arrow_width = arrow_size.cx; + arrow_height = arrow_size.cy; + } else { + // Sadly I didn't see a specify metrics for this. + arrow_width = GetSystemMetrics(SM_CXMENUCHECK); + arrow_height = GetSystemMetrics(SM_CYMENUCHECK); + } + + SIZE gutter_size; + if (NativeTheme::instance()->GetThemePartSize( + NativeTheme::MENU, dc, MENU_POPUPGUTTER, MSM_NORMAL, &bounds, + TS_TRUE, &gutter_size) == S_OK) { + gutter_width = gutter_size.cx; + render_gutter = true; + } else { + gutter_width = 0; + render_gutter = false; + } + + SIZE separator_size; + if (NativeTheme::instance()->GetThemePartSize( + NativeTheme::MENU, dc, MENU_POPUPSEPARATOR, MSM_NORMAL, &bounds, + TS_TRUE, &separator_size) == S_OK) { + separator_height = separator_size.cy; + } else { + separator_height = GetSystemMetrics(SM_CYMENU) / 2; + } + + item_right_margin = kLabelToArrowPadding + arrow_width + kArrowToEdgePadding; + + if (has_icons) { + label_start = kItemLeftMargin + check_width + kIconToLabelPadding; + } else { + // If there are no icons don't pad by the icon to label padding. This + // makes us look close to system menus. + label_start = kItemLeftMargin + check_width; + } + if (render_gutter) + label_start += gutter_width + kGutterToLabel; + + ReleaseDC(NULL, dc); + + MenuItemView menu_item(NULL); + menu_item.SetTitle(L"blah"); // Text doesn't matter here. + pref_menu_h = menu_item.GetPreferredSize().height(); +#endif +} + +// Convenience for scrolling the view such that the origin is visible. +static void ScrollToVisible(View* view) { + view->ScrollRectToVisible(0, 0, view->width(), view->height()); +} + +// MenuSeparator --------------------------------------------------------------- + +// Renders a separator. + +class MenuSeparator : public View { + public: + MenuSeparator() { + } + + void Paint(gfx::Canvas* canvas) { + // The gutter is rendered before the background. + int start_x = 0; + int start_y = height() / 3; + HDC dc = canvas->beginPlatformPaint(); + if (render_gutter) { + // If render_gutter is true, we're on Vista and need to render the + // gutter, then indent the separator from the gutter. + RECT gutter_bounds = { label_start - kGutterToLabel - gutter_width, 0, 0, + height() }; + gutter_bounds.right = gutter_bounds.left + gutter_width; + NativeTheme::instance()->PaintMenuGutter(dc, MENU_POPUPGUTTER, MPI_NORMAL, + &gutter_bounds); + start_x = gutter_bounds.left + gutter_width; + start_y = 0; + } + RECT separator_bounds = { start_x, start_y, width(), height() }; + NativeTheme::instance()->PaintMenuSeparator(dc, MENU_POPUPSEPARATOR, + MPI_NORMAL, &separator_bounds); + canvas->endPlatformPaint(); + } + + gfx::Size GetPreferredSize() { + return gfx::Size(10, // Just in case we're the only item in a menu. + separator_height); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MenuSeparator); +}; + +// EmptyMenuMenuItem --------------------------------------------------------- + +// EmptyMenuMenuItem is used when a menu has no menu items. EmptyMenuMenuItem +// is itself a MenuItemView, but it uses a different ID so that it isn't +// identified as a MenuItemView. + +class EmptyMenuMenuItem : public MenuItemView { + public: + explicit EmptyMenuMenuItem(MenuItemView* parent) : + MenuItemView(parent, 0, NORMAL) { + SetTitle(l10n_util::GetString(IDS_APP_MENU_EMPTY_SUBMENU)); + // Set this so that we're not identified as a normal menu item. + SetID(kEmptyMenuItemViewID); + SetEnabled(false); + } + + private: + DISALLOW_COPY_AND_ASSIGN(EmptyMenuMenuItem); +}; + +} // namespace + +// MenuItemView --------------------------------------------------------------- + +// static +const int MenuItemView::kMenuItemViewID = 1001; + +// static +const int MenuItemView::kEmptyMenuItemViewID = + MenuItemView::kMenuItemViewID + 1; + +// static +bool MenuItemView::allow_task_nesting_during_run_ = false; + +MenuItemView::MenuItemView(MenuDelegate* delegate) { + // NOTE: don't check the delegate for NULL, UpdateMenuPartSizes supplies a + // NULL delegate. + Init(NULL, 0, SUBMENU, delegate); +} + +MenuItemView::~MenuItemView() { + if (controller_) { + // We're currently showing. + + // We can't delete ourselves while we're blocking. + DCHECK(!controller_->IsBlockingRun()); + + // Invoking Cancel is going to call us back and notify the delegate. + // Notifying the delegate from the destructor can be problematic. To avoid + // this the delegate is set to NULL. + delegate_ = NULL; + + controller_->Cancel(true); + } + delete submenu_; +} + +// static +int MenuItemView::pref_menu_height() { + return pref_menu_h; +} + +void MenuItemView::RunMenuAt(HWND parent, + const gfx::Rect& bounds, + AnchorPosition anchor, + bool has_mnemonics) { + PrepareForRun(has_mnemonics); + + int mouse_event_flags; + + MenuController* controller = MenuController::GetActiveInstance(); + if (controller && !controller->IsBlockingRun()) { + // A menu is already showing, but it isn't a blocking menu. Cancel it. + // We can get here during drag and drop if the user right clicks on the + // menu quickly after the drop. + controller->Cancel(true); + controller = NULL; + } + bool owns_controller = false; + if (!controller) { + // No menus are showing, show one. + controller = new MenuController(true); + MenuController::SetActiveInstance(controller); + owns_controller = true; + } else { + // A menu is already showing, use the same controller. + + // Don't support blocking from within non-blocking. + DCHECK(controller->IsBlockingRun()); + } + + controller_ = controller; + + // Run the loop. + MenuItemView* result = + controller->Run(parent, this, bounds, anchor, &mouse_event_flags); + + RemoveEmptyMenus(); + + controller_ = NULL; + + if (owns_controller) { + // We created the controller and need to delete it. + if (MenuController::GetActiveInstance() == controller) + MenuController::SetActiveInstance(NULL); + delete controller; + } + // Make sure all the windows we created to show the menus have been + // destroyed. + DestroyAllMenuHosts(); + if (result && delegate_) + delegate_->ExecuteCommand(result->GetCommand(), mouse_event_flags); +} + +void MenuItemView::RunMenuForDropAt(HWND parent, + const gfx::Rect& bounds, + AnchorPosition anchor) { + PrepareForRun(false); + + // If there is a menu, hide it so that only one menu is shown during dnd. + MenuController* current_controller = MenuController::GetActiveInstance(); + if (current_controller) { + current_controller->Cancel(true); + } + + // Always create a new controller for non-blocking. + controller_ = new MenuController(false); + + // Set the instance, that way it can be canceled by another menu. + MenuController::SetActiveInstance(controller_); + + controller_->Run(parent, this, bounds, anchor, NULL); +} + +void MenuItemView::Cancel() { + if (controller_ && !canceled_) { + canceled_ = true; + controller_->Cancel(true); + } +} + +SubmenuView* MenuItemView::CreateSubmenu() { + if (!submenu_) + submenu_ = new SubmenuView(this); + return submenu_; +} + +void MenuItemView::SetSelected(bool selected) { + selected_ = selected; + SchedulePaint(); +} + +void MenuItemView::SetIcon(const SkBitmap& icon, int item_id) { + MenuItemView* item = GetDescendantByID(item_id); + DCHECK(item); + item->SetIcon(icon); +} + +void MenuItemView::SetIcon(const SkBitmap& icon) { + icon_ = icon; + SchedulePaint(); +} + +void MenuItemView::Paint(gfx::Canvas* canvas) { + Paint(canvas, false); +} + +gfx::Size MenuItemView::GetPreferredSize() { + gfx::Font& font = GetRootMenuItem()->font_; + return gfx::Size( + font.GetStringWidth(title_) + label_start + item_right_margin, + font.height() + GetBottomMargin() + GetTopMargin()); +} + +MenuController* MenuItemView::GetMenuController() { + return GetRootMenuItem()->controller_; +} + +MenuDelegate* MenuItemView::GetDelegate() { + return GetRootMenuItem()->delegate_; +} + +MenuItemView* MenuItemView::GetRootMenuItem() { + MenuItemView* item = this; + while (item) { + MenuItemView* parent = item->GetParentMenuItem(); + if (!parent) + return item; + item = parent; + } + NOTREACHED(); + return NULL; +} + +wchar_t MenuItemView::GetMnemonic() { + if (!has_mnemonics_) + return 0; + + const std::wstring& title = GetTitle(); + size_t index = 0; + do { + index = title.find('&', index); + if (index != std::wstring::npos) { + if (index + 1 != title.size() && title[index + 1] != '&') + return title[index + 1]; + index++; + } + } while (index != std::wstring::npos); + return 0; +} + +MenuItemView::MenuItemView(MenuItemView* parent, + int command, + MenuItemView::Type type) { + Init(parent, command, type, NULL); +} + +void MenuItemView::Init(MenuItemView* parent, + int command, + MenuItemView::Type type, + MenuDelegate* delegate) { + delegate_ = delegate; + controller_ = NULL; + canceled_ = false; + parent_menu_item_ = parent; + type_ = type; + selected_ = false; + command_ = command; + submenu_ = NULL; + // Assign our ID, this allows SubmenuItemView to find MenuItemViews. + SetID(kMenuItemViewID); + has_icons_ = false; + + MenuDelegate* root_delegate = GetDelegate(); + if (root_delegate) + SetEnabled(root_delegate->IsCommandEnabled(command)); +} + +MenuItemView* MenuItemView::AppendMenuItemInternal(int item_id, + const std::wstring& label, + const SkBitmap& icon, + Type type) { + if (!submenu_) + CreateSubmenu(); + if (type == SEPARATOR) { + submenu_->AddChildView(new MenuSeparator()); + return NULL; + } + MenuItemView* item = new MenuItemView(this, item_id, type); + if (label.empty() && GetDelegate()) + item->SetTitle(GetDelegate()->GetLabel(item_id)); + else + item->SetTitle(label); + item->SetIcon(icon); + if (type == SUBMENU) + item->CreateSubmenu(); + submenu_->AddChildView(item); + return item; +} + +MenuItemView* MenuItemView::GetDescendantByID(int id) { + if (GetCommand() == id) + return this; + if (!HasSubmenu()) + return NULL; + for (int i = 0; i < GetSubmenu()->GetChildViewCount(); ++i) { + View* child = GetSubmenu()->GetChildViewAt(i); + if (child->GetID() == MenuItemView::kMenuItemViewID) { + MenuItemView* result = static_cast<MenuItemView*>(child)-> + GetDescendantByID(id); + if (result) + return result; + } + } + return NULL; +} + +void MenuItemView::DropMenuClosed(bool notify_delegate) { + DCHECK(controller_); + DCHECK(!controller_->IsBlockingRun()); + if (MenuController::GetActiveInstance() == controller_) + MenuController::SetActiveInstance(NULL); + delete controller_; + controller_ = NULL; + + RemoveEmptyMenus(); + + if (notify_delegate && delegate_) { + // Our delegate is null when invoked from the destructor. + delegate_->DropMenuClosed(this); + } + // WARNING: its possible the delegate deleted us at this point. +} + +void MenuItemView::PrepareForRun(bool has_mnemonics) { + // Currently we only support showing the root. + DCHECK(!parent_menu_item_); + + // Don't invoke run from within run on the same menu. + DCHECK(!controller_); + + // Force us to have a submenu. + CreateSubmenu(); + + canceled_ = false; + + has_mnemonics_ = has_mnemonics; + + AddEmptyMenus(); + + if (!MenuController::GetActiveInstance()) { + // Only update the menu size if there are no menus showing, otherwise + // things may shift around. + UpdateMenuPartSizes(has_icons_); + } + + font_ = GetMenuFont(); + + BOOL show_cues; + show_mnemonics = + (SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &show_cues, 0) && + show_cues == TRUE); +} + +int MenuItemView::GetDrawStringFlags() { + int flags = 0; + if (UILayoutIsRightToLeft()) + flags |= gfx::Canvas::TEXT_ALIGN_RIGHT; + else + flags |= gfx::Canvas::TEXT_ALIGN_LEFT; + + if (has_mnemonics_) { + if (show_mnemonics) + flags |= gfx::Canvas::SHOW_PREFIX; + else + flags |= gfx::Canvas::HIDE_PREFIX; + } + return flags; +} + +void MenuItemView::AddEmptyMenus() { + DCHECK(HasSubmenu()); + if (submenu_->GetChildViewCount() == 0) { + submenu_->AddChildView(0, new EmptyMenuMenuItem(this)); + } else { + for (int i = 0, item_count = submenu_->GetMenuItemCount(); i < item_count; + ++i) { + MenuItemView* child = submenu_->GetMenuItemAt(i); + if (child->HasSubmenu()) + child->AddEmptyMenus(); + } + } +} + +void MenuItemView::RemoveEmptyMenus() { + DCHECK(HasSubmenu()); + // Iterate backwards as we may end up removing views, which alters the child + // view count. + for (int i = submenu_->GetChildViewCount() - 1; i >= 0; --i) { + View* child = submenu_->GetChildViewAt(i); + if (child->GetID() == MenuItemView::kMenuItemViewID) { + MenuItemView* menu_item = static_cast<MenuItemView*>(child); + if (menu_item->HasSubmenu()) + menu_item->RemoveEmptyMenus(); + } else if (child->GetID() == EmptyMenuMenuItem::kEmptyMenuItemViewID) { + submenu_->RemoveChildView(child); + } + } +} + +void MenuItemView::AdjustBoundsForRTLUI(gfx::Rect* rect) const { + rect->set_x(MirroredLeftPointForRect(*rect)); +} + +void MenuItemView::Paint(gfx::Canvas* canvas, bool for_drag) { + bool render_selection = + (!for_drag && IsSelected() && + parent_menu_item_->GetSubmenu()->GetShowSelection(this)); + int state = render_selection ? MPI_HOT : + (IsEnabled() ? MPI_NORMAL : MPI_DISABLED); + HDC dc = canvas->beginPlatformPaint(); + + // The gutter is rendered before the background. + if (render_gutter && !for_drag) { + gfx::Rect gutter_bounds(label_start - kGutterToLabel - gutter_width, 0, + gutter_width, height()); + AdjustBoundsForRTLUI(&gutter_bounds); + RECT gutter_rect = gutter_bounds.ToRECT(); + NativeTheme::instance()->PaintMenuGutter(dc, MENU_POPUPGUTTER, MPI_NORMAL, + &gutter_rect); + } + + // Render the background. + if (!for_drag) { + gfx::Rect item_bounds(0, 0, width(), height()); + AdjustBoundsForRTLUI(&item_bounds); + RECT item_rect = item_bounds.ToRECT(); + NativeTheme::instance()->PaintMenuItemBackground( + NativeTheme::MENU, dc, MENU_POPUPITEM, state, render_selection, + &item_rect); + } + + int icon_x = kItemLeftMargin; + int top_margin = GetTopMargin(); + int bottom_margin = GetBottomMargin(); + int icon_y = top_margin + (height() - kItemTopMargin - + bottom_margin - check_height) / 2; + int icon_height = check_height; + int icon_width = check_width; + + if (type_ == CHECKBOX && GetDelegate()->IsItemChecked(GetCommand())) { + // Draw the check background. + gfx::Rect check_bg_bounds(0, 0, icon_x + icon_width, height()); + const int bg_state = IsEnabled() ? MCB_NORMAL : MCB_DISABLED; + AdjustBoundsForRTLUI(&check_bg_bounds); + RECT check_bg_rect = check_bg_bounds.ToRECT(); + NativeTheme::instance()->PaintMenuCheckBackground( + NativeTheme::MENU, dc, MENU_POPUPCHECKBACKGROUND, bg_state, + &check_bg_rect); + + // And the check. + gfx::Rect check_bounds(icon_x, icon_y, icon_width, icon_height); + const int check_state = IsEnabled() ? MC_CHECKMARKNORMAL : + MC_CHECKMARKDISABLED; + AdjustBoundsForRTLUI(&check_bounds); + RECT check_rect = check_bounds.ToRECT(); + NativeTheme::instance()->PaintMenuCheck( + NativeTheme::MENU, dc, MENU_POPUPCHECK, check_state, &check_rect, + render_selection); + } + + // Render the foreground. + // Menu color is specific to Vista, fallback to classic colors if can't + // get color. + int default_sys_color = render_selection ? COLOR_HIGHLIGHTTEXT : + (IsEnabled() ? COLOR_MENUTEXT : COLOR_GRAYTEXT); + SkColor fg_color = NativeTheme::instance()->GetThemeColorWithDefault( + NativeTheme::MENU, MENU_POPUPITEM, state, TMT_TEXTCOLOR, + default_sys_color); + int width = this->width() - item_right_margin - label_start; + gfx::Font& font = GetRootMenuItem()->font_; + gfx::Rect text_bounds(label_start, top_margin, width, font.height()); + text_bounds.set_x(MirroredLeftPointForRect(text_bounds)); + if (for_drag) { + // With different themes, it's difficult to tell what the correct foreground + // and background colors are for the text to draw the correct halo. Instead, + // just draw black on white, which will look good in most cases. + canvas->DrawStringWithHalo(GetTitle(), font, 0x00000000, 0xFFFFFFFF, + text_bounds.x(), text_bounds.y(), + text_bounds.width(), text_bounds.height(), + GetRootMenuItem()->GetDrawStringFlags()); + } else { + canvas->DrawStringInt(GetTitle(), font, fg_color, + text_bounds.x(), text_bounds.y(), text_bounds.width(), + text_bounds.height(), + GetRootMenuItem()->GetDrawStringFlags()); + } + + if (icon_.width() > 0) { + gfx::Rect icon_bounds(kItemLeftMargin, + top_margin + (height() - top_margin - + bottom_margin - icon_.height()) / 2, + icon_.width(), + icon_.height()); + icon_bounds.set_x(MirroredLeftPointForRect(icon_bounds)); + canvas->DrawBitmapInt(icon_, icon_bounds.x(), icon_bounds.y()); + } + + if (HasSubmenu()) { + int state_id = IsEnabled() ? MSM_NORMAL : MSM_DISABLED; + gfx::Rect arrow_bounds(this->width() - item_right_margin + kLabelToArrowPadding, + 0, arrow_width, height()); + AdjustBoundsForRTLUI(&arrow_bounds); + + // If our sub menus open from right to left (which is the case when the + // locale is RTL) then we should make sure the menu arrow points to the + // right direction. + NativeTheme::MenuArrowDirection arrow_direction; + if (UILayoutIsRightToLeft()) + arrow_direction = NativeTheme::LEFT_POINTING_ARROW; + else + arrow_direction = NativeTheme::RIGHT_POINTING_ARROW; + + RECT arrow_rect = arrow_bounds.ToRECT(); + NativeTheme::instance()->PaintMenuArrow( + NativeTheme::MENU, dc, MENU_POPUPSUBMENU, state_id, &arrow_rect, + arrow_direction, render_selection); + } + canvas->endPlatformPaint(); +} + +void MenuItemView::DestroyAllMenuHosts() { + if (!HasSubmenu()) + return; + + submenu_->Close(); + for (int i = 0, item_count = submenu_->GetMenuItemCount(); i < item_count; + ++i) { + submenu_->GetMenuItemAt(i)->DestroyAllMenuHosts(); + } +} + +int MenuItemView::GetTopMargin() { + MenuItemView* root = GetRootMenuItem(); + return root && root->has_icons_ ? kItemTopMargin : kItemNoIconTopMargin; +} + +int MenuItemView::GetBottomMargin() { + MenuItemView* root = GetRootMenuItem(); + return root && root->has_icons_ ? + kItemBottomMargin : kItemNoIconBottomMargin; +} + +} // namespace views |