| // Copyright 2024 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/quick_insert/views/quick_insert_preview_bubble.h" |
| |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| |
| #include "ash/ash_element_identifiers.h" |
| #include "ash/bubble/bubble_constants.h" |
| #include "ash/bubble/bubble_utils.h" |
| #include "ash/style/typography.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/base/mojom/dialog_button.mojom.h" |
| #include "ui/chromeos/styles/cros_tokens_color_mappings.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/gfx/geometry/skia_conversions.h" |
| #include "ui/views/background.h" |
| #include "ui/views/border.h" |
| #include "ui/views/bubble/bubble_border.h" |
| #include "ui/views/bubble/bubble_dialog_delegate_view.h" |
| #include "ui/views/controls/image_view.h" |
| #include "ui/views/layout/box_layout.h" |
| #include "ui/views/layout/box_layout_view.h" |
| #include "ui/views/metadata/view_factory.h" |
| #include "ui/views/view_class_properties.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace ash { |
| namespace { |
| |
| constexpr int kBubbleOverlapOverPicker = 4; |
| constexpr int kQuickInsertBubbleCornerRadius = 12; |
| constexpr gfx::Insets kMargins(8); |
| constexpr int kPreviewBackgroundBorderRadius = 8; |
| constexpr gfx::Insets kLabelPadding = gfx::Insets::TLBR(8, 8, 0, 8); |
| |
| // A preview thumbnail image view with rounded corners. |
| class RoundedPreviewImageView : public views::ImageView { |
| METADATA_HEADER(RoundedPreviewImageView, views::ImageView) |
| |
| public: |
| explicit RoundedPreviewImageView(const gfx::Size image_size, int radius) { |
| SetImageSize(image_size); |
| SetBackground(views::CreateRoundedRectBackground( |
| cros_tokens::kCrosSysSeparator, radius)); |
| SetClipPath(SkPath::RRect(SkRRect::MakeRectXY( |
| gfx::RectToSkRect(gfx::Rect(image_size)), radius, radius))); |
| } |
| RoundedPreviewImageView(const RoundedPreviewImageView&) = delete; |
| RoundedPreviewImageView& operator=(const RoundedPreviewImageView&) = delete; |
| }; |
| |
| BEGIN_METADATA(RoundedPreviewImageView) |
| END_METADATA |
| |
| BEGIN_VIEW_BUILDER(/*no export*/, RoundedPreviewImageView, views::ImageView) |
| END_VIEW_BUILDER |
| |
| } // namespace |
| } // namespace ash |
| |
| DEFINE_VIEW_BUILDER(/* no export */, ash::RoundedPreviewImageView) |
| |
| namespace ash { |
| |
| QuickInsertPreviewBubbleView::QuickInsertPreviewBubbleView( |
| views::View* anchor_view) |
| : BubbleDialogDelegateView(anchor_view, |
| views::BubbleBorder::LEFT_CENTER, |
| views::BubbleBorder::STANDARD_SHADOW, |
| /*autosize=*/true) { |
| SetBackgroundColor(cros_tokens::kCrosSysSystemBaseElevatedOpaque); |
| |
| // Configuration for this view. |
| SetLayoutManager( |
| std::make_unique<views::BoxLayout>(views::LayoutOrientation::kVertical)) |
| ->set_cross_axis_alignment(views::LayoutAlignment::kStretch); |
| SetCanActivate(false); |
| // Ignore this bubble for accessibility purposes. The contents of the preview |
| // bubble are announced via the item view that triggered the bubble. |
| SetAccessibleWindowRole(ax::mojom::Role::kNone); |
| // Highlighting of the anchor is done by the anchor itself. |
| set_highlight_button_when_shown(false); |
| |
| views::Builder<QuickInsertPreviewBubbleView>(this) |
| .set_margins(kMargins) |
| .set_corner_radius(kQuickInsertBubbleCornerRadius) |
| .SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone)) |
| .SetProperty(views::kElementIdentifierKey, |
| kQuickInsertPreviewBubbleElementId) |
| .AddChildren(views::Builder<RoundedPreviewImageView>( |
| std::make_unique<RoundedPreviewImageView>( |
| kPreviewImageSize, kPreviewBackgroundBorderRadius)) |
| .CopyAddressTo(&image_view_), |
| views::Builder<views::BoxLayoutView>() |
| .SetOrientation(views::BoxLayout::Orientation::kVertical) |
| .SetCrossAxisAlignment( |
| views::BoxLayout::CrossAxisAlignment::kStart) |
| .SetInsideBorderInsets(kLabelPadding) |
| .SetVisible(false) |
| .CopyAddressTo(&box_layout_view_) |
| .AddChildren(views::Builder<views::Label>( |
| bubble_utils::CreateLabel( |
| TypographyToken::kCrosBody2, u"", |
| cros_tokens::kCrosSysOnSurface)) |
| .CopyAddressTo(&main_label_))) |
| .BuildChildren(); |
| |
| // Show the widget. |
| views::BubbleDialogDelegateView::CreateBubble(this); |
| } |
| |
| ui::ImageModel QuickInsertPreviewBubbleView::GetPreviewImage() const { |
| return image_view_->GetImageModel(); |
| } |
| |
| void QuickInsertPreviewBubbleView::SetPreviewImage(ui::ImageModel image) { |
| image_view_->SetImage(std::move(image)); |
| } |
| |
| bool QuickInsertPreviewBubbleView::GetLabelVisibleForTesting() const { |
| return box_layout_view_->GetVisible(); |
| } |
| |
| std::u16string_view QuickInsertPreviewBubbleView::GetMainTextForTesting() |
| const { |
| return main_label_->GetText(); |
| } |
| |
| void QuickInsertPreviewBubbleView::SetText(const std::u16string& main_text) { |
| main_label_->SetText(main_text); |
| box_layout_view_->SetVisible(true); |
| } |
| |
| void QuickInsertPreviewBubbleView::ClearText() { |
| main_label_->SetText(u""); |
| box_layout_view_->SetVisible(false); |
| } |
| |
| gfx::Rect QuickInsertPreviewBubbleView::GetAnchorRect() const { |
| gfx::Rect rect = BubbleDialogDelegateView::GetAnchorRect(); |
| rect.Inset(kBubbleOverlapOverPicker); |
| return rect; |
| } |
| |
| void QuickInsertPreviewBubbleView::Close() { |
| GetWidget()->CloseWithReason(views::Widget::ClosedReason::kUnspecified); |
| } |
| |
| BEGIN_METADATA(QuickInsertPreviewBubbleView) |
| END_METADATA |
| |
| } // namespace ash |