summaryrefslogtreecommitdiffstats
path: root/ash/wm
diff options
context:
space:
mode:
authorjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-16 22:30:48 +0000
committerjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-16 22:30:48 +0000
commitb0fcb0e709bc2731e6e71fbee0eb31b8a1ba7213 (patch)
tree091b318d966de6961cca373b1aef6dc79e1301bd /ash/wm
parent6f98f122e37c62262d9547a91d28b1bbaa6b90d2 (diff)
downloadchromium_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.cc171
-rw-r--r--ash/wm/resize_shadow.h80
-rw-r--r--ash/wm/resize_shadow_controller.cc67
-rw-r--r--ash/wm/resize_shadow_controller.h61
-rw-r--r--ash/wm/root_window_event_filter.cc2
-rw-r--r--ash/wm/shadow_controller.cc1
-rw-r--r--ash/wm/toplevel_window_event_filter.cc32
-rw-r--r--ash/wm/toplevel_window_event_filter.h8
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_;