Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / webkit / glue / webmenurunner_mac.mm
blobcb3c10c3dd50e93a5791198a053bf3eac61df324
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "webkit/glue/webmenurunner_mac.h"
7 #include "base/strings/sys_string_conversions.h"
9 @interface WebMenuRunner (PrivateAPI)
11 // Worker function used during initialization.
12 - (void)addItem:(const WebMenuItem&)item;
14 // A callback for the menu controller object to call when an item is selected
15 // from the menu. This is not called if the menu is dismissed without a
16 // selection.
17 - (void)menuItemSelected:(id)sender;
19 @end  // WebMenuRunner (PrivateAPI)
21 @implementation WebMenuRunner
23 - (id)initWithItems:(const std::vector<WebMenuItem>&)items
24            fontSize:(CGFloat)fontSize
25        rightAligned:(BOOL)rightAligned {
26   if ((self = [super init])) {
27     menu_.reset([[NSMenu alloc] initWithTitle:@""]);
28     [menu_ setAutoenablesItems:NO];
29     index_ = -1;
30     fontSize_ = fontSize;
31     rightAligned_ = rightAligned;
32     for (size_t i = 0; i < items.size(); ++i)
33       [self addItem:items[i]];
34   }
35   return self;
38 - (void)addItem:(const WebMenuItem&)item {
39   if (item.type == WebMenuItem::SEPARATOR) {
40     [menu_ addItem:[NSMenuItem separatorItem]];
41     return;
42   }
44   NSString* title = base::SysUTF16ToNSString(item.label);
45   NSMenuItem* menuItem = [menu_ addItemWithTitle:title
46                                           action:@selector(menuItemSelected:)
47                                    keyEquivalent:@""];
48   if (!item.toolTip.empty()) {
49     NSString* toolTip = base::SysUTF16ToNSString(item.toolTip);
50     [menuItem setToolTip:toolTip];
51   }
52   [menuItem setEnabled:(item.enabled && item.type != WebMenuItem::GROUP)];
53   [menuItem setTarget:self];
55   // Set various alignment/language attributes. Note that many (if not most) of
56   // these attributes are functional only on 10.6 and above.
57   scoped_nsobject<NSMutableDictionary> attrs(
58       [[NSMutableDictionary alloc] initWithCapacity:3]);
59   scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
60       [[NSMutableParagraphStyle alloc] init]);
61   [paragraphStyle setAlignment:rightAligned_ ? NSRightTextAlignment
62                                              : NSLeftTextAlignment];
63   NSWritingDirection writingDirection =
64       item.rtl ? NSWritingDirectionRightToLeft
65                : NSWritingDirectionLeftToRight;
66   [paragraphStyle setBaseWritingDirection:writingDirection];
67   [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
69   if (item.has_directional_override) {
70     scoped_nsobject<NSNumber> directionValue(
71         [[NSNumber alloc] initWithInteger:
72             writingDirection + NSTextWritingDirectionOverride]);
73     scoped_nsobject<NSArray> directionArray(
74         [[NSArray alloc] initWithObjects:directionValue.get(), nil]);
75     [attrs setObject:directionArray forKey:NSWritingDirectionAttributeName];
76   }
78   [attrs setObject:[NSFont menuFontOfSize:fontSize_]
79             forKey:NSFontAttributeName];
81   scoped_nsobject<NSAttributedString> attrTitle(
82       [[NSAttributedString alloc] initWithString:title
83                                       attributes:attrs]);
84   [menuItem setAttributedTitle:attrTitle];
86   [menuItem setTag:[menu_ numberOfItems] - 1];
89 // Reflects the result of the user's interaction with the popup menu. If NO, the
90 // menu was dismissed without the user choosing an item, which can happen if the
91 // user clicked outside the menu region or hit the escape key. If YES, the user
92 // selected an item from the menu.
93 - (BOOL)menuItemWasChosen {
94   return menuItemWasChosen_;
97 - (void)menuItemSelected:(id)sender {
98   menuItemWasChosen_ = YES;
101 - (void)runMenuInView:(NSView*)view
102            withBounds:(NSRect)bounds
103          initialIndex:(int)index {
104   // Set up the button cell, converting to NSView coordinates. The menu is
105   // positioned such that the currently selected menu item appears over the
106   // popup button, which is the expected Mac popup menu behavior.
107   scoped_nsobject<NSPopUpButtonCell>
108       cell([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]);
109   [cell setMenu:menu_];
110   // We use selectItemWithTag below so if the index is out-of-bounds nothing
111   // bad happens.
112   [cell selectItemWithTag:index];
114   if (rightAligned_ &&
115       [cell respondsToSelector:@selector(setUserInterfaceLayoutDirection:)]) {
116     [cell setUserInterfaceLayoutDirection:
117         NSUserInterfaceLayoutDirectionRightToLeft];
118   }
120   // When popping up a menu near the Dock, Cocoa restricts the menu
121   // size to not overlap the Dock, with a scroll arrow.  Below a
122   // certain point this doesn't work.  At that point the menu is
123   // popped up above the element, so that the current item can be
124   // selected without mouse-tracking selecting a different item
125   // immediately.
126   //
127   // Unfortunately, instead of popping up above the passed |bounds|,
128   // it pops up above the bounds of the view passed to inView:.  Use a
129   // dummy view to fake this out.
130   scoped_nsobject<NSView> dummyView([[NSView alloc] initWithFrame:bounds]);
131   [view addSubview:dummyView];
133   // Display the menu, and set a flag if a menu item was chosen.
134   [cell attachPopUpWithFrame:[dummyView bounds] inView:dummyView];
135   [cell performClickWithFrame:[dummyView bounds] inView:dummyView];
137   [dummyView removeFromSuperview];
139   if ([self menuItemWasChosen])
140     index_ = [cell indexOfSelectedItem];
143 - (int)indexOfSelectedItem {
144   return index_;
147 @end  // WebMenuRunner