Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: ui/aura_shell/toplevel_frame_view.cc

Issue 7977012: Adds a NonClientFrameView for generic toplevel windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "ui/aura_shell/toplevel_frame_view.h"
6
7 #include "grit/ui_resources.h"
8 #include "ui/base/animation/throb_animation.h"
9 #include "ui/base/resource/resource_bundle.h"
10 #include "ui/gfx/canvas.h"
11 #include "views/controls/button/custom_button.h"
12 #include "views/widget/widget.h"
13 #include "views/widget/widget_delegate.h"
14
15 #if !defined(OS_WIN)
16 #include "views/window/hit_test.h"
17 #endif
18
19 namespace aura_shell {
20 namespace internal {
21
22 namespace {
23 // The thickness of the left, right and bottom edges of the frame.
24 const int kFrameBorderThickness = 8;
25 const int kFrameOpacity = 50;
26 // The color used to fill the frame.
27 const SkColor kFrameColor = SkColorSetARGB(kFrameOpacity, 0, 0, 0);
28 const int kFrameBorderHiddenOpacity = 0;
29 const int kFrameBorderVisibleOpacity = kFrameOpacity;
30 // How long the hover animation takes if uninterrupted.
31 const int kHoverFadeDurationMs = 250;
32 } // namespace
33
34 class WindowControlButton : public views::CustomButton {
sky 2011/09/22 18:06:19 Add a description.
35 public:
36 WindowControlButton(views::ButtonListener* listener,
37 SkColor color,
38 SkBitmap icon)
sky 2011/09/22 18:06:19 const SkBitmap&
39 : views::CustomButton(listener),
40 color_(color),
41 icon_(icon) {
42 }
43 virtual ~WindowControlButton() {}
44
45 // Overridden from views::View:
46 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
47 canvas->FillRectInt(GetBackgroundColor(), 0, 0, width(), height());
48 canvas->DrawBitmapInt(icon_, 0, 0);
49 }
50 virtual gfx::Size GetPreferredSize() OVERRIDE {
51 gfx::Size size(icon_.width(), icon_.height());
52 size.Enlarge(3, 2);
53 return size;
54 }
55
56 private:
57 SkColor GetBackgroundColor() {
58 return SkColorSetARGB(hover_animation_->CurrentValueBetween(0, 150),
59 SkColorGetR(color_),
60 SkColorGetG(color_),
61 SkColorGetB(color_));
62 }
63
64 SkColor color_;
65 SkBitmap icon_;
66
67 DISALLOW_COPY_AND_ASSIGN(WindowControlButton);
68 };
69
70 class SizingBorder : public views::View,
71 public ui::AnimationDelegate {
72 public:
73 SizingBorder()
74 : ALLOW_THIS_IN_INITIALIZER_LIST(
75 animation_(new ui::SlideAnimation(this))) {
76 animation_->SetSlideDuration(kHoverFadeDurationMs);
77 }
78 virtual ~SizingBorder() {}
79
80 void Configure(const gfx::Rect& hidden_bounds,
81 const gfx::Rect& visible_bounds) {
82 hidden_bounds_ = hidden_bounds;
83 visible_bounds_ = visible_bounds;
84 SetBoundsRect(hidden_bounds_);
85 }
86
87 void Show() {
88 animation_->Show();
89 }
90
91 void Hide() {
92 animation_->Hide();
93 }
94
95 bool IsShowing() const {
96 return animation_->IsShowing();
97 }
98
99 bool IsHiding() const {
100 return animation_->IsClosing();
101 }
102
103 private:
104 // Overridden from views::View:
105 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
106 // Fill with current opacity value.
107 int opacity = animation_->CurrentValueBetween(kFrameBorderHiddenOpacity,
108 kFrameBorderVisibleOpacity);
109 canvas->FillRectInt(SkColorSetARGB(opacity,
110 SkColorGetR(kFrameColor),
111 SkColorGetG(kFrameColor),
112 SkColorGetB(kFrameColor)),
113 0, 0, width(), height());
114 }
115
116 // Overridden from ui::AnimationDelegate:
117 void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
118 // TODO: update bounds.
119 gfx::Rect current_bounds = animation_->CurrentValueBetween(hidden_bounds_,
120 visible_bounds_);
121 SetBoundsRect(current_bounds);
122 SchedulePaint();
123 }
124
125 // Each of these represents the hidden/visible states of the sizing border.
126 // When the view is shown or hidden it animates between them.
127 gfx::Rect hidden_bounds_;
128 gfx::Rect visible_bounds_;
129
130 scoped_ptr<ui::SlideAnimation> animation_;
131
132 DISALLOW_COPY_AND_ASSIGN(SizingBorder);
133 };
134
135 ////////////////////////////////////////////////////////////////////////////////
136 // ToplevelFrameView, public:
137
138 ToplevelFrameView::ToplevelFrameView()
139 : current_hittest_code_(HTNOWHERE),
140 left_edge_(new SizingBorder),
141 right_edge_(new SizingBorder),
142 bottom_edge_(new SizingBorder) {
143 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
144 close_button_ =
145 new WindowControlButton(this, SK_ColorRED,
146 *rb.GetBitmapNamed(IDR_AURA_WINDOW_CLOSE_ICON));
147 zoom_button_ =
148 new WindowControlButton(this, SK_ColorGREEN,
149 *rb.GetBitmapNamed(IDR_AURA_WINDOW_ZOOM_ICON));
150 AddChildView(close_button_);
151 AddChildView(zoom_button_);
152
153 AddChildView(left_edge_);
154 AddChildView(right_edge_);
155 AddChildView(bottom_edge_);
156 }
157
158 ToplevelFrameView::~ToplevelFrameView() {
159 }
160
161 ////////////////////////////////////////////////////////////////////////////////
162 // ToplevelFrameView, private:
163
164 int ToplevelFrameView::NonClientBorderThickness() const {
165 return kFrameBorderThickness;
166 }
167
168 int ToplevelFrameView::NonClientTopBorderHeight() const {
169 return close_button_->GetPreferredSize().height();
170 }
171
172 int ToplevelFrameView::NonClientHitTestImpl(const gfx::Point& point) {
173 // Sanity check.
174 if (!GetLocalBounds().Contains(point))
175 return HTNOWHERE;
176
177 // The client view gets first crack at claiming the point.
178 int frame_component = GetWidget()->client_view()->NonClientHitTest(point);
179 if (frame_component != HTNOWHERE)
180 return frame_component;
181
182 // The window controls come second.
183 if (close_button_->GetMirroredBounds().Contains(point))
184 return HTCLOSE;
185 else if (zoom_button_->GetMirroredBounds().Contains(point))
186 return HTMAXBUTTON;
187
188 // Finally other portions of the frame/sizing border.
189 frame_component =
190 GetHTComponentForFrame(point,
191 NonClientBorderThickness(),
192 NonClientBorderThickness(),
193 NonClientBorderThickness(),
194 NonClientBorderThickness(),
195 GetWidget()->widget_delegate()->CanResize());
196
197 // Coerce HTCAPTION as a fallback.
198 return frame_component == HTNOWHERE ? HTCAPTION : frame_component;
199 }
200
201 void ToplevelFrameView::ShowSizingBorder(SizingBorder* sizing_border) {
202 if (sizing_border && !sizing_border->IsShowing())
203 sizing_border->Show();
204 if (left_edge_ != sizing_border && !left_edge_->IsHiding())
205 left_edge_->Hide();
206 if (right_edge_ != sizing_border && !right_edge_->IsHiding())
207 right_edge_->Hide();
208 if (bottom_edge_ != sizing_border && !bottom_edge_->IsHiding())
209 bottom_edge_->Hide();
210 }
211
212 bool ToplevelFrameView::PointIsInChildView(views::View* child,
213 const gfx::Point& point) const {
214 gfx::Point child_point(point);
215 ConvertPointToView(this, child, &child_point);
216 return child->HitTest(child_point);
217 }
218
219 gfx::Rect ToplevelFrameView::GetHiddenBoundsForSizingBorder(
220 int frame_component) const {
221 int border_size = NonClientBorderThickness();
222 int caption_height = NonClientTopBorderHeight();
223 switch (frame_component) {
224 case HTLEFT:
225 return gfx::Rect(border_size, caption_height, border_size,
226 height() - border_size - caption_height);
227 case HTBOTTOM:
228 return gfx::Rect(border_size, height() - 2 * border_size,
229 width() - 2 * border_size, border_size);
230 case HTRIGHT:
231 return gfx::Rect(width() - 2 * border_size, caption_height, border_size,
232 height() - border_size - caption_height);
233 default:
234 break;
235 }
236 return gfx::Rect();
237 }
238
239 gfx::Rect ToplevelFrameView::GetVisibleBoundsForSizingBorder(
240 int frame_component) const {
241 int border_size = NonClientBorderThickness();
242 int caption_height = NonClientTopBorderHeight();
243 switch (frame_component) {
244 case HTLEFT:
245 return gfx::Rect(0, caption_height, border_size,
246 height() - border_size - caption_height);
247 case HTBOTTOM:
248 return gfx::Rect(border_size, height() - border_size,
249 width() - 2 * border_size, border_size);
250 case HTRIGHT:
251 return gfx::Rect(width() - border_size, caption_height, border_size,
252 height() - border_size - caption_height);
253 default:
254 break;
255 }
256 return gfx::Rect();
257 }
258
259 ////////////////////////////////////////////////////////////////////////////////
260 // ToplevelFrameView, views::NonClientFrameView overrides:
261
262 gfx::Rect ToplevelFrameView::GetBoundsForClientView() const {
263 return client_view_bounds_;
264 }
265
266 gfx::Rect ToplevelFrameView::GetWindowBoundsForClientBounds(
267 const gfx::Rect& client_bounds) const {
268 gfx::Rect window_bounds = client_bounds;
269 window_bounds.Inset(-NonClientBorderThickness(),
270 -NonClientTopBorderHeight(),
271 -NonClientBorderThickness(),
272 -NonClientBorderThickness());
273 return window_bounds;
274 }
275
276 int ToplevelFrameView::NonClientHitTest(const gfx::Point& point) {
277 int old_hittest_code = current_hittest_code_;
278 current_hittest_code_ = NonClientHitTestImpl(point);
279 return current_hittest_code_;
280 }
281
282 void ToplevelFrameView::GetWindowMask(const gfx::Size& size,
283 gfx::Path* window_mask) {
284 // Nothing.
285 }
286
287 void ToplevelFrameView::EnableClose(bool enable) {
288 close_button_->SetEnabled(enable);
289 }
290
291 void ToplevelFrameView::ResetWindowControls() {
292 NOTIMPLEMENTED();
293 }
294
295 void ToplevelFrameView::UpdateWindowIcon() {
296 NOTIMPLEMENTED();
297 }
298
299 ////////////////////////////////////////////////////////////////////////////////
300 // ToplevelFrameView, views::View overrides:
301
302 void ToplevelFrameView::Layout() {
303 client_view_bounds_ = GetLocalBounds();
304 client_view_bounds_.Inset(NonClientBorderThickness(),
305 NonClientTopBorderHeight(),
306 NonClientBorderThickness(),
307 NonClientBorderThickness());
308
309 gfx::Size close_button_ps = close_button_->GetPreferredSize();
310 close_button_->SetBoundsRect(
311 gfx::Rect(width() - close_button_ps.width() - NonClientBorderThickness(),
312 0, close_button_ps.width(), close_button_ps.height()));
313
314 gfx::Size zoom_button_ps = zoom_button_->GetPreferredSize();
315 zoom_button_->SetBoundsRect(
316 gfx::Rect(close_button_->x() - zoom_button_ps.width(), 0,
317 zoom_button_ps.width(), zoom_button_ps.height()));
318
319 left_edge_->Configure(GetHiddenBoundsForSizingBorder(HTLEFT),
320 GetVisibleBoundsForSizingBorder(HTLEFT));
321 right_edge_->Configure(GetHiddenBoundsForSizingBorder(HTRIGHT),
322 GetVisibleBoundsForSizingBorder(HTRIGHT));
323 bottom_edge_->Configure(GetHiddenBoundsForSizingBorder(HTBOTTOM),
324 GetVisibleBoundsForSizingBorder(HTBOTTOM));
325 }
326
327 void ToplevelFrameView::OnPaint(gfx::Canvas* canvas) {
328 gfx::Rect caption_rect(NonClientBorderThickness(), 0,
329 width() - 2 * NonClientBorderThickness(),
330 NonClientTopBorderHeight());
331 canvas->FillRectInt(kFrameColor, caption_rect.x(), caption_rect.y(),
332 caption_rect.width(), caption_rect.height());
333 }
334
335 void ToplevelFrameView::OnMouseMoved(const views::MouseEvent& event) {
336 switch (current_hittest_code_) {
337 case HTLEFT:
338 ShowSizingBorder(left_edge_);
339 break;
340 case HTRIGHT:
341 ShowSizingBorder(right_edge_);
342 break;
343 case HTBOTTOM:
344 ShowSizingBorder(bottom_edge_);
345 break;
346 default:
347 break;
348 }
349 }
350
351 void ToplevelFrameView::OnMouseExited(const views::MouseEvent& event) {
352 ShowSizingBorder(NULL);
353 }
354
355 views::View* ToplevelFrameView::GetEventHandlerForPoint(
356 const gfx::Point& point) {
357 if (PointIsInChildView(left_edge_, point) ||
358 PointIsInChildView(right_edge_, point) ||
359 PointIsInChildView(bottom_edge_, point)) {
360 return this;
361 }
362 return View::GetEventHandlerForPoint(point);
363 }
364
365
366 ////////////////////////////////////////////////////////////////////////////////
367 // ToplevelFrameView, views::ButtonListener implementation:
368
369 void ToplevelFrameView::ButtonPressed(views::Button* sender,
370 const views::Event& event) {
371 if (sender == close_button_) {
372 GetWidget()->Close();
373 } else if (sender == zoom_button_) {
374 if (GetWidget()->IsMaximized())
375 GetWidget()->Restore();
376 else
377 GetWidget()->Maximize();
378 }
379 }
380
381 } // namespace internal
382 } // namespace aura_shell
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698