shelf_view.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "ash/shelf/shelf_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/ash_constants.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/ash_switches.h"
11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "ash/drag_drop/drag_image_view.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/metrics/user_metrics_recorder.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/root_window_controller.h"
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ash/scoped_target_root_window.h"
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/shelf/alternate_app_list_button.h"
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/shelf/app_list_button.h"
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/shelf/overflow_bubble.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/overflow_bubble_view.h"
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/shelf/overflow_button.h"
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/shelf_button.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf_constants.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_delegate.h"
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ash/shelf/shelf_icon_observer.h"
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_item_delegate.h"
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_item_delegate_manager.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shelf/shelf_layout_manager.h"
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_menu_model.h"
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/shelf_model.h"
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/shelf/shelf_tooltip_manager.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shelf/shelf_widget.h"
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shell.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/coordinate_conversion.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/auto_reset.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/histogram.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ash_resources.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/ash_strings.h"
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "ui/aura/client/screen_position_client.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/simple_menu_model.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer_animator.h"
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/compositor/scoped_animation_duration_scale_mode.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/gfx/point.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/animation/bounds_animator.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/border.h"
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/button/image_button.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_model_adapter.h"
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_runner.h"
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/focus/focus_search.h"
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view_model.h"
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view_model_utils.h"
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using gfx::Animation;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using views::View;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM = 0;
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT = 1;
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT = 2;
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT = 3;
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default amount content is inset on the left edge.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDefaultLeadingInset = 8;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Minimum distance before drag starts.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinimumDragDistance = 8;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Size between the buttons.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kButtonSpacing = 4;
78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochconst int kAlternateButtonSpacing = 10;
79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Size allocated to for each button.
81ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochconst int kButtonSize = 44;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Additional spacing for the left and right side of icons.
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kHorizontalIconSpacing = 2;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Inset for items which do not have an icon.
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kHorizontalNoIconInsetSpacing =
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    kHorizontalIconSpacing + kDefaultLeadingInset;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The proportion of the shelf space reserved for non-panel icons. Panels
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// may flow into this space but will be put into the overflow bubble if there
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is contention for the space.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const float kReservedNonPanelIconProportion = 0.67f;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is the command id of the menu item which contains the name of the menu.
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kCommandIdOfMenuName = 0;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The background color of the active item in the list.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kActiveListItemBackgroundColor = SkColorSetRGB(203 , 219, 241);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The background color of the active & hovered item in the list.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kFocusedActiveListItemBackgroundColor =
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkColorSetRGB(193, 211, 236);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The text color of the caption item in a list.
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kCaptionItemForegroundColor = SK_ColorBLACK;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The maximum allowable length of a menu line of an application menu in pixels.
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaximumAppMenuItemLength = 350;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// The distance of the cursor from the outer rim of the shelf before it
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// separates.
113424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const int kRipOffDistance = 48;
114424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
115424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// The rip off drag and drop proxy image should get scaled by this factor.
116424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const float kDragAndDropProxyScale = 1.5f;
117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The opacity represents that this partially disappeared item will get removed.
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const float kDraggedImageOpacity = 0.5f;
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A class to temporarily disable a given bounds animator.
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class BoundsAnimatorDisabler {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BoundsAnimatorDisabler(views::BoundsAnimator* bounds_animator)
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : old_duration_(bounds_animator->GetAnimationDuration()),
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        bounds_animator_(bounds_animator) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bounds_animator_->SetAnimationDuration(1);
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~BoundsAnimatorDisabler() {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bounds_animator_->SetAnimationDuration(old_duration_);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The previous animation duration.
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int old_duration_;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The bounds animator which gets used.
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  views::BoundsAnimator* bounds_animator_;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorDisabler);
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The MenuModelAdapter gets slightly changed to adapt the menu appearance to
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// our requirements.
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class ShelfMenuModelAdapter : public views::MenuModelAdapter {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  explicit ShelfMenuModelAdapter(ShelfMenuModel* menu_model);
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // views::MenuModelAdapter:
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual const gfx::FontList* GetLabelFontList(int command_id) const OVERRIDE;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsCommandEnabled(int id) const OVERRIDE;
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void GetHorizontalIconMargins(int id,
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        int icon_size,
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        int* left_margin,
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        int* right_margin) const OVERRIDE;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool GetForegroundColor(int command_id,
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  bool is_hovered,
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  SkColor* override_color) const OVERRIDE;
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool GetBackgroundColor(int command_id,
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  bool is_hovered,
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  SkColor* override_color) const OVERRIDE;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int GetMaxWidthForMenu(views::MenuItemView* menu) OVERRIDE;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool ShouldReserveSpaceForSubmenuIndicator() const OVERRIDE;
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfMenuModel* menu_model_;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShelfMenuModelAdapter);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ShelfMenuModelAdapter::ShelfMenuModelAdapter(ShelfMenuModel* menu_model)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : MenuModelAdapter(menu_model),
175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      menu_model_(menu_model) {
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const gfx::FontList* ShelfMenuModelAdapter::GetLabelFontList(
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int command_id) const {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_id != kCommandIdOfMenuName)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return MenuModelAdapter::GetLabelFontList(command_id);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return &rb.GetFontList(ui::ResourceBundle::BoldFont);
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::IsCommandEnabled(int id) const {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return id != kCommandIdOfMenuName;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::GetForegroundColor(int command_id,
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               bool is_hovered,
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               SkColor* override_color) const {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_id != kCommandIdOfMenuName)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *override_color = kCaptionItemForegroundColor;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::GetBackgroundColor(int command_id,
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               bool is_hovered,
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               SkColor* override_color) const {
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!menu_model_->IsCommandActive(command_id))
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *override_color = is_hovered ? kFocusedActiveListItemBackgroundColor :
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 kActiveListItemBackgroundColor;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ShelfMenuModelAdapter::GetHorizontalIconMargins(int command_id,
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                     int icon_size,
214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                     int* left_margin,
215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                     int* right_margin) const {
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *left_margin = kHorizontalIconSpacing;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *right_margin = (command_id != kCommandIdOfMenuName) ?
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kHorizontalIconSpacing : -(icon_size + kHorizontalNoIconInsetSpacing);
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)int ShelfMenuModelAdapter::GetMaxWidthForMenu(views::MenuItemView* menu) {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kMaximumAppMenuItemLength;
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::ShouldReserveSpaceForSubmenuIndicator() const {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Custom FocusSearch used to navigate the shelf in the order items are in
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the ViewModel.
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ShelfFocusSearch : public views::FocusSearch {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit ShelfFocusSearch(views::ViewModel* view_model)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : FocusSearch(NULL, true, true),
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_model_(view_model) {}
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~ShelfFocusSearch() {}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views::FocusSearch overrides:
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual View* FindNextFocusableView(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      View* starting_view,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool reverse,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Direction direction,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool check_starting_view,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      views::FocusTraversable** focus_traversable,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      View** focus_traversable_view) OVERRIDE {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index = view_model_->GetIndexOfView(starting_view);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index == -1)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return view_model_->view_at(0);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reverse) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      --index;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index < 0)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        index = view_model_->view_size() - 1;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++index;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index >= view_model_->view_size())
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        index = 0;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return view_model_->view_at(index);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::ViewModel* view_model_;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShelfFocusSearch);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AnimationDelegate used when inserting a new item. This steadily increases the
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opacity of the layer as the animation progress.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FadeInAnimationDelegate
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public views::BoundsAnimator::OwnedAnimationDelegate {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit FadeInAnimationDelegate(views::View* view) : view_(view) {}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~FadeInAnimationDelegate() {}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AnimationDelegate overrides:
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationProgressed(const Animation* animation) OVERRIDE {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(animation->GetCurrentValue());
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationEnded(const Animation* animation) OVERRIDE {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationCanceled(const Animation* animation) OVERRIDE {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view_;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FadeInAnimationDelegate);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ReflectItemStatus(const ShelfItem& item, ShelfButton* button) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (item.status) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_CLOSED:
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ACTIVE);
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_RUNNING);
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ATTENTION);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_RUNNING:
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ACTIVE);
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_RUNNING);
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ATTENTION);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_ACTIVE:
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_ACTIVE);
310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_RUNNING);
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ATTENTION);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_ATTENTION:
314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ACTIVE);
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_RUNNING);
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_ATTENTION);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// AnimationDelegate used when deleting an item. This steadily decreased the
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opacity of the layer as the animation progress.
3258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)class ShelfView::FadeOutAnimationDelegate
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public views::BoundsAnimator::OwnedAnimationDelegate {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FadeOutAnimationDelegate(ShelfView* host, views::View* view)
3298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : shelf_view_(host),
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_(view) {}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~FadeOutAnimationDelegate() {}
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AnimationDelegate overrides:
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationProgressed(const Animation* animation) OVERRIDE {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1 - animation->GetCurrentValue());
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationEnded(const Animation* animation) OVERRIDE {
3398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    shelf_view_->OnFadeOutAnimationEnded();
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationCanceled(const Animation* animation) OVERRIDE {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShelfView* shelf_view_;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<views::View> view_;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FadeOutAnimationDelegate);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AnimationDelegate used to trigger fading an element in. When an item is
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// inserted this delegate is attached to the animation that expands the size of
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the item.  When done it kicks off another animation to fade the item in.
3548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)class ShelfView::StartFadeAnimationDelegate
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public views::BoundsAnimator::OwnedAnimationDelegate {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  StartFadeAnimationDelegate(ShelfView* host,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             views::View* view)
3598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : shelf_view_(host),
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_(view) {}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~StartFadeAnimationDelegate() {}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AnimationDelegate overrides:
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationEnded(const Animation* animation) OVERRIDE {
3658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    shelf_view_->FadeIn(view_);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationCanceled(const Animation* animation) OVERRIDE {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShelfView* shelf_view_;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view_;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(StartFadeAnimationDelegate);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ShelfView::ShelfView(ShelfModel* model,
379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     ShelfDelegate* delegate,
380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     ShelfLayoutManager* manager)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : model_(model),
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate),
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_model_(new views::ViewModel),
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_visible_index_(0),
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_visible_index_(-1),
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      overflow_button_(NULL),
3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      owner_overflow_bubble_(NULL),
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_pointer_(NONE),
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_view_(NULL),
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_offset_(0),
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_drag_index_(-1),
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context_menu_id_(0),
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      leading_inset_(kDefaultLeadingInset),
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cancelling_drag_model_changed_(false),
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      last_hidden_index_(0),
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      closing_event_time_(base::TimeDelta()),
397b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      got_deleted_(NULL),
3987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      drag_and_drop_item_pinned_(false),
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      drag_and_drop_shelf_id_(0),
400424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      dragged_off_shelf_(false),
401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back_from_rip_off_view_(NULL),
402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      item_manager_(Shell::GetInstance()->shelf_item_delegate_manager()),
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      layout_manager_(manager),
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      overflow_mode_(false),
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_(NULL),
406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_(false) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(model_);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_.reset(new views::BoundsAnimator(this));
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->AddObserver(this);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_context_menu_controller(this);
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  focus_search_.reset(new ShelfFocusSearch(view_model_.get()));
412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  tooltip_.reset(new ShelfTooltipManager(manager, this));
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ShelfView::~ShelfView() {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->RemoveObserver(this);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->RemoveObserver(this);
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we are inside the MenuRunner, we need to know if we were getting
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // deleted while it was running.
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (got_deleted_)
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *got_deleted_ = true;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::Init() {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->AddObserver(this);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ShelfItems& items(model_->items());
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ShelfItems::const_iterator i = items.begin(); i != items.end(); ++i) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* child = CreateViewForItem(*i);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    child->SetPaintToLayer(true);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->Add(child, static_cast<int>(i - items.begin()));
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(child);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ShelfStatusChanged();
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_ = new OverflowButton(this);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->set_context_menu_controller(this);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigureChildView(overflow_button_);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(overflow_button_);
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateFirstButtonPadding();
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We'll layout when our bounds change.
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnShelfAlignmentChanged() {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateFirstButtonPadding();
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_button_->OnShelfAlignmentChanged();
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LayoutToIdealBounds();
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i=0; i < view_model_->view_size(); ++i) {
449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // TODO: remove when AppIcon is a Shelf Button.
450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (TYPE_APP_LIST == model_->items()[i].type &&
451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        !ash::switches::UseAlternateShelfLayout()) {
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<AppListButton*>(view_model_->view_at(i))->SetImageAlignment(
4531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          layout_manager_->SelectValueForShelfAlignment(
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_CENTER,
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_LEFT,
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_RIGHT,
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_CENTER),
4581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          layout_manager_->SelectValueForShelfAlignment(
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_TOP,
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_MIDDLE,
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_MIDDLE,
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              views::ImageButton::ALIGN_BOTTOM));
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i >= first_visible_index_ && i <= last_visible_index_)
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      view_model_->view_at(i)->Layout();
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
467d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  tooltip_->Close();
468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (overflow_bubble_)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_bubble_->Hide();
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::SchedulePaintForAllButtons() {
473ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (int i = 0; i < view_model_->view_size(); ++i) {
474ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (i >= first_visible_index_ && i <= last_visible_index_)
475ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      view_model_->view_at(i)->SchedulePaint();
476ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
477ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (overflow_button_ && overflow_button_->visible())
478ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    overflow_button_->SchedulePaint();
479ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
480ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)gfx::Rect ShelfView::GetIdealBoundsOfItemIcon(ShelfID id) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (index == -1 || (index > last_visible_index_ &&
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      index < model_->FirstPanelIndex()))
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Rect();
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect& ideal_bounds(view_model_->ideal_bounds(index));
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(TYPE_APP_LIST, model_->items()[index].type);
488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ShelfButton* button = static_cast<ShelfButton*>(view_model_->view_at(index));
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect icon_bounds = button->GetIconBounds();
490868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return gfx::Rect(GetMirroredXWithWidthInView(
491868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       ideal_bounds.x() + icon_bounds.x(), icon_bounds.width()),
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   ideal_bounds.y() + icon_bounds.y(),
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   icon_bounds.width(),
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   icon_bounds.height());
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShelfView::UpdatePanelIconPosition(ShelfID id,
4988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                        const gfx::Point& midpoint) {
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int current_index = model_->ItemIndexByID(id);
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int first_panel_index = model_->FirstPanelIndex();
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_index < first_panel_index)
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
504868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Point midpoint_in_view(GetMirroredXInView(midpoint.x()),
505868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              midpoint.y());
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int target_index = current_index;
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (target_index > first_panel_index &&
5081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
5091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)             view_model_->ideal_bounds(target_index).x(),
5101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)             view_model_->ideal_bounds(target_index).y()) >
5111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(midpoint_in_view.x(),
5121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                           midpoint_in_view.y())) {
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    --target_index;
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (target_index < view_model_->view_size() - 1 &&
5161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(target_index).right(),
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(target_index).bottom()) <
5191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(midpoint_in_view.x(),
5201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                           midpoint_in_view.y())) {
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++target_index;
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_index != target_index)
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model_->Move(current_index, target_index);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::IsShowingMenu() const {
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (launcher_menu_runner_.get() &&
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       launcher_menu_runner_->IsRunning());
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::IsShowingOverflowBubble() const {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return overflow_bubble_.get() && overflow_bubble_->IsShowing();
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::View* ShelfView::GetAppListButtonView() const {
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < model_->item_count(); ++i) {
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (model_->items()[i].type == TYPE_APP_LIST)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return view_model_->view_at(i);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Applist button not found";
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
5478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// ShelfView, FocusTraversable implementation:
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::FocusSearch* ShelfView::GetFocusSearch() {
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return focus_search_.get();
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::FocusTraversable* ShelfView::GetFocusTraversableParent() {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parent()->GetFocusTraversable();
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)View* ShelfView::GetFocusTraversableParentView() {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::CreateDragIconProxy(
562a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const gfx::Point& location_in_screen_coordinates,
563a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const gfx::ImageSkia& icon,
564a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    views::View* replaced_view,
565868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Vector2d& cursor_offset_from_center,
566a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    float scale_factor) {
567a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_replaced_view_ = replaced_view;
568c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  drag_image_.reset(new ash::DragImageView(
5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      drag_replaced_view_->GetWidget()->GetNativeWindow()->GetRootWindow(),
5704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE));
571a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_->SetImage(icon);
572a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  gfx::Size size = drag_image_->GetPreferredSize();
573a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  size.set_width(size.width() * scale_factor);
574a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  size.set_height(size.height() * scale_factor);
575868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  drag_image_offset_ = gfx::Vector2d(size.width() / 2, size.height() / 2) +
576868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       cursor_offset_from_center;
577a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  gfx::Rect drag_image_bounds(
578f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      location_in_screen_coordinates - drag_image_offset_,
579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      size);
580a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_->SetBoundsInScreen(drag_image_bounds);
581a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_->SetWidgetVisible(true);
582a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
583a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::UpdateDragIconProxy(
585a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const gfx::Point& location_in_screen_coordinates) {
586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // TODO(jennyz): Investigate why drag_image_ becomes NULL at this point per
587a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // crbug.com/34722, while the app list item is still being dragged around.
588a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (drag_image_) {
589a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    drag_image_->SetScreenPosition(
590a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        location_in_screen_coordinates - drag_image_offset_);
591a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
592a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
593a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::DestroyDragIconProxy() {
595a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_.reset();
596a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_offset_ = gfx::Vector2d(0, 0);
597a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
598a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::StartDrag(const std::string& app_id,
6008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                          const gfx::Point& location_in_screen_coordinates) {
601b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Bail if an operation is already going on - or the cursor is not inside.
602b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // This could happen if mouse / touch operations overlap.
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (drag_and_drop_shelf_id_ ||
604b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !GetBoundsInScreen().Contains(location_in_screen_coordinates))
605b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return false;
606b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
607b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // If the AppsGridView (which was dispatching this event) was opened by our
6088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // button, ShelfView dragging operations are locked and we have to unlock.
609b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  CancelDrag(-1);
6107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  drag_and_drop_item_pinned_ = false;
611b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  drag_and_drop_app_id_ = app_id;
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  drag_and_drop_shelf_id_ =
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->GetShelfIDForAppID(drag_and_drop_app_id_);
6147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Check if the application is known and pinned - if not, we have to pin it so
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // that we can re-arrange the shelf order accordingly. Note that items have
6167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // to be pinned to give them the same (order) possibilities as a shortcut.
617a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // When an item is dragged from overflow to shelf, IsShowingOverflowBubble()
618a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // returns true. At this time, we don't need to pin the item.
619a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!IsShowingOverflowBubble() &&
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (!drag_and_drop_shelf_id_ ||
621a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       !delegate_->IsAppPinned(app_id))) {
622b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    delegate_->PinAppWithID(app_id);
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    drag_and_drop_shelf_id_ =
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        delegate_->GetShelfIDForAppID(drag_and_drop_app_id_);
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!drag_and_drop_shelf_id_)
626b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return false;
6277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    drag_and_drop_item_pinned_ = true;
628b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
629b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View* drag_and_drop_view = view_model_->view_at(
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      model_->ItemIndexByID(drag_and_drop_shelf_id_));
631b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(drag_and_drop_view);
632b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
633a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Since there is already an icon presented by the caller, we hide this item
634a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // for now. That has to be done by reducing the size since the visibility will
635a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // change once a regrouping animation is performed.
636a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  pre_drag_and_drop_size_ = drag_and_drop_view->size();
637a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_and_drop_view->SetSize(gfx::Size());
638a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
639b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // First we have to center the mouse cursor over the item.
640b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  gfx::Point pt = drag_and_drop_view->GetBoundsInScreen().CenterPoint();
641b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View::ConvertPointFromScreen(drag_and_drop_view, &pt);
642f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point point_in_root = location_in_screen_coordinates;
643f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ash::wm::ConvertPointFromScreen(
644f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ash::wm::GetRootWindowAt(location_in_screen_coordinates),
645f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      &point_in_root);
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ui::MouseEvent event(ui::ET_MOUSE_PRESSED, pt, point_in_root, 0, 0);
647f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PointerPressedOnButton(drag_and_drop_view,
648f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         ShelfButtonHost::DRAG_AND_DROP,
649f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         event);
650b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
651b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Drag the item where it really belongs.
652b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  Drag(location_in_screen_coordinates);
653b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return true;
654b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
655b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::Drag(const gfx::Point& location_in_screen_coordinates) {
6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!drag_and_drop_shelf_id_ ||
658b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !GetBoundsInScreen().Contains(location_in_screen_coordinates))
659b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return false;
660b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
661b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  gfx::Point pt = location_in_screen_coordinates;
662b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View* drag_and_drop_view = view_model_->view_at(
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      model_->ItemIndexByID(drag_and_drop_shelf_id_));
664f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ConvertPointFromScreen(drag_and_drop_view, &pt);
665f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point point_in_root = location_in_screen_coordinates;
666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ash::wm::ConvertPointFromScreen(
667f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ash::wm::GetRootWindowAt(location_in_screen_coordinates),
668f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      &point_in_root);
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ui::MouseEvent event(ui::ET_MOUSE_DRAGGED, pt, point_in_root, 0, 0);
670f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PointerDraggedOnButton(drag_and_drop_view,
671f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         ShelfButtonHost::DRAG_AND_DROP,
672f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         event);
673b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return true;
674b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
675b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::EndDrag(bool cancel) {
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!drag_and_drop_shelf_id_)
678b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
679b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
680b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View* drag_and_drop_view = view_model_->view_at(
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      model_->ItemIndexByID(drag_and_drop_shelf_id_));
682b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  PointerReleasedOnButton(
683f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      drag_and_drop_view, ShelfButtonHost::DRAG_AND_DROP, cancel);
684b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
685a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Either destroy the temporarily created item - or - make the item visible.
6867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (drag_and_drop_item_pinned_ && cancel)
687424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    delegate_->UnpinAppWithID(drag_and_drop_app_id_);
68858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  else if (drag_and_drop_view) {
68958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (cancel) {
69058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // When a hosted drag gets canceled, the item can remain in the same slot
69158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // and it might have moved within the bounds. In that case the item need
69258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // to animate back to its correct location.
69358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AnimateToIdealBounds();
69458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else {
69558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      drag_and_drop_view->SetSize(pre_drag_and_drop_size_);
69658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
69758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
698b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  drag_and_drop_shelf_id_ = 0;
700b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
701b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
7028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::LayoutToIdealBounds() {
7031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (bounds_animator_->IsAnimating()) {
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimateToIdealBounds();
7051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
7061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  IdealBounds ideal_bounds;
7091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
7101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds);
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
714a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ShelfView::UpdateAllButtonsVisibilityInOverflowMode() {
715a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The overflow button is not shown in overflow mode.
716a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  overflow_button_->SetVisible(false);
717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int last_button_index = model_->FirstPanelIndex() - 1;
718a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK_LT(last_visible_index_, view_model_->view_size());
719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
720a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool visible = i >= first_visible_index_ &&
721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        i <= last_visible_index_;
722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!ash::switches::UseAlternateShelfLayout())
723a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      visible &= i != last_button_index;
724a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
725a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // To track the dragging of |drag_view_| continuously, its visibility
726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // should be always true regardless of its position.
727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (dragged_off_from_overflow_to_shelf_ &&
728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        view_model_->view_at(i) == drag_view_)
729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      view_model_->view_at(i)->SetVisible(true);
730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    else
731a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      view_model_->view_at(i)->SetVisible(visible);
732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
733a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::CalculateIdealBounds(IdealBounds* bounds) {
7361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int available_size = layout_manager_->PrimaryAxisValue(width(), height());
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(model_->item_count() == view_model_->view_size());
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!available_size)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int first_panel_index = model_->FirstPanelIndex();
742ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int last_button_index = first_panel_index - 1;
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initial x,y values account both leading_inset in primary
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // coordinate and secondary coordinate based on the dynamic edge of the
7465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // shelf (eg top edge on bottom-aligned shelf).
7471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int inset = ash::switches::UseAlternateShelfLayout() ? 0 : leading_inset_;
7481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int x = layout_manager_->SelectValueForShelfAlignment(inset, 0, 0, inset);
7491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int y = layout_manager_->SelectValueForShelfAlignment(0, inset, inset, 0);
750ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
751f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int button_size = GetButtonSize();
752f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int button_spacing = GetButtonSpacing();
753ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
7541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int w = layout_manager_->PrimaryAxisValue(button_size, width());
7551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int h = layout_manager_->PrimaryAxisValue(height(), button_size);
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i < first_visible_index_) {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0));
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
763ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (i != last_button_index) {
7641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      x = layout_manager_->PrimaryAxisValue(x + w + button_spacing, x);
7651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      y = layout_manager_->PrimaryAxisValue(y, y + h + button_spacing);
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_overflow_mode()) {
770a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    UpdateAllButtonsVisibilityInOverflowMode();
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // To address Fitt's law, we make the first shelf button include the
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // leading inset (if there is one).
776ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!ash::switches::UseAlternateShelfLayout()) {
777ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (view_model_->view_size() > 0) {
778ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      view_model_->set_ideal_bounds(0, gfx::Rect(gfx::Size(
7791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          layout_manager_->PrimaryAxisValue(inset + w, w),
7801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          layout_manager_->PrimaryAxisValue(h, inset + h))));
781ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Right aligned icons.
785ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int end_position = available_size - button_spacing;
7861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  x = layout_manager_->PrimaryAxisValue(end_position, 0);
7871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  y = layout_manager_->PrimaryAxisValue(0, end_position);
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = view_model_->view_size() - 1;
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       i >= first_panel_index; --i) {
7901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    x = layout_manager_->PrimaryAxisValue(x - w - button_spacing, x);
7911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    y = layout_manager_->PrimaryAxisValue(y, y - h - button_spacing);
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
7931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    end_position = layout_manager_->PrimaryAxisValue(x, y);
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Icons on the left / top are guaranteed up to kLeftIconProportion of
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the available space.
7981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int last_icon_position = layout_manager_->PrimaryAxisValue(
799ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      view_model_->ideal_bounds(last_button_index).right(),
800ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      view_model_->ideal_bounds(last_button_index).bottom())
801ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      + button_size + inset;
802ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!ash::switches::UseAlternateShelfLayout())
803ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      last_icon_position += button_size;
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int reserved_icon_space = available_size * kReservedNonPanelIconProportion;
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (last_icon_position < reserved_icon_space)
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    end_position = last_icon_position;
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    end_position = std::max(end_position, reserved_icon_space);
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bounds->overflow_bounds.set_size(
8111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      gfx::Size(layout_manager_->PrimaryAxisValue(w, width()),
8121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                layout_manager_->PrimaryAxisValue(height(), h)));
8134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (ash::switches::UseAlternateShelfLayout()) {
815ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    last_visible_index_ = DetermineLastVisibleIndex(
816ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        end_position - button_size);
8174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
818ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    last_visible_index_ = DetermineLastVisibleIndex(
819ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        end_position - inset - 2 * button_size);
8204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  last_hidden_index_ = DetermineFirstVisiblePanelIndex(end_position) - 1;
822ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool show_overflow =
823ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      ((ash::switches::UseAlternateShelfLayout() ? 0 : 1) +
824ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      last_visible_index_ < last_button_index ||
825ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      last_hidden_index_ >= first_panel_index);
826ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
827ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Create Space for the overflow button
828ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (show_overflow && ash::switches::UseAlternateShelfLayout() &&
82958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      last_visible_index_ > 0 && last_visible_index_ < last_button_index)
830ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    --last_visible_index_;
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
832ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bool visible = i <= last_visible_index_ || i > last_hidden_index_;
833ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // Always show the app list.
834ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (!ash::switches::UseAlternateShelfLayout())
835ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      visible |= (i == last_button_index);
8364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // To receive drag event continously from |drag_view_| during the dragging
8374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // off from the shelf, don't make |drag_view_| invisible. It will be
8384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // eventually invisible and removed from the |view_model_| by
8394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // FinalizeRipOffDrag().
8404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (dragged_off_shelf_ && view_model_->view_at(i) == drag_view_)
8414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      continue;
842ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    view_model_->view_at(i)->SetVisible(visible);
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->SetVisible(show_overflow);
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (show_overflow) {
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(0, view_model_->view_size());
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (last_visible_index_ == -1) {
8491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      x = layout_manager_->SelectValueForShelfAlignment(inset, 0, 0, inset);
8501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      y = layout_manager_->SelectValueForShelfAlignment(0, inset, inset, 0);
85158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else if (last_visible_index_ == last_button_index
85258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        && !ash::switches::UseAlternateShelfLayout()) {
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      x = view_model_->ideal_bounds(last_visible_index_).x();
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      y = view_model_->ideal_bounds(last_visible_index_).y();
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      x = layout_manager_->PrimaryAxisValue(
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).right(),
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).x());
8591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      y = layout_manager_->PrimaryAxisValue(
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).y(),
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).bottom());
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set all hidden panel icon positions to be on the overflow button.
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = first_panel_index; i <= last_hidden_index_; ++i)
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Add more space between last visible item and overflow button.
8681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Without this, two buttons look too close compared with other items.
8691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (ash::switches::UseAlternateShelfLayout()) {
8701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      x = layout_manager_->PrimaryAxisValue(x + button_spacing, x);
8711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      y = layout_manager_->PrimaryAxisValue(y, y + button_spacing);
8721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
8731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
874ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bounds->overflow_bounds.set_x(x);
875ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bounds->overflow_bounds.set_y(y);
876ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (!ash::switches::UseAlternateShelfLayout()) {
877ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      // Position app list after overflow button.
878ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      gfx::Rect app_list_bounds = view_model_->ideal_bounds(last_button_index);
879ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
8801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      x = layout_manager_->PrimaryAxisValue(x + w + button_spacing, x);
8811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      y = layout_manager_->PrimaryAxisValue(y, y + h + button_spacing);
882ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      app_list_bounds.set_x(x);
883ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      app_list_bounds.set_y(y);
884ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      view_model_->set_ideal_bounds(last_button_index, app_list_bounds);
885ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (overflow_bubble_.get() && overflow_bubble_->IsShowing())
8878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      UpdateOverflowRange(overflow_bubble_->shelf_view());
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
889c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (overflow_bubble_)
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      overflow_bubble_->Hide();
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::DetermineLastVisibleIndex(int max_value) const {
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int index = model_->FirstPanelIndex() - 1;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (index >= 0 &&
8971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             view_model_->ideal_bounds(index).right(),
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             view_model_->ideal_bounds(index).bottom()) > max_value) {
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index--;
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index;
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::DetermineFirstVisiblePanelIndex(int min_value) const {
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int index = model_->FirstPanelIndex();
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (index < view_model_->view_size() &&
9081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(index).right(),
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(index).bottom()) < min_value) {
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++index;
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return index;
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ShelfView::AddIconObserver(ShelfIconObserver* observer) {
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ShelfView::RemoveIconObserver(ShelfIconObserver* observer) {
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::AnimateToIdealBounds() {
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdealBounds ideal_bounds;
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    View* view = view_model_->view_at(i);
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds_animator_->AnimateViewTo(view, view_model_->ideal_bounds(i));
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Now that the item animation starts, we have to make sure that the
9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // padding of the first gets properly transferred to the new first item.
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i && view->border())
9335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      view->SetBorder(views::Border::NullBorder());
9342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (!i && !view->border())
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdateFirstButtonPadding();
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds);
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)views::View* ShelfView::CreateViewForItem(const ShelfItem& item) {
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = NULL;
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (item.type) {
94390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case TYPE_BROWSER_SHORTCUT:
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_SHORTCUT:
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TYPE_WINDOWED_APP:
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_PLATFORM_APP:
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TYPE_DIALOG:
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_PANEL: {
949f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShelfButton* button = ShelfButton::Create(this, this, layout_manager_);
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button->SetImage(item.image);
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReflectItemStatus(item, button);
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view = button;
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_LIST: {
957eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (ash::switches::UseAlternateShelfLayout()) {
9581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        view = new AlternateAppListButton(this,
9591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                          this,
9601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                          layout_manager_->shelf_widget());
961eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      } else {
962f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // TODO(dave): turn this into a ShelfButton too.
963eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        AppListButton* button = new AppListButton(this, this);
964eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        button->SetImageAlignment(
9651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            layout_manager_->SelectValueForShelfAlignment(
966eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_CENTER,
967eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_LEFT,
968eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_RIGHT,
969eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_CENTER),
9701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            layout_manager_->SelectValueForShelfAlignment(
971eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_TOP,
972eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_MIDDLE,
973eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_MIDDLE,
974eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                views::ImageButton::ALIGN_BOTTOM));
975eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        view = button;
976eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->set_context_menu_controller(this);
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(view);
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigureChildView(view);
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view;
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::FadeIn(views::View* view) {
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetVisible(true);
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->layer()->SetOpacity(0);
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AnimateToIdealBounds();
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->SetAnimationDelegate(
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view, new FadeInAnimationDelegate(view), true);
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event) {
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!dragging());
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drag_view_);
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_pointer_ = pointer;
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_drag_index_ = view_model_->GetIndexOfView(drag_view_);
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1004424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (start_drag_index_== -1) {
1005424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    CancelDrag(-1);
1006424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
1007424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1008424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the item is no longer draggable, bail out.
1010a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
10114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[start_drag_index_].id);
10124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!item_delegate->IsDraggable()) {
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelDrag(-1);
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move the view to the front so that it appears on top of other views.
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReorderChildView(drag_view_, -1);
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->StopAnimatingView(drag_view_);
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ContinueDrag(const ui::LocatedEvent& event) {
1023424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Due to a syncing operation the application might have been removed.
1024424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Bail if it is gone.
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int current_index = view_model_->GetIndexOfView(drag_view_);
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(-1, current_index);
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1028a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
10294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[current_index].id);
10304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!item_delegate->IsDraggable()) {
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelDrag(-1);
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // If this is not a drag and drop host operation and not the app list item,
1036424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // check if the item got ripped off the shelf - if it did we are done.
1037a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!drag_and_drop_shelf_id_ &&
1038424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      RemovableByRipOff(current_index) != NOT_REMOVABLE) {
1039424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (HandleRipOffDrag(event))
1040424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return;
1041424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // The rip off handler could have changed the location of the item.
1042424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    current_index = view_model_->GetIndexOfView(drag_view_);
1043424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1044424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1045424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // TODO: I don't think this works correctly with RTL.
1046424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  gfx::Point drag_point(event.location());
1047f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ConvertPointToTarget(drag_view_, this, &drag_point);
1048424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Constrain the location to the range of valid indices for the type.
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<int, int> indices(GetDragRange(current_index));
10512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int first_drag_index = indices.first;
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int last_drag_index = indices.second;
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the last index isn't valid, we're overflowing. Constrain to the app list
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (which is the last visible item).
10552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (first_drag_index < model_->FirstPanelIndex() &&
10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      last_drag_index > last_visible_index_)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_drag_index = last_visible_index_;
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x = 0, y = 0;
10591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (layout_manager_->IsHorizontalAlignment()) {
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = std::max(view_model_->ideal_bounds(indices.first).x(),
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     drag_point.x() - drag_offset_);
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = std::min(view_model_->ideal_bounds(last_drag_index).right() -
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 view_model_->ideal_bounds(current_index).width(),
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 x);
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (drag_view_->x() == x)
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_view_->SetX(x);
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    y = std::max(view_model_->ideal_bounds(indices.first).y(),
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     drag_point.y() - drag_offset_);
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    y = std::min(view_model_->ideal_bounds(last_drag_index).bottom() -
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 view_model_->ideal_bounds(current_index).height(),
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 y);
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (drag_view_->y() == y)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_view_->SetY(y);
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_index =
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      views::ViewModelUtils::DetermineMoveIndex(
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          *view_model_, drag_view_,
10821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          layout_manager_->IsHorizontalAlignment() ?
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              views::ViewModelUtils::HORIZONTAL :
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              views::ViewModelUtils::VERTICAL,
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          x, y);
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_index =
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::min(indices.second, std::max(target_index, indices.first));
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_index == current_index)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Change the model, the ShelfItemMoved() callback will handle the
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |view_model_| update.
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->Move(current_index, target_index);
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->StopAnimatingView(drag_view_);
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::HandleRipOffDrag(const ui::LocatedEvent& event) {
1098424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int current_index = view_model_->GetIndexOfView(drag_view_);
1099424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK_NE(-1, current_index);
1100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string dragged_app_id =
11015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->GetAppIDForShelfID(model_->items()[current_index].id);
1102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point screen_location = event.root_location();
1104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ash::wm::ConvertPointToScreen(GetWidget()->GetNativeWindow()->GetRootWindow(),
1105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                &screen_location);
1106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // To avoid ugly forwards and backwards flipping we use different constants
1108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // for ripping off / re-inserting the items.
1109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (dragged_off_shelf_) {
1110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // If the shelf/overflow bubble bounds contains |screen_location| we insert
1111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // the item back into the shelf.
1112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (GetBoundsForDragInsertInScreen().Contains(screen_location)) {
1113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (dragged_off_from_overflow_to_shelf_) {
1114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // During the dragging an item from Shelf to Overflow, it can enter here
1115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // directly because both are located very closly.
1116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        main_shelf_->EndDrag(true);
1117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // Stops the animation of |drag_view_| and sets its bounds explicitly
1118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // becase ContinueDrag() stops its animation. Without this, unexpected
1119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // bounds will be set.
1120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        bounds_animator_->StopAnimatingView(drag_view_);
1121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        int drag_view_index = view_model_->GetIndexOfView(drag_view_);
1122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index));
1123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        dragged_off_from_overflow_to_shelf_ = false;
1124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
1125424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Destroy our proxy view item.
1126424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      DestroyDragIconProxy();
1127424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Re-insert the item and return simply false since the caller will handle
1128424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // the move as in any normal case.
1129424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      dragged_off_shelf_ = false;
1130424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      drag_view_->layer()->SetOpacity(1.0f);
1131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // The size of Overflow bubble should be updated immediately when an item
1132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // is re-inserted.
1133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (is_overflow_mode())
1134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        PreferredSizeChanged();
1135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
1136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (is_overflow_mode() &&
1137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               main_shelf_->GetBoundsForDragInsertInScreen().Contains(
1138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                   screen_location)) {
1139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (!dragged_off_from_overflow_to_shelf_) {
1140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        dragged_off_from_overflow_to_shelf_ = true;
1141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        drag_image_->SetOpacity(1.0f);
1142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        main_shelf_->StartDrag(dragged_app_id, screen_location);
1143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      } else {
1144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        main_shelf_->Drag(screen_location);
1145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
1146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (dragged_off_from_overflow_to_shelf_) {
1147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Makes the |drag_image_| partially disappear again.
1148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_ = false;
1149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_image_->SetOpacity(kDraggedImageOpacity);
1150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_->EndDrag(true);
1151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bounds_animator_->StopAnimatingView(drag_view_);
1152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      int drag_view_index = view_model_->GetIndexOfView(drag_view_);
1153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index));
1154424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1155424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Move our proxy view item.
1156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    UpdateDragIconProxy(screen_location);
1157424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
1158424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1159424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Check if we are too far away from the shelf to enter the ripped off state.
1160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Determine the distance to the shelf.
11615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int delta = CalculateShelfDistance(screen_location);
1162424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (delta > kRipOffDistance) {
1163424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Create a proxy view item which can be moved anywhere.
1164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ShelfButton* button = static_cast<ShelfButton*>(drag_view_);
1165424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    CreateDragIconProxy(event.root_location(),
1166424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        button->GetImage(),
1167424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        drag_view_,
1168424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        gfx::Vector2d(0, 0),
1169424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        kDragAndDropProxyScale);
1170424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    drag_view_->layer()->SetOpacity(0.0f);
11714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    dragged_off_shelf_ = true;
1172424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (RemovableByRipOff(current_index) == REMOVABLE) {
11731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // Move the item to the front of the first panel item and hide it.
11745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // ShelfItemMoved() callback will handle the |view_model_| update and
11751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // call AnimateToIdealBounds().
1176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (current_index != model_->FirstPanelIndex() - 1) {
1177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        model_->Move(current_index, model_->FirstPanelIndex() - 1);
1178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        StartFadeInLastVisibleItem();
1179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      } else if (is_overflow_mode()) {
1180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Overflow bubble should be shrunk when an item is ripped off.
1181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        PreferredSizeChanged();
1182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
1183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Make the item partially disappear to show that it will get removed if
1184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // dropped.
1185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_image_->SetOpacity(kDraggedImageOpacity);
1186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
1188424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1189424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return false;
1190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
1191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
11928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::FinalizeRipOffDrag(bool cancel) {
1193424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!dragged_off_shelf_)
1194424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
1195424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Make sure we do not come in here again.
1196424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  dragged_off_shelf_ = false;
1197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Coming here we should always have a |drag_view_|.
1199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(drag_view_);
1200424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int current_index = view_model_->GetIndexOfView(drag_view_);
1201424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // If the view isn't part of the model anymore (|current_index| == -1), a sync
1202424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // operation must have removed it. In that case we shouldn't change the model
1203424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // and only delete the proxy image.
1204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (current_index == -1) {
1205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    DestroyDragIconProxy();
1206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
1207424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1208424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1209424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Set to true when the animation should snap back to where it was before.
1210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  bool snap_back = false;
1211424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Items which cannot be dragged off will be handled as a cancel.
1212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!cancel) {
1213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (dragged_off_from_overflow_to_shelf_) {
1214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_ = false;
1215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_->EndDrag(false);
1216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_view_->layer()->SetOpacity(1.0f);
1217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (RemovableByRipOff(current_index) != REMOVABLE) {
1218a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Make sure we do not try to remove un-removable items like items which
1219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // were not pinned or have to be always there.
1220424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      cancel = true;
1221424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back = true;
1222424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    } else {
1223424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Make sure the item stays invisible upon removal.
1224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      drag_view_->SetVisible(false);
1225424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      std::string app_id =
12265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          delegate_->GetAppIDForShelfID(model_->items()[current_index].id);
1227424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      delegate_->UnpinAppWithID(app_id);
1228424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1229424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1230424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (cancel || snap_back) {
1231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (dragged_off_from_overflow_to_shelf_) {
1232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_ = false;
1233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Main shelf handles revert of dragged item.
1234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_->EndDrag(true);
1235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_view_->layer()->SetOpacity(1.0f);
1236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (!cancelling_drag_model_changed_) {
1237424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Only do something if the change did not come through a model change.
1238424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      gfx::Rect drag_bounds = drag_image_->GetBoundsInScreen();
1239424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      gfx::Point relative_to = GetBoundsInScreen().origin();
1240424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      gfx::Rect target(
1241424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          gfx::PointAtOffsetFromOrigin(drag_bounds.origin()- relative_to),
1242424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          drag_bounds.size());
1243424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      drag_view_->SetBoundsRect(target);
1244424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Hide the status from the active item since we snap it back now. Upon
1245424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // animation end the flag gets cleared if |snap_back_from_rip_off_view_|
1246424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // is set.
1247424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back_from_rip_off_view_ = drag_view_;
1248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShelfButton* button = static_cast<ShelfButton*>(drag_view_);
1249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_HIDDEN);
1250424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // When a canceling drag model is happening, the view model is diverged
1251424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // from the menu model and movements / animations should not be done.
1252424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      model_->Move(current_index, start_drag_index_);
1253424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      AnimateToIdealBounds();
1254424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1255424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    drag_view_->layer()->SetOpacity(1.0f);
1256424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1257424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DestroyDragIconProxy();
1258424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
1259424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
12608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ShelfView::RemovableState ShelfView::RemovableByRipOff(int index) {
1261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(index >= 0 && index < model_->item_count());
12625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfItemType type = model_->items()[index].type;
12635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type == TYPE_APP_LIST || type == TYPE_DIALOG || !delegate_->CanPin())
1264424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return NOT_REMOVABLE;
12655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = delegate_->GetAppIDForShelfID(model_->items()[index].id);
1267424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Note: Only pinned app shortcuts can be removed!
1268424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return (type == TYPE_APP_SHORTCUT && delegate_->IsAppPinned(app_id)) ?
1269424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      REMOVABLE : DRAGGABLE;
1270424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
1271424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
12725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShelfView::SameDragType(ShelfItemType typea, ShelfItemType typeb) const {
1273ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  switch (typea) {
1274ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_APP_SHORTCUT:
1275ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_BROWSER_SHORTCUT:
1276ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return (typeb == TYPE_APP_SHORTCUT || typeb == TYPE_BROWSER_SHORTCUT);
127768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    case TYPE_APP_LIST:
1278424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case TYPE_PLATFORM_APP:
1279ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_WINDOWED_APP:
1280ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_APP_PANEL:
12815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TYPE_DIALOG:
1282ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return typeb == typea;
1283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case TYPE_UNDEFINED:
12845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTREACHED() << "ShelfItemType must be set.";
1285424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::pair<int, int> ShelfView::GetDragRange(int index) {
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int min_index = -1;
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_index = -1;
12945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfItemType type = model_->items()[index].type;
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < model_->item_count(); ++i) {
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SameDragType(model_->items()[i].type, type)) {
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (min_index == -1)
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        min_index = i;
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_index = i;
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::pair<int, int>(min_index, max_index);
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ConfigureChildView(views::View* view) {
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetPaintToLayer(true);
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->layer()->SetFillsBoundsOpaquely(false);
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ToggleOverflowBubble() {
13112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsShowingOverflowBubble()) {
13122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    overflow_bubble_->Hide();
13132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
13142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!overflow_bubble_)
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_bubble_.reset(new OverflowBubble());
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShelfView* overflow_view =
13201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ShelfView(model_, delegate_, layout_manager_);
1321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  overflow_view->overflow_mode_ = true;
13222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->Init();
13234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  overflow_view->set_owner_overflow_bubble(overflow_bubble_.get());
13242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->OnShelfAlignmentChanged();
1325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  overflow_view->main_shelf_ = this;
13262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateOverflowRange(overflow_view);
13272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_bubble_->Show(overflow_button_, overflow_view);
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shell::GetInstance()->UpdateShelfVisibility();
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::UpdateFirstButtonPadding() {
1334ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (ash::switches::UseAlternateShelfLayout())
1335ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
1336ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
13375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Creates an empty border for first shelf button to make included leading
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // inset act as the button's padding. This is only needed on button creation
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and when shelf alignment changes.
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_model_->view_size() > 0) {
13415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    view_model_->view_at(0)->SetBorder(views::Border::CreateEmptyBorder(
13421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        layout_manager_->PrimaryAxisValue(0, leading_inset_),
13431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        layout_manager_->PrimaryAxisValue(leading_inset_, 0),
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        0,
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        0));
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnFadeOutAnimationEnded() {
13502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AnimateToIdealBounds();
13511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  StartFadeInLastVisibleItem();
13521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
13532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ShelfView::StartFadeInLastVisibleItem() {
13552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If overflow button is visible and there is a valid new last item, fading
13562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the new last item in after sliding animation is finished.
13572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (overflow_button_->visible() && last_visible_index_ >= 0) {
13582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    views::View* last_visible_view = view_model_->view_at(last_visible_index_);
13592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    last_visible_view->layer()->SetOpacity(0);
13602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds_animator_->SetAnimationDelegate(
13612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        last_visible_view,
13628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        new ShelfView::StartFadeAnimationDelegate(this, last_visible_view),
13632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        true);
13642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
13662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) {
13682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int first_overflow_index = last_visible_index_ + 1;
13692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int last_overflow_index = last_hidden_index_;
13702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LE(first_overflow_index, last_overflow_index);
13712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(last_overflow_index, view_model_->view_size());
13722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->first_visible_index_ = first_overflow_index;
13742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->last_visible_index_ = last_overflow_index;
13752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
13762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int ShelfView::GetButtonSize() const {
1378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return ash::switches::UseAlternateShelfLayout() ?
13795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kButtonSize : kShelfPreferredSize;
1380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int ShelfView::GetButtonSpacing() const {
1383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return ash::switches::UseAlternateShelfLayout() ?
1384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      kAlternateButtonSpacing : kButtonSpacing;
1385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
13878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) {
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect active_bounds;
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < child_count(); ++i) {
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* child = child_at(i);
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (child == overflow_button_)
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
13942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!ShouldShowTooltipForView(child))
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect child_bounds = child->GetMirroredBounds();
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    active_bounds.Union(child_bounds);
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !active_bounds.Contains(cursor_location);
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)gfx::Rect ShelfView::GetVisibleItemsBoundsInScreen() {
14054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  gfx::Size preferred_size = GetPreferredSize();
14064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0);
14074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ConvertPointToScreen(this, &origin);
14084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return gfx::Rect(origin, preferred_size);
14094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
14104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Rect ShelfView::GetBoundsForDragInsertInScreen() {
1412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Size preferred_size;
1413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (is_overflow_mode()) {
1414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(owner_overflow_bubble_);
1415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    gfx::Rect bubble_bounds =
1416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        owner_overflow_bubble_->bubble_view()->GetBubbleBounds();
1417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    preferred_size = bubble_bounds.size();
1418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
1419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const int preferred_shelf_size = layout_manager_->GetPreferredShelfSize();
1420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const int last_button_index = view_model_->view_size() - 1;
1422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    gfx::Rect last_button_bounds =
1423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        view_model_->view_at(last_button_index)->bounds();
1424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (overflow_button_->visible() &&
1425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        model_->GetItemIndexForType(TYPE_APP_PANEL) == -1) {
1426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // When overflow button is visible and shelf has no panel items,
1427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // last_button_bounds should be overflow button's bounds.
1428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      last_button_bounds = overflow_button_->bounds();
1429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (layout_manager_->IsHorizontalAlignment()) {
1432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      preferred_size = gfx::Size(last_button_bounds.right() + leading_inset_,
1433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 preferred_shelf_size);
1434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else {
1435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      preferred_size = gfx::Size(preferred_shelf_size,
1436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 last_button_bounds.bottom() + leading_inset_);
1437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0);
1440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1441f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // In overflow mode, we should use OverflowBubbleView as a source for
1442f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // converting |origin| to screen coordinates. When a scroll operation is
1443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // occurred in OverflowBubble, the bounds of ShelfView in OverflowBubble can
1444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // be changed.
1445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (is_overflow_mode())
1446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ConvertPointToScreen(owner_overflow_bubble_->bubble_view(), &origin);
1447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  else
1448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ConvertPointToScreen(this, &origin);
1449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return gfx::Rect(origin, preferred_size);
1451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1452f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
14538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::CancelDrag(int modified_index) {
1454424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FinalizeRipOffDrag(true);
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!drag_view_)
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return modified_index;
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_dragging = dragging();
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int drag_view_index = view_model_->GetIndexOfView(drag_view_);
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_pointer_ = NONE;
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_view_ = NULL;
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_view_index == modified_index) {
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The view that was being dragged is being modified. Don't do anything.
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return modified_index;
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!was_dragging)
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return modified_index;
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Restore previous position, tracking the position of the modified view.
14692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool at_end = modified_index == view_model_->view_size();
14702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View* modified_view =
14712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (modified_index >= 0 && !at_end) ?
14722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      view_model_->view_at(modified_index) : NULL;
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->Move(drag_view_index, start_drag_index_);
14742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the modified view will be at the end of the list, return the new end of
14762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the list.
14772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (at_end)
14782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return view_model_->view_size();
14792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return modified_view ? view_model_->GetIndexOfView(modified_view) : -1;
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)gfx::Size ShelfView::GetPreferredSize() {
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdealBounds ideal_bounds;
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const int preferred_size = layout_manager_->GetPreferredShelfSize();
14874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int last_button_index = is_overflow_mode() ?
1489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      last_visible_index_ : view_model_->view_size() - 1;
1490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // When an item is dragged off from the overflow bubble, it is moved to last
1492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // position and and changed to invisible. Overflow bubble size should be
1493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // shrunk to fit only for visible items.
1494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // If |dragged_off_from_overflow_to_shelf_| is set, there will be no invisible
1495a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // items in the shelf.
1496a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (is_overflow_mode() &&
1497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_shelf_ &&
1498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      !dragged_off_from_overflow_to_shelf_ &&
1499f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      RemovableByRipOff(view_model_->GetIndexOfView(drag_view_)) == REMOVABLE)
1500f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    last_button_index--;
1501f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect last_button_bounds =
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_button_index  >= first_visible_index_ ?
1504f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          view_model_->ideal_bounds(last_button_index) :
15054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          gfx::Rect(gfx::Size(preferred_size, preferred_size));
15062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (layout_manager_->IsHorizontalAlignment()) {
15081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return gfx::Size(last_button_bounds.right() + leading_inset_,
15094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     preferred_size);
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return gfx::Size(preferred_size,
15131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   last_button_bounds.bottom() + leading_inset_);
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
15175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This bounds change is produced by the shelf movement and all content has
15185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // to follow. Using an animation at that time would produce a time lag since
15195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the animation of the BoundsAnimator has itself a delay before it arrives
15205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // at the required location. As such we tell the animator to go there
15215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // immediately.
15225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BoundsAnimatorDisabler disabler(bounds_animator_.get());
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LayoutToIdealBounds();
15241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
15251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    OnShelfIconPositionsChanged());
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsShowingOverflowBubble())
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_bubble_->Hide();
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::FocusTraversable* ShelfView::GetPaneFocusTraversable() {
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ShelfView::GetAccessibleState(ui::AXViewState* state) {
1536a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_TOOLBAR;
15372385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  state->name = l10n_util::GetStringUTF16(IDS_ASH_SHELF_ACCESSIBLE_NAME);
153890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
153990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnGestureEvent(ui::GestureEvent* event) {
15412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (gesture_handler_.ProcessGestureEvent(*event))
15422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event->StopPropagation();
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ShelfView::ShelfItemAdded(int model_index) {
15462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
15472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoReset<bool> cancelling_drag(
15482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelling_drag_model_changed_, true);
15492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model_index = CancelDrag(model_index);
15502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = CreateViewForItem(model_->items()[model_index]);
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(view);
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hide the view, it'll be made visible when the animation is done. Using
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // opacity 0 here to avoid messing with CalculateIdealBounds which touches
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the view's visibility.
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->layer()->SetOpacity(0);
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_->Add(view, model_index);
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give the button its ideal bounds. That way if we end up animating the
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // button before this animation completes it doesn't appear at some random
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // spot (because it was in the middle of animating from 0,0 0x0 to its
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // target).
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdealBounds ideal_bounds;
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetBoundsRect(view_model_->ideal_bounds(model_index));
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The first animation moves all the views to their target position. |view|
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is hidden, so it visually appears as though we are providing space for
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it. When done we'll fade the view in.
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AnimateToIdealBounds();
15712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (model_index <= last_visible_index_ ||
15722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      model_index >= model_->FirstPanelIndex()) {
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds_animator_->SetAnimationDelegate(
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view, new StartFadeAnimationDelegate(this, view), true);
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Undo the hiding if animation does not run.
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view->layer()->SetOpacity(1.0f);
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) {
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id == context_menu_id_)
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    launcher_menu_runner_.reset();
15842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
15852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoReset<bool> cancelling_drag(
15862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelling_drag_model_changed_, true);
15872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model_index = CancelDrag(model_index);
15882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = view_model_->view_at(model_index);
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_->Remove(model_index);
15910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
15920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // When the overflow bubble is visible, the overflow range needs to be set
15930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // before CalculateIdealBounds() gets called. Otherwise CalculateIdealBounds()
15945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // could trigger a ShelfItemChanged() by hiding the overflow bubble and
1595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // since the overflow bubble is not yet synced with the ShelfModel this
15960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // could cause a crash.
15972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (overflow_bubble_ && overflow_bubble_->IsShowing()) {
15982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    last_hidden_index_ = std::min(last_hidden_index_,
15992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  view_model_->view_size() - 1);
16008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    UpdateOverflowRange(overflow_bubble_->shelf_view());
16012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1602d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
16030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (view->visible()) {
16040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // The first animation fades out the view. When done we'll animate the rest
16050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // of the views to their target location.
16060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    bounds_animator_->AnimateViewTo(view, view->bounds());
16070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    bounds_animator_->SetAnimationDelegate(
16080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        view, new FadeOutAnimationDelegate(this, view), true);
16090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
16100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // We don't need to show a fade out animation for invisible |view|. When an
16110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // item is ripped out from the shelf, its |view| is already invisible.
16120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    AnimateToIdealBounds();
16130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
16140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1615d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Close the tooltip because it isn't needed any longer and its anchor view
1616d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // will be deleted soon.
1617d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (tooltip_->GetCurrentAnchorView() == view)
1618d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    tooltip_->Close();
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) {
16225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ShelfItem& item(model_->items()[model_index]);
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_item.type != item.type) {
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Type changed, swap the views.
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_index = CancelDrag(model_index);
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<views::View> old_view(view_model_->view_at(model_index));
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds_animator_->StopAnimatingView(old_view.get());
16283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Removing and re-inserting a view in our view model will strip the ideal
16293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // bounds from the item. To avoid recalculation of everything the bounds
16303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // get remembered and restored after the insertion to the previous value.
16313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    gfx::Rect old_ideal_bounds = view_model_->ideal_bounds(model_index);
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->Remove(model_index);
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* new_view = CreateViewForItem(item);
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(new_view);
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->Add(new_view, model_index);
16363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    view_model_->set_ideal_bounds(model_index, old_ideal_bounds);
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_view->SetBoundsRect(old_view->bounds());
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = view_model_->view_at(model_index);
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (item.type) {
16432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TYPE_BROWSER_SHORTCUT:
1644f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Fallthrough for the new Shelf since it needs to show the activation
16452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // change as well.
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_SHORTCUT:
16472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TYPE_WINDOWED_APP:
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_PLATFORM_APP:
16495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TYPE_DIALOG:
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_PANEL: {
1651f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShelfButton* button = static_cast<ShelfButton*>(view);
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReflectItemStatus(item, button);
16532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // The browser shortcut is currently not a "real" item and as such the
16542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // the image is bogous as well. We therefore keep the image as is for it.
16552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (item.type != TYPE_BROWSER_SHORTCUT)
16562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        button->SetImage(item.image);
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button->SchedulePaint();
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ShelfView::ShelfItemMoved(int start_index, int target_index) {
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_->Move(start_index, target_index);
16685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // When cancelling a drag due to a shelf item being added, the currently
16692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // dragged item is moved back to its initial position. AnimateToIdealBounds
16702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // will be called again when the new item is added to the |view_model_| but
16712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // at this time the |view_model_| is inconsistent with the |model_|.
16722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!cancelling_drag_model_changed_)
16732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AnimateToIdealBounds();
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1676f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ShelfView::ShelfStatusChanged() {
1677eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (ash::switches::UseAlternateShelfLayout())
1678eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppListButton* app_list_button =
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<AppListButton*>(GetAppListButtonView());
1681f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (model_->status() == ShelfModel::STATUS_LOADING)
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    app_list_button->StartLoadingAnimation();
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    app_list_button->StopLoadingAnimation();
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PointerPressedOnButton(views::View* view,
16888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       Pointer pointer,
16898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       const ui::LocatedEvent& event) {
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_view_)
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = view_model_->GetIndexOfView(view);
1694424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (index == -1)
1695424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
1696424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
16984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[index].id);
16994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (view_model_->view_size() <= 1 || !item_delegate->IsDraggable())
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // View is being deleted or not draggable, ignore request.
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_view_ = view;
17031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  drag_offset_ = layout_manager_->PrimaryAxisValue(event.x(), event.y());
1704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentUsage",
1705f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      layout_manager_->SelectValueForShelfAlignment(
1706f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM,
1707f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT,
1708f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT,
1709f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          -1),
1710f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT);
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PointerDraggedOnButton(views::View* view,
17148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       Pointer pointer,
17158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       const ui::LocatedEvent& event) {
17160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // To prepare all drag types (moving an item in the shelf and dragging off),
17170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // we should check the x-axis and y-axis offset.
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dragging() && drag_view_ &&
17190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      ((abs(event.x() - drag_offset_) >= kMinimumDragDistance) ||
17200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       (abs(event.y() - drag_offset_) >= kMinimumDragDistance))) {
17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PrepareForDrag(pointer, event);
17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_pointer_ == pointer)
17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ContinueDrag(event);
17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PointerReleasedOnButton(views::View* view,
17288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                        Pointer pointer,
17298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                        bool canceled) {
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (canceled) {
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelDrag(-1);
17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (drag_pointer_ == pointer) {
1733424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    FinalizeRipOffDrag(false);
17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_pointer_ = NONE;
17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimateToIdealBounds();
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1737ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // If the drag pointer is NONE, no drag operation is going on and the
1738ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // drag_view can be released.
1739ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (drag_pointer_ == NONE)
1740ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    drag_view_ = NULL;
17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::MouseMovedOverButton(views::View* view) {
17442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!ShouldShowTooltipForView(view))
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tooltip_->IsVisible())
17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->ResetTimer();
17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::MouseEnteredButton(views::View* view) {
17522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!ShouldShowTooltipForView(view))
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tooltip_->IsVisible()) {
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->ShowImmediately(view, GetAccessibleName(view));
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->ShowDelayed(view, GetAccessibleName(view));
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::MouseExitedButton(views::View* view) {
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tooltip_->IsVisible())
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->StopTimer();
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)base::string16 ShelfView::GetAccessibleName(const views::View* view) {
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int view_index = view_model_->GetIndexOfView(view);
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May be -1 while in the process of animating closed.
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_index == -1)
1771c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return base::string16();
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1773a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
17744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[view_index].id);
17754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return item_delegate->GetTitle();
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ButtonPressed(views::Button* sender, const ui::Event& event) {
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do not handle mouse release during drag.
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dragging())
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sender == overflow_button_) {
17842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ToggleOverflowBubble();
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int view_index = view_model_->GetIndexOfView(sender);
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May be -1 while in the process of animating closed.
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_index == -1)
17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the previous menu was closed by the same event as this one, we ignore
17942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the call.
17952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsUsableEvent(event))
17962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
17972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1799a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ScopedTargetRootWindow scoped_target(
1800a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        sender->GetWidget()->GetNativeView()->GetRootWindow());
18012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Slow down activation animations if shift key is pressed.
18022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations;
18032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (event.IsShiftDown()) {
18042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode(
18052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
18062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1808b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Collect usage statistics before we decide what to do with the click.
1809b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    switch (model_->items()[view_index].type) {
1810b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_APP_SHORTCUT:
1811b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_WINDOWED_APP:
1812b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_PLATFORM_APP:
181390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case TYPE_BROWSER_SHORTCUT:
18145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Shell::GetInstance()->metrics()->RecordUserMetricsAction(
1815b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            UMA_LAUNCHER_CLICK_ON_APP);
1816b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        break;
18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1818b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_APP_LIST:
18195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Shell::GetInstance()->metrics()->RecordUserMetricsAction(
1820b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
1821424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        break;
1822424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1823424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      case TYPE_APP_PANEL:
18245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case TYPE_DIALOG:
1825424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        break;
1826424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1827424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      case TYPE_UNDEFINED:
18285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        NOTREACHED() << "ShelfItemType must be set.";
1829b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        break;
18302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1831424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1832a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ShelfItemDelegate* item_delegate =
1833a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        item_manager_->GetShelfItemDelegate(model_->items()[view_index].id);
1834f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!item_delegate->ItemSelected(event))
1835f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShowListMenuForView(model_->items()[view_index], sender, event);
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
18382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShelfView::ShowListMenuForView(const ShelfItem& item,
18408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                    views::View* source,
18418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                    const ui::Event& event) {
1842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<ShelfMenuModel> menu_model;
1843a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate =
1844a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      item_manager_->GetShelfItemDelegate(item.id);
18454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  menu_model.reset(item_delegate->CreateApplicationMenu(event.flags()));
18462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make sure we have a menu and it has at least two items in addition to the
18482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // application title and the 3 spacing separators.
18492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!menu_model.get() || menu_model->GetItemCount() <= 5)
18502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
18512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ShowMenu(scoped_ptr<views::MenuModelAdapter>(
1853a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               new ShelfMenuModelAdapter(menu_model.get())),
18542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           source,
18552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           gfx::Point(),
18567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           false,
18577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           ui::GetMenuSourceTypeForEvent(event));
18582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ShowContextMenuForView(views::View* source,
18628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       const gfx::Point& point,
18638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       ui::MenuSourceType source_type) {
18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int view_index = view_model_->GetIndexOfView(source);
18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_index == -1) {
18667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    Shell::GetInstance()->ShowContextMenu(point, source_type);
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1870424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  scoped_ptr<ui::MenuModel> menu_model;
1871a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
18724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[view_index].id);
1873424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  menu_model.reset(item_delegate->CreateContextMenu(
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      source->GetWidget()->GetNativeView()->GetRootWindow()));
1875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!menu_model)
18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1877424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
18785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::AutoReset<ShelfID> reseter(
18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &context_menu_id_,
18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_index == -1 ? 0 : model_->items()[view_index].id);
18812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ShowMenu(scoped_ptr<views::MenuModelAdapter>(
18832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               new views::MenuModelAdapter(menu_model.get())),
18842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           source,
18852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           point,
18867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           true,
18877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           source_type);
18882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
18892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ShowMenu(scoped_ptr<views::MenuModelAdapter> menu_model_adapter,
18918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         views::View* source,
18928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         const gfx::Point& click_point,
18938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         bool context_menu,
18948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         ui::MenuSourceType source_type) {
18952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  closing_event_time_ = base::TimeDelta();
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  launcher_menu_runner_.reset(
18972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new views::MenuRunner(menu_model_adapter->CreateMenu()));
18982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1899a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ScopedTargetRootWindow scoped_target(
1900a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      source->GetWidget()->GetNativeView()->GetRootWindow());
1901a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
19022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Determine the menu alignment dependent on the shelf.
19032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::MenuItemView::AnchorPosition menu_alignment =
19042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      views::MenuItemView::TOPLEFT;
19052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect anchor_point = gfx::Rect(click_point, gfx::Size());
19062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfWidget* shelf = RootWindowController::ForShelf(
1908c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetWidget()->GetNativeView())->shelf();
19092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!context_menu) {
19102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Application lists use a bubble.
19115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShelfAlignment align = shelf->GetAlignment();
19122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    anchor_point = source->GetBoundsInScreen();
19132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // It is possible to invoke the menu while it is sliding into view. To cover
19157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that case, the screen coordinates are offsetted by the animation delta.
19167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    gfx::Vector2d offset =
19177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        source->GetWidget()->GetNativeWindow()->bounds().origin() -
19187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        source->GetWidget()->GetNativeWindow()->GetTargetBounds().origin();
19197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    anchor_point.set_x(anchor_point.x() - offset.x());
19207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    anchor_point.set_y(anchor_point.y() - offset.y());
19217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1922f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Shelf items can have an asymmetrical border for spacing reasons.
19232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Adjust anchor location for this.
19242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (source->border())
19252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      anchor_point.Inset(source->border()->GetInsets());
19262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (align) {
19285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_BOTTOM:
19292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        menu_alignment = views::MenuItemView::BUBBLE_ABOVE;
19302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
19315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_LEFT:
19322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        menu_alignment = views::MenuItemView::BUBBLE_RIGHT;
19332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
19345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_RIGHT:
19352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        menu_alignment = views::MenuItemView::BUBBLE_LEFT;
19362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
19375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_TOP:
19382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        menu_alignment = views::MenuItemView::BUBBLE_BELOW;
19392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
19402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
19412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
19425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If this gets deleted while we are in the menu, the shelf will be gone
1943c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // as well.
1944c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool got_deleted = false;
1945c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  got_deleted_ = &got_deleted;
1946c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1947c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  shelf->ForceUndimming(true);
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: if you convert to HAS_MNEMONICS be sure and update menu building
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // code.
19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (launcher_menu_runner_->RunMenuAt(
19512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          source->GetWidget(),
19522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NULL,
19532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          anchor_point,
19542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          menu_alignment,
19557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          source_type,
19567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          context_menu ? views::MenuRunner::CONTEXT_MENU : 0) ==
19577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      views::MenuRunner::MENU_DELETED) {
1958c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!got_deleted) {
1959c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      got_deleted_ = NULL;
1960c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      shelf->ForceUndimming(false);
1961c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1963c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1964c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  got_deleted_ = NULL;
1965c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  shelf->ForceUndimming(false);
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If it is a context menu and we are showing overflow bubble
19684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // we want to hide overflow bubble.
19694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (owner_overflow_bubble_)
19704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    owner_overflow_bubble_->HideBubbleAndRefreshButton();
19714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Unpinning an item will reset the |launcher_menu_runner_| before coming
19732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // here.
1974c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (launcher_menu_runner_)
19752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closing_event_time_ = launcher_menu_runner_->closing_event_time();
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shell::GetInstance()->UpdateShelfVisibility();
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) {
19801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
19811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    OnShelfIconPositionsChanged());
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreferredSizeChanged();
19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
1986424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (snap_back_from_rip_off_view_ && animator == bounds_animator_) {
1987424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (!animator->IsAnimating(snap_back_from_rip_off_view_)) {
1988f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Coming here the animation of the ShelfButton is finished and the
1989424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // previously hidden status can be shown again. Since the button itself
1990424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // might have gone away or changed locations we check that the button
1991424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // is still in the shelf and show its status again.
1992424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      for (int index = 0; index < view_model_->view_size(); index++) {
1993424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        views::View* view = view_model_->view_at(index);
1994424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (view == snap_back_from_rip_off_view_) {
1995f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          ShelfButton* button = static_cast<ShelfButton*>(view);
1996f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          button->ClearState(ShelfButton::STATE_HIDDEN);
1997424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          break;
1998424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
1999424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      }
2000424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back_from_rip_off_view_ = NULL;
2001424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
2002424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::IsUsableEvent(const ui::Event& event) {
20062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (closing_event_time_ == base::TimeDelta())
20072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
20082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta delta =
20102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta(event.time_stamp() - closing_event_time_);
20112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  closing_event_time_ = base::TimeDelta();
20122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(skuhne): This time seems excessive, but it appears that the reposting
20132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // takes that long.  Need to come up with a better way of doing this.
20142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (delta.InMilliseconds() < 0 || delta.InMilliseconds() > 130);
20152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
20162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const ShelfItem* ShelfView::ShelfItemForView(const views::View* view) const {
20182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int view_index = view_model_->GetIndexOfView(view);
20192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (view_index == -1)
20202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
20212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return &(model_->items()[view_index]);
20222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
20232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::ShouldShowTooltipForView(const views::View* view) const {
20252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (view == GetAppListButtonView() &&
20262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Shell::GetInstance()->GetAppListWindow())
20272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
20285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ShelfItem* item = ShelfItemForView(view);
2029424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!item)
2030424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
2031a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate =
2032a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      item_manager_->GetShelfItemDelegate(item->id);
20334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return item_delegate->ShouldShowTooltip();
2034424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
2035424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
20368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const {
20375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfWidget* shelf = RootWindowController::ForShelf(
2038424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      GetWidget()->GetNativeView())->shelf();
20395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfAlignment align = shelf->GetAlignment();
2040424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const gfx::Rect bounds = GetBoundsInScreen();
2041424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int distance = 0;
2042424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  switch (align) {
20435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_BOTTOM:
2044424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = bounds.y() - coordinate.y();
2045424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
20465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_LEFT:
2047424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = coordinate.x() - bounds.right();
2048424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
20495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_RIGHT:
2050424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = bounds.x() - coordinate.x();
2051424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
20525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_TOP:
2053424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = coordinate.y() - bounds.bottom();
2054424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
2055424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
2056424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return distance > 0 ? distance : 0;
20572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
20582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
2060