1// Copyright 2013 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 "ui/app_list/cocoa/app_list_pager_view.h" 6 7#include "base/mac/mac_util.h" 8#include "skia/ext/skia_utils_mac.h" 9#include "ui/app_list/app_list_constants.h" 10#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 11 12namespace { 13 14const CGFloat kButtonHeight = 6; 15const CGFloat kButtonCornerRadius = 2; 16const CGFloat kButtonStripPadding = 20; 17 18} // namespace 19 20@interface AppListPagerView () 21 22@property(assign, nonatomic) NSInteger hoveredSegment; 23 24- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow; 25 26@end 27 28@interface AppListPagerCell : NSSegmentedCell; 29@end 30 31@implementation AppListPagerView 32 33@synthesize hoveredSegment = hoveredSegment_; 34 35+ (Class)cellClass { 36 return [AppListPagerCell class]; 37} 38 39- (id)init { 40 if ((self = [super initWithFrame:NSZeroRect])) { 41 trackingArea_.reset( 42 [[CrTrackingArea alloc] initWithRect:NSZeroRect 43 options:NSTrackingInVisibleRect | 44 NSTrackingMouseEnteredAndExited | 45 NSTrackingMouseMoved | 46 NSTrackingActiveInKeyWindow 47 owner:self 48 userInfo:nil]); 49 [self addTrackingArea:trackingArea_.get()]; 50 hoveredSegment_ = -1; 51 } 52 return self; 53} 54 55- (NSInteger)findAndHighlightSegmentAtLocation:(NSPoint)locationInWindow { 56 NSInteger segment = [self segmentUnderLocation:locationInWindow]; 57 [self setHoveredSegment:segment]; 58 return segment; 59} 60 61- (void)setHoveredSegment:(NSInteger)segment { 62 if (segment == hoveredSegment_) 63 return; 64 65 hoveredSegment_ = segment; 66 [self setNeedsDisplay:YES]; 67 return; 68} 69 70- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow { 71 if ([self segmentCount] == 0) 72 return -1; 73 74 NSPoint pointInView = [self convertPoint:locationInWindow 75 fromView:nil]; 76 if (![self mouse:pointInView inRect:[self bounds]]) 77 return -1; 78 79 CGFloat segmentWidth = [self bounds].size.width / [self segmentCount]; 80 return pointInView.x / segmentWidth; 81} 82 83- (BOOL)isHoveredForSegment:(NSInteger)segment { 84 return segment == hoveredSegment_; 85} 86 87- (void)mouseExited:(NSEvent*)theEvent { 88 [self setHoveredSegment:-1]; 89} 90 91- (void)mouseMoved:(NSEvent*)theEvent { 92 [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]]; 93} 94 95- (void)mouseDown:(NSEvent*)theEvent { 96 // Temporarily clear the highlight to give feedback. 97 [self setHoveredSegment:-1]; 98} 99 100// The stock NSSegmentedControl ignores any clicks outside the non-default 101// control height, so process all clicks here. 102- (void)mouseUp:(NSEvent*)theEvent { 103 [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]]; 104 if (hoveredSegment_ < 0) 105 return; 106 107 [self setSelectedSegment:hoveredSegment_]; 108 [[self target] performSelector:[self action] 109 withObject:self]; 110} 111 112@end 113 114@implementation AppListPagerCell 115 116- (void)drawWithFrame:(NSRect)cellFrame 117 inView:(NSView*)controlView { 118 // Draw nothing if there are less than two segments. 119 if ([self segmentCount] < 2) 120 return; 121 122 cellFrame.size.width /= [self segmentCount]; 123 for (NSInteger i = 0; i < [self segmentCount]; ++i) { 124 [self drawSegment:i 125 inFrame:cellFrame 126 withView:controlView]; 127 cellFrame.origin.x += cellFrame.size.width; 128 } 129} 130 131- (void)drawSegment:(NSInteger)segment 132 inFrame:(NSRect)frame 133 withView:(NSView*)controlView { 134 gfx::ScopedNSGraphicsContextSaveGState context; 135 NSRect clipRect = NSMakeRect( 136 frame.origin.x + kButtonStripPadding / 2, 137 floor(frame.origin.y + (frame.size.height - kButtonHeight) / 2), 138 frame.size.width - kButtonStripPadding, 139 kButtonHeight); 140 [[NSBezierPath bezierPathWithRoundedRect:clipRect 141 xRadius:kButtonCornerRadius 142 yRadius:kButtonCornerRadius] addClip]; 143 144 AppListPagerView* pagerControl = 145 base::mac::ObjCCastStrict<AppListPagerView>(controlView); 146 SkColor backgroundColor = [pagerControl hoveredSegment] == segment ? 147 app_list::kPagerHoverColor : 148 app_list::kPagerNormalColor; 149 150 [gfx::SkColorToSRGBNSColor(backgroundColor) set]; 151 NSRectFill(frame); 152 153 if (![[self target] conformsToProtocol:@protocol(AppListPagerDelegate)]) 154 return; 155 156 CGFloat selectedRatio = [[self target] visiblePortionOfPage:segment]; 157 if (selectedRatio == 0.0) 158 return; 159 160 [gfx::SkColorToSRGBNSColor(app_list::kPagerSelectedColor) set]; 161 if (selectedRatio < 0) 162 frame.origin.x += frame.size.width + frame.size.width * selectedRatio; 163 frame.size.width *= fabs(selectedRatio); 164 NSRectFill(frame); 165} 166 167@end 168