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

Side by Side Diff: ui/app_list/cocoa/apps_search_box_controller.mm

Issue 2131463002: Purge the App Launcher code from Mac (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Zap mac-specific icon assets Created 4 years, 5 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 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/apps_search_box_controller.h"
6
7 #include "base/mac/foundation_util.h"
8 #include "base/mac/mac_util.h"
9 #include "base/macros.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "ui/app_list/app_list_menu.h"
12 #include "ui/app_list/app_list_model.h"
13 #include "ui/app_list/resources/grit/app_list_resources.h"
14 #include "ui/app_list/search_box_model.h"
15 #include "ui/app_list/search_box_model_observer.h"
16 #include "ui/base/cocoa/cocoa_base_utils.h"
17 #import "ui/base/cocoa/controls/hover_image_menu_button.h"
18 #import "ui/base/cocoa/controls/hover_image_menu_button_cell.h"
19 #import "ui/base/cocoa/menu_controller.h"
20 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/gfx/image/image_skia_util_mac.h"
22
23 namespace {
24
25 // Padding either side of the search icon and menu button.
26 const CGFloat kPadding = 14;
27
28 // Size of the search icon.
29 const CGFloat kSearchIconDimension = 32;
30
31 // Size of the menu button on the right.
32 const CGFloat kMenuButtonDimension = 29;
33
34 // Menu offset relative to the bottom-right corner of the menu button.
35 const CGFloat kMenuYOffsetFromButton = -4;
36 const CGFloat kMenuXOffsetFromButton = -7;
37
38 }
39
40 @interface AppsSearchBoxController ()
41
42 - (NSImageView*)searchImageView;
43 - (void)addSubviews;
44
45 @end
46
47 namespace app_list {
48
49 class SearchBoxModelObserverBridge : public SearchBoxModelObserver {
50 public:
51 SearchBoxModelObserverBridge(AppsSearchBoxController* parent);
52 ~SearchBoxModelObserverBridge() override;
53
54 void SetSearchText(const base::string16& text);
55
56 void IconChanged() override;
57 void SpeechRecognitionButtonPropChanged() override;
58 void HintTextChanged() override;
59 void SelectionModelChanged() override;
60 void TextChanged() override;
61
62 private:
63 SearchBoxModel* GetModel();
64
65 AppsSearchBoxController* parent_; // Weak. Owns us.
66
67 DISALLOW_COPY_AND_ASSIGN(SearchBoxModelObserverBridge);
68 };
69
70 SearchBoxModelObserverBridge::SearchBoxModelObserverBridge(
71 AppsSearchBoxController* parent)
72 : parent_(parent) {
73 IconChanged();
74 HintTextChanged();
75 GetModel()->AddObserver(this);
76 }
77
78 SearchBoxModelObserverBridge::~SearchBoxModelObserverBridge() {
79 GetModel()->RemoveObserver(this);
80 }
81
82 SearchBoxModel* SearchBoxModelObserverBridge::GetModel() {
83 SearchBoxModel* searchBoxModel = [[parent_ delegate] searchBoxModel];
84 DCHECK(searchBoxModel);
85 return searchBoxModel;
86 }
87
88 void SearchBoxModelObserverBridge::SetSearchText(const base::string16& text) {
89 SearchBoxModel* model = GetModel();
90 model->RemoveObserver(this);
91 model->SetText(text);
92 // TODO(tapted): See if this should call SetSelectionModel here.
93 model->AddObserver(this);
94 }
95
96 void SearchBoxModelObserverBridge::IconChanged() {
97 [[parent_ searchImageView] setImage:gfx::NSImageFromImageSkiaWithColorSpace(
98 GetModel()->icon(), base::mac::GetSRGBColorSpace())];
99 }
100
101 void SearchBoxModelObserverBridge::SpeechRecognitionButtonPropChanged() {
102 // TODO(mukai): implement.
103 NOTIMPLEMENTED();
104 }
105
106 void SearchBoxModelObserverBridge::HintTextChanged() {
107 [[[parent_ searchTextField] cell] setPlaceholderString:
108 base::SysUTF16ToNSString(GetModel()->hint_text())];
109 }
110
111 void SearchBoxModelObserverBridge::SelectionModelChanged() {
112 // TODO(tapted): See if anything needs to be done here for RTL.
113 }
114
115 void SearchBoxModelObserverBridge::TextChanged() {
116 // Currently the model text is only changed when we are not observing it, or
117 // it is changed in tests to establish a particular state.
118 [[parent_ searchTextField]
119 setStringValue:base::SysUTF16ToNSString(GetModel()->text())];
120 [[parent_ delegate] modelTextDidChange];
121 }
122
123 } // namespace app_list
124
125 @interface SearchTextField : NSTextField {
126 @private
127 NSRect textFrameInset_;
128 }
129
130 @property(readonly, nonatomic) NSRect textFrameInset;
131
132 - (void)setMarginsWithLeftMargin:(CGFloat)leftMargin
133 rightMargin:(CGFloat)rightMargin;
134
135 @end
136
137 @interface AppListMenuController : MenuController {
138 @private
139 AppsSearchBoxController* searchBoxController_; // Weak. Owns us.
140 }
141
142 - (id)initWithSearchBoxController:(AppsSearchBoxController*)parent;
143
144 @end
145
146 @implementation AppsSearchBoxController
147
148 @synthesize delegate = delegate_;
149
150 - (id)initWithFrame:(NSRect)frame {
151 if ((self = [super init])) {
152 base::scoped_nsobject<NSView> containerView(
153 [[NSView alloc] initWithFrame:frame]);
154 [self setView:containerView];
155 [self addSubviews];
156 }
157 return self;
158 }
159
160 - (void)clearSearch {
161 [searchTextField_ setStringValue:@""];
162 // -controlTextDidChange:'s parameter is marked nonnull in the 10.11 SDK,
163 // so pass a dummy object even though we know that this class's implementation
164 // never looks at the parameter.
165 [self controlTextDidChange:[NSNotification notificationWithName:@""
166 object:self]];
167 }
168
169 - (void)rebuildMenu {
170 if (![delegate_ appListDelegate])
171 return;
172
173 menuController_.reset();
174 appListMenu_.reset(
175 new app_list::AppListMenu([delegate_ appListDelegate]));
176 menuController_.reset([[AppListMenuController alloc]
177 initWithSearchBoxController:self]);
178 [menuButton_ setMenu:[menuController_ menu]]; // Menu will populate here.
179 }
180
181 - (void)setDelegate:(id<AppsSearchBoxDelegate>)delegate {
182 [[menuButton_ menu] removeAllItems];
183 menuController_.reset();
184 appListMenu_.reset();
185 bridge_.reset(); // Ensure observers are cleared before updating |delegate_|.
186 delegate_ = delegate;
187 if (!delegate_)
188 return;
189
190 bridge_.reset(new app_list::SearchBoxModelObserverBridge(self));
191 [self rebuildMenu];
192 }
193
194 - (NSTextField*)searchTextField {
195 return searchTextField_;
196 }
197
198 - (NSPopUpButton*)menuControl {
199 return menuButton_;
200 }
201
202 - (app_list::AppListMenu*)appListMenu {
203 return appListMenu_.get();
204 }
205
206 - (NSImageView*)searchImageView {
207 return searchImageView_;
208 }
209
210 - (void)addSubviews {
211 NSRect viewBounds = [[self view] bounds];
212 searchImageView_.reset([[NSImageView alloc] initWithFrame:NSMakeRect(
213 kPadding, 0, kSearchIconDimension, NSHeight(viewBounds))]);
214
215 searchTextField_.reset([[SearchTextField alloc] initWithFrame:viewBounds]);
216 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
217 [searchTextField_ setDelegate:self];
218 [searchTextField_ setFont:rb.GetFont(
219 ui::ResourceBundle::MediumFont).GetNativeFont()];
220 [searchTextField_
221 setMarginsWithLeftMargin:NSMaxX([searchImageView_ frame]) + kPadding
222 rightMargin:kMenuButtonDimension + 2 * kPadding];
223
224 // Add the drop-down menu, with a custom button.
225 NSRect buttonFrame = NSMakeRect(
226 NSWidth(viewBounds) - kMenuButtonDimension - kPadding,
227 floor(NSMidY(viewBounds) - kMenuButtonDimension / 2),
228 kMenuButtonDimension,
229 kMenuButtonDimension);
230 menuButton_.reset([[HoverImageMenuButton alloc] initWithFrame:buttonFrame
231 pullsDown:YES]);
232 [[menuButton_ hoverImageMenuButtonCell] setDefaultImage:
233 rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_NORMAL).AsNSImage()];
234 [[menuButton_ hoverImageMenuButtonCell] setAlternateImage:
235 rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_PRESSED).AsNSImage()];
236 [[menuButton_ hoverImageMenuButtonCell] setHoverImage:
237 rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_HOVER).AsNSImage()];
238
239 [[self view] addSubview:searchImageView_];
240 [[self view] addSubview:searchTextField_];
241 [[self view] addSubview:menuButton_];
242 }
243
244 - (BOOL)control:(NSControl*)control
245 textView:(NSTextView*)textView
246 doCommandBySelector:(SEL)command {
247 // Forward the message first, to handle grid or search results navigation.
248 BOOL handled = [delegate_ control:control
249 textView:textView
250 doCommandBySelector:command];
251 if (handled)
252 return YES;
253
254 // If the delegate did not handle the escape key, it means the window was not
255 // dismissed because there were search results. Clear them.
256 if (command == @selector(complete:)) {
257 [self clearSearch];
258 return YES;
259 }
260
261 return NO;
262 }
263
264 - (void)controlTextDidChange:(NSNotification*)notification {
265 if (bridge_) {
266 bridge_->SetSearchText(
267 base::SysNSStringToUTF16([searchTextField_ stringValue]));
268 }
269
270 [delegate_ modelTextDidChange];
271 }
272
273 @end
274
275 @interface SearchTextFieldCell : NSTextFieldCell;
276
277 - (NSRect)textFrameForFrameInternal:(NSRect)cellFrame;
278
279 @end
280
281 @implementation SearchTextField
282
283 @synthesize textFrameInset = textFrameInset_;
284
285 + (Class)cellClass {
286 return [SearchTextFieldCell class];
287 }
288
289 - (id)initWithFrame:(NSRect)theFrame {
290 if ((self = [super initWithFrame:theFrame])) {
291 [self setFocusRingType:NSFocusRingTypeNone];
292 [self setDrawsBackground:NO];
293 [self setBordered:NO];
294 }
295 return self;
296 }
297
298 - (void)setMarginsWithLeftMargin:(CGFloat)leftMargin
299 rightMargin:(CGFloat)rightMargin {
300 // Find the preferred height for the current text properties, and center.
301 NSRect viewBounds = [self bounds];
302 [self sizeToFit];
303 NSRect textBounds = [self bounds];
304 textFrameInset_.origin.x = leftMargin;
305 textFrameInset_.origin.y = floor(NSMidY(viewBounds) - NSMidY(textBounds));
306 textFrameInset_.size.width = leftMargin + rightMargin;
307 textFrameInset_.size.height = NSHeight(viewBounds) - NSHeight(textBounds);
308 [self setFrame:viewBounds];
309 }
310
311 @end
312
313 @implementation SearchTextFieldCell
314
315 - (NSRect)textFrameForFrameInternal:(NSRect)cellFrame {
316 SearchTextField* searchTextField =
317 base::mac::ObjCCastStrict<SearchTextField>([self controlView]);
318 NSRect insetRect = [searchTextField textFrameInset];
319 cellFrame.origin.x += insetRect.origin.x;
320 cellFrame.origin.y += insetRect.origin.y;
321 cellFrame.size.width -= insetRect.size.width;
322 cellFrame.size.height -= insetRect.size.height;
323 return cellFrame;
324 }
325
326 - (NSRect)textFrameForFrame:(NSRect)cellFrame {
327 return [self textFrameForFrameInternal:cellFrame];
328 }
329
330 - (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
331 return [self textFrameForFrameInternal:cellFrame];
332 }
333
334 - (void)resetCursorRect:(NSRect)cellFrame
335 inView:(NSView*)controlView {
336 [super resetCursorRect:[self textCursorFrameForFrame:cellFrame]
337 inView:controlView];
338 }
339
340 - (NSRect)drawingRectForBounds:(NSRect)theRect {
341 return [super drawingRectForBounds:[self textFrameForFrame:theRect]];
342 }
343
344 - (void)editWithFrame:(NSRect)cellFrame
345 inView:(NSView*)controlView
346 editor:(NSText*)editor
347 delegate:(id)delegate
348 event:(NSEvent*)event {
349 [super editWithFrame:[self textFrameForFrame:cellFrame]
350 inView:controlView
351 editor:editor
352 delegate:delegate
353 event:event];
354 }
355
356 - (void)selectWithFrame:(NSRect)cellFrame
357 inView:(NSView*)controlView
358 editor:(NSText*)editor
359 delegate:(id)delegate
360 start:(NSInteger)start
361 length:(NSInteger)length {
362 [super selectWithFrame:[self textFrameForFrame:cellFrame]
363 inView:controlView
364 editor:editor
365 delegate:delegate
366 start:start
367 length:length];
368 }
369
370 @end
371
372 @implementation AppListMenuController
373
374 - (id)initWithSearchBoxController:(AppsSearchBoxController*)parent {
375 // Need to initialze super with a NULL model, otherwise it will immediately
376 // try to populate, which can't be done until setting the parent.
377 if ((self = [super initWithModel:NULL
378 useWithPopUpButtonCell:YES])) {
379 searchBoxController_ = parent;
380 [super setModel:[parent appListMenu]->menu_model()];
381 }
382 return self;
383 }
384
385 - (NSRect)confinementRectForMenu:(NSMenu*)menu
386 onScreen:(NSScreen*)screen {
387 NSPopUpButton* menuButton = [searchBoxController_ menuControl];
388 // Ensure the menu comes up below the menu button by trimming the window frame
389 // to a point anchored below the bottom right of the button.
390 NSRect anchorRect = [menuButton convertRect:[menuButton bounds]
391 toView:nil];
392 NSPoint anchorPoint = ui::ConvertPointFromWindowToScreen(
393 [menuButton window],
394 NSMakePoint(NSMaxX(anchorRect) + kMenuXOffsetFromButton,
395 NSMinY(anchorRect) - kMenuYOffsetFromButton));
396
397 NSRect confinementRect = [[menuButton window] frame];
398 confinementRect.size = NSMakeSize(anchorPoint.x - NSMinX(confinementRect),
399 anchorPoint.y - NSMinY(confinementRect));
400 return confinementRect;
401 }
402
403 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698