// Copyright (c) 2013 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 "ui/message_center/cocoa/status_item_view.h" #include #include "base/format_macros.h" #include "base/mac/sdk_forward_declarations.h" #include "ui/base/resource/resource_bundle.h" #include "ui/resources/grit/ui_resources.h" // The width of the status bar item when it's just the icon. const CGFloat kStatusItemLength = 26; // The amount of space between the left and right edges and the content of the // status item. const CGFloat kMargin = 5; @interface MCStatusItemView (Private) // Whether or not the status item should be drawn highlighted. - (BOOL)shouldHighlight; - (int)getTrayResourceId; @end @implementation MCStatusItemView @synthesize highlight = highlight_; - (id)init { statusItem_.reset([[[NSStatusBar systemStatusBar] statusItemWithLength: NSVariableStatusItemLength] retain]); CGFloat thickness = [[statusItem_ statusBar] thickness]; NSRect frame = NSMakeRect(0, 0, kStatusItemLength, thickness); if ((self = [super initWithFrame:frame])) { [statusItem_ setView:self]; } return self; } - (void)removeItem { [[NSStatusBar systemStatusBar] removeStatusItem:statusItem_]; statusItem_.reset(); } - (size_t)unreadCount { return unreadCount_; } - (message_center::StatusItemClickedCallback)callback { return callback_.get(); } - (void)setCallback:(message_center::StatusItemClickedCallback)callback { callback_.reset(callback, base::scoped_policy::RETAIN); } - (void)setUnreadCount:(size_t)unreadCount withQuietMode:(BOOL)quietMode { unreadCount_ = unreadCount; quietMode_ = quietMode; NSRect frame = [self frame]; frame.size.width = kStatusItemLength; [self setFrame:frame]; [self setNeedsDisplay:YES]; } - (void)setHighlight:(BOOL)highlight { highlight_ = highlight; [self setNeedsDisplay:YES]; } - (void)mouseDown:(NSEvent*)event { inMouseEventSequence_ = YES; [self setNeedsDisplay:YES]; if (callback_) callback_.get()(); } - (void)mouseUp:(NSEvent*)event { inMouseEventSequence_ = NO; [self setNeedsDisplay:YES]; } - (void)rightMouseDown:(NSEvent*)event { [self mouseDown:event]; } - (void)rightMouseUp:(NSEvent*)event { [self mouseUp:event]; } - (void)otherMouseDown:(NSEvent*)event { [self mouseDown:event]; } - (void)otherMouseUp:(NSEvent*)event { [self mouseUp:event]; } - (void)drawRect:(NSRect)dirtyRect { NSRect frame = [self bounds]; // Draw the background color. BOOL highlight = [self shouldHighlight]; [statusItem_ drawStatusBarBackgroundInRect:frame withHighlight:highlight]; int resource_id = [self getTrayResourceId]; // Draw the icon. ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); NSImage* image = rb.GetNativeImageNamed(resource_id).ToNSImage(); NSSize size = [image size]; NSRect drawRect = NSMakeRect(kMargin, floorf((NSHeight(frame) - size.height) / 2), size.width, size.height); [image drawInRect:drawRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; } - (NSArray*)accessibilityActionNames { return @[ NSAccessibilityPressAction ]; } - (void)accessibilityPerformAction:(NSString*)action { if ([action isEqualToString:NSAccessibilityPressAction]) { if (callback_) callback_.get()(); return; } [super accessibilityPerformAction:action]; } // Private ///////////////////////////////////////////////////////////////////// - (BOOL)shouldHighlight { return highlight_ || inMouseEventSequence_; } - (int)getTrayResourceId { BOOL highlight = [self shouldHighlight]; BOOL hasUnreadItems = unreadCount_ > 0; BOOL dark = NO; Class nsAppearanceClass = NSClassFromString(@"NSAppearance"); if ([self respondsToSelector:@selector(effectiveAppearance)] && [nsAppearanceClass respondsToSelector:@selector(appearanceNamed:)]) { id darkAppearance = [nsAppearanceClass appearanceNamed:NSAppearanceNameVibrantDark]; dark = [[self effectiveAppearance] isEqual:darkAppearance]; } int kResourceIds[2][2][2][2] = { { { { IDR_TRAY_EMPTY, IDR_TRAY_EMPTY_PRESSED }, { IDR_TRAY_ATTENTION, IDR_TRAY_ATTENTION_PRESSED }, }, { { IDR_TRAY_DO_NOT_DISTURB_EMPTY, IDR_TRAY_DO_NOT_DISTURB_EMPTY_PRESSED }, { IDR_TRAY_DO_NOT_DISTURB_ATTENTION, IDR_TRAY_DO_NOT_DISTURB_ATTENTION_PRESSED }, }, }, { { // We chose not to support the empty version of the pressed // resource for the dark theme, so we use the same resource // for both "pressed" options. { IDR_DARK_TRAY_EMPTY, IDR_DARK_TRAY_PRESSED }, { IDR_DARK_TRAY_ATTENTION, IDR_DARK_TRAY_PRESSED }, }, { { IDR_DARK_TRAY_DO_NOT_DISTURB_EMPTY, IDR_DARK_TRAY_DO_NOT_DISTURB_PRESSED }, { IDR_DARK_TRAY_DO_NOT_DISTURB_ATTENTION, IDR_DARK_TRAY_DO_NOT_DISTURB_PRESSED }, }, } }; return kResourceIds[dark][quietMode_][hasUnreadItems][highlight]; } @end