OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "ui/app_list/cocoa/apps_search_box_controller.h" | 5 #import "ui/app_list/cocoa/apps_search_box_controller.h" |
6 | 6 |
7 #include "base/strings/sys_string_conversions.h" | 7 #include "base/strings/sys_string_conversions.h" |
8 #include "grit/ui_resources.h" | |
9 #include "ui/app_list/app_list_menu.h" | |
10 #import "ui/app_list/cocoa/current_user_menu_item_view.h" | |
8 #include "ui/app_list/search_box_model.h" | 11 #include "ui/app_list/search_box_model.h" |
9 #include "ui/app_list/search_box_model_observer.h" | 12 #include "ui/app_list/search_box_model_observer.h" |
13 #import "ui/base/cocoa/controls/hover_image_menu_button.h" | |
10 #include "ui/base/resource/resource_bundle.h" | 14 #include "ui/base/resource/resource_bundle.h" |
11 #include "ui/gfx/image/image_skia_util_mac.h" | 15 #include "ui/gfx/image/image_skia_util_mac.h" |
12 | 16 |
13 namespace { | 17 namespace { |
14 | 18 |
15 // Padding either side of the search icon. | 19 // Padding either side of the search icon and menu button. |
16 const CGFloat kPadding = 14; | 20 const CGFloat kPadding = 14; |
17 | 21 |
18 // Size of the search icon. | 22 // Size of the search icon. |
19 const CGFloat kSearchIconDimension = 32; | 23 const CGFloat kSearchIconDimension = 32; |
20 | 24 |
25 // Size of the menu button on the right. | |
26 const CGFloat kMenuButtonDimension = 29; | |
27 | |
28 // Vertical offset that the menu should appear below the menu button. | |
29 const CGFloat kMenuOffsetFromButton = 2; | |
30 | |
21 } | 31 } |
22 | 32 |
23 @interface AppsSearchBoxController () | 33 @interface AppsSearchBoxController () |
24 | 34 |
25 - (NSImageView*)searchImage; | 35 - (NSImageView*)searchImage; |
26 - (void)addSubviews; | 36 - (void)addSubviews; |
37 - (void)menuItemSelected:(NSMenuItem*)sender; | |
38 | |
39 - (void)addItemToMenu:(NSMenu*)menu | |
40 forIndex:(int)index; | |
27 | 41 |
28 @end | 42 @end |
29 | 43 |
30 namespace app_list { | 44 namespace app_list { |
31 | 45 |
32 class SearchBoxModelObserverBridge : public SearchBoxModelObserver { | 46 class SearchBoxModelObserverBridge : public SearchBoxModelObserver { |
33 public: | 47 public: |
34 SearchBoxModelObserverBridge(AppsSearchBoxController* parent, | 48 SearchBoxModelObserverBridge(AppsSearchBoxController* parent, |
35 SearchBoxModel* model); | 49 SearchBoxModel* model); |
36 virtual ~SearchBoxModelObserverBridge(); | 50 virtual ~SearchBoxModelObserverBridge(); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 return self; | 116 return self; |
103 } | 117 } |
104 | 118 |
105 - (void)clearSearch { | 119 - (void)clearSearch { |
106 [searchInput_ setStringValue:[NSString string]]; | 120 [searchInput_ setStringValue:[NSString string]]; |
107 [self controlTextDidChange:nil]; | 121 [self controlTextDidChange:nil]; |
108 } | 122 } |
109 | 123 |
110 - (void)setDelegate:(id<AppsSearchBoxDelegate>)delegate { | 124 - (void)setDelegate:(id<AppsSearchBoxDelegate>)delegate { |
111 delegate_ = delegate; | 125 delegate_ = delegate; |
126 app_list::AppListViewDelegate* appListDelegate = [delegate appListDelegate]; | |
112 app_list::SearchBoxModel* searchBoxModel = [delegate searchBoxModel]; | 127 app_list::SearchBoxModel* searchBoxModel = [delegate searchBoxModel]; |
128 appListMenu_.reset(appListDelegate ? | |
129 new app_list::AppListMenu(appListDelegate) : NULL); | |
113 bridge_.reset(searchBoxModel ? | 130 bridge_.reset(searchBoxModel ? |
114 new app_list::SearchBoxModelObserverBridge(self, searchBoxModel) : NULL); | 131 new app_list::SearchBoxModelObserverBridge(self, searchBoxModel) : NULL); |
115 } | 132 } |
116 | 133 |
117 - (NSTextField*)textField { | 134 - (NSTextField*)textField { |
118 return searchInput_; | 135 return searchInput_; |
119 } | 136 } |
120 | 137 |
138 - (NSPopUpButton*)menuControl { | |
139 return menuButton_; | |
140 } | |
141 | |
142 - (app_list::AppListMenu*)appListMenu { | |
143 return appListMenu_.get(); | |
144 } | |
145 | |
121 - (NSImageView*)searchImage { | 146 - (NSImageView*)searchImage { |
122 return searchImage_; | 147 return searchImage_; |
123 } | 148 } |
124 | 149 |
125 - (void)addSubviews { | 150 - (void)addSubviews { |
126 NSSize viewSize = [[self view] bounds].size; | 151 NSSize viewSize = [[self view] bounds].size; |
127 searchImage_.reset([[NSImageView alloc] initWithFrame:NSMakeRect( | 152 searchImage_.reset([[NSImageView alloc] initWithFrame:NSMakeRect( |
128 kPadding, 0, kSearchIconDimension, viewSize.height)]); | 153 kPadding, 0, kSearchIconDimension, viewSize.height)]); |
129 | 154 |
155 ui::ResourceBundle& resourceBundle = ui::ResourceBundle::GetSharedInstance(); | |
130 searchInput_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]); | 156 searchInput_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]); |
131 [searchInput_ setFocusRingType:NSFocusRingTypeNone]; | 157 [searchInput_ setFocusRingType:NSFocusRingTypeNone]; |
132 [searchInput_ setDrawsBackground:NO]; | 158 [searchInput_ setDrawsBackground:NO]; |
133 [searchInput_ setBordered:NO]; | 159 [searchInput_ setBordered:NO]; |
134 [searchInput_ setDelegate:self]; | 160 [searchInput_ setDelegate:self]; |
135 [searchInput_ setFont:ui::ResourceBundle::GetSharedInstance().GetFont( | 161 [searchInput_ setFont:resourceBundle.GetFont( |
136 ui::ResourceBundle::MediumFont).GetNativeFont()]; | 162 ui::ResourceBundle::MediumFont).GetNativeFont()]; |
137 | 163 |
138 // Find the preferred height for those text properties, and center. | 164 // Find the preferred height for those text properties, and center. |
139 [searchInput_ sizeToFit]; | 165 [searchInput_ sizeToFit]; |
140 CGFloat inputXOffset = kSearchIconDimension + 2 * kPadding; | 166 CGFloat inputXOffset = kSearchIconDimension + 2 * kPadding; |
141 CGFloat inputHeight = NSHeight([searchInput_ bounds]); | 167 CGFloat inputHeight = NSHeight([searchInput_ bounds]); |
142 [searchInput_ setFrame:NSMakeRect( | 168 [searchInput_ setFrame:NSMakeRect( |
143 inputXOffset, | 169 inputXOffset, |
144 floor(viewSize.height / 2 - inputHeight / 2), | 170 floor(viewSize.height / 2 - inputHeight / 2), |
145 viewSize.width - inputXOffset - kPadding, | 171 viewSize.width - inputXOffset - kMenuButtonDimension - 2 * kPadding, |
146 inputHeight)]; | 172 inputHeight)]; |
147 | 173 |
174 // Add the drop-down menu, with a custom button. | |
175 NSRect buttonFrame = NSMakeRect( | |
176 NSMaxX([searchInput_ frame]) + kPadding, | |
177 floor(viewSize.height / 2 - kMenuButtonDimension / 2), | |
178 kMenuButtonDimension, | |
179 kMenuButtonDimension); | |
180 menuButton_.reset([[HoverImageMenuButton alloc] initWithFrame:buttonFrame | |
181 pullsDown:YES]); | |
182 [[menuButton_ menu] setDelegate:self]; | |
183 [[menuButton_ cell] setImage:resourceBundle.GetNativeImageNamed( | |
sail
2013/05/31 19:07:03
use hoverImageMenuButtonCell accessor instead?
tapted
2013/06/03 12:49:18
Done.
| |
184 IDR_APP_LIST_TOOLS_NORMAL).AsNSImage()]; | |
185 [[menuButton_ cell] setAlternateImage:resourceBundle.GetNativeImageNamed( | |
186 IDR_APP_LIST_TOOLS_PRESSED).AsNSImage()]; | |
187 [[menuButton_ cell] setHoverImage:resourceBundle.GetNativeImageNamed( | |
188 IDR_APP_LIST_TOOLS_HOVER).AsNSImage()]; | |
189 | |
148 [[self view] addSubview:searchImage_]; | 190 [[self view] addSubview:searchImage_]; |
149 [[self view] addSubview:searchInput_]; | 191 [[self view] addSubview:searchInput_]; |
192 [[self view] addSubview:menuButton_]; | |
193 } | |
194 | |
195 - (void)menuItemSelected:(NSMenuItem*)sender { | |
196 if (!appListMenu_) | |
sail
2013/05/31 19:07:03
is this possible?
tapted
2013/06/03 12:49:18
Initially I wasn't sure, but I realised the menu i
| |
197 return; | |
198 | |
199 appListMenu_->menu_model()->ActivatedAt([sender tag]); | |
200 } | |
201 | |
202 - (void)menuNeedsUpdate:(NSMenu*)menu { | |
203 if (!appListMenu_ || [menu numberOfItems] != 1) | |
204 return; | |
205 | |
206 int itemCount = appListMenu_->menu_model()->GetItemCount(); | |
sail
2013/05/31 19:07:03
do this in addSubviews instead?
tapted
2013/06/03 12:49:18
I initially did it here because it means the creat
| |
207 for (int i = 0; i < itemCount; ++i) { | |
208 [self addItemToMenu:menu | |
209 forIndex:i]; | |
210 } | |
211 } | |
212 | |
213 - (void)addItemToMenu:(NSMenu*)menu | |
Robert Sesek
2013/05/31 19:16:09
Have you considered using MenuController? https://
tapted
2013/06/03 12:54:24
I have! But, it would need further refactoring to
| |
214 forIndex:(int)index { | |
215 DCHECK(appListMenu_); | |
216 ui::MenuModel* menuModel = appListMenu_->menu_model(); | |
217 if (menuModel->GetTypeAt(index) == ui::MenuModel::TYPE_SEPARATOR) { | |
218 [menu addItem:[NSMenuItem separatorItem]]; | |
219 return; | |
220 } | |
221 | |
222 string16 labelText = menuModel->GetLabelAt(index); | |
223 scoped_nsobject<NSMenuItem> item( | |
224 [[NSMenuItem alloc] initWithTitle:base::SysUTF16ToNSString(labelText) | |
225 action:@selector(menuItemSelected:) | |
226 keyEquivalent:[NSString string]]); | |
227 [item setTag:index]; | |
228 [item setTarget:self]; | |
229 | |
230 if (menuModel->GetCommandIdAt(index) == app_list::AppListMenu::CURRENT_USER) { | |
231 scoped_nsobject<NSView> customItemView([[CurrentUserMenuItemView alloc] | |
232 initWithDelegate:[delegate_ appListDelegate] | |
233 usingFont:[menu font]]); | |
234 | |
235 [item setView:customItemView]; | |
236 } | |
237 | |
238 [menu addItem:item]; | |
239 } | |
240 | |
241 - (NSRect)confinementRectForMenu:(NSMenu*)menu | |
242 onScreen:(NSScreen*)screen { | |
243 // Ensure the menu comes up below the menu button by trimming the window frame | |
244 // to a point anchored below the bottom right of the button. | |
245 NSPoint anchor = NSMakePoint(kMenuButtonDimension, | |
246 kMenuButtonDimension + kMenuOffsetFromButton); | |
247 anchor = [menuButton_ convertPoint:anchor | |
248 toView:nil]; | |
249 anchor = [[menuButton_ window] convertBaseToScreen:anchor]; | |
250 NSRect rect = [[menuButton_ window] frame]; | |
251 rect.size = NSMakeSize(anchor.x - NSMinX(rect), anchor.y - NSMinY(rect)); | |
sail
2013/05/31 19:07:03
how about just converting [menuButton_ bounds] to
tapted
2013/06/03 12:49:18
Sadly, NSWindow convertRectToScreen: is OSX 10.7+
| |
252 return rect; | |
150 } | 253 } |
151 | 254 |
152 - (BOOL)control:(NSControl*)control | 255 - (BOOL)control:(NSControl*)control |
153 textView:(NSTextView*)textView | 256 textView:(NSTextView*)textView |
154 doCommandBySelector:(SEL)command { | 257 doCommandBySelector:(SEL)command { |
155 // Forward the message first, to handle grid or search results navigation. | 258 // Forward the message first, to handle grid or search results navigation. |
156 BOOL handled = [delegate_ control:control | 259 BOOL handled = [delegate_ control:control |
157 textView:textView | 260 textView:textView |
158 doCommandBySelector:command]; | 261 doCommandBySelector:command]; |
159 if (handled) | 262 if (handled) |
160 return YES; | 263 return YES; |
161 | 264 |
162 // Escape when there is text clears the search input. | 265 // Escape when there is text clears the search input. |
163 if (command == @selector(complete:)) { | 266 if (command == @selector(complete:)) { |
164 [self clearSearch]; | 267 [self clearSearch]; |
165 return YES; | 268 return YES; |
166 } | 269 } |
167 | 270 |
168 return NO; | 271 return NO; |
169 } | 272 } |
170 | 273 |
171 - (void)controlTextDidChange:(NSNotification*)notification { | 274 - (void)controlTextDidChange:(NSNotification*)notification { |
172 if (bridge_) | 275 if (bridge_) |
173 bridge_->updateModel(base::SysNSStringToUTF16([searchInput_ stringValue])); | 276 bridge_->updateModel(base::SysNSStringToUTF16([searchInput_ stringValue])); |
174 | 277 |
175 [delegate_ modelTextDidChange]; | 278 [delegate_ modelTextDidChange]; |
176 } | 279 } |
177 | 280 |
178 @end | 281 @end |
OLD | NEW |