blob: 7998c29b1755da43f5dbf7436c6bb5eecaad375c [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 "ash/assistant/ui/assistant_container_view.h"
#include "ash/assistant/assistant_controller.h"
#include "ash/assistant/assistant_ui_controller.h"
#include "ash/assistant/model/assistant_ui_model.h"
#include "ash/assistant/ui/assistant_main_view.h"
#include "ash/assistant/ui/assistant_mini_view.h"
#include "ash/assistant/ui/assistant_web_view.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/views/bubble/bubble_dialog_delegate.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
#include "ui/wm/core/shadow_types.h"
namespace ash {
namespace {
// Appearance.
constexpr SkColor kBackgroundColor = SK_ColorWHITE;
constexpr int kCornerRadiusDip = 20;
constexpr int kMarginDip = 8;
} // namespace
AssistantContainerView::AssistantContainerView(
AssistantController* assistant_controller)
: assistant_controller_(assistant_controller) {
set_accept_events(true);
SetAnchor();
set_arrow(views::BubbleBorder::Arrow::BOTTOM_CENTER);
set_close_on_deactivate(false);
set_color(kBackgroundColor);
set_margins(gfx::Insets());
set_shadow(views::BubbleBorder::Shadow::NO_ASSETS);
set_title_margins(gfx::Insets());
views::BubbleDialogDelegateView::CreateBubble(this);
// These attributes can only be set after bubble creation:
GetBubbleFrameView()->bubble_border()->SetCornerRadius(kCornerRadiusDip);
SetAlignment(views::BubbleBorder::BubbleAlignment::ALIGN_EDGE_TO_ANCHOR_EDGE);
SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
// The AssistantController owns the view hierarchy to which
// AssistantContainerView belongs so is guaranteed to outlive it.
assistant_controller_->ui_controller()->AddModelObserver(this);
}
AssistantContainerView::~AssistantContainerView() {
assistant_controller_->ui_controller()->RemoveModelObserver(this);
}
void AssistantContainerView::ChildPreferredSizeChanged(views::View* child) {
PreferredSizeChanged();
}
void AssistantContainerView::PreferredSizeChanged() {
views::View::PreferredSizeChanged();
if (GetWidget())
SizeToContents();
}
int AssistantContainerView::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
void AssistantContainerView::OnBeforeBubbleWidgetInit(
views::Widget::InitParams* params,
views::Widget* widget) const {
params->corner_radius = kCornerRadiusDip;
params->keep_on_top = true;
params->shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP;
params->shadow_elevation = wm::kShadowElevationActiveWindow;
}
void AssistantContainerView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
// Apply a clip path to ensure children do not extend outside container
// boundaries. The clip path also enforces our round corners on child views.
gfx::Path clip_path;
clip_path.addRoundRect(gfx::RectToSkRect(GetLocalBounds()), kCornerRadiusDip,
kCornerRadiusDip);
set_clip_path(clip_path);
SchedulePaint();
}
void AssistantContainerView::Init() {
SetLayoutManager(std::make_unique<views::FillLayout>());
// Main view.
assistant_main_view_ =
std::make_unique<AssistantMainView>(assistant_controller_);
assistant_main_view_->set_owned_by_client();
// Mini view.
assistant_mini_view_ =
std::make_unique<AssistantMiniView>(assistant_controller_);
assistant_mini_view_->set_delegate(assistant_controller_->ui_controller());
assistant_mini_view_->set_owned_by_client();
// Web view.
assistant_web_view_ =
std::make_unique<AssistantWebView>(assistant_controller_);
assistant_web_view_->set_owned_by_client();
// Update the view state based on the current UI mode.
OnUiModeChanged(assistant_controller_->ui_controller()->model()->ui_mode());
}
void AssistantContainerView::RequestFocus() {
if (assistant_main_view_)
assistant_main_view_->RequestFocus();
}
void AssistantContainerView::SetAnchor() {
// TODO(dmblack): Handle multiple displays, dynamic shelf repositioning, and
// any other corner cases.
// Anchors to bottom center of primary display's work area.
display::Display primary_display =
display::Screen::GetScreen()->GetPrimaryDisplay();
gfx::Rect work_area = primary_display.work_area();
gfx::Rect anchor = gfx::Rect(work_area.x(), work_area.bottom() - kMarginDip,
work_area.width(), 0);
SetAnchorRect(anchor);
}
void AssistantContainerView::OnUiModeChanged(AssistantUiMode ui_mode) {
RemoveAllChildViews(/*delete_children=*/false);
switch (ui_mode) {
case AssistantUiMode::kMiniUi:
AddChildView(assistant_mini_view_.get());
break;
case AssistantUiMode::kMainUi:
AddChildView(assistant_main_view_.get());
break;
case AssistantUiMode::kWebUi:
AddChildView(assistant_web_view_.get());
break;
}
PreferredSizeChanged();
}
} // namespace ash