blob: 03afc139d3e97510ea8be739282bf3b8baae400e [file] [log] [blame]
// 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 "chrome/browser/chromeos/accessibility/switch_access_panel.h"
#include "ash/public/interfaces/accessibility_controller.mojom.h"
#include "ash/public/interfaces/constants.mojom.h"
#include "base/no_destructor.h"
#include "content/public/common/service_manager_connection.h"
#include "services/service_manager/public/cpp/connector.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/views/widget/widget.h"
namespace {
const char kWidgetName[] = "SwitchAccessMenu";
const int kFocusRingBuffer = 5;
const std::string& UrlForContent() {
static const base::NoDestructor<std::string> url(
std::string(EXTENSION_PREFIX) + extension_misc::kSwitchAccessExtensionId +
"/menu_panel.html");
return *url;
}
} // namespace
SwitchAccessPanel::SwitchAccessPanel(content::BrowserContext* browser_context)
: AccessibilityPanel(browser_context, UrlForContent(), kWidgetName) {
Hide();
}
void SwitchAccessPanel::Show(const gfx::Rect& element_bounds,
int width,
int height,
bool back_button_only) {
// TODO(crbug/893752): Support multiple displays
gfx::Rect screen_bounds =
display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
gfx::Rect panel_bounds;
if (back_button_only) {
int x = element_bounds.right();
int y = element_bounds.y() - height;
panel_bounds.SetRect(x, y, width, height);
panel_bounds.AdjustToFit(screen_bounds);
} else {
panel_bounds =
CalculatePanelBounds(element_bounds, screen_bounds, width, height);
}
GetAccessibilityController()->SetAccessibilityPanelBounds(
panel_bounds, ash::mojom::AccessibilityPanelState::BOUNDED);
}
void SwitchAccessPanel::Hide() {
// This isn't set to (0, 0, 0, 0) because the drop shadow remains visible.
// TODO(crbug/911344): Find the root cause and fix it.
gfx::Rect bounds(-1, -1, 1, 1);
GetAccessibilityController()->SetAccessibilityPanelBounds(
bounds, ash::mojom::AccessibilityPanelState::BOUNDED);
}
const gfx::Rect SwitchAccessPanel::CalculatePanelBounds(
const gfx::Rect& element_bounds,
const gfx::Rect& screen_bounds,
const int panel_width,
const int panel_height) {
gfx::Rect padded_element_bounds = element_bounds;
padded_element_bounds.Inset(-GetFocusRingBuffer(), -GetFocusRingBuffer());
// Decide if the horizontal position should be to the right of the element, to
// the left of the element, or if neither is possible, against the right edge
// of the screen.
int panel_x = padded_element_bounds.right();
if (padded_element_bounds.right() + panel_width > screen_bounds.right()) {
if (padded_element_bounds.x() - panel_width > screen_bounds.x())
panel_x = padded_element_bounds.x() - panel_width;
else
panel_x = screen_bounds.right() - panel_width;
}
// Decide if the vertical position should be below the element, above the
// element, or if neither is possible, against the bottom edge of the screen.
int panel_y = padded_element_bounds.bottom();
if (padded_element_bounds.bottom() + panel_height > screen_bounds.bottom()) {
if (padded_element_bounds.y() - panel_height > screen_bounds.y())
panel_y = padded_element_bounds.y() - panel_height;
else
panel_y = screen_bounds.bottom() - panel_height;
}
return gfx::Rect(panel_x, panel_y, panel_width, panel_height);
}
int SwitchAccessPanel::GetFocusRingBuffer() {
return kFocusRingBuffer;
}