• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/dock_icon.h"
6
7#include "base/memory/scoped_nsobject.h"
8
9// The fraction of the size of the dock icon that the badge is.
10static const float kBadgeFraction = 0.4f;
11
12// The indentation of the badge.
13static const float kBadgeIndent = 5.0f;
14
15// A view that draws our dock tile.
16@interface DockTileView : NSView {
17 @private
18  int downloads_;
19  BOOL indeterminate_;
20  float progress_;
21}
22
23// Indicates how many downloads are in progress.
24@property (nonatomic) int downloads;
25
26// Indicates whether the progress indicator should be in an indeterminate state
27// or not.
28@property (nonatomic) BOOL indeterminate;
29
30// Indicates the amount of progress made of the download. Ranges from [0..1].
31@property (nonatomic) float progress;
32
33@end
34
35@implementation DockTileView
36
37@synthesize downloads = downloads_;
38@synthesize indeterminate = indeterminate_;
39@synthesize progress = progress_;
40
41- (void)drawRect:(NSRect)dirtyRect {
42  // Not -[NSApplication applicationIconImage]; that fails to return a pasted
43  // custom icon.
44  NSString* appPath = [[NSBundle mainBundle] bundlePath];
45  NSImage* appIcon = [[NSWorkspace sharedWorkspace] iconForFile:appPath];
46  [appIcon drawInRect:[self bounds]
47             fromRect:NSZeroRect
48            operation:NSCompositeSourceOver
49             fraction:1.0];
50
51  if (downloads_ == 0)
52    return;
53
54  NSRect badgeRect = [self bounds];
55  badgeRect.size.height = (int)(kBadgeFraction * badgeRect.size.height);
56  int newWidth = kBadgeFraction * badgeRect.size.width;
57  badgeRect.origin.x = badgeRect.size.width - newWidth;
58  badgeRect.size.width = newWidth;
59
60  CGFloat badgeRadius = NSMidY(badgeRect);
61
62  badgeRect.origin.x -= kBadgeIndent;
63  badgeRect.origin.y += kBadgeIndent;
64
65  NSPoint badgeCenter = NSMakePoint(NSMidX(badgeRect),
66                                    NSMidY(badgeRect));
67
68  // Background
69  NSColor* backgroundColor = [NSColor colorWithCalibratedRed:0.85
70                                                       green:0.85
71                                                        blue:0.85
72                                                       alpha:1.0];
73  NSColor* backgroundHighlight =
74      [backgroundColor blendedColorWithFraction:0.85
75                                        ofColor:[NSColor whiteColor]];
76  scoped_nsobject<NSGradient> backgroundGradient(
77      [[NSGradient alloc] initWithStartingColor:backgroundHighlight
78                                    endingColor:backgroundColor]);
79  NSBezierPath* badgeEdge = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
80  [NSGraphicsContext saveGraphicsState];
81  [badgeEdge addClip];
82  [backgroundGradient drawFromCenter:badgeCenter
83                              radius:0.0
84                            toCenter:badgeCenter
85                              radius:badgeRadius
86                             options:0];
87  [NSGraphicsContext restoreGraphicsState];
88
89  // Slice
90  if (!indeterminate_) {
91    NSColor* sliceColor = [NSColor colorWithCalibratedRed:0.45
92                                                    green:0.8
93                                                     blue:0.25
94                                                    alpha:1.0];
95    NSColor* sliceHighlight =
96        [sliceColor blendedColorWithFraction:0.4
97                                     ofColor:[NSColor whiteColor]];
98    scoped_nsobject<NSGradient> sliceGradient(
99        [[NSGradient alloc] initWithStartingColor:sliceHighlight
100                                      endingColor:sliceColor]);
101    NSBezierPath* progressSlice;
102    if (progress_ >= 1.0) {
103      progressSlice = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
104    } else {
105      CGFloat endAngle = 90.0 - 360.0 * progress_;
106      if (endAngle < 0.0)
107        endAngle += 360.0;
108      progressSlice = [NSBezierPath bezierPath];
109      [progressSlice moveToPoint:badgeCenter];
110      [progressSlice appendBezierPathWithArcWithCenter:badgeCenter
111                                                radius:badgeRadius
112                                            startAngle:90.0
113                                              endAngle:endAngle
114                                             clockwise:YES];
115      [progressSlice closePath];
116    }
117    [NSGraphicsContext saveGraphicsState];
118    [progressSlice addClip];
119    [sliceGradient drawFromCenter:badgeCenter
120                           radius:0.0
121                         toCenter:badgeCenter
122                           radius:badgeRadius
123                          options:0];
124    [NSGraphicsContext restoreGraphicsState];
125  }
126
127  // Edge
128  [NSGraphicsContext saveGraphicsState];
129  [[NSColor whiteColor] set];
130  scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
131  [shadow.get() setShadowOffset:NSMakeSize(0, -2)];
132  [shadow setShadowBlurRadius:2];
133  [shadow set];
134  [badgeEdge setLineWidth:2];
135  [badgeEdge stroke];
136  [NSGraphicsContext restoreGraphicsState];
137
138  // Download count
139  scoped_nsobject<NSNumberFormatter> formatter(
140      [[NSNumberFormatter alloc] init]);
141  NSString* countString =
142      [formatter stringFromNumber:[NSNumber numberWithInt:downloads_]];
143
144  scoped_nsobject<NSShadow> countShadow([[NSShadow alloc] init]);
145  [countShadow setShadowBlurRadius:3.0];
146  [countShadow.get() setShadowColor:[NSColor whiteColor]];
147  [countShadow.get() setShadowOffset:NSMakeSize(0.0, 0.0)];
148  NSMutableDictionary* countAttrsDict =
149      [NSMutableDictionary dictionaryWithObjectsAndKeys:
150          [NSColor blackColor], NSForegroundColorAttributeName,
151          countShadow.get(), NSShadowAttributeName,
152          nil];
153  CGFloat countFontSize = badgeRadius;
154  NSSize countSize = NSZeroSize;
155  scoped_nsobject<NSAttributedString> countAttrString;
156  while (1) {
157    NSFont* countFont = [NSFont fontWithName:@"Helvetica-Bold"
158                                        size:countFontSize];
159    [countAttrsDict setObject:countFont forKey:NSFontAttributeName];
160    countAttrString.reset(
161        [[NSAttributedString alloc] initWithString:countString
162                                        attributes:countAttrsDict]);
163    countSize = [countAttrString size];
164    if (countSize.width > badgeRadius * 1.5) {
165      countFontSize -= 1.0;
166    } else {
167      break;
168    }
169  }
170
171  NSPoint countOrigin = badgeCenter;
172  countOrigin.x -= countSize.width / 2;
173  countOrigin.y -= countSize.height / 2.2;  // tweak; otherwise too low
174
175  [countAttrString.get() drawAtPoint:countOrigin];
176}
177
178@end
179
180
181@implementation DockIcon
182
183+ (DockIcon*)sharedDockIcon {
184  static DockIcon* icon;
185  if (!icon) {
186    NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
187
188    scoped_nsobject<DockTileView> dockTileView([[DockTileView alloc] init]);
189    [dockTile setContentView:dockTileView];
190
191    icon = [[DockIcon alloc] init];
192  }
193
194  return icon;
195}
196
197- (void)updateIcon {
198  NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
199
200  [dockTile display];
201}
202
203- (void)setDownloads:(int)downloads {
204  NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
205  DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
206
207  [dockTileView setDownloads:downloads];
208}
209
210- (void)setIndeterminate:(BOOL)indeterminate {
211  NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
212  DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
213
214  [dockTileView setIndeterminate:indeterminate];
215}
216
217- (void)setProgress:(float)progress {
218  NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
219  DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
220
221  [dockTileView setProgress:progress];
222}
223
224@end
225