Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1650)

Side by Side Diff: views/controls/menu/native_menu_win.cc

Issue 126092: Begin to upgrade BackForwardMenuModelViews to use new menu API.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in the 2 // source code is governed by a BSD-style license that can be found in the
3 // LICENSE file. 3 // LICENSE file.
4 4
5 #include "views/controls/menu/native_menu_win.h" 5 #include "views/controls/menu/native_menu_win.h"
6 6
7 #include "app/gfx/canvas.h"
8 #include "app/gfx/font.h"
7 #include "app/l10n_util.h" 9 #include "app/l10n_util.h"
8 #include "app/l10n_util_win.h" 10 #include "app/l10n_util_win.h"
9 #include "base/logging.h" 11 #include "base/logging.h"
10 #include "base/stl_util-inl.h" 12 #include "base/stl_util-inl.h"
13 #include "third_party/skia/include/core/SkBitmap.h"
11 #include "views/accelerator.h" 14 #include "views/accelerator.h"
12 #include "views/controls/menu/menu_2.h" 15 #include "views/controls/menu/menu_2.h"
13 16
14 namespace views { 17 namespace views {
15 18
19 // The width of an icon, including the pixels between the icon and
20 // the item label.
21 static const int kIconWidth = 23;
22 // Margins between the top of the item and the label.
23 static const int kItemTopMargin = 3;
24 // Margins between the bottom of the item and the label.
25 static const int kItemBottomMargin = 4;
26 // Margins between the left of the item and the icon.
27 static const int kItemLeftMargin = 4;
28 // Margins between the right of the item and the label.
29 static const int kItemRightMargin = 10;
30 // The width for displaying the sub-menu arrow.
31 static const int kArrowWidth = 10;
32
16 struct NativeMenuWin::ItemData { 33 struct NativeMenuWin::ItemData {
17 // The Windows API requires that whoever creates the menus must own the 34 // The Windows API requires that whoever creates the menus must own the
18 // strings used for labels, and keep them around for the lifetime of the 35 // strings used for labels, and keep them around for the lifetime of the
19 // created menu. So be it. 36 // created menu. So be it.
20 std::wstring label; 37 std::wstring label;
21 38
22 // Someone needs to own submenus, it may as well be us. 39 // Someone needs to own submenus, it may as well be us.
23 scoped_ptr<Menu2> submenu; 40 scoped_ptr<Menu2> submenu;
41
42 // We need a pointer back to the containing menu in various circumstances.
43 NativeMenuWin* native_menu_win;
44
45 // The index of the item within the menu's model.
46 int model_index;
24 }; 47 };
25 48
26 // A window that receives messages from Windows relevant to the native menu 49 // A window that receives messages from Windows relevant to the native menu
27 // structure we have constructed in NativeMenuWin. 50 // structure we have constructed in NativeMenuWin.
28 class NativeMenuWin::MenuHostWindow { 51 class NativeMenuWin::MenuHostWindow {
29 public: 52 public:
30 MenuHostWindow() { 53 MenuHostWindow() {
31 RegisterClass(); 54 RegisterClass();
32 hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName, 55 hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName,
33 L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 56 L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 if (mii.wID == w_param) 106 if (mii.wID == w_param)
84 return i; 107 return i;
85 } 108 }
86 // If we didn't find a matching command ID, this means a submenu has been 109 // If we didn't find a matching command ID, this means a submenu has been
87 // selected instead, and rather than passing a command ID in 110 // selected instead, and rather than passing a command ID in
88 // LOWORD(w_param), Windows has actually passed us a position, so we just 111 // LOWORD(w_param), Windows has actually passed us a position, so we just
89 // return it. 112 // return it.
90 return w_param; 113 return w_param;
91 } 114 }
92 115
116 NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) {
117 return reinterpret_cast<NativeMenuWin::ItemData*>(item_data);
118 }
119
93 // Called when the user selects a specific item. 120 // Called when the user selects a specific item.
94 void OnMenuCommand(int position, HMENU menu) { 121 void OnMenuCommand(int position, HMENU menu) {
95 NativeMenuWin* intergoat = GetNativeMenuWinFromHMENU(menu); 122 NativeMenuWin* intergoat = GetNativeMenuWinFromHMENU(menu);
96 Menu2Model* model = intergoat->model_; 123 Menu2Model* model = intergoat->model_;
97 model->ActivatedAt(position); 124 model->ActivatedAt(position);
98 } 125 }
99 126
100 // Called as the user moves their mouse or arrows through the contents of the 127 // Called as the user moves their mouse or arrows through the contents of the
101 // menu. 128 // menu.
102 void OnMenuSelect(WPARAM w_param, HMENU menu) { 129 void OnMenuSelect(WPARAM w_param, HMENU menu) {
103 if (!menu) 130 if (!menu)
104 return; // menu is null when closing on XP. 131 return; // menu is null when closing on XP.
105 132
106 int position = GetMenuItemIndexFromWPARAM(menu, w_param); 133 int position = GetMenuItemIndexFromWPARAM(menu, w_param);
107 if (position >= 0) 134 if (position >= 0)
108 GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position); 135 GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position);
109 } 136 }
110 137
138 // Called by Windows to measure the size of an owner-drawn menu item.
139 void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
140 NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
141 if (data) {
142 gfx::Font font;
143 measure_item_struct->itemWidth = font.GetStringWidth(data->label) +
144 kIconWidth + kItemLeftMargin + kItemRightMargin -
145 GetSystemMetrics(SM_CXMENUCHECK);
146 if (data->submenu.get())
147 measure_item_struct->itemWidth += kArrowWidth;
148 // If the label contains an accelerator, make room for tab.
149 if (data->label.find(L'\t') != std::wstring::npos)
150 measure_item_struct->itemWidth += font.GetStringWidth(L" ");
151 measure_item_struct->itemHeight =
152 font.height() + kItemBottomMargin + kItemTopMargin;
153 } else {
154 // Measure separator size.
155 measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
156 measure_item_struct->itemWidth = 0;
157 }
158 }
159
160 // Called by Windows to paint an owner-drawn menu item.
161 void OnDrawItem(UINT w_param, DRAWITEMSTRUCT* draw_item_struct) {
162 HDC dc = draw_item_struct->hDC;
163 COLORREF prev_bg_color, prev_text_color;
164
165 // Set background color and text color
166 if (draw_item_struct->itemState & ODS_SELECTED) {
167 prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
168 prev_text_color = SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
169 } else {
170 prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_MENU));
171 if (draw_item_struct->itemState & ODS_DISABLED)
172 prev_text_color = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
173 else
174 prev_text_color = SetTextColor(dc, GetSysColor(COLOR_MENUTEXT));
175 }
176
177 if (draw_item_struct->itemData) {
178 NativeMenuWin::ItemData* data = GetItemData(draw_item_struct->itemData);
179 // Draw the background.
180 HBRUSH hbr = CreateSolidBrush(GetBkColor(dc));
181 FillRect(dc, &draw_item_struct->rcItem, hbr);
182 DeleteObject(hbr);
183
184 // Draw the label.
185 RECT rect = draw_item_struct->rcItem;
186 rect.top += kItemTopMargin;
187 // Should we add kIconWidth only when icon.width() != 0 ?
188 rect.left += kItemLeftMargin + kIconWidth;
189 rect.right -= kItemRightMargin;
190 UINT format = DT_TOP | DT_SINGLELINE;
191 // Check whether the mnemonics should be underlined.
192 BOOL underline_mnemonics;
193 SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
194 if (!underline_mnemonics)
195 format |= DT_HIDEPREFIX;
196 gfx::Font font;
197 HGDIOBJ old_font = static_cast<HFONT>(SelectObject(dc, font.hfont()));
198 int fontsize = font.FontSize();
199
200 // If an accelerator is specified (with a tab delimiting the rest of the
201 // label from the accelerator), we have to justify the fist part on the
202 // left and the accelerator on the right.
203 // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
204 // window system UI font and will not hit here.
205 std::wstring label = data->label;
206 std::wstring accel;
207 std::wstring::size_type tab_pos = label.find(L'\t');
208 if (tab_pos != std::wstring::npos) {
209 accel = label.substr(tab_pos);
210 label = label.substr(0, tab_pos);
211 }
212 DrawTextEx(dc, const_cast<wchar_t*>(label.data()),
213 static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
214 if (!accel.empty())
215 DrawTextEx(dc, const_cast<wchar_t*>(accel.data()),
216 static_cast<int>(accel.size()), &rect,
217 format | DT_RIGHT, NULL);
218 SelectObject(dc, old_font);
219
220 // Draw the icon after the label, otherwise it would be covered
221 // by the label.
222 SkBitmap icon;
223 if (data->native_menu_win->model_->GetIconAt(data->model_index, &icon)) {
224 gfx::Canvas canvas(icon.width(), icon.height(), false);
225 canvas.drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode);
226 canvas.DrawBitmapInt(icon, 0, 0);
227 canvas.getTopPlatformDevice().drawToHDC(dc,
228 draw_item_struct->rcItem.left + kItemLeftMargin,
229 draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
230 draw_item_struct->rcItem.top - icon.height()) / 2, NULL);
231 }
232
233 } else {
234 // Draw the separator
235 draw_item_struct->rcItem.top +=
236 (draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3;
237 DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP);
238 }
239
240 SetBkColor(dc, prev_bg_color);
241 SetTextColor(dc, prev_text_color);
242 }
243
111 bool ProcessWindowMessage(HWND window, 244 bool ProcessWindowMessage(HWND window,
112 UINT message, 245 UINT message,
113 WPARAM w_param, 246 WPARAM w_param,
114 LPARAM l_param, 247 LPARAM l_param,
115 LRESULT* l_result) { 248 LRESULT* l_result) {
116 switch (message) { 249 switch (message) {
117 case WM_MENUCOMMAND: 250 case WM_MENUCOMMAND:
118 OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param)); 251 OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
119 *l_result = 0; 252 *l_result = 0;
120 return true; 253 return true;
121 case WM_MENUSELECT: 254 case WM_MENUSELECT:
122 OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param)); 255 OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param));
123 *l_result = 0; 256 *l_result = 0;
124 return true; 257 return true;
258 case WM_MEASUREITEM:
259 OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param));
260 *l_result = 0;
261 return true;
262 case WM_DRAWITEM:
263 OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param));
264 *l_result = 0;
265 return true;
125 // TODO(beng): bring over owner draw from old menu system. 266 // TODO(beng): bring over owner draw from old menu system.
126 } 267 }
127 return false; 268 return false;
128 } 269 }
129 270
130 static LRESULT CALLBACK MenuHostWindowProc(HWND window, 271 static LRESULT CALLBACK MenuHostWindowProc(HWND window,
131 UINT message, 272 UINT message,
132 WPARAM w_param, 273 WPARAM w_param,
133 LPARAM l_param) { 274 LPARAM l_param) {
134 MenuHostWindow* host = 275 MenuHostWindow* host =
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 // A depth-first walk of the menu items, updating states. 347 // A depth-first walk of the menu items, updating states.
207 for (int menu_index = first_item_index_; 348 for (int menu_index = first_item_index_;
208 menu_index < first_item_index_ + model_->GetItemCount(); ++menu_index) { 349 menu_index < first_item_index_ + model_->GetItemCount(); ++menu_index) {
209 int model_index = menu_index - first_item_index_; 350 int model_index = menu_index - first_item_index_;
210 SetMenuItemState(menu_index, model_->IsEnabledAt(model_index), 351 SetMenuItemState(menu_index, model_->IsEnabledAt(model_index),
211 model_->IsItemCheckedAt(model_index), false); 352 model_->IsItemCheckedAt(model_index), false);
212 if (model_->IsLabelDynamicAt(model_index)) { 353 if (model_->IsLabelDynamicAt(model_index)) {
213 SetMenuItemLabel(menu_index, model_index, 354 SetMenuItemLabel(menu_index, model_index,
214 model_->GetLabelAt(model_index)); 355 model_->GetLabelAt(model_index));
215 } 356 }
216 Menu2* submenu = items_.at(model_index)->submenu.get(); 357 Menu2* submenu = items_[model_index]->submenu.get();
217 if (submenu) 358 if (submenu)
218 submenu->UpdateStates(); 359 submenu->UpdateStates();
219 } 360 }
220 } 361 }
221 362
222 gfx::NativeMenu NativeMenuWin::GetNativeMenu() const { 363 gfx::NativeMenu NativeMenuWin::GetNativeMenu() const {
223 return menu_; 364 return menu_;
224 } 365 }
225 366
226 //////////////////////////////////////////////////////////////////////////////// 367 ////////////////////////////////////////////////////////////////////////////////
227 // NativeMenuWin, private: 368 // NativeMenuWin, private:
228 369
229 bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const { 370 bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const {
230 MENUITEMINFO mii = {0}; 371 MENUITEMINFO mii = {0};
231 mii.cbSize = sizeof(mii); 372 mii.cbSize = sizeof(mii);
232 mii.fMask = MIIM_FTYPE; 373 mii.fMask = MIIM_FTYPE;
233 GetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii); 374 GetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
234 return !!(mii.fType & MF_SEPARATOR); 375 return !!(mii.fType & MF_SEPARATOR);
235 } 376 }
236 377
237 void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) { 378 void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
238 MENUITEMINFO mii = {0}; 379 MENUITEMINFO mii = {0};
239 mii.cbSize = sizeof(mii); 380 mii.cbSize = sizeof(mii);
240 mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA; 381 mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA;
241 if (!owner_draw_) 382 if (!owner_draw_)
242 mii.fType = MFT_STRING; 383 mii.fType = MFT_STRING;
243 else 384 else
244 mii.fType = MFT_OWNERDRAW; 385 mii.fType = MFT_OWNERDRAW;
245 mii.dwItemData = reinterpret_cast<ULONG_PTR>(this);
246 386
247 ItemData* item_data = new ItemData; 387 ItemData* item_data = new ItemData;
388 item_data->label = std::wstring();
248 Menu2Model::ItemType type = model_->GetTypeAt(model_index); 389 Menu2Model::ItemType type = model_->GetTypeAt(model_index);
249 if (type == Menu2Model::TYPE_SUBMENU) { 390 if (type == Menu2Model::TYPE_SUBMENU) {
250 item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index))); 391 item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
251 mii.fMask |= MIIM_SUBMENU; 392 mii.fMask |= MIIM_SUBMENU;
252 mii.hSubMenu = item_data->submenu->GetNativeMenu(); 393 mii.hSubMenu = item_data->submenu->GetNativeMenu();
253 } else { 394 } else {
254 if (type == Menu2Model::TYPE_RADIO) 395 if (type == Menu2Model::TYPE_RADIO)
255 mii.fType |= MFT_RADIOCHECK; 396 mii.fType |= MFT_RADIOCHECK;
256 mii.wID = model_->GetCommandIdAt(model_index); 397 mii.wID = model_->GetCommandIdAt(model_index);
257 } 398 }
399 item_data->native_menu_win = this;
400 item_data->model_index = model_index;
258 items_.insert(items_.begin() + model_index, item_data); 401 items_.insert(items_.begin() + model_index, item_data);
402 mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data);
259 UpdateMenuItemInfoForString(&mii, model_index, 403 UpdateMenuItemInfoForString(&mii, model_index,
260 model_->GetLabelAt(model_index)); 404 model_->GetLabelAt(model_index));
261 InsertMenuItem(menu_, menu_index, TRUE, &mii); 405 InsertMenuItem(menu_, menu_index, TRUE, &mii);
262 } 406 }
263 407
264 void NativeMenuWin::AddSeparatorItemAt(int menu_index, int model_index) { 408 void NativeMenuWin::AddSeparatorItemAt(int menu_index, int model_index) {
265 MENUITEMINFO mii = {0}; 409 MENUITEMINFO mii = {0};
266 mii.cbSize = sizeof(mii); 410 mii.cbSize = sizeof(mii);
267 mii.fMask = MIIM_FTYPE; 411 mii.fMask = MIIM_FTYPE;
268 mii.fType = MFT_SEPARATOR; 412 mii.fType = MFT_SEPARATOR;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 468
325 // Windows only requires a pointer to the label string if it's going to be 469 // Windows only requires a pointer to the label string if it's going to be
326 // doing the drawing. 470 // doing the drawing.
327 if (!owner_draw_) { 471 if (!owner_draw_) {
328 mii->fMask |= MIIM_STRING; 472 mii->fMask |= MIIM_STRING;
329 mii->dwTypeData = 473 mii->dwTypeData =
330 const_cast<wchar_t*>(items_.at(model_index)->label.c_str()); 474 const_cast<wchar_t*>(items_.at(model_index)->label.c_str());
331 } 475 }
332 } 476 }
333 477
334 NativeMenuWin* NativeMenuWin::GetMenuForCommandId(UINT command_id) const {
335 // Menus can have nested submenus. In the views Menu system, each submenu is
336 // wrapped in a NativeMenu instance, which may have a different model and
337 // delegate from the parent menu. The trouble is, RunMenuAt is called on the
338 // parent NativeMenuWin, and so it's not possible to assume that we can just
339 // dispatch the command id returned by TrackPopupMenuEx to the parent's
340 // delegate. For this reason, we stow a pointer on every menu item we create
341 // to the NativeMenuWin that most closely contains it. Fortunately, Windows
342 // provides GetMenuItemInfo, which can walk down the menu item tree from
343 // the root |menu_| to find the data for a given item even if it's in a
344 // submenu.
345 MENUITEMINFO mii = {0};
346 mii.cbSize = sizeof(mii);
347 mii.fMask = MIIM_DATA;
348 GetMenuItemInfo(menu_, command_id, FALSE, &mii);
349 return reinterpret_cast<NativeMenuWin*>(mii.dwItemData);
350 }
351
352 UINT NativeMenuWin::GetAlignmentFlags(int alignment) const { 478 UINT NativeMenuWin::GetAlignmentFlags(int alignment) const {
353 bool rtl = l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT; 479 bool rtl = l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT;
354 UINT alignment_flags = TPM_TOPALIGN; 480 UINT alignment_flags = TPM_TOPALIGN;
355 if (alignment == Menu2::ALIGN_TOPLEFT) 481 if (alignment == Menu2::ALIGN_TOPLEFT)
356 alignment_flags |= TPM_LEFTALIGN; 482 alignment_flags |= TPM_LEFTALIGN;
357 else if (alignment == Menu2::ALIGN_TOPRIGHT) 483 else if (alignment == Menu2::ALIGN_TOPRIGHT)
358 alignment_flags |= TPM_RIGHTALIGN; 484 alignment_flags |= TPM_RIGHTALIGN;
359 return alignment_flags; 485 return alignment_flags;
360 } 486 }
361 487
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 531
406 //////////////////////////////////////////////////////////////////////////////// 532 ////////////////////////////////////////////////////////////////////////////////
407 // MenuWrapper, public: 533 // MenuWrapper, public:
408 534
409 // static 535 // static
410 MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) { 536 MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) {
411 return new NativeMenuWin(menu->model(), NULL); 537 return new NativeMenuWin(menu->model(), NULL);
412 } 538 }
413 539
414 } // namespace views 540 } // namespace views
OLDNEW
« chrome/browser/back_forward_menu_model.h ('K') | « views/controls/menu/native_menu_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698