tri_view.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright 2016 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/tray/tri_view.h"
  5. #include "ash/system/tray/size_range_layout.h"
  6. #include "base/check.h"
  7. #include "base/notreached.h"
  8. #include "ui/gfx/geometry/insets.h"
  9. #include "ui/views/border.h"
  10. #include "ui/views/layout/box_layout.h"
  11. #include "ui/views/layout/fill_layout.h"
  12. #include "ui/views/layout/layout_manager.h"
  13. namespace ash {
  14. namespace {
  15. // Converts TriView::Orientation values to views::BoxLayout::Orientation values.
  16. views::BoxLayout::Orientation GetOrientation(TriView::Orientation orientation) {
  17. switch (orientation) {
  18. case TriView::Orientation::HORIZONTAL:
  19. return views::BoxLayout::Orientation::kHorizontal;
  20. case TriView::Orientation::VERTICAL:
  21. return views::BoxLayout::Orientation::kVertical;
  22. }
  23. // Required for some compilers.
  24. NOTREACHED();
  25. return views::BoxLayout::Orientation::kHorizontal;
  26. }
  27. // A View that will perform a layout if a child view's preferred size changes.
  28. class RelayoutView : public views::View {
  29. public:
  30. RelayoutView() = default;
  31. RelayoutView(const RelayoutView&) = delete;
  32. RelayoutView& operator=(const RelayoutView&) = delete;
  33. // views::View:
  34. void ChildPreferredSizeChanged(View* child) override { Layout(); }
  35. };
  36. } // namespace
  37. TriView::TriView() : TriView(0) {}
  38. TriView::TriView(int padding_between_containers)
  39. : TriView(Orientation::HORIZONTAL, padding_between_containers) {}
  40. TriView::TriView(Orientation orientation) : TriView(orientation, 0) {}
  41. TriView::TriView(Orientation orientation, int padding_between_containers) {
  42. AddChildView(new RelayoutView);
  43. AddChildView(new RelayoutView);
  44. AddChildView(new RelayoutView);
  45. start_container_layout_manager_ =
  46. GetContainer(Container::START)
  47. ->SetLayoutManager(std::make_unique<SizeRangeLayout>());
  48. center_container_layout_manager_ =
  49. GetContainer(Container::CENTER)
  50. ->SetLayoutManager(std::make_unique<SizeRangeLayout>());
  51. end_container_layout_manager_ =
  52. GetContainer(Container::END)
  53. ->SetLayoutManager(std::make_unique<SizeRangeLayout>());
  54. auto layout = std::make_unique<views::BoxLayout>(
  55. GetOrientation(orientation), gfx::Insets(), padding_between_containers);
  56. layout->set_cross_axis_alignment(
  57. views::BoxLayout::CrossAxisAlignment::kStart);
  58. box_layout_ = SetLayoutManager(std::move(layout));
  59. enable_hierarchy_changed_dcheck_ = true;
  60. }
  61. TriView::~TriView() {
  62. enable_hierarchy_changed_dcheck_ = false;
  63. }
  64. void TriView::SetMinHeight(int height) {
  65. gfx::Size min_size;
  66. min_size = GetMinSize(TriView::Container::START);
  67. min_size.set_height(height);
  68. SetMinSize(TriView::Container::START, min_size);
  69. min_size = GetMinSize(TriView::Container::CENTER);
  70. min_size.set_height(height);
  71. SetMinSize(TriView::Container::CENTER, min_size);
  72. min_size = GetMinSize(TriView::Container::END);
  73. min_size.set_height(height);
  74. SetMinSize(TriView::Container::END, min_size);
  75. }
  76. void TriView::SetMinSize(Container container, const gfx::Size& size) {
  77. GetLayoutManager(container)->SetMinSize(size);
  78. }
  79. gfx::Size TriView::GetMinSize(Container container) {
  80. return GetLayoutManager(container)->min_size();
  81. }
  82. void TriView::SetMaxSize(Container container, const gfx::Size& size) {
  83. GetLayoutManager(container)->SetMaxSize(size);
  84. }
  85. void TriView::AddView(Container container, views::View* view) {
  86. GetContainer(container)->AddChildView(view);
  87. }
  88. void TriView::AddViewAt(Container container, views::View* view, int index) {
  89. GetContainer(container)->AddChildViewAt(view, index);
  90. }
  91. void TriView::SetInsets(const gfx::Insets& insets) {
  92. box_layout_->set_inside_border_insets(insets);
  93. }
  94. void TriView::SetContainerBorder(Container container,
  95. std::unique_ptr<views::Border> border) {
  96. GetContainer(container)->SetBorder(std::move(border));
  97. }
  98. void TriView::SetContainerVisible(Container container, bool visible) {
  99. if (GetContainer(container)->GetVisible() == visible)
  100. return;
  101. GetContainer(container)->SetVisible(visible);
  102. Layout();
  103. }
  104. void TriView::SetFlexForContainer(Container container, int flex) {
  105. box_layout_->SetFlexForView(GetContainer(container), flex);
  106. }
  107. void TriView::SetContainerLayout(
  108. Container container,
  109. std::unique_ptr<views::LayoutManager> layout_manager) {
  110. GetLayoutManager(container)->SetLayoutManager(std::move(layout_manager));
  111. }
  112. void TriView::ViewHierarchyChanged(
  113. const views::ViewHierarchyChangedDetails& details) {
  114. views::View::ViewHierarchyChanged(details);
  115. if (!enable_hierarchy_changed_dcheck_)
  116. return;
  117. if (details.parent == this) {
  118. if (details.is_add) {
  119. DCHECK(false)
  120. << "Child views should not be added directly. They should be added "
  121. "using TriView::AddView().";
  122. } else {
  123. DCHECK(false) << "Container views should not be removed.";
  124. }
  125. }
  126. }
  127. const char* TriView::GetClassName() const {
  128. return "TriView";
  129. }
  130. gfx::Rect TriView::GetAnchorBoundsInScreen() const {
  131. gfx::Rect bounds = View::GetAnchorBoundsInScreen();
  132. // Inset bounds a bit so that bubbles overlap the nominal empty space at
  133. // the bottom of the TriView slightly.
  134. // This specific piece of code was added to accommodate a specific refactoring
  135. // where anchor insets had to be removed from
  136. // NetworkStateListDetailedView::InfoBubble. This bubble is the only one I
  137. // could find that directly anchors directly to a TriView.
  138. // If there are other instantiations of TriView where this overlap doesn't
  139. // make sense, the below inset could be settable on TriView and called from
  140. // NetworkStateListDetailedView.
  141. bounds.Inset(gfx::Insets::TLBR(0, 0, 8, 0));
  142. return bounds;
  143. }
  144. views::View* TriView::GetContainer(Container container) {
  145. return children()[static_cast<size_t>(container)];
  146. }
  147. SizeRangeLayout* TriView::GetLayoutManager(Container container) {
  148. switch (container) {
  149. case Container::START:
  150. return start_container_layout_manager_;
  151. case Container::CENTER:
  152. return center_container_layout_manager_;
  153. case Container::END:
  154. return end_container_layout_manager_;
  155. }
  156. // Required for some compilers.
  157. NOTREACHED();
  158. return nullptr;
  159. }
  160. } // namespace ash