Home | History | Annotate | Download | only in overview
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ash/wm/overview/window_selector_panels.h"
      6 
      7 #include "ash/screen_util.h"
      8 #include "ash/shell.h"
      9 #include "ash/shell_window_ids.h"
     10 #include "ash/wm/overview/scoped_transform_overview_window.h"
     11 #include "ash/wm/overview/transparent_activate_window_button.h"
     12 #include "ash/wm/panels/panel_layout_manager.h"
     13 #include "ash/wm/window_util.h"
     14 #include "ui/aura/window.h"
     15 #include "ui/compositor/layer.h"
     16 #include "ui/compositor/layer_animation_observer.h"
     17 #include "ui/compositor/layer_animation_sequence.h"
     18 #include "ui/views/controls/button/button.h"
     19 
     20 namespace ash {
     21 
     22 namespace {
     23 
     24 // This class extends ScopedTransformOverviewMode to hide and show the callout
     25 // widget for a panel window when entering / leaving overview mode, as well as
     26 // to add a transparent button for each panel window.
     27 class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow {
     28  public:
     29   explicit ScopedTransformPanelWindow(aura::Window* window);
     30   virtual ~ScopedTransformPanelWindow();
     31 
     32   // ScopedTransformOverviewWindow overrides:
     33   virtual void PrepareForOverview() OVERRIDE;
     34 
     35   virtual void SetTransform(
     36       aura::Window* root_window,
     37       const gfx::Transform& transform,
     38       bool animate) OVERRIDE;
     39 
     40  private:
     41   // Returns the panel window bounds after the transformation.
     42   gfx::Rect GetTransformedBounds();
     43 
     44   scoped_ptr<TransparentActivateWindowButton> window_button_;
     45 
     46   DISALLOW_COPY_AND_ASSIGN(ScopedTransformPanelWindow);
     47 };
     48 
     49 ScopedTransformPanelWindow::ScopedTransformPanelWindow(aura::Window* window)
     50     : ScopedTransformOverviewWindow(window) {
     51 }
     52 
     53 ScopedTransformPanelWindow::~ScopedTransformPanelWindow() {
     54 }
     55 
     56 void ScopedTransformPanelWindow::PrepareForOverview() {
     57   ScopedTransformOverviewWindow::PrepareForOverview();
     58   window_button_.reset(new TransparentActivateWindowButton(window()));
     59 }
     60 
     61 void ScopedTransformPanelWindow::SetTransform(
     62     aura::Window* root_window,
     63     const gfx::Transform& transform,
     64     bool animate) {
     65   ScopedTransformOverviewWindow::SetTransform(root_window, transform, animate);
     66   window_button_->SetBounds(GetTransformedBounds());
     67 }
     68 
     69 gfx::Rect ScopedTransformPanelWindow::GetTransformedBounds() {
     70   gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(
     71           window()->GetRootWindow(), window()->layer()->bounds()));
     72   gfx::Transform new_transform;
     73   new_transform.Translate(bounds.x(),
     74                           bounds.y());
     75   new_transform.PreconcatTransform(window()->layer()->GetTargetTransform());
     76   new_transform.Translate(-bounds.x(),
     77                           -bounds.y());
     78   new_transform.TransformRect(&bounds);
     79   return ToEnclosingRect(bounds);
     80 }
     81 
     82 }  // namespace
     83 
     84 WindowSelectorPanels::WindowSelectorPanels(aura::Window* panels_root_window)
     85     : panels_root_window_(panels_root_window) {
     86   static_cast<PanelLayoutManager*>(
     87       Shell::GetContainer(panels_root_window_, kShellWindowId_PanelContainer)->
     88           layout_manager())->SetShowCalloutWidgets(false);
     89 }
     90 
     91 WindowSelectorPanels::~WindowSelectorPanels() {
     92   static_cast<PanelLayoutManager*>(
     93       Shell::GetContainer(panels_root_window_, kShellWindowId_PanelContainer)->
     94           layout_manager())->SetShowCalloutWidgets(true);
     95   for (WindowList::iterator iter = transform_windows_.begin();
     96       iter != transform_windows_.end(); iter++) {
     97     (*iter)->window()->RemoveObserver(this);
     98   }
     99 }
    100 
    101 void WindowSelectorPanels::AddWindow(aura::Window* window) {
    102   DCHECK(window->GetRootWindow() == panels_root_window_);
    103   window->AddObserver(this);
    104   transform_windows_.push_back(new ScopedTransformPanelWindow(window));
    105 }
    106 
    107 aura::Window* WindowSelectorPanels::GetRootWindow() {
    108   return transform_windows_.front()->window()->GetRootWindow();
    109 }
    110 
    111 bool WindowSelectorPanels::HasSelectableWindow(const aura::Window* window) {
    112   for (WindowList::const_iterator iter = transform_windows_.begin();
    113        iter != transform_windows_.end(); ++iter) {
    114     if ((*iter)->window() == window)
    115       return true;
    116   }
    117   return false;
    118 }
    119 
    120 bool WindowSelectorPanels::Contains(const aura::Window* target) {
    121   for (WindowList::const_iterator iter = transform_windows_.begin();
    122        iter != transform_windows_.end(); ++iter) {
    123     if ((*iter)->Contains(target))
    124       return true;
    125   }
    126   return false;
    127 }
    128 
    129 void WindowSelectorPanels::RestoreWindowOnExit(aura::Window* window) {
    130   for (WindowList::iterator iter = transform_windows_.begin();
    131        iter != transform_windows_.end(); ++iter) {
    132     if ((*iter)->Contains(window)) {
    133       (*iter)->RestoreWindowOnExit();
    134       break;
    135     }
    136   }
    137 }
    138 
    139 aura::Window* WindowSelectorPanels::SelectionWindow() {
    140   return transform_windows_.front()->window();
    141 }
    142 
    143 void WindowSelectorPanels::RemoveWindow(const aura::Window* window) {
    144   for (WindowList::iterator iter = transform_windows_.begin();
    145        iter != transform_windows_.end(); ++iter) {
    146     if ((*iter)->window() == window) {
    147       (*iter)->window()->RemoveObserver(this);
    148       (*iter)->OnWindowDestroyed();
    149       transform_windows_.erase(iter);
    150       break;
    151     }
    152   }
    153   WindowSelectorItem::RemoveWindow(window);
    154 }
    155 
    156 bool WindowSelectorPanels::empty() const {
    157   return transform_windows_.empty();
    158 }
    159 
    160 void WindowSelectorPanels::PrepareForOverview() {
    161   // |panel_windows| will hold all the windows in the panel container, sorted
    162   // according to their stacking order.
    163   const aura::Window::Windows panels =
    164       transform_windows_.front()->window()->parent()->children();
    165 
    166   // Call PrepareForOverview() in the reverse stacking order so that the
    167   // transparent windows that handle the events are in the correct stacking
    168   // order.
    169   size_t transformed_windows = 0;
    170   for (aura::Window::Windows::const_reverse_iterator iter = panels.rbegin();
    171       iter != panels.rend(); iter++) {
    172     for (size_t j = 0; j < transform_windows_.size(); ++j) {
    173       if (transform_windows_[j]->window() == (*iter)) {
    174         transform_windows_[j]->PrepareForOverview();
    175         transformed_windows++;
    176       }
    177     }
    178   }
    179   DCHECK(transformed_windows == transform_windows_.size());
    180 }
    181 
    182 void WindowSelectorPanels::SetItemBounds(aura::Window* root_window,
    183                                          const gfx::Rect& target_bounds,
    184                                          bool animate) {
    185   gfx::Rect bounding_rect;
    186   for (WindowList::iterator iter = transform_windows_.begin();
    187        iter != transform_windows_.end(); ++iter) {
    188     bounding_rect.Union((*iter)->GetBoundsInScreen());
    189   }
    190   set_bounds(ScopedTransformOverviewWindow::
    191       ShrinkRectToFitPreservingAspectRatio(bounding_rect, target_bounds));
    192   gfx::Transform bounding_transform =
    193       ScopedTransformOverviewWindow::GetTransformForRect(bounding_rect,
    194                                                          bounds());
    195   for (WindowList::iterator iter = transform_windows_.begin();
    196        iter != transform_windows_.end(); ++iter) {
    197     gfx::Transform transform;
    198     gfx::Rect bounds = (*iter)->GetBoundsInScreen();
    199     transform.Translate(bounding_rect.x() - bounds.x(),
    200                         bounding_rect.y() - bounds.y());
    201     transform.PreconcatTransform(bounding_transform);
    202     transform.Translate(bounds.x() - bounding_rect.x(),
    203                         bounds.y() - bounding_rect.y());
    204     (*iter)->SetTransform(root_window, transform, animate);
    205   }
    206 }
    207 
    208 void WindowSelectorPanels::SetOpacity(float opacity) {
    209   // TODO(flackr): find a way to make panels that are hidden behind other panels
    210   // look nice.
    211   for (WindowList::iterator iter = transform_windows_.begin();
    212        iter != transform_windows_.end(); iter++) {
    213     (*iter)->window()->layer()->SetOpacity(opacity);
    214   }
    215   WindowSelectorItem::SetOpacity(opacity);
    216 }
    217 
    218 }  // namespace ash
    219