[go: nahoru, domu]

blob: d47e249a37cfe60e8ed7297be5f3d5d2444a4669 [file] [log] [blame]
// Copyright 2016 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/tray/tray_popup_utils.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/ash_view_ids.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/tray/hover_highlight_view.h"
#include "ash/system/tray/size_range_layout.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/unfocusable_label.h"
#include "chromeos/ui/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/square_ink_drop_ripple.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/button/toggle_button.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/separator.h"
#include "ui/views/controls/slider.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/painter.h"
namespace ash {
namespace {
// Creates a layout manager that positions Views vertically. The Views will be
// stretched horizontally and centered vertically.
std::unique_ptr<views::LayoutManager> CreateDefaultCenterLayoutManager() {
// TODO(bruthig): Use constants instead of magic numbers.
auto box_layout = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical,
gfx::Insets(8, kTrayPopupLabelHorizontalPadding));
box_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
box_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStretch);
return std::move(box_layout);
}
// Creates a layout manager that positions Views horizontally. The Views will be
// centered along the horizontal and vertical axis.
std::unique_ptr<views::LayoutManager> CreateDefaultEndsLayoutManager() {
auto box_layout = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal);
box_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
box_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
return std::move(box_layout);
}
std::unique_ptr<views::LayoutManager> CreateDefaultLayoutManager(
TriView::Container container) {
switch (container) {
case TriView::Container::START:
case TriView::Container::END:
return CreateDefaultEndsLayoutManager();
case TriView::Container::CENTER:
return CreateDefaultCenterLayoutManager();
}
// Required by some compilers.
NOTREACHED();
return nullptr;
}
// Configures the default size and flex value for the specified |container|
// of the given |tri_view|. Used by CreateDefaultRowView().
void ConfigureDefaultSizeAndFlex(TriView* tri_view,
TriView::Container container) {
int min_width = 0;
switch (container) {
case TriView::Container::START:
min_width = kTrayPopupItemMinStartWidth;
break;
case TriView::Container::CENTER:
tri_view->SetFlexForContainer(TriView::Container::CENTER, 1.f);
break;
case TriView::Container::END:
min_width = kTrayPopupItemMinEndWidth;
break;
}
tri_view->SetMinSize(container,
gfx::Size(min_width, kTrayPopupItemMinHeight));
constexpr int kTrayPopupItemMaxHeight = 144;
tri_view->SetMaxSize(container, gfx::Size(SizeRangeLayout::kAbsoluteMaxSize,
kTrayPopupItemMaxHeight));
}
gfx::Insets GetInkDropInsets(TrayPopupInkDropStyle ink_drop_style) {
if (ink_drop_style == TrayPopupInkDropStyle::HOST_CENTERED ||
ink_drop_style == TrayPopupInkDropStyle::INSET_BOUNDS) {
return gfx::Insets(kTrayPopupInkDropInset);
}
return gfx::Insets();
}
class HighlightPathGenerator : public views::HighlightPathGenerator {
public:
explicit HighlightPathGenerator(TrayPopupInkDropStyle ink_drop_style)
: ink_drop_style_(ink_drop_style) {}
HighlightPathGenerator(const HighlightPathGenerator&) = delete;
HighlightPathGenerator& operator=(const HighlightPathGenerator&) = delete;
// views::HighlightPathGenerator:
base::Optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect) override {
gfx::RectF bounds = rect;
bounds.Inset(GetInkDropInsets(ink_drop_style_));
float corner_radius = 0.f;
switch (ink_drop_style_) {
case TrayPopupInkDropStyle::HOST_CENTERED:
corner_radius = std::min(bounds.width(), bounds.height()) / 2.f;
bounds.ClampToCenteredSize(gfx::SizeF(corner_radius, corner_radius));
break;
case TrayPopupInkDropStyle::INSET_BOUNDS:
corner_radius = kTrayPopupInkDropCornerRadius;
break;
case TrayPopupInkDropStyle::FILL_BOUNDS:
break;
}
return gfx::RRectF(bounds, corner_radius);
}
private:
const TrayPopupInkDropStyle ink_drop_style_;
};
} // namespace
TriView* TrayPopupUtils::CreateDefaultRowView() {
TriView* tri_view = CreateMultiTargetRowView();
tri_view->SetContainerLayout(
TriView::Container::START,
CreateDefaultLayoutManager(TriView::Container::START));
tri_view->SetContainerLayout(
TriView::Container::CENTER,
CreateDefaultLayoutManager(TriView::Container::CENTER));
tri_view->SetContainerLayout(
TriView::Container::END,
CreateDefaultLayoutManager(TriView::Container::END));
return tri_view;
}
TriView* TrayPopupUtils::CreateSubHeaderRowView(bool start_visible) {
TriView* tri_view = CreateDefaultRowView();
if (!start_visible) {
tri_view->SetInsets(gfx::Insets(
0, kTrayPopupPaddingHorizontal - kTrayPopupLabelHorizontalPadding, 0,
0));
tri_view->SetContainerVisible(TriView::Container::START, false);
}
return tri_view;
}
TriView* TrayPopupUtils::CreateMultiTargetRowView() {
TriView* tri_view = new TriView(0 /* padding_between_items */);
tri_view->SetInsets(gfx::Insets(0, kMenuExtraMarginFromLeftEdge, 0, 0));
ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::START);
ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::CENTER);
ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::END);
tri_view->SetContainerLayout(TriView::Container::START,
std::make_unique<views::FillLayout>());
tri_view->SetContainerLayout(TriView::Container::CENTER,
std::make_unique<views::FillLayout>());
tri_view->SetContainerLayout(TriView::Container::END,
std::make_unique<views::FillLayout>());
return tri_view;
}
views::Label* TrayPopupUtils::CreateDefaultLabel() {
views::Label* label = new views::Label();
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetSubpixelRenderingEnabled(false);
return label;
}
UnfocusableLabel* TrayPopupUtils::CreateUnfocusableLabel() {
UnfocusableLabel* label = new UnfocusableLabel();
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetSubpixelRenderingEnabled(false);
return label;
}
views::ImageView* TrayPopupUtils::CreateMainImageView() {
auto* image = new views::ImageView;
image->SetPreferredSize(
gfx::Size(kTrayPopupItemMinStartWidth, kTrayPopupItemMinHeight));
return image;
}
views::ToggleButton* TrayPopupUtils::CreateToggleButton(
views::Button::PressedCallback callback,
int accessible_name_id) {
views::ToggleButton* toggle = new views::ToggleButton(std::move(callback));
const gfx::Size toggle_size(toggle->GetPreferredSize());
const int vertical_padding = (kMenuButtonSize - toggle_size.height()) / 2;
const int horizontal_padding =
(kTrayToggleButtonWidth - toggle_size.width()) / 2;
toggle->SetBorder(views::CreateEmptyBorder(
gfx::Insets(vertical_padding, horizontal_padding)));
toggle->SetAccessibleName(l10n_util::GetStringUTF16(accessible_name_id));
UpdateToggleButtonColors(toggle);
return toggle;
}
std::unique_ptr<views::Painter> TrayPopupUtils::CreateFocusPainter() {
return views::Painter::CreateSolidFocusPainter(
AshColorProvider::Get()->GetControlsLayerColor(
AshColorProvider::ControlsLayerType::kFocusRingColor),
kFocusBorderThickness, gfx::InsetsF());
}
void TrayPopupUtils::ConfigureTrayPopupButton(views::Button* button) {
button->SetInstallFocusRingOnFocus(true);
button->SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
button->SetHasInkDropActionOnClick(true);
}
void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) {
view->SetID(VIEW_ID_STICKY_HEADER);
view->SetBorder(
views::CreateEmptyBorder(gfx::Insets(kMenuSeparatorVerticalPadding, 0)));
view->SetPaintToLayer();
view->layer()->SetFillsBoundsOpaquely(false);
}
void TrayPopupUtils::ConfigureContainer(TriView::Container container,
views::View* container_view) {
container_view->SetLayoutManager(CreateDefaultLayoutManager(container));
}
views::LabelButton* TrayPopupUtils::CreateTrayPopupButton(
views::Button::PressedCallback callback,
const std::u16string& text) {
auto button =
std::make_unique<views::MdTextButton>(std::move(callback), text);
button->SetProminent(true);
return button.release();
}
views::Separator* TrayPopupUtils::CreateVerticalSeparator() {
views::Separator* separator = new views::Separator();
separator->SetPreferredHeight(24);
separator->SetColor(AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSeparatorColor));
return separator;
}
std::unique_ptr<views::InkDrop> TrayPopupUtils::CreateInkDrop(
views::InkDropHostView* host) {
std::unique_ptr<views::InkDropImpl> ink_drop =
std::make_unique<views::InkDropImpl>(host, host->size());
ink_drop->SetAutoHighlightMode(
views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE);
ink_drop->SetShowHighlightOnHover(false);
return std::move(ink_drop);
}
std::unique_ptr<views::InkDropRipple> TrayPopupUtils::CreateInkDropRipple(
TrayPopupInkDropStyle ink_drop_style,
const views::View* host,
const gfx::Point& center_point) {
const AshColorProvider::RippleAttributes ripple_attributes =
AshColorProvider::Get()->GetRippleAttributes();
return std::make_unique<views::FloodFillInkDropRipple>(
host->size(), GetInkDropInsets(ink_drop_style), center_point,
ripple_attributes.base_color, ripple_attributes.inkdrop_opacity);
}
std::unique_ptr<views::InkDropHighlight> TrayPopupUtils::CreateInkDropHighlight(
const views::View* host) {
const AshColorProvider::RippleAttributes ripple_attributes =
AshColorProvider::Get()->GetRippleAttributes();
auto highlight = std::make_unique<views::InkDropHighlight>(
gfx::SizeF(host->size()), ripple_attributes.base_color);
highlight->set_visible_opacity(ripple_attributes.highlight_opacity);
return highlight;
}
void TrayPopupUtils::InstallHighlightPathGenerator(
views::View* host,
TrayPopupInkDropStyle ink_drop_style) {
views::HighlightPathGenerator::Install(
host, std::make_unique<HighlightPathGenerator>(ink_drop_style));
}
views::Separator* TrayPopupUtils::CreateListItemSeparator(bool left_inset) {
views::Separator* separator = new views::Separator();
separator->SetColor(AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSeparatorColor));
separator->SetBorder(views::CreateEmptyBorder(
kMenuSeparatorVerticalPadding - views::Separator::kThickness,
left_inset ? kMenuExtraMarginFromLeftEdge + kMenuButtonSize +
kTrayPopupLabelHorizontalPadding
: 0,
kMenuSeparatorVerticalPadding, 0));
return separator;
}
bool TrayPopupUtils::CanOpenWebUISettings() {
return Shell::Get()->session_controller()->ShouldEnableSettings();
}
void TrayPopupUtils::InitializeAsCheckableRow(HoverHighlightView* container,
bool checked,
bool enterprise_managed) {
const int dip_size = GetDefaultSizeOfVectorIcon(kCheckCircleIcon);
gfx::ImageSkia check_mark = CreateVectorIcon(
kHollowCheckCircleIcon, dip_size,
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kIconColorProminent));
if (enterprise_managed) {
gfx::ImageSkia enterprise_managed_icon = CreateVectorIcon(
chromeos::kEnterpriseIcon, dip_size, gfx::kGoogleGrey100);
container->AddRightIcon(enterprise_managed_icon,
enterprise_managed_icon.width());
}
container->AddRightIcon(check_mark, check_mark.width());
UpdateCheckMarkVisibility(container, checked);
}
void TrayPopupUtils::UpdateCheckMarkVisibility(HoverHighlightView* container,
bool visible) {
container->SetRightViewVisible(visible);
container->SetAccessibilityState(
visible ? HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX
: HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX);
}
void TrayPopupUtils::UpdateToggleButtonColors(views::ToggleButton* toggle) {
auto* ash_color_provider = AshColorProvider::Get();
toggle->SetThumbOnColor(ash_color_provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSwitchKnobColorActive));
toggle->SetThumbOffColor(ash_color_provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSwitchKnobColorInactive));
toggle->SetTrackOnColor(ash_color_provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSwitchTrackColorActive));
toggle->SetTrackOffColor(ash_color_provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSwitchTrackColorInactive));
}
void TrayPopupUtils::SetLabelFontList(views::Label* label, FontStyle style) {
label->SetAutoColorReadabilityEnabled(false);
const gfx::FontList google_sans_font_list({"Google Sans"}, gfx::Font::NORMAL,
16, gfx::Font::Weight::MEDIUM);
const gfx::FontList roboto_font_list({"Roboto"}, gfx::Font::NORMAL, 16,
gfx::Font::Weight::MEDIUM);
switch (style) {
case FontStyle::kTitle:
label->SetFontList(google_sans_font_list);
break;
case FontStyle::kPodMenuHeader:
label->SetFontList(roboto_font_list);
break;
case FontStyle::kSubHeader:
label->SetFontList(roboto_font_list.Derive(-1, gfx::Font::NORMAL,
gfx::Font::Weight::MEDIUM));
break;
case FontStyle::kSmallTitle:
label->SetFontList(roboto_font_list.Derive(-3, gfx::Font::NORMAL,
gfx::Font::Weight::MEDIUM));
break;
case FontStyle::kDetailedViewLabel:
case FontStyle::kSystemInfo:
label->SetFontList(roboto_font_list.Derive(-4, gfx::Font::NORMAL,
gfx::Font::Weight::NORMAL));
break;
}
}
} // namespace ash