Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(846)

Side by Side Diff: chrome/browser/ui/cocoa/website_settings/split_block_button.mm

Issue 2741933003: Move Cocoa Page Info UI code to its own folder. (Closed)
Patch Set: Fixin' more unit tests BUILD paths (does mass_rename.py just not pick those up? => crbug.com/701529) Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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/website_settings/split_block_button.h"
6
7 #include <cmath>
8
9 #include "base/logging.h"
10 #include "base/mac/scoped_nsobject.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "skia/ext/skia_utils_mac.h"
13 #import "ui/base/cocoa/menu_controller.h"
14 #include "ui/base/l10n/l10n_util_mac.h"
15 #include "ui/base/models/simple_menu_model.h"
16
17 namespace {
18
19 enum MouseLocation {
20 kInsideLeftCell,
21 kInsideRightCell,
22 kNotInside,
23 };
24
25 enum CornerType {
26 kRounded,
27 kAngled,
28 };
29
30 NSBezierPath* PathWithCornerStyles(NSRect frame,
31 CornerType leftCornerStyle,
32 CornerType rightCornerStyle) {
33 base::scoped_nsobject<NSBezierPath> path([[NSBezierPath bezierPath] retain]);
34 const CGFloat x0 = NSMinX(frame);
35 const CGFloat x1 = NSMaxX(frame);
36 const CGFloat y0 = NSMinY(frame);
37 const CGFloat y1 = NSMaxY(frame);
38 const CGFloat radius = 2;
39
40 // Start at the center bottom. Draw left and up, including both left corners.
41 [path moveToPoint:NSMakePoint(std::floor((x1 - x0) * .5), y0)];
42 if (leftCornerStyle == kAngled) {
43 [path lineToPoint:NSMakePoint(x0, y0)];
44 [path lineToPoint:NSMakePoint(x0, y1)];
45 } else {
46 [path appendBezierPathWithArcFromPoint:NSMakePoint(x0, y0)
47 toPoint:NSMakePoint(x0, y0 + radius)
48 radius:radius];
49 [path appendBezierPathWithArcFromPoint:NSMakePoint(x0, y1)
50 toPoint:NSMakePoint(x0 + radius, y1)
51 radius:radius];
52 }
53 // Draw through the upper right-hand and lower-right-hand corners.
54 if (rightCornerStyle == kAngled) {
55 [path lineToPoint:NSMakePoint(x1, y1)];
56 [path lineToPoint:NSMakePoint(x1, y0)];
57 } else {
58 [path appendBezierPathWithArcFromPoint:NSMakePoint(x1, y1)
59 toPoint:NSMakePoint(x1, y1 - radius)
60 radius:radius];
61 [path appendBezierPathWithArcFromPoint:NSMakePoint(x1, y0)
62 toPoint:NSMakePoint(x1 - radius, y0)
63 radius:radius];
64 }
65 return path.autorelease();
66 }
67
68 void DrawBezel(id<ConstrainedWindowButtonDrawableCell>cell,
69 CornerType leftCorners,
70 CornerType rightCorners,
71 NSRect frame,
72 NSView* view) {
73 if ([cell isMouseInside]) {
74 base::scoped_nsobject<NSBezierPath> path(
75 [PathWithCornerStyles(frame, leftCorners, rightCorners) retain]);
76 [ConstrainedWindowButton DrawBackgroundAndShadowForPath:path
77 withCell:cell
78 inView:view];
79 [ConstrainedWindowButton DrawInnerHighlightForPath:path
80 withCell:cell
81 inView:view];
82 }
83 }
84
85 } // namespace
86
87 // A button cell used by SplitBlockButton, containing the title.
88 @interface SplitButtonTitleCell : ConstrainedWindowButtonCell
89 - (NSRect)rect;
90 @end
91
92 // A button cell used by SplitBlockButton, containing the popup menu.
93 @interface SplitButtonPopUpCell :
94 NSPopUpButtonCell<ConstrainedWindowButtonDrawableCell> {
95 @private
96 BOOL isMouseInside_;
97 base::scoped_nsobject<MenuController> menuController_;
98 std::unique_ptr<ui::SimpleMenuModel> menuModel_;
99 }
100
101 // Designated initializer.
102 - (id)initWithMenuDelegate:(ui::SimpleMenuModel::Delegate*)menuDelegate;
103
104 - (NSRect)rect;
105
106 @end
107
108 @implementation SplitBlockButton
109
110 - (id)initWithMenuDelegate:(ui::SimpleMenuModel::Delegate*)menuDelegate {
111 if (self = [super initWithFrame:NSZeroRect]) {
112 leftCell_.reset([[SplitButtonTitleCell alloc] init]);
113 rightCell_.reset([[SplitButtonPopUpCell alloc]
114 initWithMenuDelegate:menuDelegate]);
115 [leftCell_ setTitle:l10n_util::GetNSString(IDS_PERMISSION_DENY)];
116 [leftCell_ setEnabled:YES];
117 [rightCell_ setEnabled:YES];
118 }
119 return self;
120 }
121
122 + (Class)cellClass {
123 return nil;
124 }
125
126 - (NSString*)title {
127 return [leftCell_ title];
128 }
129
130 - (void)setAction:(SEL)action {
131 [leftCell_ setAction:action];
132 }
133
134 - (void)setTarget:(id)target {
135 [leftCell_ setTarget:target];
136 }
137
138 - (void)drawRect:(NSRect)rect {
139 // Copy the base class: inset to leave room for the shadow.
140 --rect.size.height;
141
142 // This function assumes that |rect| is always the same as [self frame].
143 // If that changes, the drawing functions will need to be adjusted.
144 const CGFloat radius = 2;
145 NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:rect
146 xRadius:radius
147 yRadius:radius];
148 [ConstrainedWindowButton DrawBackgroundAndShadowForPath:path
149 withCell:nil
150 inView:self];
151
152 // Use intersection rects for the cell drawing, to ensure the height
153 // adjustment is honored.
154 [leftCell_ setControlView:self];
155 [leftCell_ drawWithFrame:NSIntersectionRect(rect, [self leftCellRect])
156 inView:self];
157
158 [rightCell_ setControlView:self];
159 [rightCell_ drawWithFrame:NSIntersectionRect(rect, [self rightCellRect])
160 inView:self];
161
162 // Draw the border.
163 path = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(rect, 0.5, 0.5)
164 xRadius:radius
165 yRadius:radius];
166 [ConstrainedWindowButton DrawBorderForPath:path
167 withCell:nil
168 inView:self];
169 }
170
171 - (void)updateTrackingAreas {
172 [self updateTrackingArea:&leftTrackingArea_
173 forCell:leftCell_
174 withRect:[self leftCellRect]];
175
176 [self updateTrackingArea:&rightTrackingArea_
177 forCell:rightCell_
178 withRect:[self rightCellRect]];
179 }
180
181 - (void)updateTrackingArea:(ui::ScopedCrTrackingArea*)trackingArea
182 forCell:(id<ConstrainedWindowButtonDrawableCell>)cell
183 withRect:(NSRect)rect {
184 DCHECK(trackingArea);
185 NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
186 NSTrackingActiveInActiveApp;
187 [self removeTrackingArea:trackingArea->get()];
188 trackingArea->reset([[CrTrackingArea alloc] initWithRect:rect
189 options:options
190 owner:self
191 userInfo:nil]);
192 [self addTrackingArea:trackingArea->get()];
193 }
194
195 - (void)mouseEntered:(NSEvent*)theEvent {
196 [self mouseMoved:theEvent];
197 }
198
199 - (void)mouseExited:(NSEvent*)theEvent {
200 [self mouseMoved:theEvent];
201 }
202
203 - (void)mouseMoved:(NSEvent*)theEvent {
204 MouseLocation location = [self mouseLocationForEvent:theEvent];
205 [rightCell_ setIsMouseInside:NO];
206 [leftCell_ setIsMouseInside:NO];
207 if (location == kInsideLeftCell)
208 [leftCell_ setIsMouseInside:YES];
209 else if (location == kInsideRightCell)
210 [rightCell_ setIsMouseInside:YES];
211 [self setNeedsDisplay:YES];
212 }
213
214 - (void)mouseDown:(NSEvent*)theEvent {
215 MouseLocation downLocation = [self mouseLocationForEvent:theEvent];
216 NSCell* focusCell = nil;
217 NSRect rect;
218 if (downLocation == kInsideLeftCell) {
219 focusCell = leftCell_.get();
220 rect = [self leftCellRect];
221 } else if (downLocation == kInsideRightCell) {
222 focusCell = rightCell_.get();
223 rect = [self rightCellRect];
224 }
225
226 do {
227 MouseLocation location = [self mouseLocationForEvent:theEvent];
228 if (location != kNotInside) {
229 [focusCell setHighlighted:YES];
230 [self setNeedsDisplay:YES];
231
232 if ([focusCell trackMouse:theEvent
233 inRect:rect
234 ofView:self
235 untilMouseUp:NO]) {
236 [focusCell setState:![focusCell state]];
237 [self setNeedsDisplay:YES];
238 break;
239 } else {
240 // The above -trackMouse call returned NO, so we know that
241 // the mouse left the cell before a mouse up event occurred.
242 [focusCell setHighlighted:NO];
243 [self setNeedsDisplay:YES];
244 }
245 }
246 const NSUInteger mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
247 theEvent = [[self window] nextEventMatchingMask:mask];
248 } while ([theEvent type] != NSLeftMouseUp);
249 }
250
251 - (MouseLocation)mouseLocationForEvent:(NSEvent*)theEvent {
252 MouseLocation location = kNotInside;
253 NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow]
254 fromView:nil];
255 if ([self mouse:mousePoint inRect:[leftCell_ rect]])
256 location = kInsideLeftCell;
257 else if ([self mouse:mousePoint inRect:[self rightCellRect]])
258 location = kInsideRightCell;
259 return location;
260 }
261
262 - (void)sizeToFit {
263 NSSize leftSize = [leftCell_ cellSize];
264 NSSize rightSize = [rightCell_ cellSize];
265 NSSize size = NSMakeSize(
266 std::ceil(std::max(leftSize.width + rightSize.width,
267 constrained_window_button::kButtonMinWidth)),
268 std::ceil(std::max(leftSize.height, rightSize.height)));
269 [self setFrameSize:size];
270 }
271
272 - (NSRect)leftCellRect {
273 return [leftCell_ rect];
274 }
275
276 - (NSRect)rightCellRect {
277 NSRect leftFrame, rightFrame;
278 NSDivideRect([self bounds], &leftFrame, &rightFrame,
279 NSWidth([self leftCellRect]), NSMinXEdge);
280 return rightFrame;
281 }
282
283 // Accessor for Testing.
284 - (NSMenu*)menu {
285 return [rightCell_ menu];
286 }
287
288 @end
289
290 @implementation SplitButtonTitleCell
291
292 - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView {
293 DrawBezel(self, kRounded, kAngled, frame, controlView);
294 }
295
296 - (NSRect)rect {
297 NSSize size = [self cellSize];
298 return NSMakeRect(0, 0, std::ceil(size.width), std::ceil(size.height));
299 }
300
301 @end
302
303 @implementation SplitButtonPopUpCell
304
305 @synthesize isMouseInside = isMouseInside_;
306
307 - (id)initWithMenuDelegate:(ui::SimpleMenuModel::Delegate*)menuDelegate {
308 if (self = [super initTextCell:@"" pullsDown:YES]) {
309 [self setControlSize:NSSmallControlSize];
310 [self setArrowPosition:NSPopUpArrowAtCenter];
311 [self setBordered:NO];
312 [self setBackgroundColor:[NSColor clearColor]];
313 menuModel_.reset(new ui::SimpleMenuModel(menuDelegate));
314 menuModel_->AddItemWithStringId(0, IDS_PERMISSION_CUSTOMIZE);
315 menuController_.reset(
316 [[MenuController alloc] initWithModel:menuModel_.get()
317 useWithPopUpButtonCell:NO]);
318 [self setMenu:[menuController_ menu]];
319 [self setUsesItemFromMenu:NO];
320 }
321 return self;
322 }
323
324 - (void)drawBorderAndBackgroundWithFrame:(NSRect)frame
325 inView:(NSView*)controlView {
326 // The arrow, which is what should be drawn by the base class, is drawn
327 // during -drawBezelWithFrame. The only way to draw our own border with
328 // the default arrow is to make the cell unbordered, and draw the border
329 // from -drawBorderAndBackgroundWithFrame, rather than simply overriding
330 // -drawBezelWithFrame.
331 DrawBezel(self, kAngled, kRounded, frame, controlView);
332 [super drawBorderAndBackgroundWithFrame:NSOffsetRect(frame, -4, 0)
333 inView:controlView];
334 }
335
336 - (NSRect)rect {
337 NSSize size = [self cellSize];
338 return NSMakeRect(0, 0, std::ceil(size.width), std::ceil(size.height));
339 }
340
341 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698