123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- // 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/workspace/phantom_window_controller.h"
- #include <math.h>
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/public/cpp/style/scoped_light_mode_as_default.h"
- #include "ash/root_window_controller.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "ash/style/ash_color_provider.h"
- #include "ash/wm/window_util.h"
- #include "ui/aura/window.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/scoped_layer_animation_settings.h"
- #include "ui/display/screen.h"
- #include "ui/gfx/canvas.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/views/animation/animation_builder.h"
- #include "ui/views/background.h"
- #include "ui/views/border.h"
- #include "ui/views/controls/label.h"
- #include "ui/views/highlight_border.h"
- #include "ui/views/layout/box_layout.h"
- #include "ui/views/view.h"
- #include "ui/views/widget/widget.h"
- #include "ui/wm/core/coordinate_conversion.h"
- #include "ui/wm/core/shadow_controller.h"
- #include "ui/wm/core/shadow_types.h"
- namespace ash {
- namespace {
- // The size of the phantom window at the beginning of the show animation in
- // relation to the size of the phantom window at the end of the animation.
- constexpr float kScrimStartBoundsRatio = 0.75f;
- // The duration of the phantom scrim entrance animation for size transform.
- constexpr base::TimeDelta kScrimEntranceSizeAnimationDurationMs =
- base::Milliseconds(150);
- // The duration of the phantom scrim entrance animation for opacity.
- constexpr base::TimeDelta kScrimEntranceOpacityAnimationDurationMs =
- base::Milliseconds(50);
- // The elevation of the shadow for the phantom window should match that of an
- // active window.
- // The shadow ninebox requires a minimum size to work well. See
- // ui/compositor_extra/shadow.cc
- constexpr int kMinWidthWithShadow = 2 * ::wm::kShadowElevationActiveWindow;
- constexpr int kMinHeightWithShadow = 4 * ::wm::kShadowElevationActiveWindow;
- // The top margin of the cue from the top of work area.
- constexpr int kMaximizeCueTopMargin = 32;
- constexpr int kMaximizeCueHeight = 36;
- constexpr int kMaximizeCueHorizontalInsets = 16;
- constexpr int kMaximizeCueVerticalInsets = 8;
- constexpr int kPhantomWindowCornerRadius = 4;
- constexpr gfx::Insets kPhantomWindowInsets(8);
- // The move up factor of starting y-position from the target position for
- // entrance animation of maximize cue.
- constexpr float kMaximizeCueEntraceAnimationYPositionMoveUpFactor = 0.5f;
- // The duration of the maximize cue entrance animation.
- constexpr base::TimeDelta kMaximizeCueEntranceAnimationDurationMs =
- base::Milliseconds(150);
- // The duration of the maximize cue exit animation.
- constexpr base::TimeDelta kMaximizeCueExitAnimationDurationMs =
- base::Milliseconds(100);
- // The delay of the maximize cue entrance and exit animation.
- constexpr base::TimeDelta kMaximizeCueAnimationDelayMs =
- base::Milliseconds(100);
- } // namespace
- // PhantomWindowController ----------------------------------------------------
- PhantomWindowController::PhantomWindowController(aura::Window* window)
- : window_(window) {}
- PhantomWindowController::~PhantomWindowController() = default;
- void PhantomWindowController::Show(const gfx::Rect& window_bounds_in_screen) {
- gfx::Rect target_bounds_in_screen = window_bounds_in_screen;
- target_bounds_in_screen.Inset(kPhantomWindowInsets);
- if (target_bounds_in_screen == target_bounds_in_screen_)
- return;
- target_bounds_in_screen_ = target_bounds_in_screen;
- // Computes starting size with a shrinking ratio |kScrimStartBoundsRatio|
- // from the actual size |target_bounds_in_screen| used for entrace animation
- // in `ShowPhantomWidget()`.
- gfx::Rect start_bounds_in_screen = target_bounds_in_screen_;
- int start_width = std::max(kMinWidthWithShadow,
- static_cast<int>(start_bounds_in_screen.width() *
- kScrimStartBoundsRatio));
- int start_height = std::max(kMinHeightWithShadow,
- static_cast<int>(start_bounds_in_screen.height() *
- kScrimStartBoundsRatio));
- start_bounds_in_screen.Inset(gfx::Insets::VH(
- floor((start_bounds_in_screen.height() - start_height) / 2.0f),
- floor((start_bounds_in_screen.width() - start_width) / 2.0f)));
- // Create a phantom widget with starting size so `ShowPhantomWidget()` can
- // animate from that current size to |target_bounds_in_screen|.
- phantom_widget_ = CreatePhantomWidget(
- window_util::GetRootWindowMatching(target_bounds_in_screen_),
- start_bounds_in_screen);
- ShowPhantomWidget();
- }
- void PhantomWindowController::HideMaximizeCue() {
- DCHECK(maximize_cue_widget_);
- ui::Layer* widget_layer = maximize_cue_widget_->GetLayer();
- views::AnimationBuilder()
- .SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
- .Once()
- .SetDuration(kMaximizeCueAnimationDelayMs)
- .Then()
- .SetDuration(kMaximizeCueExitAnimationDurationMs)
- .SetOpacity(widget_layer, 0, gfx::Tween::LINEAR);
- }
- void PhantomWindowController::ShowMaximizeCue() {
- if (!maximize_cue_widget_) {
- maximize_cue_widget_ = CreateMaximizeCue(
- window_util::GetRootWindowMatching(target_bounds_in_screen_));
- maximize_cue_widget_->Show();
- }
- maximize_cue_widget_->SetOpacity(0);
- // Starts entrance animation with fade in and moving the cue from 50%
- // higher y position to the actual y position.
- const gfx::Rect target_bounds =
- maximize_cue_widget_->GetNativeView()->bounds();
- const gfx::Rect starting_bounds = gfx::Rect(
- target_bounds.x(),
- target_bounds.y() * kMaximizeCueEntraceAnimationYPositionMoveUpFactor,
- target_bounds.width(), target_bounds.height());
- maximize_cue_widget_->SetBounds(starting_bounds);
- ui::Layer* widget_layer = maximize_cue_widget_->GetLayer();
- views::AnimationBuilder()
- .SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
- .Once()
- .SetDuration(kMaximizeCueAnimationDelayMs)
- .Then()
- .SetDuration(kMaximizeCueEntranceAnimationDurationMs)
- .SetBounds(widget_layer, target_bounds, gfx::Tween::ACCEL_LIN_DECEL_100)
- .SetOpacity(widget_layer, 1, gfx::Tween::LINEAR);
- }
- void PhantomWindowController::TransformPhantomWidgetFromSnapTopToMaximize(
- const gfx::Rect& maximize_window_bounds_in_screen) {
- gfx::Rect target_bounds_in_screen = maximize_window_bounds_in_screen;
- target_bounds_in_screen.Inset(kPhantomWindowInsets);
- target_bounds_in_screen_ = target_bounds_in_screen;
- ui::Layer* widget_layer = phantom_widget_->GetLayer();
- views::AnimationBuilder()
- .SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
- .Once()
- .SetDuration(kScrimEntranceSizeAnimationDurationMs)
- .SetBounds(widget_layer, target_bounds_in_screen,
- gfx::Tween::ACCEL_20_DECEL_100);
- }
- gfx::Rect PhantomWindowController::GetTargetWindowBounds() const {
- gfx::Rect target_window_bounds = target_bounds_in_screen_;
- target_window_bounds.Inset(-kPhantomWindowInsets);
- return target_window_bounds;
- }
- views::Widget* PhantomWindowController::GetMaximizeCueForTesting() const {
- return maximize_cue_widget_.get();
- }
- std::unique_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget(
- aura::Window* root_window,
- const gfx::Rect& bounds_in_screen) {
- std::unique_ptr<views::Widget> phantom_widget(new views::Widget);
- views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
- params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
- // PhantomWindowController is used by FrameMaximizeButton to highlight the
- // launcher button. Put the phantom in the same window as the launcher so that
- // the phantom is visible.
- params.z_order = ui::ZOrderLevel::kFloatingUIElement;
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.name = "PhantomWindow";
- params.layer_type = ui::LAYER_SOLID_COLOR;
- params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
- params.parent = root_window->GetChildById(kShellWindowId_ShelfContainer);
- phantom_widget->set_focus_on_creation(false);
- phantom_widget->Init(std::move(params));
- phantom_widget->SetVisibilityChangedAnimationsEnabled(false);
- aura::Window* phantom_widget_window = phantom_widget->GetNativeWindow();
- phantom_widget_window->SetId(kShellWindowId_PhantomWindow);
- phantom_widget->SetBounds(bounds_in_screen);
- // TODO(sky): I suspect this is never true, verify that.
- if (phantom_widget_window->parent() == window_->parent()) {
- phantom_widget_window->parent()->StackChildAbove(phantom_widget_window,
- window_);
- } else {
- // Ensure the phantom and its shadow do not cover the shelf.
- phantom_widget_window->parent()->StackChildAtBottom(phantom_widget_window);
- }
- views::View* phantom_view =
- phantom_widget->SetContentsView(std::make_unique<views::View>());
- phantom_view->SetPaintToLayer();
- phantom_view->layer()->SetFillsBoundsOpaquely(false);
- phantom_view->SetBackground(views::CreateRoundedRectBackground(
- AshColorProvider::Get()->GetShieldLayerColor(
- AshColorProvider::ShieldLayerType::kShield20),
- kPhantomWindowCornerRadius));
- phantom_view->SetBorder(std::make_unique<views::HighlightBorder>(
- kPhantomWindowCornerRadius,
- views::HighlightBorder::Type::kHighlightBorder1,
- /*use_light_colors=*/false));
- return phantom_widget;
- }
- std::unique_ptr<views::Widget> PhantomWindowController::CreateMaximizeCue(
- aura::Window* root_window) {
- DCHECK(phantom_widget_);
- std::unique_ptr<views::Widget> maximize_cue_widget(new views::Widget);
- views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
- params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
- // Put the maximize cue in the same window as the floating UI.
- params.z_order = ui::ZOrderLevel::kFloatingUIElement;
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.name = "MaximizeCueWidget";
- params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
- params.parent = root_window->GetChildById(kShellWindowId_OverlayContainer);
- maximize_cue_widget->set_focus_on_creation(false);
- maximize_cue_widget->Init(std::move(params));
- aura::Window* maximize_cue_widget_window =
- maximize_cue_widget->GetNativeWindow();
- maximize_cue_widget_window->parent()->StackChildAtTop(
- maximize_cue_widget_window);
- views::View* maximize_cue =
- maximize_cue_widget->SetContentsView(std::make_unique<views::View>());
- maximize_cue->SetPaintToLayer();
- maximize_cue->layer()->SetFillsBoundsOpaquely(false);
- auto* color_provider = AshColorProvider::Get();
- maximize_cue->SetBackground(views::CreateRoundedRectBackground(
- color_provider->GetBaseLayerColor(
- AshColorProvider::BaseLayerType::kTransparent80),
- kMaximizeCueHeight / 2));
- maximize_cue->layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
- const gfx::RoundedCornersF radii(kMaximizeCueHeight / 2);
- maximize_cue->layer()->SetRoundedCornerRadius(radii);
- maximize_cue->SetBorder(std::make_unique<views::HighlightBorder>(
- kMaximizeCueHeight / 2, views::HighlightBorder::Type::kHighlightBorder1,
- /*use_light_colors=*/false));
- // Set layout of cue view and add a label to the view.
- maximize_cue->SetLayoutManager(std::make_unique<views::BoxLayout>(
- views::BoxLayout::Orientation::kHorizontal,
- gfx::Insets::VH(kMaximizeCueVerticalInsets,
- kMaximizeCueHorizontalInsets)));
- views::Label* maximize_cue_label =
- maximize_cue->AddChildView(std::make_unique<views::Label>(
- l10n_util::GetStringUTF16(IDS_ASH_SPLIT_VIEW_HOLD_TO_MAXIMIZE)));
- maximize_cue_label->SetPaintToLayer();
- maximize_cue_label->layer()->SetFillsBoundsOpaquely(false);
- maximize_cue_label->SetEnabledColor(color_provider->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kTextColorPrimary));
- maximize_cue_label->SetVisible(true);
- maximize_cue_label->SetAutoColorReadabilityEnabled(false);
- maximize_cue_label->SetFontList(views::Label::GetDefaultFontList().Derive(
- 2, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL));
- const display::Display& display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(root_window);
- const gfx::Rect work_area = display.work_area();
- const int maximize_cue_width = maximize_cue->GetPreferredSize().width();
- const int maximize_cue_y = work_area.y() + kMaximizeCueTopMargin;
- const gfx::Rect phantom_bounds = phantom_widget_->GetNativeView()->bounds();
- const gfx::Rect maximize_cue_bounds =
- gfx::Rect(phantom_bounds.CenterPoint().x() - maximize_cue_width / 2,
- maximize_cue_y, maximize_cue_width, kMaximizeCueHeight);
- maximize_cue_widget->SetBounds(maximize_cue_bounds);
- return maximize_cue_widget;
- }
- void PhantomWindowController::ShowPhantomWidget() {
- phantom_widget_->Show();
- phantom_widget_->SetOpacity(0);
- ui::Layer* widget_layer = phantom_widget_->GetLayer();
- // Layer uses bounds in parent so convert from screen bounds.
- gfx::Rect bounds = target_bounds_in_screen_;
- wm::ConvertRectFromScreen(phantom_widget_->GetNativeWindow()->parent(),
- &bounds);
- views::AnimationBuilder()
- .SetPreemptionStrategy(
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
- .Once()
- .SetDuration(kScrimEntranceSizeAnimationDurationMs)
- .SetBounds(widget_layer, bounds, gfx::Tween::ACCEL_20_DECEL_100)
- .At(base::Seconds(0))
- .SetDuration(kScrimEntranceOpacityAnimationDurationMs)
- .SetOpacity(widget_layer, 1, gfx::Tween::LINEAR);
- }
- } // namespace ash
|