summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/download_item_cell.h56
-rw-r--r--chrome/browser/cocoa/download_item_cell.mm437
-rw-r--r--chrome/browser/cocoa/download_item_controller.h9
-rw-r--r--chrome/browser/cocoa/download_item_controller.mm49
-rw-r--r--chrome/browser/cocoa/download_shelf_controller.mm42
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.h12
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.mm136
7 files changed, 642 insertions, 99 deletions
diff --git a/chrome/browser/cocoa/download_item_cell.h b/chrome/browser/cocoa/download_item_cell.h
new file mode 100644
index 0000000..e2c5162
--- /dev/null
+++ b/chrome/browser/cocoa/download_item_cell.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_ITEM_CELL_H_
+#define CHROME_BROWSER_COCOA_DOWNLOAD_ITEM_CELL_H_
+
+#import "chrome/browser/cocoa/gradient_button_cell.h"
+
+#include "base/file_path.h"
+
+class BaseDownloadItemModel;
+
+// A button cell that implements the weird button/popup button hybrid that is
+// used by the download items.
+
+// The button represented by this cell consists of a button part on the left
+// and a dropdown-menu part on the right. This enum describes which part the
+// mouse cursor is over currently.
+enum DownloadItemMousePosition {
+ kDownloadItemMouseOutside,
+ kDownloadItemMouseOverButtonPart,
+ kDownloadItemMouseOverDropdownPart
+};
+
+@interface DownloadItemCell : GradientButtonCell {
+ @private
+ // Track which part of the button the mouse is over
+ DownloadItemMousePosition mousePosition_;
+ int mouseInsideCount_;
+ scoped_nsobject<NSTrackingArea> trackingAreaButton_;
+ scoped_nsobject<NSTrackingArea> trackingAreaDropdown_;
+
+ FilePath downloadPath_; // stored unelided
+ NSString* secondaryTitle_;
+ NSFont* secondaryFont_;
+
+ BOOL isStatusTextVisible_;
+ CGFloat titleY_;
+ CGFloat statusAlpha_;
+ scoped_nsobject<NSAnimation> hideStatusAnimation_;
+}
+
+- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel;
+
+@property (copy) NSString* secondaryTitle;
+@property (retain) NSFont* secondaryFont;
+
+// Valid to call in response to a click of the cell's button. Returns if the
+// button part of the cell was clicked.
+- (BOOL)isButtonPartPressed;
+
+@end
+
+#endif // CHROME_BROWSER_COCOA_DOWNLOAD_ITEM_CELL_H_
+
diff --git a/chrome/browser/cocoa/download_item_cell.mm b/chrome/browser/cocoa/download_item_cell.mm
new file mode 100644
index 0000000..62f0ec4
--- /dev/null
+++ b/chrome/browser/cocoa/download_item_cell.mm
@@ -0,0 +1,437 @@
+// Copyright (c) 2009 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 "chrome/browser/cocoa/download_item_cell.h"
+
+#include "app/gfx/text_elider.h"
+#include "app/l10n_util.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/cocoa/download_item_cell.h"
+#include "chrome/browser/download/download_item_model.h"
+#include "chrome/browser/download/download_manager.h"
+#import "third_party/GTM/AppKit/GTMTheme.h"
+
+namespace {
+
+// Distance from top border to icon
+const CGFloat kImagePaddingTop = 1;
+
+// Distance from left border to icon
+const CGFloat kImagePaddingLeft = 1;
+
+// Width of icon
+const CGFloat kImageWidth = 32;
+
+// Height of icon
+const CGFloat kImageHeight = 32;
+
+// x coordinate of download name string, in view coords
+const CGFloat kTextPosLeft = kImagePaddingLeft + kImageWidth + 1;
+
+// Distance from end of download name string to dropdown area
+const CGFloat kTextPaddingRight = 3;
+
+// y coordinate of download name string, in view coords, when status message
+// is visible
+const CGFloat kPrimaryTextPosTop = 5;
+
+// y coordinate of download name string, in view coords, when status message
+// is not visible
+const CGFloat kPrimaryTextOnlyPosTop = 10;
+
+// y coordinate of status message, in view coords
+const CGFloat kSecondaryTextPosTop = 17;
+
+// Width of dropdown area on the right
+const CGFloat kDropdownAreaWidth = 18;
+
+// Width of dropdown arrow
+const CGFloat kDropdownArrowWidth = 5;
+
+// Height of dropdown arrow
+const CGFloat kDropdownArrowHeight = 3;
+
+// Duration of the two-lines-to-one-line animation, in seconds
+NSTimeInterval kHideStatusDuration = 0.3;
+
+}
+
+// This is a helper class to animate the fading out of the status text.
+@interface HideSecondaryTitleAnimation : NSAnimation {
+ DownloadItemCell* cell_;
+}
+- (id)initWithDownloadItemCell:(DownloadItemCell*)cell;
+@end
+
+@interface DownloadItemCell(Private)
+- (void)updateTrackingAreas:(id)sender;
+- (void)hideSecondaryTitle;
+- (void)animationProgressed:(NSAnimationProgress)progress;
+@end
+
+@implementation DownloadItemCell
+
+@synthesize secondaryTitle = secondaryTitle_;
+@synthesize secondaryFont = secondaryFont_;
+
+- (void)setInitialState {
+ isStatusTextVisible_ = NO;
+ titleY_ = kPrimaryTextPosTop;
+ statusAlpha_ = 1.0;
+
+ [self setFont:[NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
+ [self setSecondaryFont:[NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSMiniControlSize]]];
+
+ [self updateTrackingAreas:self];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateTrackingAreas:)
+ name:NSViewFrameDidChangeNotification
+ object:[self controlView]];
+}
+
+// For nib instantiations
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder])) {
+ [self setInitialState];
+ }
+ return self;
+}
+
+// For programmatic instantiations
+- (id)initTextCell:(NSString *)string {
+ if ((self = [super initTextCell:string])) {
+ [self setInitialState];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [secondaryTitle_ release];
+ [secondaryFont_ release];
+ [super dealloc];
+}
+
+- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel {
+ // Set name and icon of download.
+ downloadPath_ = downloadModel->download()->GetFileName();
+
+ // TODO(paulg): Use IconManager for loading icons on the file thread
+ // (crbug.com/16226).
+ NSString* extension = base::SysUTF8ToNSString(downloadPath_.Extension());
+ NSImage* icon = [[NSWorkspace sharedWorkspace] iconForFileType:extension];
+ [self setImage:icon];
+
+ std::wstring statusText = downloadModel->GetStatusText();
+ if (statusText.empty()) {
+ // Remove the status text label.
+ [self hideSecondaryTitle];
+ isStatusTextVisible_ = NO;
+ } else {
+ // Set status text.
+ NSString* statusString = base::SysWideToNSString(statusText);
+ [self setSecondaryTitle:statusString];
+ isStatusTextVisible_ = YES;
+ }
+}
+
+- (void)updateTrackingAreas:(id)sender {
+ if (trackingAreaButton_) {
+ [[self controlView] removeTrackingArea:trackingAreaButton_.get()];
+ trackingAreaButton_.reset(nil);
+ }
+ if (trackingAreaDropdown_) {
+ [[self controlView] removeTrackingArea:trackingAreaDropdown_.get()];
+ trackingAreaDropdown_.reset(nil);
+ }
+
+ // Use two distinct tracking rects for left and right parts.
+ NSRect bounds = [[self controlView] bounds];
+ NSRect buttonRect, dropdownRect;
+ NSDivideRect(bounds, &dropdownRect, &buttonRect,
+ kDropdownAreaWidth, NSMaxXEdge);
+
+ trackingAreaButton_.reset([[NSTrackingArea alloc]
+ initWithRect:buttonRect
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInActiveApp)
+ owner:self
+ userInfo:nil]);
+ [[self controlView] addTrackingArea:trackingAreaButton_.get()];
+
+ trackingAreaDropdown_.reset([[NSTrackingArea alloc]
+ initWithRect:dropdownRect
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInActiveApp)
+ owner:self
+ userInfo:nil]);
+ [[self controlView] addTrackingArea:trackingAreaDropdown_.get()];
+}
+
+- (void)setShowsBorderOnlyWhileMouseInside:(BOOL)showOnly {
+ // Override to make sure it doesn't do anything if it's called accidentally.
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ mouseInsideCount_++;
+ if ([theEvent trackingArea] == trackingAreaButton_.get())
+ mousePosition_ = kDownloadItemMouseOverButtonPart;
+ else if ([theEvent trackingArea] == trackingAreaDropdown_.get())
+ mousePosition_ = kDownloadItemMouseOverButtonPart;
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (void)mouseExited:(NSEvent *)theEvent {
+ mouseInsideCount_--;
+ if (mouseInsideCount_ == 0)
+ mousePosition_ = kDownloadItemMouseOutside;
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (BOOL)isMouseInside {
+ return mousePosition_ != kDownloadItemMouseOutside;
+}
+
+- (BOOL)isMouseOverButtonPart {
+ return mousePosition_ == kDownloadItemMouseOverButtonPart;
+}
+
+- (BOOL)isButtonPartPressed {
+ return [self isHighlighted]
+ && mousePosition_ == kDownloadItemMouseOverButtonPart;
+}
+
+- (BOOL)isMouseOverDropdownPart {
+ return mousePosition_ == kDownloadItemMouseOverButtonPart;
+}
+
+- (BOOL)isDropdownPartPressed {
+ return [self isHighlighted]
+ && mousePosition_ == kDownloadItemMouseOverButtonPart;
+}
+
+- (NSBezierPath*)leftRoundedPath:(CGFloat)radius inRect:(NSRect)rect {
+
+ NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
+ NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
+ NSPoint bottomRight = NSMakePoint(NSMaxX(rect) , NSMinY(rect));
+
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:topRight];
+ [path appendBezierPathWithArcFromPoint:topLeft
+ toPoint:rect.origin
+ radius:radius];
+ [path appendBezierPathWithArcFromPoint:rect.origin
+ toPoint:bottomRight
+ radius:radius];
+ [path lineToPoint:bottomRight];
+ return path;
+}
+
+- (NSBezierPath*)rightRoundedPath:(CGFloat)radius inRect:(NSRect)rect {
+
+ NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
+ NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
+ NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect));
+
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:rect.origin];
+ [path appendBezierPathWithArcFromPoint:bottomRight
+ toPoint:topRight
+ radius:radius];
+ [path appendBezierPathWithArcFromPoint:topRight
+ toPoint:topLeft
+ radius:radius];
+ [path lineToPoint:topLeft];
+ [path closePath]; // Right path is closed
+ return path;
+}
+
+- (void)elideTitle:(int)availableWidth {
+ NSFont* font = [self font];
+ gfx::Font font_chr =
+ gfx::Font::CreateFont(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
+
+ NSString* titleString = base::SysWideToNSString(
+ ElideFilename(downloadPath_, font_chr, availableWidth));
+ [self setTitle:titleString];
+}
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+
+ // Constants from Cole. Will kConstan them once the feedback loop
+ // is complete.
+ NSRect drawFrame = NSInsetRect(cellFrame, 0.5, 0.5);
+ NSRect innerFrame = NSInsetRect(cellFrame, 1, 1);
+
+ const float radius = 3.5;
+ NSWindow* window = [controlView window];
+ BOOL active = [window isKeyWindow] || [window isMainWindow];
+
+ GTMTheme* theme = [controlView gtm_theme];
+
+ NSRect buttonDrawRect, dropdownDrawRect;
+ NSDivideRect(drawFrame, &dropdownDrawRect, &buttonDrawRect,
+ kDropdownAreaWidth, NSMaxXEdge);
+
+ NSRect buttonInnerRect, dropdownInnerRect;
+ NSDivideRect(innerFrame, &dropdownInnerRect, &buttonInnerRect,
+ kDropdownAreaWidth, NSMaxXEdge);
+
+ NSBezierPath* buttonInnerPath = [self
+ leftRoundedPath:radius inRect:buttonDrawRect];
+ NSBezierPath* buttonOuterPath = [self
+ leftRoundedPath:(radius + 1)
+ inRect:NSInsetRect(buttonDrawRect, -1, -1)];
+
+ NSBezierPath* dropdownInnerPath = [self
+ rightRoundedPath:radius inRect:dropdownDrawRect];
+ NSBezierPath* dropdownOuterPath = [self
+ rightRoundedPath:(radius + 1)
+ inRect:NSInsetRect(dropdownDrawRect, -1, -1)];
+
+ // Stroke the borders and appropriate fill gradient. If we're borderless,
+ // the only time we want to draw the inner gradient is if we're highlighted.
+ if ([self isHighlighted] || [self isMouseInside]) {
+ [self drawBorderAndFillForTheme:theme
+ controlView:controlView
+ outerPath:buttonOuterPath
+ innerPath:buttonInnerPath
+ showHighlightGradient:[self isMouseOverButtonPart]
+ showClickedGradient:[self isButtonPartPressed]
+ active:active
+ cellFrame:cellFrame];
+
+ [self drawBorderAndFillForTheme: theme
+ controlView:controlView
+ outerPath:dropdownOuterPath
+ innerPath:dropdownInnerPath
+ showHighlightGradient:[self isMouseOverDropdownPart]
+ showClickedGradient:[self isDropdownPartPressed]
+ active:active
+ cellFrame:cellFrame];
+ }
+
+ [self drawInteriorWithFrame:innerFrame inView:controlView];
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ // Draw title
+ [self elideTitle:cellFrame.size.width -
+ (kTextPosLeft + kTextPaddingRight + kDropdownAreaWidth)];
+
+ NSColor* color = [self isButtonPartPressed]
+ ? [NSColor alternateSelectedControlTextColor] : [NSColor textColor];
+ NSString* primaryText = [self title];
+
+ NSDictionary* primaryTextAttributes = [NSDictionary
+ dictionaryWithObjectsAndKeys:
+ color, NSForegroundColorAttributeName,
+ [self font], NSFontAttributeName,
+ nil];
+ NSPoint primaryPos = NSMakePoint(
+ cellFrame.origin.x + kTextPosLeft,
+ titleY_);
+
+ [primaryText drawAtPoint:primaryPos withAttributes:primaryTextAttributes];
+
+ // Draw secondary title, if any
+ if ([self secondaryTitle] != nil && statusAlpha_ > 0) {
+ NSString* secondaryText = [self secondaryTitle];
+ NSColor* secondaryColor = [color colorWithAlphaComponent:statusAlpha_];
+ NSDictionary* secondaryTextAttributes = [NSDictionary
+ dictionaryWithObjectsAndKeys:
+ secondaryColor, NSForegroundColorAttributeName,
+ [self secondaryFont], NSFontAttributeName,
+ nil];
+ NSPoint secondaryPos = NSMakePoint(
+ cellFrame.origin.x + kTextPosLeft,
+ kSecondaryTextPosTop);
+ [secondaryText drawAtPoint:secondaryPos
+ withAttributes:secondaryTextAttributes];
+ }
+
+ // Draw icon
+ NSRect imageRect = NSZeroRect;
+ imageRect.size = [[self image] size];
+ [[self image] setFlipped:[controlView isFlipped]];
+ [[self image] drawInRect:[self imageRectForBounds:cellFrame]
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:[self isEnabled] ? 1.0 : 0.5];
+
+ // Popup arrow. Put center of mass of the arrow in the center of the
+ // dropdown area.
+ CGFloat cx = NSMaxX(cellFrame) - kDropdownAreaWidth/2;
+ CGFloat cy = NSMidY(cellFrame);
+ NSPoint p1 = NSMakePoint(cx - kDropdownArrowWidth/2,
+ cy - kDropdownArrowHeight/3);
+ NSPoint p2 = NSMakePoint(cx + kDropdownArrowWidth/2,
+ cy - kDropdownArrowHeight/3);
+ NSPoint p3 = NSMakePoint(cx, cy + kDropdownArrowHeight*2/3);
+ NSBezierPath *triangle = [NSBezierPath bezierPath];
+ [triangle moveToPoint:p1];
+ [triangle lineToPoint:p2];
+ [triangle lineToPoint:p3];
+ [triangle closePath];
+
+ NSColor* fill = [self isDropdownPartPressed]
+ ? [NSColor alternateSelectedControlTextColor] : [NSColor textColor];
+ [fill setFill];
+ [triangle fill];
+}
+
+- (NSRect)imageRectForBounds:(NSRect)cellFrame {
+ return NSMakeRect(
+ kImagePaddingLeft, kImagePaddingTop, kImageWidth, kImageHeight);
+}
+
+- (void)hideSecondaryTitle {
+ if (isStatusTextVisible_) {
+ // No core animation -- text in CA layers is not subpixel antialiased :-/
+ hideStatusAnimation_.reset([[HideSecondaryTitleAnimation alloc]
+ initWithDownloadItemCell:self]);
+ [hideStatusAnimation_.get() setDelegate:self];
+ [hideStatusAnimation_.get() startAnimation];
+ } else {
+ // If the download is done so quickly that the status line is never visible,
+ // don't show an animation
+ [self animationProgressed:1.0];
+ }
+}
+
+- (void)animationProgressed:(NSAnimationProgress)progress {
+ titleY_ = progress*kPrimaryTextOnlyPosTop + (1 - progress)*kPrimaryTextPosTop;
+ statusAlpha_ = 1 - progress;
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (void)animationDidEnd:(NSAnimation *)animation {
+ hideStatusAnimation_.reset();
+}
+
+@end
+
+@implementation HideSecondaryTitleAnimation
+
+- (id)initWithDownloadItemCell:(DownloadItemCell*)cell {
+ if ((self = [super initWithDuration:kHideStatusDuration
+ animationCurve:NSAnimationEaseIn])) {
+ cell_ = cell;
+ [self setAnimationBlockingMode:NSAnimationNonblocking];
+ }
+ return self;
+}
+
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ [super setCurrentProgress:progress];
+ [cell_ animationProgressed:progress];
+}
+
+@end
diff --git a/chrome/browser/cocoa/download_item_controller.h b/chrome/browser/cocoa/download_item_controller.h
index dec9f7c..30bc28e 100644
--- a/chrome/browser/cocoa/download_item_controller.h
+++ b/chrome/browser/cocoa/download_item_controller.h
@@ -7,6 +7,7 @@
#include "base/scoped_ptr.h"
class BaseDownloadItemModel;
+@class DownloadItemCell;
class DownloadItemMac;
class DownloadShelfContextMenuMac;
@class DownloadShelfController;
@@ -15,11 +16,14 @@ class DownloadShelfContextMenuMac;
@interface DownloadItemController : NSViewController {
@private
- IBOutlet NSPopUpButton* popupButton_;
+ IBOutlet NSButton* progressView_;
+ IBOutlet DownloadItemCell* cell_;
IBOutlet NSMenu* activeDownloadMenu_;
IBOutlet NSMenu* completeDownloadMenu_;
+ NSMenu* currentMenu_; // points to one of the two menus above
+
scoped_ptr<DownloadItemMac> bridge_;
scoped_ptr<DownloadShelfContextMenuMac> menuBridge_;
@@ -38,6 +42,9 @@ class DownloadShelfContextMenuMac;
// Remove ourself from the download UI.
- (void)remove;
+// Download item button clicked
+- (IBAction)handleButtonClick:(id)sender;
+
// Context menu handlers.
- (IBAction)handleOpen:(id)sender;
- (IBAction)handleAlwaysOpen:(id)sender;
diff --git a/chrome/browser/cocoa/download_item_controller.mm b/chrome/browser/cocoa/download_item_controller.mm
index aa0d8a5..f5d2836 100644
--- a/chrome/browser/cocoa/download_item_controller.mm
+++ b/chrome/browser/cocoa/download_item_controller.mm
@@ -4,12 +4,13 @@
#import "chrome/browser/cocoa/download_item_controller.h"
-#include "app/l10n_util.h"
#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
+#import "chrome/browser/cocoa/download_item_cell.h"
#include "chrome/browser/cocoa/download_item_mac.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/download/download_util.h"
+
// A class for the chromium-side part of the download shelf context menu.
@@ -59,32 +60,12 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
// Set correct popup menu.
if (downloadModel->download()->state() == DownloadItem::COMPLETE)
- [popupButton_ setMenu:completeDownloadMenu_];
+ currentMenu_ = completeDownloadMenu_;
else
- [popupButton_ setMenu:activeDownloadMenu_];
-
- // Set name and icon of download.
- FilePath downloadPath = downloadModel->download()->GetFileName();
-
- // TODO(thakis): use filename eliding like gtk/windows versions.
- NSString* titleString = base::SysWideToNSString(downloadPath.ToWStringHack());
- [[popupButton_ itemAtIndex:0] setTitle:titleString];
-
- // TODO(paulg): Use IconManager for loading icons on the file thread
- // (crbug.com/16226).
- NSString* extension = base::SysUTF8ToNSString(downloadPath.Extension());
- [[popupButton_ itemAtIndex:0] setImage:
- [[NSWorkspace sharedWorkspace] iconForFileType:extension]];
-
- // Set status text.
- std::wstring statusText = downloadModel->GetStatusText();
- // Remove the status text label.
- if (statusText.empty()) {
- // TODO(thakis): Once there is a status label, hide it here.
- return;
- }
+ currentMenu_ = activeDownloadMenu_;
- // TODO(thakis): Set status_text as status label.
+ [progressView_ setMenu:currentMenu_]; // for context menu
+ [cell_ setStateFromDownload:downloadModel];
}
- (void)remove {
@@ -92,6 +73,22 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
[shelf_ remove:self];
}
+- (IBAction)handleButtonClick:(id)sender {
+ if ([cell_ isButtonPartPressed]) {
+ DownloadItem* download = bridge_->download_model()->download();
+ if (download->state() == DownloadItem::IN_PROGRESS) {
+ download->set_open_when_complete(!download->open_when_complete());
+ } else if (download->state() == DownloadItem::COMPLETE) {
+ download_util::OpenDownload(download);
+ }
+ } else {
+ // TODO(thakis): Align menu nicely with left view edge
+ [NSMenu popUpContextMenu:currentMenu_
+ withEvent:[NSApp currentEvent]
+ forView:progressView_];
+ }
+}
+
// Sets the enabled and checked state of a particular menu item for this
// download. We translate the NSMenuItem selection to menu selections understood
// by the non platform specific download context menu.
diff --git a/chrome/browser/cocoa/download_shelf_controller.mm b/chrome/browser/cocoa/download_shelf_controller.mm
index 896b72e..ccb672d 100644
--- a/chrome/browser/cocoa/download_shelf_controller.mm
+++ b/chrome/browser/cocoa/download_shelf_controller.mm
@@ -17,20 +17,21 @@
namespace {
-// TODO(thakis): These are all temporary until there's a download item view.
-
// Border padding of a download item.
-const int kDownloadItemBorderPadding = 4;
+const int kDownloadItemBorderPadding = 3;
-// Width of a download item.
+// Width of a download item, must match width in DownloadItem.xib.
const int kDownloadItemWidth = 200;
-// Height of a download item.
-const int kDownloadItemHeight = 32;
+// Height of a download item, must match height in DownloadItem.xib.
+const int kDownloadItemHeight = 34;
// Horizontal padding between two download items.
const int kDownloadItemPadding = 10;
+// Duration for the open-new-leftmost-item animation, in seconds.
+const NSTimeInterval kDownloadItemOpenDuration = 0.8;
+
} // namespace
@interface DownloadShelfController(Private)
@@ -69,7 +70,7 @@ const int kDownloadItemPadding = 10;
[paragraphStyle.get() setAlignment:NSRightTextAlignment];
NSDictionary* linkAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
- self, NSLinkAttributeName,
+ @"", NSLinkAttributeName,
[NSCursor pointingHandCursor], NSCursorAttributeName,
paragraphStyle.get(), NSParagraphStyleAttributeName,
nil];
@@ -191,17 +192,21 @@ const int kDownloadItemPadding = 10;
}
- (void)addDownloadItem:(BaseDownloadItemModel*)model {
- // TODO(thakis): we need to delete these at some point. There's no explicit
- // mass delete on windows, figure out where they do it.
-
// TODO(thakis): RTL support?
// (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
- int startX = kDownloadItemBorderPadding +
- (kDownloadItemWidth + kDownloadItemPadding) *
- [downloadItemControllers_ count];
+ // Shift all existing items to the right
+ for (DownloadItemController* itemController in downloadItemControllers_.get()) {
+ NSRect frame = [[itemController view] frame];
+ frame.origin.x += kDownloadItemWidth + kDownloadItemPadding;
+ [[[itemController view] animator] setFrame:frame];
+ }
+ // Insert new item at the left
+ int startX = kDownloadItemBorderPadding;
+
+ // Start at width 0...
NSRect position = NSMakeRect(startX, kDownloadItemBorderPadding,
- kDownloadItemWidth, kDownloadItemHeight);
+ 0, kDownloadItemHeight);
scoped_nsobject<DownloadItemController> controller(
[[DownloadItemController alloc] initWithFrame:position
model:model
@@ -209,6 +214,15 @@ const int kDownloadItemPadding = 10;
[downloadItemControllers_ addObject:controller.get()];
[[self view] addSubview:[controller.get() view]];
+
+ // ...then animate in
+ NSRect frame = [[controller.get() view] frame];
+ frame.size.width = kDownloadItemWidth;
+
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kDownloadItemOpenDuration];
+ [[[controller.get() view] animator] setFrame:frame];
+ [NSAnimationContext endGrouping];
}
@end
diff --git a/chrome/browser/cocoa/gradient_button_cell.h b/chrome/browser/cocoa/gradient_button_cell.h
index f0039e9..61c9a4f 100644
--- a/chrome/browser/cocoa/gradient_button_cell.h
+++ b/chrome/browser/cocoa/gradient_button_cell.h
@@ -9,12 +9,15 @@
#include "base/scoped_nsobject.h"
+@class GTMTheme;
+
// Base class for button cells for toolbar and bookmark bar.
//
// This is a button cell that handles drawing/highlighting of buttons.
// The appearance is determined by setting the cell's tag (not the
// view's) to one of the constants below (ButtonType).
+// Set this as the cell's tag.
enum {
kLeftButtonType = -1,
kLeftButtonWithShadowType = -2,
@@ -37,6 +40,15 @@ typedef NSInteger ButtonType;
// Turn off theming. Temporary work-around.
- (void)setShouldTheme:(BOOL)shouldTheme;
+- (void)drawBorderAndFillForTheme:(GTMTheme*)theme
+ controlView:(NSView*)controlView
+ outerPath:(NSBezierPath*)outerPath
+ innerPath:(NSBezierPath*)innerPath
+ showHighlightGradient:(BOOL)showHighlightGradient
+ showClickedGradient:(BOOL)showClickedGradient
+ active:(BOOL)active
+ cellFrame:(NSRect)cellFrame;
+
// An image to underlay beneath the existing image; not themed. May be nil.
- (NSImage*)underlayImage;
- (void)setUnderlayImage:(NSImage*)image;
diff --git a/chrome/browser/cocoa/gradient_button_cell.mm b/chrome/browser/cocoa/gradient_button_cell.mm
index dbc80af..a0b31522 100644
--- a/chrome/browser/cocoa/gradient_button_cell.mm
+++ b/chrome/browser/cocoa/gradient_button_cell.mm
@@ -89,6 +89,76 @@
}
}
+- (void)drawBorderAndFillForTheme:(GTMTheme*)theme
+ controlView:(NSView*)controlView
+ outerPath:(NSBezierPath*)outerPath
+ innerPath:(NSBezierPath*)innerPath
+ showHighlightGradient:(BOOL)showHighlightGradient
+ showClickedGradient:(BOOL)showClickedGradient
+ active:(BOOL)active
+ cellFrame:(NSRect)cellFrame {
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.25] set];
+ [outerPath stroke];
+
+ NSImage* backgroundImage =
+ [theme backgroundImageForStyle:GTMThemeStyleToolBarButton state:YES];
+
+ if (backgroundImage) {
+ NSColor* patternColor = [NSColor colorWithPatternImage:backgroundImage];
+ [patternColor set];
+ // Set the phase to match window.
+ NSRect trueRect = [controlView convertRectToBase:cellFrame];
+ [[NSGraphicsContext currentContext]
+ setPatternPhase:NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect))];
+ [innerPath fill];
+ } else {
+ if (showClickedGradient) {
+ NSGradient* gradient =
+ [theme gradientForStyle:GTMThemeStyleToolBarButtonPressed
+ state:active];
+ [gradient drawInBezierPath:innerPath angle:90.0];
+ }
+ }
+
+ if (!showClickedGradient && showHighlightGradient) {
+ [NSGraphicsContext saveGraphicsState];
+ [innerPath addClip];
+
+ // Draw the inner glow.
+ [innerPath setLineWidth:2];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.9] setStroke];
+ [innerPath stroke];
+
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.9] setStroke];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setFill];
+
+ // Draw the top inner highlight.
+ NSAffineTransform* highlightTransform = [NSAffineTransform transform];
+ [highlightTransform translateXBy:1 yBy:1];
+ scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]);
+ [highlightPath transformUsingAffineTransform:highlightTransform];
+
+ [highlightPath stroke];
+
+ NSColor* startColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.666];
+ NSColor* endColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.333];
+ scoped_nsobject<NSBezierPath> gradient([[NSGradient alloc]
+ initWithColorsAndLocations:startColor, 0.33, endColor, 1.0, nil]);
+
+ [gradient drawInBezierPath:innerPath angle:90.0];
+
+ [NSGraphicsContext restoreGraphicsState];
+ }
+
+ NSColor* stroke = [theme strokeColorForStyle:GTMThemeStyleToolBarButton
+ state:active];
+ [stroke setStroke];
+
+ [innerPath setLineWidth:1];
+ [innerPath stroke];
+}
+
+
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
// Constants from Cole. Will kConstant them once the feedback loop
// is complete.
@@ -129,65 +199,15 @@
if (([self isBordered] && ![self showsBorderOnlyWhileMouseInside]) ||
pressed ||
[self isMouseInside]) {
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.25] set];
- [outerPath stroke];
-
- NSImage* backgroundImage =
- [theme backgroundImageForStyle:GTMThemeStyleToolBarButton state:YES];
-
- if (backgroundImage) {
- NSColor* patternColor = [NSColor colorWithPatternImage:backgroundImage];
- [patternColor set];
- // Set the phase to match window.
- NSRect trueRect = [controlView convertRectToBase:cellFrame];
- [[NSGraphicsContext currentContext]
- setPatternPhase:NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect))];
- [innerPath fill];
- } else {
- if (pressed) {
- NSGradient* gradient =
- [theme gradientForStyle:GTMThemeStyleToolBarButtonPressed
- state:active];
- [gradient drawInBezierPath:innerPath angle:90.0];
- }
- }
-
- if (!pressed) {
- [NSGraphicsContext saveGraphicsState];
- [innerPath addClip];
-
- // Draw the inner glow.
- [innerPath setLineWidth:2];
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.9] setStroke];
- [innerPath stroke];
-
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.9] setStroke];
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setFill];
-
- // Draw the top inner highlight.
- NSAffineTransform* highlightTransform = [NSAffineTransform transform];
- [highlightTransform translateXBy:1 yBy:1];
- scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]);
- [highlightPath transformUsingAffineTransform:highlightTransform];
-
- [highlightPath stroke];
- NSColor* startColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.666];
- NSColor* endColor = [NSColor colorWithCalibratedWhite:1.0 alpha:0.333];
- scoped_nsobject<NSBezierPath> gradient([[NSGradient alloc]
- initWithColorsAndLocations:startColor, 0.33, endColor, 1.0, nil]);
-
- [gradient drawInBezierPath:innerPath angle:90.0];
-
- [NSGraphicsContext restoreGraphicsState];
- }
-
- NSColor* stroke = [theme strokeColorForStyle:GTMThemeStyleToolBarButton
- state:active];
- [stroke setStroke];
-
- [innerPath setLineWidth:1];
- [innerPath stroke];
+ [self drawBorderAndFillForTheme:theme
+ controlView:controlView
+ outerPath:outerPath
+ innerPath:innerPath
+ showHighlightGradient:YES
+ showClickedGradient:pressed
+ active:active
+ cellFrame:cellFrame];
}
// If this is the left side of a segmented button, draw a slight shadow.