| // Copyright 2020 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/system/accessibility/select_to_speak_menu_bubble_controller.h" |
| |
| #include "ash/accessibility/accessibility_controller_impl.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/system/accessibility/floating_menu_utils.h" |
| #include "ash/system/accessibility/select_to_speak_constants.h" |
| #include "ash/system/tray/tray_background_view.h" |
| #include "ash/system/tray/tray_constants.h" |
| #include "ash/system/unified/unified_system_tray_view.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/wm/public/activation_client.h" |
| |
| namespace ash { |
| |
| namespace { |
| const int kAnchorRectVerticalSpacing = 12; |
| const int kPreferredWidth = 368; |
| } // namespace |
| |
| SelectToSpeakMenuBubbleController::SelectToSpeakMenuBubbleController() { |
| Shell::Get()->activation_client()->AddObserver(this); |
| } |
| |
| SelectToSpeakMenuBubbleController::~SelectToSpeakMenuBubbleController() { |
| Shell::Get()->activation_client()->RemoveObserver(this); |
| if (bubble_widget_ && !bubble_widget_->IsClosed()) |
| bubble_widget_->CloseNow(); |
| } |
| |
| void SelectToSpeakMenuBubbleController::Show(const gfx::Rect& anchor, |
| bool is_paused, |
| double initial_speech_rate) { |
| initial_speech_rate_ = initial_speech_rate; |
| if (!bubble_widget_) { |
| TrayBubbleView::InitParams init_params; |
| init_params.delegate = this; |
| init_params.parent_window = |
| Shell::GetContainer(Shell::GetPrimaryRootWindow(), |
| kShellWindowId_AccessibilityBubbleContainer); |
| init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect; |
| init_params.is_anchored_to_status_area = false; |
| init_params.insets = gfx::Insets(kUnifiedMenuPadding, kUnifiedMenuPadding); |
| init_params.corner_radius = kUnifiedTrayCornerRadius; |
| init_params.has_shadow = false; |
| init_params.translucent = true; |
| init_params.preferred_width = kPreferredWidth; |
| init_params.close_on_deactivate = false; |
| bubble_view_ = new TrayBubbleView(init_params); |
| bubble_view_->SetArrow(views::BubbleBorder::TOP_LEFT); |
| bubble_view_->SetCanActivate(true); |
| |
| menu_view_ = new SelectToSpeakMenuView(this); |
| menu_view_->SetBorder( |
| views::CreateEmptyBorder(kUnifiedTopShortcutSpacing, 0, 0, 0)); |
| bubble_view_->AddChildView(menu_view_); |
| menu_view_->SetSpeedButtonToggled(false); |
| menu_view_->SetPaintToLayer(); |
| menu_view_->layer()->SetFillsBoundsOpaquely(false); |
| |
| bubble_widget_ = |
| views::BubbleDialogDelegateView::CreateBubble(bubble_view_); |
| TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_); |
| bubble_view_->InitializeAndShowBubble(); |
| } |
| |
| // Update button states. |
| menu_view_->SetPaused(is_paused); |
| menu_view_->SetInitialSpeechRate(initial_speech_rate); |
| |
| // Add vertical spacing to given anchor rect. |
| bubble_view_->ChangeAnchorRect(gfx::Rect( |
| anchor.x(), anchor.y() - kAnchorRectVerticalSpacing, anchor.width(), |
| anchor.height() + kAnchorRectVerticalSpacing * 2)); |
| |
| if (!bubble_widget_->IsVisible()) { |
| bubble_widget_->Show(); |
| } |
| } |
| |
| void SelectToSpeakMenuBubbleController::Hide() { |
| if (bubble_widget_) { |
| bubble_widget_->Hide(); |
| } |
| if (speed_bubble_controller_) { |
| speed_bubble_controller_.reset(); |
| } |
| } |
| |
| std::u16string SelectToSpeakMenuBubbleController::GetAccessibleNameForBubble() { |
| return l10n_util::GetStringUTF16(IDS_ASH_SELECT_TO_SPEAK_MENU); |
| } |
| |
| void SelectToSpeakMenuBubbleController::BubbleViewDestroyed() { |
| bubble_view_ = nullptr; |
| bubble_widget_ = nullptr; |
| menu_view_ = nullptr; |
| } |
| |
| void SelectToSpeakMenuBubbleController::OnWindowActivated( |
| ActivationReason reason, |
| aura::Window* gained_active, |
| aura::Window* lost_active) { |
| if (!gained_active || !bubble_widget_) |
| return; |
| |
| views::Widget* gained_widget = |
| views::Widget::GetWidgetForNativeView(gained_active); |
| if (gained_widget == bubble_widget_ && menu_view_ && |
| (!lost_active || |
| lost_active->GetName() != kSelectToSpeakSpeedBubbleWindowName)) { |
| // Reset initial focus of the menu view, unless we're coming from the |
| // reading speed selector. |
| menu_view_->SetInitialFocus(); |
| } |
| } |
| |
| void SelectToSpeakMenuBubbleController::OnActionSelected( |
| SelectToSpeakPanelAction action) { |
| if (action == SelectToSpeakPanelAction::kChangeSpeed) { |
| // Toggle reading speed selection menu. |
| if (!speed_bubble_controller_) { |
| speed_bubble_controller_ = |
| std::make_unique<SelectToSpeakSpeedBubbleController>(this); |
| } |
| if (speed_bubble_controller_->IsVisible()) { |
| speed_bubble_controller_.reset(); |
| menu_view_->SetSpeedButtonToggled(false); |
| } else { |
| speed_bubble_controller_->Show( |
| /*anchor=*/menu_view_, initial_speech_rate_); |
| menu_view_->SetSpeedButtonToggled(true); |
| } |
| return; |
| } |
| Shell::Get()->accessibility_controller()->OnSelectToSpeakPanelAction( |
| action, /*value=*/0.0); |
| } |
| |
| void SelectToSpeakMenuBubbleController::OnSpeechRateSelected( |
| double speech_rate) { |
| if (speed_bubble_controller_) { |
| menu_view_->SetSpeedButtonToggled(false); |
| menu_view_->SetSpeedButtonFocused(); |
| speed_bubble_controller_->Hide(); |
| speed_bubble_controller_.reset(); |
| } |
| Shell::Get()->accessibility_controller()->OnSelectToSpeakPanelAction( |
| SelectToSpeakPanelAction::kChangeSpeed, /*value=*/speech_rate); |
| } |
| |
| } // namespace ash |