| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" | 5 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" |
| 6 | 6 |
| 7 #include "base/i18n/rtl.h" | 7 #include "base/i18n/rtl.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/mac/sdk_forward_declarations.h" | 9 #include "base/mac/sdk_forward_declarations.h" |
| 10 #include "base/strings/sys_string_conversions.h" | 10 #include "base/strings/sys_string_conversions.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 const NSTimeInterval kAlertHideDuration = 0.4; | 38 const NSTimeInterval kAlertHideDuration = 0.4; |
| 39 | 39 |
| 40 // The default time interval in seconds between glow updates (when | 40 // The default time interval in seconds between glow updates (when |
| 41 // increasing/decreasing). | 41 // increasing/decreasing). |
| 42 const NSTimeInterval kGlowUpdateInterval = 0.025; | 42 const NSTimeInterval kGlowUpdateInterval = 0.025; |
| 43 | 43 |
| 44 // This is used to judge whether the mouse has moved during rapid closure; if it | 44 // This is used to judge whether the mouse has moved during rapid closure; if it |
| 45 // has moved less than the threshold, we want to close the tab. | 45 // has moved less than the threshold, we want to close the tab. |
| 46 const CGFloat kRapidCloseDist = 2.5; | 46 const CGFloat kRapidCloseDist = 2.5; |
| 47 | 47 |
| 48 @interface TabView(MaterialDesign) | 48 // This class contains the logic for drawing Material Design tab images. The |
| 49 // |setTabEdgeStrokeColor| method is overridden by |TabHeavyImageMaker| to draw |
| 50 // high-contrast tabs. |
| 51 @interface TabImageMaker : NSObject |
| 49 + (void)drawTabLeftMaskImage; | 52 + (void)drawTabLeftMaskImage; |
| 50 + (void)drawTabRightMaskImage; | 53 + (void)drawTabRightMaskImage; |
| 51 + (void)drawTabLeftEdgeImage; | 54 + (void)drawTabLeftEdgeImage; |
| 52 + (void)drawTabMiddleEdgeImage; | 55 + (void)drawTabMiddleEdgeImage; |
| 53 + (void)drawTabRightEdgeImage; | 56 + (void)drawTabRightEdgeImage; |
| 57 + (void)setTabEdgeStrokeColor; |
| 58 @end |
| 59 |
| 60 @interface TabHeavyImageMaker : TabImageMaker |
| 61 + (void)setTabEdgeStrokeColor; |
| 54 @end | 62 @end |
| 55 | 63 |
| 56 @interface TabController(Private) | 64 @interface TabController(Private) |
| 57 // The TabView's close button. | 65 // The TabView's close button. |
| 58 - (HoverCloseButton*)closeButton; | 66 - (HoverCloseButton*)closeButton; |
| 59 @end | 67 @end |
| 60 | 68 |
| 69 extern NSString* const _Nonnull NSWorkspaceAccessibilityDisplayOptionsDidChangeN
otification; |
| 70 |
| 61 namespace { | 71 namespace { |
| 62 | 72 |
| 63 NSImage* imageForResourceID(int resource_id) { | 73 enum StrokeType { |
| 74 STROKE_NORMAL, |
| 75 STROKE_HEAVY, |
| 76 }; |
| 77 |
| 78 NSImage* imageForResourceID(int resource_id, StrokeType stroke_type) { |
| 64 if (!ui::MaterialDesignController::IsModeMaterial()) { | 79 if (!ui::MaterialDesignController::IsModeMaterial()) { |
| 65 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 80 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 66 return [rb.GetNativeImageNamed(resource_id).CopyNSImage() autorelease]; | 81 return [rb.GetNativeImageNamed(resource_id).CopyNSImage() autorelease]; |
| 67 } | 82 } |
| 68 | 83 |
| 69 CGFloat imageWidth = resource_id == IDR_TAB_ACTIVE_CENTER ? 1 : 18; | 84 CGFloat imageWidth = resource_id == IDR_TAB_ACTIVE_CENTER ? 1 : 18; |
| 70 SEL theSelector = 0; | 85 SEL theSelector = 0; |
| 71 switch (resource_id) { | 86 switch (resource_id) { |
| 72 case IDR_TAB_ACTIVE_LEFT: | 87 case IDR_TAB_ACTIVE_LEFT: |
| 73 theSelector = @selector(drawTabLeftEdgeImage); | 88 theSelector = @selector(drawTabLeftEdgeImage); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 84 case IDR_TAB_ALPHA_LEFT: | 99 case IDR_TAB_ALPHA_LEFT: |
| 85 theSelector = @selector(drawTabLeftMaskImage); | 100 theSelector = @selector(drawTabLeftMaskImage); |
| 86 break; | 101 break; |
| 87 | 102 |
| 88 case IDR_TAB_ALPHA_RIGHT: | 103 case IDR_TAB_ALPHA_RIGHT: |
| 89 theSelector = @selector(drawTabRightMaskImage); | 104 theSelector = @selector(drawTabRightMaskImage); |
| 90 break; | 105 break; |
| 91 } | 106 } |
| 92 DCHECK(theSelector); | 107 DCHECK(theSelector); |
| 93 | 108 |
| 109 Class makerClass = stroke_type == STROKE_HEAVY ? [TabHeavyImageMaker class] |
| 110 : [TabImageMaker class]; |
| 94 base::scoped_nsobject<NSCustomImageRep> imageRep([[NSCustomImageRep alloc] | 111 base::scoped_nsobject<NSCustomImageRep> imageRep([[NSCustomImageRep alloc] |
| 95 initWithDrawSelector:theSelector | 112 initWithDrawSelector:theSelector |
| 96 delegate:[TabView class]]); | 113 delegate:makerClass]); |
| 97 | 114 |
| 98 NSImage* newTabButtonImage = | 115 NSImage* newTabButtonImage = |
| 99 [[[NSImage alloc] initWithSize:NSMakeSize(imageWidth, 29)] autorelease]; | 116 [[[NSImage alloc] initWithSize:NSMakeSize(imageWidth, 29)] autorelease]; |
| 100 [newTabButtonImage setCacheMode:NSImageCacheAlways]; | 117 [newTabButtonImage setCacheMode:NSImageCacheAlways]; |
| 101 [newTabButtonImage addRepresentation:imageRep]; | 118 [newTabButtonImage addRepresentation:imageRep]; |
| 102 | 119 |
| 103 return newTabButtonImage; | 120 return newTabButtonImage; |
| 104 } | 121 } |
| 105 | 122 |
| 106 ui::ThreePartImage& GetMaskImage() { | 123 ui::ThreePartImage& GetMaskImage() { |
| 107 CR_DEFINE_STATIC_LOCAL(ui::ThreePartImage, mask, | 124 CR_DEFINE_STATIC_LOCAL( |
| 108 (imageForResourceID(IDR_TAB_ALPHA_LEFT), nullptr, | 125 ui::ThreePartImage, mask, |
| 109 imageForResourceID(IDR_TAB_ALPHA_RIGHT))); | 126 (imageForResourceID(IDR_TAB_ALPHA_LEFT, STROKE_NORMAL), nullptr, |
| 127 imageForResourceID(IDR_TAB_ALPHA_RIGHT, STROKE_NORMAL))); |
| 110 | 128 |
| 111 return mask; | 129 return mask; |
| 112 } | 130 } |
| 113 | 131 |
| 114 ui::ThreePartImage& GetStrokeImage(bool active) { | 132 ui::ThreePartImage& GetStrokeImage(bool active, StrokeType stroke_type) { |
| 115 if (!ui::MaterialDesignController::IsModeMaterial() && !active) { | 133 if (!ui::MaterialDesignController::IsModeMaterial() && !active) { |
| 116 CR_DEFINE_STATIC_LOCAL( | 134 CR_DEFINE_STATIC_LOCAL( |
| 117 ui::ThreePartImage, inactiveStroke, | 135 ui::ThreePartImage, inactiveStroke, |
| 118 (imageForResourceID(IDR_TAB_INACTIVE_LEFT), | 136 (imageForResourceID(IDR_TAB_INACTIVE_LEFT, STROKE_NORMAL), |
| 119 imageForResourceID(IDR_TAB_INACTIVE_CENTER), | 137 imageForResourceID(IDR_TAB_INACTIVE_CENTER, STROKE_NORMAL), |
| 120 imageForResourceID(IDR_TAB_INACTIVE_RIGHT))); | 138 imageForResourceID(IDR_TAB_INACTIVE_RIGHT, STROKE_NORMAL))); |
| 121 return inactiveStroke; | 139 return inactiveStroke; |
| 122 } | 140 } |
| 123 CR_DEFINE_STATIC_LOCAL( | 141 CR_DEFINE_STATIC_LOCAL( |
| 124 ui::ThreePartImage, stroke, | 142 ui::ThreePartImage, stroke, |
| 125 (imageForResourceID(IDR_TAB_ACTIVE_LEFT), | 143 (imageForResourceID(IDR_TAB_ACTIVE_LEFT, STROKE_NORMAL), |
| 126 imageForResourceID(IDR_TAB_ACTIVE_CENTER), | 144 imageForResourceID(IDR_TAB_ACTIVE_CENTER, STROKE_NORMAL), |
| 127 imageForResourceID(IDR_TAB_ACTIVE_RIGHT))); | 145 imageForResourceID(IDR_TAB_ACTIVE_RIGHT, STROKE_NORMAL))); |
| 146 CR_DEFINE_STATIC_LOCAL( |
| 147 ui::ThreePartImage, heavyStroke, |
| 148 (imageForResourceID(IDR_TAB_ACTIVE_LEFT, STROKE_HEAVY), |
| 149 imageForResourceID(IDR_TAB_ACTIVE_CENTER, STROKE_HEAVY), |
| 150 imageForResourceID(IDR_TAB_ACTIVE_RIGHT, STROKE_HEAVY))); |
| 128 | 151 |
| 129 return stroke; | 152 return stroke_type == STROKE_HEAVY ? heavyStroke : stroke; |
| 130 } | 153 } |
| 131 | 154 |
| 132 CGFloat LineWidthFromContext(CGContextRef context) { | 155 CGFloat LineWidthFromContext(CGContextRef context) { |
| 133 CGRect unitRect = CGRectMake(0.0, 0.0, 1.0, 1.0); | 156 CGRect unitRect = CGRectMake(0.0, 0.0, 1.0, 1.0); |
| 134 CGRect deviceRect = CGContextConvertRectToDeviceSpace(context, unitRect); | 157 CGRect deviceRect = CGContextConvertRectToDeviceSpace(context, unitRect); |
| 135 return 1.0 / deviceRect.size.height; | 158 return 1.0 / deviceRect.size.height; |
| 136 } | 159 } |
| 137 | 160 |
| 138 } // namespace | 161 } // namespace |
| 139 | 162 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 titleView_.reset([[NSTextField alloc] init]); | 194 titleView_.reset([[NSTextField alloc] init]); |
| 172 [titleView_ setAutoresizingMask:NSViewWidthSizable]; | 195 [titleView_ setAutoresizingMask:NSViewWidthSizable]; |
| 173 base::scoped_nsobject<GTMFadeTruncatingTextFieldCell> labelCell( | 196 base::scoped_nsobject<GTMFadeTruncatingTextFieldCell> labelCell( |
| 174 [[GTMFadeTruncatingTextFieldCell alloc] initTextCell:@"Label"]); | 197 [[GTMFadeTruncatingTextFieldCell alloc] initTextCell:@"Label"]); |
| 175 [labelCell setControlSize:NSSmallControlSize]; | 198 [labelCell setControlSize:NSSmallControlSize]; |
| 176 // Font size is 12, per Material Design spec. | 199 // Font size is 12, per Material Design spec. |
| 177 CGFloat fontSize = 12; | 200 CGFloat fontSize = 12; |
| 178 if (!ui::MaterialDesignController::IsModeMaterial()) { | 201 if (!ui::MaterialDesignController::IsModeMaterial()) { |
| 179 fontSize = [NSFont systemFontSizeForControlSize:NSSmallControlSize]; | 202 fontSize = [NSFont systemFontSizeForControlSize:NSSmallControlSize]; |
| 180 } | 203 } |
| 181 [labelCell setFont:[NSFont systemFontOfSize:fontSize]]; | |
| 182 [titleView_ setCell:labelCell]; | 204 [titleView_ setCell:labelCell]; |
| 183 titleViewCell_ = labelCell; | 205 titleViewCell_ = labelCell; |
| 184 | 206 |
| 185 [self setWantsLayer:YES]; // -drawFill: needs a layer. | 207 [self setWantsLayer:YES]; // -drawFill: needs a layer. |
| 208 |
| 209 if (&NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification) { |
| 210 NSNotificationCenter* center = |
| 211 [[NSWorkspace sharedWorkspace] notificationCenter]; |
| 212 [center |
| 213 addObserver:self |
| 214 selector:@selector(accessibilityOptionsDidChange:) |
| 215 name: |
| 216 NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification |
| 217 object:nil]; |
| 218 } |
| 186 } | 219 } |
| 187 return self; | 220 return self; |
| 188 } | 221 } |
| 189 | 222 |
| 190 - (void)dealloc { | 223 - (void)dealloc { |
| 191 // Cancel any delayed requests that may still be pending (drags or hover). | 224 // Cancel any delayed requests that may still be pending (drags or hover). |
| 192 [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 225 [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
| 226 if (&NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification) { |
| 227 NSNotificationCenter* center = |
| 228 [[NSWorkspace sharedWorkspace] notificationCenter]; |
| 229 [center removeObserver:self]; |
| 230 } |
| 193 [super dealloc]; | 231 [super dealloc]; |
| 194 } | 232 } |
| 195 | 233 |
| 196 // Called to obtain the context menu for when the user hits the right mouse | 234 // Called to obtain the context menu for when the user hits the right mouse |
| 197 // button (or control-clicks). (Note that -rightMouseDown: is *not* called for | 235 // button (or control-clicks). (Note that -rightMouseDown: is *not* called for |
| 198 // control-click.) | 236 // control-click.) |
| 199 - (NSMenu*)menu { | 237 - (NSMenu*)menu { |
| 200 if ([self isClosing]) | 238 if ([self isClosing]) |
| 201 return nil; | 239 return nil; |
| 202 | 240 |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 482 NSRect bounds = [self bounds]; | 520 NSRect bounds = [self bounds]; |
| 483 if (ui::MaterialDesignController::IsModeMaterial()) { | 521 if (ui::MaterialDesignController::IsModeMaterial()) { |
| 484 // In Material Design the tab strip separator is always 1 pixel high - | 522 // In Material Design the tab strip separator is always 1 pixel high - |
| 485 // add a clip rect to avoid drawing the tab edge over it. | 523 // add a clip rect to avoid drawing the tab edge over it. |
| 486 NSRect clipRect = bounds; | 524 NSRect clipRect = bounds; |
| 487 clipRect.origin.y += [self cr_lineWidth]; | 525 clipRect.origin.y += [self cr_lineWidth]; |
| 488 NSRectClip(clipRect); | 526 NSRectClip(clipRect); |
| 489 // In MD, the tab stroke is always opaque. | 527 // In MD, the tab stroke is always opaque. |
| 490 alpha = 1; | 528 alpha = 1; |
| 491 } | 529 } |
| 492 GetStrokeImage(state_ == NSOnState) | 530 const ui::ThemeProvider* provider = [[self window] themeProvider]; |
| 531 GetStrokeImage(state_ == NSOnState, |
| 532 provider && provider->ShouldIncreaseContrast() |
| 533 ? STROKE_HEAVY |
| 534 : STROKE_NORMAL) |
| 493 .DrawInRect(bounds, NSCompositeSourceOver, alpha); | 535 .DrawInRect(bounds, NSCompositeSourceOver, alpha); |
| 494 } | 536 } |
| 495 | 537 |
| 496 - (void)drawRect:(NSRect)dirtyRect { | 538 - (void)drawRect:(NSRect)dirtyRect { |
| 497 [self drawFill:dirtyRect]; | 539 [self drawFill:dirtyRect]; |
| 498 [self drawStroke:dirtyRect]; | 540 [self drawStroke:dirtyRect]; |
| 499 | 541 |
| 500 // We draw the title string directly instead of using a NSTextField subview. | 542 // We draw the title string directly instead of using a NSTextField subview. |
| 501 // This is so that we can get font smoothing to work on earlier OS, and even | 543 // This is so that we can get font smoothing to work on earlier OS, and even |
| 502 // when the tab background is a pattern image (when using themes). | 544 // when the tab background is a pattern image (when using themes). |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 if (titleHidden == [titleView_ isHidden]) | 633 if (titleHidden == [titleView_ isHidden]) |
| 592 return; | 634 return; |
| 593 [titleView_ setHidden:titleHidden]; | 635 [titleView_ setHidden:titleHidden]; |
| 594 [self setNeedsDisplayInRect:[titleView_ frame]]; | 636 [self setNeedsDisplayInRect:[titleView_ frame]]; |
| 595 } | 637 } |
| 596 | 638 |
| 597 - (SkColor)closeButtonColor { | 639 - (SkColor)closeButtonColor { |
| 598 return [[controller_ closeButton] iconColor]; | 640 return [[controller_ closeButton] iconColor]; |
| 599 } | 641 } |
| 600 | 642 |
| 643 - (void)accessibilityOptionsDidChange:(id)ignored { |
| 644 [self updateLabelFont]; |
| 645 [self setNeedsDisplay:YES]; |
| 646 } |
| 647 |
| 648 - (void)updateLabelFont { |
| 649 CGFloat fontSize = [titleViewCell_ font].pointSize; |
| 650 const ui::ThemeProvider* provider = [[self window] themeProvider]; |
| 651 if (provider && provider->ShouldIncreaseContrast() && state_ == NSOnState) { |
| 652 [titleViewCell_ setFont:[NSFont boldSystemFontOfSize:fontSize]]; |
| 653 } else { |
| 654 [titleViewCell_ setFont:[NSFont systemFontOfSize:fontSize]]; |
| 655 } |
| 656 } |
| 657 |
| 601 - (void)setState:(NSCellStateValue)state { | 658 - (void)setState:(NSCellStateValue)state { |
| 602 if (state_ == state) | 659 if (state_ == state) |
| 603 return; | 660 return; |
| 604 state_ = state; | 661 state_ = state; |
| 662 [self updateLabelFont]; |
| 605 [self setNeedsDisplay:YES]; | 663 [self setNeedsDisplay:YES]; |
| 606 } | 664 } |
| 607 | 665 |
| 608 - (void)setClosing:(BOOL)closing { | 666 - (void)setClosing:(BOOL)closing { |
| 609 closing_ = closing; // Safe because the property is nonatomic. | 667 closing_ = closing; // Safe because the property is nonatomic. |
| 610 // When closing, ensure clicks to the close button go nowhere. | 668 // When closing, ensure clicks to the close button go nowhere. |
| 611 if (closing) { | 669 if (closing) { |
| 612 [closeButton_ setTarget:nil]; | 670 [closeButton_ setTarget:nil]; |
| 613 [closeButton_ setAction:nil]; | 671 [closeButton_ setAction:nil]; |
| 614 } | 672 } |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 814 | 872 |
| 815 if (nextUpdate < kNoUpdate) | 873 if (nextUpdate < kNoUpdate) |
| 816 [self performSelector:_cmd withObject:nil afterDelay:nextUpdate]; | 874 [self performSelector:_cmd withObject:nil afterDelay:nextUpdate]; |
| 817 | 875 |
| 818 [self resetLastGlowUpdateTime]; | 876 [self resetLastGlowUpdateTime]; |
| 819 [self setNeedsDisplay:YES]; | 877 [self setNeedsDisplay:YES]; |
| 820 } | 878 } |
| 821 | 879 |
| 822 @end // @implementation TabView(Private) | 880 @end // @implementation TabView(Private) |
| 823 | 881 |
| 824 | 882 @implementation TabImageMaker |
| 825 @implementation TabView(MaterialDesign) | |
| 826 | 883 |
| 827 + (NSBezierPath*)tabLeftEdgeBezierPathForContext:(CGContextRef)context { | 884 + (NSBezierPath*)tabLeftEdgeBezierPathForContext:(CGContextRef)context { |
| 828 NSBezierPath* bezierPath = [NSBezierPath bezierPath]; | 885 NSBezierPath* bezierPath = [NSBezierPath bezierPath]; |
| 829 | 886 |
| 830 [bezierPath moveToPoint:NSMakePoint(-2, 0)]; | 887 [bezierPath moveToPoint:NSMakePoint(-2, 0)]; |
| 831 [bezierPath curveToPoint:NSMakePoint(2.5, 2) | 888 [bezierPath curveToPoint:NSMakePoint(2.5, 2) |
| 832 controlPoint1:NSMakePoint(1.805, -0.38) | 889 controlPoint1:NSMakePoint(1.805, -0.38) |
| 833 controlPoint2:NSMakePoint(2.17, 1.415)]; | 890 controlPoint2:NSMakePoint(2.17, 1.415)]; |
| 834 | 891 |
| 835 [bezierPath lineToPoint:NSMakePoint(14, 27)]; | 892 [bezierPath lineToPoint:NSMakePoint(14, 27)]; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 + (void)setTabEdgeStrokeColor { | 924 + (void)setTabEdgeStrokeColor { |
| 868 static NSColor* strokeColor = | 925 static NSColor* strokeColor = |
| 869 [skia::SkColorToSRGBNSColor(SkColorSetARGB(76, 0, 0, 0)) retain]; | 926 [skia::SkColorToSRGBNSColor(SkColorSetARGB(76, 0, 0, 0)) retain]; |
| 870 [strokeColor set]; | 927 [strokeColor set]; |
| 871 } | 928 } |
| 872 | 929 |
| 873 + (void)drawTabLeftEdgeImage { | 930 + (void)drawTabLeftEdgeImage { |
| 874 CGContextRef context = static_cast<CGContextRef>( | 931 CGContextRef context = static_cast<CGContextRef>( |
| 875 [[NSGraphicsContext currentContext] graphicsPort]); | 932 [[NSGraphicsContext currentContext] graphicsPort]); |
| 876 | 933 |
| 877 [TabView setTabEdgeStrokeColor]; | 934 [self setTabEdgeStrokeColor]; |
| 878 [[self tabLeftEdgeBezierPathForContext:context] stroke]; | 935 [[self tabLeftEdgeBezierPathForContext:context] stroke]; |
| 879 } | 936 } |
| 880 | 937 |
| 881 + (void)drawTabMiddleEdgeImage { | 938 + (void)drawTabMiddleEdgeImage { |
| 882 NSBezierPath* middleEdgePath = [NSBezierPath bezierPath]; | 939 NSBezierPath* middleEdgePath = [NSBezierPath bezierPath]; |
| 883 [middleEdgePath moveToPoint:NSMakePoint(0, 29)]; | 940 [middleEdgePath moveToPoint:NSMakePoint(0, 29)]; |
| 884 [middleEdgePath lineToPoint:NSMakePoint(1, 29)]; | 941 [middleEdgePath lineToPoint:NSMakePoint(1, 29)]; |
| 885 [middleEdgePath setLineCapStyle:NSSquareLineCapStyle]; | 942 [middleEdgePath setLineCapStyle:NSSquareLineCapStyle]; |
| 886 | 943 |
| 887 CGContextRef context = static_cast<CGContextRef>( | 944 CGContextRef context = static_cast<CGContextRef>( |
| 888 [[NSGraphicsContext currentContext] graphicsPort]); | 945 [[NSGraphicsContext currentContext] graphicsPort]); |
| 889 CGFloat lineWidth = LineWidthFromContext(context); | 946 CGFloat lineWidth = LineWidthFromContext(context); |
| 890 | 947 |
| 891 // Line width is always 1px. | 948 // Line width is always 1px. |
| 892 [middleEdgePath setLineWidth:lineWidth]; | 949 [middleEdgePath setLineWidth:lineWidth]; |
| 893 | 950 |
| 894 // Align to device pixels. | 951 // Align to device pixels. |
| 895 NSAffineTransform* translationTransform = [NSAffineTransform transform]; | 952 NSAffineTransform* translationTransform = [NSAffineTransform transform]; |
| 896 [translationTransform translateXBy:0 yBy:-1 + lineWidth / 2.]; | 953 [translationTransform translateXBy:0 yBy:-1 + lineWidth / 2.]; |
| 897 [middleEdgePath transformUsingAffineTransform:translationTransform]; | 954 [middleEdgePath transformUsingAffineTransform:translationTransform]; |
| 898 | 955 |
| 899 [TabView setTabEdgeStrokeColor]; | 956 [self setTabEdgeStrokeColor]; |
| 900 [middleEdgePath stroke]; | 957 [middleEdgePath stroke]; |
| 901 } | 958 } |
| 902 | 959 |
| 903 + (void)drawTabRightEdgeImage { | 960 + (void)drawTabRightEdgeImage { |
| 904 CGContextRef context = static_cast<CGContextRef>( | 961 CGContextRef context = static_cast<CGContextRef>( |
| 905 [[NSGraphicsContext currentContext] graphicsPort]); | 962 [[NSGraphicsContext currentContext] graphicsPort]); |
| 906 | 963 |
| 907 NSBezierPath* leftEdgePath = [self tabLeftEdgeBezierPathForContext:context]; | 964 NSBezierPath* leftEdgePath = [self tabLeftEdgeBezierPathForContext:context]; |
| 908 | 965 |
| 909 // Draw the right edge path by flipping the left edge path vertically. | 966 // Draw the right edge path by flipping the left edge path vertically. |
| 910 NSAffineTransform* transform = [NSAffineTransform transform]; | 967 NSAffineTransform* transform = [NSAffineTransform transform]; |
| 911 [transform scaleXBy:-1 yBy:1]; | 968 [transform scaleXBy:-1 yBy:1]; |
| 912 [transform translateXBy:-18 yBy:0]; | 969 [transform translateXBy:-18 yBy:0]; |
| 913 [leftEdgePath transformUsingAffineTransform:transform]; | 970 [leftEdgePath transformUsingAffineTransform:transform]; |
| 914 | 971 |
| 915 [TabView setTabEdgeStrokeColor]; | 972 [self setTabEdgeStrokeColor]; |
| 916 [leftEdgePath stroke]; | 973 [leftEdgePath stroke]; |
| 917 } | 974 } |
| 918 | 975 |
| 919 + (NSBezierPath*)tabLeftMaskBezierPath { | 976 + (NSBezierPath*)tabLeftMaskBezierPath { |
| 920 NSBezierPath* bezierPath = [self tabLeftEdgeBezierPathForContext:nullptr]; | 977 NSBezierPath* bezierPath = [self tabLeftEdgeBezierPathForContext:nullptr]; |
| 921 | 978 |
| 922 // Box in the open edges. | 979 // Box in the open edges. |
| 923 [bezierPath lineToPoint:NSMakePoint(18, 0)]; | 980 [bezierPath lineToPoint:NSMakePoint(18, 0)]; |
| 924 [bezierPath lineToPoint:NSMakePoint(0, 0)]; | 981 [bezierPath lineToPoint:NSMakePoint(0, 0)]; |
| 925 | 982 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 944 NSBezierPath* bezierPath = [self tabLeftMaskBezierPath]; | 1001 NSBezierPath* bezierPath = [self tabLeftMaskBezierPath]; |
| 945 NSAffineTransform* transform = [NSAffineTransform transform]; | 1002 NSAffineTransform* transform = [NSAffineTransform transform]; |
| 946 [transform scaleXBy:-1 yBy:1]; | 1003 [transform scaleXBy:-1 yBy:1]; |
| 947 [transform translateXBy:-17.5 yBy:-0.25]; | 1004 [transform translateXBy:-17.5 yBy:-0.25]; |
| 948 [bezierPath transformUsingAffineTransform:transform]; | 1005 [bezierPath transformUsingAffineTransform:transform]; |
| 949 | 1006 |
| 950 [[NSColor whiteColor] set]; | 1007 [[NSColor whiteColor] set]; |
| 951 [bezierPath fill]; | 1008 [bezierPath fill]; |
| 952 } | 1009 } |
| 953 | 1010 |
| 954 @end // @implementation TabView(MaterialDesign) | 1011 @end |
| 1012 |
| 1013 @implementation TabHeavyImageMaker |
| 1014 |
| 1015 // For "Increase Contrast" mode, use flat black instead of semitransparent black |
| 1016 // for the tab edge stroke. |
| 1017 + (void)setTabEdgeStrokeColor { |
| 1018 static NSColor* heavyStrokeColor = |
| 1019 [skia::SkColorToSRGBNSColor(SK_ColorBLACK) retain]; |
| 1020 [heavyStrokeColor set]; |
| 1021 } |
| 1022 |
| 1023 @end |
| OLD | NEW |