diff options
-rw-r--r-- | ash/resources/ash_resources.grd | 4 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_unittest.cc | 3 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_window.cc | 106 | ||||
-rw-r--r-- | ash/wm/overview/window_selector_window.h | 21 |
4 files changed, 132 insertions, 2 deletions
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd index 396c720..19f1b31 100644 --- a/ash/resources/ash_resources.grd +++ b/ash/resources/ash_resources.grd @@ -259,6 +259,10 @@ <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_RIGHT" file="common/window_header_shade_right_inactive.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_TOP" file="common/window_header_shade_top_inactive.png" /> + <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_OVERVIEW_CLOSE" file="common/window_overview_close_normal.png" /> + <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_OVERVIEW_CLOSE_H" file="common/window_overview_close_hover.png" /> + <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_OVERVIEW_CLOSE_P" file="common/window_overview_close_pressed.png" /> + <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_POSITION_LEFT" file="common/window_position_left_normal.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_POSITION_LEFT_H" file="common/window_position_left_hover.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_POSITION_LEFT_P" file="common/window_position_left_pressed.png" /> diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc index e88e25a..64aa56c 100644 --- a/ash/wm/overview/window_selector_unittest.cc +++ b/ash/wm/overview/window_selector_unittest.cc @@ -1072,9 +1072,10 @@ TEST_F(WindowSelectorTest, HitTestingInOverview) { aura::Window* windows[] = { window1.get(), window2.get() }; for (size_t w = 0; w < arraysize(windows); ++w) { gfx::RectF bounds = GetTransformedBoundsInRootWindow(windows[w]); + // The close button covers the top-right corner of the window so we skip + // this in hit testing. gfx::Point points[] = { gfx::Point(bounds.x(), bounds.y()), - gfx::Point(bounds.right() - 1, bounds.y()), gfx::Point(bounds.x(), bounds.bottom() - 1), gfx::Point(bounds.right() - 1, bounds.bottom() - 1), }; diff --git a/ash/wm/overview/window_selector_window.cc b/ash/wm/overview/window_selector_window.cc index ea82416..40b53d4 100644 --- a/ash/wm/overview/window_selector_window.cc +++ b/ash/wm/overview/window_selector_window.cc @@ -4,10 +4,54 @@ #include "ash/wm/overview/window_selector_window.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/wm/overview/scoped_transform_overview_window.h" +#include "grit/ash_resources.h" #include "ui/aura/window.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/transform.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/widget/widget.h" namespace ash { +namespace { + +views::Widget* CreateCloseWindowButton(aura::Window* root_window, + views::ButtonListener* listener) { + views::Widget* widget = new views::Widget; + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.can_activate = false; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.parent = Shell::GetContainer(root_window, + ash::internal::kShellWindowId_OverlayContainer); + widget->set_focus_on_creation(false); + widget->Init(params); + views::ImageButton* button = new views::ImageButton(listener); + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + button->SetImage(views::CustomButton::STATE_NORMAL, + rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE)); + button->SetImage(views::CustomButton::STATE_HOVERED, + rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_H)); + button->SetImage(views::CustomButton::STATE_PRESSED, + rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_P)); + widget->SetContentsView(button); + widget->SetSize(rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE)->size()); + widget->Show(); + return widget; +} + +// The time for the close button to fade in when initially shown on entering +// overview mode. +const int kCloseButtonFadeInMilliseconds = 80; + +} // namespace + WindowSelectorWindow::WindowSelectorWindow(aura::Window* window) : transform_window_(window) { } @@ -40,6 +84,10 @@ aura::Window* WindowSelectorWindow::SelectionWindow() { void WindowSelectorWindow::RemoveWindow(const aura::Window* window) { DCHECK_EQ(transform_window_.window(), window); transform_window_.OnWindowDestroyed(); + // Remove the close button now so that the exited mouse event which is + // delivered to the destroyed button as it is destroyed does not happen while + // this item is being removed from the list of windows in overview. + close_button_.reset(); } bool WindowSelectorWindow::empty() const { @@ -59,6 +107,64 @@ void WindowSelectorWindow::SetItemBounds(aura::Window* root_window, transform_window_.SetTransform(root_window, ScopedTransformOverviewWindow::GetTransformForRect(src_rect, bounds()), animate); + UpdateCloseButtonBounds(); +} + +void WindowSelectorWindow::ButtonPressed(views::Button* sender, + const ui::Event& event) { + views::Widget::GetTopLevelWidgetForNativeView( + transform_window_.window())->Close(); +} + +void WindowSelectorWindow::UpdateCloseButtonBounds() { + aura::Window* root_window = GetRootWindow(); + gfx::Rect align_bounds(bounds()); + gfx::Transform close_button_transform; + close_button_transform.Translate(align_bounds.right(), align_bounds.y()); + + // If the root window has changed, force the close button to be recreated + // and faded in on the new root window. + if (close_button_ && + close_button_->GetNativeWindow()->GetRootWindow() != root_window) { + close_button_.reset(); + } + + if (!close_button_) { + close_button_.reset(CreateCloseWindowButton(root_window, this)); + gfx::Rect close_button_rect(close_button_->GetNativeWindow()->bounds()); + // Align the center of the button with position (0, 0) so that the + // translate transform does not need to take the button dimensions into + // account. + close_button_rect.set_x(-close_button_rect.width() / 2); + close_button_rect.set_y(-close_button_rect.height() / 2); + close_button_->GetNativeWindow()->SetBounds(close_button_rect); + close_button_->GetNativeWindow()->SetTransform(close_button_transform); + // The close button is initialized when entering overview, fade the button + // in after the window should be in place. + ui::Layer* layer = close_button_->GetNativeWindow()->layer(); + layer->SetOpacity(0); + layer->GetAnimator()->StopAnimating(); + layer->GetAnimator()->SchedulePauseForProperties( + base::TimeDelta::FromMilliseconds( + ScopedTransformOverviewWindow::kTransitionMilliseconds), + ui::LayerAnimationElement::OPACITY); + { + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); + settings.SetPreemptionStrategy( + ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); + settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( + kCloseButtonFadeInMilliseconds)); + layer->SetOpacity(1); + } + } else { + ui::ScopedLayerAnimationSettings settings( + close_button_->GetNativeWindow()->layer()->GetAnimator()); + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( + ScopedTransformOverviewWindow::kTransitionMilliseconds)); + close_button_->GetNativeWindow()->SetTransform(close_button_transform); + } } } // namespace ash diff --git a/ash/wm/overview/window_selector_window.h b/ash/wm/overview/window_selector_window.h index 5662f29..0c6d7b8 100644 --- a/ash/wm/overview/window_selector_window.h +++ b/ash/wm/overview/window_selector_window.h @@ -8,17 +8,24 @@ #include "ash/wm/overview/scoped_transform_overview_window.h" #include "ash/wm/overview/window_selector_item.h" #include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" #include "ui/gfx/rect.h" +#include "ui/views/controls/button/button.h" namespace aura { class Window; } +namespace views { +class Widget; +} + namespace ash { // This implements a window overview item with a single window which can be // selected. -class WindowSelectorWindow : public WindowSelectorItem { +class WindowSelectorWindow : public WindowSelectorItem, + public views::ButtonListener { public: WindowSelectorWindow(aura::Window* window); virtual ~WindowSelectorWindow(); @@ -36,9 +43,21 @@ class WindowSelectorWindow : public WindowSelectorItem { const gfx::Rect& target_bounds, bool animate) OVERRIDE; + // views::ButtonListener: + virtual void ButtonPressed(views::Button* sender, + const ui::Event& event) OVERRIDE; + private: + // Creates the close button window if it does not exist and updates the bounds + // to match the window selector item. + void UpdateCloseButtonBounds(); + + // The window with a scoped transform represented by this selector item. ScopedTransformOverviewWindow transform_window_; + // An easy to access close button for the window in this item. + scoped_ptr<views::Widget> close_button_; + DISALLOW_COPY_AND_ASSIGN(WindowSelectorWindow); }; |