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 "ui/app_list/app_list_menu.h" |
| 9 #import "ui/app_list/cocoa/app_list_menu_cocoa.h" |
8 #include "ui/app_list/search_box_model.h" | 10 #include "ui/app_list/search_box_model.h" |
9 #include "ui/app_list/search_box_model_observer.h" | 11 #include "ui/app_list/search_box_model_observer.h" |
10 #include "ui/base/resource/resource_bundle.h" | 12 #include "ui/base/resource/resource_bundle.h" |
11 #include "ui/gfx/image/image_skia_util_mac.h" | 13 #include "ui/gfx/image/image_skia_util_mac.h" |
12 | 14 |
13 namespace { | 15 namespace { |
14 | 16 |
15 // Padding either side of the search icon. | 17 // Padding either side of the search icon and menu button. |
16 const CGFloat kPadding = 14; | 18 const CGFloat kPadding = 14; |
17 | 19 |
18 // Size of the search icon. | 20 // Size of the search icon. |
19 const CGFloat kSearchIconDimension = 32; | 21 const CGFloat kSearchIconDimension = 32; |
20 | 22 |
| 23 // Size of the menu button on the right. |
| 24 const CGFloat kMenuButtonDimension = 29; |
| 25 |
| 26 // Vertical offset that the menu should appear below the menu button. |
| 27 const CGFloat kMenuOffsetFromButton = 2; |
| 28 |
21 } | 29 } |
22 | 30 |
23 @interface AppsSearchBoxController () | 31 @interface AppsSearchBoxController () |
24 | 32 |
25 - (NSImageView*)searchImage; | 33 - (NSImageView*)searchImage; |
26 - (void)addSubviews; | 34 - (void)addSubviews; |
| 35 - (void)menuItemSelected:(NSMenuItem*)sender; |
| 36 - (NSMenuItem*)createMenuItemAtIndex:(int)index; |
27 | 37 |
28 @end | 38 @end |
29 | 39 |
30 namespace app_list { | 40 namespace app_list { |
31 | 41 |
32 class SearchBoxModelObserverBridge : public SearchBoxModelObserver { | 42 class SearchBoxModelObserverBridge : public SearchBoxModelObserver { |
33 public: | 43 public: |
34 SearchBoxModelObserverBridge(AppsSearchBoxController* parent, | 44 SearchBoxModelObserverBridge(AppsSearchBoxController* parent, |
35 SearchBoxModel* model); | 45 SearchBoxModel* model); |
36 virtual ~SearchBoxModelObserverBridge(); | 46 virtual ~SearchBoxModelObserverBridge(); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 return self; | 112 return self; |
103 } | 113 } |
104 | 114 |
105 - (void)clearSearch { | 115 - (void)clearSearch { |
106 [searchInput_ setStringValue:[NSString string]]; | 116 [searchInput_ setStringValue:[NSString string]]; |
107 [self controlTextDidChange:nil]; | 117 [self controlTextDidChange:nil]; |
108 } | 118 } |
109 | 119 |
110 - (void)setDelegate:(id<AppsSearchBoxDelegate>)delegate { | 120 - (void)setDelegate:(id<AppsSearchBoxDelegate>)delegate { |
111 delegate_ = delegate; | 121 delegate_ = delegate; |
| 122 app_list::AppListViewDelegate* appListDelegate = [delegate appListDelegate]; |
112 app_list::SearchBoxModel* searchBoxModel = [delegate searchBoxModel]; | 123 app_list::SearchBoxModel* searchBoxModel = [delegate searchBoxModel]; |
| 124 appListMenu_.reset(appListDelegate ? |
| 125 new app_list::AppListMenu(appListDelegate) : NULL); |
113 bridge_.reset(searchBoxModel ? | 126 bridge_.reset(searchBoxModel ? |
114 new app_list::SearchBoxModelObserverBridge(self, searchBoxModel) : NULL); | 127 new app_list::SearchBoxModelObserverBridge(self, searchBoxModel) : NULL); |
115 } | 128 } |
116 | 129 |
117 - (NSTextField*)textField { | 130 - (NSTextField*)textField { |
118 return searchInput_; | 131 return searchInput_; |
119 } | 132 } |
120 | 133 |
| 134 - (NSPopUpButton*)menuControl { |
| 135 return menuButton_; |
| 136 } |
| 137 |
| 138 - (app_list::AppListMenu*)appListMenu { |
| 139 return appListMenu_.get(); |
| 140 } |
| 141 |
121 - (NSImageView*)searchImage { | 142 - (NSImageView*)searchImage { |
122 return searchImage_; | 143 return searchImage_; |
123 } | 144 } |
124 | 145 |
125 - (void)addSubviews { | 146 - (void)addSubviews { |
126 NSSize viewSize = [[self view] bounds].size; | 147 NSSize viewSize = [[self view] bounds].size; |
127 searchImage_.reset([[NSImageView alloc] initWithFrame:NSMakeRect( | 148 searchImage_.reset([[NSImageView alloc] initWithFrame:NSMakeRect( |
128 kPadding, 0, kSearchIconDimension, viewSize.height)]); | 149 kPadding, 0, kSearchIconDimension, viewSize.height)]); |
129 | 150 |
130 searchInput_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]); | 151 searchInput_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]); |
131 [searchInput_ setFocusRingType:NSFocusRingTypeNone]; | 152 [searchInput_ setFocusRingType:NSFocusRingTypeNone]; |
132 [searchInput_ setDrawsBackground:NO]; | 153 [searchInput_ setDrawsBackground:NO]; |
133 [searchInput_ setBordered:NO]; | 154 [searchInput_ setBordered:NO]; |
134 [searchInput_ setDelegate:self]; | 155 [searchInput_ setDelegate:self]; |
135 [searchInput_ setFont:ui::ResourceBundle::GetSharedInstance().GetFont( | 156 [searchInput_ setFont:ui::ResourceBundle::GetSharedInstance().GetFont( |
136 ui::ResourceBundle::MediumFont).GetNativeFont()]; | 157 ui::ResourceBundle::MediumFont).GetNativeFont()]; |
137 | 158 |
138 // Find the preferred height for those text properties, and center. | 159 // Find the preferred height for those text properties, and center. |
139 [searchInput_ sizeToFit]; | 160 [searchInput_ sizeToFit]; |
140 CGFloat inputXOffset = kSearchIconDimension + 2 * kPadding; | 161 CGFloat inputXOffset = kSearchIconDimension + 2 * kPadding; |
141 CGFloat inputHeight = NSHeight([searchInput_ bounds]); | 162 CGFloat inputHeight = NSHeight([searchInput_ bounds]); |
142 [searchInput_ setFrame:NSMakeRect( | 163 [searchInput_ setFrame:NSMakeRect( |
143 inputXOffset, | 164 inputXOffset, |
144 floor(viewSize.height / 2 - inputHeight / 2), | 165 floor(viewSize.height / 2 - inputHeight / 2), |
145 viewSize.width - inputXOffset - kPadding, | 166 viewSize.width - inputXOffset - kMenuButtonDimension - 2 * kPadding, |
146 inputHeight)]; | 167 inputHeight)]; |
147 | 168 |
| 169 // Add the drop-down menu, with a custom button. |
| 170 NSRect buttonFrame = NSMakeRect( |
| 171 NSMaxX([searchInput_ frame]) + kPadding, |
| 172 floor(viewSize.height / 2 - kMenuButtonDimension / 2), |
| 173 kMenuButtonDimension, |
| 174 kMenuButtonDimension); |
| 175 menuButton_.reset([[AppListMenuCocoa alloc] initWithFrame:buttonFrame]); |
| 176 [[menuButton_ menu] setDelegate:self]; |
| 177 |
148 [[self view] addSubview:searchImage_]; | 178 [[self view] addSubview:searchImage_]; |
149 [[self view] addSubview:searchInput_]; | 179 [[self view] addSubview:searchInput_]; |
| 180 [[self view] addSubview:menuButton_]; |
| 181 } |
| 182 |
| 183 - (void)menuItemSelected:(NSMenuItem*)sender { |
| 184 if (!appListMenu_) |
| 185 return; |
| 186 |
| 187 appListMenu_->menu_model()->ActivatedAt([sender tag]); |
| 188 } |
| 189 |
| 190 - (void)menuNeedsUpdate:(NSMenu*)menu { |
| 191 if (!appListMenu_) |
| 192 return; |
| 193 |
| 194 int itemCount = appListMenu_->menu_model()->GetItemCount(); |
| 195 if ([menu numberOfItems] == itemCount) |
| 196 return; // Already populated. |
| 197 |
| 198 for (int i = 0; i < itemCount; ++i) |
| 199 [menu addItem:[self createMenuItemAtIndex:i]]; |
| 200 } |
| 201 |
| 202 - (NSMenuItem*)createMenuItemAtIndex:(int)index { |
| 203 DCHECK(appListMenu_); |
| 204 ui::MenuModel* menuModel = appListMenu_->menu_model(); |
| 205 if (menuModel->GetTypeAt(index) == ui::MenuModel::TYPE_SEPARATOR) |
| 206 return [NSMenuItem separatorItem]; |
| 207 |
| 208 string16 labelText = menuModel->GetLabelAt(index); |
| 209 scoped_nsobject<NSMenuItem> item( |
| 210 [[NSMenuItem alloc] initWithTitle:base::SysUTF16ToNSString(labelText) |
| 211 action:@selector(menuItemSelected:) |
| 212 keyEquivalent:[NSString string]]); |
| 213 [item setTag:index]; |
| 214 [item setTarget:self]; |
| 215 if (menuModel->GetCommandIdAt(index) == app_list::AppListMenu::CURRENT_USER) { |
| 216 [item setView: |
| 217 [AppListMenuCocoa makeCurrentUserView:[delegate_ appListDelegate]]]; |
| 218 } |
| 219 |
| 220 return item.autorelease(); |
| 221 } |
| 222 |
| 223 - (NSRect)confinementRectForMenu:(NSMenu*)menu |
| 224 onScreen:(NSScreen*)screen { |
| 225 // Ensure the menu comes up below the menu button by trimming the window frame |
| 226 // to a point anchored below the bottom right of the button. |
| 227 NSPoint anchor = NSMakePoint(kMenuButtonDimension, |
| 228 kMenuButtonDimension + kMenuOffsetFromButton); |
| 229 anchor = [menuButton_ convertPoint:anchor |
| 230 toView:nil]; |
| 231 anchor = [[menuButton_ window] convertBaseToScreen:anchor]; |
| 232 NSRect rect = [[menuButton_ window] frame]; |
| 233 rect.size = NSMakeSize(anchor.x - NSMinX(rect), anchor.y - NSMinY(rect)); |
| 234 return rect; |
150 } | 235 } |
151 | 236 |
152 - (BOOL)control:(NSControl*)control | 237 - (BOOL)control:(NSControl*)control |
153 textView:(NSTextView*)textView | 238 textView:(NSTextView*)textView |
154 doCommandBySelector:(SEL)command { | 239 doCommandBySelector:(SEL)command { |
155 // Forward the message first, to handle grid or search results navigation. | 240 // Forward the message first, to handle grid or search results navigation. |
156 BOOL handled = [delegate_ control:control | 241 BOOL handled = [delegate_ control:control |
157 textView:textView | 242 textView:textView |
158 doCommandBySelector:command]; | 243 doCommandBySelector:command]; |
159 if (handled) | 244 if (handled) |
160 return YES; | 245 return YES; |
161 | 246 |
162 // Escape when there is text clears the search input. | 247 // Escape when there is text clears the search input. |
163 if (command == @selector(complete:)) { | 248 if (command == @selector(complete:)) { |
164 [self clearSearch]; | 249 [self clearSearch]; |
165 return YES; | 250 return YES; |
166 } | 251 } |
167 | 252 |
168 return NO; | 253 return NO; |
169 } | 254 } |
170 | 255 |
171 - (void)controlTextDidChange:(NSNotification*)notification { | 256 - (void)controlTextDidChange:(NSNotification*)notification { |
172 if (bridge_) | 257 if (bridge_) |
173 bridge_->updateModel(base::SysNSStringToUTF16([searchInput_ stringValue])); | 258 bridge_->updateModel(base::SysNSStringToUTF16([searchInput_ stringValue])); |
174 | 259 |
175 [delegate_ modelTextDidChange]; | 260 [delegate_ modelTextDidChange]; |
176 } | 261 } |
177 | 262 |
178 @end | 263 @end |
OLD | NEW |