summaryrefslogtreecommitdiffstats
path: root/ui/views/controls/menu/native_menu_win.h
blob: 08e07bade49e0fd0a79c1036591753bae7de4824 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright (c) 2011 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 UI_VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
#define UI_VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
#pragma once

#include <vector>

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/controls/menu/menu_wrapper.h"
#include "ui/views/views_export.h"

namespace views {

// A Windows implementation of MenuWrapper.
// TODO(beng): rename to MenuWin once the old class is dead.
class VIEWS_EXPORT NativeMenuWin : public MenuWrapper {
 public:
  // Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
  // is non-NULL, the NativeMenuWin wraps the system menu for that window.
  // The caller owns the model and the delegate.
  NativeMenuWin(ui::MenuModel* model, HWND system_menu_for);
  virtual ~NativeMenuWin();

  // Overridden from MenuWrapper:
  virtual void RunMenuAt(const gfx::Point& point, int alignment) OVERRIDE;
  virtual void CancelMenu() OVERRIDE;
  virtual void Rebuild() OVERRIDE;
  virtual void UpdateStates() OVERRIDE;
  virtual gfx::NativeMenu GetNativeMenu() const OVERRIDE;
  virtual MenuAction GetMenuAction() const OVERRIDE;
  virtual void AddMenuListener(MenuListener* listener) OVERRIDE;
  virtual void RemoveMenuListener(MenuListener* listener) OVERRIDE;
  virtual void SetMinimumWidth(int width) OVERRIDE;

 private:
  // IMPORTANT: Note about indices.
  //            Functions in this class deal in two index spaces:
  //            1. menu_index - the index of an item within the actual Windows
  //               native menu.
  //            2. model_index - the index of the item within our model.
  //            These two are most often but not always the same value! The
  //            notable exception is when this object is used to wrap the
  //            Windows System Menu. In this instance, the model indices start
  //            at 0, but the insertion index into the existing menu is not.
  //            It is important to take this into consideration when editing the
  //            code in the functions in this class.

  struct HighlightedMenuItemInfo;

  // Returns true if the item at the specified index is a separator.
  bool IsSeparatorItemAt(int menu_index) const;

  // Add items. See note above about indices.
  void AddMenuItemAt(int menu_index, int model_index);
  void AddSeparatorItemAt(int menu_index, int model_index);

  // Sets the state of the item at the specified index.
  void SetMenuItemState(int menu_index,
                        bool enabled,
                        bool checked,
                        bool is_default);

  // Sets the label of the item at the specified index.
  void SetMenuItemLabel(int menu_index,
                        int model_index,
                        const string16& label);

  // Updates the local data structure with the correctly formatted version of
  // |label| at the specified model_index, and adds string data to |mii| if
  // the menu is not owner-draw. That's a mouthful. This function exists because
  // of the peculiarities of the Windows menu API.
  void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
                                   int model_index,
                                   const string16& label);

  // Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
  // supplied alignment and the UI text direction.
  UINT GetAlignmentFlags(int alignment) const;

  // Resets the native menu stored in |menu_| by destroying any old menu then
  // creating a new empty one.
  void ResetNativeMenu();

  // Creates the host window that receives notifications from the menu.
  void CreateHostWindow();

  // Callback from task to notify menu it was selected.
  void DelayedSelect();

  // Given a menu that's currently popped-up, find the currently highlighted
  // item. Returns true if a highlighted item was found.
  static bool GetHighlightedMenuItemInfo(HMENU menu,
                                         HighlightedMenuItemInfo* info);

  // Hook to receive keyboard events while the menu is open.
  static LRESULT CALLBACK MenuMessageHook(
      int n_code, WPARAM w_param, LPARAM l_param);

  // Our attached model and delegate.
  ui::MenuModel* model_;

  HMENU menu_;

  // True if the contents of menu items in this menu are drawn by the menu host
  // window, rather than Windows.
  bool owner_draw_;

  // An object that collects all of the data associated with an individual menu
  // item.
  struct ItemData;
  std::vector<ItemData*> items_;

  // The window that receives notifications from the menu.
  class MenuHostWindow;
  friend MenuHostWindow;
  scoped_ptr<MenuHostWindow> host_window_;

  // The HWND this menu is the system menu for, or NULL if the menu is not a
  // system menu.
  HWND system_menu_for_;

  // The index of the first item in the model in the menu.
  int first_item_index_;

  // The action that took place during the call to RunMenuAt.
  MenuAction menu_action_;

  // A list of listeners to call when the menu opens.
  ObserverList<MenuListener> listeners_;

  // Keep track of whether the listeners have already been called at least
  // once.
  bool listeners_called_;

  // See comment in MenuMessageHook for details on these.
  NativeMenuWin* menu_to_select_;
  int position_to_select_;
  base::WeakPtrFactory<NativeMenuWin> menu_to_select_factory_;

  // If we're a submenu, this is our parent.
  NativeMenuWin* parent_;

  // If non-null the destructor sets this to true. This is set to non-null while
  // the menu is showing. It is used to detect if the menu was deleted while
  // running.
  bool* destroyed_flag_;

  // Ugly: a static pointer to the instance of this class that currently
  // has a menu open, because our hook function that receives keyboard
  // events doesn't have a mechanism to get a user data pointer.
  static NativeMenuWin* open_native_menu_win_;

  DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
};

// A SimpleMenuModel subclass that allows the system menu for a window to be
// wrapped.
class VIEWS_EXPORT SystemMenuModel : public ui::SimpleMenuModel {
 public:
  explicit SystemMenuModel(Delegate* delegate);
  virtual ~SystemMenuModel();

  // Overridden from ui::MenuModel:
  virtual int GetFirstItemIndex(gfx::NativeMenu native_menu) const;

 protected:
  // Overridden from SimpleMenuModel:
  virtual int FlipIndex(int index) const { return GetItemCount() - index - 1; }

 private:
  DISALLOW_COPY_AND_ASSIGN(SystemMenuModel);
};

}  // namespace views

#endif  // UI_VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_