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

Side by Side Diff: base/popup_menu.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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
« no previous file with comments | « base/popup_menu.h ('k') | base/preprocessor_fun.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2005-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/base/popup_menu.h"
17
18 #include <windows.h>
19 #include "omaha/base/debug.h"
20 #include "omaha/base/error.h"
21 #include "omaha/base/logging.h"
22 #include "omaha/base/string.h"
23 #include "omaha/base/utils.h"
24
25 namespace omaha {
26
27 // Hold owner draw data
28 struct OwnerDrawData {
29 HFONT font;
30 CString text;
31 HICON icon;
32
33 OwnerDrawData(HFONT f, const TCHAR* t, HICON i) {
34 font = f;
35 text = t;
36 icon = i;
37 }
38 };
39
40
41 // Default constructor
42 PopupMenu::PopupMenu()
43 : wnd_(NULL) {
44 reset(menu_, ::CreatePopupMenu());
45 ASSERT1(menu_);
46 }
47
48 // Constructor
49 PopupMenu::PopupMenu(HINSTANCE inst, const TCHAR* name)
50 : wnd_(NULL) {
51 LoadFromResource(inst, name);
52 ASSERT1(menu_);
53 }
54
55 // Destructor
56 PopupMenu::~PopupMenu() {
57 }
58
59 // Load from resource
60 bool PopupMenu::LoadFromResource(HINSTANCE inst, const TCHAR* name) {
61 reset(menu_, GetSubMenu(reinterpret_cast<HMENU>(::LoadMenu(inst, name)), 0));
62 return get(menu_) != NULL;
63 }
64
65 // Append menu item
66 bool PopupMenu::AppendMenuItem(int menu_item_id, const TCHAR* text) {
67 return AppendMenuItem(menu_item_id, text, NULL);
68 }
69
70 // Append menu item
71 bool PopupMenu::AppendMenuItem(int menu_item_id,
72 const TCHAR* text,
73 const MenuItemDrawStyle* style) {
74 int count = ::GetMenuItemCount(get(menu_));
75 if (count == -1)
76 return false;
77
78 return InsertMenuItem(menu_item_id, count, true, text, style);
79 }
80
81 // Append separator
82 bool PopupMenu::AppendSeparator() {
83 return AppendMenuItem(-1, NULL, NULL);
84 }
85
86 // Insert menu item
87 bool PopupMenu::InsertMenuItem(int menu_item_id,
88 int before_item,
89 bool by_pos,
90 const TCHAR* text) {
91 return InsertMenuItem(menu_item_id, before_item, by_pos, text, NULL);
92 }
93
94 // Helper function that populates the MENUITEMINFO structure and sets
95 // accelerator keys for OWNERDRAW menu items
96 MENUITEMINFO PopupMenu::PrepareMenuItemInfo(int menu_item_id, const TCHAR* text,
97 const MenuItemDrawStyle* style) {
98 // Fill in the MENUITEMINFO structure
99 MENUITEMINFO menuitem_info;
100 SetZero(menuitem_info);
101 menuitem_info.cbSize = sizeof(MENUITEMINFO);
102 menuitem_info.wID = menu_item_id;
103 if (text == NULL) {
104 menuitem_info.fMask = MIIM_FTYPE | MIIM_ID;
105 menuitem_info.fType = MFT_SEPARATOR;
106 } else {
107 if (!style) {
108 menuitem_info.fMask = MIIM_STRING | MIIM_ID;
109 menuitem_info.fType = MFT_STRING;
110 menuitem_info.dwTypeData = const_cast<TCHAR*>(text);
111 } else {
112 // Handle bold font style
113 HFONT font = NULL;
114 if (style->is_bold) {
115 font = GetBoldFont();
116 }
117
118 // Remove '&' if it is there
119 CString text_str(text);
120 int pos = String_FindChar(text_str, _T('&'));
121 if (pos != -1) {
122 if (pos + 1 < text_str.GetLength()) {
123 accelerator_keys_.Add(Char_ToLower(text_str[pos + 1]), menu_item_id);
124 }
125 ReplaceCString(text_str, _T("&"), _T(""));
126 }
127
128 // Set owner-draw related properties
129 OwnerDrawData* data = new OwnerDrawData(font, text_str, style->icon);
130 menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_ID;
131 menuitem_info.fType = MFT_OWNERDRAW;
132 menuitem_info.dwItemData = reinterpret_cast<ULONG_PTR>(data);
133 }
134 }
135
136 return menuitem_info;
137 }
138
139 // Insert menu item
140 bool PopupMenu::InsertMenuItem(int menu_item_id,
141 int before_item,
142 bool by_pos,
143 const TCHAR* text,
144 const MenuItemDrawStyle* style) {
145 MENUITEMINFO menuitem_info = PrepareMenuItemInfo(menu_item_id, text, style);
146 if (!::InsertMenuItem(get(menu_), before_item, by_pos, &menuitem_info))
147 return false;
148
149 return Redraw();
150 }
151
152 // Insert separator
153 bool PopupMenu::InsertSeparator(int before_item, bool by_pos) {
154 return InsertMenuItem(-1, before_item, by_pos, NULL, NULL);
155 }
156
157 // Modify a given menu item
158 bool PopupMenu::ModifyMenuItem(int menu_item, bool by_pos, const TCHAR* text,
159 const MenuItemDrawStyle* style) {
160 // Get OWNERDRAW data for later deletion
161 MENUITEMINFO menuitem_info;
162 SetZero(menuitem_info);
163 menuitem_info.cbSize = sizeof(MENUITEMINFO);
164 menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA;
165 if (!::GetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {
166 return false;
167 }
168
169 OwnerDrawData* old_owner_data = NULL;
170 if ((menuitem_info.fType | MFT_OWNERDRAW) && menuitem_info.dwItemData) {
171 old_owner_data =
172 reinterpret_cast<OwnerDrawData *>(menuitem_info.dwItemData);
173 }
174
175 // Remove old accelerator mapping
176 int menu_item_id = by_pos ? ::GetMenuItemID(get(menu_), menu_item) :
177 menu_item;
178 int key_pos = accelerator_keys_.FindVal(menu_item_id);
179 if (key_pos != -1) {
180 accelerator_keys_.RemoveAt(key_pos);
181 }
182
183 // Set new menu item info
184 menuitem_info = PrepareMenuItemInfo(menu_item_id, text, style);
185 if (!::SetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {
186 return false;
187 }
188
189 // Delete old owner draw data
190 if (old_owner_data) {
191 delete old_owner_data;
192 }
193
194 // Redraw
195 return Redraw();
196 }
197
198 // Remove a menu item
199 bool PopupMenu::RemoveMenuItem(int menu_item, bool by_pos) {
200 // Get OWNERDRAW data for later deletion
201 MENUITEMINFO menuitem_info;
202 SetZero(menuitem_info);
203 menuitem_info.cbSize = sizeof(MENUITEMINFO);
204 menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA;
205 if (!::GetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {
206 return false;
207 }
208
209 OwnerDrawData* old_owner_data = NULL;
210 if ((menuitem_info.fType | MFT_OWNERDRAW) && menuitem_info.dwItemData) {
211 old_owner_data =
212 reinterpret_cast<OwnerDrawData *>(menuitem_info.dwItemData);
213 }
214
215 // Remove the menu item
216 if (!::RemoveMenu(get(menu_), menu_item, by_pos ? MF_BYPOSITION :
217 MF_BYCOMMAND)) {
218 return false;
219 }
220
221 // Remove old accelerator mapping
222 int menu_item_id = by_pos ? ::GetMenuItemID(get(menu_), menu_item) :
223 menu_item;
224 int key_pos = accelerator_keys_.FindVal(menu_item_id);
225 if (key_pos != -1) {
226 accelerator_keys_.RemoveAt(key_pos);
227 }
228
229 // Delete old owner draw data
230 if (old_owner_data) {
231 delete old_owner_data;
232 }
233
234 // Redraw
235 return Redraw();
236 }
237
238 // Enable menu item
239 bool PopupMenu::EnableMenuItem(int menu_item, bool by_pos, bool enabled) {
240 if (::EnableMenuItem(get(menu_), menu_item,
241 (by_pos ? MF_BYPOSITION : MF_BYCOMMAND) |
242 (enabled ? MF_ENABLED : MF_GRAYED)) == -1)
243 return false;
244
245 return Redraw();
246 }
247
248 // Get menu state
249 bool PopupMenu::GetMenuState(int menu_item, bool by_pos, int* menu_state) {
250 int state = ::GetMenuState(get(menu_),
251 menu_item, by_pos ? MF_BYPOSITION : MF_BYCOMMAND);
252 if (menu_state)
253 *menu_state = state;
254 return state != -1;
255 }
256
257 // Exists a menu item
258 bool PopupMenu::ExistsMenuItem(int menu_item_id) {
259 return GetMenuState(menu_item_id, false, NULL);
260 }
261
262 // Redraw menu
263 bool PopupMenu::Redraw() {
264 if (!wnd_)
265 return true;
266
267 return ::DrawMenuBar(wnd_) == TRUE;
268 }
269
270 // Track menu
271 bool PopupMenu::Track() {
272 ASSERT1(wnd_);
273
274 // If we don't set it to be foreground, it will not stop tracking even
275 // if we click outside of menu.
276 ::SetForegroundWindow(wnd_);
277
278 POINT point = {0, 0};
279 VERIFY(::GetCursorPos(&point), (_T("")));
280
281 uint32 kFlags = TPM_LEFTALIGN |
282 TPM_RETURNCMD |
283 TPM_NONOTIFY |
284 TPM_LEFTBUTTON |
285 TPM_VERTICAL;
286 int command = ::TrackPopupMenuEx(get(menu_),
287 kFlags,
288 point.x, point.y, wnd_, NULL);
289
290 if (command != 0)
291 ::SendMessage(wnd_, WM_COMMAND, command, 0);
292
293 return true;
294 }
295
296 // Handle WM_MEASUREITEM message
297 bool PopupMenu::OnMeasureItem(MEASUREITEMSTRUCT* mi) {
298 ASSERT1(wnd_);
299
300 // Get owner draw data
301 ASSERT1(mi->itemData);
302 OwnerDrawData* data = reinterpret_cast<OwnerDrawData*>(mi->itemData);
303
304 // Get the DC
305 scoped_hdc dc;
306 reset(dc, ::GetDC(wnd_));
307
308 // Select the font
309 HFONT old_font = reinterpret_cast<HFONT>(::SelectObject(get(dc), data->font));
310 if (!old_font)
311 return false;
312
313 // compute the size of the text
314 SIZE size = {0, 0};
315 bool success = ::GetTextExtentPoint32(get(dc),
316 data->text.GetString(),
317 data->text.GetLength(),
318 &size) != 0;
319 if (success) {
320 mi->itemWidth = size.cx;
321 mi->itemHeight = size.cy;
322 }
323
324 // deselect the title font
325 ::SelectObject(get(dc), old_font);
326
327 return success;
328 }
329
330 // Handle WM_MDRAWITEM message
331 bool PopupMenu::OnDrawItem(DRAWITEMSTRUCT* di) {
332 ASSERT1(di);
333
334 // Get owner draw data
335 ASSERT1(di->itemData);
336 OwnerDrawData* data = reinterpret_cast<OwnerDrawData*>(di->itemData);
337
338 // Select the font
339 HFONT prev_font = NULL;
340 if (data->font) {
341 prev_font = reinterpret_cast<HFONT>(::SelectObject(di->hDC, data->font));
342 if (!prev_font) {
343 return false;
344 }
345 }
346
347 // Draw the text per the menuitem state
348 int fg_color_idx =
349 (di->itemState & ODS_DISABLED) ?
350 COLOR_GRAYTEXT :
351 ((di->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT);
352
353 int bg_color_idx =
354 (di->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHT : COLOR_MENU;
355
356 bool success = DrawText(data->text, di, fg_color_idx, bg_color_idx);
357
358 // Restore the original font
359 if (prev_font) {
360 ::SelectObject(di->hDC, prev_font);
361 }
362
363 // Compute the width and height
364 int height = di->rcItem.bottom - di->rcItem.top + 1;
365 int width = static_cast<int>(::GetSystemMetrics(SM_CXMENUCHECK) *
366 (static_cast<double>(height) / ::GetSystemMetrics(SM_CYMENUCHECK)));
367
368 // Draw the icon
369 // TODO(omaha): Draw a grayed icon when the menuitem is disabled
370 if (success && data->icon) {
371 success = ::DrawIconEx(di->hDC,
372 di->rcItem.left,
373 di->rcItem.top,
374 data->icon,
375 width,
376 height,
377 0,
378 NULL,
379 DI_NORMAL) != 0;
380 }
381
382 return success;
383 }
384
385 // Draw the text
386 bool PopupMenu::DrawText(const CString& text,
387 DRAWITEMSTRUCT* di,
388 int fg_color_idx,
389 int bg_color_idx) {
390 // Set the appropriate foreground and background colors
391 COLORREF prev_fg_color = 0, prev_bg_color = 0;
392 prev_fg_color = ::SetTextColor(di->hDC, ::GetSysColor(fg_color_idx));
393 if (prev_fg_color == CLR_INVALID) {
394 return false;
395 }
396 prev_bg_color = ::SetBkColor(di->hDC, ::GetSysColor(bg_color_idx));
397 if (prev_bg_color == CLR_INVALID) {
398 return false;
399 }
400
401 // Draw the text
402 bool success = ::ExtTextOut(
403 di->hDC,
404 di->rcItem.left + ::GetSystemMetrics(SM_CXMENUCHECK) + 4,
405 di->rcItem.top,
406 ETO_OPAQUE,
407 &di->rcItem,
408 text.GetString(),
409 text.GetLength(),
410 NULL) == TRUE;
411
412 // Restore the original colors
413 ::SetTextColor(di->hDC, prev_fg_color);
414 ::SetBkColor(di->hDC, prev_bg_color);
415
416 return success;
417 }
418
419 // Handle WM_MENUCHAR message
420 int PopupMenu::OnMenuChar(TCHAR key) {
421 int pos = accelerator_keys_.FindKey(Char_ToLower(key));
422 if (pos != -1)
423 return GetMenuPosFromID(accelerator_keys_.GetValueAt(pos));
424 else
425 return -1;
426 }
427
428 HFONT PopupMenu::GetBoldFont() {
429 if (!bold_font_) {
430 NONCLIENTMETRICS ncm;
431 SetZero(ncm);
432 ncm.cbSize = sizeof(NONCLIENTMETRICS);
433 if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {
434 ncm.lfMenuFont.lfWeight = FW_BOLD;
435 reset(bold_font_, ::CreateFontIndirect(&ncm.lfMenuFont));
436 } else {
437 UTIL_LOG(LEVEL_ERROR, (_T("[PopupMenu::GetBoldFont]")
438 _T("[failed to get system menu font][0x%x]"),
439 HRESULTFromLastError()));
440 }
441 }
442
443 ASSERT1(bold_font_);
444
445 return get(bold_font_);
446 }
447
448 // Get menu pos from ID
449 int PopupMenu::GetMenuPosFromID(int id) {
450 ASSERT1(id >= 0);
451 int count = ::GetMenuItemCount(get(menu_));
452 if (count > 0) {
453 for (int pos = 0; pos < count; ++pos) {
454 if (::GetMenuItemID(get(menu_), pos) == static_cast<UINT>(id)) {
455 return pos;
456 }
457 }
458 }
459
460 return -1;
461 }
462
463 } // namespace omaha
464
OLDNEW
« no previous file with comments | « base/popup_menu.h ('k') | base/preprocessor_fun.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698