123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- // Copyright 2018 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/splitview/split_view_highlight_view.h"
- #include "ash/display/screen_orientation_controller.h"
- #include "ash/shell.h"
- #include "ash/style/ash_color_provider.h"
- #include "ash/wm/splitview/split_view_controller.h"
- #include "base/i18n/rtl.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/layer_type.h"
- #include "ui/gfx/geometry/rounded_corners_f.h"
- #include "ui/views/background.h"
- #include "ui/views/highlight_border.h"
- #include "ui/views/view.h"
- #include "ui/views/view_observer.h"
- #include "ui/views/widget/widget.h"
- namespace ash {
- namespace {
- // The amount of round applied to the corners of the highlight views.
- constexpr int kHighlightScreenRoundRectRadius = 4;
- // Self deleting animation observer that removes clipping on View's layer and
- // optionally sets bounds after the animation ends.
- class ClippingObserver : public ui::ImplicitAnimationObserver,
- public views::ViewObserver {
- public:
- ClippingObserver(views::View* view, absl::optional<gfx::Rect> bounds)
- : view_(view), bounds_(bounds) {
- view_->AddObserver(this);
- }
- ~ClippingObserver() override { view_->RemoveObserver(this); }
- // ui::ImplicitAnimationObserver:
- void OnImplicitAnimationsCompleted() override {
- view_->layer()->SetClipRect(gfx::Rect());
- if (bounds_)
- view_->SetBoundsRect(*bounds_);
- delete this;
- }
- // views::ViewObserver:
- void OnViewIsDeleting(views::View* observed_view) override {
- DCHECK_EQ(view_, observed_view);
- delete this;
- }
- private:
- views::View* const view_;
- absl::optional<gfx::Rect> bounds_;
- };
- } // namespace
- SplitViewHighlightView::SplitViewHighlightView(bool is_right_or_bottom)
- : is_right_or_bottom_(is_right_or_bottom) {
- SetPaintToLayer(ui::LAYER_TEXTURED);
- SetBackground(views::CreateRoundedRectBackground(
- AshColorProvider::Get()->GetBackgroundColor(),
- kHighlightScreenRoundRectRadius));
- layer()->SetFillsBoundsOpaquely(false);
- layer()->SetRoundedCornerRadius(
- gfx::RoundedCornersF{kHighlightScreenRoundRectRadius});
- layer()->SetIsFastRoundedCorner(true);
- }
- SplitViewHighlightView::~SplitViewHighlightView() = default;
- void SplitViewHighlightView::OnThemeChanged() {
- views::View::OnThemeChanged();
- background()->SetNativeControlColor(
- AshColorProvider::Get()->GetBackgroundColor());
- if (chromeos::features::IsDarkLightModeEnabled()) {
- SetBorder(std::make_unique<views::HighlightBorder>(
- kHighlightScreenRoundRectRadius,
- views::HighlightBorder::Type::kHighlightBorder1,
- /*use_light_colors=*/false));
- }
- }
- void SplitViewHighlightView::SetBounds(
- const gfx::Rect& bounds,
- const absl::optional<SplitviewAnimationType>& animation_type) {
- if (bounds == this->bounds())
- return;
- if (!animation_type) {
- SetBoundsRect(bounds);
- return;
- }
- const gfx::Rect old_bounds = this->bounds();
- // Note: This is passed on the assumption that the highlights either.
- // 1) Slide out - x or y increases and other dimension stays the same.
- // 2) Slide in - x or y decreases and other dimension stays the same.
- // 3) Expands(Nix inset) - x and y both increase by a small amount.
- const bool grows = bounds.size().GetArea() > old_bounds.size().GetArea();
- // If the highlight grows, set the final bounds and clip the rect to the
- // current bounds and animate. Otherwise, start the clip animation and set the
- // bounds after the animation is complete.
- if (grows)
- SetBoundsRect(bounds);
- // The origin of the clip rect needs to be shifted depending on whether we are
- // growing or shrinking for right/bottom views since their animations are
- // mirrored.
- gfx::Point start_origin, end_origin;
- const bool nix_animation =
- *animation_type == SPLITVIEW_ANIMATION_PREVIEW_AREA_NIX_INSET;
- if (is_right_or_bottom_ || nix_animation) {
- gfx::Vector2d clip_offset = bounds.origin() - old_bounds.origin();
- // Make sure a widget exists because the test might not add it.
- DCHECK(GetWidget());
- // RTL is a special case since for the right highlight we will receive a
- // mirrored rect whose origin will not change. In this case the clip rect
- // offset should be the change in width. Portrait mode does not care since
- // it is unaffected by RTL and the nix inset animation will supply the
- // current bounds offset.
- if (base::i18n::IsRTL() &&
- SplitViewController::IsLayoutHorizontal(
- GetWidget()->GetNativeWindow()) &&
- !nix_animation) {
- clip_offset = gfx::Vector2d(bounds.width() - old_bounds.width(), 0);
- }
- clip_offset.set_x(std::abs(clip_offset.x()));
- clip_offset.set_y(std::abs(clip_offset.y()));
- if (grows)
- start_origin += clip_offset;
- else
- end_origin += clip_offset;
- }
- layer()->SetClipRect(gfx::Rect(start_origin, old_bounds.size()));
- DoSplitviewClipRectAnimation(
- layer(), *animation_type, gfx::Rect(end_origin, bounds.size()),
- std::make_unique<ClippingObserver>(
- this, grows ? absl::nullopt : absl::make_optional(bounds)));
- }
- void SplitViewHighlightView::OnWindowDraggingStateChanged(
- SplitViewDragIndicators::WindowDraggingState window_dragging_state,
- SplitViewDragIndicators::WindowDraggingState previous_window_dragging_state,
- bool previews_only,
- bool can_dragged_window_be_snapped) {
- // No top indicator for dragging from the top in portrait orientation.
- if (window_dragging_state ==
- SplitViewDragIndicators::WindowDraggingState::kFromTop &&
- !IsCurrentScreenOrientationLandscape() && !is_right_or_bottom_) {
- return;
- }
- if (window_dragging_state ==
- SplitViewDragIndicators::WindowDraggingState::kOtherDisplay) {
- DoSplitviewOpacityAnimation(layer(),
- SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT);
- return;
- }
- const SplitViewController::SnapPosition preview_position =
- SplitViewDragIndicators::GetSnapPosition(window_dragging_state);
- const SplitViewController::SnapPosition previous_preview_position =
- SplitViewDragIndicators::GetSnapPosition(previous_window_dragging_state);
- aura::Window* window = GetWidget()->GetNativeWindow();
- if (window_dragging_state ==
- SplitViewDragIndicators::WindowDraggingState::kNoDrag) {
- if (previous_preview_position == SplitViewController::NONE) {
- DoSplitviewOpacityAnimation(layer(),
- SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT);
- return;
- }
- if (is_right_or_bottom_ != SplitViewController::IsPhysicalLeftOrTop(
- previous_preview_position, window)) {
- DoSplitviewOpacityAnimation(layer(),
- SPLITVIEW_ANIMATION_PREVIEW_AREA_FADE_OUT);
- }
- return;
- }
- background()->SetNativeControlColor(
- AshColorProvider::Get()->GetBackgroundColor());
- if (chromeos::features::IsDarkLightModeEnabled()) {
- SetBorder(std::make_unique<views::HighlightBorder>(
- kHighlightScreenRoundRectRadius,
- views::HighlightBorder::Type::kHighlightBorder1,
- /*use_light_colors=*/false));
- }
- if (preview_position != SplitViewController::NONE) {
- DoSplitviewOpacityAnimation(
- layer(),
- is_right_or_bottom_ != SplitViewController::IsPhysicalLeftOrTop(
- preview_position, window)
- ? SPLITVIEW_ANIMATION_PREVIEW_AREA_FADE_IN
- : SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_FADE_OUT);
- return;
- }
- if (previous_preview_position != SplitViewController::NONE) {
- // There was a snap preview showing, but now the user has dragged away from
- // the edge of the screen, so that the preview should go away.
- if (is_right_or_bottom_ != SplitViewController::IsPhysicalLeftOrTop(
- previous_preview_position, window)) {
- // This code is for the preview. If |previews_only|, just fade out. Else
- // fade in from |kPreviewAreaHighlightOpacity| to |kHighlightOpacity|.
- DoSplitviewOpacityAnimation(
- layer(),
- previews_only
- ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT
- : can_dragged_window_be_snapped
- ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN
- : SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN_CANNOT_SNAP);
- } else {
- // This code is for the other highlight. If |previews_only|, just stay
- // hidden (in other words, do nothing). Else fade in.
- DCHECK_EQ(0.f, layer()->GetTargetOpacity());
- if (!previews_only) {
- DoSplitviewOpacityAnimation(
- layer(),
- can_dragged_window_be_snapped
- ? SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_FADE_IN
- : SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_FADE_IN_CANNOT_SNAP);
- }
- }
- return;
- }
- // The drag just started or came in from another display, and is not currently
- // in a snap area. If |previews_only|, there is nothing to do. Else fade in.
- DCHECK_EQ(0.f, layer()->GetTargetOpacity());
- if (!previews_only) {
- DoSplitviewOpacityAnimation(
- layer(), can_dragged_window_be_snapped
- ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN
- : SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN_CANNOT_SNAP);
- return;
- }
- }
- } // namespace ash
|