| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/tab_strip_view.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/mac/mac_util.h" | |
| 9 #include "chrome/browser/themes/browser_theme_provider.h" | |
| 10 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | |
| 11 #import "chrome/browser/ui/cocoa/tab_strip_controller.h" | |
| 12 #import "chrome/browser/ui/cocoa/view_id_util.h" | |
| 13 | |
| 14 @implementation TabStripView | |
| 15 | |
| 16 @synthesize newTabButton = newTabButton_; | |
| 17 @synthesize dropArrowShown = dropArrowShown_; | |
| 18 @synthesize dropArrowPosition = dropArrowPosition_; | |
| 19 | |
| 20 - (id)initWithFrame:(NSRect)frame { | |
| 21 self = [super initWithFrame:frame]; | |
| 22 if (self) { | |
| 23 // Set lastMouseUp_ = -1000.0 so that timestamp-lastMouseUp_ is big unless | |
| 24 // lastMouseUp_ has been reset. | |
| 25 lastMouseUp_ = -1000.0; | |
| 26 | |
| 27 // Register to be an URL drop target. | |
| 28 dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]); | |
| 29 } | |
| 30 return self; | |
| 31 } | |
| 32 | |
| 33 // Draw bottom border (a dark border and light highlight). Each tab is | |
| 34 // responsible for mimicking this bottom border, unless it's the selected | |
| 35 // tab. | |
| 36 - (void)drawBorder:(NSRect)bounds { | |
| 37 NSRect borderRect, contentRect; | |
| 38 | |
| 39 borderRect = bounds; | |
| 40 borderRect.origin.y = 1; | |
| 41 borderRect.size.height = 1; | |
| 42 [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set]; | |
| 43 NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); | |
| 44 NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMinYEdge); | |
| 45 | |
| 46 BrowserThemeProvider* themeProvider = | |
| 47 static_cast<BrowserThemeProvider*>([[self window] themeProvider]); | |
| 48 if (!themeProvider) | |
| 49 return; | |
| 50 | |
| 51 NSColor* bezelColor = themeProvider->GetNSColor( | |
| 52 themeProvider->UsingDefaultTheme() ? | |
| 53 BrowserThemeProvider::COLOR_TOOLBAR_BEZEL : | |
| 54 BrowserThemeProvider::COLOR_TOOLBAR, true); | |
| 55 [bezelColor set]; | |
| 56 NSRectFill(borderRect); | |
| 57 NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); | |
| 58 } | |
| 59 | |
| 60 - (void)drawRect:(NSRect)rect { | |
| 61 NSRect boundsRect = [self bounds]; | |
| 62 | |
| 63 [self drawBorder:boundsRect]; | |
| 64 | |
| 65 // Draw drop-indicator arrow (if appropriate). | |
| 66 // TODO(viettrungluu): this is all a stop-gap measure. | |
| 67 if ([self dropArrowShown]) { | |
| 68 // Programmer art: an arrow parametrized by many knobs. Note that the arrow | |
| 69 // points downwards (so understand "width" and "height" accordingly). | |
| 70 | |
| 71 // How many (pixels) to inset on the top/bottom. | |
| 72 const CGFloat kArrowTopInset = 1.5; | |
| 73 const CGFloat kArrowBottomInset = 1; | |
| 74 | |
| 75 // What proportion of the vertical space is dedicated to the arrow tip, | |
| 76 // i.e., (arrow tip height)/(amount of vertical space). | |
| 77 const CGFloat kArrowTipProportion = 0.5; | |
| 78 | |
| 79 // This is a slope, i.e., (arrow tip height)/(0.5 * arrow tip width). | |
| 80 const CGFloat kArrowTipSlope = 1.2; | |
| 81 | |
| 82 // What proportion of the arrow tip width is the stem, i.e., (stem | |
| 83 // width)/(arrow tip width). | |
| 84 const CGFloat kArrowStemProportion = 0.33; | |
| 85 | |
| 86 NSPoint arrowTipPos = [self dropArrowPosition]; | |
| 87 arrowTipPos.y += kArrowBottomInset; // Inset on the bottom. | |
| 88 | |
| 89 // Height we have to work with (insetting on the top). | |
| 90 CGFloat availableHeight = | |
| 91 NSMaxY(boundsRect) - arrowTipPos.y - kArrowTopInset; | |
| 92 DCHECK(availableHeight >= 5); | |
| 93 | |
| 94 // Based on the knobs above, calculate actual dimensions which we'll need | |
| 95 // for drawing. | |
| 96 CGFloat arrowTipHeight = kArrowTipProportion * availableHeight; | |
| 97 CGFloat arrowTipWidth = 2 * arrowTipHeight / kArrowTipSlope; | |
| 98 CGFloat arrowStemHeight = availableHeight - arrowTipHeight; | |
| 99 CGFloat arrowStemWidth = kArrowStemProportion * arrowTipWidth; | |
| 100 CGFloat arrowStemInset = (arrowTipWidth - arrowStemWidth) / 2; | |
| 101 | |
| 102 // The line width is arbitrary, but our path really should be mitered. | |
| 103 NSBezierPath* arrow = [NSBezierPath bezierPath]; | |
| 104 [arrow setLineJoinStyle:NSMiterLineJoinStyle]; | |
| 105 [arrow setLineWidth:1]; | |
| 106 | |
| 107 // Define the arrow's shape! We start from the tip and go clockwise. | |
| 108 [arrow moveToPoint:arrowTipPos]; | |
| 109 [arrow relativeLineToPoint:NSMakePoint(-arrowTipWidth / 2, arrowTipHeight)]; | |
| 110 [arrow relativeLineToPoint:NSMakePoint(arrowStemInset, 0)]; | |
| 111 [arrow relativeLineToPoint:NSMakePoint(0, arrowStemHeight)]; | |
| 112 [arrow relativeLineToPoint:NSMakePoint(arrowStemWidth, 0)]; | |
| 113 [arrow relativeLineToPoint:NSMakePoint(0, -arrowStemHeight)]; | |
| 114 [arrow relativeLineToPoint:NSMakePoint(arrowStemInset, 0)]; | |
| 115 [arrow closePath]; | |
| 116 | |
| 117 // Draw and fill the arrow. | |
| 118 [[NSColor colorWithCalibratedWhite:0 alpha:0.67] set]; | |
| 119 [arrow stroke]; | |
| 120 [[NSColor colorWithCalibratedWhite:1 alpha:0.67] setFill]; | |
| 121 [arrow fill]; | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 // YES if a double-click in the background of the tab strip minimizes the | |
| 126 // window. | |
| 127 - (BOOL)doubleClickMinimizesWindow { | |
| 128 return YES; | |
| 129 } | |
| 130 | |
| 131 // We accept first mouse so clicks onto close/zoom/miniaturize buttons and | |
| 132 // title bar double-clicks are properly detected even when the window is in the | |
| 133 // background. | |
| 134 - (BOOL)acceptsFirstMouse:(NSEvent*)event { | |
| 135 return YES; | |
| 136 } | |
| 137 | |
| 138 // Trap double-clicks and make them miniaturize the browser window. | |
| 139 - (void)mouseUp:(NSEvent*)event { | |
| 140 // Bail early if double-clicks are disabled. | |
| 141 if (![self doubleClickMinimizesWindow]) { | |
| 142 [super mouseUp:event]; | |
| 143 return; | |
| 144 } | |
| 145 | |
| 146 NSInteger clickCount = [event clickCount]; | |
| 147 NSTimeInterval timestamp = [event timestamp]; | |
| 148 | |
| 149 // Double-clicks on Zoom/Close/Mininiaturize buttons shouldn't cause | |
| 150 // miniaturization. For those, we miss the first click but get the second | |
| 151 // (with clickCount == 2!). We thus check that we got a first click shortly | |
| 152 // before (measured up-to-up) a double-click. Cocoa doesn't have a documented | |
| 153 // way of getting the proper interval (= (double-click-threshold) + | |
| 154 // (drag-threshold); the former is Carbon GetDblTime()/60.0 or | |
| 155 // com.apple.mouse.doubleClickThreshold [undocumented]). So we hard-code | |
| 156 // "short" as 0.8 seconds. (Measuring up-to-up isn't enough to properly | |
| 157 // detect double-clicks, but we're actually using Cocoa for that.) | |
| 158 if (clickCount == 2 && (timestamp - lastMouseUp_) < 0.8) { | |
| 159 if (base::mac::ShouldWindowsMiniaturizeOnDoubleClick()) | |
| 160 [[self window] performMiniaturize:self]; | |
| 161 } else { | |
| 162 [super mouseUp:event]; | |
| 163 } | |
| 164 | |
| 165 // If clickCount is 0, the drag threshold was passed. | |
| 166 lastMouseUp_ = (clickCount == 1) ? timestamp : -1000.0; | |
| 167 } | |
| 168 | |
| 169 // (URLDropTarget protocol) | |
| 170 - (id<URLDropTargetController>)urlDropController { | |
| 171 BrowserWindowController* windowController = [[self window] windowController]; | |
| 172 DCHECK([windowController isKindOfClass:[BrowserWindowController class]]); | |
| 173 return [windowController tabStripController]; | |
| 174 } | |
| 175 | |
| 176 // (URLDropTarget protocol) | |
| 177 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { | |
| 178 return [dropHandler_ draggingEntered:sender]; | |
| 179 } | |
| 180 | |
| 181 // (URLDropTarget protocol) | |
| 182 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { | |
| 183 return [dropHandler_ draggingUpdated:sender]; | |
| 184 } | |
| 185 | |
| 186 // (URLDropTarget protocol) | |
| 187 - (void)draggingExited:(id<NSDraggingInfo>)sender { | |
| 188 return [dropHandler_ draggingExited:sender]; | |
| 189 } | |
| 190 | |
| 191 // (URLDropTarget protocol) | |
| 192 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { | |
| 193 return [dropHandler_ performDragOperation:sender]; | |
| 194 } | |
| 195 | |
| 196 - (BOOL)accessibilityIsIgnored { | |
| 197 return NO; | |
| 198 } | |
| 199 | |
| 200 - (id)accessibilityAttributeValue:(NSString*)attribute { | |
| 201 if ([attribute isEqual:NSAccessibilityRoleAttribute]) | |
| 202 return NSAccessibilityGroupRole; | |
| 203 | |
| 204 return [super accessibilityAttributeValue:attribute]; | |
| 205 } | |
| 206 | |
| 207 - (ViewID)viewID { | |
| 208 return VIEW_ID_TAB_STRIP; | |
| 209 } | |
| 210 | |
| 211 @end | |
| OLD | NEW |