blob: 3f06e6b7b6e69d32313e8f27c077985600a335d9 [file] [log] [blame]
// 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/holding_space/holding_space_item_chip_view.h"
#include "ash/public/cpp/holding_space/holding_space_constants.h"
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "ash/public/cpp/rounded_image_view.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/holding_space/holding_space_item_view.h"
#include "ash/system/holding_space/holding_space_util.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/views/background.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/metadata/metadata_impl_macros.h"
namespace ash {
// HoldingSpaceItemChipView::LabelMaskOwner ------------------------------------
class HoldingSpaceItemChipView::LabelMaskLayerOwner : public ui::LayerDelegate {
public:
LabelMaskLayerOwner() : layer_(ui::LAYER_TEXTURED) {
layer_.set_delegate(this);
layer_.SetFillsBoundsOpaquely(false);
}
LabelMaskLayerOwner(const LabelMaskLayerOwner&) = delete;
LabelMaskLayerOwner& operator=(const LabelMaskLayerOwner&) = delete;
~LabelMaskLayerOwner() override { layer_.set_delegate(nullptr); }
ui::Layer* layer() { return &layer_; }
private:
// ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override {
const gfx::Size size = layer()->size();
views::PaintInfo paint_info =
views::PaintInfo::CreateRootPaintInfo(context, size);
const auto& paint_recording_size = paint_info.paint_recording_size();
// Pass the scale factor when constructing `PaintRecorder` so the mask layer
// size is not incorrectly rounded (see https://crbug.com/921274).
ui::PaintRecorder recorder(
context, paint_info.paint_recording_size(),
static_cast<float>(paint_recording_size.width()) / size.width(),
static_cast<float>(paint_recording_size.height()) / size.height(),
/*cache*/ nullptr);
cc::PaintFlags flags;
flags.setAntiAlias(false);
gfx::Point gradient_end(size.width() - kHoldingSpaceIconSize, 0);
gfx::Point gradient_start(
gradient_end.x() - kHoldingSpaceChipLabelMaskGradientWidth,
gradient_end.y());
flags.setShader(gfx::CreateGradientShader(
gradient_start, gradient_end, SK_ColorBLACK, SK_ColorTRANSPARENT));
recorder.canvas()->DrawRect(gfx::Rect(size), flags);
}
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override {}
ui::Layer layer_;
};
// HoldingSpaceItemChipView ----------------------------------------------------
HoldingSpaceItemChipView::HoldingSpaceItemChipView(
HoldingSpaceItemViewDelegate* delegate,
const HoldingSpaceItem* item)
: HoldingSpaceItemView(delegate, item) {
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal,
gfx::Insets(kHoldingSpaceChipPadding), kHoldingSpaceChipChildSpacing));
layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
SetPreferredSize(gfx::Size(kHoldingSpaceChipWidth, kHoldingSpaceChipHeight));
image_ = AddChildView(std::make_unique<RoundedImageView>(
kHoldingSpaceChipIconSize / 2, RoundedImageView::Alignment::kLeading));
image_->SetBackground(views::CreateRoundedRectBackground(
SK_ColorWHITE, kHoldingSpaceChipIconSize / 2));
// Subscribe to be notified of changes to `item_`'s image.
image_subscription_ =
item->image().AddImageSkiaChangedCallback(base::BindRepeating(
&HoldingSpaceItemChipView::UpdateImage, base::Unretained(this)));
UpdateImage();
label_and_pin_button_container_ =
AddChildView(std::make_unique<views::View>());
layout->SetFlexForView(label_and_pin_button_container_, 1);
label_and_pin_button_container_->SetLayoutManager(
std::make_unique<views::FillLayout>());
label_ = label_and_pin_button_container_->AddChildView(
holding_space_util::CreateLabel(holding_space_util::LabelStyle::kChip));
label_->SetElideBehavior(gfx::ELIDE_MIDDLE);
label_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
label_->SetText(item->text());
label_mask_layer_owner_ = std::make_unique<LabelMaskLayerOwner>();
label_->SetPaintToLayer();
label_->layer()->SetFillsBoundsOpaquely(false);
label_->layer()->SetMaskLayer(label_mask_layer_owner_->layer());
views::View* pin_button_container =
label_and_pin_button_container_->AddChildView(
std::make_unique<views::View>());
auto* pin_layout =
pin_button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
pin_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kEnd);
pin_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
AddPin(/*parent=*/pin_button_container);
}
HoldingSpaceItemChipView::~HoldingSpaceItemChipView() = default;
void HoldingSpaceItemChipView::OnHoldingSpaceItemUpdated(
const HoldingSpaceItem* item) {
HoldingSpaceItemView::OnHoldingSpaceItemUpdated(item);
if (this->item() == item)
label_->SetText(item->text());
}
void HoldingSpaceItemChipView::OnPinVisiblityChanged(bool pin_visible) {
if (label_mask_layer_owner_->layer()->bounds() !=
label_and_pin_button_container_->bounds()) {
// Mask layer has the same size as the label container so that the gradient
// ends at the end of the container.
label_mask_layer_owner_->layer()->SetBounds(
label_and_pin_button_container_->bounds());
}
label_mask_layer_owner_->layer()->SetVisible(pin_visible);
}
void HoldingSpaceItemChipView::UpdateImage() {
image_->SetImage(
item()->image().image_skia(),
gfx::Size(kHoldingSpaceChipIconSize, kHoldingSpaceChipIconSize));
SchedulePaint();
}
BEGIN_METADATA(HoldingSpaceItemChipView, HoldingSpaceItemView)
END_METADATA
} // namespace ash