blob: dfb2519f92314a99ccd02175cfad9ac252c70461 [file] [log] [blame]
// Copyright 2014 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_OVERVIEW_WINDOW_GRID_H_
#define ASH_WM_OVERVIEW_WINDOW_GRID_H_
#include <stddef.h>
#include <memory>
#include <set>
#include <vector>
#include "ash/wm/overview/window_selector.h"
#include "ash/wm/window_state_observer.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "ui/aura/window_observer.h"
#include "ui/gfx/geometry/rect.h"
namespace views {
class Widget;
}
namespace wm {
class Shadow;
}
namespace ash {
class OverviewWindowAnimationObserver;
class WindowSelectorItem;
// Represents a grid of windows in the Overview Mode in a particular root
// window, and manages a selection widget that can be moved with the arrow keys.
// The idea behind the movement strategy is that it should be possible to access
// any window pressing a given arrow key repeatedly.
// +-------+ +-------+ +-------+
// | 0 | | 1 | | 2 |
// +-------+ +-------+ +-------+
// +-------+ +-------+ +-------+
// | 3 | | 4 | | 5 |
// +-------+ +-------+ +-------+
// +-------+
// | 6 |
// +-------+
// Example sequences:
// - Going right to left
// 0, 1, 2, 3, 4, 5, 6
// The selector is switched to the next window grid (if available) or wrapped if
// it reaches the end of its movement sequence.
class ASH_EXPORT WindowGrid : public aura::WindowObserver,
public wm::WindowStateObserver {
public:
WindowGrid(aura::Window* root_window,
const std::vector<aura::Window*>& window_list,
WindowSelector* window_selector,
const gfx::Rect& bounds_in_screen);
~WindowGrid() override;
// Exits overview mode, fading out the |shield_widget_| if necessary.
void Shutdown();
// Prepares the windows in this grid for overview. This will restore all
// minimized windows and ensure they are visible.
void PrepareForOverview();
// Positions all the windows in rows of equal height scaling each window to
// fit that height.
// Layout is done in 2 stages maintaining fixed MRU ordering.
// 1. Optimal height is determined. In this stage |height| is bisected to find
// maximum height which still allows all the windows to fit.
// 2. Row widths are balanced. In this stage the available width is reduced
// until some windows are no longer fitting or until the difference between
// the narrowest and the widest rows starts growing.
// Overall this achieves the goals of maximum size for previews (or maximum
// row height which is equivalent assuming fixed height), balanced rows and
// minimal wasted space.
// Optionally animates the windows to their targets when |animate| is true.
// If |ignored_item| is not null and is an item in |window_list_|, that item
// is not positioned. This is for split screen.
void PositionWindows(bool animate,
WindowSelectorItem* ignored_item = nullptr);
// Updates |selected_index_| according to the specified |direction| and calls
// MoveSelectionWidget(). Returns |true| if the new selection index is out of
// this window grid bounds.
bool Move(WindowSelector::Direction direction, bool animate);
// Returns the target selected window, or NULL if there is none selected.
WindowSelectorItem* SelectedWindow() const;
// Returns true if a window is contained in any of the WindowSelectorItems
// this grid owns.
bool Contains(const aura::Window* window) const;
// Adds |window| to the grid. Intended to be used by split view. |window|
// cannot already be on the grid.
void AddItem(aura::Window* window);
// Removes |selector_item| from the grid.
void RemoveItem(WindowSelectorItem* selector_item);
// Dims the items whose titles do not contain |pattern| and prevents their
// selection. The pattern has its accents removed and is converted to
// lowercase in a l10n sensitive context.
// If |pattern| is empty, no item is dimmed.
void FilterItems(const base::string16& pattern);
// Called when |window| is about to get closed. If the |window| is currently
// selected the implementation fades out |selection_widget_| to transparent
// opacity, effectively hiding the selector widget.
void WindowClosing(WindowSelectorItem* window);
// Sets bounds for the window grid and positions all windows in the grid.
void SetBoundsAndUpdatePositions(const gfx::Rect& bounds_in_screen);
void SetBoundsAndUpdatePositionsIgnoringWindow(
const gfx::Rect& bounds,
WindowSelectorItem* ignored_item);
// Shows or hides the selection widget. To be called by a window selector item
// when it is dragged.
void SetSelectionWidgetVisibility(bool visible);
void UpdateCannotSnapWarningVisibility();
// Called when any WindowSelectorItem on any WindowGrid has started/ended
// being dragged.
void OnSelectorItemDragStarted(WindowSelectorItem* item);
void OnSelectorItemDragEnded();
// Returns true if the grid has no more windows.
bool empty() const { return window_list_.empty(); }
// Returns how many window selector items are in the grid.
size_t size() const { return window_list_.size(); }
// Returns true if the selection widget is active.
bool is_selecting() const { return selection_widget_ != nullptr; }
// Returns the root window in which the grid displays the windows.
const aura::Window* root_window() const { return root_window_; }
const std::vector<std::unique_ptr<WindowSelectorItem>>& window_list() const {
return window_list_;
}
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
// TODO(flackr): Handle window bounds changed in WindowSelectorItem.
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
// wm::WindowStateObserver:
void OnPostWindowStateTypeChange(wm::WindowState* window_state,
mojom::WindowStateType old_type) override;
bool IsNoItemsIndicatorLabelVisibleForTesting();
WindowSelector* window_selector() { return window_selector_; }
void set_window_animation_observer(
base::WeakPtr<OverviewWindowAnimationObserver> observer) {
window_animation_observer_ = observer;
}
base::WeakPtr<OverviewWindowAnimationObserver> window_animation_observer() {
return window_animation_observer_;
}
// Sets |should_animate_when_entering_| and |should_animate_when_exiting_|
// of the selector items of the windows based on where the first MRU window
// covering the available workspace is found. Also sets the
// |should_be_observed_when_exiting_| of the last should-animate item.
// |selector_item| is not nullptr when |selector_item| is the selected item
// when exiting overview mode.
void SetWindowListAnimationStates(
WindowSelectorItem* selected_item,
WindowSelector::OverviewTransition transition);
private:
class ShieldView;
friend class WindowSelectorTest;
// Initializes the screen shield widget.
void InitShieldWidget();
// Internal function to initialize the selection widget.
void InitSelectionWidget(WindowSelector::Direction direction);
// Moves the selection widget to the specified |direction|.
void MoveSelectionWidget(WindowSelector::Direction direction,
bool recreate_selection_widget,
bool out_of_bounds,
bool animate);
// Moves the selection widget to the targeted window.
void MoveSelectionWidgetToTarget(bool animate);
// Attempts to fit all |rects| inside |bounds|. The method ensures that
// the |rects| vector has appropriate size and populates it with the values
// placing Rects next to each other left-to-right in rows of equal |height|.
// While fitting |rects| several metrics are collected that can be used by the
// caller. |max_bottom| specifies the bottom that the rects are extending to.
// |min_right| and |max_right| report the right bound of the narrowest and the
// widest rows respectively. In-values of the |max_bottom|, |min_right| and
// |max_right| parameters are ignored and their values are always initialized
// inside this method. Returns true on success and false otherwise.
bool FitWindowRectsInBounds(const gfx::Rect& bounds,
int height,
std::vector<gfx::Rect>* rects,
int* max_bottom,
int* min_right,
int* max_right);
// Sets |selector_item|'s |should_animate_when_entering_|,
// |should_animate_when_exiting_| and |should_be_observed_when_exiting_|.
// |selector_item| is not nullptr when |selector_item| is the selected item
// when exiting overview mode.
void SetWindowSelectorItemAnimationState(
WindowSelectorItem* selector_item,
bool* has_fullscreen_coverred,
bool selected,
WindowSelector::OverviewTransition transition);
// Root window the grid is in.
aura::Window* root_window_;
// Pointer to the window selector that spawned this grid.
WindowSelector* window_selector_;
// Vector containing all the windows in this grid.
std::vector<std::unique_ptr<WindowSelectorItem>> window_list_;
ScopedObserver<aura::Window, WindowGrid> window_observer_;
ScopedObserver<wm::WindowState, WindowGrid> window_state_observer_;
// Widget that darkens the screen background.
std::unique_ptr<views::Widget> shield_widget_;
// A pointer to |shield_widget_|'s content view.
ShieldView* shield_view_ = nullptr;
// Widget that indicates to the user which is the selected window.
std::unique_ptr<views::Widget> selection_widget_;
// Shadow around the selector.
std::unique_ptr<::wm::Shadow> selector_shadow_;
// Current selected window position.
size_t selected_index_;
// Number of columns in the grid.
size_t num_columns_;
// True only after all windows have been prepared for overview.
bool prepared_for_overview_;
// This WindowGrid's total bounds in screen coordinates.
gfx::Rect bounds_;
// Weak ptr to the observer monitoring the exit animation of the first MRU
// window which covers the available workspace. The observer will be deleted
// by itself when the animation completes.
base::WeakPtr<OverviewWindowAnimationObserver> window_animation_observer_ =
nullptr;
DISALLOW_COPY_AND_ASSIGN(WindowGrid);
};
} // namespace ash
#endif // ASH_WM_OVERVIEW_WINDOW_GRID_H_