Commit d00da359 authored by Avi Drissman's avatar Avi Drissman Committed by Chromium LUCI CQ

Implement IPH for Mac menus

Bug: 1136676
Change-Id: I4ca7106dc8ee64854ab70fc4724b692d68b91aba
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2570116
Commit-Queue: Avi Drissman <avi@chromium.org>
Auto-Submit: Avi Drissman <avi@chromium.org>
Reviewed-by: default avatarCollin Baker <collinbaker@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833534}
parent c31f8f27
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
namespace { namespace {
constexpr CGFloat kNativeCheckmarkWidth = 18;
constexpr CGFloat kNativeMenuItemHeight = 18;
constexpr CGFloat kIPHDotSize = 6;
NSImage* NewTagImage() { NSImage* NewTagImage() {
// 1. Make the attributed string. // 1. Make the attributed string.
...@@ -92,47 +96,116 @@ NSImage* NewTagImage() { ...@@ -92,47 +96,116 @@ NSImage* NewTagImage() {
}]; }];
} }
NSImage* IPHDotImage() {
// Embed horizontal centering space as NSMenuItem will otherwise left-align
// it.
return [NSImage
imageWithSize:NSMakeSize(2 * kIPHDotSize, kIPHDotSize)
flipped:NO
drawingHandler:^(NSRect dest_rect) {
NSBezierPath* dot_path = [NSBezierPath
bezierPathWithOvalInRect:NSMakeRect(kIPHDotSize / 2, 0, kIPHDotSize,
kIPHDotSize)];
NSColor* dot_color = skia::SkColorToSRGBNSColor(
ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
ui::NativeTheme::kColorId_ProminentButtonColor));
[dot_color set];
[dot_path fill];
return YES;
}];
}
NSMutableAttributedString* MutableAttributedStringForMenuItemTitleString(
NSString* string) {
// Starting in 10.13, if an attributed string is set as a menu item title,
// and NSFontAttributeName is not specified for it, it is automatically
// rendered in a font matching other menu items. Prior to then, a menu item
// with no specified font is rendered in Helvetica. In addition, while the
// documentation says that -[NSFont menuFontOfSize:0] gives the standard
// menu font, that doesn't actually match up. Therefore, specify a font that
// visually matches.
NSDictionary* attrs = nil;
if (base::mac::IsAtMostOS10_12())
attrs = @{NSFontAttributeName : [NSFont menuFontOfSize:14]};
return [[[NSMutableAttributedString alloc] initWithString:string
attributes:attrs] autorelease];
}
} // namespace } // namespace
@interface MenuControllerDelegate : NSObject <MenuControllerCocoaDelegate> // --- Private API begin ---
@interface NSCarbonMenuImpl : NSObject
- (void)highlightItemAtIndex:(NSInteger)index;
@end
@interface NSMenu ()
- (NSCarbonMenuImpl*)_menuImpl;
@end
// --- Private API end ---
@interface MenuControllerDelegate : NSObject <MenuControllerCocoaDelegate> {
id<NSObject> _menuOpenObserver;
}
@end @end
@implementation MenuControllerDelegate @implementation MenuControllerDelegate
- (void)dealloc {
if (_menuOpenObserver)
[[NSNotificationCenter defaultCenter] removeObserver:_menuOpenObserver];
[super dealloc];
}
- (void)controllerWillAddItem:(NSMenuItem*)menuItem - (void)controllerWillAddItem:(NSMenuItem*)menuItem
fromModel:(ui::MenuModel*)model fromModel:(ui::MenuModel*)model
atIndex:(NSInteger)index { atIndex:(NSInteger)index {
static const bool feature_enabled = static const bool newBadgeFeatureEnabled =
base::FeatureList::IsEnabled(views::features::kEnableNewBadgeOnMenuItems); base::FeatureList::IsEnabled(views::features::kEnableNewBadgeOnMenuItems);
if (!feature_enabled || !model->IsNewFeatureAt(index)) if (newBadgeFeatureEnabled && model->IsNewFeatureAt(index)) {
return; NSTextAttachment* attachment =
[[[NSTextAttachment alloc] initWithData:nil ofType:nil] autorelease];
NSTextAttachment* attachment = attachment.image = NewTagImage();
[[[NSTextAttachment alloc] initWithData:nil ofType:nil] autorelease]; NSSize newTagSize = attachment.image.size;
attachment.image = NewTagImage(); attachment.bounds =
NSSize newTagSize = attachment.image.size; NSMakeRect(0, views::NewBadge::kNewBadgeBaselineOffsetMac,
attachment.bounds = NSMakeRect(0, views::NewBadge::kNewBadgeBaselineOffsetMac, newTagSize.width, newTagSize.height);
newTagSize.width, newTagSize.height);
NSMutableAttributedString* attrTitle =
// Starting in 10.13, if an attributed string is set as a menu item title, and MutableAttributedStringForMenuItemTitleString(menuItem.title);
// NSFontAttributeName is not specified for it, it is automatically rendered [attrTitle
// in a font matching other menu items. Prior to then, a menu item with no appendAttributedString:[NSAttributedString
// specified font is rendered in Helvetica. In addition, while the attributedStringWithAttachment:attachment]];
// documentation says that -[NSFont menuFontOfSize:0] gives the standard menu
// font, that doesn't actually match up. Therefore, specify a font that menuItem.attributedTitle = attrTitle;
// visually matches. }
NSDictionary* attrs = nil;
if (base::mac::IsAtMostOS10_12())
attrs = @{NSFontAttributeName : [NSFont menuFontOfSize:14]};
base::scoped_nsobject<NSMutableAttributedString> attrTitle(
[[NSMutableAttributedString alloc] initWithString:menuItem.title
attributes:attrs]);
[attrTitle
appendAttributedString:[NSAttributedString
attributedStringWithAttachment:attachment]];
menuItem.attributedTitle = attrTitle; if (model->IsAlertedAt(index)) {
NSImage* iphDotImage = IPHDotImage();
menuItem.onStateImage = iphDotImage;
menuItem.offStateImage = iphDotImage;
menuItem.mixedStateImage = iphDotImage;
DCHECK(!_menuOpenObserver);
_menuOpenObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSMenuDidBeginTrackingNotification
object:menuItem.menu
queue:nil
usingBlock:^(NSNotification* note) {
NSMenu* menu = note.object;
if ([menu respondsToSelector:@selector(_menuImpl)]) {
NSCarbonMenuImpl* menuImpl = [menu _menuImpl];
if ([menuImpl respondsToSelector:@selector
(highlightItemAtIndex:)]) {
[menuImpl highlightItemAtIndex:index];
}
}
}];
}
} }
@end @end
...@@ -141,9 +214,6 @@ namespace views { ...@@ -141,9 +214,6 @@ namespace views {
namespace internal { namespace internal {
namespace { namespace {
constexpr CGFloat kNativeCheckmarkWidth = 18;
constexpr CGFloat kNativeMenuItemHeight = 18;
// Returns the first item in |menu_controller|'s menu that will be checked. // Returns the first item in |menu_controller|'s menu that will be checked.
NSMenuItem* FirstCheckedItem(MenuControllerCocoa* menu_controller) { NSMenuItem* FirstCheckedItem(MenuControllerCocoa* menu_controller) {
for (NSMenuItem* item in [[menu_controller menu] itemArray]) { for (NSMenuItem* item in [[menu_controller menu] itemArray]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment