| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/capture_mode/key_item_view.h" |
| |
| #include <memory> |
| |
| #include "ash/capture_mode/capture_mode_util.h" |
| #include "chromeos/constants/chromeos_features.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/base/models/image_model.h" |
| #include "ui/chromeos/styles/cros_tokens_color_mappings.h" |
| #include "ui/color/color_id.h" |
| #include "ui/color/color_provider.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/gfx/font_list.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/views/background.h" |
| #include "ui/views/border.h" |
| #include "ui/views/controls/image_view.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/highlight_border.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| constexpr int kKeyItemMinWidth = 56; |
| constexpr int kKeyItemHeight = 56; |
| constexpr int kKeyItemVerticalPadding = 16; |
| constexpr int kKeyItemHorizontalPadding = 20; |
| constexpr gfx::Size kIconSize{20, 20}; |
| constexpr char kGoogleSansFont[] = "Google Sans"; |
| constexpr int kKeyItemViewFontSize = 18; |
| constexpr int kKeyItemViewLineHeight = 24; |
| |
| SkColor GetColor() { |
| return capture_mode_util::GetColorProviderForNativeTheme()->GetColor( |
| cros_tokens::kCrosSysSystemBaseElevated); |
| } |
| |
| } // namespace |
| |
| KeyItemView::KeyItemView(ui::KeyboardCode key_code) |
| : key_code_(key_code), |
| shadow_(SystemShadow::CreateShadowOnTextureLayer( |
| SystemShadow::Type::kElevation4)) { |
| SetPaintToLayer(); |
| SetBackground( |
| views::CreateRoundedRectBackground(GetColor(), kKeyItemHeight / 2)); |
| layer()->SetFillsBoundsOpaquely(false); |
| |
| capture_mode_util::SetHighlightBorder( |
| this, kKeyItemHeight / 2, |
| views::HighlightBorder::Type::kHighlightBorderOnShadow); |
| |
| shadow_->SetRoundedCornerRadius(kKeyItemHeight / 2); |
| } |
| |
| KeyItemView::~KeyItemView() = default; |
| |
| void KeyItemView::AddedToWidget() { |
| // Since the layer of the shadow has to be added as a sibling to this view's |
| // layer, we need to wait until the view is added to the widget. |
| auto* parent = layer()->parent(); |
| parent->Add(shadow_->GetLayer()); |
| parent->StackAtBottom(shadow_->GetLayer()); |
| |
| // Make the shadow observe the color provider source change to update the |
| // colors. |
| shadow_->ObserveColorProviderSource(GetWidget()); |
| } |
| |
| void KeyItemView::OnBoundsChanged(const gfx::Rect& previous_bounds) { |
| // The shadow layer is a sibling of this view's layer, and should have the |
| // same bounds. Need to update the location of the shadow when the key items |
| // in the combo change position and/or size. |
| shadow_->SetContentBounds(layer()->bounds()); |
| } |
| |
| void KeyItemView::OnThemeChanged() { |
| views::View::OnThemeChanged(); |
| GetBackground()->SetNativeControlColor(GetColor()); |
| SchedulePaint(); |
| } |
| |
| void KeyItemView::Layout(PassKey) { |
| const auto bounds = GetContentsBounds(); |
| if (icon_) { |
| icon_->SetBoundsRect(bounds); |
| } |
| |
| if (label_) { |
| label_->SetBoundsRect(bounds); |
| } |
| } |
| |
| gfx::Size KeyItemView::CalculatePreferredSize() const { |
| // Return the fixed size if the key item contains icon or label with a single |
| // character. |
| if (icon_ || (label_ && label_->GetText().length() == 1)) { |
| return gfx::Size(kKeyItemMinWidth, kKeyItemHeight); |
| } |
| |
| int width = 0; |
| for (const views::View* child : children()) { |
| const auto child_size = child->GetPreferredSize(); |
| width += child_size.width(); |
| } |
| |
| width = std::max(width, kKeyItemMinWidth); |
| return gfx::Size(width, kKeyItemHeight); |
| } |
| |
| void KeyItemView::SetIcon(const gfx::VectorIcon& icon) { |
| if (!icon_) { |
| icon_ = AddChildView(std::make_unique<views::ImageView>()); |
| icon_->SetHorizontalAlignment(views::ImageView::Alignment::kCenter); |
| icon_->SetVerticalAlignment(views::ImageView::Alignment::kCenter); |
| } |
| |
| icon_->SetImage( |
| ui::ImageModel::FromVectorIcon(icon, cros_tokens::kCrosSysOnSurface)); |
| icon_->SetImageSize(kIconSize); |
| } |
| |
| void KeyItemView::SetText(const std::u16string& text) { |
| if (!label_) { |
| label_ = AddChildView(std::make_unique<views::Label>()); |
| label_->SetEnabledColorId(cros_tokens::kCrosSysOnSurface); |
| label_->SetElideBehavior(gfx::ElideBehavior::NO_ELIDE); |
| label_->SetFontList(gfx::FontList({kGoogleSansFont}, gfx::Font::NORMAL, |
| kKeyItemViewFontSize, |
| gfx::Font::Weight::MEDIUM)); |
| label_->SetLineHeight(kKeyItemViewLineHeight); |
| } |
| |
| // Set the border only when necessary which is the multi-character case and |
| // clear the border for the single-character case in case the border was set |
| // with the multi-character settings before. |
| label_->SetBorder( |
| text.length() == 1 |
| ? nullptr |
| : views::CreateEmptyBorder(gfx::Insets::VH( |
| kKeyItemVerticalPadding, kKeyItemHorizontalPadding))); |
| label_->SetText(text); |
| } |
| |
| BEGIN_METADATA(KeyItemView) |
| END_METADATA |
| |
| } // namespace ash |