1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef ASH_SHELF_SHELF_APP_BUTTON_H_
6 #define ASH_SHELF_SHELF_APP_BUTTON_H_
7 
8 #include "ash/ash_export.h"
9 #include "ash/shelf/shelf_button.h"
10 #include "ash/shelf/shelf_button_delegate.h"
11 #include "base/macros.h"
12 #include "base/timer/timer.h"
13 #include "ui/compositor/layer_animation_observer.h"
14 #include "ui/gfx/shadow_value.h"
15 #include "ui/views/animation/ink_drop_observer.h"
16 #include "ui/views/animation/ink_drop_state.h"
17 
18 namespace views {
19 class ImageView;
20 }
21 
22 namespace ash {
23 struct ShelfItem;
24 class ShelfView;
25 
26 // Button used for app shortcuts on the shelf..
27 class ASH_EXPORT ShelfAppButton : public ShelfButton,
28                                   public views::InkDropObserver,
29                                   public ui::ImplicitAnimationObserver {
30  public:
31   static const char kViewClassName[];
32 
33   // Used to indicate the current state of the button.
34   enum State {
35     // Nothing special. Usually represents an app shortcut item with no running
36     // instance.
37     STATE_NORMAL = 0,
38     // Button has mouse hovering on it.
39     STATE_HOVERED = 1 << 0,
40     // Underlying ShelfItem has a running instance.
41     STATE_RUNNING = 1 << 1,
42     // Underlying ShelfItem needs user's attention.
43     STATE_ATTENTION = 1 << 2,
44     // Hide the status (temporarily for some animations).
45     STATE_HIDDEN = 1 << 3,
46     // Button is being dragged.
47     STATE_DRAGGING = 1 << 4,
48     // App has at least 1 notification.
49     STATE_NOTIFICATION = 1 << 5,
50     // Underlying ShelfItem owns the window that is currently active.
51     STATE_ACTIVE = 1 << 6,
52   };
53 
54   // Returns whether |event| should be handled by a ShelfAppButton if a context
55   // menu for the view is shown. Note that the context menu controller will
56   // redirect gesture events to the hotseat widget if the context menu was shown
57   // for a ShelfAppButton). The hotseat widget uses this method to determine
58   // whether such events can/should be dropped without handling.
59   static bool ShouldHandleEventFromContextMenu(const ui::GestureEvent* event);
60 
61   ShelfAppButton(ShelfView* shelf_view,
62                  ShelfButtonDelegate* shelf_button_delegate);
63   ~ShelfAppButton() override;
64 
65   // Sets the image to display for this entry.
66   void SetImage(const gfx::ImageSkia& image);
67 
68   // Retrieve the image to show proxy operations.
69   const gfx::ImageSkia& GetImage() const;
70 
71   // |state| is or'd into the current state.
72   void AddState(State state);
73   void ClearState(State state);
state()74   int state() const { return state_; }
75 
76   // Clears drag drag state that might have been set by gesture handling when a
77   // gesture ends. No-op if the drag state has already been cleared.
78   void ClearDragStateOnGestureEnd();
79 
80   // Returns the bounds of the icon.
81   gfx::Rect GetIconBounds() const;
82 
83   // Returns the bounds of the icon in screen coordinates.
84   gfx::Rect GetIconBoundsInScreen() const;
85 
86   views::InkDrop* GetInkDropForTesting();
87 
88   // Called when user started dragging the shelf button.
89   void OnDragStarted(const ui::LocatedEvent* event);
90 
91   // Callback used when a menu for this ShelfAppButton is closed.
92   void OnMenuClosed();
93 
94   // views::Button overrides:
95   void ShowContextMenu(const gfx::Point& p,
96                        ui::MenuSourceType source_type) override;
97   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
98   bool ShouldEnterPushedState(const ui::Event& event) override;
99 
100   // views::View overrides:
101   const char* GetClassName() const override;
102   bool OnMousePressed(const ui::MouseEvent& event) override;
103   void OnMouseReleased(const ui::MouseEvent& event) override;
104   void OnMouseCaptureLost() override;
105   bool OnMouseDragged(const ui::MouseEvent& event) override;
106   void Layout() override;
107   void ChildPreferredSizeChanged(views::View* child) override;
108 
109   // Update button state from ShelfItem.
110   void ReflectItemStatus(const ShelfItem& item);
111 
112   // Returns whether the icon size is up to date.
113   bool IsIconSizeCurrent();
114 
115   bool FireDragTimerForTest();
116   void FireRippleActivationTimerForTest();
117 
118   // Return the bounds in the local coordinates enclosing the small ripple area.
119   gfx::Rect CalculateSmallRippleArea() const;
120 
121   // Gets the color of the |notification_indicator_| for test usage.
122   SkColor GetNotificationIndicatorColorForTest();
123 
124  protected:
125   // ui::EventHandler:
126   void OnGestureEvent(ui::GestureEvent* event) override;
127 
128   // views::Button:
129   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
130 
131   // ui::ImplicitAnimationObserver:
132   void OnImplicitAnimationsCompleted() override;
133 
134   // Sets the icon image with a shadow.
135   void SetShadowedImage(const gfx::ImageSkia& bitmap);
136 
137  private:
138   class AppNotificationIndicatorView;
139   class AppStatusIndicatorView;
140 
141   // views::View:
142   bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
143 
144   // views::InkDropObserver:
145   void InkDropAnimationStarted() override;
146   void InkDropRippleAnimationEnded(views::InkDropState state) override;
147 
148   // Updates the parts of the button to reflect the current |state_| and
149   // alignment. This may add or remove views, layout and paint.
150   void UpdateState();
151 
152   // Invoked when |touch_drag_timer_| fires to show dragging UI.
153   void OnTouchDragTimer();
154 
155   // Invoked when |ripple_activation_timer_| fires to activate the ink drop.
156   void OnRippleTimer();
157 
158   // Scales up app icon if |scale_up| is true, otherwise scales it back to
159   // normal size.
160   void ScaleAppIcon(bool scale_up);
161 
162   // Calculates the icon bounds for an icon scaled by |icon_scale|.
163   gfx::Rect GetIconViewBounds(float icon_scale);
164 
165   // Calculates the transform between the icon scaled by |icon_scale| and the
166   // normal size icon.
167   gfx::Transform GetScaleTransform(float icon_scale);
168 
169   // Marks whether the ink drop animation has started or not.
170   void SetInkDropAnimationStarted(bool started);
171 
172   // The icon part of a button can be animated independently of the rest.
173   views::ImageView* icon_view_;
174 
175   // The ShelfView showing this ShelfAppButton. Owned by RootWindowController.
176   ShelfView* shelf_view_;
177 
178   // Draws an indicator underneath the image to represent the state of the
179   // application.
180   AppStatusIndicatorView* indicator_;
181 
182   // Draws an indicator in the top right corner of the image to represent an
183   // active notification.
184   AppNotificationIndicatorView* notification_indicator_;
185 
186   // The current application state, a bitfield of State enum values.
187   int state_;
188 
189   gfx::ShadowValues icon_shadows_;
190 
191   // If non-null the destuctor sets this to true. This is set while the menu is
192   // showing and used to detect if the menu was deleted while running.
193   bool* destroyed_flag_;
194 
195   // Whether the notification indicator is enabled.
196   const bool is_notification_indicator_enabled_;
197 
198   // The bitmap image for this app button.
199   gfx::ImageSkia icon_image_;
200 
201   // The scaling factor for displaying the app icon.
202   float icon_scale_ = 1.0f;
203 
204   // Indicates whether the ink drop animation starts.
205   bool ink_drop_animation_started_ = false;
206 
207   // A timer to defer showing drag UI when the shelf button is pressed.
208   base::OneShotTimer drag_timer_;
209 
210   // A timer to activate the ink drop ripple during a long press.
211   base::OneShotTimer ripple_activation_timer_;
212 
213   std::unique_ptr<ShelfButtonDelegate::ScopedActiveInkDropCount>
214       ink_drop_count_;
215 
216   DISALLOW_COPY_AND_ASSIGN(ShelfAppButton);
217 };
218 
219 }  // namespace ash
220 
221 #endif  // ASH_SHELF_SHELF_APP_BUTTON_H_
222