1// Copyright (c) 2012 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#include "chrome/browser/ui/cocoa/background_gradient_view.h" 6 7#import "chrome/browser/themes/theme_properties.h" 8#import "chrome/browser/themes/theme_service.h" 9#import "chrome/browser/ui/cocoa/themed_window.h" 10#include "grit/theme_resources.h" 11#import "ui/base/cocoa/nsview_additions.h" 12 13@interface BackgroundGradientView (Private) 14- (void)commonInit; 15- (NSColor*)backgroundImageColor; 16@end 17 18@implementation BackgroundGradientView 19 20@synthesize showsDivider = showsDivider_; 21 22- (id)initWithFrame:(NSRect)frameRect { 23 if ((self = [super initWithFrame:frameRect])) { 24 [self commonInit]; 25 } 26 return self; 27} 28 29- (id)initWithCoder:(NSCoder*)decoder { 30 if ((self = [super initWithCoder:decoder])) { 31 [self commonInit]; 32 } 33 return self; 34} 35 36- (void)dealloc { 37 [[NSNotificationCenter defaultCenter] removeObserver:self]; 38 [super dealloc]; 39} 40 41- (void)commonInit { 42 showsDivider_ = YES; 43} 44 45- (void)setShowsDivider:(BOOL)show { 46 if (showsDivider_ == show) 47 return; 48 showsDivider_ = show; 49 [self setNeedsDisplay:YES]; 50} 51 52- (void)drawBackgroundWithOpaque:(BOOL)opaque { 53 const NSRect bounds = [self bounds]; 54 55 if (opaque) { 56 // If the background image is semi transparent then we need something 57 // to blend against. Using 20% black gives us a color similar to Windows. 58 [[NSColor colorWithCalibratedWhite:0.2 alpha:1.0] set]; 59 NSRectFill(bounds); 60 } 61 62 [[self backgroundImageColor] set]; 63 NSRectFillUsingOperation(bounds, NSCompositeSourceOver); 64 65 if (showsDivider_) { 66 // Draw bottom stroke 67 [[self strokeColor] set]; 68 NSRect borderRect, contentRect; 69 NSDivideRect(bounds, &borderRect, &contentRect, [self cr_lineWidth], 70 NSMinYEdge); 71 NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); 72 } 73} 74 75- (NSColor*)strokeColor { 76 NSWindow* window = [self window]; 77 78 // Some views have a child NSWindow between them and the window that is 79 // active (e.g, OmniboxPopupTopSeparatorView). For these, check the status 80 // of parentWindow instead. Note that this is not tracked correctly (but 81 // the views that do this appear to be removed when the window loses focus 82 // anyway). 83 if ([window parentWindow]) 84 window = [window parentWindow]; 85 BOOL isActive = [window isMainWindow]; 86 87 ui::ThemeProvider* themeProvider = [window themeProvider]; 88 if (!themeProvider) 89 return [NSColor blackColor]; 90 return themeProvider->GetNSColor( 91 isActive ? ThemeProperties::COLOR_TOOLBAR_STROKE : 92 ThemeProperties::COLOR_TOOLBAR_STROKE_INACTIVE); 93} 94 95- (NSColor*)backgroundImageColor { 96 ThemeService* themeProvider = 97 static_cast<ThemeService*>([[self window] themeProvider]); 98 if (!themeProvider) 99 return [[self window] backgroundColor]; 100 101 // Themes don't have an inactive image so only look for one if there's no 102 // theme. 103 BOOL isActive = [[self window] isMainWindow]; 104 if (!isActive && themeProvider->UsingDefaultTheme()) { 105 NSColor* color = themeProvider->GetNSImageColorNamed( 106 IDR_THEME_TOOLBAR_INACTIVE); 107 if (color) 108 return color; 109 } 110 111 return themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR); 112} 113 114- (void)windowFocusDidChange:(NSNotification*)notification { 115 // Some child views will indirectly use BackgroundGradientView by calling an 116 // ancestor's draw function (e.g, BookmarkButtonView). Call setNeedsDisplay 117 // on all descendants to ensure that these views re-draw. 118 // TODO(ccameron): Enable these views to listen for focus notifications 119 // directly. 120 [self cr_recursivelySetNeedsDisplay:YES]; 121} 122 123- (void)viewWillMoveToWindow:(NSWindow*)window { 124 if ([self window]) { 125 [[NSNotificationCenter defaultCenter] 126 removeObserver:self 127 name:NSWindowDidBecomeKeyNotification 128 object:[self window]]; 129 [[NSNotificationCenter defaultCenter] 130 removeObserver:self 131 name:NSWindowDidBecomeMainNotification 132 object:[self window]]; 133 } 134 if (window) { 135 [[NSNotificationCenter defaultCenter] 136 addObserver:self 137 selector:@selector(windowFocusDidChange:) 138 name:NSWindowDidBecomeMainNotification 139 object:window]; 140 [[NSNotificationCenter defaultCenter] 141 addObserver:self 142 selector:@selector(windowFocusDidChange:) 143 name:NSWindowDidResignMainNotification 144 object:window]; 145 // The new window for the view may have a different focus state than the 146 // last window this view was part of. Force a re-draw to ensure that the 147 // view draws the right state. 148 [self windowFocusDidChange:nil]; 149 } 150 [super viewWillMoveToWindow:window]; 151} 152 153- (void)setFrameOrigin:(NSPoint)origin { 154 // The background color depends on the view's vertical position. This impacts 155 // any child views that draw using this view's functions. 156 if (NSMinY([self frame]) != origin.y) 157 [self cr_recursivelySetNeedsDisplay:YES]; 158 159 [super setFrameOrigin:origin]; 160} 161 162@end 163