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

Side by Side Diff: webkit/glue/webmenurunner_mac.mm

Issue 6410125: Extend Mac popup to handle more directionality.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 10 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 | Annotate | Revision Log
« no previous file with comments | « webkit/glue/webmenurunner_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "webkit/glue/webmenurunner_mac.h" 5 #include "webkit/glue/webmenurunner_mac.h"
6 6
7 #include "base/sys_string_conversions.h" 7 #include "base/sys_string_conversions.h"
8 8
9 namespace {
10
11 const CGFloat kPopupXOffset = -10.0f;
12 BOOL gNewNSMenuAPI;
13
14 } // namespace
15
16 #if !defined(MAC_OS_X_VERSION_10_6) || \ 9 #if !defined(MAC_OS_X_VERSION_10_6) || \
17 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 10 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
18 @interface NSMenu (SnowLeopardSDKDeclarations) 11 enum {
19 - (BOOL)popUpMenuPositioningItem:(NSMenuItem *)item 12 NSUserInterfaceLayoutDirectionLeftToRight = 0,
20 atLocation:(NSPoint)location 13 NSUserInterfaceLayoutDirectionRightToLeft = 1
21 inView:(NSView *)view; 14 };
22 - (void)setFont:(NSFont *)font; 15 typedef NSInteger NSUserInterfaceLayoutDirection;
16
17 @interface NSCell (SnowLeopardSDKDeclarations)
18 - (void)setUserInterfaceLayoutDirection:
19 (NSUserInterfaceLayoutDirection)layoutDirection;
23 @end 20 @end
21
22 enum {
23 NSTextWritingDirectionEmbedding = (0 << 1),
24 NSTextWritingDirectionOverride = (1 << 1)
25 };
26
27 static NSString* NSWritingDirectionAttributeName = @"NSWritingDirection";
24 #endif 28 #endif
25 29
26 @interface WebMenuRunner (PrivateAPI) 30 @interface WebMenuRunner (PrivateAPI)
27 31
28 // Worker function used during initialization. 32 // Worker function used during initialization.
29 - (void)addItem:(const WebMenuItem&)item 33 - (void)addItem:(const WebMenuItem&)item;
30 withAttributes:(NSDictionary*)attrs;
31 34
32 // A callback for the menu controller object to call when an item is selected 35 // A callback for the menu controller object to call when an item is selected
33 // from the menu. This is not called if the menu is dismissed without a 36 // from the menu. This is not called if the menu is dismissed without a
34 // selection. 37 // selection.
35 - (void)menuItemSelected:(id)sender; 38 - (void)menuItemSelected:(id)sender;
36 39
37 @end // WebMenuRunner (PrivateAPI) 40 @end // WebMenuRunner (PrivateAPI)
38 41
39 @implementation WebMenuRunner 42 @implementation WebMenuRunner
40 43
41 - (id)initWithItems:(const std::vector<WebMenuItem>&)items 44 - (id)initWithItems:(const std::vector<WebMenuItem>&)items
42 fontSize:(CGFloat)fontSize 45 fontSize:(CGFloat)fontSize
43 rightAligned:(BOOL)rightAligned { 46 rightAligned:(BOOL)rightAligned {
44 static BOOL newNSMenuAPIInitialized = NO;
45 if (!newNSMenuAPIInitialized) {
46 newNSMenuAPIInitialized = YES;
47 gNewNSMenuAPI = [NSMenu instancesRespondToSelector:
48 @selector(popUpMenuPositioningItem:atLocation:inView:)] &&
49 [NSMenu instancesRespondToSelector:@selector(setFont:)];
50 }
51
52 if ((self = [super init])) { 47 if ((self = [super init])) {
53 menu_.reset([[NSMenu alloc] initWithTitle:@""]); 48 menu_.reset([[NSMenu alloc] initWithTitle:@""]);
54 if (gNewNSMenuAPI)
55 [menu_ setFont:[NSFont menuFontOfSize:fontSize]];
56 [menu_ setAutoenablesItems:NO]; 49 [menu_ setAutoenablesItems:NO];
57 index_ = -1; 50 index_ = -1;
58 fontSize_ = fontSize; 51 fontSize_ = fontSize;
59 scoped_nsobject<NSDictionary> attrs; 52 rightAligned_ = rightAligned;
60 if (rightAligned) {
61 // NB: Right-aligning menu items in this manner is known to not work in
62 // Mac OS X 10.5.
63 scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
64 [[NSMutableParagraphStyle alloc] init]);
65 [paragraphStyle setAlignment:NSRightTextAlignment];
66 attrs.reset([[NSDictionary alloc] initWithObjectsAndKeys:
67 paragraphStyle, NSParagraphStyleAttributeName, nil]);
68 }
69 for (size_t i = 0; i < items.size(); ++i) 53 for (size_t i = 0; i < items.size(); ++i)
70 [self addItem:items[i] withAttributes:attrs]; 54 [self addItem:items[i]];
71 } 55 }
72 return self; 56 return self;
73 } 57 }
74 58
75 - (void)addItem:(const WebMenuItem&)item 59 - (void)addItem:(const WebMenuItem&)item {
76 withAttributes:(NSDictionary*)attrs {
77 if (item.type == WebMenuItem::SEPARATOR) { 60 if (item.type == WebMenuItem::SEPARATOR) {
78 [menu_ addItem:[NSMenuItem separatorItem]]; 61 [menu_ addItem:[NSMenuItem separatorItem]];
79 return; 62 return;
80 } 63 }
81 64
82 NSString* title = base::SysUTF16ToNSString(item.label); 65 NSString* title = base::SysUTF16ToNSString(item.label);
83 NSMenuItem* menuItem = [menu_ addItemWithTitle:title 66 NSMenuItem* menuItem = [menu_ addItemWithTitle:title
84 action:@selector(menuItemSelected:) 67 action:@selector(menuItemSelected:)
85 keyEquivalent:@""]; 68 keyEquivalent:@""];
86 [menuItem setEnabled:(item.enabled && item.type != WebMenuItem::GROUP)]; 69 [menuItem setEnabled:(item.enabled && item.type != WebMenuItem::GROUP)];
87 [menuItem setTarget:self]; 70 [menuItem setTarget:self];
88 if (attrs) { 71
89 scoped_nsobject<NSAttributedString> attrTitle( 72 // Set various alignment/language attributes. Note that many (if not most) of
90 [[NSAttributedString alloc] initWithString:title 73 // these attributes are functional only on 10.6 and above.
91 attributes:attrs]); 74 scoped_nsobject<NSMutableDictionary> attrs(
92 [menuItem setAttributedTitle:attrTitle]; 75 [[NSMutableDictionary alloc] initWithCapacity:3]);
76 scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
77 [[NSMutableParagraphStyle alloc] init]);
78 [paragraphStyle setAlignment:rightAligned_ ? NSRightTextAlignment
79 : NSLeftTextAlignment];
80 NSWritingDirection writingDirection =
81 item.rtl ? NSWritingDirectionRightToLeft
82 : NSWritingDirectionLeftToRight;
83 [paragraphStyle setBaseWritingDirection:writingDirection];
84 [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
85
86 if (item.directional_override) {
87 scoped_nsobject<NSNumber> directionValue(
88 [[NSNumber alloc] initWithInteger:
89 writingDirection + NSTextWritingDirectionOverride]);
90 scoped_nsobject<NSArray> directionArray(
91 [[NSArray alloc] initWithObjects:directionValue.get(), nil]);
92 [attrs setObject:directionArray forKey:NSWritingDirectionAttributeName];
93 } 93 }
94
95 [attrs setObject:[NSFont menuFontOfSize:fontSize_]
96 forKey:NSFontAttributeName];
97
98 scoped_nsobject<NSAttributedString> attrTitle(
99 [[NSAttributedString alloc] initWithString:title
100 attributes:attrs]);
101 [menuItem setAttributedTitle:attrTitle];
102
94 [menuItem setTag:[menu_ numberOfItems] - 1]; 103 [menuItem setTag:[menu_ numberOfItems] - 1];
95 } 104 }
96 105
97 // Reflects the result of the user's interaction with the popup menu. If NO, the 106 // Reflects the result of the user's interaction with the popup menu. If NO, the
98 // menu was dismissed without the user choosing an item, which can happen if the 107 // menu was dismissed without the user choosing an item, which can happen if the
99 // user clicked outside the menu region or hit the escape key. If YES, the user 108 // user clicked outside the menu region or hit the escape key. If YES, the user
100 // selected an item from the menu. 109 // selected an item from the menu.
101 - (BOOL)menuItemWasChosen { 110 - (BOOL)menuItemWasChosen {
102 return menuItemWasChosen_; 111 return menuItemWasChosen_;
103 } 112 }
104 113
105 - (void)menuItemSelected:(id)sender { 114 - (void)menuItemSelected:(id)sender {
106 menuItemWasChosen_ = YES; 115 menuItemWasChosen_ = YES;
107 if (gNewNSMenuAPI)
108 index_ = [sender tag];
109 } 116 }
110 117
111 - (void)runMenuInView:(NSView*)view 118 - (void)runMenuInView:(NSView*)view
112 withBounds:(NSRect)bounds 119 withBounds:(NSRect)bounds
113 initialIndex:(int)index { 120 initialIndex:(int)index {
114 if (gNewNSMenuAPI) { 121 // Set up the button cell, converting to NSView coordinates. The menu is
115 // index might be out of bounds, in which case we set no selection. 122 // positioned such that the currently selected menu item appears over the
116 NSMenuItem* selectedItem = [menu_ itemWithTag:index]; 123 // popup button, which is the expected Mac popup menu behavior.
117 if (selectedItem) { 124 NSPopUpButtonCell* button = [[NSPopUpButtonCell alloc] initTextCell:@""
118 [selectedItem setState:NSOnState]; 125 pullsDown:NO];
119 } else { 126 [button autorelease];
120 selectedItem = [menu_ itemWithTag:0]; 127 [button setMenu:menu_];
121 } 128 // We use selectItemWithTag below so if the index is out-of-bounds nothing
122 NSPoint anchor = NSMakePoint(NSMinX(bounds) + kPopupXOffset, 129 // bad happens.
123 NSMaxY(bounds)); 130 [button selectItemWithTag:index];
124 [menu_ popUpMenuPositioningItem:selectedItem
125 atLocation:anchor
126 inView:view];
127 } else {
128 // Set up the button cell, converting to NSView coordinates. The menu is
129 // positioned such that the currently selected menu item appears over the
130 // popup button, which is the expected Mac popup menu behavior.
131 NSPopUpButtonCell* button = [[NSPopUpButtonCell alloc] initTextCell:@""
132 pullsDown:NO];
133 [button autorelease];
134 [button setMenu:menu_];
135 // We use selectItemWithTag below so if the index is out-of-bounds nothing
136 // bad happens.
137 [button selectItemWithTag:index];
138 [button setFont:[NSFont menuFontOfSize:fontSize_]];
139 131
140 // Create a dummy view to associate the popup with, since the OS will use 132 if (rightAligned_ &&
141 // that view for positioning the menu. 133 [button respondsToSelector:@selector(setUserInterfaceLayoutDirection:)]) {
142 NSView* dummyView = [[[NSView alloc] initWithFrame:bounds] autorelease]; 134 [button setUserInterfaceLayoutDirection:
143 [view addSubview:dummyView]; 135 NSUserInterfaceLayoutDirectionRightToLeft];
144 NSRect dummyBounds = [dummyView convertRect:bounds fromView:view]; 136 }
145 137
146 // Display the menu, and set a flag if a menu item was chosen. 138 // Create a dummy view to associate the popup with, since the OS will use
147 [button performClickWithFrame:dummyBounds inView:dummyView]; 139 // that view for positioning the menu.
140 NSView* dummyView = [[[NSView alloc] initWithFrame:bounds] autorelease];
141 [view addSubview:dummyView];
142 NSRect dummyBounds = [dummyView convertRect:bounds fromView:view];
148 143
149 if ([self menuItemWasChosen]) 144 // Display the menu, and set a flag if a menu item was chosen.
150 index_ = [button indexOfSelectedItem]; 145 [button performClickWithFrame:dummyBounds inView:dummyView];
151 146
152 [dummyView removeFromSuperview]; 147 if ([self menuItemWasChosen])
153 } 148 index_ = [button indexOfSelectedItem];
149
150 [dummyView removeFromSuperview];
154 } 151 }
155 152
156 - (int)indexOfSelectedItem { 153 - (int)indexOfSelectedItem {
157 return index_; 154 return index_;
158 } 155 }
159 156
160 @end // WebMenuRunner 157 @end // WebMenuRunner
161 158
162 namespace webkit_glue { 159 namespace webkit_glue {
163 160
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 characters:@"" 206 characters:@""
210 charactersIgnoringModifiers:escape_str 207 charactersIgnoringModifiers:escape_str
211 isARepeat:NO 208 isARepeat:NO
212 keyCode:0x1B]; 209 keyCode:0x1B];
213 } 210 }
214 211
215 return event; 212 return event;
216 } 213 }
217 214
218 } // namespace webkit_glue 215 } // namespace webkit_glue
OLDNEW
« no previous file with comments | « webkit/glue/webmenurunner_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698