| // Copyright 2017 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 "chrome/browser/ui/views/payments/payment_request_row_view.h" |
| |
| #include <string> |
| |
| #include "chrome/browser/ui/views/payments/payment_request_views_util.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/accessibility/ax_node_data.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/color/color_id.h" |
| #include "ui/color/color_provider.h" |
| #include "ui/views/background.h" |
| #include "ui/views/border.h" |
| #include "ui/views/controls/focus_ring.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/layout/table_layout.h" |
| #include "ui/views/view_class_properties.h" |
| #include "ui/views/view_utils.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace { |
| |
| // TODO(pbos): Reconsider how to construct accessible names from these nodes. |
| // Right now this concatenates (with newlines) every Label inside the row to |
| // ensure that no data is inaccessible. |
| std::u16string GetAccessibleNameFromTree(views::View* view) { |
| if (views::IsViewClass<views::Label>(view)) |
| return static_cast<views::Label*>(view)->GetAccessibleName(); |
| |
| std::u16string accessible_name; |
| for (views::View* child : view->children()) { |
| // Skip buttons they will be announced independently. This is used for |
| // "more" items. |
| if (views::IsViewClass<views::Button>(child)) |
| continue; |
| std::u16string child_accessible_name = GetAccessibleNameFromTree(child); |
| if (child_accessible_name.empty()) |
| continue; |
| if (!accessible_name.empty()) |
| accessible_name += '\n'; |
| accessible_name += child_accessible_name; |
| } |
| return accessible_name; |
| } |
| |
| } // namespace |
| |
| namespace payments { |
| |
| PaymentRequestRowView::PaymentRequestRowView() |
| : PaymentRequestRowView(PressedCallback(), |
| /*clickable=*/true, |
| gfx::Insets()) {} |
| |
| PaymentRequestRowView::PaymentRequestRowView(PressedCallback callback, |
| bool clickable, |
| const gfx::Insets& insets) |
| : views::Button(std::move(callback)), |
| clickable_(clickable), |
| row_insets_(insets) { |
| UpdateButtonState(); |
| ShowBottomSeparator(); |
| SetFocusBehavior(views::View::FocusBehavior::ALWAYS); |
| } |
| |
| PaymentRequestRowView::~PaymentRequestRowView() = default; |
| |
| bool PaymentRequestRowView::GetClickable() const { |
| return clickable_; |
| } |
| void PaymentRequestRowView::SetClickable(bool clickable) { |
| if (clickable == clickable_) |
| return; |
| clickable_ = clickable; |
| UpdateButtonState(); |
| OnPropertyChanged(&clickable_, views::PropertyEffects::kPropertyEffectsPaint); |
| } |
| |
| gfx::Insets PaymentRequestRowView::GetRowInsets() const { |
| return row_insets_; |
| } |
| |
| void PaymentRequestRowView::SetRowInsets(const gfx::Insets& row_insets) { |
| if (row_insets == row_insets_) |
| return; |
| row_insets_ = row_insets; |
| UpdateBottomSeparator(); |
| OnPropertyChanged(&row_insets_, |
| views::PropertyEffects::kPropertyEffectsPaint); |
| } |
| |
| void PaymentRequestRowView::SetActiveBackground() { |
| // TODO(crbug/976890): Check whether we can GetColor from a ColorId instead of |
| // hard code here. |
| SetBackground(views::CreateSolidBackground(SkColorSetA(SK_ColorBLACK, 0x0D))); |
| } |
| |
| void PaymentRequestRowView::ShowBottomSeparator() { |
| bottom_separator_visible_ = true; |
| UpdateBottomSeparator(); |
| SchedulePaint(); |
| } |
| |
| void PaymentRequestRowView::HideBottomSeparator() { |
| bottom_separator_visible_ = false; |
| UpdateBottomSeparator(); |
| SchedulePaint(); |
| } |
| |
| void PaymentRequestRowView::UpdateBottomSeparator() { |
| // Create an empty border even when not present in a Widget hierarchy as the |
| // border is needed to correctly compute the bounds of the ScrollView in the |
| // PaymentRequestSheetController which is done before this is added to its |
| // Widget. |
| // TODO(crbug.com/1213247): Update PaymentRequestSheetController to recompute |
| // the bounds of its ScrollView in response to changes in preferred size. |
| SetBorder( |
| bottom_separator_visible_ && GetWidget() |
| ? payments::CreatePaymentRequestRowBorder( |
| GetColorProvider()->GetColor(ui::kColorSeparator), row_insets_) |
| : views::CreateEmptyBorder(row_insets_)); |
| } |
| |
| void PaymentRequestRowView::SetIsHighlighted(bool highlighted) { |
| if (highlighted) { |
| SetActiveBackground(); |
| HideBottomSeparator(); |
| if (previous_row_) |
| previous_row_->HideBottomSeparator(); |
| } else { |
| SetBackground(nullptr); |
| ShowBottomSeparator(); |
| if (previous_row_) |
| previous_row_->ShowBottomSeparator(); |
| } |
| } |
| |
| void PaymentRequestRowView::UpdateButtonState() { |
| // When not clickable, use Button's STATE_DISABLED but don't set our |
| // View state to disabled. The former ensures we aren't clickable, the |
| // latter also disables us and our children for event handling. |
| views::Button::SetState(clickable_ ? views::Button::STATE_NORMAL |
| : views::Button::STATE_DISABLED); |
| } |
| |
| void PaymentRequestRowView::GetAccessibleNodeData(ui::AXNodeData* node_data) { |
| Button::GetAccessibleNodeData(node_data); |
| node_data->SetName(GetAccessibleNameFromTree(this)); |
| } |
| |
| void PaymentRequestRowView::StateChanged(ButtonState old_state) { |
| Button::StateChanged(old_state); |
| if (!GetClickable()) |
| return; |
| |
| SetIsHighlighted(GetState() == views::Button::STATE_HOVERED || |
| GetState() == views::Button::STATE_PRESSED); |
| } |
| |
| void PaymentRequestRowView::OnThemeChanged() { |
| Button::OnThemeChanged(); |
| UpdateBottomSeparator(); |
| } |
| |
| void PaymentRequestRowView::OnFocus() { |
| if (GetClickable()) { |
| SetIsHighlighted(true); |
| SchedulePaint(); |
| } |
| View::OnFocus(); |
| views::FocusRing* focus_ring = views::FocusRing::Get(this); |
| views::TableLayout* layout = |
| static_cast<views::TableLayout*>(GetLayoutManager()); |
| if (focus_ring && layout) |
| layout->SetChildViewIgnoredByLayout(focus_ring, true); |
| } |
| |
| void PaymentRequestRowView::OnBlur() { |
| if (GetClickable()) { |
| SetIsHighlighted(false); |
| SchedulePaint(); |
| } |
| } |
| |
| BEGIN_METADATA(PaymentRequestRowView, views::Button) |
| ADD_PROPERTY_METADATA(bool, Clickable) |
| ADD_PROPERTY_METADATA(gfx::Insets, RowInsets) |
| END_METADATA |
| |
| } // namespace payments |