| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "ash/app_list/app_list_view.h" | 5 #include "ash/app_list/app_list_view.h" |
| 6 | 6 |
| 7 #include "ash/app_list/app_list.h" |
| 8 #include "ash/app_list/app_list_bubble_border.h" |
| 7 #include "ash/app_list/app_list_item_view.h" | 9 #include "ash/app_list/app_list_item_view.h" |
| 8 #include "ash/app_list/app_list_model.h" | 10 #include "ash/app_list/app_list_model.h" |
| 9 #include "ash/app_list/app_list_model_view.h" | 11 #include "ash/app_list/app_list_model_view.h" |
| 10 #include "ash/app_list/app_list_view_delegate.h" | 12 #include "ash/app_list/app_list_view_delegate.h" |
| 13 #include "ash/app_list/page_switcher.h" |
| 14 #include "ash/app_list/pagination_model.h" |
| 15 #include "ash/launcher/launcher.h" |
| 11 #include "ash/screen_ash.h" | 16 #include "ash/screen_ash.h" |
| 12 #include "ash/shell.h" | 17 #include "ash/shell.h" |
| 13 #include "ash/shell_window_ids.h" | 18 #include "ash/shell_window_ids.h" |
| 14 #include "ash/wm/shelf_layout_manager.h" | 19 #include "ash/wm/shelf_layout_manager.h" |
| 15 #include "ui/compositor/layer.h" | 20 #include "ui/compositor/layer.h" |
| 16 #include "ui/compositor/scoped_layer_animation_settings.h" | 21 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 17 #include "ui/gfx/screen.h" | 22 #include "ui/gfx/screen.h" |
| 18 #include "ui/gfx/transform_util.h" | 23 #include "ui/gfx/transform_util.h" |
| 19 #include "ui/views/background.h" | 24 #include "ui/views/background.h" |
| 25 #include "ui/views/bubble/bubble_frame_view.h" |
| 26 #include "ui/views/layout/box_layout.h" |
| 20 #include "ui/views/widget/widget.h" | 27 #include "ui/views/widget/widget.h" |
| 21 | 28 |
| 22 namespace ash { | 29 namespace ash { |
| 23 | 30 |
| 24 namespace { | 31 namespace { |
| 25 | 32 |
| 26 // 0.2 black | 33 // 0.2 black |
| 27 const SkColor kBackgroundColor = SkColorSetARGB(0x33, 0, 0, 0); | 34 const SkColor kWidgetBackgroundColor = SkColorSetARGB(0x33, 0, 0, 0); |
| 28 | 35 |
| 29 const float kModelViewAnimationScaleFactor = 0.9f; | 36 const float kModelViewAnimationScaleFactor = 0.9f; |
| 30 | 37 |
| 38 const int kPreferredIconDimension = 48; |
| 39 const int kPreferredCols = 4; |
| 40 const int kPreferredRows = 4; |
| 41 // Padding space in pixels between model view and page switcher footer. |
| 42 const int kModelViewFooterPadding = 10; |
| 43 |
| 31 ui::Transform GetScaleTransform(AppListModelView* model_view) { | 44 ui::Transform GetScaleTransform(AppListModelView* model_view) { |
| 32 gfx::Rect pixel_bounds = model_view->GetLayerBoundsInPixel(); | 45 gfx::Rect pixel_bounds = model_view->GetLayerBoundsInPixel(); |
| 33 gfx::Point center(pixel_bounds.width() / 2, pixel_bounds.height() / 2); | 46 gfx::Point center(pixel_bounds.width() / 2, pixel_bounds.height() / 2); |
| 34 return ui::GetScaleTransform(center, kModelViewAnimationScaleFactor); | 47 return ui::GetScaleTransform(center, kModelViewAnimationScaleFactor); |
| 35 } | 48 } |
| 36 | 49 |
| 50 // Bounds returned is used for full screen mode. Use full monitor rect so that |
| 51 // the app list shade goes behind the launcher. |
| 52 gfx::Rect GetFullScreenBounds() { |
| 53 gfx::Point cursor = gfx::Screen::GetCursorScreenPoint(); |
| 54 return gfx::Screen::GetMonitorNearestPoint(cursor).bounds(); |
| 55 } |
| 56 |
| 37 } // namespace | 57 } // namespace |
| 38 | 58 |
| 39 AppListView::AppListView( | 59 //////////////////////////////////////////////////////////////////////////////// |
| 40 AppListViewDelegate* delegate, | 60 // AppListView: |
| 41 const gfx::Rect& bounds) | 61 |
| 62 AppListView::AppListView(AppListViewDelegate* delegate) |
| 42 : delegate_(delegate), | 63 : delegate_(delegate), |
| 64 pagination_model_(new PaginationModel), |
| 65 bubble_style_(false), |
| 66 bubble_border_(NULL), |
| 43 model_view_(NULL) { | 67 model_view_(NULL) { |
| 44 set_background(views::Background::CreateSolidBackground(kBackgroundColor)); | 68 if (internal::AppList::UseAppListV2()) |
| 45 Init(bounds); | 69 InitAsBubble(); |
| 70 else |
| 71 InitAsFullscreenWidget(); |
| 46 } | 72 } |
| 47 | 73 |
| 48 AppListView::~AppListView() { | 74 AppListView::~AppListView() { |
| 49 // Model is going away, so set to NULL before superclass deletes child views. | 75 // Model is going away, so set to NULL before superclass deletes child views. |
| 50 if (model_view_) | 76 if (model_view_) |
| 51 model_view_->SetModel(NULL); | 77 model_view_->SetModel(NULL); |
| 52 } | 78 } |
| 53 | 79 |
| 54 void AppListView::AnimateShow(int duration_ms) { | 80 void AppListView::AnimateShow(int duration_ms) { |
| 81 if (bubble_style_) |
| 82 return; |
| 83 |
| 55 ui::Layer* layer = model_view_->layer(); | 84 ui::Layer* layer = model_view_->layer(); |
| 56 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); | 85 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); |
| 57 animation.SetTransitionDuration( | 86 animation.SetTransitionDuration( |
| 58 base::TimeDelta::FromMilliseconds(duration_ms)); | 87 base::TimeDelta::FromMilliseconds(duration_ms)); |
| 59 animation.SetTweenType(ui::Tween::EASE_OUT); | 88 animation.SetTweenType(ui::Tween::EASE_OUT); |
| 60 model_view_->SetTransform(ui::Transform()); | 89 model_view_->SetTransform(ui::Transform()); |
| 61 } | 90 } |
| 62 | 91 |
| 63 void AppListView::AnimateHide(int duration_ms) { | 92 void AppListView::AnimateHide(int duration_ms) { |
| 93 if (bubble_style_) |
| 94 return; |
| 95 |
| 64 ui::Layer* layer = model_view_->layer(); | 96 ui::Layer* layer = model_view_->layer(); |
| 65 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); | 97 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); |
| 66 animation.SetTransitionDuration( | 98 animation.SetTransitionDuration( |
| 67 base::TimeDelta::FromMilliseconds(duration_ms)); | 99 base::TimeDelta::FromMilliseconds(duration_ms)); |
| 68 animation.SetTweenType(ui::Tween::EASE_IN); | 100 animation.SetTweenType(ui::Tween::EASE_IN); |
| 69 model_view_->SetTransform(GetScaleTransform(model_view_)); | 101 model_view_->SetTransform(GetScaleTransform(model_view_)); |
| 70 } | 102 } |
| 71 | 103 |
| 72 void AppListView::Close() { | 104 void AppListView::Close() { |
| 73 if (GetWidget()->IsVisible()) | 105 if (GetWidget()->IsVisible()) |
| 74 Shell::GetInstance()->ToggleAppList(); | 106 Shell::GetInstance()->ToggleAppList(); |
| 75 } | 107 } |
| 76 | 108 |
| 77 void AppListView::Init(const gfx::Rect& bounds) { | 109 void AppListView::UpdateBounds() { |
| 78 model_view_ = new AppListModelView(this); | 110 if (bubble_style_) |
| 111 SizeToContents(); |
| 112 else |
| 113 GetWidget()->SetBounds(GetFullScreenBounds()); |
| 114 } |
| 115 |
| 116 void AppListView::InitAsFullscreenWidget() { |
| 117 bubble_style_ = false; |
| 118 set_background(views::Background::CreateSolidBackground( |
| 119 kWidgetBackgroundColor)); |
| 120 |
| 121 model_view_ = new AppListModelView(this, pagination_model_.get()); |
| 79 model_view_->SetPaintToLayer(true); | 122 model_view_->SetPaintToLayer(true); |
| 80 model_view_->layer()->SetFillsBoundsOpaquely(false); | 123 model_view_->layer()->SetFillsBoundsOpaquely(false); |
| 81 AddChildView(model_view_); | 124 AddChildView(model_view_); |
| 82 | 125 |
| 83 views::Widget::InitParams widget_params( | 126 views::Widget::InitParams widget_params( |
| 84 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); | 127 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| 85 widget_params.delegate = this; | 128 widget_params.delegate = this; |
| 86 widget_params.keep_on_top = true; | |
| 87 widget_params.transparent = true; | 129 widget_params.transparent = true; |
| 88 widget_params.parent = Shell::GetInstance()->GetContainer( | 130 widget_params.parent = Shell::GetInstance()->GetContainer( |
| 89 internal::kShellWindowId_AppListContainer); | 131 internal::kShellWindowId_AppListContainer); |
| 90 | 132 |
| 91 views::Widget* widget = new views::Widget; | 133 views::Widget* widget = new views::Widget; |
| 92 widget->Init(widget_params); | 134 widget->Init(widget_params); |
| 93 widget->SetContentsView(this); | 135 widget->SetContentsView(this); |
| 94 widget->SetBounds(bounds); | 136 |
| 137 widget->SetBounds(GetFullScreenBounds()); |
| 95 | 138 |
| 96 // Turns off default animation. | 139 // Turns off default animation. |
| 97 widget->SetVisibilityChangedAnimationsEnabled(false); | 140 widget->SetVisibilityChangedAnimationsEnabled(false); |
| 98 | 141 |
| 99 // Sets initial transform. AnimateShow changes it back to identity transform. | 142 // Sets initial transform. AnimateShow changes it back to identity transform. |
| 100 model_view_->SetTransform(GetScaleTransform(model_view_)); | 143 model_view_->SetTransform(GetScaleTransform(model_view_)); |
| 101 UpdateModel(); | 144 UpdateModel(); |
| 102 } | 145 } |
| 103 | 146 |
| 147 void AppListView::InitAsBubble() { |
| 148 bubble_style_ = true; |
| 149 set_background(NULL); |
| 150 |
| 151 SetLayoutManager(new views::BoxLayout( |
| 152 views::BoxLayout::kVertical, 0, 0, kModelViewFooterPadding)); |
| 153 |
| 154 model_view_ = new AppListModelView(this, pagination_model_.get()); |
| 155 model_view_->SetLayout(kPreferredIconDimension, |
| 156 kPreferredCols, |
| 157 kPreferredRows); |
| 158 AddChildView(model_view_); |
| 159 |
| 160 PageSwitcher* page_switcher = new PageSwitcher(pagination_model_.get()); |
| 161 AddChildView(page_switcher); |
| 162 |
| 163 set_anchor_view(Shell::GetInstance()->launcher()->GetAppListButtonView()); |
| 164 set_parent_window(Shell::GetInstance()->GetContainer( |
| 165 internal::kShellWindowId_AppListContainer)); |
| 166 set_close_on_deactivate(false); |
| 167 views::BubbleDelegateView::CreateBubble(this); |
| 168 |
| 169 // Resets default background since AppListBubbleBorder paints background. |
| 170 GetBubbleFrameView()->set_background(NULL); |
| 171 |
| 172 // Overrides border with AppListBubbleBorder. |
| 173 bubble_border_ = new AppListBubbleBorder(this); |
| 174 GetBubbleFrameView()->SetBubbleBorder(bubble_border_); |
| 175 SizeToContents(); // Recalcuates with new border. |
| 176 |
| 177 UpdateModel(); |
| 178 } |
| 179 |
| 104 void AppListView::UpdateModel() { | 180 void AppListView::UpdateModel() { |
| 105 if (delegate_.get()) { | 181 if (delegate_.get()) { |
| 106 scoped_ptr<AppListModel> new_model(new AppListModel); | 182 scoped_ptr<AppListModel> new_model(new AppListModel); |
| 107 delegate_->SetModel(new_model.get()); | 183 delegate_->SetModel(new_model.get()); |
| 108 delegate_->UpdateModel(std::string()); | 184 delegate_->UpdateModel(std::string()); |
| 109 model_view_->SetModel(new_model.get()); | 185 model_view_->SetModel(new_model.get()); |
| 110 model_.reset(new_model.release()); | 186 model_.reset(new_model.release()); |
| 111 } | 187 } |
| 112 } | 188 } |
| 113 | 189 |
| 114 views::View* AppListView::GetInitiallyFocusedView() { | 190 views::View* AppListView::GetInitiallyFocusedView() { |
| 115 return model_view_; | 191 return model_view_; |
| 116 } | 192 } |
| 117 | 193 |
| 118 void AppListView::Layout() { | 194 void AppListView::Layout() { |
| 119 gfx::Rect rect(GetContentsBounds()); | 195 gfx::Rect rect(GetContentsBounds()); |
| 120 if (rect.IsEmpty()) | 196 if (rect.IsEmpty()) |
| 121 return; | 197 return; |
| 122 | 198 |
| 123 // Gets work area rect, which is in screen coordinates. | 199 if (bubble_style_) { |
| 124 gfx::Rect workarea = Shell::GetInstance()->shelf()->IsVisible() ? | 200 views::View::Layout(); |
| 125 ScreenAsh::GetUnmaximizedWorkAreaBounds(GetWidget()->GetNativeView()) : | 201 } else { |
| 126 gfx::Screen::GetMonitorNearestWindow( | 202 // Gets work area rect, which is in screen coordinates. |
| 127 GetWidget()->GetNativeView()).work_area(); | 203 gfx::Rect workarea = Shell::GetInstance()->shelf()->IsVisible() ? |
| 204 ScreenAsh::GetUnmaximizedWorkAreaBounds(GetWidget()->GetNativeView()) : |
| 205 gfx::Screen::GetMonitorNearestWindow( |
| 206 GetWidget()->GetNativeView()).work_area(); |
| 128 | 207 |
| 129 // Converts |workarea| into view's coordinates. | 208 // Converts |workarea| into view's coordinates. |
| 130 gfx::Point origin(workarea.origin()); | 209 gfx::Point origin(workarea.origin()); |
| 131 views::View::ConvertPointFromScreen(this, &origin); | 210 views::View::ConvertPointFromScreen(this, &origin); |
| 132 workarea.Offset(-origin.x(), -origin.y()); | 211 workarea.Offset(-origin.x(), -origin.y()); |
| 133 | 212 |
| 134 rect = rect.Intersect(workarea); | 213 rect = rect.Intersect(workarea); |
| 135 model_view_->SetBoundsRect(rect); | 214 model_view_->SetBoundsRect(rect); |
| 215 } |
| 136 } | 216 } |
| 137 | 217 |
| 138 bool AppListView::OnKeyPressed(const views::KeyEvent& event) { | 218 bool AppListView::OnKeyPressed(const views::KeyEvent& event) { |
| 139 if (event.key_code() == ui::VKEY_ESCAPE) { | 219 if (event.key_code() == ui::VKEY_ESCAPE) { |
| 140 Close(); | 220 Close(); |
| 141 return true; | 221 return true; |
| 142 } | 222 } |
| 143 | 223 |
| 144 return false; | 224 return false; |
| 145 } | 225 } |
| 146 | 226 |
| 147 bool AppListView::OnMousePressed(const views::MouseEvent& event) { | 227 bool AppListView::OnMousePressed(const views::MouseEvent& event) { |
| 148 // If mouse click reaches us, this means user clicks on blank area. So close. | 228 // For full screen mode, if mouse click reaches us, this means user clicks |
| 149 Close(); | 229 // on blank area. So close. |
| 230 if (!bubble_style_) |
| 231 Close(); |
| 150 | 232 |
| 151 return true; | 233 return true; |
| 152 } | 234 } |
| 153 | 235 |
| 154 void AppListView::ButtonPressed(views::Button* sender, | 236 void AppListView::ButtonPressed(views::Button* sender, |
| 155 const views::Event& event) { | 237 const views::Event& event) { |
| 156 if (sender->GetClassName() != AppListItemView::kViewClassName) | 238 if (sender->GetClassName() != AppListItemView::kViewClassName) |
| 157 return; | 239 return; |
| 158 | 240 |
| 159 if (delegate_.get()) { | 241 if (delegate_.get()) { |
| 160 delegate_->OnAppListItemActivated( | 242 delegate_->OnAppListItemActivated( |
| 161 static_cast<AppListItemView*>(sender)->model(), | 243 static_cast<AppListItemView*>(sender)->model(), |
| 162 event.flags()); | 244 event.flags()); |
| 163 } | 245 } |
| 164 Close(); | 246 Close(); |
| 165 } | 247 } |
| 166 | 248 |
| 249 gfx::Rect AppListView::GetBubbleBounds() { |
| 250 // This happens before replacing the default border. |
| 251 if (!bubble_border_) |
| 252 return views::BubbleDelegateView::GetBubbleBounds(); |
| 253 |
| 254 const int old_arrow_offset = bubble_border_->arrow_offset(); |
| 255 const gfx::Rect anchor_rect = GetAnchorRect(); |
| 256 |
| 257 bubble_border_->set_arrow_offset(0); |
| 258 gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds( |
| 259 anchor_rect, |
| 260 GetPreferredSize(), |
| 261 false /* try_mirroring_arrow */); |
| 262 |
| 263 gfx::Rect monitor_rect = gfx::Screen::GetMonitorNearestPoint( |
| 264 anchor_rect.CenterPoint()).work_area(); |
| 265 if (monitor_rect.IsEmpty() || monitor_rect.Contains(bubble_rect)) |
| 266 return bubble_rect; |
| 267 |
| 268 int offset = 0; |
| 269 if (bubble_rect.x() < monitor_rect.x()) |
| 270 offset = monitor_rect.x() - bubble_rect.x(); |
| 271 else if (bubble_rect.right() > monitor_rect.right()) |
| 272 offset = monitor_rect.right() - bubble_rect.right(); |
| 273 |
| 274 bubble_rect.set_x(bubble_rect.x() + offset); |
| 275 |
| 276 // Moves bubble arrow in the opposite direction. i.e. If bubble bounds is |
| 277 // moved to right (positive offset), we need to move arrow to left so that |
| 278 // it points to the same position before the move. |
| 279 bubble_border_->set_arrow_offset(-offset); |
| 280 |
| 281 // Repaints border if arrow offset is changed. |
| 282 if (bubble_border_->arrow_offset() != old_arrow_offset) |
| 283 GetBubbleFrameView()->SchedulePaint(); |
| 284 |
| 285 return bubble_rect; |
| 286 } |
| 287 |
| 167 } // namespace ash | 288 } // namespace ash |
| OLD | NEW |