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

Side by Side Diff: chrome/browser/ui/views/frame/app_non_client_frame_view_aura.cc

Issue 9359022: Aura: Support hovering restore & close buttons for full screen apps (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove resources, as they've already been committed Created 8 years, 10 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/browser/ui/views/frame/app_non_client_frame_view_aura.h"
6
7 #include "base/debug/stack_trace.h"
8 #include "chrome/browser/ui/views/frame/browser_frame.h"
9 #include "chrome/browser/ui/views/frame/browser_view.h"
10 #include "grit/ui_resources.h"
11 #include "ui/aura/window.h"
12 #include "ui/base/animation/slide_animation.h"
13 #include "ui/base/hit_test.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/compositor/layer.h"
17 #include "ui/gfx/image/image.h"
18 #include "ui/gfx/point.h"
19 #include "ui/gfx/rect.h"
20 #include "ui/gfx/size.h"
21 #include "ui/views/controls/button/image_button.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/window/non_client_view.h"
24
25 namespace {
26 // The number of pixels to use as a hover zone at the top of the screen.
27 const int kTopMargin = 1;
28 // How long the hover animation takes if uninterrupted.
29 const int kHoverFadeDurationMs = 130;
30 // The number of pixels within the shadow to draw the buttons.
31 const int kShadowStart = 28;
32 }
33
34 class AppNonClientFrameViewAura::ControlView
35 : public views::View, public views::ButtonListener {
36 public:
37 explicit ControlView(AppNonClientFrameViewAura* owner) :
38 owner_(owner),
39 close_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_CLOSE)),
40 restore_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_RESTORE)) {
41 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
42 separator_ =
43 *rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SEPARATOR).ToSkBitmap();
44 shadow_ = *rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SHADOW).ToSkBitmap();
45 AddChildView(close_button_);
46 AddChildView(restore_button_);
47 }
48
49 virtual void Layout() OVERRIDE {
50 restore_button_->SetPosition(gfx::Point(kShadowStart, 0));
51 close_button_->SetPosition(
52 gfx::Point(kShadowStart + close_button_->width() + separator_.width(),
53 0));
54 }
55
56 virtual gfx::Size GetPreferredSize() OVERRIDE {
57 return gfx::Size(shadow_.width(), shadow_.height());
58 }
59
60 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
61 views::View::OnPaint(canvas);
62 canvas->DrawBitmapInt(
63 separator_, restore_button_->x() + restore_button_->width(), 0);
64 canvas->DrawBitmapInt(shadow_, 0, 0);
65 }
66
67 void ButtonPressed(
68 views::Button* sender,
69 const views::Event& event) OVERRIDE {
70 if (sender == close_button_)
71 owner_->Close();
72 else if (sender == restore_button_)
73 owner_->Restore();
74 }
75
76 private:
77 // Gets an image representing 3 bitmaps laid out horizontally that will be
78 // used as the normal, hot and pushed states for the created button.
79 views::ImageButton* CreateImageButton(int resource_id) {
80 views::ImageButton* button = new views::ImageButton(this);
81 const SkBitmap* all_images =
82 ResourceBundle::GetSharedInstance().GetImageNamed(
83 resource_id).ToSkBitmap();
84 int width = all_images->width() / 3;
85 int height = all_images->height();
86
87 SkBitmap normal, hot, pushed;
88 all_images->extractSubset(
89 &normal,
90 SkIRect::MakeXYWH(0, 0, width, height));
91 all_images->extractSubset(
92 &hot,
93 SkIRect::MakeXYWH(width, 0, width, height));
94 all_images->extractSubset(
95 &pushed,
96 SkIRect::MakeXYWH(2 * width, 0, width, height));
97 button->SetImage(views::CustomButton::BS_NORMAL, &normal);
98 button->SetImage(views::CustomButton::BS_HOT, &hot);
99 button->SetImage(views::CustomButton::BS_PUSHED, &pushed);
100
101 button->SizeToPreferredSize();
102 return button;
103 }
104
105 AppNonClientFrameViewAura* owner_;
106 views::ImageButton* close_button_;
107 views::ImageButton* restore_button_;
108 SkBitmap separator_;
109 SkBitmap shadow_;
110
111 DISALLOW_COPY_AND_ASSIGN(ControlView);
112 };
113
114 class AppNonClientFrameViewAura::Host : public views::MouseWatcherHost {
115 public:
116 explicit Host(AppNonClientFrameViewAura* owner) : owner_(owner) {}
117 virtual ~Host() {}
118
119 virtual bool Contains(
120 const gfx::Point& screen_point,
121 views::MouseWatcherHost::MouseEventType type) {
122 gfx::Rect top_margin = owner_->GetScreenBounds();
123 top_margin.set_height(kTopMargin);
124 gfx::Rect control_bounds = owner_->GetControlBounds();
125 control_bounds.Inset(kShadowStart, 0, 0, kShadowStart);
126 return top_margin.Contains(screen_point) ||
127 control_bounds.Contains(screen_point);
128 }
129
130 AppNonClientFrameViewAura* owner_;
131
132 DISALLOW_COPY_AND_ASSIGN(Host);
133 };
134
135 AppNonClientFrameViewAura::AppNonClientFrameViewAura(
136 BrowserFrame* frame, BrowserView* browser_view)
137 : BrowserNonClientFrameView(frame, browser_view),
138 control_view_(new ControlView(this)),
139 control_widget_(NULL),
140 ALLOW_THIS_IN_INITIALIZER_LIST(
141 show_animation_(new ui::SlideAnimation(this))),
142 ALLOW_THIS_IN_INITIALIZER_LIST(
143 mouse_watcher_(new Host(this), this)) {
144 show_animation_->SetSlideDuration(kHoverFadeDurationMs);
145 }
146
147 AppNonClientFrameViewAura::~AppNonClientFrameViewAura() {
148 if (control_widget_) {
149 control_widget_->Close();
150 }
151 }
152 gfx::Rect AppNonClientFrameViewAura::GetBoundsForClientView() const {
153 gfx::Rect bounds = GetLocalBounds();
154 bounds.Inset(0, kTopMargin, 0, 0);
155 return bounds;
156 }
157
158 gfx::Rect AppNonClientFrameViewAura::GetWindowBoundsForClientBounds(
159 const gfx::Rect& client_bounds) const {
160 gfx::Rect bounds = client_bounds;
161 bounds.Inset(0, -kTopMargin, 0, 0);
162 return bounds;
163 }
164
165 int AppNonClientFrameViewAura::NonClientHitTest(
166 const gfx::Point& point) {
167 return bounds().Contains(point) ? HTCLIENT : HTNOWHERE;
168 }
169
170 void AppNonClientFrameViewAura::GetWindowMask(const gfx::Size& size,
171 gfx::Path* window_mask) {
172 }
173
174 void AppNonClientFrameViewAura::ResetWindowControls() {
175 }
176
177 void AppNonClientFrameViewAura::UpdateWindowIcon() {
178 }
179
180 gfx::Rect AppNonClientFrameViewAura::GetBoundsForTabStrip(
181 views::View* tabstrip) const {
182 return gfx::Rect();
183 }
184
185 int AppNonClientFrameViewAura::GetHorizontalTabStripVerticalOffset(
186 bool restored) const {
187 return 0;
188 }
189
190 void AppNonClientFrameViewAura::UpdateThrobber(bool running) {
191 }
192
193 void AppNonClientFrameViewAura::OnMouseEntered(
194 const views::MouseEvent& event) {
195 if (show_animation_->IsShowing())
196 return;
197
198 if (!control_widget_) {
199 control_widget_ = new views::Widget;
200 views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
201 params.parent = browser_view()->GetNativeHandle();
202 params.transparent = true;
203 control_widget_->Init(params);
204 control_widget_->SetContentsView(control_view_);
205 }
206 gfx::Rect control_bounds = GetControlBounds();
207 control_bounds.set_y(control_bounds.y() - control_bounds.height());
208 control_widget_->SetBounds(control_bounds);
209 control_widget_->Show();
210 show_animation_->Show();
211 mouse_watcher_.Start();
212 }
213
214 void AppNonClientFrameViewAura::AnimationProgressed(
215 const ui::Animation* animation) {
216 if (animation == show_animation_.get()) {
217 double value = show_animation_->GetCurrentValue();
218 gfx::Rect control_bounds = GetControlBounds();
219 int y = control_bounds.y() - (1.0 - value) * control_bounds.height();
220 control_bounds.set_y(y);
221 control_widget_->GetNativeWindow()->layer()->SetOpacity(value);
222 control_widget_->SetBounds(control_bounds);
223 return;
224 }
225 }
226
227 void AppNonClientFrameViewAura::MouseMovedOutOfHost() {
228 show_animation_->Hide();
229 }
230
231 gfx::Rect AppNonClientFrameViewAura::GetControlBounds() const {
232 gfx::Size preferred = control_view_->GetPreferredSize();
233 gfx::Point location(width() - preferred.width(), 0);
234 ConvertPointToWidget(this, &location);
235 return gfx::Rect(
236 location.x(), location.y(),
237 preferred.width(), preferred.height());
238 }
239
240 void AppNonClientFrameViewAura::Close() {
241 control_widget_->Close();
242 control_widget_ = NULL;
243 mouse_watcher_.Stop();
244 frame()->Close();
245 }
246
247 void AppNonClientFrameViewAura::Restore() {
248 control_widget_->Close();
249 control_widget_ = NULL;
250 mouse_watcher_.Stop();
251 frame()->Restore();
252 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698