Chromium Code Reviews| 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(); |
| +} |