feature_pod_button.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/system/unified/feature_pod_button.h"
  5. #include "ash/resources/vector_icons/vector_icons.h"
  6. #include "ash/strings/grit/ash_strings.h"
  7. #include "ash/style/ash_color_provider.h"
  8. #include "ash/style/style_util.h"
  9. #include "ash/system/tray/tray_constants.h"
  10. #include "ash/system/unified/feature_pod_controller_base.h"
  11. #include "ui/base/metadata/metadata_impl_macros.h"
  12. #include "ui/color/color_id.h"
  13. #include "ui/compositor/layer.h"
  14. #include "ui/gfx/paint_vector_icon.h"
  15. #include "ui/views/accessibility/view_accessibility.h"
  16. #include "ui/views/border.h"
  17. #include "ui/views/controls/focus_ring.h"
  18. #include "ui/views/controls/highlight_path_generator.h"
  19. #include "ui/views/controls/image_view.h"
  20. #include "ui/views/controls/label.h"
  21. #include "ui/views/layout/box_layout.h"
  22. #include "ui/views/view_class_properties.h"
  23. namespace ash {
  24. using ContentLayerType = AshColorProvider::ContentLayerType;
  25. using ControlsLayerType = AshColorProvider::ControlsLayerType;
  26. namespace {
  27. void ConfigureFeaturePodLabel(views::Label* label,
  28. int line_height,
  29. int font_size) {
  30. label->SetAutoColorReadabilityEnabled(false);
  31. label->SetSubpixelRenderingEnabled(false);
  32. label->SetCanProcessEventsWithinSubtree(false);
  33. label->SetLineHeight(line_height);
  34. gfx::Font default_font;
  35. gfx::Font label_font =
  36. default_font.Derive(font_size - default_font.GetFontSize(),
  37. gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
  38. gfx::FontList font_list(label_font);
  39. label->SetFontList(font_list);
  40. }
  41. } // namespace
  42. FeaturePodIconButton::FeaturePodIconButton(PressedCallback callback,
  43. bool is_togglable)
  44. : IconButton(std::move(callback),
  45. IconButton::Type::kMedium,
  46. /*icon=*/nullptr,
  47. is_togglable,
  48. /*has_border=*/true) {
  49. SetFlipCanvasOnPaintForRTLUI(false);
  50. GetViewAccessibility().OverrideIsLeaf(true);
  51. }
  52. FeaturePodIconButton::~FeaturePodIconButton() = default;
  53. BEGIN_METADATA(FeaturePodIconButton, IconButton)
  54. END_METADATA
  55. FeaturePodLabelButton::FeaturePodLabelButton(PressedCallback callback)
  56. : Button(std::move(callback)),
  57. label_(new views::Label),
  58. sub_label_(new views::Label),
  59. detailed_view_arrow_(new views::ImageView) {
  60. SetBorder(views::CreateEmptyBorder(kUnifiedFeaturePodHoverPadding));
  61. GetViewAccessibility().OverrideIsLeaf(true);
  62. label_->SetLineHeight(kUnifiedFeaturePodLabelLineHeight);
  63. label_->SetMultiLine(true);
  64. label_->SetMaxLines(kUnifiedFeaturePodLabelMaxLines);
  65. ConfigureFeaturePodLabel(label_, kUnifiedFeaturePodLabelLineHeight,
  66. kUnifiedFeaturePodLabelFontSize);
  67. ConfigureFeaturePodLabel(sub_label_, kUnifiedFeaturePodSubLabelLineHeight,
  68. kUnifiedFeaturePodSubLabelFontSize);
  69. sub_label_->SetVisible(false);
  70. detailed_view_arrow_->SetCanProcessEventsWithinSubtree(false);
  71. detailed_view_arrow_->SetVisible(false);
  72. AddChildView(label_);
  73. AddChildView(detailed_view_arrow_);
  74. AddChildView(sub_label_);
  75. StyleUtil::SetUpInkDropForButton(this);
  76. SetPaintToLayer();
  77. layer()->SetFillsBoundsOpaquely(false);
  78. views::InstallRoundRectHighlightPathGenerator(
  79. this, gfx::Insets(), kUnifiedFeaturePodHoverCornerRadius);
  80. views::FocusRing::Get(this)->SetColorId(ui::kColorAshFocusRing);
  81. }
  82. FeaturePodLabelButton::~FeaturePodLabelButton() = default;
  83. void FeaturePodLabelButton::Layout() {
  84. DCHECK(views::FocusRing::Get(this));
  85. views::FocusRing::Get(this)->Layout();
  86. LayoutInCenter(label_, GetContentsBounds().y());
  87. LayoutInCenter(sub_label_, GetContentsBounds().CenterPoint().y() +
  88. kUnifiedFeaturePodInterLabelPadding);
  89. if (!detailed_view_arrow_->GetVisible())
  90. return;
  91. // We need custom Layout() because |label_| is first laid out in the center
  92. // without considering |detailed_view_arrow_|, then |detailed_view_arrow_| is
  93. // placed on the right side of |label_|.
  94. gfx::Size arrow_size = detailed_view_arrow_->GetPreferredSize();
  95. detailed_view_arrow_->SetBoundsRect(gfx::Rect(
  96. gfx::Point(label_->bounds().right() + kUnifiedFeaturePodArrowSpacing,
  97. label_->bounds().CenterPoint().y() - arrow_size.height() / 2),
  98. arrow_size));
  99. }
  100. gfx::Size FeaturePodLabelButton::CalculatePreferredSize() const {
  101. // Minimum width of the button
  102. int width = kUnifiedFeaturePodLabelWidth + GetInsets().width();
  103. if (detailed_view_arrow_->GetVisible()) {
  104. const int label_width = std::min(kUnifiedFeaturePodLabelWidth,
  105. label_->GetPreferredSize().width());
  106. // Symmetrically increase the width to accommodate the arrow
  107. const int extra_space_for_arrow =
  108. 2 * (kUnifiedFeaturePodArrowSpacing +
  109. detailed_view_arrow_->GetPreferredSize().width());
  110. width = std::max(width,
  111. label_width + extra_space_for_arrow + GetInsets().width());
  112. }
  113. // Make sure there is sufficient margin around the label.
  114. int horizontal_margin = width - label_->GetPreferredSize().width();
  115. if (horizontal_margin < 2 * kUnifiedFeaturePodMinimumHorizontalMargin)
  116. width += 2 * kUnifiedFeaturePodMinimumHorizontalMargin - horizontal_margin;
  117. int height = label_->GetPreferredSize().height() + GetInsets().height();
  118. if (sub_label_->GetVisible()) {
  119. height += kUnifiedFeaturePodInterLabelPadding +
  120. sub_label_->GetPreferredSize().height();
  121. }
  122. return gfx::Size(width, height);
  123. }
  124. void FeaturePodLabelButton::OnThemeChanged() {
  125. views::Button::OnThemeChanged();
  126. OnEnabledChanged();
  127. }
  128. void FeaturePodLabelButton::SetLabel(const std::u16string& label) {
  129. label_->SetText(label);
  130. InvalidateLayout();
  131. }
  132. const std::u16string& FeaturePodLabelButton::GetLabelText() const {
  133. return label_->GetText();
  134. }
  135. void FeaturePodLabelButton::SetSubLabel(const std::u16string& sub_label) {
  136. sub_label_->SetText(sub_label);
  137. sub_label_->SetVisible(!sub_label.empty());
  138. label_->SetMultiLine(sub_label.empty());
  139. InvalidateLayout();
  140. }
  141. const std::u16string& FeaturePodLabelButton::GetSubLabelText() const {
  142. return sub_label_->GetText();
  143. }
  144. void FeaturePodLabelButton::ShowDetailedViewArrow() {
  145. detailed_view_arrow_->SetVisible(true);
  146. InvalidateLayout();
  147. }
  148. void FeaturePodLabelButton::OnEnabledChanged() {
  149. const AshColorProvider* color_provider = AshColorProvider::Get();
  150. const SkColor primary_text_color =
  151. color_provider->GetContentLayerColor(ContentLayerType::kTextColorPrimary);
  152. const SkColor secondary_text_color = color_provider->GetContentLayerColor(
  153. ContentLayerType::kTextColorSecondary);
  154. label_->SetEnabledColor(
  155. GetEnabled() ? primary_text_color
  156. : AshColorProvider::GetDisabledColor(primary_text_color));
  157. sub_label_->SetEnabledColor(
  158. GetEnabled() ? secondary_text_color
  159. : AshColorProvider::GetDisabledColor(secondary_text_color));
  160. const SkColor icon_color =
  161. color_provider->GetContentLayerColor(ContentLayerType::kIconColorPrimary);
  162. detailed_view_arrow_->SetImage(gfx::CreateVectorIcon(
  163. kUnifiedMenuMoreIcon,
  164. GetEnabled() ? icon_color
  165. : AshColorProvider::GetDisabledColor(icon_color)));
  166. }
  167. void FeaturePodLabelButton::LayoutInCenter(views::View* child, int y) {
  168. gfx::Rect contents_bounds = GetContentsBounds();
  169. gfx::Size preferred_size = child->GetPreferredSize();
  170. int child_width =
  171. std::min(kUnifiedFeaturePodLabelWidth, preferred_size.width());
  172. child->SetBounds(
  173. contents_bounds.x() + (contents_bounds.width() - child_width) / 2, y,
  174. child_width, preferred_size.height());
  175. }
  176. BEGIN_METADATA(FeaturePodLabelButton, views::Button)
  177. END_METADATA
  178. FeaturePodButton::FeaturePodButton(FeaturePodControllerBase* controller,
  179. bool is_togglable)
  180. : icon_button_(new FeaturePodIconButton(
  181. base::BindRepeating(&FeaturePodControllerBase::OnIconPressed,
  182. base::Unretained(controller)),
  183. is_togglable)),
  184. label_button_(new FeaturePodLabelButton(
  185. base::BindRepeating(&FeaturePodControllerBase::OnLabelPressed,
  186. base::Unretained(controller)))) {
  187. auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
  188. views::BoxLayout::Orientation::kVertical, gfx::Insets(),
  189. kUnifiedFeaturePodSpacing));
  190. layout->set_cross_axis_alignment(
  191. views::BoxLayout::CrossAxisAlignment::kCenter);
  192. AddChildView(icon_button_);
  193. AddChildView(label_button_);
  194. SetPaintToLayer();
  195. layer()->SetFillsBoundsOpaquely(false);
  196. }
  197. FeaturePodButton::~FeaturePodButton() = default;
  198. double FeaturePodButton::GetOpacityForExpandedAmount(double expanded_amount) {
  199. // TODO(amehfooz): Confirm the animation curve with UX.
  200. return std::max(0., 5. * expanded_amount - 4.);
  201. }
  202. void FeaturePodButton::SetVectorIcon(const gfx::VectorIcon& icon) {
  203. icon_button_->SetVectorIcon(icon);
  204. }
  205. void FeaturePodButton::SetLabel(const std::u16string& label) {
  206. if (label_button_->GetLabelText() == label)
  207. return;
  208. label_button_->SetLabel(label);
  209. Layout();
  210. label_button_->SchedulePaint();
  211. }
  212. void FeaturePodButton::SetSubLabel(const std::u16string& sub_label) {
  213. if (label_button_->GetSubLabelText() == sub_label)
  214. return;
  215. label_button_->SetSubLabel(sub_label);
  216. Layout();
  217. label_button_->SchedulePaint();
  218. }
  219. void FeaturePodButton::SetIconTooltip(const std::u16string& text) {
  220. icon_button_->SetTooltipText(text);
  221. }
  222. void FeaturePodButton::SetLabelTooltip(const std::u16string& text) {
  223. label_button_->SetTooltipText(text);
  224. }
  225. void FeaturePodButton::SetIconAndLabelTooltips(const std::u16string& text) {
  226. SetIconTooltip(text);
  227. SetLabelTooltip(text);
  228. }
  229. void FeaturePodButton::ShowDetailedViewArrow() {
  230. label_button_->ShowDetailedViewArrow();
  231. Layout();
  232. label_button_->SchedulePaint();
  233. }
  234. void FeaturePodButton::DisableLabelButtonFocus() {
  235. label_button_->SetFocusBehavior(FocusBehavior::NEVER);
  236. }
  237. void FeaturePodButton::SetToggled(bool toggled) {
  238. icon_button_->SetToggled(toggled);
  239. }
  240. void FeaturePodButton::SetExpandedAmount(double expanded_amount,
  241. bool fade_icon_button) {
  242. label_button_->SetVisible(expanded_amount > 0.0);
  243. label_button_->layer()->SetOpacity(
  244. GetOpacityForExpandedAmount(expanded_amount));
  245. if (fade_icon_button)
  246. layer()->SetOpacity(GetOpacityForExpandedAmount(expanded_amount));
  247. else
  248. layer()->SetOpacity(1.0);
  249. }
  250. void FeaturePodButton::SetVisibleByContainer(bool visible) {
  251. View::SetVisible(visible);
  252. }
  253. void FeaturePodButton::SetVisible(bool visible) {
  254. visible_preferred_ = visible;
  255. View::SetVisible(visible);
  256. }
  257. bool FeaturePodButton::HasFocus() const {
  258. return icon_button_->HasFocus() || label_button_->HasFocus();
  259. }
  260. void FeaturePodButton::RequestFocus() {
  261. label_button_->RequestFocus();
  262. }
  263. void FeaturePodButton::OnEnabledChanged() {
  264. icon_button_->SetEnabled(GetEnabled());
  265. label_button_->SetEnabled(GetEnabled());
  266. }
  267. BEGIN_METADATA(FeaturePodButton, views::View)
  268. END_METADATA
  269. } // namespace ash