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 
5 #include "ash/system/tray/tri_view.h"
6 
7 #include "ash/system/tray/size_range_layout.h"
8 #include "base/check.h"
9 #include "base/notreached.h"
10 #include "ui/gfx/geometry/insets.h"
11 #include "ui/views/border.h"
12 #include "ui/views/layout/box_layout.h"
13 #include "ui/views/layout/fill_layout.h"
14 #include "ui/views/layout/layout_manager.h"
15 
16 namespace ash {
17 namespace {
18 
19 // Converts TriView::Orientation values to views::BoxLayout::Orientation values.
GetOrientation(TriView::Orientation orientation)20 views::BoxLayout::Orientation GetOrientation(TriView::Orientation orientation) {
21   switch (orientation) {
22     case TriView::Orientation::HORIZONTAL:
23       return views::BoxLayout::Orientation::kHorizontal;
24     case TriView::Orientation::VERTICAL:
25       return views::BoxLayout::Orientation::kVertical;
26   }
27   // Required for some compilers.
28   NOTREACHED();
29   return views::BoxLayout::Orientation::kHorizontal;
30 }
31 
32 // A View that will perform a layout if a child view's preferred size changes.
33 class RelayoutView : public views::View {
34  public:
35   RelayoutView() = default;
36 
37   // views::View:
ChildPreferredSizeChanged(View * child)38   void ChildPreferredSizeChanged(View* child) override { Layout(); }
39 
40  private:
41   DISALLOW_COPY_AND_ASSIGN(RelayoutView);
42 };
43 
44 }  // namespace
45 
TriView()46 TriView::TriView() : TriView(0) {}
47 
TriView(int padding_between_containers)48 TriView::TriView(int padding_between_containers)
49     : TriView(Orientation::HORIZONTAL, padding_between_containers) {}
50 
TriView(Orientation orientation)51 TriView::TriView(Orientation orientation) : TriView(orientation, 0) {}
52 
TriView(Orientation orientation,int padding_between_containers)53 TriView::TriView(Orientation orientation, int padding_between_containers) {
54   AddChildView(new RelayoutView);
55   AddChildView(new RelayoutView);
56   AddChildView(new RelayoutView);
57 
58   start_container_layout_manager_ =
59       GetContainer(Container::START)
60           ->SetLayoutManager(std::make_unique<SizeRangeLayout>());
61   center_container_layout_manager_ =
62       GetContainer(Container::CENTER)
63           ->SetLayoutManager(std::make_unique<SizeRangeLayout>());
64   end_container_layout_manager_ =
65       GetContainer(Container::END)
66           ->SetLayoutManager(std::make_unique<SizeRangeLayout>());
67 
68   auto layout = std::make_unique<views::BoxLayout>(
69       GetOrientation(orientation), gfx::Insets(), padding_between_containers);
70   layout->set_cross_axis_alignment(
71       views::BoxLayout::CrossAxisAlignment::kStart);
72   box_layout_ = SetLayoutManager(std::move(layout));
73 
74   enable_hierarchy_changed_dcheck_ = true;
75 }
76 
~TriView()77 TriView::~TriView() {
78   enable_hierarchy_changed_dcheck_ = false;
79 }
80 
SetMinHeight(int height)81 void TriView::SetMinHeight(int height) {
82   gfx::Size min_size;
83 
84   min_size = GetMinSize(TriView::Container::START);
85   min_size.set_height(height);
86   SetMinSize(TriView::Container::START, min_size);
87 
88   min_size = GetMinSize(TriView::Container::CENTER);
89   min_size.set_height(height);
90   SetMinSize(TriView::Container::CENTER, min_size);
91 
92   min_size = GetMinSize(TriView::Container::END);
93   min_size.set_height(height);
94   SetMinSize(TriView::Container::END, min_size);
95 }
96 
SetMinSize(Container container,const gfx::Size & size)97 void TriView::SetMinSize(Container container, const gfx::Size& size) {
98   GetLayoutManager(container)->SetMinSize(size);
99 }
100 
GetMinSize(Container container)101 gfx::Size TriView::GetMinSize(Container container) {
102   return GetLayoutManager(container)->min_size();
103 }
104 
SetMaxSize(Container container,const gfx::Size & size)105 void TriView::SetMaxSize(Container container, const gfx::Size& size) {
106   GetLayoutManager(container)->SetMaxSize(size);
107 }
108 
AddView(Container container,views::View * view)109 void TriView::AddView(Container container, views::View* view) {
110   GetContainer(container)->AddChildView(view);
111 }
112 
RemoveAllChildren(Container container,bool delete_children)113 void TriView::RemoveAllChildren(Container container, bool delete_children) {
114   GetContainer(container)->RemoveAllChildViews(delete_children);
115 }
116 
SetInsets(const gfx::Insets & insets)117 void TriView::SetInsets(const gfx::Insets& insets) {
118   box_layout_->set_inside_border_insets(insets);
119 }
120 
SetContainerBorder(Container container,std::unique_ptr<views::Border> border)121 void TriView::SetContainerBorder(Container container,
122                                  std::unique_ptr<views::Border> border) {
123   GetContainer(container)->SetBorder(std::move(border));
124 }
125 
SetContainerVisible(Container container,bool visible)126 void TriView::SetContainerVisible(Container container, bool visible) {
127   if (GetContainer(container)->GetVisible() == visible)
128     return;
129   GetContainer(container)->SetVisible(visible);
130   Layout();
131 }
132 
SetFlexForContainer(Container container,int flex)133 void TriView::SetFlexForContainer(Container container, int flex) {
134   box_layout_->SetFlexForView(GetContainer(container), flex);
135 }
136 
SetContainerLayout(Container container,std::unique_ptr<views::LayoutManager> layout_manager)137 void TriView::SetContainerLayout(
138     Container container,
139     std::unique_ptr<views::LayoutManager> layout_manager) {
140   GetLayoutManager(container)->SetLayoutManager(std::move(layout_manager));
141 }
142 
ViewHierarchyChanged(const views::ViewHierarchyChangedDetails & details)143 void TriView::ViewHierarchyChanged(
144     const views::ViewHierarchyChangedDetails& details) {
145   views::View::ViewHierarchyChanged(details);
146   if (!enable_hierarchy_changed_dcheck_)
147     return;
148 
149   if (details.parent == this) {
150     if (details.is_add) {
151       DCHECK(false)
152           << "Child views should not be added directly. They should be added "
153              "using TriView::AddView().";
154     } else {
155       DCHECK(false) << "Container views should not be removed.";
156     }
157   }
158 }
159 
GetClassName() const160 const char* TriView::GetClassName() const {
161   return "TriView";
162 }
163 
GetContainer(Container container)164 views::View* TriView::GetContainer(Container container) {
165   return children()[static_cast<size_t>(container)];
166 }
167 
GetLayoutManager(Container container)168 SizeRangeLayout* TriView::GetLayoutManager(Container container) {
169   switch (container) {
170     case Container::START:
171       return start_container_layout_manager_;
172     case Container::CENTER:
173       return center_container_layout_manager_;
174     case Container::END:
175       return end_container_layout_manager_;
176   }
177   // Required for some compilers.
178   NOTREACHED();
179   return nullptr;
180 }
181 
182 }  // namespace ash
183