Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Side by Side Diff: ui/views/examples/box_layout_example.cc

Issue 2836313002: BoxLayout now suports per-view margins. (Closed)
Patch Set: Merged with master. Removed cached orientation_ from ViewWrapper. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/views/examples/box_layout_example.h ('k') | ui/views/examples/examples_window.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 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 "box_layout_example.h"
6
7 #include <vector>
8
9 #include "base/memory/ptr_util.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "third_party/skia/include/core/SkColor.h"
14 #include "ui/base/models/combobox_model.h"
15 #include "ui/gfx/geometry/insets.h"
16 #include "ui/gfx/geometry/point.h"
17 #include "ui/gfx/geometry/rect.h"
18 #include "ui/views/border.h"
19 #include "ui/views/controls/button/checkbox.h"
20 #include "ui/views/controls/button/md_text_button.h"
21 #include "ui/views/controls/combobox/combobox.h"
22 #include "ui/views/controls/label.h"
23 #include "ui/views/controls/textfield/textfield.h"
24 #include "ui/views/examples/example_combobox_model.h"
25 #include "ui/views/layout/fill_layout.h"
26 #include "ui/views/view.h"
27 #include "ui/views/view_properties.h"
28
29 namespace views {
30 namespace examples {
31
32 namespace {
33
34 // This View holds two other views which consists of a view on the left onto
35 // which the BoxLayout is attached for demonstrating its features. The view
36 // on the right contains all the various controls which allow the user to
37 // interactively control the various features/properties of BoxLayout. Layout()
38 // will ensure the left view takes 75% and the right view fills the remaining
39 // 25%.
40 class FullPanel : public View {
41 public:
42 FullPanel() {}
43 ~FullPanel() override {}
44
45 // View
46 void Layout() override;
47
48 private:
49 DISALLOW_COPY_AND_ASSIGN(FullPanel);
50 };
51
52 // This view is created and added to the left-side view in the FullPanel each
53 // time the "Add" button is pressed. It also will display Textfield controls
54 // when the mouse is pressed over the view. These Textfields allow the user to
55 // interactively set each margin and the "flex" for the given view.
56 class ChildPanel : public View, public TextfieldController {
57 public:
58 explicit ChildPanel(BoxLayoutExample* example, gfx::Size preferred_size);
59 ~ChildPanel() override {}
60
61 // View
62 gfx::Size CalculatePreferredSize() const override;
63 bool OnMousePressed(const ui::MouseEvent& event) override;
64 void Layout() override;
65
66 void SetSelected(bool value);
67 bool selected() const { return selected_; };
68
69 int GetFlex();
70
71 private:
72 // TextfieldController
73 void ContentsChanged(Textfield* sender,
74 const base::string16& new_contents) override;
75
76 Textfield* CreateTextfield();
77
78 BoxLayoutExample* example_;
79 bool selected_ = false;
80 Textfield* flex_;
81 Textfield* margin_[4];
82 gfx::Size preferred_size_;
83
84 DISALLOW_COPY_AND_ASSIGN(ChildPanel);
85 };
86
87 void FullPanel::Layout() {
88 DCHECK_EQ(child_count(), 2);
89 View* left_panel = child_at(0);
90 View* right_panel = child_at(1);
91 gfx::Rect bounds = GetContentsBounds();
92 left_panel->SetBounds(bounds.x(), bounds.y(), (bounds.width() * 75) / 100,
93 bounds.height());
94 right_panel->SetBounds(left_panel->width(), bounds.y(),
95 bounds.width() - left_panel->width(), bounds.height());
96 }
97
98 ChildPanel::ChildPanel(BoxLayoutExample* example, gfx::Size preferred_size)
99 : View(), example_(example), preferred_size_(preferred_size) {
100 SetBorder(CreateSolidBorder(1, SK_ColorGRAY));
101 for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i)
102 margin_[i] = CreateTextfield();
103 flex_ = CreateTextfield();
104 flex_->SetText(base::ASCIIToUTF16(""));
105 }
106
107 gfx::Size ChildPanel::CalculatePreferredSize() const {
108 return preferred_size_;
109 }
110
111 bool ChildPanel::OnMousePressed(const ui::MouseEvent& event) {
112 if (event.IsOnlyLeftMouseButton())
113 SetSelected(true);
114 return true;
115 }
116
117 void ChildPanel::Layout() {
118 const int kSpacing = 2;
119 if (selected_) {
120 gfx::Rect client = GetContentsBounds();
121 for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
122 gfx::Point pos;
123 Textfield* textfield = margin_[i];
124 switch (i) {
125 case 0:
126 pos = gfx::Point((client.width() - textfield->width()) / 2, kSpacing);
127 break;
128 case 1:
129 pos =
130 gfx::Point(kSpacing, (client.height() - textfield->height()) / 2);
131 break;
132 case 2:
133 pos = gfx::Point((client.width() - textfield->width()) / 2,
134 client.height() - textfield->height() - kSpacing);
135 break;
136 case 3:
137 pos = gfx::Point(client.width() - textfield->width() - kSpacing,
138 (client.height() - textfield->height()) / 2);
139 break;
140 default:
141 NOTREACHED();
142 }
143 textfield->SetPosition(pos);
144 }
145 flex_->SetPosition(gfx::Point((client.width() - flex_->width()) / 2,
146 (client.height() - flex_->height()) / 2));
147 }
148 }
149
150 void ChildPanel::SetSelected(bool value) {
151 if (value != selected_) {
152 selected_ = value;
153 SetBorder(CreateSolidBorder(1, selected_ ? SK_ColorBLACK : SK_ColorGRAY));
154 if (selected_ && parent()) {
155 for (int i = 0; i < parent()->child_count(); ++i) {
156 View* child = parent()->child_at(i);
157 if (child != this && child->GetGroup() == GetGroup()) {
158 ChildPanel* child_panel = static_cast<ChildPanel*>(child);
159 child_panel->SetSelected(false);
160 }
161 }
162 }
163 for (Textfield* textfield : margin_)
164 textfield->SetVisible(selected_);
165 flex_->SetVisible(selected_);
166 InvalidateLayout();
167 example_->RefreshLayoutPanel();
168 }
169 }
170
171 int ChildPanel::GetFlex() {
172 int flex;
173 if (base::StringToInt(flex_->text(), &flex))
174 return flex;
175 return -1;
176 }
177
178 void ChildPanel::ContentsChanged(Textfield* sender,
179 const base::string16& new_contents) {
180 int edges[4];
181 for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
182 base::StringToInt(margin_[i]->text(), &edges[i]);
183 }
184 gfx::Insets margins = gfx::Insets(edges[0], edges[1], edges[2], edges[3]);
185 if (!margins.IsEmpty())
186 this->SetProperty(kMarginsKey, new gfx::Insets(margins));
187 else
188 this->ClearProperty(kMarginsKey);
189 if (sender == flex_)
190 example_->UpdateLayoutManager();
191 example_->RefreshLayoutPanel();
192 }
193
194 Textfield* ChildPanel::CreateTextfield() {
195 Textfield* textfield = new Textfield();
196 textfield->set_default_width_in_chars(3);
197 textfield->SizeToPreferredSize();
198 textfield->SetText(base::ASCIIToUTF16("0"));
199 textfield->set_controller(this);
200 textfield->SetVisible(false);
201 AddChildView(textfield);
202 return textfield;
203 }
204
205 const int kSpacing = 3;
206 const int kPadding = 8;
207 const int kMaxPanels = 5;
208 const int kChildPanelGroup = 100;
209 const int kChildPanelWidth = 180;
210 const int kChildPanelHeight = 90;
211 const char* orientation_values[2] = {"Horizontal", "Vertical"};
212 const char* main_axis_values[3] = {"Start", "Center", "End"};
213 const char* cross_axis_values[4] = {"Stretch", "Start", "Center", "End"};
214 }
215
216 BoxLayoutExample::BoxLayoutExample() : ExampleBase("Box Layout") {}
217
218 BoxLayoutExample::~BoxLayoutExample() {}
219
220 Combobox* BoxLayoutExample::CreateCombobox(const base::string16& label_text,
221 const char** items,
222 int count,
223 int& vertical_pos) {
224 Label* label = new Label(label_text);
225 label->SetPosition(gfx::Point(kPadding, vertical_pos));
226 label->SizeToPreferredSize();
227 Combobox* combo_box =
228 new Combobox(base::MakeUnique<ExampleComboboxModel>(items, count));
229 combo_box->SetPosition(
230 gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
231 combo_box->SizeToPreferredSize();
232 combo_box->set_listener(this);
233 label->SetSize(gfx::Size(label->width(), combo_box->height()));
234 control_panel_->AddChildView(label);
235 control_panel_->AddChildView(combo_box);
236 vertical_pos += combo_box->height() + kSpacing;
237 return combo_box;
238 }
239
240 Textfield* BoxLayoutExample::CreateRawTextfield(int& horizontal_pos,
241 int vertical_pos,
242 bool add) {
243 Textfield* text_field = new Textfield();
244 text_field->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
245 text_field->set_default_width_in_chars(3);
246 text_field->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
247 text_field->SizeToPreferredSize();
248 text_field->SetText(base::ASCIIToUTF16("0"));
249 text_field->set_controller(this);
250 horizontal_pos += text_field->width() + kSpacing;
251 if (add)
252 control_panel_->AddChildView(text_field);
253 return text_field;
254 }
255
256 Textfield* BoxLayoutExample::CreateTextfield(const base::string16& label_text,
257 int& vertical_pos) {
258 Label* label = new Label(label_text);
259 label->SetPosition(gfx::Point(kPadding, vertical_pos));
260 label->SizeToPreferredSize();
261 int horizontal_pos = label->x() + label->width() + kSpacing;
262 Textfield* text_field =
263 CreateRawTextfield(horizontal_pos, vertical_pos, false);
264 label->SetSize(gfx::Size(label->width(), text_field->height()));
265 control_panel_->AddChildView(label);
266 control_panel_->AddChildView(text_field);
267 vertical_pos += text_field->height() + kSpacing;
268 return text_field;
269 }
270
271 gfx::Size BoxLayoutExample::GetChildPanelSize() const {
272 int width;
273 int height;
274 if (!base::StringToInt(child_panel_size_[0]->text(), &width))
275 width = kChildPanelWidth;
276 if (!base::StringToInt(child_panel_size_[1]->text(), &height))
277 height = kChildPanelHeight;
278 return gfx::Size(std::max(0, width), std::max(0, height));
279 }
280
281 void BoxLayoutExample::CreateExampleView(View* container) {
282 container->SetLayoutManager(new FillLayout());
283 full_panel_ = new FullPanel();
284 container->AddChildView(full_panel_);
285
286 box_layout_panel_ = new View();
287 box_layout_panel_->SetBorder(CreateSolidBorder(1, SK_ColorLTGRAY));
288 full_panel_->AddChildView(box_layout_panel_);
289 control_panel_ = new View();
290 full_panel_->AddChildView(control_panel_);
291
292 int vertical_pos = kSpacing;
293 int horizontal_pos = kPadding;
294 add_button_ =
295 MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Add"));
296 add_button_->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
297 add_button_->SizeToPreferredSize();
298 control_panel_->AddChildView(add_button_);
299 horizontal_pos += add_button_->width() + kSpacing;
300 for (unsigned i = 0;
301 i < sizeof(child_panel_size_) / sizeof(child_panel_size_[0]); ++i) {
302 child_panel_size_[i] =
303 CreateRawTextfield(horizontal_pos, vertical_pos, true);
304 child_panel_size_[i]->SetY(
305 vertical_pos +
306 (add_button_->height() - child_panel_size_[i]->height()) / 2);
307 }
308 child_panel_size_[0]->SetText(base::IntToString16(kChildPanelWidth));
309 child_panel_size_[1]->SetText(base::IntToString16(kChildPanelHeight));
310 vertical_pos += add_button_->height() + kSpacing;
311
312 orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"),
313 orientation_values, 2, vertical_pos);
314 main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"),
315 main_axis_values, 3, vertical_pos);
316 cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"),
317 cross_axis_values, 4, vertical_pos);
318
319 between_child_spacing_ =
320 CreateTextfield(base::ASCIIToUTF16("Child spacing"), vertical_pos);
321 default_flex_ =
322 CreateTextfield(base::ASCIIToUTF16("Default flex"), vertical_pos);
323 min_cross_axis_size_ =
324 CreateTextfield(base::ASCIIToUTF16("Min cross axis"), vertical_pos);
325
326 border_insets_[0] =
327 CreateTextfield(base::ASCIIToUTF16("Insets"), vertical_pos);
328 horizontal_pos =
329 border_insets_[0]->x() + border_insets_[0]->width() + kSpacing;
330 for (unsigned i = 1; i < sizeof(border_insets_) / sizeof(border_insets_[0]);
331 ++i)
332 border_insets_[i] =
333 CreateRawTextfield(horizontal_pos, border_insets_[0]->y(), true);
334
335 collapse_margins_ = new Checkbox(base::ASCIIToUTF16("Collapse margins"));
336 collapse_margins_->SetPosition(gfx::Point(kPadding, vertical_pos));
337 collapse_margins_->SizeToPreferredSize();
338 collapse_margins_->set_listener(this);
339 control_panel_->AddChildView(collapse_margins_);
340
341 UpdateLayoutManager();
342 }
343
344 void BoxLayoutExample::ButtonPressed(Button* sender, const ui::Event& event) {
345 if (sender == add_button_) {
346 if (panel_count_ < kMaxPanels) {
347 ++panel_count_;
348 ChildPanel* panel = new ChildPanel(this, GetChildPanelSize());
349 panel->SetGroup(kChildPanelGroup);
350 box_layout_panel_->AddChildView(panel);
351 RefreshLayoutPanel();
352 } else {
353 PrintStatus("Only %i panels may be added", kMaxPanels);
354 }
355 } else if (sender == collapse_margins_) {
356 UpdateLayoutManager();
357 RefreshLayoutPanel();
358 }
359 }
360
361 void BoxLayoutExample::OnPerformAction(Combobox* combobox) {
362 if (combobox == orientation_) {
363 UpdateLayoutManager();
364 } else if (combobox == main_axis_alignment_) {
365 layout_->set_main_axis_alignment(static_cast<BoxLayout::MainAxisAlignment>(
366 main_axis_alignment_->selected_index()));
367 } else if (combobox == cross_axis_alignment_) {
368 layout_->set_cross_axis_alignment(
369 static_cast<BoxLayout::CrossAxisAlignment>(
370 cross_axis_alignment_->selected_index()));
371 }
372 RefreshLayoutPanel();
373 }
374
375 void BoxLayoutExample::ContentsChanged(Textfield* textfield,
376 const base::string16& new_contents) {
377 if (textfield == between_child_spacing_) {
378 UpdateLayoutManager();
379 } else if (textfield == default_flex_) {
380 int default_flex;
381 base::StringToInt(default_flex_->text(), &default_flex);
382 layout_->SetDefaultFlex(default_flex);
383 } else if (textfield == min_cross_axis_size_) {
384 int min_cross_size;
385 base::StringToInt(min_cross_axis_size_->text(), &min_cross_size);
386 layout_->set_minimum_cross_axis_size(min_cross_size);
387 } else if (textfield == border_insets_[0] || textfield == border_insets_[1] ||
388 textfield == border_insets_[2] || textfield == border_insets_[3]) {
389 UpdateBorderInsets();
390 }
391 RefreshLayoutPanel();
392 }
393
394 void BoxLayoutExample::RefreshLayoutPanel() {
395 box_layout_panel_->Layout();
396 box_layout_panel_->SchedulePaint();
397 }
398
399 void BoxLayoutExample::UpdateBorderInsets() {
400 int inset_values[4];
401 for (unsigned i = 0; i < sizeof(border_insets_) / sizeof(border_insets_[0]);
402 ++i)
403 base::StringToInt(border_insets_[i]->text(), &inset_values[i]);
404 layout_->set_inside_border_insets(gfx::Insets(
405 inset_values[0], inset_values[1], inset_values[2], inset_values[3]));
406 }
407
408 void BoxLayoutExample::UpdateLayoutManager() {
409 int child_spacing;
410 int default_flex;
411 int min_cross_size;
412 base::StringToInt(between_child_spacing_->text(), &child_spacing);
413 base::StringToInt(default_flex_->text(), &default_flex);
414 base::StringToInt(min_cross_axis_size_->text(), &min_cross_size);
415 layout_ = new BoxLayout(
416 orientation_->selected_index() == 0 ? BoxLayout::Orientation::kHorizontal
417 : BoxLayout::Orientation::kVertical,
418 gfx::Insets(0, 0), child_spacing, collapse_margins_->checked());
419 layout_->set_cross_axis_alignment(static_cast<BoxLayout::CrossAxisAlignment>(
420 cross_axis_alignment_->selected_index()));
421 layout_->set_main_axis_alignment(static_cast<BoxLayout::MainAxisAlignment>(
422 main_axis_alignment_->selected_index()));
423 layout_->SetDefaultFlex(default_flex);
424 layout_->set_minimum_cross_axis_size(min_cross_size);
425 UpdateBorderInsets();
426 box_layout_panel_->SetLayoutManager(layout_);
427 for (int i = 0; i < box_layout_panel_->child_count(); ++i) {
428 ChildPanel* panel =
429 static_cast<ChildPanel*>(box_layout_panel_->child_at(i));
430 int flex = panel->GetFlex();
431 if (flex < 0)
432 layout_->ClearFlexForView(panel);
433 else
434 layout_->SetFlexForView(panel, flex);
435 }
436 }
437
438 } // namespace examples
439 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/examples/box_layout_example.h ('k') | ui/views/examples/examples_window.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698