diff options
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r-- | chrome/browser/cocoa/download_item_cell.h | 56 | ||||
-rw-r--r-- | chrome/browser/cocoa/download_item_cell.mm | 437 | ||||
-rw-r--r-- | chrome/browser/cocoa/download_item_controller.h | 9 | ||||
-rw-r--r-- | chrome/browser/cocoa/download_item_controller.mm | 49 | ||||
-rw-r--r-- | chrome/browser/cocoa/download_shelf_controller.mm | 42 | ||||
-rw-r--r-- | chrome/browser/cocoa/gradient_button_cell.h | 12 | ||||
-rw-r--r-- | chrome/browser/cocoa/gradient_button_cell.mm | 136 |
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. |