123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713 |
- // Copyright 2017 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_drag_indicators.h"
- #include <utility>
- #include <vector>
- #include "ash/display/screen_orientation_controller.h"
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/public/cpp/window_animation_types.h"
- #include "ash/screen_util.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shell.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "ash/style/ash_color_provider.h"
- #include "ash/style/default_color_constants.h"
- #include "ash/style/default_colors.h"
- #include "ash/utility/haptics_util.h"
- #include "ash/wm/overview/overview_controller.h"
- #include "ash/wm/overview/overview_window_drag_controller.h"
- #include "ash/wm/splitview/split_view_constants.h"
- #include "ash/wm/splitview/split_view_highlight_view.h"
- #include "ash/wm/splitview/split_view_utils.h"
- #include "ash/wm/window_animations.h"
- #include "ash/wm/window_util.h"
- #include "base/i18n/rtl.h"
- #include "base/strings/utf_string_conversions.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_observer.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/layer_type.h"
- #include "ui/compositor/scoped_layer_animation_settings.h"
- #include "ui/display/display_observer.h"
- #include "ui/events/devices/haptic_touchpad_effects.h"
- #include "ui/views/background.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/window_animations.h"
- namespace ash {
- namespace {
- // When a preview is shown, the opposite highlight shall contract to this ratio
- // of the screen length.
- constexpr float kOtherHighlightScreenPrimaryAxisRatio = 0.03f;
- // Creates the widget responsible for displaying the indicators.
- std::unique_ptr<views::Widget> CreateWidget(aura::Window* root_window) {
- auto widget = std::make_unique<views::Widget>();
- views::Widget::InitParams params;
- params.type = views::Widget::InitParams::TYPE_POPUP;
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
- params.accept_events = false;
- params.layer_type = ui::LAYER_NOT_DRAWN;
- params.parent =
- Shell::GetContainer(root_window, kShellWindowId_OverlayContainer);
- widget->set_focus_on_creation(false);
- widget->Init(std::move(params));
- return widget;
- }
- // Computes the transform which rotates the labels |angle| degrees. The point
- // of rotation is the relative center point of |bounds|.
- gfx::Transform ComputeRotateAroundCenterTransform(const gfx::Rect& bounds,
- double angle) {
- gfx::Transform transform;
- const gfx::Vector2dF center_point_vector =
- bounds.CenterPoint() - bounds.origin();
- transform.Translate(center_point_vector);
- transform.Rotate(angle);
- transform.Translate(-center_point_vector);
- return transform;
- }
- // Returns the work area bounds that has no overlap with shelf.
- gfx::Rect GetWorkAreaBoundsNoOverlapWithShelf(aura::Window* root_window) {
- aura::Window* window =
- root_window->GetChildById(kShellWindowId_OverlayContainer);
- gfx::Rect bounds = screen_util::GetDisplayWorkAreaBoundsInParent(window);
- ::wm::ConvertRectToScreen(root_window, &bounds);
- bounds.Subtract(Shelf::ForWindow(root_window)->GetIdealBounds());
- return bounds;
- }
- } // namespace
- // static
- SplitViewController::SnapPosition SplitViewDragIndicators::GetSnapPosition(
- WindowDraggingState window_dragging_state) {
- switch (window_dragging_state) {
- case WindowDraggingState::kToSnapLeft:
- return SplitViewController::LEFT;
- case WindowDraggingState::kToSnapRight:
- return SplitViewController::RIGHT;
- default:
- return SplitViewController::NONE;
- }
- }
- // static
- SplitViewDragIndicators::WindowDraggingState
- SplitViewDragIndicators::ComputeWindowDraggingState(
- bool is_dragging,
- WindowDraggingState non_snap_state,
- SplitViewController::SnapPosition snap_position) {
- if (!is_dragging || !ShouldAllowSplitView())
- return WindowDraggingState::kNoDrag;
- switch (snap_position) {
- case SplitViewController::NONE:
- return non_snap_state;
- case SplitViewController::LEFT:
- return WindowDraggingState::kToSnapLeft;
- case SplitViewController::RIGHT:
- return WindowDraggingState::kToSnapRight;
- }
- }
- // View which contains a label and can be rotated. Used by and rotated by
- // SplitViewDragIndicatorsView.
- class SplitViewDragIndicators::RotatedImageLabelView : public views::View {
- public:
- explicit RotatedImageLabelView(bool is_right_or_bottom)
- : is_right_or_bottom_(is_right_or_bottom) {
- // TODO(sammiequon): Remove this extra intermediate layer.
- SetPaintToLayer(ui::LAYER_NOT_DRAWN);
- layer()->SetFillsBoundsOpaquely(false);
- // Use |label_parent_| to add padding and rounded edges to the text. Create
- // this extra view so that we can rotate the label, while having a slide
- // animation at times on the whole thing.
- label_parent_ = AddChildView(std::make_unique<views::View>());
- label_parent_->SetPaintToLayer(ui::LAYER_TEXTURED);
- label_parent_->layer()->SetFillsBoundsOpaquely(false);
- label_parent_->SetLayoutManager(std::make_unique<views::BoxLayout>(
- views::BoxLayout::Orientation::kVertical,
- gfx::Insets::VH(kSplitviewLabelVerticalInsetDp,
- kSplitviewLabelHorizontalInsetDp)));
- label_ = label_parent_->AddChildView(std::make_unique<views::Label>(
- std::u16string(), views::style::CONTEXT_LABEL));
- label_->SetFontList(views::Label::GetDefaultFontList().Derive(
- 2, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL));
- }
- RotatedImageLabelView(const RotatedImageLabelView&) = delete;
- RotatedImageLabelView& operator=(const RotatedImageLabelView&) = delete;
- ~RotatedImageLabelView() override = default;
- void SetLabelText(const std::u16string& text) { label_->SetText(text); }
- // Called when the view's bounds are altered. Rotates the view by |angle|
- // degrees.
- void OnBoundsUpdated(const gfx::Rect& bounds, double angle) {
- SetBoundsRect(bounds);
- label_parent_->SetBoundsRect(gfx::Rect(bounds.size()));
- label_parent_->SetTransform(
- ComputeRotateAroundCenterTransform(bounds, angle));
- }
- // Called to update the opacity of the labels view on |indicator_state|.
- void OnWindowDraggingStateChanged(
- WindowDraggingState window_dragging_state,
- WindowDraggingState previous_window_dragging_state,
- bool can_dragged_window_be_snapped) {
- // No top label for dragging from the top in portrait orientation.
- if (window_dragging_state == WindowDraggingState::kFromTop &&
- !IsCurrentScreenOrientationLandscape() && !is_right_or_bottom_) {
- return;
- }
- // If there is no drag currently in this display, any label that is showing
- // shall fade out with the corresponding indicator.
- if (window_dragging_state == WindowDraggingState::kNoDrag ||
- window_dragging_state == WindowDraggingState::kOtherDisplay) {
- DoSplitviewOpacityAnimation(
- layer(), SPLITVIEW_ANIMATION_TEXT_FADE_OUT_WITH_HIGHLIGHT);
- return;
- }
- // When a snap preview is shown, any label that is showing shall fade out.
- if (GetSnapPosition(window_dragging_state) != SplitViewController::NONE) {
- DoSplitviewOpacityAnimation(layer(), SPLITVIEW_ANIMATION_TEXT_FADE_OUT);
- return;
- }
- // Set the text according to |can_dragged_window_be_snapped|.
- SetLabelText(l10n_util::GetStringUTF16(
- can_dragged_window_be_snapped ? IDS_ASH_SPLIT_VIEW_GUIDANCE
- : IDS_ASH_SPLIT_VIEW_CANNOT_SNAP));
- // When dragging begins in this display or comes in from another display, if
- // there is now no snap preview, fade in with an indicator.
- if (previous_window_dragging_state == WindowDraggingState::kNoDrag ||
- previous_window_dragging_state == WindowDraggingState::kOtherDisplay) {
- DoSplitviewOpacityAnimation(
- layer(), SPLITVIEW_ANIMATION_TEXT_FADE_IN_WITH_HIGHLIGHT);
- return;
- }
- // If a snap preview was shown, the labels shall now fade in.
- if (GetSnapPosition(previous_window_dragging_state) !=
- SplitViewController::NONE) {
- DoSplitviewOpacityAnimation(layer(), SPLITVIEW_ANIMATION_TEXT_FADE_IN);
- return;
- }
- }
- // views:View:
- void OnThemeChanged() override {
- views::View::OnThemeChanged();
- label_parent_->SetBackground(views::CreateRoundedRectBackground(
- AshColorProvider::Get()->GetBaseLayerColor(
- AshColorProvider::BaseLayerType::kTransparent80),
- kSplitviewLabelRoundRectRadiusDp));
- // TODO(crbug/1258983): Add blur background. This requires fixing a bug
- // that `SetRoundedCornerRadius()` does not work with transform or find a
- // solution to work around.
- label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kTextColorPrimary));
- label_->SetBackgroundColor(AshColorProvider::Get()->GetBaseLayerColor(
- AshColorProvider::BaseLayerType::kTransparent80));
- label_->SetFontList(views::Label::GetDefaultFontList().Derive(
- 2, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL));
- if (chromeos::features::IsDarkLightModeEnabled()) {
- label_parent_->SetBorder(std::make_unique<views::HighlightBorder>(
- /*corner_radius=*/kSplitviewLabelRoundRectRadiusDp,
- views::HighlightBorder::Type::kHighlightBorder1,
- /*use_light_colors=*/false));
- }
- }
- protected:
- gfx::Size CalculatePreferredSize() const override {
- return label_parent_->GetPreferredSize();
- }
- private:
- // True if the label view is the right/bottom side one, false if it is the
- // left/top one.
- const bool is_right_or_bottom_;
- views::View* label_parent_ = nullptr;
- views::Label* label_ = nullptr;
- };
- // View which contains two highlights on each side indicator where a user should
- // drag a selected window in order to initiate splitview. Each highlight has a
- // label with instructions to further guide users. The highlights are on the
- // left and right of the display in landscape mode, and on the top and bottom of
- // the display in landscape mode. The highlights can expand and shrink if a
- // window has entered a snap region to display the bounds of the window, if it
- // were to get snapped.
- class SplitViewDragIndicators::SplitViewDragIndicatorsView
- : public views::View,
- public aura::WindowObserver {
- public:
- SplitViewDragIndicatorsView() {
- left_highlight_view_ = AddChildView(
- std::make_unique<SplitViewHighlightView>(/*is_right_or_bottom=*/false));
- right_highlight_view_ = AddChildView(
- std::make_unique<SplitViewHighlightView>(/*is_right_or_bottom=*/true));
- left_rotated_view_ = AddChildView(
- std::make_unique<RotatedImageLabelView>(/*is_right_or_bottom=*/false));
- right_rotated_view_ = AddChildView(
- std::make_unique<RotatedImageLabelView>(/*is_right_or_bottom=*/true));
- // Nothing is shown initially.
- left_highlight_view_->layer()->SetOpacity(0.f);
- right_highlight_view_->layer()->SetOpacity(0.f);
- left_rotated_view_->layer()->SetOpacity(0.f);
- right_rotated_view_->layer()->SetOpacity(0.f);
- }
- SplitViewDragIndicatorsView(const SplitViewDragIndicatorsView&) = delete;
- SplitViewDragIndicatorsView& operator=(const SplitViewDragIndicatorsView&) =
- delete;
- ~SplitViewDragIndicatorsView() override {
- if (dragged_window_)
- dragged_window_->RemoveObserver(this);
- }
- SplitViewHighlightView* left_highlight_view() { return left_highlight_view_; }
- // Called by parent widget when the state machine changes. Handles setting the
- // opacity and bounds of the highlights and labels.
- void OnWindowDraggingStateChanged(WindowDraggingState window_dragging_state) {
- DCHECK_NE(window_dragging_state_, window_dragging_state);
- previous_window_dragging_state_ = window_dragging_state_;
- window_dragging_state_ = window_dragging_state;
- SplitViewController* split_view_controller =
- SplitViewController::Get(GetWidget()->GetNativeWindow());
- const bool previews_only =
- window_dragging_state == WindowDraggingState::kFromShelf ||
- window_dragging_state == WindowDraggingState::kFromTop ||
- split_view_controller->InSplitViewMode();
- const bool can_dragged_window_be_snapped =
- dragged_window_ &&
- split_view_controller->CanSnapWindow(dragged_window_);
- if (!previews_only) {
- left_rotated_view_->OnWindowDraggingStateChanged(
- window_dragging_state, previous_window_dragging_state_,
- can_dragged_window_be_snapped);
- right_rotated_view_->OnWindowDraggingStateChanged(
- window_dragging_state, previous_window_dragging_state_,
- can_dragged_window_be_snapped);
- }
- left_highlight_view_->OnWindowDraggingStateChanged(
- window_dragging_state, previous_window_dragging_state_, previews_only,
- can_dragged_window_be_snapped);
- right_highlight_view_->OnWindowDraggingStateChanged(
- window_dragging_state, previous_window_dragging_state_, previews_only,
- can_dragged_window_be_snapped);
- if (window_dragging_state != WindowDraggingState::kNoDrag ||
- GetSnapPosition(previous_window_dragging_state_) !=
- SplitViewController::NONE) {
- Layout(previous_window_dragging_state_ != WindowDraggingState::kNoDrag);
- }
- }
- views::View* GetViewForIndicatorType(IndicatorType type) {
- switch (type) {
- case IndicatorType::kLeftHighlight:
- return left_highlight_view_;
- case IndicatorType::kLeftText:
- return left_rotated_view_;
- case IndicatorType::kRightHighlight:
- return right_highlight_view_;
- case IndicatorType::kRightText:
- return right_rotated_view_;
- }
- NOTREACHED();
- return nullptr;
- }
- void SetDraggedWindow(aura::Window* dragged_window) {
- if (dragged_window_)
- dragged_window_->RemoveObserver(this);
- dragged_window_ = dragged_window;
- if (dragged_window)
- dragged_window->AddObserver(this);
- }
- // views::View:
- void Layout() override { Layout(/*animate=*/false); }
- // aura::WindowObserver:
- void OnWindowDestroyed(aura::Window* window) override {
- DCHECK_EQ(dragged_window_, window);
- dragged_window_ = nullptr;
- }
- private:
- // Layout the bounds of the highlight views and helper labels. One should
- // animate when changing states, but not when bounds or orientation is
- // changed.
- void Layout(bool animate) {
- // TODO(xdai|afakhry): Attempt to simplify this logic.
- const bool horizontal =
- SplitViewController::IsLayoutHorizontal(GetWidget()->GetNativeWindow());
- const int display_width = horizontal ? width() : height();
- const int display_height = horizontal ? height() : width();
- // Calculate the bounds of the two highlight regions.
- const int highlight_width =
- display_width * kHighlightScreenPrimaryAxisRatio;
- const int highlight_height =
- display_height - 2 * kHighlightScreenEdgePaddingDp;
- gfx::Size highlight_size(highlight_width, highlight_height);
- // When one highlight expands to become a preview area, the other highlight
- // contracts to this width.
- const int other_highlight_width =
- display_width * kOtherHighlightScreenPrimaryAxisRatio;
- // The origin of the right highlight view in horizontal split view layout,
- // or the bottom highlight view in vertical split view layout.
- gfx::Point right_bottom_origin(
- display_width - highlight_width - kHighlightScreenEdgePaddingDp,
- kHighlightScreenEdgePaddingDp);
- const gfx::Point highlight_padding_point(kHighlightScreenEdgePaddingDp,
- kHighlightScreenEdgePaddingDp);
- gfx::Rect left_highlight_bounds(highlight_padding_point, highlight_size);
- gfx::Rect right_highlight_bounds(right_bottom_origin, highlight_size);
- if (!horizontal) {
- left_highlight_bounds.Transpose();
- right_highlight_bounds.Transpose();
- }
- // True when the drag ends in a snap area, meaning that the dragged window
- // actually becomes snapped.
- const bool drag_ending_in_snap =
- window_dragging_state_ == WindowDraggingState::kNoDrag &&
- GetSnapPosition(previous_window_dragging_state_) !=
- SplitViewController::NONE;
- SplitViewController::SnapPosition snap_position =
- GetSnapPosition(window_dragging_state_);
- if (snap_position == SplitViewController::NONE)
- snap_position = GetSnapPosition(previous_window_dragging_state_);
- gfx::Rect preview_area_bounds;
- absl::optional<SplitviewAnimationType> left_highlight_animation_type;
- absl::optional<SplitviewAnimationType> right_highlight_animation_type;
- if (GetSnapPosition(window_dragging_state_) != SplitViewController::NONE ||
- drag_ending_in_snap) {
- // Get the preview area bounds from the split view controller.
- preview_area_bounds =
- SplitViewController::Get(GetWidget()->GetNativeWindow())
- ->GetSnappedWindowBoundsInScreen(snap_position, dragged_window_);
- aura::Window* root_window =
- GetWidget()->GetNativeWindow()->GetRootWindow();
- wm::ConvertRectFromScreen(root_window, &preview_area_bounds);
- // Preview area should have no overlap with the shelf.
- preview_area_bounds.Subtract(
- Shelf::ForWindow(root_window)->GetIdealBounds());
- gfx::Rect work_area_bounds =
- GetWorkAreaBoundsNoOverlapWithShelf(root_window);
- wm::ConvertRectFromScreen(root_window, &work_area_bounds);
- preview_area_bounds.set_y(preview_area_bounds.y() - work_area_bounds.y());
- if (!drag_ending_in_snap)
- preview_area_bounds.Inset(kHighlightScreenEdgePaddingDp);
- // Calculate the bounds of the other highlight, which is the one that
- // shrinks and fades away, while the other one, the preview area, expands
- // and takes up half the screen.
- gfx::Rect other_bounds(
- display_width - other_highlight_width - kHighlightScreenEdgePaddingDp,
- kHighlightScreenEdgePaddingDp, other_highlight_width,
- display_height - 2 * kHighlightScreenEdgePaddingDp);
- if (!horizontal)
- other_bounds.Transpose();
- if (SplitViewController::IsPhysicalLeftOrTop(snap_position,
- dragged_window_)) {
- left_highlight_bounds = preview_area_bounds;
- right_highlight_bounds = other_bounds;
- if (animate) {
- if (drag_ending_in_snap) {
- left_highlight_animation_type =
- SPLITVIEW_ANIMATION_PREVIEW_AREA_NIX_INSET;
- } else {
- left_highlight_animation_type =
- SPLITVIEW_ANIMATION_PREVIEW_AREA_SLIDE_IN;
- right_highlight_animation_type =
- SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_SLIDE_OUT;
- }
- }
- } else {
- other_bounds.set_origin(highlight_padding_point);
- left_highlight_bounds = other_bounds;
- right_highlight_bounds = preview_area_bounds;
- if (animate) {
- if (drag_ending_in_snap) {
- right_highlight_animation_type =
- SPLITVIEW_ANIMATION_PREVIEW_AREA_NIX_INSET;
- } else {
- left_highlight_animation_type =
- SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_SLIDE_OUT;
- right_highlight_animation_type =
- SPLITVIEW_ANIMATION_PREVIEW_AREA_SLIDE_IN;
- }
- }
- }
- } else if (GetSnapPosition(previous_window_dragging_state_) !=
- SplitViewController::NONE &&
- animate) {
- if (SplitViewController::IsPhysicalLeftOrTop(snap_position,
- dragged_window_)) {
- left_highlight_animation_type =
- SPLITVIEW_ANIMATION_PREVIEW_AREA_SLIDE_OUT;
- right_highlight_animation_type =
- SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_SLIDE_IN;
- } else {
- left_highlight_animation_type =
- SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_SLIDE_IN;
- right_highlight_animation_type =
- SPLITVIEW_ANIMATION_PREVIEW_AREA_SLIDE_OUT;
- }
- }
- left_highlight_view_->SetBounds(GetMirroredRect(left_highlight_bounds),
- left_highlight_animation_type);
- right_highlight_view_->SetBounds(GetMirroredRect(right_highlight_bounds),
- right_highlight_animation_type);
- // Calculate the bounds of the views which contain the guidance text and
- // icon. Rotate the two views in horizontal split view layout.
- const gfx::Size size(right_rotated_view_->GetPreferredSize().width(),
- kSplitviewLabelPreferredHeightDp);
- if (!horizontal)
- highlight_size.SetSize(highlight_size.height(), highlight_size.width());
- gfx::Rect left_rotated_bounds(
- highlight_size.width() / 2 - size.width() / 2,
- highlight_size.height() / 2 - size.height() / 2, size.width(),
- size.height());
- gfx::Rect right_rotated_bounds = left_rotated_bounds;
- left_rotated_bounds.Offset(highlight_padding_point.x(),
- highlight_padding_point.y());
- if (!horizontal) {
- right_bottom_origin.SetPoint(right_bottom_origin.y(),
- right_bottom_origin.x());
- }
- right_rotated_bounds.Offset(right_bottom_origin.x(),
- right_bottom_origin.y());
- // In portrait mode, there is no need to rotate the text and warning icon.
- // In horizontal split view layout, rotate the left text 90 degrees
- // clockwise in rtl and 90 degress anti clockwise in ltr. The right text is
- // rotated 90 degrees in the opposite direction of the left text.
- double left_rotation_angle = 0.0;
- if (horizontal)
- left_rotation_angle = 90.0 * (base::i18n::IsRTL() ? 1 : -1);
- left_rotated_view_->OnBoundsUpdated(left_rotated_bounds,
- /*angle=*/left_rotation_angle);
- right_rotated_view_->OnBoundsUpdated(right_rotated_bounds,
- /*angle=*/-left_rotation_angle);
- if (drag_ending_in_snap) {
- // Reset the label transforms, in preparation for the next drag (if any).
- left_rotated_view_->layer()->SetTransform(gfx::Transform());
- right_rotated_view_->layer()->SetTransform(gfx::Transform());
- return;
- }
- ui::Layer* preview_label_layer;
- ui::Layer* other_highlight_label_layer;
- if (snap_position == SplitViewController::NONE) {
- preview_label_layer = nullptr;
- other_highlight_label_layer = nullptr;
- } else if (SplitViewController::IsPhysicalLeftOrTop(snap_position,
- dragged_window_)) {
- preview_label_layer = left_rotated_view_->layer();
- other_highlight_label_layer = right_rotated_view_->layer();
- } else {
- preview_label_layer = right_rotated_view_->layer();
- other_highlight_label_layer = left_rotated_view_->layer();
- }
- // Slide out the labels when a snap preview appears. This code also adjusts
- // the label transforms for things like display rotation while there is a
- // snap preview.
- if (GetSnapPosition(window_dragging_state_) != SplitViewController::NONE) {
- // How far each label shall slide to stay centered in the corresponding
- // highlight as it expands/contracts. Include distance traveled with zero
- // opacity (whence a label still slides, not only for simplicity in
- // calculating the values below, but also to facilitate that the label
- // transform and the highlight transform have matching easing).
- const float preview_label_distance =
- 0.5f * (preview_area_bounds.width() - highlight_width);
- const float other_highlight_label_distance =
- 0.5f * (highlight_width - other_highlight_width);
- // Positive for right or down; negative for left or up.
- float preview_label_delta, other_highlight_label_delta;
- if (SplitViewController::IsPhysicalLeftOrTop(snap_position,
- dragged_window_)) {
- preview_label_delta = preview_label_distance;
- other_highlight_label_delta = other_highlight_label_distance;
- } else {
- preview_label_delta = -preview_label_distance;
- other_highlight_label_delta = -other_highlight_label_distance;
- }
- // x-axis if |horizontal|; else y-axis.
- gfx::Transform preview_label_transform, other_highlight_label_transform;
- if (horizontal) {
- preview_label_transform.Translate(preview_label_delta, 0.f);
- other_highlight_label_transform.Translate(other_highlight_label_delta,
- 0.f);
- } else {
- preview_label_transform.Translate(0.f, preview_label_delta);
- other_highlight_label_transform.Translate(0.f,
- other_highlight_label_delta);
- }
- if (animate) {
- // Animate the labels sliding out.
- DoSplitviewTransformAnimation(
- preview_label_layer,
- SPLITVIEW_ANIMATION_PREVIEW_AREA_TEXT_SLIDE_OUT,
- preview_label_transform, /*animation_observers=*/{});
- DoSplitviewTransformAnimation(
- other_highlight_label_layer,
- SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_TEXT_SLIDE_OUT,
- other_highlight_label_transform, /*animation_observers=*/{});
- } else {
- // Put the labels where they belong.
- preview_label_layer->SetTransform(preview_label_transform);
- other_highlight_label_layer->SetTransform(
- other_highlight_label_transform);
- }
- return;
- }
- // Slide in the labels when a snap preview disappears because you drag
- // inward. (Having reached this code, we know that the window is not
- // becoming snapped, because that case is handled earlier and we bail out.)
- if (GetSnapPosition(previous_window_dragging_state_) !=
- SplitViewController::NONE) {
- if (animate) {
- // Animate the labels sliding in.
- DoSplitviewTransformAnimation(
- preview_label_layer, SPLITVIEW_ANIMATION_PREVIEW_AREA_TEXT_SLIDE_IN,
- gfx::Transform(), /*animation_observers=*/{});
- DoSplitviewTransformAnimation(
- other_highlight_label_layer,
- SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_TEXT_SLIDE_IN, gfx::Transform(),
- /*animation_observers=*/{});
- } else {
- // Put the labels where they belong.
- preview_label_layer->SetTransform(gfx::Transform());
- other_highlight_label_layer->SetTransform(gfx::Transform());
- }
- return;
- }
- }
- SplitViewHighlightView* left_highlight_view_ = nullptr;
- SplitViewHighlightView* right_highlight_view_ = nullptr;
- RotatedImageLabelView* left_rotated_view_ = nullptr;
- RotatedImageLabelView* right_rotated_view_ = nullptr;
- WindowDraggingState window_dragging_state_ = WindowDraggingState::kNoDrag;
- WindowDraggingState previous_window_dragging_state_ =
- WindowDraggingState::kNoDrag;
- aura::Window* dragged_window_ = nullptr;
- };
- SplitViewDragIndicators::SplitViewDragIndicators(aura::Window* root_window) {
- widget_ = CreateWidget(root_window);
- widget_->SetBounds(GetWorkAreaBoundsNoOverlapWithShelf(root_window));
- indicators_view_ =
- widget_->SetContentsView(std::make_unique<SplitViewDragIndicatorsView>());
- widget_->Show();
- }
- SplitViewDragIndicators::~SplitViewDragIndicators() {
- // Allow some extra time for animations to finish.
- aura::Window* window = widget_->GetNativeWindow();
- if (window == nullptr)
- return;
- wm::SetWindowVisibilityAnimationType(
- window, WINDOW_VISIBILITY_ANIMATION_TYPE_STEP_END);
- AnimateOnChildWindowVisibilityChanged(window, /*visible=*/false);
- }
- void SplitViewDragIndicators::SetDraggedWindow(aura::Window* dragged_window) {
- DCHECK_EQ(WindowDraggingState::kNoDrag, current_window_dragging_state_);
- indicators_view_->SetDraggedWindow(dragged_window);
- }
- void SplitViewDragIndicators::SetWindowDraggingState(
- WindowDraggingState window_dragging_state) {
- if (window_dragging_state == current_window_dragging_state_)
- return;
- // Fire a haptic event if necessary.
- if (GetSnapPosition(window_dragging_state) != SplitViewController::NONE) {
- OverviewController* overview_controller =
- Shell::Get()->overview_controller();
- if (overview_controller->InOverviewSession() &&
- overview_controller->overview_session()->window_drag_controller() &&
- !overview_controller->overview_session()
- ->window_drag_controller()
- ->is_touch_dragging()) {
- haptics_util::PlayHapticTouchpadEffect(
- ui::HapticTouchpadEffect::kSnap,
- ui::HapticTouchpadEffectStrength::kMedium);
- }
- }
- current_window_dragging_state_ = window_dragging_state;
- indicators_view_->OnWindowDraggingStateChanged(window_dragging_state);
- }
- void SplitViewDragIndicators::OnDisplayBoundsChanged() {
- aura::Window* root_window = widget_->GetNativeView()->GetRootWindow();
- widget_->SetBounds(GetWorkAreaBoundsNoOverlapWithShelf(root_window));
- }
- bool SplitViewDragIndicators::GetIndicatorTypeVisibilityForTesting(
- IndicatorType type) const {
- return indicators_view_->GetViewForIndicatorType(type)->layer()->opacity() >
- 0.f;
- }
- gfx::Rect SplitViewDragIndicators::GetLeftHighlightViewBounds() const {
- return indicators_view_->left_highlight_view()->bounds();
- }
- } // namespace ash
|