| // 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 <cmath> |
| |
| #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<NSObject> 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 |