blob: 65227983c8a7d4f97c135a6f49b21b2eb6ac91e8 [file] [log] [blame]
// Copyright 2018 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.
#import <Cocoa/Cocoa.h>
#include <vector>
#include "base/mac/scoped_nsobject.h"
#include "base/optional.h"
namespace chrome {
// Creates the main menu bar using the name specified in |product_name|, and
// registers it as such on |nsapp|. The NSApplicationDelegate |app_delegate|
// is the target for specific, special menu items.
// Normally the main menu is built in a MainMenu.nib file, but NIB files files
// are hard to edit (especially cross-platform) and bring in a compile
// dependency on ibtool. Building the menu in code has a lower maintenance
// burden.
void BuildMainMenu(NSApplication* nsapp,
id<NSApplicationDelegate> app_delegate,
const base::string16& product_name,
bool is_pwa);
// Internal ////////////////////////////////////////////////////////////////////
namespace internal {
// Helper class that builds NSMenuItems from data. Instances of this class
// should not outlive an autorelease pool scope as it does not retain any
// Objective-C members.
// This builder follows a fluent-interface pattern where the setters are
// not prefixed with the typical "set_" and they return a reference to this
// for easier method chaining.
// This class is only exposed for testing.
class MenuItemBuilder {
explicit MenuItemBuilder(int string_id = 0);
MenuItemBuilder(const MenuItemBuilder&);
MenuItemBuilder& operator=(const MenuItemBuilder&);
// Converts the item to a separator. Only tag() is also applicable.
MenuItemBuilder& is_separator() {
DCHECK_EQ(string_id_, 0);
is_separator_ = true;
return *this;
MenuItemBuilder& target(id target) {
target_ = target;
return *this;
MenuItemBuilder& action(SEL action) {
action_ = action;
return *this;
MenuItemBuilder& tag(int tag) {
tag_ = tag;
return *this;
// Wires up the menu item to the CommandDispatcher based on an
// IDC_ command code.
MenuItemBuilder& command_id(int command_id) {
return tag(command_id).action(@selector(commandDispatch:));
// Specifies the string to substitute for the $1 found in the string for
// |string_id_|.
MenuItemBuilder& string_format_1(const base::string16& arg) {
string_arg1_ = arg;
return *this;
MenuItemBuilder& submenu(std::vector<MenuItemBuilder> items) {
submenu_ = std::move(items);
return *this;
// Registers a custom key equivalent. Normally the key equivalent is looked
// up via AcceleratorsCocoa based on the command_id(). If one is not present,
// the one specified here is used instead.
MenuItemBuilder& key_equivalent(NSString* key_equivalent,
NSEventModifierFlags flags) {
DCHECK((flags & NSEventModifierFlagShift) == 0)
<< "The shift modifier flag should be directly applied to the key "
key_equivalent_ = key_equivalent;
key_equivalent_flags_ = flags;
return *this;
// Marks the item as an alternate keyboard equivalent menu item.
MenuItemBuilder& is_alternate() {
is_alternate_ = true;
return *this;
// Excludes this item from the menu if |condition| is true.
MenuItemBuilder& remove_if(bool condition) {
is_removed_ |= condition;
return *this;
// Builds a NSMenuItem instance from the properties set on the Builder.
base::scoped_nsobject<NSMenuItem> Build() const;
bool is_separator_ = false;
int string_id_ = 0;
base::string16 string_arg1_;
int tag_ = 0;
id target_ = nil;
SEL action_ = nil;
NSString* key_equivalent_ = @"";
NSEventModifierFlags key_equivalent_flags_ = 0;
bool is_alternate_ = false;
bool is_removed_ = false;
base::Optional<std::vector<MenuItemBuilder>> submenu_;
// Copy and assign allowed.
} // namespace internal
} // namespace chrome