| Index: views/controls/menu/native_menu_win.cc
|
| ===================================================================
|
| --- views/controls/menu/native_menu_win.cc (revision 18347)
|
| +++ views/controls/menu/native_menu_win.cc (working copy)
|
| @@ -4,15 +4,32 @@
|
|
|
| #include "views/controls/menu/native_menu_win.h"
|
|
|
| +#include "app/gfx/canvas.h"
|
| +#include "app/gfx/font.h"
|
| #include "app/l10n_util.h"
|
| #include "app/l10n_util_win.h"
|
| #include "base/logging.h"
|
| #include "base/stl_util-inl.h"
|
| +#include "third_party/skia/include/core/SkBitmap.h"
|
| #include "views/accelerator.h"
|
| #include "views/controls/menu/menu_2.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;
|
| +
|
| struct NativeMenuWin::ItemData {
|
| // The Windows API requires that whoever creates the menus must own the
|
| // strings used for labels, and keep them around for the lifetime of the
|
| @@ -21,6 +38,12 @@
|
|
|
| // Someone needs to own submenus, it may as well be us.
|
| scoped_ptr<Menu2> submenu;
|
| +
|
| + // We need a pointer back to the containing menu in various circumstances.
|
| + NativeMenuWin* native_menu_win;
|
| +
|
| + // The index of the item within the menu's model.
|
| + int model_index;
|
| };
|
|
|
| // A window that receives messages from Windows relevant to the native menu
|
| @@ -90,6 +113,10 @@
|
| return w_param;
|
| }
|
|
|
| + NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) {
|
| + return reinterpret_cast<NativeMenuWin::ItemData*>(item_data);
|
| + }
|
| +
|
| // Called when the user selects a specific item.
|
| void OnMenuCommand(int position, HMENU menu) {
|
| NativeMenuWin* intergoat = GetNativeMenuWinFromHMENU(menu);
|
| @@ -108,6 +135,112 @@
|
| GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position);
|
| }
|
|
|
| + // Called by Windows to measure the size of an owner-drawn menu item.
|
| + void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
|
| + NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
|
| + if (data) {
|
| + gfx::Font font;
|
| + measure_item_struct->itemWidth = font.GetStringWidth(data->label) +
|
| + kIconWidth + kItemLeftMargin + kItemRightMargin -
|
| + GetSystemMetrics(SM_CXMENUCHECK);
|
| + if (data->submenu.get())
|
| + measure_item_struct->itemWidth += kArrowWidth;
|
| + // If the label contains an accelerator, make room for tab.
|
| + if (data->label.find(L'\t') != std::wstring::npos)
|
| + measure_item_struct->itemWidth += font.GetStringWidth(L" ");
|
| + measure_item_struct->itemHeight =
|
| + font.height() + kItemBottomMargin + kItemTopMargin;
|
| + } else {
|
| + // Measure separator size.
|
| + measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
|
| + measure_item_struct->itemWidth = 0;
|
| + }
|
| + }
|
| +
|
| + // Called by Windows to paint an owner-drawn menu item.
|
| + void OnDrawItem(UINT w_param, DRAWITEMSTRUCT* draw_item_struct) {
|
| + HDC dc = draw_item_struct->hDC;
|
| + COLORREF prev_bg_color, prev_text_color;
|
| +
|
| + // Set background color and text color
|
| + if (draw_item_struct->itemState & ODS_SELECTED) {
|
| + prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
|
| + prev_text_color = SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
| + } else {
|
| + prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_MENU));
|
| + if (draw_item_struct->itemState & ODS_DISABLED)
|
| + prev_text_color = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
|
| + else
|
| + prev_text_color = SetTextColor(dc, GetSysColor(COLOR_MENUTEXT));
|
| + }
|
| +
|
| + if (draw_item_struct->itemData) {
|
| + NativeMenuWin::ItemData* data = GetItemData(draw_item_struct->itemData);
|
| + // Draw the background.
|
| + HBRUSH hbr = CreateSolidBrush(GetBkColor(dc));
|
| + FillRect(dc, &draw_item_struct->rcItem, hbr);
|
| + DeleteObject(hbr);
|
| +
|
| + // Draw the label.
|
| + RECT rect = draw_item_struct->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;
|
| + gfx::Font font;
|
| + HGDIOBJ old_font = static_cast<HFONT>(SelectObject(dc, 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(dc, const_cast<wchar_t*>(label.data()),
|
| + static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
|
| + if (!accel.empty())
|
| + DrawTextEx(dc, const_cast<wchar_t*>(accel.data()),
|
| + static_cast<int>(accel.size()), &rect,
|
| + format | DT_RIGHT, NULL);
|
| + SelectObject(dc, old_font);
|
| +
|
| + // Draw the icon after the label, otherwise it would be covered
|
| + // by the label.
|
| + SkBitmap icon;
|
| + if (data->native_menu_win->model_->GetIconAt(data->model_index, &icon)) {
|
| + gfx::Canvas canvas(icon.width(), icon.height(), false);
|
| + canvas.drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode);
|
| + canvas.DrawBitmapInt(icon, 0, 0);
|
| + canvas.getTopPlatformDevice().drawToHDC(dc,
|
| + draw_item_struct->rcItem.left + kItemLeftMargin,
|
| + draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
|
| + draw_item_struct->rcItem.top - icon.height()) / 2, NULL);
|
| + }
|
| +
|
| + } else {
|
| + // Draw the separator
|
| + draw_item_struct->rcItem.top +=
|
| + (draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3;
|
| + DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP);
|
| + }
|
| +
|
| + SetBkColor(dc, prev_bg_color);
|
| + SetTextColor(dc, prev_text_color);
|
| + }
|
| +
|
| bool ProcessWindowMessage(HWND window,
|
| UINT message,
|
| WPARAM w_param,
|
| @@ -122,6 +255,14 @@
|
| OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param));
|
| *l_result = 0;
|
| return true;
|
| + case WM_MEASUREITEM:
|
| + OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param));
|
| + *l_result = 0;
|
| + return true;
|
| + case WM_DRAWITEM:
|
| + OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param));
|
| + *l_result = 0;
|
| + return true;
|
| // TODO(beng): bring over owner draw from old menu system.
|
| }
|
| return false;
|
| @@ -213,7 +354,7 @@
|
| SetMenuItemLabel(menu_index, model_index,
|
| model_->GetLabelAt(model_index));
|
| }
|
| - Menu2* submenu = items_.at(model_index)->submenu.get();
|
| + Menu2* submenu = items_[model_index]->submenu.get();
|
| if (submenu)
|
| submenu->UpdateStates();
|
| }
|
| @@ -242,9 +383,9 @@
|
| mii.fType = MFT_STRING;
|
| else
|
| mii.fType = MFT_OWNERDRAW;
|
| - mii.dwItemData = reinterpret_cast<ULONG_PTR>(this);
|
|
|
| ItemData* item_data = new ItemData;
|
| + item_data->label = std::wstring();
|
| Menu2Model::ItemType type = model_->GetTypeAt(model_index);
|
| if (type == Menu2Model::TYPE_SUBMENU) {
|
| item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
|
| @@ -255,7 +396,10 @@
|
| mii.fType |= MFT_RADIOCHECK;
|
| mii.wID = model_->GetCommandIdAt(model_index);
|
| }
|
| + item_data->native_menu_win = this;
|
| + item_data->model_index = model_index;
|
| items_.insert(items_.begin() + model_index, item_data);
|
| + mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data);
|
| UpdateMenuItemInfoForString(&mii, model_index,
|
| model_->GetLabelAt(model_index));
|
| InsertMenuItem(menu_, menu_index, TRUE, &mii);
|
| @@ -331,24 +475,6 @@
|
| }
|
| }
|
|
|
| -NativeMenuWin* NativeMenuWin::GetMenuForCommandId(UINT command_id) const {
|
| - // Menus can have nested submenus. In the views Menu system, each submenu is
|
| - // wrapped in a NativeMenu instance, which may have a different model and
|
| - // delegate from the parent menu. The trouble is, RunMenuAt is called on the
|
| - // parent NativeMenuWin, and so it's not possible to assume that we can just
|
| - // dispatch the command id returned by TrackPopupMenuEx to the parent's
|
| - // delegate. For this reason, we stow a pointer on every menu item we create
|
| - // to the NativeMenuWin that most closely contains it. Fortunately, Windows
|
| - // provides GetMenuItemInfo, which can walk down the menu item tree from
|
| - // the root |menu_| to find the data for a given item even if it's in a
|
| - // submenu.
|
| - MENUITEMINFO mii = {0};
|
| - mii.cbSize = sizeof(mii);
|
| - mii.fMask = MIIM_DATA;
|
| - GetMenuItemInfo(menu_, command_id, FALSE, &mii);
|
| - return reinterpret_cast<NativeMenuWin*>(mii.dwItemData);
|
| -}
|
| -
|
| UINT NativeMenuWin::GetAlignmentFlags(int alignment) const {
|
| bool rtl = l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT;
|
| UINT alignment_flags = TPM_TOPALIGN;
|
|
|