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/app_list_button.h"
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/shelf/overflow_bubble.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/overflow_bubble_view.h"
18424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/shelf/overflow_button.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/shelf_button.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf_constants.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_delegate.h"
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ash/shelf/shelf_icon_observer.h"
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_item_delegate.h"
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_item_delegate_manager.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shelf/shelf_layout_manager.h"
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_menu_model.h"
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/shelf_model.h"
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/shelf/shelf_tooltip_manager.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shelf/shelf_widget.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shell.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/wm/coordinate_conversion.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/auto_reset.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/histogram.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/ash_strings.h"
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "ui/aura/client/screen_position_client.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/simple_menu_model.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer_animator.h"
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/compositor/scoped_animation_duration_scale_mode.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/gfx/point.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/animation/bounds_animator.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/border.h"
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/button/image_button.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_model_adapter.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_runner.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/focus/focus_search.h"
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view_model.h"
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view_model_utils.h"
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/wm/core/coordinate_conversion.h"
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using gfx::Animation;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using views::View;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM = 0;
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT = 1;
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT = 2;
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT = 3;
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default amount content is inset on the left edge.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDefaultLeadingInset = 8;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Minimum distance before drag starts.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinimumDragDistance = 8;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Additional spacing for the left and right side of icons.
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kHorizontalIconSpacing = 2;
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Inset for items which do not have an icon.
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kHorizontalNoIconInsetSpacing =
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    kHorizontalIconSpacing + kDefaultLeadingInset;
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The proportion of the shelf space reserved for non-panel icons. Panels
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// may flow into this space but will be put into the overflow bubble if there
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is contention for the space.
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const float kReservedNonPanelIconProportion = 0.67f;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is the command id of the menu item which contains the name of the menu.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kCommandIdOfMenuName = 0;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The background color of the active item in the list.
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kActiveListItemBackgroundColor = SkColorSetRGB(203 , 219, 241);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The background color of the active & hovered item in the list.
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kFocusedActiveListItemBackgroundColor =
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkColorSetRGB(193, 211, 236);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The text color of the caption item in a list.
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kCaptionItemForegroundColor = SK_ColorBLACK;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The maximum allowable length of a menu line of an application menu in pixels.
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaximumAppMenuItemLength = 350;
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// The distance of the cursor from the outer rim of the shelf before it
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// separates.
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const int kRipOffDistance = 48;
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// The rip off drag and drop proxy image should get scaled by this factor.
108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const float kDragAndDropProxyScale = 1.5f;
109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The opacity represents that this partially disappeared item will get removed.
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const float kDraggedImageOpacity = 0.5f;
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A class to temporarily disable a given bounds animator.
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class BoundsAnimatorDisabler {
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  explicit BoundsAnimatorDisabler(views::BoundsAnimator* bounds_animator)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : old_duration_(bounds_animator->GetAnimationDuration()),
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        bounds_animator_(bounds_animator) {
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bounds_animator_->SetAnimationDuration(1);
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~BoundsAnimatorDisabler() {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bounds_animator_->SetAnimationDuration(old_duration_);
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The previous animation duration.
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int old_duration_;
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The bounds animator which gets used.
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  views::BoundsAnimator* bounds_animator_;
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorDisabler);
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The MenuModelAdapter gets slightly changed to adapt the menu appearance to
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// our requirements.
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class ShelfMenuModelAdapter : public views::MenuModelAdapter {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  explicit ShelfMenuModelAdapter(ShelfMenuModel* menu_model);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // views::MenuModelAdapter:
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual const gfx::FontList* GetLabelFontList(int command_id) const OVERRIDE;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsCommandEnabled(int id) const OVERRIDE;
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void GetHorizontalIconMargins(int id,
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        int icon_size,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        int* left_margin,
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        int* right_margin) const OVERRIDE;
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool GetForegroundColor(int command_id,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  bool is_hovered,
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  SkColor* override_color) const OVERRIDE;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool GetBackgroundColor(int command_id,
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  bool is_hovered,
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  SkColor* override_color) const OVERRIDE;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int GetMaxWidthForMenu(views::MenuItemView* menu) OVERRIDE;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool ShouldReserveSpaceForSubmenuIndicator() const OVERRIDE;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfMenuModel* menu_model_;
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShelfMenuModelAdapter);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ShelfMenuModelAdapter::ShelfMenuModelAdapter(ShelfMenuModel* menu_model)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : MenuModelAdapter(menu_model),
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      menu_model_(menu_model) {
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const gfx::FontList* ShelfMenuModelAdapter::GetLabelFontList(
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int command_id) const {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_id != kCommandIdOfMenuName)
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return MenuModelAdapter::GetLabelFontList(command_id);
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return &rb.GetFontList(ui::ResourceBundle::BoldFont);
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::IsCommandEnabled(int id) const {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return id != kCommandIdOfMenuName;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::GetForegroundColor(int command_id,
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               bool is_hovered,
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               SkColor* override_color) const {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_id != kCommandIdOfMenuName)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *override_color = kCaptionItemForegroundColor;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::GetBackgroundColor(int command_id,
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               bool is_hovered,
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               SkColor* override_color) const {
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!menu_model_->IsCommandActive(command_id))
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *override_color = is_hovered ? kFocusedActiveListItemBackgroundColor :
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 kActiveListItemBackgroundColor;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ShelfMenuModelAdapter::GetHorizontalIconMargins(int command_id,
205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                     int icon_size,
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                     int* left_margin,
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                     int* right_margin) const {
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *left_margin = kHorizontalIconSpacing;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *right_margin = (command_id != kCommandIdOfMenuName) ?
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kHorizontalIconSpacing : -(icon_size + kHorizontalNoIconInsetSpacing);
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)int ShelfMenuModelAdapter::GetMaxWidthForMenu(views::MenuItemView* menu) {
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kMaximumAppMenuItemLength;
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ShelfMenuModelAdapter::ShouldReserveSpaceForSubmenuIndicator() const {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Custom FocusSearch used to navigate the shelf in the order items are in
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the ViewModel.
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ShelfFocusSearch : public views::FocusSearch {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit ShelfFocusSearch(views::ViewModel* view_model)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : FocusSearch(NULL, true, true),
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_model_(view_model) {}
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~ShelfFocusSearch() {}
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views::FocusSearch overrides:
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual View* FindNextFocusableView(
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      View* starting_view,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool reverse,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Direction direction,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool check_starting_view,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      views::FocusTraversable** focus_traversable,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      View** focus_traversable_view) OVERRIDE {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index = view_model_->GetIndexOfView(starting_view);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index == -1)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return view_model_->view_at(0);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reverse) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      --index;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index < 0)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        index = view_model_->view_size() - 1;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++index;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index >= view_model_->view_size())
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        index = 0;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return view_model_->view_at(index);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::ViewModel* view_model_;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShelfFocusSearch);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AnimationDelegate used when inserting a new item. This steadily increases the
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opacity of the layer as the animation progress.
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class FadeInAnimationDelegate : public gfx::AnimationDelegate {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit FadeInAnimationDelegate(views::View* view) : view_(view) {}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~FadeInAnimationDelegate() {}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AnimationDelegate overrides:
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationProgressed(const Animation* animation) OVERRIDE {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(animation->GetCurrentValue());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationEnded(const Animation* animation) OVERRIDE {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationCanceled(const Animation* animation) OVERRIDE {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view_;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FadeInAnimationDelegate);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ReflectItemStatus(const ShelfItem& item, ShelfButton* button) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (item.status) {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_CLOSED:
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ACTIVE);
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_RUNNING);
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ATTENTION);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_RUNNING:
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ACTIVE);
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_RUNNING);
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ATTENTION);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_ACTIVE:
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_ACTIVE);
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_RUNNING);
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ATTENTION);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATUS_ATTENTION:
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_ACTIVE);
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->ClearState(ShelfButton::STATE_RUNNING);
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_ATTENTION);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// AnimationDelegate used when deleting an item. This steadily decreased the
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opacity of the layer as the animation progress.
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class ShelfView::FadeOutAnimationDelegate : public gfx::AnimationDelegate {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FadeOutAnimationDelegate(ShelfView* host, views::View* view)
3198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : shelf_view_(host),
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_(view) {}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~FadeOutAnimationDelegate() {}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AnimationDelegate overrides:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationProgressed(const Animation* animation) OVERRIDE {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1 - animation->GetCurrentValue());
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->ScheduleDraw();
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationEnded(const Animation* animation) OVERRIDE {
3298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    shelf_view_->OnFadeOutAnimationEnded();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationCanceled(const Animation* animation) OVERRIDE {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShelfView* shelf_view_;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<views::View> view_;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FadeOutAnimationDelegate);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AnimationDelegate used to trigger fading an element in. When an item is
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// inserted this delegate is attached to the animation that expands the size of
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the item.  When done it kicks off another animation to fade the item in.
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class ShelfView::StartFadeAnimationDelegate : public gfx::AnimationDelegate {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  StartFadeAnimationDelegate(ShelfView* host,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             views::View* view)
3488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : shelf_view_(host),
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_(view) {}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~StartFadeAnimationDelegate() {}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AnimationDelegate overrides:
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationEnded(const Animation* animation) OVERRIDE {
3548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    shelf_view_->FadeIn(view_);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void AnimationCanceled(const Animation* animation) OVERRIDE {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->layer()->SetOpacity(1.0f);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShelfView* shelf_view_;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view_;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(StartFadeAnimationDelegate);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ShelfView::ShelfView(ShelfModel* model,
368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     ShelfDelegate* delegate,
369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     ShelfLayoutManager* manager)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : model_(model),
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate),
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_model_(new views::ViewModel),
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_visible_index_(0),
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_visible_index_(-1),
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      overflow_button_(NULL),
3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      owner_overflow_bubble_(NULL),
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_pointer_(NONE),
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_view_(NULL),
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_drag_index_(-1),
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context_menu_id_(0),
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      leading_inset_(kDefaultLeadingInset),
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cancelling_drag_model_changed_(false),
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      last_hidden_index_(0),
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      closing_event_time_(base::TimeDelta()),
385b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      got_deleted_(NULL),
3867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      drag_and_drop_item_pinned_(false),
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      drag_and_drop_shelf_id_(0),
388424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      dragged_off_shelf_(false),
389424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back_from_rip_off_view_(NULL),
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      item_manager_(Shell::GetInstance()->shelf_item_delegate_manager()),
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      layout_manager_(manager),
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      overflow_mode_(false),
393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_(NULL),
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_(false) {
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(model_);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_.reset(new views::BoundsAnimator(this));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->AddObserver(this);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_context_menu_controller(this);
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  focus_search_.reset(new ShelfFocusSearch(view_model_.get()));
400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  tooltip_.reset(new ShelfTooltipManager(manager, this));
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ShelfView::~ShelfView() {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->RemoveObserver(this);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->RemoveObserver(this);
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we are inside the MenuRunner, we need to know if we were getting
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // deleted while it was running.
408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (got_deleted_)
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *got_deleted_ = true;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::Init() {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->AddObserver(this);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ShelfItems& items(model_->items());
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ShelfItems::const_iterator i = items.begin(); i != items.end(); ++i) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* child = CreateViewForItem(*i);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    child->SetPaintToLayer(true);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->Add(child, static_cast<int>(i - items.begin()));
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(child);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_ = new OverflowButton(this);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->set_context_menu_controller(this);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigureChildView(overflow_button_);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(overflow_button_);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We'll layout when our bounds change.
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnShelfAlignmentChanged() {
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_button_->OnShelfAlignmentChanged();
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LayoutToIdealBounds();
4331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (int i = 0; i < view_model_->view_size(); ++i) {
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i >= first_visible_index_ && i <= last_visible_index_)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      view_model_->view_at(i)->Layout();
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
437d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  tooltip_->Close();
438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (overflow_bubble_)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_bubble_->Hide();
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::SchedulePaintForAllButtons() {
443ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (int i = 0; i < view_model_->view_size(); ++i) {
444ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (i >= first_visible_index_ && i <= last_visible_index_)
445ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      view_model_->view_at(i)->SchedulePaint();
446ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
447ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (overflow_button_ && overflow_button_->visible())
448ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    overflow_button_->SchedulePaint();
449ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
450ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)gfx::Rect ShelfView::GetIdealBoundsOfItemIcon(ShelfID id) {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
453cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (index == -1)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Rect();
455cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Map all items from overflow area to the overflow button. Note that the
456cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // section between last_index_hidden_ and model_->FirstPanelIndex() is the
457cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // list of invisible panel items. However, these items are currently nowhere
458cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // represented and get dropped instead - see (crbug.com/378907). As such there
459cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // is no way to address them or place them. We therefore move them over the
460cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // overflow button.
461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (index > last_visible_index_ && index < model_->FirstPanelIndex())
462cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    index = last_visible_index_ + 1;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect& ideal_bounds(view_model_->ideal_bounds(index));
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(TYPE_APP_LIST, model_->items()[index].type);
465f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ShelfButton* button = static_cast<ShelfButton*>(view_model_->view_at(index));
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect icon_bounds = button->GetIconBounds();
467868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return gfx::Rect(GetMirroredXWithWidthInView(
468868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       ideal_bounds.x() + icon_bounds.x(), icon_bounds.width()),
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   ideal_bounds.y() + icon_bounds.y(),
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   icon_bounds.width(),
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   icon_bounds.height());
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShelfView::UpdatePanelIconPosition(ShelfID id,
4758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                        const gfx::Point& midpoint) {
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int current_index = model_->ItemIndexByID(id);
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int first_panel_index = model_->FirstPanelIndex();
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_index < first_panel_index)
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
481868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Point midpoint_in_view(GetMirroredXInView(midpoint.x()),
482868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              midpoint.y());
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int target_index = current_index;
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (target_index > first_panel_index &&
4851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
4861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)             view_model_->ideal_bounds(target_index).x(),
4871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)             view_model_->ideal_bounds(target_index).y()) >
4881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(midpoint_in_view.x(),
4891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                           midpoint_in_view.y())) {
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    --target_index;
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (target_index < view_model_->view_size() - 1 &&
4931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(target_index).right(),
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(target_index).bottom()) <
4961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(midpoint_in_view.x(),
4971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                           midpoint_in_view.y())) {
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++target_index;
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_index != target_index)
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model_->Move(current_index, target_index);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::IsShowingMenu() const {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (launcher_menu_runner_.get() &&
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       launcher_menu_runner_->IsRunning());
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::IsShowingOverflowBubble() const {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return overflow_bubble_.get() && overflow_bubble_->IsShowing();
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::View* ShelfView::GetAppListButtonView() const {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < model_->item_count(); ++i) {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (model_->items()[i].type == TYPE_APP_LIST)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return view_model_->view_at(i);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Applist button not found";
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
5248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// ShelfView, FocusTraversable implementation:
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::FocusSearch* ShelfView::GetFocusSearch() {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return focus_search_.get();
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::FocusTraversable* ShelfView::GetFocusTraversableParent() {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parent()->GetFocusTraversable();
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)View* ShelfView::GetFocusTraversableParentView() {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::CreateDragIconProxy(
539a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const gfx::Point& location_in_screen_coordinates,
540a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const gfx::ImageSkia& icon,
541a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    views::View* replaced_view,
542868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Vector2d& cursor_offset_from_center,
543a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    float scale_factor) {
544a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_replaced_view_ = replaced_view;
545c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  drag_image_.reset(new ash::DragImageView(
5464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      drag_replaced_view_->GetWidget()->GetNativeWindow()->GetRootWindow(),
5474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE));
548a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_->SetImage(icon);
549a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  gfx::Size size = drag_image_->GetPreferredSize();
550a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  size.set_width(size.width() * scale_factor);
551a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  size.set_height(size.height() * scale_factor);
552868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  drag_image_offset_ = gfx::Vector2d(size.width() / 2, size.height() / 2) +
553868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       cursor_offset_from_center;
554a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  gfx::Rect drag_image_bounds(
555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      location_in_screen_coordinates - drag_image_offset_,
556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      size);
557a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_->SetBoundsInScreen(drag_image_bounds);
558a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_->SetWidgetVisible(true);
559a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
560a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::UpdateDragIconProxy(
562a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const gfx::Point& location_in_screen_coordinates) {
563a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // TODO(jennyz): Investigate why drag_image_ becomes NULL at this point per
564a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // crbug.com/34722, while the app list item is still being dragged around.
565a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (drag_image_) {
566a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    drag_image_->SetScreenPosition(
567a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        location_in_screen_coordinates - drag_image_offset_);
568a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
569a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
570a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::DestroyDragIconProxy() {
572a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_.reset();
573a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_image_offset_ = gfx::Vector2d(0, 0);
574a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
575a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::StartDrag(const std::string& app_id,
5778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                          const gfx::Point& location_in_screen_coordinates) {
578b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Bail if an operation is already going on - or the cursor is not inside.
579b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // This could happen if mouse / touch operations overlap.
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (drag_and_drop_shelf_id_ ||
581b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !GetBoundsInScreen().Contains(location_in_screen_coordinates))
582b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return false;
583b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
584b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // If the AppsGridView (which was dispatching this event) was opened by our
5858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // button, ShelfView dragging operations are locked and we have to unlock.
586b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  CancelDrag(-1);
5877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  drag_and_drop_item_pinned_ = false;
588b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  drag_and_drop_app_id_ = app_id;
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  drag_and_drop_shelf_id_ =
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->GetShelfIDForAppID(drag_and_drop_app_id_);
5917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Check if the application is known and pinned - if not, we have to pin it so
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // that we can re-arrange the shelf order accordingly. Note that items have
5937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // to be pinned to give them the same (order) possibilities as a shortcut.
594a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // When an item is dragged from overflow to shelf, IsShowingOverflowBubble()
595a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // returns true. At this time, we don't need to pin the item.
596a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!IsShowingOverflowBubble() &&
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (!drag_and_drop_shelf_id_ ||
598a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       !delegate_->IsAppPinned(app_id))) {
599b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    delegate_->PinAppWithID(app_id);
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    drag_and_drop_shelf_id_ =
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        delegate_->GetShelfIDForAppID(drag_and_drop_app_id_);
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!drag_and_drop_shelf_id_)
603b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return false;
6047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    drag_and_drop_item_pinned_ = true;
605b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
606b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View* drag_and_drop_view = view_model_->view_at(
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      model_->ItemIndexByID(drag_and_drop_shelf_id_));
608b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(drag_and_drop_view);
609b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
610a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Since there is already an icon presented by the caller, we hide this item
611a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // for now. That has to be done by reducing the size since the visibility will
612a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // change once a regrouping animation is performed.
613a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  pre_drag_and_drop_size_ = drag_and_drop_view->size();
614a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  drag_and_drop_view->SetSize(gfx::Size());
615a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
616b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // First we have to center the mouse cursor over the item.
617b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  gfx::Point pt = drag_and_drop_view->GetBoundsInScreen().CenterPoint();
618b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View::ConvertPointFromScreen(drag_and_drop_view, &pt);
619f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point point_in_root = location_in_screen_coordinates;
6206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ::wm::ConvertPointFromScreen(
6216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ash::wm::GetRootWindowAt(location_in_screen_coordinates), &point_in_root);
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ui::MouseEvent event(ui::ET_MOUSE_PRESSED, pt, point_in_root, 0, 0);
623f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PointerPressedOnButton(drag_and_drop_view,
624f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         ShelfButtonHost::DRAG_AND_DROP,
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         event);
626b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
627b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Drag the item where it really belongs.
628b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  Drag(location_in_screen_coordinates);
629b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return true;
630b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
631b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::Drag(const gfx::Point& location_in_screen_coordinates) {
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!drag_and_drop_shelf_id_ ||
634b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      !GetBoundsInScreen().Contains(location_in_screen_coordinates))
635b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return false;
636b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
637b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  gfx::Point pt = location_in_screen_coordinates;
638b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View* drag_and_drop_view = view_model_->view_at(
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      model_->ItemIndexByID(drag_and_drop_shelf_id_));
640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ConvertPointFromScreen(drag_and_drop_view, &pt);
641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point point_in_root = location_in_screen_coordinates;
6426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ::wm::ConvertPointFromScreen(
6436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ash::wm::GetRootWindowAt(location_in_screen_coordinates), &point_in_root);
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ui::MouseEvent event(ui::ET_MOUSE_DRAGGED, pt, point_in_root, 0, 0);
645f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PointerDraggedOnButton(drag_and_drop_view,
646f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         ShelfButtonHost::DRAG_AND_DROP,
647f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         event);
648b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return true;
649b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
650b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::EndDrag(bool cancel) {
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!drag_and_drop_shelf_id_)
653b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
654b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
655b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  views::View* drag_and_drop_view = view_model_->view_at(
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      model_->ItemIndexByID(drag_and_drop_shelf_id_));
657b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  PointerReleasedOnButton(
658f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      drag_and_drop_view, ShelfButtonHost::DRAG_AND_DROP, cancel);
659b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
660a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Either destroy the temporarily created item - or - make the item visible.
6611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (drag_and_drop_item_pinned_ && cancel) {
662424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    delegate_->UnpinAppWithID(drag_and_drop_app_id_);
6631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (drag_and_drop_view) {
66458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (cancel) {
66558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // When a hosted drag gets canceled, the item can remain in the same slot
66658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // and it might have moved within the bounds. In that case the item need
66758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // to animate back to its correct location.
66858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AnimateToIdealBounds();
66958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else {
67058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      drag_and_drop_view->SetSize(pre_drag_and_drop_size_);
67158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
67258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
673b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  drag_and_drop_shelf_id_ = 0;
675b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
676b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::LayoutToIdealBounds() {
6781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (bounds_animator_->IsAnimating()) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimateToIdealBounds();
6801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
6811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  IdealBounds ideal_bounds;
6841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
6851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds);
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
689a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ShelfView::UpdateAllButtonsVisibilityInOverflowMode() {
690a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The overflow button is not shown in overflow mode.
691a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  overflow_button_->SetVisible(false);
692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK_LT(last_visible_index_, view_model_->view_size());
693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
694a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool visible = i >= first_visible_index_ &&
695a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        i <= last_visible_index_;
696a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // To track the dragging of |drag_view_| continuously, its visibility
697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // should be always true regardless of its position.
698a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (dragged_off_from_overflow_to_shelf_ &&
699a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        view_model_->view_at(i) == drag_view_)
700a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      view_model_->view_at(i)->SetVisible(true);
701a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    else
702a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      view_model_->view_at(i)->SetVisible(visible);
703a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
704a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
705a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
706cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ShelfView::CalculateIdealBounds(IdealBounds* bounds) const {
7071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int available_size = layout_manager_->PrimaryAxisValue(width(), height());
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(model_->item_count() == view_model_->view_size());
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!available_size)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int first_panel_index = model_->FirstPanelIndex();
713ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int last_button_index = first_panel_index - 1;
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
715a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  int x = 0;
716a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  int y = 0;
717a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  int button_size = kShelfButtonSize;
718a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  int button_spacing = kShelfButtonSpacing;
719ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
7201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int w = layout_manager_->PrimaryAxisValue(button_size, width());
7211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int h = layout_manager_->PrimaryAxisValue(height(), button_size);
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i < first_visible_index_) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0));
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
729ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (i != last_button_index) {
7301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      x = layout_manager_->PrimaryAxisValue(x + w + button_spacing, x);
7311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      y = layout_manager_->PrimaryAxisValue(y, y + h + button_spacing);
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_overflow_mode()) {
736cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const_cast<ShelfView*>(this)->UpdateAllButtonsVisibilityInOverflowMode();
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Right aligned icons.
741ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int end_position = available_size - button_spacing;
7421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  x = layout_manager_->PrimaryAxisValue(end_position, 0);
7431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  y = layout_manager_->PrimaryAxisValue(0, end_position);
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = view_model_->view_size() - 1;
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       i >= first_panel_index; --i) {
7461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    x = layout_manager_->PrimaryAxisValue(x - w - button_spacing, x);
7471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    y = layout_manager_->PrimaryAxisValue(y, y - h - button_spacing);
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
7491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    end_position = layout_manager_->PrimaryAxisValue(x, y);
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Icons on the left / top are guaranteed up to kLeftIconProportion of
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the available space.
7541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int last_icon_position = layout_manager_->PrimaryAxisValue(
755ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      view_model_->ideal_bounds(last_button_index).right(),
756a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      view_model_->ideal_bounds(last_button_index).bottom()) + button_size;
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int reserved_icon_space = available_size * kReservedNonPanelIconProportion;
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (last_icon_position < reserved_icon_space)
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    end_position = last_icon_position;
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    end_position = std::max(end_position, reserved_icon_space);
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bounds->overflow_bounds.set_size(
7641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      gfx::Size(layout_manager_->PrimaryAxisValue(w, width()),
7651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                layout_manager_->PrimaryAxisValue(height(), h)));
7664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
767a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  last_visible_index_ = DetermineLastVisibleIndex(
768a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      end_position - button_size);
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  last_hidden_index_ = DetermineFirstVisiblePanelIndex(end_position) - 1;
770a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  bool show_overflow = last_visible_index_ < last_button_index ||
771a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      last_hidden_index_ >= first_panel_index;
772ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
773ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Create Space for the overflow button
774a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (show_overflow &&
77558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      last_visible_index_ > 0 && last_visible_index_ < last_button_index)
776ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    --last_visible_index_;
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
778ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bool visible = i <= last_visible_index_ || i > last_hidden_index_;
779cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // To receive drag event continuously from |drag_view_| during the dragging
7804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // off from the shelf, don't make |drag_view_| invisible. It will be
7814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // eventually invisible and removed from the |view_model_| by
7824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // FinalizeRipOffDrag().
7834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (dragged_off_shelf_ && view_model_->view_at(i) == drag_view_)
7844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      continue;
785ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    view_model_->view_at(i)->SetVisible(visible);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->SetVisible(show_overflow);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (show_overflow) {
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(0, view_model_->view_size());
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (last_visible_index_ == -1) {
792a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      x = 0;
793a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      y = 0;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
7951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      x = layout_manager_->PrimaryAxisValue(
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).right(),
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).x());
7981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      y = layout_manager_->PrimaryAxisValue(
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).y(),
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          view_model_->ideal_bounds(last_visible_index_).bottom());
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Set all hidden panel icon positions to be on the overflow button.
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = first_panel_index; i <= last_hidden_index_; ++i)
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Add more space between last visible item and overflow button.
8071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Without this, two buttons look too close compared with other items.
808a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    x = layout_manager_->PrimaryAxisValue(x + button_spacing, x);
809a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    y = layout_manager_->PrimaryAxisValue(y, y + button_spacing);
8101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
811ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bounds->overflow_bounds.set_x(x);
812ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bounds->overflow_bounds.set_y(y);
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (overflow_bubble_.get() && overflow_bubble_->IsShowing())
8148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      UpdateOverflowRange(overflow_bubble_->shelf_view());
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
816c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (overflow_bubble_)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      overflow_bubble_->Hide();
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::DetermineLastVisibleIndex(int max_value) const {
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int index = model_->FirstPanelIndex() - 1;
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (index >= 0 &&
8241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             view_model_->ideal_bounds(index).right(),
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             view_model_->ideal_bounds(index).bottom()) > max_value) {
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index--;
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::DetermineFirstVisiblePanelIndex(int min_value) const {
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int index = model_->FirstPanelIndex();
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (index < view_model_->view_size() &&
8351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         layout_manager_->PrimaryAxisValue(
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(index).right(),
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             view_model_->ideal_bounds(index).bottom()) < min_value) {
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++index;
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return index;
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ShelfView::AddIconObserver(ShelfIconObserver* observer) {
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ShelfView::RemoveIconObserver(ShelfIconObserver* observer) {
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::AnimateToIdealBounds() {
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdealBounds ideal_bounds;
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < view_model_->view_size(); ++i) {
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    View* view = view_model_->view_at(i);
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds_animator_->AnimateViewTo(view, view_model_->ideal_bounds(i));
8572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Now that the item animation starts, we have to make sure that the
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // padding of the first gets properly transferred to the new first item.
8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i && view->border())
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      view->SetBorder(views::Border::NullBorder());
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds);
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)views::View* ShelfView::CreateViewForItem(const ShelfItem& item) {
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = NULL;
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (item.type) {
86890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case TYPE_BROWSER_SHORTCUT:
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_SHORTCUT:
8702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TYPE_WINDOWED_APP:
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_PLATFORM_APP:
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TYPE_DIALOG:
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_PANEL: {
874f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShelfButton* button = ShelfButton::Create(this, this, layout_manager_);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button->SetImage(item.image);
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReflectItemStatus(item, button);
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view = button;
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_LIST: {
882a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      view = new AppListButton(this, this, layout_manager_->shelf_widget());
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->set_context_menu_controller(this);
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(view);
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigureChildView(view);
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view;
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::FadeIn(views::View* view) {
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetVisible(true);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->layer()->SetOpacity(0);
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AnimateToIdealBounds();
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->SetAnimationDelegate(
901f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      view,
902f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      scoped_ptr<gfx::AnimationDelegate>(new FadeInAnimationDelegate(view)));
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event) {
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!dragging());
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drag_view_);
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_pointer_ = pointer;
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_drag_index_ = view_model_->GetIndexOfView(drag_view_);
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
911424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (start_drag_index_== -1) {
912424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    CancelDrag(-1);
913424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
914424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
915424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the item is no longer draggable, bail out.
917a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
9184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[start_drag_index_].id);
9194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!item_delegate->IsDraggable()) {
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelDrag(-1);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move the view to the front so that it appears on top of other views.
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReorderChildView(drag_view_, -1);
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->StopAnimatingView(drag_view_);
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ContinueDrag(const ui::LocatedEvent& event) {
930424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Due to a syncing operation the application might have been removed.
931424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Bail if it is gone.
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int current_index = view_model_->GetIndexOfView(drag_view_);
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(-1, current_index);
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
9364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[current_index].id);
9374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!item_delegate->IsDraggable()) {
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelDrag(-1);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
942424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // If this is not a drag and drop host operation and not the app list item,
943424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // check if the item got ripped off the shelf - if it did we are done.
944a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!drag_and_drop_shelf_id_ &&
945424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      RemovableByRipOff(current_index) != NOT_REMOVABLE) {
946424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (HandleRipOffDrag(event))
947424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return;
948424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // The rip off handler could have changed the location of the item.
949424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    current_index = view_model_->GetIndexOfView(drag_view_);
950424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
951424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
952424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // TODO: I don't think this works correctly with RTL.
953424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  gfx::Point drag_point(event.location());
954f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ConvertPointToTarget(drag_view_, this, &drag_point);
955424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Constrain the location to the range of valid indices for the type.
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<int, int> indices(GetDragRange(current_index));
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int first_drag_index = indices.first;
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int last_drag_index = indices.second;
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the last index isn't valid, we're overflowing. Constrain to the app list
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (which is the last visible item).
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (first_drag_index < model_->FirstPanelIndex() &&
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      last_drag_index > last_visible_index_)
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_drag_index = last_visible_index_;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x = 0, y = 0;
9661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (layout_manager_->IsHorizontalAlignment()) {
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = std::max(view_model_->ideal_bounds(indices.first).x(),
968f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     drag_point.x() - drag_origin_.x());
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = std::min(view_model_->ideal_bounds(last_drag_index).right() -
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 view_model_->ideal_bounds(current_index).width(),
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 x);
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (drag_view_->x() == x)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_view_->SetX(x);
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    y = std::max(view_model_->ideal_bounds(indices.first).y(),
977f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     drag_point.y() - drag_origin_.y());
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    y = std::min(view_model_->ideal_bounds(last_drag_index).bottom() -
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 view_model_->ideal_bounds(current_index).height(),
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 y);
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (drag_view_->y() == y)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_view_->SetY(y);
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_index =
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      views::ViewModelUtils::DetermineMoveIndex(
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          *view_model_, drag_view_,
9891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          layout_manager_->IsHorizontalAlignment() ?
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              views::ViewModelUtils::HORIZONTAL :
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              views::ViewModelUtils::VERTICAL,
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          x, y);
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_index =
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::min(indices.second, std::max(target_index, indices.first));
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_index == current_index)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Change the model, the ShelfItemMoved() callback will handle the
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |view_model_| update.
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->Move(current_index, target_index);
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds_animator_->StopAnimatingView(drag_view_);
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::HandleRipOffDrag(const ui::LocatedEvent& event) {
1005424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int current_index = view_model_->GetIndexOfView(drag_view_);
1006424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK_NE(-1, current_index);
1007a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string dragged_app_id =
10085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->GetAppIDForShelfID(model_->items()[current_index].id);
1009f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1010f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point screen_location = event.root_location();
10116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ::wm::ConvertPointToScreen(GetWidget()->GetNativeWindow()->GetRootWindow(),
10126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             &screen_location);
1013f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1014424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // To avoid ugly forwards and backwards flipping we use different constants
1015424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // for ripping off / re-inserting the items.
1016424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (dragged_off_shelf_) {
1017f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // If the shelf/overflow bubble bounds contains |screen_location| we insert
1018f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // the item back into the shelf.
1019f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (GetBoundsForDragInsertInScreen().Contains(screen_location)) {
1020a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (dragged_off_from_overflow_to_shelf_) {
1021a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // During the dragging an item from Shelf to Overflow, it can enter here
1022a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // directly because both are located very closly.
1023a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        main_shelf_->EndDrag(true);
1024a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // Stops the animation of |drag_view_| and sets its bounds explicitly
1025a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // becase ContinueDrag() stops its animation. Without this, unexpected
1026a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // bounds will be set.
1027a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        bounds_animator_->StopAnimatingView(drag_view_);
1028a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        int drag_view_index = view_model_->GetIndexOfView(drag_view_);
1029a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index));
1030a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        dragged_off_from_overflow_to_shelf_ = false;
1031a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
1032424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Destroy our proxy view item.
1033424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      DestroyDragIconProxy();
1034424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Re-insert the item and return simply false since the caller will handle
1035424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // the move as in any normal case.
1036424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      dragged_off_shelf_ = false;
1037424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      drag_view_->layer()->SetOpacity(1.0f);
1038a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // The size of Overflow bubble should be updated immediately when an item
1039a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // is re-inserted.
1040f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (is_overflow_mode())
1041f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        PreferredSizeChanged();
1042424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
1043a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (is_overflow_mode() &&
1044a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               main_shelf_->GetBoundsForDragInsertInScreen().Contains(
1045a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                   screen_location)) {
1046a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (!dragged_off_from_overflow_to_shelf_) {
1047a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        dragged_off_from_overflow_to_shelf_ = true;
1048a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        drag_image_->SetOpacity(1.0f);
1049a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        main_shelf_->StartDrag(dragged_app_id, screen_location);
1050a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      } else {
1051a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        main_shelf_->Drag(screen_location);
1052a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
1053a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (dragged_off_from_overflow_to_shelf_) {
1054a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Makes the |drag_image_| partially disappear again.
1055a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_ = false;
1056a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_image_->SetOpacity(kDraggedImageOpacity);
1057a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_->EndDrag(true);
1058a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bounds_animator_->StopAnimatingView(drag_view_);
1059a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      int drag_view_index = view_model_->GetIndexOfView(drag_view_);
1060a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index));
1061424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1062424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Move our proxy view item.
1063f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    UpdateDragIconProxy(screen_location);
1064424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
1065424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1066424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Check if we are too far away from the shelf to enter the ripped off state.
1067f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Determine the distance to the shelf.
10685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int delta = CalculateShelfDistance(screen_location);
1069424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (delta > kRipOffDistance) {
1070424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Create a proxy view item which can be moved anywhere.
1071f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ShelfButton* button = static_cast<ShelfButton*>(drag_view_);
1072424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    CreateDragIconProxy(event.root_location(),
1073424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        button->GetImage(),
1074424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        drag_view_,
1075424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        gfx::Vector2d(0, 0),
1076424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        kDragAndDropProxyScale);
1077424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    drag_view_->layer()->SetOpacity(0.0f);
10784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    dragged_off_shelf_ = true;
1079424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (RemovableByRipOff(current_index) == REMOVABLE) {
10801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // Move the item to the front of the first panel item and hide it.
10815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // ShelfItemMoved() callback will handle the |view_model_| update and
10821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // call AnimateToIdealBounds().
1083f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (current_index != model_->FirstPanelIndex() - 1) {
1084f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        model_->Move(current_index, model_->FirstPanelIndex() - 1);
1085f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        StartFadeInLastVisibleItem();
1086f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      } else if (is_overflow_mode()) {
1087f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Overflow bubble should be shrunk when an item is ripped off.
1088f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        PreferredSizeChanged();
1089f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
1090424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Make the item partially disappear to show that it will get removed if
1091424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // dropped.
1092a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_image_->SetOpacity(kDraggedImageOpacity);
1093424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1094424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
1095424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1096424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return false;
1097424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
1098424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
10998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::FinalizeRipOffDrag(bool cancel) {
1100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!dragged_off_shelf_)
1101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
1102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Make sure we do not come in here again.
1103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  dragged_off_shelf_ = false;
1104424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Coming here we should always have a |drag_view_|.
1106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(drag_view_);
1107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int current_index = view_model_->GetIndexOfView(drag_view_);
1108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // If the view isn't part of the model anymore (|current_index| == -1), a sync
1109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // operation must have removed it. In that case we shouldn't change the model
1110424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // and only delete the proxy image.
1111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (current_index == -1) {
1112424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    DestroyDragIconProxy();
1113424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
1114424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1115424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1116424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Set to true when the animation should snap back to where it was before.
1117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  bool snap_back = false;
1118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Items which cannot be dragged off will be handled as a cancel.
1119424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!cancel) {
1120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (dragged_off_from_overflow_to_shelf_) {
1121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_ = false;
1122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_->EndDrag(false);
1123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_view_->layer()->SetOpacity(1.0f);
1124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (RemovableByRipOff(current_index) != REMOVABLE) {
1125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Make sure we do not try to remove un-removable items like items which
1126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // were not pinned or have to be always there.
1127424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      cancel = true;
1128424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back = true;
1129424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    } else {
1130424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Make sure the item stays invisible upon removal.
1131424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      drag_view_->SetVisible(false);
1132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      std::string app_id =
11335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          delegate_->GetAppIDForShelfID(model_->items()[current_index].id);
1134424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      delegate_->UnpinAppWithID(app_id);
1135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1137424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (cancel || snap_back) {
1138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (dragged_off_from_overflow_to_shelf_) {
1139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_from_overflow_to_shelf_ = false;
1140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Main shelf handles revert of dragged item.
1141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      main_shelf_->EndDrag(true);
1142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      drag_view_->layer()->SetOpacity(1.0f);
1143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (!cancelling_drag_model_changed_) {
1144424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Only do something if the change did not come through a model change.
1145424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      gfx::Rect drag_bounds = drag_image_->GetBoundsInScreen();
1146424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      gfx::Point relative_to = GetBoundsInScreen().origin();
1147424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      gfx::Rect target(
1148424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          gfx::PointAtOffsetFromOrigin(drag_bounds.origin()- relative_to),
1149424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          drag_bounds.size());
1150424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      drag_view_->SetBoundsRect(target);
1151424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // Hide the status from the active item since we snap it back now. Upon
1152424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // animation end the flag gets cleared if |snap_back_from_rip_off_view_|
1153424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // is set.
1154424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back_from_rip_off_view_ = drag_view_;
1155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShelfButton* button = static_cast<ShelfButton*>(drag_view_);
1156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      button->AddState(ShelfButton::STATE_HIDDEN);
1157424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // When a canceling drag model is happening, the view model is diverged
1158424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // from the menu model and movements / animations should not be done.
1159424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      model_->Move(current_index, start_drag_index_);
1160424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      AnimateToIdealBounds();
1161424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1162424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    drag_view_->layer()->SetOpacity(1.0f);
1163424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1164424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DestroyDragIconProxy();
1165424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
1166424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ShelfView::RemovableState ShelfView::RemovableByRipOff(int index) const {
1168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(index >= 0 && index < model_->item_count());
11695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfItemType type = model_->items()[index].type;
11705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type == TYPE_APP_LIST || type == TYPE_DIALOG || !delegate_->CanPin())
1171424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return NOT_REMOVABLE;
11725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = delegate_->GetAppIDForShelfID(model_->items()[index].id);
1174424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Note: Only pinned app shortcuts can be removed!
1175424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return (type == TYPE_APP_SHORTCUT && delegate_->IsAppPinned(app_id)) ?
1176424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      REMOVABLE : DRAGGABLE;
1177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
1178424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
11795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShelfView::SameDragType(ShelfItemType typea, ShelfItemType typeb) const {
1180ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  switch (typea) {
1181ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_APP_SHORTCUT:
1182ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_BROWSER_SHORTCUT:
1183ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return (typeb == TYPE_APP_SHORTCUT || typeb == TYPE_BROWSER_SHORTCUT);
118468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    case TYPE_APP_LIST:
1185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case TYPE_PLATFORM_APP:
1186ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_WINDOWED_APP:
1187ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    case TYPE_APP_PANEL:
11885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TYPE_DIALOG:
1189ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return typeb == typea;
1190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case TYPE_UNDEFINED:
11915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTREACHED() << "ShelfItemType must be set.";
1192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::pair<int, int> ShelfView::GetDragRange(int index) {
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int min_index = -1;
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_index = -1;
12015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfItemType type = model_->items()[index].type;
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < model_->item_count(); ++i) {
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SameDragType(model_->items()[i].type, type)) {
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (min_index == -1)
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        min_index = i;
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_index = i;
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::pair<int, int>(min_index, max_index);
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ConfigureChildView(views::View* view) {
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetPaintToLayer(true);
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->layer()->SetFillsBoundsOpaquely(false);
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ToggleOverflowBubble() {
12182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsShowingOverflowBubble()) {
12192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    overflow_bubble_->Hide();
12202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
12212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!overflow_bubble_)
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_bubble_.reset(new OverflowBubble());
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ShelfView* overflow_view =
12271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      new ShelfView(model_, delegate_, layout_manager_);
1228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  overflow_view->overflow_mode_ = true;
12292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->Init();
12304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  overflow_view->set_owner_overflow_bubble(overflow_bubble_.get());
12312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->OnShelfAlignmentChanged();
1232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  overflow_view->main_shelf_ = this;
12332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateOverflowRange(overflow_view);
12342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_bubble_->Show(overflow_button_, overflow_view);
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shell::GetInstance()->UpdateShelfVisibility();
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnFadeOutAnimationEnded() {
12412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AnimateToIdealBounds();
12421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  StartFadeInLastVisibleItem();
12431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
12442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ShelfView::StartFadeInLastVisibleItem() {
12462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If overflow button is visible and there is a valid new last item, fading
12472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the new last item in after sliding animation is finished.
12482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (overflow_button_->visible() && last_visible_index_ >= 0) {
12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    views::View* last_visible_view = view_model_->view_at(last_visible_index_);
12502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    last_visible_view->layer()->SetOpacity(0);
12512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bounds_animator_->SetAnimationDelegate(
12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        last_visible_view,
1253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        scoped_ptr<gfx::AnimationDelegate>(
1254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            new StartFadeAnimationDelegate(this, last_visible_view)));
12552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) const {
12592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int first_overflow_index = last_visible_index_ + 1;
12602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int last_overflow_index = last_hidden_index_;
12612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LE(first_overflow_index, last_overflow_index);
12622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(last_overflow_index, view_model_->view_size());
12632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->first_visible_index_ = first_overflow_index;
12652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  overflow_view->last_visible_index_ = last_overflow_index;
12662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) {
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect active_bounds;
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < child_count(); ++i) {
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* child = child_at(i);
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (child == overflow_button_)
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
12752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!ShouldShowTooltipForView(child))
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect child_bounds = child->GetMirroredBounds();
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    active_bounds.Union(child_bounds);
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !active_bounds.Contains(cursor_location);
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)gfx::Rect ShelfView::GetVisibleItemsBoundsInScreen() {
12864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  gfx::Size preferred_size = GetPreferredSize();
12874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0);
12884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ConvertPointToScreen(this, &origin);
12894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return gfx::Rect(origin, preferred_size);
12904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
12914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)gfx::Rect ShelfView::GetBoundsForDragInsertInScreen() {
1293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Size preferred_size;
1294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (is_overflow_mode()) {
1295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(owner_overflow_bubble_);
1296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    gfx::Rect bubble_bounds =
1297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        owner_overflow_bubble_->bubble_view()->GetBubbleBounds();
1298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    preferred_size = bubble_bounds.size();
1299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
1300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const int last_button_index = view_model_->view_size() - 1;
1301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    gfx::Rect last_button_bounds =
1302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        view_model_->view_at(last_button_index)->bounds();
1303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (overflow_button_->visible() &&
1304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        model_->GetItemIndexForType(TYPE_APP_PANEL) == -1) {
1305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // When overflow button is visible and shelf has no panel items,
1306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // last_button_bounds should be overflow button's bounds.
1307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      last_button_bounds = overflow_button_->bounds();
1308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (layout_manager_->IsHorizontalAlignment()) {
1311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      preferred_size = gfx::Size(last_button_bounds.right() + leading_inset_,
1312a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                 kShelfSize);
1313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else {
1314a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      preferred_size = gfx::Size(kShelfSize,
1315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                 last_button_bounds.bottom() + leading_inset_);
1316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0);
1319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // In overflow mode, we should use OverflowBubbleView as a source for
1321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // converting |origin| to screen coordinates. When a scroll operation is
1322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // occurred in OverflowBubble, the bounds of ShelfView in OverflowBubble can
1323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // be changed.
1324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (is_overflow_mode())
1325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ConvertPointToScreen(owner_overflow_bubble_->bubble_view(), &origin);
1326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  else
1327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ConvertPointToScreen(this, &origin);
1328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return gfx::Rect(origin, preferred_size);
1330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
13328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::CancelDrag(int modified_index) {
1333424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  FinalizeRipOffDrag(true);
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!drag_view_)
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return modified_index;
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_dragging = dragging();
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int drag_view_index = view_model_->GetIndexOfView(drag_view_);
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_pointer_ = NONE;
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_view_ = NULL;
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_view_index == modified_index) {
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The view that was being dragged is being modified. Don't do anything.
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return modified_index;
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!was_dragging)
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return modified_index;
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Restore previous position, tracking the position of the modified view.
13482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool at_end = modified_index == view_model_->view_size();
13492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View* modified_view =
13502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (modified_index >= 0 && !at_end) ?
13512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      view_model_->view_at(modified_index) : NULL;
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->Move(drag_view_index, start_drag_index_);
13532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the modified view will be at the end of the list, return the new end of
13552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the list.
13562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (at_end)
13572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return view_model_->view_size();
13582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return modified_view ? view_model_->GetIndexOfView(modified_view) : -1;
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size ShelfView::GetPreferredSize() const {
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdealBounds ideal_bounds;
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int last_button_index = is_overflow_mode() ?
1366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      last_visible_index_ : view_model_->view_size() - 1;
1367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // When an item is dragged off from the overflow bubble, it is moved to last
1369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // position and and changed to invisible. Overflow bubble size should be
1370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // shrunk to fit only for visible items.
1371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // If |dragged_off_from_overflow_to_shelf_| is set, there will be no invisible
1372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // items in the shelf.
1373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (is_overflow_mode() &&
1374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dragged_off_shelf_ &&
1375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      !dragged_off_from_overflow_to_shelf_ &&
1376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      RemovableByRipOff(view_model_->GetIndexOfView(drag_view_)) == REMOVABLE)
1377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    last_button_index--;
1378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect last_button_bounds =
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_button_index  >= first_visible_index_ ?
1381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          view_model_->ideal_bounds(last_button_index) :
1382a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          gfx::Rect(gfx::Size(kShelfSize, kShelfSize));
13832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (layout_manager_->IsHorizontalAlignment()) {
1385a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return gfx::Size(last_button_bounds.right() + leading_inset_, kShelfSize);
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1388a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return gfx::Size(kShelfSize,
13891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   last_button_bounds.bottom() + leading_inset_);
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
13935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This bounds change is produced by the shelf movement and all content has
13945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // to follow. Using an animation at that time would produce a time lag since
13955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the animation of the BoundsAnimator has itself a delay before it arrives
13965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // at the required location. As such we tell the animator to go there
13975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // immediately.
13985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BoundsAnimatorDisabler disabler(bounds_animator_.get());
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LayoutToIdealBounds();
14001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
14011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    OnShelfIconPositionsChanged());
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsShowingOverflowBubble())
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow_bubble_->Hide();
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)views::FocusTraversable* ShelfView::GetPaneFocusTraversable() {
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1411a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ShelfView::GetAccessibleState(ui::AXViewState* state) {
1412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_TOOLBAR;
14132385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  state->name = l10n_util::GetStringUTF16(IDS_ASH_SHELF_ACCESSIBLE_NAME);
141490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
141590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnGestureEvent(ui::GestureEvent* event) {
14172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (gesture_handler_.ProcessGestureEvent(*event))
14182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event->StopPropagation();
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ShelfView::ShelfItemAdded(int model_index) {
14222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
14232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoReset<bool> cancelling_drag(
14242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelling_drag_model_changed_, true);
14252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model_index = CancelDrag(model_index);
14262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = CreateViewForItem(model_->items()[model_index]);
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(view);
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hide the view, it'll be made visible when the animation is done. Using
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // opacity 0 here to avoid messing with CalculateIdealBounds which touches
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the view's visibility.
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->layer()->SetOpacity(0);
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_->Add(view, model_index);
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give the button its ideal bounds. That way if we end up animating the
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // button before this animation completes it doesn't appear at some random
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // spot (because it was in the middle of animating from 0,0 0x0 to its
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // target).
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdealBounds ideal_bounds;
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateIdealBounds(&ideal_bounds);
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->SetBoundsRect(view_model_->ideal_bounds(model_index));
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The first animation moves all the views to their target position. |view|
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is hidden, so it visually appears as though we are providing space for
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it. When done we'll fade the view in.
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AnimateToIdealBounds();
14472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (model_index <= last_visible_index_ ||
14482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      model_index >= model_->FirstPanelIndex()) {
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds_animator_->SetAnimationDelegate(
1450f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        view,
1451f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        scoped_ptr<gfx::AnimationDelegate>(
1452f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            new StartFadeAnimationDelegate(this, view)));
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Undo the hiding if animation does not run.
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view->layer()->SetOpacity(1.0f);
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) {
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id == context_menu_id_)
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    launcher_menu_runner_.reset();
14622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
14632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoReset<bool> cancelling_drag(
14642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelling_drag_model_changed_, true);
14652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model_index = CancelDrag(model_index);
14662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = view_model_->view_at(model_index);
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_->Remove(model_index);
14690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
14700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // When the overflow bubble is visible, the overflow range needs to be set
14710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // before CalculateIdealBounds() gets called. Otherwise CalculateIdealBounds()
14725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // could trigger a ShelfItemChanged() by hiding the overflow bubble and
1473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // since the overflow bubble is not yet synced with the ShelfModel this
14740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // could cause a crash.
14752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (overflow_bubble_ && overflow_bubble_->IsShowing()) {
14762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    last_hidden_index_ = std::min(last_hidden_index_,
14772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  view_model_->view_size() - 1);
14788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    UpdateOverflowRange(overflow_bubble_->shelf_view());
14792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1480d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
14810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (view->visible()) {
14820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // The first animation fades out the view. When done we'll animate the rest
14830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // of the views to their target location.
14840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    bounds_animator_->AnimateViewTo(view, view->bounds());
14850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    bounds_animator_->SetAnimationDelegate(
1486f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        view,
1487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        scoped_ptr<gfx::AnimationDelegate>(
1488f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            new FadeOutAnimationDelegate(this, view)));
14890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
14900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // We don't need to show a fade out animation for invisible |view|. When an
14910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // item is ripped out from the shelf, its |view| is already invisible.
14920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    AnimateToIdealBounds();
14930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
14940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1495d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Close the tooltip because it isn't needed any longer and its anchor view
1496d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // will be deleted soon.
1497d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (tooltip_->GetCurrentAnchorView() == view)
1498d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    tooltip_->Close();
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) {
15025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ShelfItem& item(model_->items()[model_index]);
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_item.type != item.type) {
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Type changed, swap the views.
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_index = CancelDrag(model_index);
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<views::View> old_view(view_model_->view_at(model_index));
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds_animator_->StopAnimatingView(old_view.get());
15083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Removing and re-inserting a view in our view model will strip the ideal
15093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // bounds from the item. To avoid recalculation of everything the bounds
15103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // get remembered and restored after the insertion to the previous value.
15113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    gfx::Rect old_ideal_bounds = view_model_->ideal_bounds(model_index);
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->Remove(model_index);
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* new_view = CreateViewForItem(item);
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildView(new_view);
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_model_->Add(new_view, model_index);
15163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    view_model_->set_ideal_bounds(model_index, old_ideal_bounds);
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_view->SetBoundsRect(old_view->bounds());
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* view = view_model_->view_at(model_index);
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (item.type) {
15232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TYPE_BROWSER_SHORTCUT:
1524f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Fallthrough for the new Shelf since it needs to show the activation
15252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // change as well.
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_SHORTCUT:
15272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case TYPE_WINDOWED_APP:
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_PLATFORM_APP:
15295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TYPE_DIALOG:
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TYPE_APP_PANEL: {
1531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShelfButton* button = static_cast<ShelfButton*>(view);
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReflectItemStatus(item, button);
15332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // The browser shortcut is currently not a "real" item and as such the
15342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // the image is bogous as well. We therefore keep the image as is for it.
15352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (item.type != TYPE_BROWSER_SHORTCUT)
15362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        button->SetImage(item.image);
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button->SchedulePaint();
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ShelfView::ShelfItemMoved(int start_index, int target_index) {
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_model_->Move(start_index, target_index);
15485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // When cancelling a drag due to a shelf item being added, the currently
15492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // dragged item is moved back to its initial position. AnimateToIdealBounds
15502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // will be called again when the new item is added to the |view_model_| but
15512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // at this time the |view_model_| is inconsistent with the |model_|.
15522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!cancelling_drag_model_changed_)
15532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AnimateToIdealBounds();
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ShelfView::ShelfStatusChanged() {
1557a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Nothing to do here.
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PointerPressedOnButton(views::View* view,
15618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       Pointer pointer,
15628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       const ui::LocatedEvent& event) {
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_view_)
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = view_model_->GetIndexOfView(view);
1567424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (index == -1)
1568424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
1569424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1570a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
15714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[index].id);
15724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (view_model_->view_size() <= 1 || !item_delegate->IsDraggable())
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // View is being deleted or not draggable, ignore request.
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_view_ = view;
1576f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  drag_origin_ = gfx::Point(event.x(), event.y());
1577f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentUsage",
1578f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      layout_manager_->SelectValueForShelfAlignment(
1579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM,
1580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT,
1581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT,
1582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          -1),
1583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT);
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PointerDraggedOnButton(views::View* view,
15878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       Pointer pointer,
15888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       const ui::LocatedEvent& event) {
15890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // To prepare all drag types (moving an item in the shelf and dragging off),
15900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // we should check the x-axis and y-axis offset.
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dragging() && drag_view_ &&
1592f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ((std::abs(event.x() - drag_origin_.x()) >= kMinimumDragDistance) ||
1593f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       (std::abs(event.y() - drag_origin_.y()) >= kMinimumDragDistance))) {
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PrepareForDrag(pointer, event);
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drag_pointer_ == pointer)
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ContinueDrag(event);
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::PointerReleasedOnButton(views::View* view,
16018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                        Pointer pointer,
16028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                        bool canceled) {
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (canceled) {
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelDrag(-1);
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (drag_pointer_ == pointer) {
1606424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    FinalizeRipOffDrag(false);
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drag_pointer_ = NONE;
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimateToIdealBounds();
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1610ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // If the drag pointer is NONE, no drag operation is going on and the
1611ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // drag_view can be released.
1612ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (drag_pointer_ == NONE)
1613ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    drag_view_ = NULL;
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::MouseMovedOverButton(views::View* view) {
16172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!ShouldShowTooltipForView(view))
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tooltip_->IsVisible())
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->ResetTimer();
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::MouseEnteredButton(views::View* view) {
16252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!ShouldShowTooltipForView(view))
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tooltip_->IsVisible()) {
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->ShowImmediately(view, GetAccessibleName(view));
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->ShowDelayed(view, GetAccessibleName(view));
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::MouseExitedButton(views::View* view) {
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tooltip_->IsVisible())
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tooltip_->StopTimer();
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)base::string16 ShelfView::GetAccessibleName(const views::View* view) {
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int view_index = view_model_->GetIndexOfView(view);
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May be -1 while in the process of animating closed.
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_index == -1)
1644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return base::string16();
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1646a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
16474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[view_index].id);
16484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return item_delegate->GetTitle();
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ButtonPressed(views::Button* sender, const ui::Event& event) {
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do not handle mouse release during drag.
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dragging())
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sender == overflow_button_) {
16572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ToggleOverflowBubble();
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int view_index = view_model_->GetIndexOfView(sender);
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May be -1 while in the process of animating closed.
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_index == -1)
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the previous menu was closed by the same event as this one, we ignore
16672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the call.
16682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsUsableEvent(event))
16692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
16702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Don't activate the item twice on double-click. Otherwise the window starts
16721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // animating open due to the first click, then immediately minimizes due to
16731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the second click. The user most likely intended to open or minimize the
16741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // item once, not do both.
16751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (event.flags() & ui::EF_IS_DOUBLE_CLICK)
16761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
16771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
16782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1679a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ScopedTargetRootWindow scoped_target(
1680a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        sender->GetWidget()->GetNativeView()->GetRootWindow());
16812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Slow down activation animations if shift key is pressed.
16822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations;
16832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (event.IsShiftDown()) {
16842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode(
16852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
16862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
16872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1688b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // Collect usage statistics before we decide what to do with the click.
1689b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    switch (model_->items()[view_index].type) {
1690b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_APP_SHORTCUT:
1691b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_WINDOWED_APP:
1692b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_PLATFORM_APP:
169390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case TYPE_BROWSER_SHORTCUT:
16945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Shell::GetInstance()->metrics()->RecordUserMetricsAction(
1695b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            UMA_LAUNCHER_CLICK_ON_APP);
1696b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        break;
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1698b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      case TYPE_APP_LIST:
16995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Shell::GetInstance()->metrics()->RecordUserMetricsAction(
1700b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
1701424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        break;
1702424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1703424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      case TYPE_APP_PANEL:
17045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case TYPE_DIALOG:
1705424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        break;
1706424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1707424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      case TYPE_UNDEFINED:
17085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        NOTREACHED() << "ShelfItemType must be set.";
1709b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        break;
17102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1711424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1712a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ShelfItemDelegate* item_delegate =
1713a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        item_manager_->GetShelfItemDelegate(model_->items()[view_index].id);
1714f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!item_delegate->ItemSelected(event))
1715f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ShowListMenuForView(model_->items()[view_index], sender, event);
17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
17182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShelfView::ShowListMenuForView(const ShelfItem& item,
17208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                    views::View* source,
17218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                    const ui::Event& event) {
1722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate =
1723a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      item_manager_->GetShelfItemDelegate(item.id);
17241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<ui::MenuModel> list_menu_model(
17251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      item_delegate->CreateApplicationMenu(event.flags()));
17262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make sure we have a menu and it has at least two items in addition to the
17282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // application title and the 3 spacing separators.
17291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!list_menu_model.get() || list_menu_model->GetItemCount() <= 5)
17302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
17312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ShowMenu(list_menu_model.get(),
17332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           source,
17342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           gfx::Point(),
17357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           false,
17367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           ui::GetMenuSourceTypeForEvent(event));
17372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::ShowContextMenuForView(views::View* source,
17418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       const gfx::Point& point,
17428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       ui::MenuSourceType source_type) {
17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int view_index = view_model_->GetIndexOfView(source);
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_index == -1) {
17457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    Shell::GetInstance()->ShowContextMenu(point, source_type);
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1749a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate(
17504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      model_->items()[view_index].id);
1751cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  context_menu_model_.reset(item_delegate->CreateContextMenu(
17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      source->GetWidget()->GetNativeView()->GetRootWindow()));
1753cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!context_menu_model_)
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1755424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
17565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::AutoReset<ShelfID> reseter(
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &context_menu_id_,
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_index == -1 ? 0 : model_->items()[view_index].id);
17592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1760cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ShowMenu(context_menu_model_.get(),
17612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           source,
17622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           point,
17637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           true,
17647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           source_type);
17652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
17662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1767cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ShelfView::ShowMenu(ui::MenuModel* menu_model,
17688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         views::View* source,
17698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         const gfx::Point& click_point,
17708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         bool context_menu,
17718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                         ui::MenuSourceType source_type) {
17722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  closing_event_time_ = base::TimeDelta();
1773116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  launcher_menu_runner_.reset(new views::MenuRunner(
1774116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      menu_model, context_menu ? views::MenuRunner::CONTEXT_MENU : 0));
17752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1776a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ScopedTargetRootWindow scoped_target(
1777a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      source->GetWidget()->GetNativeView()->GetRootWindow());
1778a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
17792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Determine the menu alignment dependent on the shelf.
17805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  views::MenuAnchorPosition menu_alignment = views::MENU_ANCHOR_TOPLEFT;
17812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Rect anchor_point = gfx::Rect(click_point, gfx::Size());
17822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfWidget* shelf = RootWindowController::ForShelf(
1784c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetWidget()->GetNativeView())->shelf();
17852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!context_menu) {
17862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Application lists use a bubble.
17875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShelfAlignment align = shelf->GetAlignment();
17882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    anchor_point = source->GetBoundsInScreen();
17892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // It is possible to invoke the menu while it is sliding into view. To cover
17917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // that case, the screen coordinates are offsetted by the animation delta.
17927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    gfx::Vector2d offset =
17937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        source->GetWidget()->GetNativeWindow()->bounds().origin() -
17947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        source->GetWidget()->GetNativeWindow()->GetTargetBounds().origin();
17957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    anchor_point.set_x(anchor_point.x() - offset.x());
17967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    anchor_point.set_y(anchor_point.y() - offset.y());
17977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1798f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Shelf items can have an asymmetrical border for spacing reasons.
17992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Adjust anchor location for this.
18002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (source->border())
18012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      anchor_point.Inset(source->border()->GetInsets());
18022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (align) {
18045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_BOTTOM:
18055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        menu_alignment = views::MENU_ANCHOR_BUBBLE_ABOVE;
18062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
18075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_LEFT:
18085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        menu_alignment = views::MENU_ANCHOR_BUBBLE_RIGHT;
18092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
18105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_RIGHT:
18115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        menu_alignment = views::MENU_ANCHOR_BUBBLE_LEFT;
18122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
18135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SHELF_ALIGNMENT_TOP:
18145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        menu_alignment = views::MENU_ANCHOR_BUBBLE_BELOW;
18152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
18162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
18172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
18185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If this gets deleted while we are in the menu, the shelf will be gone
1819c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // as well.
1820c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool got_deleted = false;
1821c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  got_deleted_ = &got_deleted;
1822c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1823c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  shelf->ForceUndimming(true);
18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: if you convert to HAS_MNEMONICS be sure and update menu building
18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // code.
1826116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (launcher_menu_runner_->RunMenuAt(source->GetWidget(),
1827116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       NULL,
1828116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       anchor_point,
1829116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       menu_alignment,
1830116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       source_type) ==
18317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      views::MenuRunner::MENU_DELETED) {
1832c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!got_deleted) {
1833c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      got_deleted_ = NULL;
1834c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      shelf->ForceUndimming(false);
1835c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1837c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1838c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  got_deleted_ = NULL;
1839c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  shelf->ForceUndimming(false);
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If it is a context menu and we are showing overflow bubble
18424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // we want to hide overflow bubble.
18434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (owner_overflow_bubble_)
18444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    owner_overflow_bubble_->HideBubbleAndRefreshButton();
18454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
18462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Unpinning an item will reset the |launcher_menu_runner_| before coming
18472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // here.
1848c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (launcher_menu_runner_)
18492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closing_event_time_ = launcher_menu_runner_->closing_event_time();
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shell::GetInstance()->UpdateShelfVisibility();
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) {
18541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
18551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    OnShelfIconPositionsChanged());
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreferredSizeChanged();
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void ShelfView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
1860424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (snap_back_from_rip_off_view_ && animator == bounds_animator_) {
1861424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (!animator->IsAnimating(snap_back_from_rip_off_view_)) {
1862f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Coming here the animation of the ShelfButton is finished and the
1863424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // previously hidden status can be shown again. Since the button itself
1864424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // might have gone away or changed locations we check that the button
1865424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // is still in the shelf and show its status again.
1866424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      for (int index = 0; index < view_model_->view_size(); index++) {
1867424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        views::View* view = view_model_->view_at(index);
1868424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (view == snap_back_from_rip_off_view_) {
1869f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          ShelfButton* button = static_cast<ShelfButton*>(view);
1870f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          button->ClearState(ShelfButton::STATE_HIDDEN);
1871424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          break;
1872424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
1873424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      }
1874424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      snap_back_from_rip_off_view_ = NULL;
1875424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
1876424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::IsUsableEvent(const ui::Event& event) {
18802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (closing_event_time_ == base::TimeDelta())
18812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
18822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta delta =
18842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta(event.time_stamp() - closing_event_time_);
18852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  closing_event_time_ = base::TimeDelta();
18862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(skuhne): This time seems excessive, but it appears that the reposting
18872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // takes that long.  Need to come up with a better way of doing this.
18882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (delta.InMilliseconds() < 0 || delta.InMilliseconds() > 130);
18892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
18902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const ShelfItem* ShelfView::ShelfItemForView(const views::View* view) const {
18922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int view_index = view_model_->GetIndexOfView(view);
18932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (view_index == -1)
18942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
18952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return &(model_->items()[view_index]);
18962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
18972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool ShelfView::ShouldShowTooltipForView(const views::View* view) const {
18992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (view == GetAppListButtonView() &&
19002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Shell::GetInstance()->GetAppListWindow())
19012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
19025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ShelfItem* item = ShelfItemForView(view);
1903424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!item)
1904424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
1905a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ShelfItemDelegate* item_delegate =
1906a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      item_manager_->GetShelfItemDelegate(item->id);
19074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return item_delegate->ShouldShowTooltip();
1908424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
1909424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
19108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const {
19115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfWidget* shelf = RootWindowController::ForShelf(
1912424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      GetWidget()->GetNativeView())->shelf();
19135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShelfAlignment align = shelf->GetAlignment();
1914424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const gfx::Rect bounds = GetBoundsInScreen();
1915424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int distance = 0;
1916424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  switch (align) {
19175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_BOTTOM:
1918424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = bounds.y() - coordinate.y();
1919424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
19205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_LEFT:
1921424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = coordinate.x() - bounds.right();
1922424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
19235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_RIGHT:
1924424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = bounds.x() - coordinate.x();
1925424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
19265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SHELF_ALIGNMENT_TOP:
1927424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      distance = coordinate.y() - bounds.bottom();
1928424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      break;
1929424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1930424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return distance > 0 ? distance : 0;
19312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
19322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
1934