summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/resources/ash_resources.grd4
-rw-r--r--ash/wm/overview/window_selector_unittest.cc3
-rw-r--r--ash/wm/overview/window_selector_window.cc106
-rw-r--r--ash/wm/overview/window_selector_window.h21
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);
};