• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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