| 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 |