blob: 6a7ff7d953e2b28d466b09fd0248063ff8a60802 [file] [log] [blame]
// Copyright (c) 2018 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/omnibox/omnibox_tab_switch_button.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/omnibox/omnibox_theme.h"
#include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
#include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
#include "components/omnibox/browser/omnibox_field_trial.h"
#include "components/omnibox/browser/vector_icons.h"
#include "components/strings/grit/components_strings.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/animation/ink_drop_mask.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/metadata/metadata_impl_macros.h"
// static
bool OmniboxTabSwitchButton::calculated_widths_ = false;
int OmniboxTabSwitchButton::icon_only_width_;
int OmniboxTabSwitchButton::short_text_width_;
int OmniboxTabSwitchButton::full_text_width_;
OmniboxTabSwitchButton::OmniboxTabSwitchButton(
PressedCallback callback,
OmniboxPopupContentsView* popup_contents_view,
OmniboxResultView* result_view,
const std::u16string& hint,
const std::u16string& hint_short,
const gfx::VectorIcon& icon)
: MdTextButton(std::move(callback),
std::u16string(),
views::style::CONTEXT_BUTTON_MD),
popup_contents_view_(popup_contents_view),
result_view_(result_view),
hint_(hint),
hint_short_(hint_short) {
views::InstallPillHighlightPathGenerator(this);
SetImage(STATE_NORMAL, gfx::CreateVectorIcon(
icon, GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
gfx::kChromeIconGrey));
SetImageLabelSpacing(8);
if (!calculated_widths_) {
icon_only_width_ = MdTextButton::CalculatePreferredSize().width();
SetText(hint_short_);
short_text_width_ = MdTextButton::CalculatePreferredSize().width();
SetText(hint_);
full_text_width_ = MdTextButton::CalculatePreferredSize().width();
calculated_widths_ = true;
} else {
SetText(hint_);
}
SetPreferredSize({full_text_width_, 32});
SetCornerRadius(views::LayoutProvider::Get()->GetCornerRadiusMetric(
views::Emphasis::kMaximum, GetPreferredSize()));
SetTooltipText(hint_);
SetElideBehavior(gfx::FADE_TAIL);
SetInstallFocusRingOnFocus(true);
focus_ring()->SetHasFocusPredicate([](View* view) {
auto* button = static_cast<OmniboxTabSwitchButton*>(view);
return button->IsSelected();
});
}
OmniboxTabSwitchButton::~OmniboxTabSwitchButton() = default;
void OmniboxTabSwitchButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
MdTextButton::OnBoundsChanged(previous_bounds);
std::u16string text = hint_;
if (width() <= icon_only_width_)
text = std::u16string();
else if (width() <= short_text_width_)
text = hint_short_;
SetText(text);
}
void OmniboxTabSwitchButton::StateChanged(ButtonState old_state) {
MdTextButton::StateChanged(old_state);
if (GetState() == STATE_NORMAL && old_state == STATE_PRESSED) {
SetMouseAndGestureHandler(parent());
if (popup_contents_view_->model()->selected_line_state() ==
OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH)
popup_contents_view_->UnselectButton();
}
}
void OmniboxTabSwitchButton::OnThemeChanged() {
views::MdTextButton::OnThemeChanged();
SetBgColorOverride(GetOmniboxColor(GetThemeProvider(),
OmniboxPart::RESULTS_BACKGROUND,
OmniboxPartState::NORMAL));
}
void OmniboxTabSwitchButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->SetName(l10n_util::GetStringUTF8(IDS_ACC_TAB_SWITCH_BUTTON));
// Although this appears visually as a button, expose as a list box option so
// that it matches the other options within its list box container.
node_data->role = ax::mojom::Role::kListBoxOption;
node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
IsSelected());
}
// static
views::FlexRule OmniboxTabSwitchButton::GetFlexRule() {
// The rule below snaps between full, short, icon-only, and zero widths.
return base::BindRepeating(
[](const views::View* view, const views::SizeBounds& maximum_size) {
gfx::Size preferred_size = view->GetPreferredSize();
int width;
if (!maximum_size.width().is_bounded()) {
// Until width is bounded, return 0 to allocate flex excess correctly.
width = 0;
} else if (full_text_width_ <= maximum_size.width()) {
width = full_text_width_;
} else if (short_text_width_ <= maximum_size.width()) {
width = short_text_width_;
} else if (icon_only_width_ < maximum_size.width()) {
width = icon_only_width_;
} else {
// Available width is too small to fit even the icon only. So don't
// show button at all.
width = 0;
}
return gfx::Size(width, preferred_size.height());
});
}
void OmniboxTabSwitchButton::UpdateBackground() {
focus_ring()->SchedulePaint();
}
bool OmniboxTabSwitchButton::IsSelected() const {
// Is this result selected and is button selected?
return result_view_->GetMatchSelected() &&
popup_contents_view_->model()->selected_line_state() ==
OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH;
}
BEGIN_METADATA(OmniboxTabSwitchButton, views::MdTextButton)
END_METADATA