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

Side by Side Diff: mash/shelf/shelf_view.cc

Issue 1585363002: Fork a subset of ash/shelf for use in mash. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add ui/resources dep; comment out unused constants. Created 4 years, 10 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
« no previous file with comments | « mash/shelf/shelf_view.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "mash/shelf/shelf_view.h" 5 #include "mash/shelf/shelf_view.h"
6 6
7 #include "base/strings/stringprintf.h" 7 #include <algorithm>
8 #include "base/strings/utf_string_conversions.h" 8
9 #include "mojo/common/common_type_converters.h" 9 #include "base/auto_reset.h"
10 #include "mojo/shell/public/cpp/application_impl.h" 10 #include "mash/shelf/shelf_button.h"
11 #include "mash/shelf/shelf_constants.h"
12 #include "ui/accessibility/ax_view_state.h"
13 #include "ui/aura/window.h"
14 #include "ui/aura/window_event_dispatcher.h"
15 #include "ui/base/l10n/l10n_util.h"
16 #include "ui/base/models/simple_menu_model.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "ui/compositor/layer.h"
19 #include "ui/compositor/layer_animator.h"
20 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
21 #include "ui/events/event_utils.h"
11 #include "ui/gfx/canvas.h" 22 #include "ui/gfx/canvas.h"
23 #include "ui/gfx/geometry/point.h"
24 #include "ui/resources/grit/ui_resources.h"
25 #include "ui/views/animation/bounds_animator.h"
26 #include "ui/views/background.h"
27 #include "ui/views/border.h"
28 #include "ui/views/controls/button/image_button.h"
12 #include "ui/views/controls/button/label_button.h" 29 #include "ui/views/controls/button/label_button.h"
13 #include "ui/views/layout/box_layout.h" 30 #include "ui/views/controls/menu/menu_model_adapter.h"
31 #include "ui/views/controls/menu/menu_runner.h"
32 #include "ui/views/focus/focus_search.h"
33 #include "ui/views/view_model_utils.h"
34 #include "ui/views/widget/widget.h"
35 #include "ui/wm/core/coordinate_conversion.h"
14 36
15 namespace mash { 37 namespace mash {
16 namespace shelf { 38 namespace shelf {
17 39
18 ShelfView::ShelfView(mojo::ApplicationImpl* app) : binding_(this) { 40 const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM = 0;
19 app->ConnectToService("mojo:desktop_wm", &user_window_controller_); 41 const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT = 1;
20 42 const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT = 2;
21 user_window_controller_->AddUserWindowObserver( 43 const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT = 3;
22 binding_.CreateInterfacePtrAndBind()); 44
23 45 // Default amount content is inset on the left edge.
24 SetLayoutManager( 46 const int kDefaultLeadingInset = 8;
25 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); 47
26 } 48 // Minimum distance before drag starts.
27 49 const int kMinimumDragDistance = 8;
28 ShelfView::~ShelfView() {} 50
29 51 // The proportion of the shelf space reserved for non-panel icons. Panels
30 size_t ShelfView::GetButtonIndexById(uint32_t window_id) const { 52 // may flow into this space but will be put into the overflow bubble if there
31 for (size_t i = 0; i < open_window_buttons_.size(); ++i) 53 // is contention for the space.
32 if (static_cast<uint32_t>(open_window_buttons_[i]->tag()) == window_id) 54 const float kReservedNonPanelIconProportion = 0.67f;
33 return i; 55
34 return open_window_buttons_.size(); 56 /* TODO(msw): Restore functionality:
35 } 57 // The distance of the cursor from the outer rim of the shelf before it
36 58 // separates.
37 void ShelfView::OnPaint(gfx::Canvas* canvas) { 59 const int kRipOffDistance = 48;
38 canvas->FillRect(GetLocalBounds(), SK_ColorYELLOW); 60
39 views::View::OnPaint(canvas); 61 // The rip off drag and drop proxy image should get scaled by this factor.
62 const float kDragAndDropProxyScale = 1.5f;
63
64 // The opacity represents that this partially disappeared item will get removed.
65 const float kDraggedImageOpacity = 0.5f;*/
66
67 namespace {
68
69 // A class to temporarily disable a given bounds animator.
70 class BoundsAnimatorDisabler {
71 public:
72 explicit BoundsAnimatorDisabler(views::BoundsAnimator* bounds_animator)
73 : old_duration_(bounds_animator->GetAnimationDuration()),
74 bounds_animator_(bounds_animator) {
75 bounds_animator_->SetAnimationDuration(1);
76 }
77
78 ~BoundsAnimatorDisabler() {
79 bounds_animator_->SetAnimationDuration(old_duration_);
80 }
81
82 private:
83 // The previous animation duration.
84 int old_duration_;
85 // The bounds animator which gets used.
86 views::BoundsAnimator* bounds_animator_;
87
88 DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorDisabler);
89 };
90
91 // Custom FocusSearch used to navigate the shelf in the order items are in
92 // the ViewModel.
93 class ShelfFocusSearch : public views::FocusSearch {
94 public:
95 explicit ShelfFocusSearch(views::ViewModel* view_model)
96 : FocusSearch(nullptr, true, true),
97 view_model_(view_model) {}
98 ~ShelfFocusSearch() override {}
99
100 // views::FocusSearch overrides:
101 views::View* FindNextFocusableView(
102 views::View* starting_view,
103 bool reverse,
104 Direction direction,
105 bool check_starting_view,
106 views::FocusTraversable** focus_traversable,
107 views::View** focus_traversable_view) override {
108 int index = view_model_->GetIndexOfView(starting_view);
109 if (index == -1)
110 return view_model_->view_at(0);
111
112 if (reverse) {
113 --index;
114 if (index < 0)
115 index = view_model_->view_size() - 1;
116 } else {
117 ++index;
118 if (index >= view_model_->view_size())
119 index = 0;
120 }
121 return view_model_->view_at(index);
122 }
123
124 private:
125 views::ViewModel* view_model_;
126
127 DISALLOW_COPY_AND_ASSIGN(ShelfFocusSearch);
128 };
129
130 // AnimationDelegate used when inserting a new item. This steadily increases the
131 // opacity of the layer as the animation progress.
132 class FadeInAnimationDelegate : public gfx::AnimationDelegate {
133 public:
134 explicit FadeInAnimationDelegate(views::View* view) : view_(view) {}
135 ~FadeInAnimationDelegate() override {}
136
137 // AnimationDelegate overrides:
138 void AnimationProgressed(const gfx::Animation* animation) override {
139 view_->layer()->SetOpacity(animation->GetCurrentValue());
140 view_->layer()->ScheduleDraw();
141 }
142 void AnimationEnded(const gfx::Animation* animation) override {
143 view_->layer()->SetOpacity(1.0f);
144 view_->layer()->ScheduleDraw();
145 }
146 void AnimationCanceled(const gfx::Animation* animation) override {
147 view_->layer()->SetOpacity(1.0f);
148 view_->layer()->ScheduleDraw();
149 }
150
151 private:
152 views::View* view_;
153
154 DISALLOW_COPY_AND_ASSIGN(FadeInAnimationDelegate);
155 };
156
157 void ReflectItemStatus(const ShelfItem& item, ShelfButton* button) {
158 switch (item.status) {
159 case STATUS_CLOSED:
160 button->ClearState(ShelfButton::STATE_ACTIVE);
161 button->ClearState(ShelfButton::STATE_RUNNING);
162 button->ClearState(ShelfButton::STATE_ATTENTION);
163 break;
164 case STATUS_RUNNING:
165 button->ClearState(ShelfButton::STATE_ACTIVE);
166 button->AddState(ShelfButton::STATE_RUNNING);
167 button->ClearState(ShelfButton::STATE_ATTENTION);
168 break;
169 case STATUS_ACTIVE:
170 button->AddState(ShelfButton::STATE_ACTIVE);
171 button->ClearState(ShelfButton::STATE_RUNNING);
172 button->ClearState(ShelfButton::STATE_ATTENTION);
173 break;
174 case STATUS_ATTENTION:
175 button->ClearState(ShelfButton::STATE_ACTIVE);
176 button->ClearState(ShelfButton::STATE_RUNNING);
177 button->AddState(ShelfButton::STATE_ATTENTION);
178 break;
179 }
180 }
181
182 } // namespace
183
184 // AnimationDelegate used when deleting an item. This steadily decreased the
185 // opacity of the layer as the animation progress.
186 class ShelfView::FadeOutAnimationDelegate : public gfx::AnimationDelegate {
187 public:
188 FadeOutAnimationDelegate(ShelfView* host, views::View* view)
189 : shelf_view_(host),
190 view_(view) {}
191 ~FadeOutAnimationDelegate() override {}
192
193 // AnimationDelegate overrides:
194 void AnimationProgressed(const gfx::Animation* animation) override {
195 view_->layer()->SetOpacity(1 - animation->GetCurrentValue());
196 view_->layer()->ScheduleDraw();
197 }
198 void AnimationEnded(const gfx::Animation* animation) override {
199 shelf_view_->OnFadeOutAnimationEnded();
200 }
201 void AnimationCanceled(const gfx::Animation* animation) override {}
202
203 private:
204 ShelfView* shelf_view_;
205 scoped_ptr<views::View> view_;
206
207 DISALLOW_COPY_AND_ASSIGN(FadeOutAnimationDelegate);
208 };
209
210 // AnimationDelegate used to trigger fading an element in. When an item is
211 // inserted this delegate is attached to the animation that expands the size of
212 // the item. When done it kicks off another animation to fade the item in.
213 class ShelfView::StartFadeAnimationDelegate : public gfx::AnimationDelegate {
214 public:
215 StartFadeAnimationDelegate(ShelfView* host, views::View* view)
216 : shelf_view_(host),
217 view_(view) {}
218 ~StartFadeAnimationDelegate() override {}
219
220 // AnimationDelegate overrides:
221 void AnimationEnded(const gfx::Animation* animation) override {
222 shelf_view_->FadeIn(view_);
223 }
224 void AnimationCanceled(const gfx::Animation* animation) override {
225 view_->layer()->SetOpacity(1.0f);
226 }
227
228 private:
229 ShelfView* shelf_view_;
230 views::View* view_;
231
232 DISALLOW_COPY_AND_ASSIGN(StartFadeAnimationDelegate);
233 };
234
235 ShelfView::ShelfView(mojo::ApplicationImpl* app)
236 : app_(app),
237 model_(app),
238 alignment_(SHELF_ALIGNMENT_BOTTOM),
239 first_visible_index_(0),
240 last_visible_index_(-1),
241 /* TODO(msw): Restore functionality:
242 overflow_button_(nullptr),
243 owner_overflow_bubble_(nullptr),*/
244 tooltip_(this),
245 drag_pointer_(NONE),
246 drag_view_(nullptr),
247 start_drag_index_(-1),
248 context_menu_id_(0),
249 leading_inset_(kDefaultLeadingInset),
250 cancelling_drag_model_changed_(false),
251 last_hidden_index_(0),
252 closing_event_time_(),
253 got_deleted_(nullptr),
254 drag_and_drop_item_pinned_(false),
255 drag_and_drop_shelf_id_(0),
256 drag_replaced_view_(nullptr),
257 dragged_off_shelf_(false),
258 snap_back_from_rip_off_view_(nullptr),
259 /* TODO(msw): Restore functionality:
260 item_manager_(Shell::GetInstance()->shelf_item_delegate_manager()),*/
261 overflow_mode_(false),
262 main_shelf_(nullptr),
263 dragged_off_from_overflow_to_shelf_(false),
264 is_repost_event_(false),
265 last_pressed_index_(-1) {
266 bounds_animator_.reset(new views::BoundsAnimator(this));
267 bounds_animator_->AddObserver(this);
268 set_context_menu_controller(this);
269 focus_search_.reset(new ShelfFocusSearch(&view_model_));
270
271 model_.AddObserver(this);
272 const ShelfItems& items(model_.items());
273 for (ShelfItems::const_iterator i = items.begin(); i != items.end(); ++i) {
274 views::View* child = CreateViewForItem(*i);
275 view_model_.Add(child, static_cast<int>(i - items.begin()));
276 AddChildView(child);
277 }
278
279 /* TODO(msw): Restore functionality:
280 overflow_button_ = new OverflowButton(this);
281 overflow_button_->set_context_menu_controller(this);
282 ConfigureChildView(overflow_button_);
283 AddChildView(overflow_button_);*/
284
285 /* TODO(msw): Add a stub apps button?
286 ShelfItem app_list;
287 app_list.type = TYPE_APP_LIST;
288 app_list.title = base::ASCIIToUTF16("APPS");
289 model()->Add(app_list);*/
290
291 // TODO(msw): Needed to paint children as layers???
292 SetPaintToLayer(true);
293 set_background(views::Background::CreateSolidBackground(SK_ColorYELLOW));
294
295 // We'll layout when our bounds change.
296 }
297
298 ShelfView::~ShelfView() {
299 bounds_animator_->RemoveObserver(this);
300 model_.RemoveObserver(this);
301 // If we are inside the MenuRunner, we need to know if we were getting
302 // deleted while it was running.
303 if (got_deleted_)
304 *got_deleted_ = true;
305 }
306
307 void ShelfView::SetAlignment(ShelfAlignment alignment) {
308 if (alignment_ == alignment)
309 return;
310
311 alignment_ = alignment;
312 /* TODO(msw): Restore functionality:
313 overflow_button_->OnShelfAlignmentChanged();*/
314 LayoutToIdealBounds();
315 for (int i = 0; i < view_model_.view_size(); ++i) {
316 if (i >= first_visible_index_ && i <= last_visible_index_)
317 view_model_.view_at(i)->Layout();
318 }
319 tooltip_.Close();
320 /* TODO(msw): Restore functionality:
321 if (overflow_bubble_)
322 overflow_bubble_->Hide();*/
323 }
324
325 void ShelfView::SchedulePaintForAllButtons() {
326 for (int i = 0; i < view_model_.view_size(); ++i) {
327 if (i >= first_visible_index_ && i <= last_visible_index_)
328 view_model_.view_at(i)->SchedulePaint();
329 }
330 /* TODO(msw): Restore functionality:
331 if (overflow_button_ && overflow_button_->visible())
332 overflow_button_->SchedulePaint();*/
333 }
334
335 gfx::Rect ShelfView::GetIdealBoundsOfItemIcon(ShelfID id) {
336 int index = model_.ItemIndexByID(id);
337 if (index == -1)
338 return gfx::Rect();
339 // Map all items from overflow area to the overflow button. Note that the
340 // section between last_index_hidden_ and model_.FirstPanelIndex() is the
341 // list of invisible panel items. However, these items are currently nowhere
342 // represented and get dropped instead - see (crbug.com/378907). As such there
343 // is no way to address them or place them. We therefore move them over the
344 // overflow button.
345 if (index > last_visible_index_ && index < model_.FirstPanelIndex())
346 index = last_visible_index_ + 1;
347 const gfx::Rect& ideal_bounds(view_model_.ideal_bounds(index));
348 DCHECK_NE(TYPE_APP_LIST, model_.items()[index].type);
349 views::View* view = view_model_.view_at(index);
350 CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName());
351 ShelfButton* button = static_cast<ShelfButton*>(view);
352 gfx::Rect icon_bounds = button->GetIconBounds();
353 return gfx::Rect(GetMirroredXWithWidthInView(
354 ideal_bounds.x() + icon_bounds.x(), icon_bounds.width()),
355 ideal_bounds.y() + icon_bounds.y(),
356 icon_bounds.width(),
357 icon_bounds.height());
358 }
359
360 void ShelfView::UpdatePanelIconPosition(ShelfID id,
361 const gfx::Point& midpoint) {
362 int current_index = model_.ItemIndexByID(id);
363 int first_panel_index = model_.FirstPanelIndex();
364 if (current_index < first_panel_index)
365 return;
366
367 gfx::Point midpoint_in_view(GetMirroredXInView(midpoint.x()),
368 midpoint.y());
369 int target_index = current_index;
370 while (target_index > first_panel_index &&
371 PrimaryAxisValue(view_model_.ideal_bounds(target_index).x(),
372 view_model_.ideal_bounds(target_index).y()) >
373 PrimaryAxisValue(midpoint_in_view.x(),
374 midpoint_in_view.y())) {
375 --target_index;
376 }
377 while (target_index < view_model_.view_size() - 1 &&
378 PrimaryAxisValue(view_model_.ideal_bounds(target_index).right(),
379 view_model_.ideal_bounds(target_index).bottom()) <
380 PrimaryAxisValue(midpoint_in_view.x(),
381 midpoint_in_view.y())) {
382 ++target_index;
383 }
384 if (current_index != target_index)
385 model_.Move(current_index, target_index);
386 }
387
388 bool ShelfView::IsShowingMenu() const {
389 return (launcher_menu_runner_.get() &&
390 launcher_menu_runner_->IsRunning());
391 }
392
393 bool ShelfView::IsShowingOverflowBubble() const {
394 /* TODO(msw): Restore functionality:
395 return overflow_bubble_.get() && overflow_bubble_->IsShowing();*/
396 return false;
397 }
398
399 views::View* ShelfView::GetAppListButtonView() const {
400 for (int i = 0; i < model_.item_count(); ++i) {
401 if (model_.items()[i].type == TYPE_APP_LIST)
402 return view_model_.view_at(i);
403 }
404
405 NOTREACHED() << "Applist button not found";
406 return nullptr;
407 }
408
409 ////////////////////////////////////////////////////////////////////////////////
410 // ShelfView, FocusTraversable implementation:
411
412 views::FocusSearch* ShelfView::GetFocusSearch() {
413 return focus_search_.get();
414 }
415
416 views::FocusTraversable* ShelfView::GetFocusTraversableParent() {
417 return parent()->GetFocusTraversable();
418 }
419
420 views::View* ShelfView::GetFocusTraversableParentView() {
421 return this;
422 }
423
424 /* TODO(msw): Restore drag/drop functionality.
425 void ShelfView::CreateDragIconProxy(
426 const gfx::Point& location_in_screen_coordinates,
427 const gfx::ImageSkia& icon,
428 views::View* replaced_view,
429 const gfx::Vector2d& cursor_offset_from_center,
430 float scale_factor) {
431 drag_replaced_view_ = replaced_view;
432 drag_image_.reset(new ash::DragImageView(
433 drag_replaced_view_->GetWidget()->GetNativeWindow()->GetRootWindow(),
434 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE));
435 drag_image_->SetImage(icon);
436 gfx::Size size = drag_image_->GetPreferredSize();
437 size.set_width(size.width() * scale_factor);
438 size.set_height(size.height() * scale_factor);
439 drag_image_offset_ = gfx::Vector2d(size.width() / 2, size.height() / 2) +
440 cursor_offset_from_center;
441 gfx::Rect drag_image_bounds(
442 location_in_screen_coordinates - drag_image_offset_,
443 size);
444 drag_image_->SetBoundsInScreen(drag_image_bounds);
445 drag_image_->SetWidgetVisible(true);
446 }
447
448 void ShelfView::UpdateDragIconProxy(
449 const gfx::Point& location_in_screen_coordinates) {
450 // TODO(jennyz): Investigate why drag_image_ becomes NULL at this point per
451 // crbug.com/34722, while the app list item is still being dragged around.
452 if (drag_image_) {
453 drag_image_->SetScreenPosition(
454 location_in_screen_coordinates - drag_image_offset_);
455 }
456 }
457
458 void ShelfView::DestroyDragIconProxy() {
459 drag_image_.reset();
460 drag_image_offset_ = gfx::Vector2d(0, 0);
461 }
462
463 bool ShelfView::StartDrag(const std::string& app_id,
464 const gfx::Point& location_in_screen_coordinates) {
465 // Bail if an operation is already going on - or the cursor is not inside.
466 // This could happen if mouse / touch operations overlap.
467 if (drag_and_drop_shelf_id_ ||
468 !GetBoundsInScreen().Contains(location_in_screen_coordinates))
469 return false;
470
471 // If the AppsGridView (which was dispatching this event) was opened by our
472 // button, ShelfView dragging operations are locked and we have to unlock.
473 CancelDrag(-1);
474 drag_and_drop_item_pinned_ = false;
475 drag_and_drop_app_id_ = app_id;
476 drag_and_drop_shelf_id_ =
477 delegate_->GetShelfIDForAppID(drag_and_drop_app_id_);
478 // Check if the application is known and pinned - if not, we have to pin it so
479 // that we can re-arrange the shelf order accordingly. Note that items have
480 // to be pinned to give them the same (order) possibilities as a shortcut.
481 // When an item is dragged from overflow to shelf, IsShowingOverflowBubble()
482 // returns true. At this time, we don't need to pin the item.
483 if (!IsShowingOverflowBubble() &&
484 (!drag_and_drop_shelf_id_ ||
485 !delegate_->IsAppPinned(app_id))) {
486 delegate_->PinAppWithID(app_id);
487 drag_and_drop_shelf_id_ =
488 delegate_->GetShelfIDForAppID(drag_and_drop_app_id_);
489 if (!drag_and_drop_shelf_id_)
490 return false;
491 drag_and_drop_item_pinned_ = true;
492 }
493 views::View* drag_and_drop_view = view_model_->view_at(
494 model_.ItemIndexByID(drag_and_drop_shelf_id_));
495 DCHECK(drag_and_drop_view);
496
497 // Since there is already an icon presented by the caller, we hide this item
498 // for now. That has to be done by reducing the size since the visibility will
499 // change once a regrouping animation is performed.
500 pre_drag_and_drop_size_ = drag_and_drop_view->size();
501 drag_and_drop_view->SetSize(gfx::Size());
502
503 // First we have to center the mouse cursor over the item.
504 gfx::Point pt = drag_and_drop_view->GetBoundsInScreen().CenterPoint();
505 views::View::ConvertPointFromScreen(drag_and_drop_view, &pt);
506 gfx::Point point_in_root = location_in_screen_coordinates;
507 ::wm::ConvertPointFromScreen(
508 ash::wm::GetRootWindowAt(location_in_screen_coordinates), &point_in_root);
509 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, pt, point_in_root,
510 ui::EventTimeForNow(), 0, 0);
511 PointerPressedOnButton(drag_and_drop_view,
512 ShelfButtonHost::DRAG_AND_DROP,
513 event);
514
515 // Drag the item where it really belongs.
516 Drag(location_in_screen_coordinates);
517 return true;
518 }
519
520 bool ShelfView::Drag(const gfx::Point& location_in_screen_coordinates) {
521 if (!drag_and_drop_shelf_id_ ||
522 !GetBoundsInScreen().Contains(location_in_screen_coordinates))
523 return false;
524
525 gfx::Point pt = location_in_screen_coordinates;
526 views::View* drag_and_drop_view = view_model_->view_at(
527 model_.ItemIndexByID(drag_and_drop_shelf_id_));
528 ConvertPointFromScreen(drag_and_drop_view, &pt);
529 gfx::Point point_in_root = location_in_screen_coordinates;
530 ::wm::ConvertPointFromScreen(
531 ash::wm::GetRootWindowAt(location_in_screen_coordinates), &point_in_root);
532 ui::MouseEvent event(ui::ET_MOUSE_DRAGGED, pt, point_in_root,
533 ui::EventTimeForNow(), 0, 0);
534 PointerDraggedOnButton(drag_and_drop_view,
535 ShelfButtonHost::DRAG_AND_DROP,
536 event);
537 return true;
538 }
539
540 void ShelfView::EndDrag(bool cancel) {
541 if (!drag_and_drop_shelf_id_)
542 return;
543
544 views::View* drag_and_drop_view = view_model_->view_at(
545 model_.ItemIndexByID(drag_and_drop_shelf_id_));
546 PointerReleasedOnButton(
547 drag_and_drop_view, ShelfButtonHost::DRAG_AND_DROP, cancel);
548
549 // Either destroy the temporarily created item - or - make the item visible.
550 if (drag_and_drop_item_pinned_ && cancel) {
551 delegate_->UnpinAppWithID(drag_and_drop_app_id_);
552 } else if (drag_and_drop_view) {
553 if (cancel) {
554 // When a hosted drag gets canceled, the item can remain in the same slot
555 // and it might have moved within the bounds. In that case the item need
556 // to animate back to its correct location.
557 AnimateToIdealBounds();
558 } else {
559 drag_and_drop_view->SetSize(pre_drag_and_drop_size_);
560 }
561 }
562
563 drag_and_drop_shelf_id_ = 0;
564 }*/
565
566 void ShelfView::LayoutToIdealBounds() {
567 if (bounds_animator_->IsAnimating()) {
568 AnimateToIdealBounds();
569 return;
570 }
571
572 CalculateIdealBounds();
573 /* TODO(msw): Restore functionality:
574 gfx::Rect overflow_bounds = CalculateIdealBounds();*/
575 views::ViewModelUtils::SetViewBoundsToIdealBounds(view_model_);
576 /* TODO(msw): Restore functionality:
577 overflow_button_->SetBoundsRect(overflow_bounds);*/
578 }
579
580 void ShelfView::UpdateAllButtonsVisibilityInOverflowMode() {
581 // The overflow button is not shown in overflow mode.
582 /* TODO(msw): Restore functionality:
583 overflow_button_->SetVisible(false);*/
584 DCHECK_LT(last_visible_index_, view_model_.view_size());
585 for (int i = 0; i < view_model_.view_size(); ++i) {
586 bool visible = i >= first_visible_index_ &&
587 i <= last_visible_index_;
588 // To track the dragging of |drag_view_| continuously, its visibility
589 // should be always true regardless of its position.
590 if (dragged_off_from_overflow_to_shelf_ &&
591 view_model_.view_at(i) == drag_view_)
592 view_model_.view_at(i)->SetVisible(true);
593 else
594 view_model_.view_at(i)->SetVisible(visible);
595 }
596 }
597
598 gfx::Rect ShelfView::CalculateIdealBounds() {
599 int available_size = PrimaryAxisValue(width(), height());
600 DCHECK_EQ(model_.item_count(), view_model_.view_size());
601 if (!available_size || model_.items().empty())
602 return gfx::Rect();
603
604 int x = 0;
605 int y = 0;
606 int button_size = kShelfButtonSize;
607 int button_spacing = kShelfButtonSpacing;
608
609 int w = PrimaryAxisValue(button_size, width());
610 int h = PrimaryAxisValue(height(), button_size);
611 for (int i = 0; i < view_model_.view_size(); ++i) {
612 if (i < first_visible_index_) {
613 view_model_.set_ideal_bounds(i, gfx::Rect(x, y, 0, 0));
614 continue;
615 }
616
617 view_model_.set_ideal_bounds(i, gfx::Rect(x, y, w, h));
618 x = PrimaryAxisValue(x + w + button_spacing, x);
619 y = PrimaryAxisValue(y, y + h + button_spacing);
620 }
621
622 if (is_overflow_mode()) {
623 UpdateAllButtonsVisibilityInOverflowMode();
624 return gfx::Rect();
625 }
626
627 // Right aligned icons.
628 int end_position = available_size - button_spacing;
629 x = PrimaryAxisValue(end_position, 0);
630 y = PrimaryAxisValue(0, end_position);
631 int first_panel_index = model_.FirstPanelIndex();
632 for (int i = view_model_.view_size() - 1; i >= first_panel_index; --i) {
633 x = PrimaryAxisValue(x - w - button_spacing, x);
634 y = PrimaryAxisValue(y, y - h - button_spacing);
635 view_model_.set_ideal_bounds(i, gfx::Rect(x, y, w, h));
636 end_position = PrimaryAxisValue(x, y);
637 }
638
639 int last_button_index = first_panel_index - 1;
640 if (last_button_index < 0)
641 return gfx::Rect();
642
643 // Icons on the left / top are guaranteed up to kLeftIconProportion of
644 // the available space.
645 int last_icon_position = PrimaryAxisValue(
646 view_model_.ideal_bounds(last_button_index).right(),
647 view_model_.ideal_bounds(last_button_index).bottom()) + button_size;
648 int reserved_icon_space = available_size * kReservedNonPanelIconProportion;
649 if (last_icon_position < reserved_icon_space)
650 end_position = last_icon_position;
651 else
652 end_position = std::max(end_position, reserved_icon_space);
653
654 gfx::Rect overflow_bounds(PrimaryAxisValue(w, width()),
655 PrimaryAxisValue(height(), h));
656
657 last_visible_index_ = DetermineLastVisibleIndex(end_position - button_size);
658 last_hidden_index_ = DetermineFirstVisiblePanelIndex(end_position) - 1;
659 bool show_overflow = last_visible_index_ < last_button_index ||
660 last_hidden_index_ >= first_panel_index;
661
662 // Create Space for the overflow button
663 if (show_overflow) {
664 // The following code makes sure that platform apps icons (aligned to left /
665 // top) are favored over panel apps icons (aligned to right / bottom).
666 if (last_visible_index_ > 0 && last_visible_index_ < last_button_index) {
667 // This condition means that we will take one platform app and replace it
668 // with the overflow button and put the app in the overflow bubble.
669 // This happens when the space needed for platform apps exceeds the
670 // reserved area for non-panel icons,
671 // (i.e. |last_icon_position| > |reserved_icon_space|).
672 --last_visible_index_;
673 } else if (last_hidden_index_ >= first_panel_index &&
674 last_hidden_index_ < view_model_.view_size() - 1) {
675 // This condition means that we will take a panel app icon and replace it
676 // with the overflow button.
677 // This happens when there is still room for platform apps in the reserved
678 // area for non-panel icons,
679 // (i.e. |last_icon_position| < |reserved_icon_space|).
680 ++last_hidden_index_;
681 }
682 }
683
684 for (int i = 0; i < view_model_.view_size(); ++i) {
685 bool visible = i <= last_visible_index_ || i > last_hidden_index_;
686 // To receive drag event continuously from |drag_view_| during the dragging
687 // off from the shelf, don't make |drag_view_| invisible. It will be
688 // eventually invisible and removed from the |view_model_| by
689 // FinalizeRipOffDrag().
690 if (dragged_off_shelf_ && view_model_.view_at(i) == drag_view_)
691 continue;
692 view_model_.view_at(i)->SetVisible(visible);
693 }
694
695 /* TODO(msw): Restore functionality:
696 overflow_button_->SetVisible(show_overflow);*/
697 if (show_overflow) {
698 DCHECK_NE(0, view_model_.view_size());
699 if (last_visible_index_ == -1) {
700 x = 0;
701 y = 0;
702 } else {
703 x = PrimaryAxisValue(
704 view_model_.ideal_bounds(last_visible_index_).right(),
705 view_model_.ideal_bounds(last_visible_index_).x());
706 y = PrimaryAxisValue(
707 view_model_.ideal_bounds(last_visible_index_).y(),
708 view_model_.ideal_bounds(last_visible_index_).bottom());
709 }
710 // Set all hidden panel icon positions to be on the overflow button.
711 for (int i = first_panel_index; i <= last_hidden_index_; ++i)
712 view_model_.set_ideal_bounds(i, gfx::Rect(x, y, w, h));
713
714 // Add more space between last visible item and overflow button.
715 // Without this, two buttons look too close compared with other items.
716 x = PrimaryAxisValue(x + button_spacing, x);
717 y = PrimaryAxisValue(y, y + button_spacing);
718
719 overflow_bounds.set_x(x);
720 overflow_bounds.set_y(y);
721 /* TODO(msw): Restore functionality:
722 if (overflow_bubble_.get() && overflow_bubble_->IsShowing())
723 UpdateOverflowRange(overflow_bubble_->shelf_view());*/
724 } else {
725 /* TODO(msw): Restore functionality:
726 if (overflow_bubble_)
727 overflow_bubble_->Hide();*/
728 }
729 return overflow_bounds;
730 }
731
732 int ShelfView::DetermineLastVisibleIndex(int max_value) const {
733 int index = model_.FirstPanelIndex() - 1;
734 while (index >= 0 &&
735 PrimaryAxisValue(
736 view_model_.ideal_bounds(index).right(),
737 view_model_.ideal_bounds(index).bottom()) > max_value) {
738 index--;
739 }
740 return index;
741 }
742
743 int ShelfView::DetermineFirstVisiblePanelIndex(int min_value) const {
744 int index = model_.FirstPanelIndex();
745 while (index < view_model_.view_size() &&
746 PrimaryAxisValue(
747 view_model_.ideal_bounds(index).right(),
748 view_model_.ideal_bounds(index).bottom()) < min_value) {
749 ++index;
750 }
751 return index;
752 }
753
754 /* TODO(msw): Restore functionality:
755 void ShelfView::AddIconObserver(ShelfIconObserver* observer) {
756 observers_.AddObserver(observer);
757 }
758
759 void ShelfView::RemoveIconObserver(ShelfIconObserver* observer) {
760 observers_.RemoveObserver(observer);
761 }*/
762
763 void ShelfView::AnimateToIdealBounds() {
764 /* TODO(msw): Restore functionality:
765 gfx::Rect overflow_bounds = CalculateIdealBounds();*/
766 CalculateIdealBounds();
767 for (int i = 0; i < view_model_.view_size(); ++i) {
768 views::View* view = view_model_.view_at(i);
769 bounds_animator_->AnimateViewTo(view, view_model_.ideal_bounds(i));
770 // Now that the item animation starts, we have to make sure that the
771 // padding of the first gets properly transferred to the new first item.
772 if (i && view->border())
773 view->SetBorder(views::Border::NullBorder());
774 }
775 /* TODO(msw): Restore functionality:
776 overflow_button_->SetBoundsRect(overflow_bounds);*/
777 }
778
779 views::View* ShelfView::CreateViewForItem(const ShelfItem& item) {
780 views::View* view = nullptr;
781 switch (item.type) {
782 case TYPE_BROWSER_SHORTCUT:
783 case TYPE_APP_SHORTCUT:
784 case TYPE_WINDOWED_APP:
785 case TYPE_PLATFORM_APP:
786 case TYPE_DIALOG:
787 case TYPE_APP_PANEL: {
788 ShelfButton* button = ShelfButton::Create(this, this);
789 button->SetImage(item.image);
790 ReflectItemStatus(item, button);
791 view = button;
792 break;
793 }
794
795 case TYPE_APP_LIST: {
796 /* TODO(msw): Restore functionality:
797 view = new AppListButton(this, this);*/
798 view = new views::LabelButton(nullptr, item.title);
799 break;
800 }
801
802 case TYPE_MOJO_APP: {
803 // TODO(msw): Support item images, etc.
804 ShelfButton* button = ShelfButton::Create(this, this);
805 int image_resource_id = IDR_DEFAULT_FAVICON;
806 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
807 button->SetImage(*rb.GetImageSkiaNamed(image_resource_id));
808 ReflectItemStatus(item, button);
809 view = button;
810 break;
811 }
812
813 default:
814 break;
815 }
816 view->set_context_menu_controller(this);
817
818 DCHECK(view);
819 ConfigureChildView(view);
820 return view;
821 }
822
823 void ShelfView::FadeIn(views::View* view) {
824 view->SetVisible(true);
825 view->layer()->SetOpacity(0);
826 AnimateToIdealBounds();
827 bounds_animator_->SetAnimationDelegate(
828 view,
829 scoped_ptr<gfx::AnimationDelegate>(new FadeInAnimationDelegate(view)));
830 }
831
832 void ShelfView::PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event) {
833 DCHECK(!dragging());
834 DCHECK(drag_view_);
835 drag_pointer_ = pointer;
836 start_drag_index_ = view_model_.GetIndexOfView(drag_view_);
837
838 if (start_drag_index_== -1) {
839 CancelDrag(-1);
840 return;
841 }
842
843 // If the item is no longer draggable, bail out.
844 /* TODO(msw): Restore functionality:
845 ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
846 model_.items()[start_drag_index_].id);
847 if (!item_delegate->IsDraggable()) {
848 CancelDrag(-1);
849 return;
850 }*/
851
852 // Move the view to the front so that it appears on top of other views.
853 ReorderChildView(drag_view_, -1);
854 bounds_animator_->StopAnimatingView(drag_view_);
855 }
856
857 void ShelfView::ContinueDrag(const ui::LocatedEvent& event) {
858 // Due to a syncing operation the application might have been removed.
859 // Bail if it is gone.
860 int current_index = view_model_.GetIndexOfView(drag_view_);
861 DCHECK_NE(-1, current_index);
862
863 /* TODO(msw): Restore functionality:
864 ShelfItemDelegate* item_delegate =
865 item_manager_->GetShelfItemDelegate(model_.items()[current_index].id);
866 if (!item_delegate->IsDraggable()) {
867 CancelDrag(-1);
868 return;
869 }*/
870
871 // If this is not a drag and drop host operation and not the app list item,
872 // check if the item got ripped off the shelf - if it did we are done.
873 if (!drag_and_drop_shelf_id_ &&
874 RemovableByRipOff(current_index) != NOT_REMOVABLE) {
875 if (HandleRipOffDrag(event))
876 return;
877 // The rip off handler could have changed the location of the item.
878 current_index = view_model_.GetIndexOfView(drag_view_);
879 }
880
881 // TODO: I don't think this works correctly with RTL.
882 gfx::Point drag_point(event.location());
883 ConvertPointToTarget(drag_view_, this, &drag_point);
884
885 // Constrain the location to the range of valid indices for the type.
886 std::pair<int, int> indices(GetDragRange(current_index));
887 int first_drag_index = indices.first;
888 int last_drag_index = indices.second;
889 // If the last index isn't valid, we're overflowing. Constrain to the app list
890 // (which is the last visible item).
891 if (first_drag_index < model_.FirstPanelIndex() &&
892 last_drag_index > last_visible_index_)
893 last_drag_index = last_visible_index_;
894 int x = 0, y = 0;
895 if (IsHorizontalAlignment()) {
896 x = std::max(view_model_.ideal_bounds(indices.first).x(),
897 drag_point.x() - drag_origin_.x());
898 x = std::min(view_model_.ideal_bounds(last_drag_index).right() -
899 view_model_.ideal_bounds(current_index).width(),
900 x);
901 if (drag_view_->x() == x)
902 return;
903 drag_view_->SetX(x);
904 } else {
905 y = std::max(view_model_.ideal_bounds(indices.first).y(),
906 drag_point.y() - drag_origin_.y());
907 y = std::min(view_model_.ideal_bounds(last_drag_index).bottom() -
908 view_model_.ideal_bounds(current_index).height(),
909 y);
910 if (drag_view_->y() == y)
911 return;
912 drag_view_->SetY(y);
913 }
914
915 int target_index =
916 views::ViewModelUtils::DetermineMoveIndex(
917 view_model_, drag_view_,
918 IsHorizontalAlignment() ? views::ViewModelUtils::HORIZONTAL :
919 views::ViewModelUtils::VERTICAL,
920 x, y);
921 target_index =
922 std::min(indices.second, std::max(target_index, indices.first));
923
924 int first_draggable_item = 0;
925 /* TODO(msw): Restore functionality:
926 while (first_draggable_item < static_cast<int>(model_.items().size()) &&
927 !item_manager_->GetShelfItemDelegate(
928 model_.items()[first_draggable_item].id)->IsDraggable()) {
929 first_draggable_item++;
930 }*/
931
932 target_index = std::max(target_index, first_draggable_item);
933
934 if (target_index == current_index)
935 return;
936
937 // Change the model, the ShelfItemMoved() callback will handle the
938 // |view_model_| update.
939 model_.Move(current_index, target_index);
940 bounds_animator_->StopAnimatingView(drag_view_);
941 }
942
943 bool ShelfView::HandleRipOffDrag(const ui::LocatedEvent& event) {
944 /* TODO(msw): Restore functionality:
945 int current_index = view_model_.GetIndexOfView(drag_view_);
946 DCHECK_NE(-1, current_index);
947 std::string dragged_app_id =
948 delegate_->GetAppIDForShelfID(model_.items()[current_index].id);
949
950 gfx::Point screen_location = event.root_location();
951 views::View::ConvertPointToScreen(this, &screen_location);
952
953 // To avoid ugly forwards and backwards flipping we use different constants
954 // for ripping off / re-inserting the items.
955 if (dragged_off_shelf_) {
956 // If the shelf/overflow bubble bounds contains |screen_location| we insert
957 // the item back into the shelf.
958 if (GetBoundsForDragInsertInScreen().Contains(screen_location)) {
959 if (dragged_off_from_overflow_to_shelf_) {
960 // During the dragging an item from Shelf to Overflow, it can enter here
961 // directly because both are located very closly.
962 main_shelf_->EndDrag(true);
963 // Stops the animation of |drag_view_| and sets its bounds explicitly
964 // becase ContinueDrag() stops its animation. Without this, unexpected
965 // bounds will be set.
966 bounds_animator_->StopAnimatingView(drag_view_);
967 int drag_view_index = view_model_.GetIndexOfView(drag_view_);
968 drag_view_->SetBoundsRect(view_model_.ideal_bounds(drag_view_index));
969 dragged_off_from_overflow_to_shelf_ = false;
970 }
971 // Destroy our proxy view item.
972 DestroyDragIconProxy();
973 // Re-insert the item and return simply false since the caller will handle
974 // the move as in any normal case.
975 dragged_off_shelf_ = false;
976 drag_view_->layer()->SetOpacity(1.0f);
977 // The size of Overflow bubble should be updated immediately when an item
978 // is re-inserted.
979 if (is_overflow_mode())
980 PreferredSizeChanged();
981 return false;
982 } else if (is_overflow_mode() &&
983 main_shelf_->GetBoundsForDragInsertInScreen().Contains(
984 screen_location)) {
985 if (!dragged_off_from_overflow_to_shelf_) {
986 dragged_off_from_overflow_to_shelf_ = true;
987 drag_image_->SetOpacity(1.0f);
988 main_shelf_->StartDrag(dragged_app_id, screen_location);
989 } else {
990 main_shelf_->Drag(screen_location);
991 }
992 } else if (dragged_off_from_overflow_to_shelf_) {
993 // Makes the |drag_image_| partially disappear again.
994 dragged_off_from_overflow_to_shelf_ = false;
995 drag_image_->SetOpacity(kDraggedImageOpacity);
996 main_shelf_->EndDrag(true);
997 bounds_animator_->StopAnimatingView(drag_view_);
998 int drag_view_index = view_model_.GetIndexOfView(drag_view_);
999 drag_view_->SetBoundsRect(view_model_.ideal_bounds(drag_view_index));
1000 }
1001 // Move our proxy view item.
1002 UpdateDragIconProxy(screen_location);
1003 return true;
1004 }
1005 // Check if we are too far away from the shelf to enter the ripped off state.
1006 // Determine the distance to the shelf.
1007 int delta = CalculateShelfDistance(screen_location);
1008 if (delta > kRipOffDistance) {
1009 // Create a proxy view item which can be moved anywhere.
1010 CreateDragIconProxy(event.root_location(),
1011 drag_view_->GetImage(),
1012 drag_view_,
1013 gfx::Vector2d(0, 0),
1014 kDragAndDropProxyScale);
1015 drag_view_->layer()->SetOpacity(0.0f);
1016 dragged_off_shelf_ = true;
1017 if (RemovableByRipOff(current_index) == REMOVABLE) {
1018 // Move the item to the front of the first panel item and hide it.
1019 // ShelfItemMoved() callback will handle the |view_model_| update and
1020 // call AnimateToIdealBounds().
1021 if (current_index != model_.FirstPanelIndex() - 1) {
1022 model_.Move(current_index, model_.FirstPanelIndex() - 1);
1023 StartFadeInLastVisibleItem();
1024 } else if (is_overflow_mode()) {
1025 // Overflow bubble should be shrunk when an item is ripped off.
1026 PreferredSizeChanged();
1027 }
1028 // Make the item partially disappear to show that it will get removed if
1029 // dropped.
1030 drag_image_->SetOpacity(kDraggedImageOpacity);
1031 }
1032 return true;
1033 }*/
1034 return false;
1035 }
1036
1037 void ShelfView::FinalizeRipOffDrag(bool cancel) {
1038 /* TODO(msw): Restore functionality:
1039 if (!dragged_off_shelf_)
1040 return;
1041 // Make sure we do not come in here again.
1042 dragged_off_shelf_ = false;
1043
1044 // Coming here we should always have a |drag_view_|.
1045 DCHECK(drag_view_);
1046 int current_index = view_model_.GetIndexOfView(drag_view_);
1047 // If the view isn't part of the model anymore (|current_index| == -1), a sync
1048 // operation must have removed it. In that case we shouldn't change the model
1049 // and only delete the proxy image.
1050 if (current_index == -1) {
1051 DestroyDragIconProxy();
1052 return;
1053 }
1054
1055 // Set to true when the animation should snap back to where it was before.
1056 bool snap_back = false;
1057 // Items which cannot be dragged off will be handled as a cancel.
1058 if (!cancel) {
1059 if (dragged_off_from_overflow_to_shelf_) {
1060 dragged_off_from_overflow_to_shelf_ = false;
1061 main_shelf_->EndDrag(false);
1062 drag_view_->layer()->SetOpacity(1.0f);
1063 } else if (RemovableByRipOff(current_index) != REMOVABLE) {
1064 // Make sure we do not try to remove un-removable items like items which
1065 // were not pinned or have to be always there.
1066 cancel = true;
1067 snap_back = true;
1068 } else {
1069 // Make sure the item stays invisible upon removal.
1070 drag_view_->SetVisible(false);
1071 std::string app_id = 0;
1072 std::string app_id =
1073 delegate_->GetAppIDForShelfID(model_.items()[current_index].id);
1074 delegate_->UnpinAppWithID(app_id);
1075 }
1076 }
1077 if (cancel || snap_back) {
1078 if (dragged_off_from_overflow_to_shelf_) {
1079 dragged_off_from_overflow_to_shelf_ = false;
1080 // Main shelf handles revert of dragged item.
1081 main_shelf_->EndDrag(true);
1082 drag_view_->layer()->SetOpacity(1.0f);
1083 } else if (!cancelling_drag_model_changed_) {
1084 // Only do something if the change did not come through a model change.
1085 gfx::Rect drag_bounds;
1086 gfx::Rect drag_bounds = drag_image_->GetBoundsInScreen();
1087 gfx::Point relative_to = GetBoundsInScreen().origin();
1088 gfx::Rect target(
1089 gfx::PointAtOffsetFromOrigin(drag_bounds.origin()- relative_to),
1090 drag_bounds.size());
1091 drag_view_->SetBoundsRect(target);
1092 // Hide the status from the active item since we snap it back now. Upon
1093 // animation end the flag gets cleared if |snap_back_from_rip_off_view_|
1094 // is set.
1095 snap_back_from_rip_off_view_ = drag_view_;
1096 drag_view_->AddState(ShelfButton::STATE_HIDDEN);
1097 // When a canceling drag model is happening, the view model is diverged
1098 // from the menu model and movements / animations should not be done.
1099 model_.Move(current_index, start_drag_index_);
1100 AnimateToIdealBounds();
1101 }
1102 drag_view_->layer()->SetOpacity(1.0f);
1103 }
1104 DestroyDragIconProxy();*/
1105 }
1106
1107 ShelfView::RemovableState ShelfView::RemovableByRipOff(int index) const {
1108 DCHECK(index >= 0 && index < model_.item_count());
1109 ShelfItemType type = model_.items()[index].type;
1110 if (type == TYPE_APP_LIST || type == TYPE_DIALOG)
1111 return NOT_REMOVABLE;
1112
1113 /* TODO(msw): Restore functionality:
1114 std::string app_id =
1115 delegate_->GetAppIDForShelfID(model_.items()[index].id);
1116 ShelfItemDelegate* item_delegate =
1117 item_manager_->GetShelfItemDelegate(model_.items()[index].id);
1118 if (!item_delegate->CanPin())
1119 return NOT_REMOVABLE;
1120 Note: Only pinned app shortcuts can be removed!
1121 return (type == TYPE_APP_SHORTCUT && delegate_->IsAppPinned(app_id)) ?
1122 REMOVABLE : DRAGGABLE;*/
1123 return REMOVABLE;
1124 }
1125
1126 bool ShelfView::SameDragType(ShelfItemType typea, ShelfItemType typeb) const {
1127 switch (typea) {
1128 case TYPE_APP_SHORTCUT:
1129 case TYPE_BROWSER_SHORTCUT:
1130 return (typeb == TYPE_APP_SHORTCUT || typeb == TYPE_BROWSER_SHORTCUT);
1131 case TYPE_APP_LIST:
1132 case TYPE_PLATFORM_APP:
1133 case TYPE_WINDOWED_APP:
1134 case TYPE_MOJO_APP:
1135 case TYPE_APP_PANEL:
1136 case TYPE_DIALOG:
1137 return typeb == typea;
1138 case TYPE_UNDEFINED:
1139 NOTREACHED() << "ShelfItemType must be set.";
1140 return false;
1141 }
1142 NOTREACHED();
1143 return false;
1144 }
1145
1146 std::pair<int, int> ShelfView::GetDragRange(int index) {
1147 int min_index = -1;
1148 int max_index = -1;
1149 ShelfItemType type = model_.items()[index].type;
1150 for (int i = 0; i < model_.item_count(); ++i) {
1151 if (SameDragType(model_.items()[i].type, type)) {
1152 if (min_index == -1)
1153 min_index = i;
1154 max_index = i;
1155 }
1156 }
1157 return std::pair<int, int>(min_index, max_index);
1158 }
1159
1160 void ShelfView::ConfigureChildView(views::View* view) {
1161 view->SetPaintToLayer(true);
1162 view->layer()->SetFillsBoundsOpaquely(false);
1163 }
1164
1165 void ShelfView::ToggleOverflowBubble() {
1166 /* TODO(msw): Restore functionality:
1167 if (IsShowingOverflowBubble()) {
1168 overflow_bubble_->Hide();
1169 return;
1170 }
1171
1172 if (!overflow_bubble_)
1173 overflow_bubble_.reset(new OverflowBubble());
1174
1175 ShelfView* overflow_view = new ShelfView(app);
1176 overflow_view->overflow_mode_ = true;
1177 overflow_view->Init();
1178 overflow_view->set_owner_overflow_bubble(overflow_bubble_.get());
1179 overflow_view->OnShelfAlignmentChanged();
1180 overflow_view->main_shelf_ = this;
1181 UpdateOverflowRange(overflow_view);
1182
1183 overflow_bubble_->Show(overflow_button_, overflow_view);
1184
1185 Shell::GetInstance()->UpdateShelfVisibility();*/
1186 }
1187
1188 void ShelfView::OnFadeOutAnimationEnded() {
1189 AnimateToIdealBounds();
1190 StartFadeInLastVisibleItem();
1191 }
1192
1193 void ShelfView::StartFadeInLastVisibleItem() {
1194 // If overflow button is visible and there is a valid new last item, fading
1195 // the new last item in after sliding animation is finished.
1196 /* TODO(msw): Restore functionality:
1197 if (overflow_button_->visible() && last_visible_index_ >= 0) {
1198 views::View* last_visible_view =
1199 view_model_.view_at(last_visible_index_);
1200 last_visible_view->layer()->SetOpacity(0);
1201 bounds_animator_->SetAnimationDelegate(
1202 last_visible_view,
1203 scoped_ptr<gfx::AnimationDelegate>(
1204 new StartFadeAnimationDelegate(this, last_visible_view)));
1205 }*/
1206 }
1207
1208 void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) const {
1209 const int first_overflow_index = last_visible_index_ + 1;
1210 const int last_overflow_index = last_hidden_index_;
1211 DCHECK_LE(first_overflow_index, last_overflow_index);
1212 DCHECK_LT(last_overflow_index, view_model_.view_size());
1213
1214 /* TODO(msw): Restore functionality:
1215 overflow_view->first_visible_index_ = first_overflow_index;
1216 overflow_view->last_visible_index_ = last_overflow_index;*/
1217 }
1218
1219 bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) {
1220 gfx::Rect active_bounds;
1221
1222 for (int i = 0; i < child_count(); ++i) {
1223 views::View* child = child_at(i);
1224 /* TODO(msw): Restore functionality:
1225 if (child == overflow_button_)
1226 continue;*/
1227 if (!ShouldShowTooltipForView(child))
1228 continue;
1229
1230 gfx::Rect child_bounds = child->GetMirroredBounds();
1231 active_bounds.Union(child_bounds);
1232 }
1233
1234 return !active_bounds.Contains(cursor_location);
1235 }
1236
1237 gfx::Rect ShelfView::GetVisibleItemsBoundsInScreen() {
1238 gfx::Size preferred_size = GetPreferredSize();
1239 gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0);
1240 ConvertPointToScreen(this, &origin);
1241 return gfx::Rect(origin, preferred_size);
1242 }
1243
1244 gfx::Rect ShelfView::GetBoundsForDragInsertInScreen() {
1245 gfx::Size preferred_size;
1246 if (is_overflow_mode()) {
1247 /* TODO(msw): Restore functionality:
1248 DCHECK(owner_overflow_bubble_);
1249 gfx::Rect bubble_bounds =
1250 owner_overflow_bubble_->bubble_view()->GetBubbleBounds();
1251 preferred_size = bubble_bounds.size();*/
1252 } else {
1253 const int last_button_index = view_model_.view_size() - 1;
1254 gfx::Rect last_button_bounds =
1255 view_model_.view_at(last_button_index)->bounds();
1256 /* TODO(msw): Restore functionality:
1257 if (overflow_button_->visible() &&
1258 model_.GetItemIndexForType(TYPE_APP_PANEL) == -1) {
1259 // When overflow button is visible and shelf has no panel items,
1260 // last_button_bounds should be overflow button's bounds.
1261 last_button_bounds = overflow_button_->bounds();
1262 }*/
1263
1264 if (IsHorizontalAlignment()) {
1265 preferred_size = gfx::Size(last_button_bounds.right() + leading_inset_,
1266 kShelfSize);
1267 } else {
1268 preferred_size = gfx::Size(kShelfSize,
1269 last_button_bounds.bottom() + leading_inset_);
1270 }
1271 }
1272 gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0);
1273
1274 // In overflow mode, we should use OverflowBubbleView as a source for
1275 // converting |origin| to screen coordinates. When a scroll operation is
1276 // occurred in OverflowBubble, the bounds of ShelfView in OverflowBubble can
1277 // be changed.
1278 /* TODO(msw): Restore functionality:
1279 if (is_overflow_mode())
1280 ConvertPointToScreen(owner_overflow_bubble_->bubble_view(), &origin);
1281 else
1282 ConvertPointToScreen(this, &origin);*/
1283
1284 return gfx::Rect(origin, preferred_size);
1285 }
1286
1287 int ShelfView::CancelDrag(int modified_index) {
1288 FinalizeRipOffDrag(true);
1289 if (!drag_view_)
1290 return modified_index;
1291 bool was_dragging = dragging();
1292 int drag_view_index = view_model_.GetIndexOfView(drag_view_);
1293 drag_pointer_ = NONE;
1294 drag_view_ = nullptr;
1295 if (drag_view_index == modified_index) {
1296 // The view that was being dragged is being modified. Don't do anything.
1297 return modified_index;
1298 }
1299 if (!was_dragging)
1300 return modified_index;
1301
1302 // Restore previous position, tracking the position of the modified view.
1303 bool at_end = modified_index == view_model_.view_size();
1304 views::View* modified_view =
1305 (modified_index >= 0 && !at_end) ?
1306 view_model_.view_at(modified_index) : nullptr;
1307 model_.Move(drag_view_index, start_drag_index_);
1308
1309 // If the modified view will be at the end of the list, return the new end of
1310 // the list.
1311 if (at_end)
1312 return view_model_.view_size();
1313 return modified_view ? view_model_.GetIndexOfView(modified_view) : -1;
40 } 1314 }
41 1315
42 gfx::Size ShelfView::GetPreferredSize() const { 1316 gfx::Size ShelfView::GetPreferredSize() const {
43 return gfx::Size(1, 48); 1317 const_cast<ShelfView*>(this)->CalculateIdealBounds();
44 } 1318
45 1319 int last_button_index = is_overflow_mode() ?
46 views::View* ShelfView::GetContentsView() { 1320 last_visible_index_ : view_model_.view_size() - 1;
1321
1322 // When an item is dragged off from the overflow bubble, it is moved to last
1323 // position and and changed to invisible. Overflow bubble size should be
1324 // shrunk to fit only for visible items.
1325 // If |dragged_off_from_overflow_to_shelf_| is set, there will be no invisible
1326 // items in the shelf.
1327 if (is_overflow_mode() &&
1328 dragged_off_shelf_ &&
1329 !dragged_off_from_overflow_to_shelf_ &&
1330 RemovableByRipOff(view_model_.GetIndexOfView(drag_view_)) == REMOVABLE)
1331 last_button_index--;
1332
1333 const gfx::Rect last_button_bounds =
1334 last_button_index >= first_visible_index_ ?
1335 view_model_.ideal_bounds(last_button_index) :
1336 gfx::Rect(gfx::Size(kShelfSize, kShelfSize));
1337
1338 if (IsHorizontalAlignment())
1339 return gfx::Size(last_button_bounds.right() + leading_inset_, kShelfSize);
1340
1341 return gfx::Size(kShelfSize, last_button_bounds.bottom() + leading_inset_);
1342 }
1343
1344 void ShelfView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
1345 // This bounds change is produced by the shelf movement and all content has
1346 // to follow. Using an animation at that time would produce a time lag since
1347 // the animation of the BoundsAnimator has itself a delay before it arrives
1348 // at the required location. As such we tell the animator to go there
1349 // immediately.
1350 BoundsAnimatorDisabler disabler(bounds_animator_.get());
1351 LayoutToIdealBounds();
1352 /* TODO(msw): Restore functionality:
1353 FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
1354 OnShelfIconPositionsChanged());
1355
1356 if (IsShowingOverflowBubble())
1357 overflow_bubble_->Hide();*/
1358 }
1359
1360 views::FocusTraversable* ShelfView::GetPaneFocusTraversable() {
47 return this; 1361 return this;
48 } 1362 }
49 1363
1364 void ShelfView::GetAccessibleState(ui::AXViewState* state) {
1365 state->role = ui::AX_ROLE_TOOLBAR;
1366 /* TODO(msw): Restore functionality:
1367 state->name = l10n_util::GetStringUTF16(IDS_ASH_SHELF_ACCESSIBLE_NAME);*/
1368 }
1369
1370 /* TODO(msw): Restore functionality:
1371 void ShelfView::OnGestureEvent(ui::GestureEvent* event) {
1372 aura::Window* target_window = static_cast<views::View*>(event->target())
1373 ->GetWidget()
1374 ->GetNativeWindow();
1375 if (gesture_handler_.ProcessGestureEvent(*event, target_window))
1376 event->StopPropagation();
1377 }*/
1378
1379 void ShelfView::ShelfItemAdded(int model_index) {
1380 {
1381 base::AutoReset<bool> cancelling_drag(
1382 &cancelling_drag_model_changed_, true);
1383 model_index = CancelDrag(model_index);
1384 }
1385 views::View* view = CreateViewForItem(model_.items()[model_index]);
1386 AddChildView(view);
1387 // Hide the view, it'll be made visible when the animation is done. Using
1388 // opacity 0 here to avoid messing with CalculateIdealBounds which touches
1389 // the view's visibility.
1390 view->layer()->SetOpacity(0);
1391 view_model_.Add(view, model_index);
1392
1393 // Give the button its ideal bounds. That way if we end up animating the
1394 // button before this animation completes it doesn't appear at some random
1395 // spot (because it was in the middle of animating from 0,0 0x0 to its
1396 // target).
1397 CalculateIdealBounds();
1398 view->SetBoundsRect(view_model_.ideal_bounds(model_index));
1399
1400 // The first animation moves all the views to their target position. |view|
1401 // is hidden, so it visually appears as though we are providing space for
1402 // it. When done we'll fade the view in.
1403 AnimateToIdealBounds();
1404 if (model_index <= last_visible_index_ ||
1405 model_index >= model_.FirstPanelIndex()) {
1406 bounds_animator_->SetAnimationDelegate(
1407 view,
1408 scoped_ptr<gfx::AnimationDelegate>(
1409 new StartFadeAnimationDelegate(this, view)));
1410 } else {
1411 // Undo the hiding if animation does not run.
1412 view->layer()->SetOpacity(1.0f);
1413 }
1414 }
1415
1416 void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) {
1417 if (id == context_menu_id_)
1418 launcher_menu_runner_.reset();
1419 {
1420 base::AutoReset<bool> cancelling_drag(
1421 &cancelling_drag_model_changed_, true);
1422 model_index = CancelDrag(model_index);
1423 }
1424 views::View* view = view_model_.view_at(model_index);
1425 view_model_.Remove(model_index);
1426
1427 // When the overflow bubble is visible, the overflow range needs to be set
1428 // before CalculateIdealBounds() gets called. Otherwise CalculateIdealBounds()
1429 // could trigger a ShelfItemChanged() by hiding the overflow bubble and
1430 // since the overflow bubble is not yet synced with the ShelfModel this
1431 // could cause a crash.
1432 /* TODO(msw): Restore functionality:
1433 if (overflow_bubble_ && overflow_bubble_->IsShowing()) {
1434 last_hidden_index_ = std::min(last_hidden_index_,
1435 view_model_.view_size() - 1);
1436 UpdateOverflowRange(overflow_bubble_->shelf_view());
1437 }*/
1438
1439 if (view->visible()) {
1440 // The first animation fades out the view. When done we'll animate the rest
1441 // of the views to their target location.
1442 bounds_animator_->AnimateViewTo(view, view->bounds());
1443 bounds_animator_->SetAnimationDelegate(
1444 view,
1445 scoped_ptr<gfx::AnimationDelegate>(
1446 new FadeOutAnimationDelegate(this, view)));
1447 } else {
1448 // We don't need to show a fade out animation for invisible |view|. When an
1449 // item is ripped out from the shelf, its |view| is already invisible.
1450 AnimateToIdealBounds();
1451 }
1452
1453 // Close the tooltip because it isn't needed any longer and its anchor view
1454 // will be deleted soon.
1455 if (tooltip_.GetCurrentAnchorView() == view)
1456 tooltip_.Close();
1457 }
1458
1459 void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) {
1460 const ShelfItem& item(model_.items()[model_index]);
1461 if (old_item.type != item.type) {
1462 // Type changed, swap the views.
1463 model_index = CancelDrag(model_index);
1464 scoped_ptr<views::View> old_view(view_model_.view_at(model_index));
1465 bounds_animator_->StopAnimatingView(old_view.get());
1466 // Removing and re-inserting a view in our view model will strip the ideal
1467 // bounds from the item. To avoid recalculation of everything the bounds
1468 // get remembered and restored after the insertion to the previous value.
1469 gfx::Rect old_ideal_bounds = view_model_.ideal_bounds(model_index);
1470 view_model_.Remove(model_index);
1471 views::View* new_view = CreateViewForItem(item);
1472 AddChildView(new_view);
1473 view_model_.Add(new_view, model_index);
1474 view_model_.set_ideal_bounds(model_index, old_ideal_bounds);
1475 new_view->SetBoundsRect(old_view->bounds());
1476 return;
1477 }
1478
1479 views::View* view = view_model_.view_at(model_index);
1480 switch (item.type) {
1481 case TYPE_BROWSER_SHORTCUT:
1482 // Fallthrough for the new Shelf since it needs to show the activation
1483 // change as well.
1484 case TYPE_APP_SHORTCUT:
1485 case TYPE_WINDOWED_APP:
1486 case TYPE_PLATFORM_APP:
1487 case TYPE_DIALOG:
1488 case TYPE_APP_PANEL: {
1489 CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName());
1490 ShelfButton* button = static_cast<ShelfButton*>(view);
1491 ReflectItemStatus(item, button);
1492 // The browser shortcut is currently not a "real" item and as such the
1493 // the image is bogous as well. We therefore keep the image as is for it.
1494 if (item.type != TYPE_BROWSER_SHORTCUT)
1495 button->SetImage(item.image);
1496 button->SchedulePaint();
1497 break;
1498 }
1499 case TYPE_MOJO_APP: {
1500 CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName());
1501 ShelfButton* button = static_cast<ShelfButton*>(view);
1502 button->SetTooltipText(item.title);
1503 break;
1504 }
1505
1506 default:
1507 break;
1508 }
1509 }
1510
1511 void ShelfView::ShelfItemMoved(int start_index, int target_index) {
1512 view_model_.Move(start_index, target_index);
1513 // When cancelling a drag due to a shelf item being added, the currently
1514 // dragged item is moved back to its initial position. AnimateToIdealBounds
1515 // will be called again when the new item is added to the |view_model_| but
1516 // at this time the |view_model_| is inconsistent with the |model_|.
1517 if (!cancelling_drag_model_changed_)
1518 AnimateToIdealBounds();
1519 }
1520
1521 void ShelfView::ShelfStatusChanged() {
1522 // Nothing to do here.
1523 }
1524
1525 ShelfAlignment ShelfView::GetAlignment() const {
1526 return alignment_;
1527 }
1528
1529 bool ShelfView::IsHorizontalAlignment() const {
1530 return alignment_ == SHELF_ALIGNMENT_BOTTOM ||
1531 alignment_ == SHELF_ALIGNMENT_TOP;
1532 }
1533
1534 void ShelfView::PointerPressedOnButton(views::View* view,
1535 Pointer pointer,
1536 const ui::LocatedEvent& event) {
1537 if (drag_view_)
1538 return;
1539
1540 int index = view_model_.GetIndexOfView(view);
1541 if (index == -1)
1542 return;
1543
1544 /* TODO(msw): Restore functionality:
1545 ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
1546 model_.items()[index].id);
1547 if (view_model_.view_size() <= 1 || !item_delegate->IsDraggable())
1548 return; // View is being deleted or not draggable, ignore request.*/
1549
1550 // Only when the repost event occurs on the same shelf item, we should ignore
1551 // the call in ShelfView::ButtonPressed(...).
1552 is_repost_event_ = IsRepostEvent(event) && (last_pressed_index_ == index);
1553
1554 CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName());
1555 drag_view_ = static_cast<ShelfButton*>(view);
1556 drag_origin_ = gfx::Point(event.x(), event.y());
1557 /* TODO(msw): Restore functionality:
1558 UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentUsage",
1559 layout_manager_->SelectValueForShelfAlignment(
1560 SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM,
1561 SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT,
1562 SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT,
1563 -1),
1564 SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT);*/
1565 }
1566
1567 void ShelfView::PointerDraggedOnButton(views::View* view,
1568 Pointer pointer,
1569 const ui::LocatedEvent& event) {
1570 // To prepare all drag types (moving an item in the shelf and dragging off),
1571 // we should check the x-axis and y-axis offset.
1572 if (!dragging() && drag_view_ &&
1573 ((std::abs(event.x() - drag_origin_.x()) >= kMinimumDragDistance) ||
1574 (std::abs(event.y() - drag_origin_.y()) >= kMinimumDragDistance))) {
1575 PrepareForDrag(pointer, event);
1576 }
1577 if (drag_pointer_ == pointer)
1578 ContinueDrag(event);
1579 }
1580
1581 void ShelfView::PointerReleasedOnButton(views::View* view,
1582 Pointer pointer,
1583 bool canceled) {
1584 // Reset |is_repost_event| to false.
1585 is_repost_event_ = false;
1586
1587 if (canceled) {
1588 CancelDrag(-1);
1589 } else if (drag_pointer_ == pointer) {
1590 FinalizeRipOffDrag(false);
1591 drag_pointer_ = NONE;
1592 AnimateToIdealBounds();
1593 }
1594 // If the drag pointer is NONE, no drag operation is going on and the
1595 // drag_view can be released.
1596 if (drag_pointer_ == NONE)
1597 drag_view_ = nullptr;
1598 }
1599
1600 void ShelfView::MouseMovedOverButton(views::View* view) {
1601 if (!ShouldShowTooltipForView(view))
1602 return;
1603
1604 if (!tooltip_.IsVisible())
1605 tooltip_.ResetTimer();
1606 }
1607
1608 void ShelfView::MouseEnteredButton(views::View* view) {
1609 // TODO(msw): Fix the initial (0,0) mouse event (causes tooltip on startup).
1610 if (!ShouldShowTooltipForView(view))
1611 return;
1612
1613 if (tooltip_.IsVisible())
1614 tooltip_.ShowImmediately(view, GetAccessibleName(view));
1615 else
1616 tooltip_.ShowDelayed(view, GetAccessibleName(view));
1617 }
1618
1619 void ShelfView::MouseExitedButton(views::View* view) {
1620 if (!tooltip_.IsVisible())
1621 tooltip_.StopTimer();
1622 }
1623
1624 base::string16 ShelfView::GetAccessibleName(const views::View* view) {
1625 int view_index = view_model_.GetIndexOfView(view);
1626 // May be -1 while in the process of animating closed.
1627 if (view_index == -1)
1628 return base::string16();
1629 return model_.items()[view_index].title;
1630 }
1631
50 void ShelfView::ButtonPressed(views::Button* sender, const ui::Event& event) { 1632 void ShelfView::ButtonPressed(views::Button* sender, const ui::Event& event) {
51 user_window_controller_->FocusUserWindow(sender->tag()); 1633 // Do not handle mouse release during drag.
52 } 1634 if (dragging())
53 1635 return;
54 void ShelfView::OnUserWindowObserverAdded( 1636
55 mojo::Array<mash::wm::mojom::UserWindowPtr> user_windows) { 1637 /* TODO(msw): Restore functionality:
56 for (size_t i = 0; i < user_windows.size(); ++i) 1638 if (sender == overflow_button_) {
57 OnUserWindowAdded(std::move(user_windows[i])); 1639 ToggleOverflowBubble();
58 } 1640 shelf_button_pressed_metric_tracker_.ButtonPressed(
59 1641 event, sender, ShelfItemDelegate::kNoAction);
60 void ShelfView::OnUserWindowAdded(mash::wm::mojom::UserWindowPtr user_window) { 1642 return;
61 views::LabelButton* open_window_button = new views::LabelButton( 1643 }*/
62 this, user_window->window_title.To<base::string16>()); 1644
63 open_window_button->set_tag(user_window->window_id); 1645 int view_index = view_model_.GetIndexOfView(sender);
64 open_window_buttons_.push_back(open_window_button); 1646 // May be -1 while in the process of animating closed.
65 AddChildView(open_window_button); 1647 if (view_index == -1)
66 Layout(); 1648 return;
67 SchedulePaint(); 1649
68 } 1650 // If the menu was just closed by the same event as this one, we ignore
69 1651 // the call and don't open the menu again. See crbug.com/343005 for more
70 void ShelfView::OnUserWindowRemoved(uint32_t window_id) { 1652 // detail.
71 const size_t index = GetButtonIndexById(window_id); 1653 if (is_repost_event_)
72 if (index >= open_window_buttons_.size()) 1654 return;
73 return; 1655
74 1656 // Record the index for the last pressed shelf item.
75 views::LabelButton* button = open_window_buttons_[index]; 1657 last_pressed_index_ = view_index;
76 open_window_buttons_.erase(open_window_buttons_.begin() + index); 1658
77 RemoveChildView(button); 1659 // Don't activate the item twice on double-click. Otherwise the window starts
78 delete button; 1660 // animating open due to the first click, then immediately minimizes due to
79 Layout(); 1661 // the second click. The user most likely intended to open or minimize the
80 SchedulePaint(); 1662 // item once, not do both.
81 } 1663 if (event.flags() & ui::EF_IS_DOUBLE_CLICK)
82 1664 return;
83 void ShelfView::OnUserWindowTitleChanged(uint32_t window_id, 1665
84 const mojo::String& window_title) { 1666 {
85 const size_t index = GetButtonIndexById(window_id); 1667 /* TODO(msw): Restore functionality:
86 if (index >= open_window_buttons_.size()) 1668 ScopedTargetRootWindow scoped_target(
87 return; 1669 sender->GetWidget()->GetNativeView()->GetRootWindow());*/
88 1670 // Slow down activation animations if shift key is pressed.
89 open_window_buttons_[index]->SetText(window_title.To<base::string16>()); 1671 scoped_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations;
90 open_window_buttons_[index]->SetMinSize(gfx::Size()); 1672 if (event.IsShiftDown()) {
91 Layout(); 1673 slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode(
92 SchedulePaint(); 1674 ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
1675 }
1676
1677 // Collect usage statistics before we decide what to do with the click.
1678 const ShelfItem& item(model_.items()[view_index]);
1679 switch (item.type) {
1680 case TYPE_APP_SHORTCUT:
1681 case TYPE_WINDOWED_APP:
1682 case TYPE_PLATFORM_APP:
1683 case TYPE_MOJO_APP:
1684 case TYPE_BROWSER_SHORTCUT:
1685 /* TODO(msw): Restore functionality:
1686 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
1687 UMA_LAUNCHER_CLICK_ON_APP);*/
1688 break;
1689
1690 case TYPE_APP_LIST:
1691 /* TODO(msw): Restore functionality:
1692 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
1693 UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);*/
1694 break;
1695
1696 case TYPE_APP_PANEL:
1697 case TYPE_DIALOG:
1698 break;
1699
1700 case TYPE_UNDEFINED:
1701 NOTREACHED() << "ShelfItemType must be set.";
1702 break;
1703 }
1704
1705 // TODO(msw): Support GetShelfItemDelegate[Manager], actions, etc.
1706 if (item.type == TYPE_MOJO_APP)
1707 model_.user_window_controller()->FocusUserWindow(item.window_id);
1708
1709 /* TODO(msw): Restore functionality:
1710 ShelfItemDelegate::PerformedAction performed_action =
1711 item_manager_->GetShelfItemDelegate(model_.items()[view_index].id)
1712 ->ItemSelected(event);
1713
1714 shelf_button_pressed_metric_tracker_.ButtonPressed(event, sender,
1715 performed_action);
1716
1717 if (performed_action != ShelfItemDelegate::kNewWindowCreated)
1718 ShowListMenuForView(model_.items()[view_index], sender, event);*/
1719 }
1720 }
1721
1722 bool ShelfView::ShowListMenuForView(const ShelfItem& item,
1723 views::View* source,
1724 const ui::Event& event) {
1725 /* TODO(msw): Restore functionality:
1726 ShelfItemDelegate* item_delegate =
1727 item_manager_->GetShelfItemDelegate(item.id);
1728 scoped_ptr<ui::MenuModel> list_menu_model(
1729 item_delegate->CreateApplicationMenu(event.flags()));
1730
1731 Make sure we have a menu and it has at least two items in addition to the
1732 application title and the 3 spacing separators.
1733 if (!list_menu_model.get() || list_menu_model->GetItemCount() <= 5)
1734 return false;
1735
1736 ShowMenu(list_menu_model.get(),
1737 source,
1738 gfx::Point(),
1739 false,
1740 ui::GetMenuSourceTypeForEvent(event));*/
1741 return true;
1742 }
1743
1744 void ShelfView::ShowContextMenuForView(views::View* source,
1745 const gfx::Point& point,
1746 ui::MenuSourceType source_type) {
1747 int view_index = view_model_.GetIndexOfView(source);
1748 if (view_index == -1) {
1749 /* TODO(msw): Restore functionality:
1750 Shell::GetInstance()->ShowContextMenu(point, source_type);*/
1751 return;
1752 }
1753
1754 /* TODO(msw): Restore functionality:
1755 ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
1756 model_.items()[view_index].id);
1757 context_menu_model_.reset(item_delegate->CreateContextMenu(
1758 source->GetWidget()->GetNativeView()->GetRootWindow()));
1759 if (!context_menu_model_)
1760 return;
1761
1762 base::AutoReset<ShelfID> reseter(
1763 &context_menu_id_,
1764 view_index == -1 ? 0 : model_.items()[view_index].id);
1765
1766 ShowMenu(context_menu_model_.get(),
1767 source,
1768 point,
1769 true,
1770 source_type);*/
1771 }
1772
1773 void ShelfView::ShowMenu(ui::MenuModel* menu_model,
1774 views::View* source,
1775 const gfx::Point& click_point,
1776 bool context_menu,
1777 ui::MenuSourceType source_type) {
1778 closing_event_time_ = base::TimeDelta();
1779 launcher_menu_runner_.reset(new views::MenuRunner(
1780 menu_model, context_menu ? views::MenuRunner::CONTEXT_MENU : 0));
1781
1782 /* TODO(msw): Restore functionality:
1783 ScopedTargetRootWindow scoped_target(
1784 source->GetWidget()->GetNativeView()->GetRootWindow());*/
1785
1786 // Determine the menu alignment dependent on the shelf.
1787 views::MenuAnchorPosition menu_alignment = views::MENU_ANCHOR_TOPLEFT;
1788 gfx::Rect anchor_point = gfx::Rect(click_point, gfx::Size());
1789
1790 if (!context_menu) {
1791 // Application lists use a bubble.
1792 anchor_point = source->GetBoundsInScreen();
1793
1794 // It is possible to invoke the menu while it is sliding into view. To cover
1795 // that case, the screen coordinates are offsetted by the animation delta.
1796 gfx::Vector2d offset =
1797 source->GetWidget()->GetNativeWindow()->bounds().origin() -
1798 source->GetWidget()->GetNativeWindow()->GetTargetBounds().origin();
1799 anchor_point.set_x(anchor_point.x() - offset.x());
1800 anchor_point.set_y(anchor_point.y() - offset.y());
1801
1802 // Shelf items can have an asymmetrical border for spacing reasons.
1803 // Adjust anchor location for this.
1804 if (source->border())
1805 anchor_point.Inset(source->border()->GetInsets());
1806
1807 menu_alignment = SelectValueForShelfAlignment(
1808 views::MENU_ANCHOR_BUBBLE_ABOVE, views::MENU_ANCHOR_BUBBLE_RIGHT,
1809 views::MENU_ANCHOR_BUBBLE_LEFT, views::MENU_ANCHOR_BUBBLE_BELOW);
1810 }
1811 // If this gets deleted while we are in the menu, the shelf will be gone
1812 // as well.
1813 bool got_deleted = false;
1814 got_deleted_ = &got_deleted;
1815
1816 /* TODO(msw): Restore functionality:
1817 shelf->ForceUndimming(true);*/
1818 // NOTE: if you convert to HAS_MNEMONICS be sure and update menu building
1819 // code.
1820 if (launcher_menu_runner_->RunMenuAt(source->GetWidget(),
1821 nullptr,
1822 anchor_point,
1823 menu_alignment,
1824 source_type) ==
1825 views::MenuRunner::MENU_DELETED) {
1826 if (!got_deleted) {
1827 got_deleted_ = nullptr;
1828 /* TODO(msw): Restore functionality:
1829 shelf->ForceUndimming(false);*/
1830 }
1831 return;
1832 }
1833 got_deleted_ = nullptr;
1834 /* TODO(msw): Restore functionality:
1835 shelf->ForceUndimming(false);*/
1836
1837 // If it is a context menu and we are showing overflow bubble
1838 // we want to hide overflow bubble.
1839 /* TODO(msw): Restore functionality:
1840 if (owner_overflow_bubble_)
1841 owner_overflow_bubble_->HideBubbleAndRefreshButton();*/
1842
1843 // Unpinning an item will reset the |launcher_menu_runner_| before coming
1844 // here.
1845 if (launcher_menu_runner_)
1846 closing_event_time_ = launcher_menu_runner_->closing_event_time();
1847 /* TODO(msw): Restore functionality:
1848 Shell::GetInstance()->UpdateShelfVisibility();*/
1849 }
1850
1851 void ShelfView::OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) {
1852 /* TODO(msw): Restore functionality:
1853 FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
1854 OnShelfIconPositionsChanged());*/
1855 PreferredSizeChanged();
1856 }
1857
1858 void ShelfView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
1859 if (snap_back_from_rip_off_view_ && animator == bounds_animator_.get()) {
1860 if (!animator->IsAnimating(snap_back_from_rip_off_view_)) {
1861 // Coming here the animation of the ShelfButton is finished and the
1862 // previously hidden status can be shown again. Since the button itself
1863 // might have gone away or changed locations we check that the button
1864 // is still in the shelf and show its status again.
1865 for (int index = 0; index < view_model_.view_size(); index++) {
1866 views::View* view = view_model_.view_at(index);
1867 if (view == snap_back_from_rip_off_view_) {
1868 CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName());
1869 ShelfButton* button = static_cast<ShelfButton*>(view);
1870 button->ClearState(ShelfButton::STATE_HIDDEN);
1871 break;
1872 }
1873 }
1874 snap_back_from_rip_off_view_ = nullptr;
1875 }
1876 }
1877 }
1878
1879 bool ShelfView::IsRepostEvent(const ui::Event& event) {
1880 if (closing_event_time_ == base::TimeDelta())
1881 return false;
1882
1883 base::TimeDelta delta =
1884 base::TimeDelta(event.time_stamp() - closing_event_time_);
1885 closing_event_time_ = base::TimeDelta();
1886 // If the current (press down) event is a repost event, the time stamp of
1887 // these two events should be the same.
1888 return (delta.InMilliseconds() == 0);
1889 }
1890
1891 const ShelfItem* ShelfView::ShelfItemForView(const views::View* view) const {
1892 int view_index = view_model_.GetIndexOfView(view);
1893 if (view_index == -1)
1894 return nullptr;
1895 return &(model_.items()[view_index]);
1896 }
1897
1898 bool ShelfView::ShouldShowTooltipForView(const views::View* view) const {
1899 /* TODO(msw): Restore functionality:
1900 if (view == GetAppListButtonView() &&
1901 Shell::GetInstance()->GetAppListWindow())
1902 return false;
1903 const ShelfItem* item = ShelfItemForView(view);
1904 if (!item)
1905 return true;
1906 return item_manager_->GetShelfItemDelegate(item->id)->ShouldShowTooltip();*/
1907 return true;
1908 }
1909
1910 int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const {
1911 const gfx::Rect bounds = GetBoundsInScreen();
1912 int distance = 0;
1913 switch (GetAlignment()) {
1914 case SHELF_ALIGNMENT_BOTTOM:
1915 distance = bounds.y() - coordinate.y();
1916 break;
1917 case SHELF_ALIGNMENT_LEFT:
1918 distance = coordinate.x() - bounds.right();
1919 break;
1920 case SHELF_ALIGNMENT_RIGHT:
1921 distance = bounds.x() - coordinate.x();
1922 break;
1923 case SHELF_ALIGNMENT_TOP:
1924 distance = coordinate.y() - bounds.bottom();
1925 break;
1926 }
1927 return distance > 0 ? distance : 0;
93 } 1928 }
94 1929
95 } // namespace shelf 1930 } // namespace shelf
96 } // namespace mash 1931 } // namespace mash
OLDNEW
« no previous file with comments | « mash/shelf/shelf_view.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698