1 // Copyright 2020 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 
5 #include "ash/system/accessibility/floating_menu_utils.h"
6 
7 #include "ash/public/cpp/accessibility_controller_enums.h"
8 #include "ash/shell.h"
9 #include "ash/wm/collision_detection/collision_detection_utils.h"
10 #include "ash/wm/work_area_insets.h"
11 #include "base/i18n/rtl.h"
12 
13 namespace ash {
14 
DefaultSystemFloatingMenuPosition()15 FloatingMenuPosition DefaultSystemFloatingMenuPosition() {
16   return base::i18n::IsRTL() ? FloatingMenuPosition::kBottomLeft
17                              : FloatingMenuPosition::kBottomRight;
18 }
19 
GetOnScreenBoundsForFloatingMenuPosition(const gfx::Size & menu_bounds,FloatingMenuPosition position)20 gfx::Rect GetOnScreenBoundsForFloatingMenuPosition(
21     const gfx::Size& menu_bounds,
22     FloatingMenuPosition position) {
23   // Calculates the ideal bounds.
24   aura::Window* window = Shell::GetPrimaryRootWindow();
25   gfx::Rect work_area =
26       WorkAreaInsets::ForWindow(window)->user_work_area_bounds();
27 
28   switch (position) {
29     case FloatingMenuPosition::kBottomRight:
30       return gfx::Rect(work_area.right() - menu_bounds.width(),
31                        work_area.bottom() - menu_bounds.height(),
32                        menu_bounds.width(), menu_bounds.height());
33     case FloatingMenuPosition::kBottomLeft:
34       return gfx::Rect(work_area.x(), work_area.bottom() - menu_bounds.height(),
35                        menu_bounds.width(), menu_bounds.height());
36     case FloatingMenuPosition::kTopLeft:
37       // Because there is no inset at the top of the widget, add
38       // 2 * kCollisionWindowWorkAreaInsetsDp to the top of the work area.
39       // to ensure correct padding.
40       return gfx::Rect(work_area.x(),
41                        work_area.y() + 2 * kCollisionWindowWorkAreaInsetsDp,
42                        menu_bounds.width(), menu_bounds.height());
43     case FloatingMenuPosition::kTopRight:
44       // Because there is no inset at the top of the widget, add
45       // 2 * kCollisionWindowWorkAreaInsetsDp to the top of the work area.
46       // to ensure correct padding.
47       return gfx::Rect(work_area.right() - menu_bounds.width(),
48                        work_area.y() + 2 * kCollisionWindowWorkAreaInsetsDp,
49                        menu_bounds.width(), menu_bounds.height());
50     case FloatingMenuPosition::kSystemDefault:
51       NOTREACHED();
52       return gfx::Rect();
53   }
54 }
55 
GetAnchorAlignmentForFloatingMenuPosition(FloatingMenuPosition position)56 views::BubbleBorder::Arrow GetAnchorAlignmentForFloatingMenuPosition(
57     FloatingMenuPosition position) {
58   // If this is the default system position, pick the position based on the
59   // language direction.
60   if (position == FloatingMenuPosition::kSystemDefault) {
61     position = DefaultSystemFloatingMenuPosition();
62   }
63   // Mirror arrow in RTL languages so that it always stays near the screen
64   // edge.
65   switch (position) {
66     case FloatingMenuPosition::kBottomLeft:
67       return base::i18n::IsRTL() ? views::BubbleBorder::Arrow::TOP_RIGHT
68                                  : views::BubbleBorder::Arrow::TOP_LEFT;
69     case FloatingMenuPosition::kTopLeft:
70       return base::i18n::IsRTL() ? views::BubbleBorder::Arrow::BOTTOM_RIGHT
71                                  : views::BubbleBorder::Arrow::BOTTOM_LEFT;
72     case FloatingMenuPosition::kBottomRight:
73       return base::i18n::IsRTL() ? views::BubbleBorder::Arrow::TOP_LEFT
74                                  : views::BubbleBorder::Arrow::TOP_RIGHT;
75     case FloatingMenuPosition::kTopRight:
76       return base::i18n::IsRTL() ? views::BubbleBorder::Arrow::BOTTOM_LEFT
77                                  : views::BubbleBorder::Arrow::BOTTOM_RIGHT;
78     case FloatingMenuPosition::kSystemDefault:
79       // It's not possible for position to be kSystemDefault here because we've
80       // set it via DefaultSystemPosition() above if it was kSystemDefault.
81       NOTREACHED();
82       return views::BubbleBorder::Arrow::TOP_LEFT;
83   }
84 }
85 
86 }  // namespace ash
87