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

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

Powered by Google App Engine
This is Rietveld 408576698