diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-16 22:30:48 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-16 22:30:48 +0000 |
commit | b0fcb0e709bc2731e6e71fbee0eb31b8a1ba7213 (patch) | |
tree | 091b318d966de6961cca373b1aef6dc79e1301bd /ash/wm | |
parent | 6f98f122e37c62262d9547a91d28b1bbaa6b90d2 (diff) | |
download | chromium_src-b0fcb0e709bc2731e6e71fbee0eb31b8a1ba7213.zip chromium_src-b0fcb0e709bc2731e6e71fbee0eb31b8a1ba7213.tar.gz chromium_src-b0fcb0e709bc2731e6e71fbee0eb31b8a1ba7213.tar.bz2 |
Ash: Add resize border shadow effect
* Add ResizeShadow that uses solid-color layers to draw the resize border shadow effect.
* Add ResizeShadowController to create ResizeShadows and track bounds changes for windows.
* Wire both into ToplevelWindowEventFilter to track mouse move/enter events near (but not inside) the window frame.
BUG=118325
TEST=visual, hover mouse near window edges, drag windows
Review URL: https://chromiumcodereview.appspot.com/9677070
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127268 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/wm')
-rw-r--r-- | ash/wm/resize_shadow.cc | 171 | ||||
-rw-r--r-- | ash/wm/resize_shadow.h | 80 | ||||
-rw-r--r-- | ash/wm/resize_shadow_controller.cc | 67 | ||||
-rw-r--r-- | ash/wm/resize_shadow_controller.h | 61 | ||||
-rw-r--r-- | ash/wm/root_window_event_filter.cc | 2 | ||||
-rw-r--r-- | ash/wm/shadow_controller.cc | 1 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_filter.cc | 32 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_filter.h | 8 |
8 files changed, 419 insertions, 3 deletions
diff --git a/ash/wm/resize_shadow.cc b/ash/wm/resize_shadow.cc new file mode 100644 index 0000000..983fdfb --- /dev/null +++ b/ash/wm/resize_shadow.cc @@ -0,0 +1,171 @@ +// 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 "ash/wm/resize_shadow.h" + +#include "grit/ui_resources.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/aura/window.h" +#include "ui/base/animation/slide_animation.h" +#include "ui/base/hit_test.h" +#include "ui/gfx/compositor/layer.h" +#include "ui/gfx/compositor/scoped_layer_animation_settings.h" + +namespace { + +// Height or width for the resize border shadow. +const int kShadowSize = 6; +// Amount to inset the resize effect from the window corners. +const int kShadowInset = 4; +// Color for resize effect. +const SkColor kShadowLayerColor = SkColorSetRGB(0, 0, 0); +// Final opacity for resize effect. +const int kShadowTargetOpacity = 64; +// Animation time for resize effect in milliseconds. +const int kShadowSlideDurationMs = 200; + +} // namespace + +namespace ash { +namespace internal { + +ResizeShadow::ResizeShadow() {} + +ResizeShadow::~ResizeShadow() {} + +void ResizeShadow::Init(aura::Window* window) { + ui::Layer* parent = window->layer(); + InitLayer(parent, &top_layer_); + InitLayer(parent, &left_layer_); + InitLayer(parent, &right_layer_); + InitLayer(parent, &bottom_layer_); + InitAnimation(&top_animation_); + InitAnimation(&left_animation_); + InitAnimation(&right_animation_); + InitAnimation(&bottom_animation_); +} + +void ResizeShadow::ShowForHitTest(int hit_test) { + // TODO(jamescook): Add support for top_left, top_right, bottom_left, and + // bottom_right corners. This approach matches the mocks but looks a little + // funny. + bool top = false; + bool left = false; + bool right = false; + bool bottom = false; + switch (hit_test) { + case HTTOPLEFT: + top = true; + left = true; + break; + case HTTOP: + top = true; + break; + case HTTOPRIGHT: + top = true; + right = true; + break; + case HTLEFT: + left = true; + break; + case HTRIGHT: + right = true; + break; + case HTBOTTOMLEFT: + left = true; + bottom = true; + break; + case HTBOTTOM: + bottom = true; + break; + case HTBOTTOMRIGHT: + bottom = true; + right = true; + break; + default: + break; + } + if (top) + top_animation_->Show(); + else + top_animation_->Hide(); + if (left) + left_animation_->Show(); + else + left_animation_->Hide(); + if (right) + right_animation_->Show(); + else + right_animation_->Hide(); + if (bottom) + bottom_animation_->Show(); + else + bottom_animation_->Hide(); +} + +void ResizeShadow::Hide() { + // Small optimization since we frequently invoke Hide(). + if (top_animation_->IsShowing() || + left_animation_->IsShowing() || + right_animation_->IsShowing() || + bottom_animation_->IsShowing()) + ShowForHitTest(HTNOWHERE); +} + +void ResizeShadow::Layout(const gfx::Rect& bounds) { + // Position the resize border effects near the window edges. + top_layer_->SetBounds(gfx::Rect(kShadowInset, + -kShadowSize, + bounds.width() - 2 * kShadowInset, + kShadowSize)); + bottom_layer_->SetBounds(gfx::Rect(kShadowInset, + bounds.height(), + bounds.width() - 2 * kShadowInset, + kShadowSize)); + left_layer_->SetBounds(gfx::Rect(-kShadowSize, + kShadowInset, + kShadowSize, + bounds.height() - 2 * kShadowInset)); + right_layer_->SetBounds(gfx::Rect(bounds.width(), + kShadowInset, + kShadowSize, + bounds.height() - 2 * kShadowInset)); +} + +void ResizeShadow::AnimationProgressed(const ui::Animation* animation) { + int opacity = animation->CurrentValueBetween(0, kShadowTargetOpacity); + if (animation == top_animation_.get()) + UpdateLayerOpacity(top_layer_.get(), opacity); + else if (animation == left_animation_.get()) + UpdateLayerOpacity(left_layer_.get(), opacity); + else if (animation == right_animation_.get()) + UpdateLayerOpacity(right_layer_.get(), opacity); + else if (animation == bottom_animation_.get()) + UpdateLayerOpacity(bottom_layer_.get(), opacity); +} + +void ResizeShadow::InitLayer(ui::Layer* parent, + scoped_ptr<ui::Layer>* new_layer) { + // Use solid colors because they don't require video memory. + new_layer->reset(new ui::Layer(ui::Layer::LAYER_SOLID_COLOR)); + // Transparency must be part of the color for solid color layers. + // Start fully transparent so we can smoothly animate in. + new_layer->get()->SetColor(SkColorSetARGB(0, 0, 0, 0)); + new_layer->get()->SetVisible(false); + parent->Add(new_layer->get()); +} + +void ResizeShadow::InitAnimation(scoped_ptr<ui::SlideAnimation>* animation) { + animation->reset(new ui::SlideAnimation(this)); + animation->get()->SetSlideDuration(kShadowSlideDurationMs); +} + +void ResizeShadow::UpdateLayerOpacity(ui::Layer* layer, int opacity) { + SkColor color = SkColorSetA(kShadowLayerColor, opacity); + layer->SetColor(color); + layer->SetVisible(opacity != 0); +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/resize_shadow.h b/ash/wm/resize_shadow.h new file mode 100644 index 0000000..4753f4d --- /dev/null +++ b/ash/wm/resize_shadow.h @@ -0,0 +1,80 @@ +// 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. + +#ifndef ASH_WM_RESIZE_SHADOW_H_ +#define ASH_WM_RESIZE_SHADOW_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "ui/base/animation/animation_delegate.h" + +namespace aura { +class Window; +} +namespace gfx { +class Rect; +} +namespace ui { +class Layer; +class SlideAnimation; +} + +namespace ash { +namespace internal { + +// A class to render the resize edge effect when the user moves their mouse +// over a sizing edge. This is just a visual effect; the actual resize is +// handled by the EventFilter. +class ResizeShadow : public ui::AnimationDelegate { + public: + ResizeShadow(); + ~ResizeShadow(); + + // Initializes the resize effect layers for a given |window|. + void Init(aura::Window* window); + + // Shows resize effects for one or more edges based on a |hit_test| code, such + // as HTRIGHT or HTBOTTOMRIGHT. + void ShowForHitTest(int hit_test); + + // Hides all resize effects. + void Hide(); + + // Updates the effect positions based on the |bounds| of its parent. + void Layout(const gfx::Rect& bounds); + + // ui::AnimationDelegate overrides: + virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; + + private: + void InitLayer(ui::Layer* parent, scoped_ptr<ui::Layer>* new_layer); + + void InitAnimation(scoped_ptr<ui::SlideAnimation>* animation); + + // Update the |opacity| for |layer| and sets the layer invisible if it is + // completely transparent. + void UpdateLayerOpacity(ui::Layer* layer, int opacity); + + // Layers of type LAYER_SOLID_COLOR for efficiency. + scoped_ptr<ui::Layer> top_layer_; + scoped_ptr<ui::Layer> left_layer_; + scoped_ptr<ui::Layer> right_layer_; + scoped_ptr<ui::Layer> bottom_layer_; + + // Slide animations for layer opacity. + // TODO(jamescook): Switch to using ui::ScopedLayerAnimationSettings once + // solid color layers support that for opacity. + scoped_ptr<ui::SlideAnimation> top_animation_; + scoped_ptr<ui::SlideAnimation> left_animation_; + scoped_ptr<ui::SlideAnimation> right_animation_; + scoped_ptr<ui::SlideAnimation> bottom_animation_; + + DISALLOW_COPY_AND_ASSIGN(ResizeShadow); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_WM_RESIZE_SHADOW_H_ diff --git a/ash/wm/resize_shadow_controller.cc b/ash/wm/resize_shadow_controller.cc new file mode 100644 index 0000000..b033439 --- /dev/null +++ b/ash/wm/resize_shadow_controller.cc @@ -0,0 +1,67 @@ +// 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 "ash/wm/resize_shadow_controller.h" + +#include <utility> + +#include "ash/wm/resize_shadow.h" +#include "ui/aura/window.h" + +namespace ash { +namespace internal { + +ResizeShadowController::ResizeShadowController() { +} + +ResizeShadowController::~ResizeShadowController() { + for (WindowShadowMap::const_iterator it = window_shadows_.begin(); + it != window_shadows_.end(); ++it) { + it->first->RemoveObserver(this); + } +} + +void ResizeShadowController::ShowShadow(aura::Window* window, int hit_test) { + ResizeShadow* shadow = GetShadowForWindow(window); + if (!shadow) + shadow = CreateShadow(window); + shadow->ShowForHitTest(hit_test); +} + +void ResizeShadowController::HideShadow(aura::Window* window) { + ResizeShadow* shadow = GetShadowForWindow(window); + if (shadow) + shadow->Hide(); +} + +void ResizeShadowController::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& bounds) { + ResizeShadow* shadow = GetShadowForWindow(window); + if (shadow) + shadow->Layout(bounds); +} + +void ResizeShadowController::OnWindowDestroyed(aura::Window* window) { + window_shadows_.erase(window); +} + +ResizeShadow* ResizeShadowController::CreateShadow(aura::Window* window) { + linked_ptr<ResizeShadow> shadow(new ResizeShadow()); + window_shadows_.insert(std::make_pair(window, shadow)); + // Attach the layers to this window. + shadow->Init(window); + // Ensure initial bounds are correct. + shadow->Layout(window->bounds()); + // Watch for bounds changes. + window->AddObserver(this); + return shadow.get(); +} + +ResizeShadow* ResizeShadowController::GetShadowForWindow(aura::Window* window) { + WindowShadowMap::const_iterator it = window_shadows_.find(window); + return it != window_shadows_.end() ? it->second.get() : NULL; +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/resize_shadow_controller.h b/ash/wm/resize_shadow_controller.h new file mode 100644 index 0000000..08294d0 --- /dev/null +++ b/ash/wm/resize_shadow_controller.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef ASH_WM_RESIZE_SHADOW_CONTROLLER_H_ +#define ASH_WM_RESIZE_SHADOW_CONTROLLER_H_ +#pragma once + +#include <map> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/linked_ptr.h" +#include "ui/aura/window_observer.h" + +namespace aura { +class Window; +} + +namespace ash { +namespace internal { + +class ResizeShadow; + +// ResizeShadowController observes changes to resizable windows and shows +// a resize handle visual effect when the cursor is near the edges. +class ResizeShadowController : public aura::WindowObserver { + public: + ResizeShadowController(); + virtual ~ResizeShadowController(); + + // Shows the appropriate shadow for a given |window| and |hit_test| location. + void ShowShadow(aura::Window* window, int hit_test); + + // Hides the shadow for a |window|, if it has one. + void HideShadow(aura::Window* window); + + // aura::WindowObserver overrides: + virtual void OnWindowBoundsChanged( + aura::Window* window, const gfx::Rect& bounds) OVERRIDE; + virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE; + + private: + typedef std::map<aura::Window*, linked_ptr<ResizeShadow> > WindowShadowMap; + + // Creates a shadow for a given window and returns it. |window_shadows_| + // owns the memory. + ResizeShadow* CreateShadow(aura::Window* window); + + // Returns the resize shadow for |window| or NULL if no shadow exists. + ResizeShadow* GetShadowForWindow(aura::Window* window); + + WindowShadowMap window_shadows_; + + DISALLOW_COPY_AND_ASSIGN(ResizeShadowController); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_WM_RESIZE_SHADOW_CONTROLLER_H_ diff --git a/ash/wm/root_window_event_filter.cc b/ash/wm/root_window_event_filter.cc index 5c79078..4c52320 100644 --- a/ash/wm/root_window_event_filter.cc +++ b/ash/wm/root_window_event_filter.cc @@ -4,8 +4,6 @@ #include "ash/wm/root_window_event_filter.h" -#include "ash/wm/activation_controller.h" -#include "ash/wm/power_button_controller.h" #include "ash/wm/window_util.h" #include "ui/aura/event.h" #include "ui/aura/focus_manager.h" diff --git a/ash/wm/shadow_controller.cc b/ash/wm/shadow_controller.cc index 52de1ce..e467f2c 100644 --- a/ash/wm/shadow_controller.cc +++ b/ash/wm/shadow_controller.cc @@ -6,7 +6,6 @@ #include <utility> -#include "ash/ash_switches.h" #include "ash/shell.h" #include "ash/wm/shadow.h" #include "ash/wm/shadow_types.h" diff --git a/ash/wm/toplevel_window_event_filter.cc b/ash/wm/toplevel_window_event_filter.cc index af0fd4d..98f761b 100644 --- a/ash/wm/toplevel_window_event_filter.cc +++ b/ash/wm/toplevel_window_event_filter.cc @@ -7,6 +7,7 @@ #include "ash/shell.h" #include "ash/wm/default_window_resizer.h" #include "ash/wm/property_util.h" +#include "ash/wm/resize_shadow_controller.h" #include "ash/wm/window_resizer.h" #include "ash/wm/window_util.h" #include "base/message_loop.h" @@ -96,6 +97,10 @@ bool ToplevelWindowEventFilter::PreHandleMouseEvent(aura::Window* target, return true; } break; + case ui::ET_MOUSE_MOVED: + return HandleMouseMoved(target, event); + case ui::ET_MOUSE_EXITED: + return HandleMouseExited(target, event); default: break; } @@ -210,4 +215,31 @@ bool ToplevelWindowEventFilter::HandleDrag(aura::Window* target, return true; } +bool ToplevelWindowEventFilter::HandleMouseMoved(aura::Window* target, + aura::LocatedEvent* event) { + // TODO(jamescook): Move the resize cursor update code into here from + // RootWindowEventFilter? + internal::ResizeShadowController* controller = + Shell::GetInstance()->resize_shadow_controller(); + if (controller) { + if (event->flags() & ui::EF_IS_NON_CLIENT) { + int component = + target->delegate()->GetNonClientComponent(event->location()); + controller->ShowShadow(target, component); + } else { + controller->HideShadow(target); + } + } + return false; +} + +bool ToplevelWindowEventFilter::HandleMouseExited(aura::Window* target, + aura::LocatedEvent* event) { + internal::ResizeShadowController* controller = + Shell::GetInstance()->resize_shadow_controller(); + if (controller) + controller->HideShadow(target); + return false; +} + } // namespace ash diff --git a/ash/wm/toplevel_window_event_filter.h b/ash/wm/toplevel_window_event_filter.h index a7fdaf6..55ab2c7 100644 --- a/ash/wm/toplevel_window_event_filter.h +++ b/ash/wm/toplevel_window_event_filter.h @@ -73,6 +73,14 @@ class ASH_EXPORT ToplevelWindowEventFilter : // The return value is returned by OnMouseEvent() above. bool HandleDrag(aura::Window* target, aura::LocatedEvent* event); + // Called during mouse moves to update window resize shadows. + // Return value is returned by OnMouseEvent() above. + bool HandleMouseMoved(aura::Window* target, aura::LocatedEvent* event); + + // Called for mouse exits to hide window resize shadows. + // Return value is returned by OnMouseEvent() above. + bool HandleMouseExited(aura::Window* target, aura::LocatedEvent* event); + // Are we running a nested message loop from RunMoveLoop(). bool in_move_loop_; |