Index: chrome/browser/ui/views/frame/app_non_client_frame_view_aura.cc |
diff --git a/chrome/browser/ui/views/frame/app_non_client_frame_view_aura.cc b/chrome/browser/ui/views/frame/app_non_client_frame_view_aura.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dc0b93970236276401a61da92809583c73f58d77 |
--- /dev/null |
+++ b/chrome/browser/ui/views/frame/app_non_client_frame_view_aura.cc |
@@ -0,0 +1,250 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ui/views/frame/app_non_client_frame_view_aura.h" |
+ |
+#include "base/debug/stack_trace.h" |
+#include "chrome/browser/ui/views/frame/browser_frame.h" |
+#include "chrome/browser/ui/views/frame/browser_view.h" |
+#include "grit/ui_resources.h" |
+#include "ui/aura/window.h" |
+#include "ui/base/animation/slide_animation.h" |
+#include "ui/base/hit_test.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/gfx/canvas.h" |
+#include "ui/gfx/compositor/layer.h" |
+#include "ui/gfx/image/image.h" |
+#include "ui/gfx/point.h" |
+#include "ui/gfx/rect.h" |
+#include "ui/gfx/size.h" |
+#include "ui/views/controls/button/image_button.h" |
+#include "ui/views/widget/widget.h" |
+#include "ui/views/window/non_client_view.h" |
+ |
+namespace { |
+// The number of pixels to use as a hover zone at the top of the screen. |
+const int kTopMargin = 1; |
+// How long the hover animation takes if uninterrupted. |
+const int kHoverFadeDurationMs = 250; |
sky
2012/02/09 01:04:17
This seems like a long time.
DaveMoore
2012/02/10 23:05:55
Cole sez 130ms.
On 2012/02/09 01:04:17, sky wrote:
|
+// The number of pixels within the shadow to draw the buttons. |
+const int kShadowStart = 28; |
+} |
+ |
+class AppNonClientFrameViewAura::ControlView |
+ : public views::View, public views::ButtonListener { |
+ public: |
+ explicit ControlView(AppNonClientFrameViewAura* owner) : |
+ owner_(owner), |
+ close_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_CLOSE)), |
+ restore_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_RESTORE)) { |
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
+ separator_ = rb.GetBitmapNamed(IDR_AURA_WINDOW_FULLSCREEN_SEPARATOR); |
sky
2012/02/09 01:04:17
Isn't GetBitmapNamed deprecated?
DaveMoore
2012/02/10 23:05:55
Done.
|
+ shadow_ = rb.GetBitmapNamed(IDR_AURA_WINDOW_FULLSCREEN_SHADOW); |
+ AddChildView(close_button_); |
+ AddChildView(restore_button_); |
+ } |
+ |
+ virtual void Layout() OVERRIDE { |
+ restore_button_->SetPosition(gfx::Point(kShadowStart, 0)); |
+ close_button_->SetPosition( |
+ gfx::Point(kShadowStart + close_button_->width() + separator_->width(), |
+ 0)); |
+ } |
+ |
+ virtual gfx::Size GetPreferredSize() OVERRIDE { |
+ return gfx::Size(shadow_->width(), shadow_->height()); |
+ } |
+ |
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { |
+ views::View::OnPaint(canvas); |
+ canvas->DrawBitmapInt( |
+ *separator_, restore_button_->x() + restore_button_->width(), 0); |
+ canvas->DrawBitmapInt(*shadow_, 0, 0); |
+ } |
+ |
+ void ButtonPressed( |
+ views::Button* sender, const views::Event& event) OVERRIDE { |
sky
2012/02/09 01:04:17
nit: each param on its own line.
DaveMoore
2012/02/10 23:05:55
Done.
|
+ if (sender == close_button_) |
+ owner_->Close(); |
+ else if (sender == restore_button_) |
+ owner_->Restore(); |
+ } |
+ |
+ private: |
+ // Gets an image representing 3 bitmaps laied out horizontally that will be |
sky
2012/02/09 01:04:17
laied -> laid
DaveMoore
2012/02/10 23:05:55
Done.
|
+ // used as the normal, hot and pushed states for the created button. |
+ views::ImageButton* CreateImageButton(int resource_id) { |
+ views::ImageButton* button = new views::ImageButton(this); |
+ const SkBitmap* all_images = |
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(resource_id); |
+ int width = all_images->width() / 3; |
+ int height = all_images->height(); |
+ |
+ SkBitmap normal, hot, pushed; |
+ all_images->extractSubset( |
sky
2012/02/09 01:04:17
This seems tedious. Is there a reason we're going
DaveMoore
2012/02/10 23:05:55
I like this approach more. It reduces the number o
|
+ &normal, |
+ SkIRect::MakeXYWH(0, 0, width, height)); |
+ all_images->extractSubset( |
+ &hot, |
+ SkIRect::MakeXYWH(width, 0, width, height)); |
+ all_images->extractSubset( |
+ &pushed, |
+ SkIRect::MakeXYWH(2 * width, 0, width, height)); |
+ button->SetImage(views::CustomButton::BS_NORMAL, &normal); |
+ button->SetImage(views::CustomButton::BS_HOT, &hot); |
+ button->SetImage(views::CustomButton::BS_PUSHED, &pushed); |
+ |
+ button->SizeToPreferredSize(); |
+ return button; |
+ } |
+ |
+ AppNonClientFrameViewAura* owner_; |
+ views::ImageButton* close_button_; |
+ views::ImageButton* restore_button_; |
+ const SkBitmap* separator_; |
sky
2012/02/09 01:04:17
Generally we prefer values for SkBitmap and not po
DaveMoore
2012/02/10 23:05:55
Done.
|
+ const SkBitmap* shadow_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ControlView); |
+}; |
+ |
+class AppNonClientFrameViewAura::Host : public views::MouseWatcherHost { |
+ public: |
+ explicit Host(AppNonClientFrameViewAura* owner) : owner_(owner) {} |
+ virtual ~Host() {} |
+ |
+ virtual bool Contains( |
+ const gfx::Point& screen_point, |
+ views::MouseWatcherHost::MouseEventType type) { |
+ gfx::Rect top_margin = owner_->GetScreenBounds(); |
+ top_margin.set_height(kTopMargin); |
+ gfx::Rect control_bounds = owner_->GetControlBounds(); |
+ control_bounds.Inset(kShadowStart, 0, 0, kShadowStart); |
+ bool ret = top_margin.Contains(screen_point) || |
sky
2012/02/09 01:04:17
Since you don't use this bool, just return the res
DaveMoore
2012/02/10 23:05:55
Done.
|
+ control_bounds.Contains(screen_point); |
+ return ret; |
+ } |
+ |
+ AppNonClientFrameViewAura* owner_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Host); |
+}; |
+ |
+AppNonClientFrameViewAura::AppNonClientFrameViewAura( |
+ BrowserFrame* frame, BrowserView* browser_view) |
+ : BrowserNonClientFrameView(frame, browser_view), |
+ control_view_(new ControlView(this)), |
+ control_widget_(NULL), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ show_animation_(new ui::SlideAnimation(this))), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ mouse_watcher_(new Host(this), this)) { |
+ show_animation_->SetSlideDuration(kHoverFadeDurationMs); |
+} |
+ |
+AppNonClientFrameViewAura::~AppNonClientFrameViewAura() { |
+ if (control_widget_) { |
+ control_widget_->Close(); |
+ } |
+} |
+gfx::Rect AppNonClientFrameViewAura::GetBoundsForClientView() const { |
+ gfx::Rect bounds = GetLocalBounds(); |
+ bounds.Inset(0, kTopMargin, 0, 0); |
+ return bounds; |
+} |
+ |
+gfx::Rect AppNonClientFrameViewAura::GetWindowBoundsForClientBounds( |
+ const gfx::Rect& client_bounds) const { |
+ gfx::Rect bounds = client_bounds; |
+ bounds.Inset(0, -kTopMargin, 0, 0); |
+ return bounds; |
+} |
+ |
+int AppNonClientFrameViewAura::NonClientHitTest( |
+ const gfx::Point& point) { |
+ return bounds().Contains(point) ? HTCLIENT : HTNOWHERE; |
+} |
+ |
+void AppNonClientFrameViewAura::GetWindowMask(const gfx::Size& size, |
+ gfx::Path* window_mask) { |
+} |
+ |
+void AppNonClientFrameViewAura::ResetWindowControls() { |
+} |
+ |
+void AppNonClientFrameViewAura::UpdateWindowIcon() { |
+} |
+ |
+gfx::Rect AppNonClientFrameViewAura::GetBoundsForTabStrip( |
+ views::View* tabstrip) const { |
+ return gfx::Rect(); |
+} |
+ |
+int AppNonClientFrameViewAura::GetHorizontalTabStripVerticalOffset( |
+ bool restored) const { |
+ return 0; |
+} |
+ |
+void AppNonClientFrameViewAura::UpdateThrobber(bool running) { |
+} |
+ |
+void AppNonClientFrameViewAura::OnMouseEntered( |
+ const views::MouseEvent& event) { |
+ if (show_animation_->IsShowing()) |
+ return; |
+ |
+ if (!control_widget_) { |
+ control_widget_ = new views::Widget; |
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); |
+ params.parent = browser_view()->GetNativeHandle(); |
+ params.transparent = true; |
+ control_widget_->Init(params); |
+ control_widget_->SetContentsView(control_view_); |
+ } |
+ gfx::Rect control_bounds = GetControlBounds(); |
+ control_bounds.set_y(control_bounds.y() - control_bounds.height()); |
+ control_widget_->SetBounds(control_bounds); |
+ control_widget_->Show(); |
+ show_animation_->Show(); |
+ mouse_watcher_.Start(); |
+} |
+ |
+void AppNonClientFrameViewAura::AnimationProgressed( |
+ const ui::Animation* animation) { |
+ if (animation == show_animation_.get()) { |
sky
2012/02/09 01:04:17
Did you try using the layer animation code? In the
DaveMoore
2012/02/10 23:05:55
I didn't, but this didn't seem very difficult. Are
sky
2012/02/13 16:01:32
It should be cleaner, and hopefully at some point
|
+ double value = show_animation_->GetCurrentValue(); |
+ gfx::Rect control_bounds = GetControlBounds(); |
+ int y = control_bounds.y() - (1.0 - value) * control_bounds.height(); |
+ control_bounds.set_y(y); |
+ control_widget_->GetNativeWindow()->layer()->SetOpacity(value); |
+ control_widget_->SetBounds(control_bounds); |
+ return; |
+ } |
+} |
+ |
+void AppNonClientFrameViewAura::MouseMovedOutOfHost() { |
+ show_animation_->Hide(); |
+} |
+ |
+gfx::Rect AppNonClientFrameViewAura::GetControlBounds() const { |
+ gfx::Size preferred = control_view_->GetPreferredSize(); |
+ gfx::Point location(width() - preferred.width(), 0); |
+ ConvertPointToWidget(this, &location); |
+ return gfx::Rect( |
+ location.x(), location.y(), |
+ preferred.width(), preferred.height()); |
+} |
+ |
+void AppNonClientFrameViewAura::Close() { |
+ control_widget_->Close(); |
sky
2012/02/09 01:04:17
I suspect explicitly closing the widget here and i
|
+ control_widget_ = NULL; |
+ mouse_watcher_.Stop(); |
+ frame()->Close(); |
+} |
+ |
+void AppNonClientFrameViewAura::Restore() { |
+ control_widget_->Close(); |
+ control_widget_ = NULL; |
+ mouse_watcher_.Stop(); |
+ frame()->Restore(); |
+} |