OLD | NEW |
| (Empty) |
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 #include "ash/wm/workspace/alternate_frame_caption_button.h" | |
6 | |
7 #include "ui/base/animation/slide_animation.h" | |
8 #include "ui/gfx/canvas.h" | |
9 | |
10 namespace ash { | |
11 | |
12 namespace { | |
13 | |
14 // The width and height of the region of the button which does not overlap | |
15 // with other buttons. | |
16 const int kSize = 32; | |
17 | |
18 // A bubble is painted in the background when the mouse button is pressed. | |
19 // When the button is pressed: | |
20 // - The bubble is faded in from opacity 0 to |kShownBubbleOpacity|. | |
21 // - The bubble is expanded from |kInitialGrowBubbleRadius| to | |
22 // |kFullyGrownBubbleRadius|. | |
23 // When the button is unpressed (STATE_NORMAL) | |
24 // - The bubble is faded out from its current opacity back to 0. | |
25 // - The bubble is further expanded from its current radius to | |
26 // |kFinalBurstBubbleRadius|. | |
27 const int kInitialGrowBubbleRadius = 16; | |
28 const int kFullyGrownBubbleRadius = 22; | |
29 const int kFinalBurstBubbleRadius = 26; | |
30 const int kShownBubbleOpacity = 100; | |
31 | |
32 // The duraton of the animations for hiding and showing the bubble. | |
33 const int kBubbleAnimationDuration = 100; | |
34 | |
35 // TODO(pkotwicz): Replace these colors with colors from UX. | |
36 const SkColor kPathColor = SK_ColorDKGRAY; | |
37 const SkColor kPressedHoveredPathColor = SK_ColorBLACK; | |
38 const SkColor kBubbleColor = SK_ColorWHITE; | |
39 | |
40 struct Line { | |
41 int x1, y1, x2, y2; | |
42 }; | |
43 | |
44 // Line segments for the button icons. The line segments are painted in a 12x12 | |
45 // centered box. | |
46 const Line kMinimizeLineSegments[] = { | |
47 {1, 11, 11, 11} | |
48 }; | |
49 const Line kMaximizeRestoreLineSegments[] = { | |
50 {1, 1, 11, 1}, | |
51 {11, 1, 11, 11}, | |
52 {11, 11, 1, 11}, | |
53 {1, 11, 1, 1} | |
54 }; | |
55 const Line kCloseLineSegments[] = { | |
56 {1, 1, 11, 11}, | |
57 {1, 11, 11, 1} | |
58 }; | |
59 | |
60 // The amount that the origin of the icon's 12x12 box should be offset from the | |
61 // center of the button. | |
62 const int kIconOffsetFromCenter = -6; | |
63 | |
64 // Sets |line_segments| to the line segments for the icon for |action|. | |
65 void GetLineSegmentsForAction(AlternateFrameCaptionButton::Action action, | |
66 const Line** line_segments, | |
67 size_t* num_line_segments) { | |
68 switch(action) { | |
69 case AlternateFrameCaptionButton::ACTION_MINIMIZE: | |
70 *line_segments = kMinimizeLineSegments; | |
71 *num_line_segments = arraysize(kMinimizeLineSegments); | |
72 break; | |
73 case AlternateFrameCaptionButton::ACTION_MAXIMIZE_RESTORE: | |
74 *line_segments = kMaximizeRestoreLineSegments; | |
75 *num_line_segments = arraysize(kMaximizeRestoreLineSegments); | |
76 break; | |
77 case AlternateFrameCaptionButton::ACTION_CLOSE: | |
78 *line_segments = kCloseLineSegments; | |
79 *num_line_segments = arraysize(kCloseLineSegments); | |
80 break; | |
81 default: | |
82 NOTREACHED(); | |
83 break; | |
84 } | |
85 } | |
86 | |
87 } // namespace | |
88 | |
89 const char AlternateFrameCaptionButton::kViewClassName[] = | |
90 "AlternateFrameCaptionButton"; | |
91 | |
92 AlternateFrameCaptionButton::AlternateFrameCaptionButton( | |
93 views::ButtonListener* listener, | |
94 Action action) | |
95 : views::CustomButton(listener), | |
96 action_(action), | |
97 hidden_bubble_radius_(0), | |
98 shown_bubble_radius_(0), | |
99 bubble_animation_(new ui::SlideAnimation(this)) { | |
100 } | |
101 | |
102 AlternateFrameCaptionButton::~AlternateFrameCaptionButton() { | |
103 } | |
104 | |
105 // static | |
106 int AlternateFrameCaptionButton::GetXOverlap() { | |
107 return kFinalBurstBubbleRadius - kSize / 2; | |
108 } | |
109 | |
110 gfx::Size AlternateFrameCaptionButton::GetPreferredSize() { | |
111 gfx::Insets insets(GetInsets()); | |
112 return gfx::Size( | |
113 std::max(kFinalBurstBubbleRadius * 2, kSize + insets.width()), | |
114 kSize + insets.height()); | |
115 } | |
116 | |
117 const char* AlternateFrameCaptionButton::GetClassName() const { | |
118 return kViewClassName; | |
119 } | |
120 | |
121 bool AlternateFrameCaptionButton::HitTestRect(const gfx::Rect& rect) const { | |
122 gfx::Rect bounds(GetLocalBounds()); | |
123 if (state_ == STATE_PRESSED) | |
124 return bounds.Intersects(rect); | |
125 | |
126 int x_overlap = GetXOverlap(); | |
127 bounds.set_x(x_overlap); | |
128 bounds.set_width(width() - x_overlap * 2); | |
129 return bounds.Intersects(rect); | |
130 } | |
131 | |
132 void AlternateFrameCaptionButton::OnPaint(gfx::Canvas* canvas) { | |
133 gfx::Point content_bounds_center(GetContentsBounds().CenterPoint()); | |
134 | |
135 int bubble_alpha = bubble_animation_->CurrentValueBetween( | |
136 0, kShownBubbleOpacity); | |
137 if (bubble_alpha != 0) { | |
138 int bubble_radius = bubble_animation_->CurrentValueBetween( | |
139 hidden_bubble_radius_, shown_bubble_radius_); | |
140 | |
141 SkPaint paint; | |
142 paint.setAntiAlias(true); | |
143 paint.setStyle(SkPaint::kFill_Style); | |
144 paint.setColor(SkColorSetA(kBubbleColor, bubble_alpha)); | |
145 canvas->DrawCircle(content_bounds_center, bubble_radius, paint); | |
146 } | |
147 | |
148 SkColor color = kPathColor; | |
149 if (state_ == STATE_HOVERED || state_ == STATE_PRESSED) | |
150 color = kPressedHoveredPathColor; | |
151 | |
152 const Line* line_segments = NULL; | |
153 size_t num_line_segments = 0; | |
154 GetLineSegmentsForAction(action_, &line_segments, &num_line_segments); | |
155 | |
156 gfx::Vector2d top_left_offset( | |
157 content_bounds_center.x() + kIconOffsetFromCenter, | |
158 content_bounds_center.y() + kIconOffsetFromCenter); | |
159 canvas->Translate(top_left_offset); | |
160 SkPaint paint; | |
161 paint.setStyle(SkPaint::kStroke_Style); | |
162 paint.setStrokeWidth(SkIntToScalar(2)); | |
163 paint.setStrokeCap(SkPaint::kSquare_Cap); | |
164 paint.setColor(color); | |
165 for (size_t i = 0; i < num_line_segments; ++i) { | |
166 canvas->DrawLine(gfx::Point(line_segments[i].x1, line_segments[i].y1), | |
167 gfx::Point(line_segments[i].x2, line_segments[i].y2), | |
168 paint); | |
169 } | |
170 canvas->Translate(-top_left_offset); | |
171 } | |
172 | |
173 void AlternateFrameCaptionButton::MaybeStartNewBubbleAnimation() { | |
174 bool should_show = (state_ == STATE_PRESSED); | |
175 if (should_show == bubble_animation_->IsShowing()) | |
176 return; | |
177 | |
178 if (!bubble_animation_->is_animating()) { | |
179 if (should_show) | |
180 hidden_bubble_radius_ = kInitialGrowBubbleRadius; | |
181 else | |
182 hidden_bubble_radius_ = kFinalBurstBubbleRadius; | |
183 shown_bubble_radius_ = kFullyGrownBubbleRadius; | |
184 | |
185 bubble_animation_->SetSlideDuration(kBubbleAnimationDuration); | |
186 if (should_show) | |
187 bubble_animation_->Show(); | |
188 else | |
189 bubble_animation_->Hide(); | |
190 } else { | |
191 if (!should_show) { | |
192 // The change in radius during a hide animation if there was no currently | |
193 // running animation. | |
194 int normal_radius_change = | |
195 kFinalBurstBubbleRadius - kFullyGrownBubbleRadius; | |
196 | |
197 // Start a fade out animation from the bubble's current radius and | |
198 // opacity. Update the bubble radius and opacity at the same rate that it | |
199 // gets updated during a normal hide animation. | |
200 int current_bubble_radius = bubble_animation_->CurrentValueBetween( | |
201 kInitialGrowBubbleRadius, kFullyGrownBubbleRadius); | |
202 hidden_bubble_radius_ = current_bubble_radius + | |
203 bubble_animation_->GetCurrentValue() * normal_radius_change; | |
204 shown_bubble_radius_ = hidden_bubble_radius_ - normal_radius_change; | |
205 bubble_animation_->SetSlideDuration( | |
206 bubble_animation_->GetCurrentValue() * kBubbleAnimationDuration); | |
207 bubble_animation_->Hide(); | |
208 } | |
209 // Else: The bubble is currently fading out. Wait till the hide animation | |
210 // completes before starting an animation to show a new bubble. | |
211 } | |
212 } | |
213 | |
214 void AlternateFrameCaptionButton::StateChanged() { | |
215 MaybeStartNewBubbleAnimation(); | |
216 } | |
217 | |
218 void AlternateFrameCaptionButton::AnimationProgressed( | |
219 const ui::Animation* animation) { | |
220 SchedulePaint(); | |
221 } | |
222 | |
223 void AlternateFrameCaptionButton::AnimationEnded( | |
224 const ui::Animation* animation) { | |
225 // The bubble animation was postponed if the button became pressed when the | |
226 // bubble was fading out. Do the animation now. | |
227 MaybeStartNewBubbleAnimation(); | |
228 } | |
229 | |
230 } // namespace ash | |
OLD | NEW |