OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "views/controls/button/custom_button.h" | 5 #include "views/controls/button/custom_button.h" |
6 | 6 |
7 #include "app/throb_animation.h" | 7 #include "app/throb_animation.h" |
8 #include "base/keyboard_codes.h" | 8 #include "base/keyboard_codes.h" |
9 | 9 |
10 namespace views { | 10 namespace views { |
11 | 11 |
12 // How long the hover animation takes if uninterrupted. | 12 // How long the hover animation takes if uninterrupted. |
13 static const int kHoverFadeDurationMs = 150; | 13 static const int kHoverFadeDurationMs = 150; |
14 | 14 |
15 //////////////////////////////////////////////////////////////////////////////// | 15 //////////////////////////////////////////////////////////////////////////////// |
16 // CustomButton, public: | 16 // CustomButton, public: |
17 | 17 |
18 CustomButton::~CustomButton() { | 18 CustomButton::~CustomButton() { |
19 } | 19 } |
20 | 20 |
21 void CustomButton::SetState(ButtonState state) { | 21 void CustomButton::SetState(ButtonState state) { |
22 if (state != state_) { | 22 if (state == state_) |
23 if (animate_on_state_change_ || !hover_animation_->is_animating()) { | 23 return; |
24 animate_on_state_change_ = true; | 24 |
25 if (state_ == BS_NORMAL && state == BS_HOT) { | 25 if (animate_on_state_change_ || !hover_animation_->is_animating()) { |
26 // Button is hovered from a normal state, start hover animation. | 26 animate_on_state_change_ = true; |
27 hover_animation_->Show(); | 27 if (state_ == BS_NORMAL && state == BS_HOT) { |
28 } else if (state_ == BS_HOT && state == BS_NORMAL) { | 28 // Button is hovered from a normal state, start hover animation. |
29 // Button is returning to a normal state from hover, start hover | 29 hover_animation_->Show(); |
30 // fade animation. | 30 } else if (state_ == BS_HOT && state == BS_NORMAL) { |
31 hover_animation_->Hide(); | 31 // Button is returning to a normal state from hover, start hover |
32 } else { | 32 // fade animation. |
33 hover_animation_->Stop(); | 33 hover_animation_->Hide(); |
34 } | 34 } else { |
| 35 hover_animation_->Stop(); |
35 } | 36 } |
| 37 } |
36 | 38 |
37 state_ = state; | 39 state_ = state; |
38 SchedulePaint(); | 40 SchedulePaint(); |
39 } | |
40 } | 41 } |
41 | 42 |
42 void CustomButton::StartThrobbing(int cycles_til_stop) { | 43 void CustomButton::StartThrobbing(int cycles_til_stop) { |
43 animate_on_state_change_ = false; | 44 animate_on_state_change_ = false; |
44 hover_animation_->StartThrobbing(cycles_til_stop); | 45 hover_animation_->StartThrobbing(cycles_til_stop); |
45 } | 46 } |
46 | 47 |
47 void CustomButton::SetAnimationDuration(int duration) { | 48 void CustomButton::SetAnimationDuration(int duration) { |
48 hover_animation_->SetSlideDuration(duration); | 49 hover_animation_->SetSlideDuration(duration); |
49 } | 50 } |
50 | 51 |
51 //////////////////////////////////////////////////////////////////////////////// | 52 //////////////////////////////////////////////////////////////////////////////// |
52 // CustomButton, View overrides: | 53 // CustomButton, View overrides: |
53 | 54 |
54 bool CustomButton::GetAccessibleState(AccessibilityTypes::State* state) { | 55 bool CustomButton::GetAccessibleState(AccessibilityTypes::State* state) { |
55 *state = 0; | 56 *state = 0; |
56 switch (state_) { | 57 switch (state_) { |
57 case BS_NORMAL: | |
58 *state = 0; | |
59 case BS_HOT: | 58 case BS_HOT: |
60 *state = AccessibilityTypes::STATE_HOTTRACKED; | 59 *state = AccessibilityTypes::STATE_HOTTRACKED; |
61 case BS_PUSHED: | 60 case BS_PUSHED: |
62 *state = AccessibilityTypes::STATE_PRESSED; | 61 *state = AccessibilityTypes::STATE_PRESSED; |
63 case BS_DISABLED: | 62 case BS_DISABLED: |
64 *state = AccessibilityTypes::STATE_UNAVAILABLE; | 63 *state = AccessibilityTypes::STATE_UNAVAILABLE; |
| 64 case BS_NORMAL: |
65 case BS_COUNT: | 65 case BS_COUNT: |
66 // No additional accessibility state set for this button state. | 66 // No additional accessibility state set for this button state. |
67 break; | 67 break; |
68 } | 68 } |
69 | 69 |
70 return true; | 70 return true; |
71 } | 71 } |
72 | 72 |
73 void CustomButton::SetEnabled(bool enabled) { | 73 void CustomButton::SetEnabled(bool enabled) { |
74 if (enabled && state_ == BS_DISABLED) { | 74 if (enabled ? (state_ == BS_DISABLED) : (state_ != BS_DISABLED)) |
75 SetState(BS_NORMAL); | 75 SetState(enabled ? BS_NORMAL : BS_DISABLED); |
76 } else if (!enabled && state_ != BS_DISABLED) { | |
77 SetState(BS_DISABLED); | |
78 } | |
79 } | 76 } |
80 | 77 |
81 bool CustomButton::IsEnabled() const { | 78 bool CustomButton::IsEnabled() const { |
82 return state_ != BS_DISABLED; | 79 return state_ != BS_DISABLED; |
83 } | 80 } |
84 | 81 |
85 bool CustomButton::IsFocusable() const { | 82 bool CustomButton::IsFocusable() const { |
86 return (state_ != BS_DISABLED) && View::IsFocusable(); | 83 return (state_ != BS_DISABLED) && View::IsFocusable(); |
87 } | 84 } |
88 | 85 |
(...skipping 11 matching lines...) Expand all Loading... |
100 } | 97 } |
101 | 98 |
102 bool CustomButton::IsTriggerableEvent(const MouseEvent& e) { | 99 bool CustomButton::IsTriggerableEvent(const MouseEvent& e) { |
103 return (triggerable_event_flags_ & e.GetFlags()) != 0; | 100 return (triggerable_event_flags_ & e.GetFlags()) != 0; |
104 } | 101 } |
105 | 102 |
106 //////////////////////////////////////////////////////////////////////////////// | 103 //////////////////////////////////////////////////////////////////////////////// |
107 // CustomButton, View overrides (protected): | 104 // CustomButton, View overrides (protected): |
108 | 105 |
109 bool CustomButton::AcceleratorPressed(const Accelerator& accelerator) { | 106 bool CustomButton::AcceleratorPressed(const Accelerator& accelerator) { |
110 if (enabled_) { | 107 if (!enabled_) |
111 SetState(BS_NORMAL); | 108 return false; |
112 KeyEvent key_event(Event::ET_KEY_RELEASED, accelerator.GetKeyCode(), | 109 |
113 accelerator.modifiers(), 0, 0); | 110 SetState(BS_NORMAL); |
114 NotifyClick(key_event); | 111 KeyEvent key_event(Event::ET_KEY_RELEASED, accelerator.GetKeyCode(), |
115 return true; | 112 accelerator.modifiers(), 0, 0); |
116 } | 113 NotifyClick(key_event); |
117 return false; | 114 return true; |
118 } | 115 } |
119 | 116 |
120 bool CustomButton::OnMousePressed(const MouseEvent& e) { | 117 bool CustomButton::OnMousePressed(const MouseEvent& e) { |
121 if (state_ != BS_DISABLED) { | 118 if (state_ != BS_DISABLED) { |
122 if (ShouldEnterPushedState(e) && HitTest(e.location())) | 119 if (ShouldEnterPushedState(e) && HitTest(e.location())) |
123 SetState(BS_PUSHED); | 120 SetState(BS_PUSHED); |
124 if (request_focus_on_press_) | 121 if (request_focus_on_press_) |
125 RequestFocus(); | 122 RequestFocus(); |
126 } | 123 } |
127 return true; | 124 return true; |
128 } | 125 } |
129 | 126 |
130 bool CustomButton::OnMouseDragged(const MouseEvent& e) { | 127 bool CustomButton::OnMouseDragged(const MouseEvent& e) { |
131 if (state_ != BS_DISABLED) { | 128 if (state_ != BS_DISABLED) { |
132 if (!HitTest(e.location())) | 129 if (HitTest(e.location())) |
| 130 SetState(ShouldEnterPushedState(e) ? BS_PUSHED : BS_HOT); |
| 131 else |
133 SetState(BS_NORMAL); | 132 SetState(BS_NORMAL); |
134 else if (ShouldEnterPushedState(e)) | |
135 SetState(BS_PUSHED); | |
136 else | |
137 SetState(BS_HOT); | |
138 } | 133 } |
139 return true; | 134 return true; |
140 } | 135 } |
141 | 136 |
142 void CustomButton::OnMouseReleased(const MouseEvent& e, bool canceled) { | 137 void CustomButton::OnMouseReleased(const MouseEvent& e, bool canceled) { |
143 if (InDrag()) { | 138 // Starting a drag results in a MouseReleased, we need to ignore it. |
144 // Starting a drag results in a MouseReleased, we need to ignore it. | 139 if ((state_ == BS_DISABLED) || InDrag()) |
| 140 return; |
| 141 |
| 142 if (!HitTest(e.location())) { |
| 143 SetState(BS_NORMAL); |
145 return; | 144 return; |
146 } | 145 } |
147 | 146 |
148 if (state_ != BS_DISABLED) { | 147 SetState(BS_HOT); |
149 if (canceled || !HitTest(e.location())) { | 148 if (!canceled && IsTriggerableEvent(e)) { |
150 SetState(BS_NORMAL); | 149 NotifyClick(e); |
151 } else { | 150 // NOTE: We may be deleted at this point (by the listener's notification |
152 SetState(BS_HOT); | 151 // handler). |
153 if (IsTriggerableEvent(e)) { | |
154 NotifyClick(e); | |
155 // We may be deleted at this point (by the listener's notification | |
156 // handler) so no more doing anything, just return. | |
157 return; | |
158 } | |
159 } | |
160 } | 152 } |
161 } | 153 } |
162 | 154 |
163 void CustomButton::OnMouseEntered(const MouseEvent& e) { | 155 void CustomButton::OnMouseEntered(const MouseEvent& e) { |
164 if (state_ != BS_DISABLED) | 156 if (state_ != BS_DISABLED) |
165 SetState(BS_HOT); | 157 SetState(BS_HOT); |
166 } | 158 } |
167 | 159 |
168 void CustomButton::OnMouseMoved(const MouseEvent& e) { | 160 void CustomButton::OnMouseMoved(const MouseEvent& e) { |
169 if (state_ != BS_DISABLED) { | 161 if (state_ != BS_DISABLED) |
170 if (HitTest(e.location())) { | 162 SetState(HitTest(e.location()) ? BS_HOT : BS_NORMAL); |
171 SetState(BS_HOT); | |
172 } else { | |
173 SetState(BS_NORMAL); | |
174 } | |
175 } | |
176 } | 163 } |
177 | 164 |
178 void CustomButton::OnMouseExited(const MouseEvent& e) { | 165 void CustomButton::OnMouseExited(const MouseEvent& e) { |
179 // Starting a drag results in a MouseExited, we need to ignore it. | 166 // Starting a drag results in a MouseExited, we need to ignore it. |
180 if (state_ != BS_DISABLED && !InDrag()) | 167 if (state_ != BS_DISABLED && !InDrag()) |
181 SetState(BS_NORMAL); | 168 SetState(BS_NORMAL); |
182 } | 169 } |
183 | 170 |
184 bool CustomButton::OnKeyPressed(const KeyEvent& e) { | 171 bool CustomButton::OnKeyPressed(const KeyEvent& e) { |
185 if (state_ != BS_DISABLED) { | 172 if (state_ == BS_DISABLED) |
186 // Space sets button state to pushed. Enter clicks the button. This matches | 173 return false; |
187 // the Windows native behavior of buttons, where Space clicks the button | 174 |
188 // on KeyRelease and Enter clicks the button on KeyPressed. | 175 // Space sets button state to pushed. Enter clicks the button. This matches |
189 if (e.GetKeyCode() == base::VKEY_SPACE) { | 176 // the Windows native behavior of buttons, where Space clicks the button on |
190 SetState(BS_PUSHED); | 177 // KeyRelease and Enter clicks the button on KeyPressed. |
191 return true; | 178 if (e.GetKeyCode() == base::VKEY_SPACE) { |
192 } else if (e.GetKeyCode() == base::VKEY_RETURN) { | 179 SetState(BS_PUSHED); |
193 SetState(BS_NORMAL); | 180 } else if (e.GetKeyCode() == base::VKEY_RETURN) { |
194 NotifyClick(e); | 181 SetState(BS_NORMAL); |
195 return true; | 182 NotifyClick(e); |
196 } | |
197 } | 183 } |
198 return false; | 184 return true; |
199 } | 185 } |
200 | 186 |
201 bool CustomButton::OnKeyReleased(const KeyEvent& e) { | 187 bool CustomButton::OnKeyReleased(const KeyEvent& e) { |
202 if (state_ != BS_DISABLED) { | 188 if ((state_ == BS_DISABLED) || (e.GetKeyCode() != base::VKEY_SPACE)) |
203 if (e.GetKeyCode() == base::VKEY_SPACE) { | 189 return false; |
204 SetState(BS_NORMAL); | 190 |
205 NotifyClick(e); | 191 SetState(BS_NORMAL); |
206 return true; | 192 NotifyClick(e); |
207 } | 193 return true; |
208 } | |
209 return false; | |
210 } | 194 } |
211 | 195 |
212 void CustomButton::OnDragDone() { | 196 void CustomButton::OnDragDone() { |
213 SetState(BS_NORMAL); | 197 SetState(BS_NORMAL); |
214 } | 198 } |
215 | 199 |
216 void CustomButton::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) { | 200 void CustomButton::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) { |
217 if (GetContextMenuController()) { | 201 if (!GetContextMenuController()) |
218 // We're about to show the context menu. Showing the context menu likely | 202 return; |
219 // means we won't get a mouse exited and reset state. Reset it now to be | 203 |
220 // sure. | 204 // We're about to show the context menu. Showing the context menu likely means |
221 if (state_ != BS_DISABLED) | 205 // we won't get a mouse exited and reset state. Reset it now to be sure. |
222 SetState(BS_NORMAL); | 206 if (state_ != BS_DISABLED) |
223 View::ShowContextMenu(p, is_mouse_gesture); | 207 SetState(BS_NORMAL); |
224 } | 208 View::ShowContextMenu(p, is_mouse_gesture); |
225 } | 209 } |
226 | 210 |
227 void CustomButton::ViewHierarchyChanged(bool is_add, View *parent, | 211 void CustomButton::ViewHierarchyChanged(bool is_add, View *parent, |
228 View *child) { | 212 View *child) { |
229 if (!is_add && state_ != BS_DISABLED) | 213 if (!is_add && state_ != BS_DISABLED) |
230 SetState(BS_NORMAL); | 214 SetState(BS_NORMAL); |
231 } | 215 } |
232 | 216 |
233 void CustomButton::SetHotTracked(bool flag) { | 217 void CustomButton::SetHotTracked(bool flag) { |
234 if (state_ != BS_DISABLED) | 218 if (state_ != BS_DISABLED) |
(...skipping 16 matching lines...) Expand all Loading... |
251 // CustomButton, AnimationDelegate implementation: | 235 // CustomButton, AnimationDelegate implementation: |
252 | 236 |
253 void CustomButton::AnimationProgressed(const Animation* animation) { | 237 void CustomButton::AnimationProgressed(const Animation* animation) { |
254 SchedulePaint(); | 238 SchedulePaint(); |
255 } | 239 } |
256 | 240 |
257 bool CustomButton::ShouldEnterPushedState(const MouseEvent& e) { | 241 bool CustomButton::ShouldEnterPushedState(const MouseEvent& e) { |
258 return IsTriggerableEvent(e); | 242 return IsTriggerableEvent(e); |
259 } | 243 } |
260 | 244 |
261 //////////////////////////////////////////////////////////////////////////////// | |
262 // CustomButton, private: | |
263 | |
264 void CustomButton::SetHighlighted(bool highlighted) { | |
265 if (highlighted && state_ != BS_DISABLED) { | |
266 SetState(BS_HOT); | |
267 } else if (!highlighted && state_ != BS_DISABLED) { | |
268 SetState(BS_NORMAL); | |
269 } | |
270 } | |
271 | |
272 bool CustomButton::IsHighlighted() const { | |
273 return state_ == BS_HOT; | |
274 } | |
275 | |
276 bool CustomButton::IsPushed() const { | |
277 return state_ == BS_PUSHED; | |
278 } | |
279 | |
280 } // namespace views | 245 } // namespace views |
OLD | NEW |