split_view_highlight_view.cc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Copyright 2018 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. #include "ash/wm/splitview/split_view_highlight_view.h"
  5. #include "ash/display/screen_orientation_controller.h"
  6. #include "ash/shell.h"
  7. #include "ash/style/ash_color_provider.h"
  8. #include "ash/wm/splitview/split_view_controller.h"
  9. #include "base/i18n/rtl.h"
  10. #include "ui/compositor/layer.h"
  11. #include "ui/compositor/layer_type.h"
  12. #include "ui/gfx/geometry/rounded_corners_f.h"
  13. #include "ui/views/background.h"
  14. #include "ui/views/highlight_border.h"
  15. #include "ui/views/view.h"
  16. #include "ui/views/view_observer.h"
  17. #include "ui/views/widget/widget.h"
  18. namespace ash {
  19. namespace {
  20. // The amount of round applied to the corners of the highlight views.
  21. constexpr int kHighlightScreenRoundRectRadius = 4;
  22. // Self deleting animation observer that removes clipping on View's layer and
  23. // optionally sets bounds after the animation ends.
  24. class ClippingObserver : public ui::ImplicitAnimationObserver,
  25. public views::ViewObserver {
  26. public:
  27. ClippingObserver(views::View* view, absl::optional<gfx::Rect> bounds)
  28. : view_(view), bounds_(bounds) {
  29. view_->AddObserver(this);
  30. }
  31. ~ClippingObserver() override { view_->RemoveObserver(this); }
  32. // ui::ImplicitAnimationObserver:
  33. void OnImplicitAnimationsCompleted() override {
  34. view_->layer()->SetClipRect(gfx::Rect());
  35. if (bounds_)
  36. view_->SetBoundsRect(*bounds_);
  37. delete this;
  38. }
  39. // views::ViewObserver:
  40. void OnViewIsDeleting(views::View* observed_view) override {
  41. DCHECK_EQ(view_, observed_view);
  42. delete this;
  43. }
  44. private:
  45. views::View* const view_;
  46. absl::optional<gfx::Rect> bounds_;
  47. };
  48. } // namespace
  49. SplitViewHighlightView::SplitViewHighlightView(bool is_right_or_bottom)
  50. : is_right_or_bottom_(is_right_or_bottom) {
  51. SetPaintToLayer(ui::LAYER_TEXTURED);
  52. SetBackground(views::CreateRoundedRectBackground(
  53. AshColorProvider::Get()->GetBackgroundColor(),
  54. kHighlightScreenRoundRectRadius));
  55. layer()->SetFillsBoundsOpaquely(false);
  56. layer()->SetRoundedCornerRadius(
  57. gfx::RoundedCornersF{kHighlightScreenRoundRectRadius});
  58. layer()->SetIsFastRoundedCorner(true);
  59. }
  60. SplitViewHighlightView::~SplitViewHighlightView() = default;
  61. void SplitViewHighlightView::OnThemeChanged() {
  62. views::View::OnThemeChanged();
  63. background()->SetNativeControlColor(
  64. AshColorProvider::Get()->GetBackgroundColor());
  65. if (chromeos::features::IsDarkLightModeEnabled()) {
  66. SetBorder(std::make_unique<views::HighlightBorder>(
  67. kHighlightScreenRoundRectRadius,
  68. views::HighlightBorder::Type::kHighlightBorder1,
  69. /*use_light_colors=*/false));
  70. }
  71. }
  72. void SplitViewHighlightView::SetBounds(
  73. const gfx::Rect& bounds,
  74. const absl::optional<SplitviewAnimationType>& animation_type) {
  75. if (bounds == this->bounds())
  76. return;
  77. if (!animation_type) {
  78. SetBoundsRect(bounds);
  79. return;
  80. }
  81. const gfx::Rect old_bounds = this->bounds();
  82. // Note: This is passed on the assumption that the highlights either.
  83. // 1) Slide out - x or y increases and other dimension stays the same.
  84. // 2) Slide in - x or y decreases and other dimension stays the same.
  85. // 3) Expands(Nix inset) - x and y both increase by a small amount.
  86. const bool grows = bounds.size().GetArea() > old_bounds.size().GetArea();
  87. // If the highlight grows, set the final bounds and clip the rect to the
  88. // current bounds and animate. Otherwise, start the clip animation and set the
  89. // bounds after the animation is complete.
  90. if (grows)
  91. SetBoundsRect(bounds);
  92. // The origin of the clip rect needs to be shifted depending on whether we are
  93. // growing or shrinking for right/bottom views since their animations are
  94. // mirrored.
  95. gfx::Point start_origin, end_origin;
  96. const bool nix_animation =
  97. *animation_type == SPLITVIEW_ANIMATION_PREVIEW_AREA_NIX_INSET;
  98. if (is_right_or_bottom_ || nix_animation) {
  99. gfx::Vector2d clip_offset = bounds.origin() - old_bounds.origin();
  100. // Make sure a widget exists because the test might not add it.
  101. DCHECK(GetWidget());
  102. // RTL is a special case since for the right highlight we will receive a
  103. // mirrored rect whose origin will not change. In this case the clip rect
  104. // offset should be the change in width. Portrait mode does not care since
  105. // it is unaffected by RTL and the nix inset animation will supply the
  106. // current bounds offset.
  107. if (base::i18n::IsRTL() &&
  108. SplitViewController::IsLayoutHorizontal(
  109. GetWidget()->GetNativeWindow()) &&
  110. !nix_animation) {
  111. clip_offset = gfx::Vector2d(bounds.width() - old_bounds.width(), 0);
  112. }
  113. clip_offset.set_x(std::abs(clip_offset.x()));
  114. clip_offset.set_y(std::abs(clip_offset.y()));
  115. if (grows)
  116. start_origin += clip_offset;
  117. else
  118. end_origin += clip_offset;
  119. }
  120. layer()->SetClipRect(gfx::Rect(start_origin, old_bounds.size()));
  121. DoSplitviewClipRectAnimation(
  122. layer(), *animation_type, gfx::Rect(end_origin, bounds.size()),
  123. std::make_unique<ClippingObserver>(
  124. this, grows ? absl::nullopt : absl::make_optional(bounds)));
  125. }
  126. void SplitViewHighlightView::OnWindowDraggingStateChanged(
  127. SplitViewDragIndicators::WindowDraggingState window_dragging_state,
  128. SplitViewDragIndicators::WindowDraggingState previous_window_dragging_state,
  129. bool previews_only,
  130. bool can_dragged_window_be_snapped) {
  131. // No top indicator for dragging from the top in portrait orientation.
  132. if (window_dragging_state ==
  133. SplitViewDragIndicators::WindowDraggingState::kFromTop &&
  134. !IsCurrentScreenOrientationLandscape() && !is_right_or_bottom_) {
  135. return;
  136. }
  137. if (window_dragging_state ==
  138. SplitViewDragIndicators::WindowDraggingState::kOtherDisplay) {
  139. DoSplitviewOpacityAnimation(layer(),
  140. SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT);
  141. return;
  142. }
  143. const SplitViewController::SnapPosition preview_position =
  144. SplitViewDragIndicators::GetSnapPosition(window_dragging_state);
  145. const SplitViewController::SnapPosition previous_preview_position =
  146. SplitViewDragIndicators::GetSnapPosition(previous_window_dragging_state);
  147. aura::Window* window = GetWidget()->GetNativeWindow();
  148. if (window_dragging_state ==
  149. SplitViewDragIndicators::WindowDraggingState::kNoDrag) {
  150. if (previous_preview_position == SplitViewController::NONE) {
  151. DoSplitviewOpacityAnimation(layer(),
  152. SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT);
  153. return;
  154. }
  155. if (is_right_or_bottom_ != SplitViewController::IsPhysicalLeftOrTop(
  156. previous_preview_position, window)) {
  157. DoSplitviewOpacityAnimation(layer(),
  158. SPLITVIEW_ANIMATION_PREVIEW_AREA_FADE_OUT);
  159. }
  160. return;
  161. }
  162. background()->SetNativeControlColor(
  163. AshColorProvider::Get()->GetBackgroundColor());
  164. if (chromeos::features::IsDarkLightModeEnabled()) {
  165. SetBorder(std::make_unique<views::HighlightBorder>(
  166. kHighlightScreenRoundRectRadius,
  167. views::HighlightBorder::Type::kHighlightBorder1,
  168. /*use_light_colors=*/false));
  169. }
  170. if (preview_position != SplitViewController::NONE) {
  171. DoSplitviewOpacityAnimation(
  172. layer(),
  173. is_right_or_bottom_ != SplitViewController::IsPhysicalLeftOrTop(
  174. preview_position, window)
  175. ? SPLITVIEW_ANIMATION_PREVIEW_AREA_FADE_IN
  176. : SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_FADE_OUT);
  177. return;
  178. }
  179. if (previous_preview_position != SplitViewController::NONE) {
  180. // There was a snap preview showing, but now the user has dragged away from
  181. // the edge of the screen, so that the preview should go away.
  182. if (is_right_or_bottom_ != SplitViewController::IsPhysicalLeftOrTop(
  183. previous_preview_position, window)) {
  184. // This code is for the preview. If |previews_only|, just fade out. Else
  185. // fade in from |kPreviewAreaHighlightOpacity| to |kHighlightOpacity|.
  186. DoSplitviewOpacityAnimation(
  187. layer(),
  188. previews_only
  189. ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_OUT
  190. : can_dragged_window_be_snapped
  191. ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN
  192. : SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN_CANNOT_SNAP);
  193. } else {
  194. // This code is for the other highlight. If |previews_only|, just stay
  195. // hidden (in other words, do nothing). Else fade in.
  196. DCHECK_EQ(0.f, layer()->GetTargetOpacity());
  197. if (!previews_only) {
  198. DoSplitviewOpacityAnimation(
  199. layer(),
  200. can_dragged_window_be_snapped
  201. ? SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_FADE_IN
  202. : SPLITVIEW_ANIMATION_OTHER_HIGHLIGHT_FADE_IN_CANNOT_SNAP);
  203. }
  204. }
  205. return;
  206. }
  207. // The drag just started or came in from another display, and is not currently
  208. // in a snap area. If |previews_only|, there is nothing to do. Else fade in.
  209. DCHECK_EQ(0.f, layer()->GetTargetOpacity());
  210. if (!previews_only) {
  211. DoSplitviewOpacityAnimation(
  212. layer(), can_dragged_window_be_snapped
  213. ? SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN
  214. : SPLITVIEW_ANIMATION_HIGHLIGHT_FADE_IN_CANNOT_SNAP);
  215. return;
  216. }
  217. }
  218. } // namespace ash