1// Copyright (c) 2013 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. 4 5#import "ui/message_center/cocoa/status_item_view.h" 6 7#include <cmath> 8 9#include "base/format_macros.h" 10#include "base/mac/sdk_forward_declarations.h" 11#include "ui/base/resource/resource_bundle.h" 12#include "ui/resources/grit/ui_resources.h" 13 14// The width of the status bar item when it's just the icon. 15const CGFloat kStatusItemLength = 26; 16 17// The amount of space between the left and right edges and the content of the 18// status item. 19const CGFloat kMargin = 5; 20 21 22@interface MCStatusItemView (Private) 23// Whether or not the status item should be drawn highlighted. 24- (BOOL)shouldHighlight; 25 26- (int)getTrayResourceId; 27@end 28 29@implementation MCStatusItemView 30 31@synthesize highlight = highlight_; 32 33- (id)init { 34 statusItem_.reset([[[NSStatusBar systemStatusBar] statusItemWithLength: 35 NSVariableStatusItemLength] retain]); 36 CGFloat thickness = [[statusItem_ statusBar] thickness]; 37 38 NSRect frame = NSMakeRect(0, 0, kStatusItemLength, thickness); 39 if ((self = [super initWithFrame:frame])) { 40 [statusItem_ setView:self]; 41 } 42 return self; 43} 44 45- (void)removeItem { 46 [[NSStatusBar systemStatusBar] removeStatusItem:statusItem_]; 47 statusItem_.reset(); 48} 49 50- (size_t)unreadCount { 51 return unreadCount_; 52} 53 54- (message_center::StatusItemClickedCallback)callback { 55 return callback_.get(); 56} 57 58- (void)setCallback:(message_center::StatusItemClickedCallback)callback { 59 callback_.reset(callback, base::scoped_policy::RETAIN); 60} 61 62- (void)setUnreadCount:(size_t)unreadCount withQuietMode:(BOOL)quietMode { 63 unreadCount_ = unreadCount; 64 quietMode_ = quietMode; 65 66 NSRect frame = [self frame]; 67 frame.size.width = kStatusItemLength; 68 [self setFrame:frame]; 69 70 [self setNeedsDisplay:YES]; 71} 72 73- (void)setHighlight:(BOOL)highlight { 74 highlight_ = highlight; 75 [self setNeedsDisplay:YES]; 76} 77 78- (void)mouseDown:(NSEvent*)event { 79 inMouseEventSequence_ = YES; 80 [self setNeedsDisplay:YES]; 81 82 if (callback_) 83 callback_.get()(); 84} 85 86- (void)mouseUp:(NSEvent*)event { 87 inMouseEventSequence_ = NO; 88 [self setNeedsDisplay:YES]; 89} 90 91- (void)rightMouseDown:(NSEvent*)event { 92 [self mouseDown:event]; 93} 94 95- (void)rightMouseUp:(NSEvent*)event { 96 [self mouseUp:event]; 97} 98 99- (void)otherMouseDown:(NSEvent*)event { 100 [self mouseDown:event]; 101} 102 103- (void)otherMouseUp:(NSEvent*)event { 104 [self mouseUp:event]; 105} 106 107- (void)drawRect:(NSRect)dirtyRect { 108 NSRect frame = [self bounds]; 109 110 // Draw the background color. 111 BOOL highlight = [self shouldHighlight]; 112 [statusItem_ drawStatusBarBackgroundInRect:frame 113 withHighlight:highlight]; 114 115 int resource_id = [self getTrayResourceId]; 116 // Draw the icon. 117 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 118 NSImage* image = rb.GetNativeImageNamed(resource_id).ToNSImage(); 119 NSSize size = [image size]; 120 NSRect drawRect = NSMakeRect(kMargin, 121 floorf((NSHeight(frame) - size.height) / 2), 122 size.width, 123 size.height); 124 [image drawInRect:drawRect 125 fromRect:NSZeroRect 126 operation:NSCompositeSourceOver 127 fraction:1.0]; 128} 129 130- (NSArray*)accessibilityActionNames { 131 return @[ NSAccessibilityPressAction ]; 132} 133 134- (void)accessibilityPerformAction:(NSString*)action { 135 if ([action isEqualToString:NSAccessibilityPressAction]) { 136 if (callback_) 137 callback_.get()(); 138 return; 139 } 140 [super accessibilityPerformAction:action]; 141} 142 143// Private ///////////////////////////////////////////////////////////////////// 144 145- (BOOL)shouldHighlight { 146 return highlight_ || inMouseEventSequence_; 147} 148 149- (int)getTrayResourceId { 150 BOOL highlight = [self shouldHighlight]; 151 BOOL hasUnreadItems = unreadCount_ > 0; 152 BOOL dark = NO; 153 154 Class nsAppearanceClass = NSClassFromString(@"NSAppearance"); 155 if ([self respondsToSelector:@selector(effectiveAppearance)] && 156 [nsAppearanceClass respondsToSelector:@selector(appearanceNamed:)]) { 157 id<NSObject> darkAppearance = 158 [nsAppearanceClass appearanceNamed:NSAppearanceNameVibrantDark]; 159 dark = [[self effectiveAppearance] isEqual:darkAppearance]; 160 } 161 162 int kResourceIds[2][2][2][2] = { 163 { 164 { 165 { IDR_TRAY_EMPTY, IDR_TRAY_EMPTY_PRESSED }, 166 { IDR_TRAY_ATTENTION, IDR_TRAY_ATTENTION_PRESSED }, 167 }, 168 { 169 { IDR_TRAY_DO_NOT_DISTURB_EMPTY, 170 IDR_TRAY_DO_NOT_DISTURB_EMPTY_PRESSED }, 171 { IDR_TRAY_DO_NOT_DISTURB_ATTENTION, 172 IDR_TRAY_DO_NOT_DISTURB_ATTENTION_PRESSED }, 173 }, 174 }, 175 { 176 { 177 // We chose not to support the empty version of the pressed 178 // resource for the dark theme, so we use the same resource 179 // for both "pressed" options. 180 { IDR_DARK_TRAY_EMPTY, IDR_DARK_TRAY_PRESSED }, 181 { IDR_DARK_TRAY_ATTENTION, IDR_DARK_TRAY_PRESSED }, 182 }, 183 { 184 { IDR_DARK_TRAY_DO_NOT_DISTURB_EMPTY, 185 IDR_DARK_TRAY_DO_NOT_DISTURB_PRESSED }, 186 { IDR_DARK_TRAY_DO_NOT_DISTURB_ATTENTION, 187 IDR_DARK_TRAY_DO_NOT_DISTURB_PRESSED }, 188 }, 189 } 190 }; 191 return kResourceIds[dark][quietMode_][hasUnreadItems][highlight]; 192} 193 194@end 195