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

Unified 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: cleanup 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 side-by-side diff with in-line comments
Download patch
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();
+}

Powered by Google App Engine
This is Rietveld 408576698