15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef UI_VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define UI_VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/observer_list.h"
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string16.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_wrapper.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/views_export.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ui {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuModel;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A Windows implementation of MenuWrapper.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(beng): rename to MenuWin once the old class is dead.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VIEWS_EXPORT NativeMenuWin : public MenuWrapper {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is non-NULL, the NativeMenuWin wraps the system menu for that window.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The caller owns the model and the delegate.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NativeMenuWin(ui::MenuModel* model, HWND system_menu_for);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~NativeMenuWin();
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overridden from MenuWrapper:
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void RunMenuAt(const gfx::Point& point, int alignment) OVERRIDE;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void CancelMenu() OVERRIDE;
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void Rebuild(MenuInsertionDelegateWin* delegate) OVERRIDE;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void UpdateStates() OVERRIDE;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual HMENU GetNativeMenu() const OVERRIDE;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual MenuAction GetMenuAction() const OVERRIDE;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AddMenuListener(MenuListener* listener) OVERRIDE;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void RemoveMenuListener(MenuListener* listener) OVERRIDE;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetMinimumWidth(int width) OVERRIDE;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IMPORTANT: Note about indices.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            Functions in this class deal in two index spaces:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            1. menu_index - the index of an item within the actual Windows
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //               native menu.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            2. model_index - the index of the item within our model.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            These two are most often but not always the same value! The
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            notable exception is when this object is used to wrap the
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            Windows System Menu. In this instance, the model indices start
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            at 0, but the insertion index into the existing menu is not.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            It is important to take this into consideration when editing the
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //            code in the functions in this class.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct HighlightedMenuItemInfo;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if the item at the specified index is a separator.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsSeparatorItemAt(int menu_index) const;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add items. See note above about indices.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddMenuItemAt(int menu_index, int model_index);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddSeparatorItemAt(int menu_index, int model_index);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the state of the item at the specified index.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetMenuItemState(int menu_index,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool enabled,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool checked,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool is_default);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets the label of the item at the specified index.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetMenuItemLabel(int menu_index,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int model_index,
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const base::string16& label);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Updates the local data structure with the correctly formatted version of
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |label| at the specified model_index, and adds string data to |mii| if
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the menu is not owner-draw. That's a mouthful. This function exists because
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the peculiarities of the Windows menu API.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int model_index,
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   const base::string16& label);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // supplied alignment and the UI text direction.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UINT GetAlignmentFlags(int alignment) const;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Resets the native menu stored in |menu_| by destroying any old menu then
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // creating a new empty one.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResetNativeMenu();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates the host window that receives notifications from the menu.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CreateHostWindow();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callback from task to notify menu it was selected.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DelayedSelect();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Given a menu that's currently popped-up, find the currently highlighted
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // item. Returns true if a highlighted item was found.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool GetHighlightedMenuItemInfo(HMENU menu,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         HighlightedMenuItemInfo* info);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hook to receive keyboard events while the menu is open.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static LRESULT CALLBACK MenuMessageHook(
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int n_code, WPARAM w_param, LPARAM l_param);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our attached model and delegate.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::MenuModel* model_;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMENU menu_;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // True if the contents of menu items in this menu are drawn by the menu host
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // window, rather than Windows.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool owner_draw_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An object that collects all of the data associated with an individual menu
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // item.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct ItemData;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ItemData*> items_;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The window that receives notifications from the menu.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class MenuHostWindow;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend MenuHostWindow;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MenuHostWindow> host_window_;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The HWND this menu is the system menu for, or NULL if the menu is not a
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // system menu.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND system_menu_for_;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The index of the first item in the model in the menu.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int first_item_index_;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The action that took place during the call to RunMenuAt.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuAction menu_action_;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A list of listeners to call when the menu opens.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ObserverList<MenuListener> listeners_;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keep track of whether the listeners have already been called at least
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // once.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool listeners_called_;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See comment in MenuMessageHook for details on these.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NativeMenuWin* menu_to_select_;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int position_to_select_;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WeakPtrFactory<NativeMenuWin> menu_to_select_factory_;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're a submenu, this is our parent.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NativeMenuWin* parent_;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If non-null the destructor sets this to true. This is set to non-null while
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the menu is showing. It is used to detect if the menu was deleted while
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // running.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool* destroyed_flag_;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ugly: a static pointer to the instance of this class that currently
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has a menu open, because our hook function that receives keyboard
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // events doesn't have a mechanism to get a user data pointer.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static NativeMenuWin* open_native_menu_win_;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // UI_VIEWS_CONTROLS_MENU_NATIVE_MENU_WIN_H_
170