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

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

Issue 2836313002: BoxLayout now suports per-view margins. (Closed)
Patch Set: Added margin collapsing and a BoxLayout example Created 3 years, 7 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
OLDNEW
(Empty)
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved.
sky 2017/05/09 19:26:02 no (c)
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 "third_party/skia/include/core/SkColor.h"
13 #include "ui/base/models/combobox_model.h"
14 #include "ui/gfx/geometry/insets.h"
15 #include "ui/gfx/geometry/point.h"
16 #include "ui/gfx/geometry/rect.h"
17 #include "ui/views/border.h"
18 #include "ui/views/controls/button/checkbox.h"
19 #include "ui/views/controls/button/md_text_button.h"
20 #include "ui/views/controls/combobox/combobox.h"
21 #include "ui/views/controls/label.h"
22 #include "ui/views/controls/textfield/textfield.h"
23 #include "ui/views/layout/fill_layout.h"
24 #include "ui/views/view.h"
25
26 namespace views {
27 namespace examples {
28
29 namespace {
30
31 class FullPanel : public View {
sky 2017/05/09 19:26:02 Please add comments for classes. This name is conf
kylix_rd 2017/05/10 15:30:36 Done.
32 public:
33 FullPanel() {}
34 ~FullPanel() override {}
35
36 void Layout() override;
sky 2017/05/09 19:26:03 Prefix with where override comes from.
kylix_rd 2017/05/10 15:30:36 Done.
37
38 private:
39 DISALLOW_COPY_AND_ASSIGN(FullPanel);
40 };
41
42 class ChildPanel : public View, public TextfieldController {
43 public:
44 ChildPanel(BoxLayoutExample* example);
sky 2017/05/09 19:26:02 explicit.
kylix_rd 2017/05/10 15:30:36 Done.
45 ~ChildPanel() override {}
46
47 // View
48 gfx::Size GetPreferredSize() const override;
49 bool OnMousePressed(const ui::MouseEvent& event) override;
50 void Layout() override;
51
52 void set_listener(ViewListener* listener) { listener_ = listener; }
53 void SetSelected(bool value);
54 bool selected() const { return selected_; };
55
56 int GetFlex();
57
58 private:
59 // TextfieldController
60 void ContentsChanged(Textfield* sender,
61 const base::string16& new_contents) override;
62
63 Textfield* CreateTextfield();
64
65 BoxLayoutExample* example_;
66 bool selected_ = false;
67 ViewListener* listener_ = nullptr;
68 Textfield* flex_;
69 Textfield* margin_[4];
70
71 DISALLOW_COPY_AND_ASSIGN(ChildPanel);
72 };
73
74 class ExampleModel : public ui::ComboboxModel {
sky 2017/05/09 19:26:03 Can you use ui/views/examples/example_combobox_mod
kylix_rd 2017/05/10 15:30:36 Yep. I didn't notice it was there. Done.
75 public:
76 ExampleModel(const std::initializer_list<base::string16>& items)
77 : ui::ComboboxModel(), items_(items) {}
78 ~ExampleModel() override {}
79 // ComboboxModel
sky 2017/05/09 19:26:02 newline between 78/79.
80 int GetItemCount() const override { return items_.size(); }
81
82 base::string16 GetItemAt(int index) override { return items_[index]; }
83
84 private:
85 std::vector<base::string16> items_;
86
87 DISALLOW_COPY_AND_ASSIGN(ExampleModel);
88 };
89
90 void FullPanel::Layout() {
91 DCHECK_EQ(child_count(), 2);
92 View* left_panel = child_at(0);
93 View* right_panel = child_at(1);
94 gfx::Rect bounds = GetContentsBounds();
95 left_panel->SetBounds(bounds.x(), bounds.y(), (bounds.width() * 75) / 100,
96 bounds.height());
97 right_panel->SetBounds(left_panel->width(), bounds.y(),
98 bounds.width() - left_panel->width(), bounds.height());
99 }
100
101 ChildPanel::ChildPanel(BoxLayoutExample* example) : View(), example_(example) {
102 SetBorder(CreateSolidBorder(1, SK_ColorGRAY));
103 for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i)
104 margin_[i] = CreateTextfield();
105 flex_ = CreateTextfield();
106 flex_->SetText(L"");
107 }
108
109 gfx::Size ChildPanel::GetPreferredSize() const {
110 return gfx::Size(180, 90);
111 }
112
113 bool ChildPanel::OnMousePressed(const ui::MouseEvent& event) {
114 if (event.IsOnlyLeftMouseButton())
115 SetSelected(true);
116 return true;
117 }
118
119 void ChildPanel::Layout() {
120 const int kSpacing = 2;
121 if (selected_) {
122 gfx::Rect client = GetContentsBounds();
123 for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
124 gfx::Point pos;
125 Textfield* textfield = margin_[i];
126 switch (i) {
127 case 0:
128 pos = gfx::Point((client.width() - textfield->width()) / 2, kSpacing);
129 break;
130 case 1:
131 pos =
132 gfx::Point(kSpacing, (client.height() - textfield->height()) / 2);
133 break;
134 case 2:
135 pos = gfx::Point((client.width() - textfield->width()) / 2,
136 client.height() - textfield->height() - kSpacing);
137 break;
138 case 3:
139 pos = gfx::Point(client.width() - textfield->width() - kSpacing,
140 (client.height() - textfield->height()) / 2);
141 break;
142 default:
143 NOTREACHED();
144 }
145 textfield->SetPosition(pos);
146 }
147 flex_->SetPosition(gfx::Point((client.width() - flex_->width()) / 2,
148 (client.height() - flex_->height()) / 2));
149 }
150 }
151
152 void ChildPanel::SetSelected(bool value) {
153 if (value != selected_) {
154 selected_ = value;
155 SetBorder(CreateSolidBorder(1, selected_ ? SK_ColorBLACK : SK_ColorGRAY));
156 if (selected_ && parent()) {
157 for (int i = 0; i < parent()->child_count(); ++i) {
158 View* child = parent()->child_at(i);
159 if (child != this && child->GetGroup() == GetGroup()) {
160 ChildPanel* child_panel = static_cast<ChildPanel*>(child);
161 child_panel->SetSelected(false);
162 }
163 }
164 if (listener_)
165 listener_->ViewSelected(this);
166 }
167 for (Textfield* textfield : margin_)
168 textfield->SetVisible(selected_);
169 flex_->SetVisible(selected_);
170 InvalidateLayout();
171 example_->RefreshLayoutPanel();
172 }
173 }
174
175 int ChildPanel::GetFlex() {
176 int flex;
177 if (base::StringToInt(flex_->text(), &flex))
178 return flex;
179 return -1;
180 }
181
182 void ChildPanel::ContentsChanged(Textfield* sender,
183 const base::string16& new_contents) {
184 int edges[4];
185 for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
186 base::StringToInt(margin_[i]->text(), &edges[i]);
187 }
188 gfx::Insets margins = gfx::Insets(edges[0], edges[1], edges[2], edges[3]);
189 if (!margins.IsEmpty())
190 this->SetProperty(kMarginsKey, new gfx::Insets(margins));
191 else
192 this->ClearProperty(kMarginsKey);
193 if (sender == flex_)
194 example_->UpdateLayoutManager();
195 example_->RefreshLayoutPanel();
196 }
197
198 Textfield* ChildPanel::CreateTextfield() {
199 Textfield* textfield = new Textfield();
200 textfield->set_default_width_in_chars(3);
201 textfield->SizeToPreferredSize();
202 textfield->SetText(L"0");
203 textfield->set_controller(this);
204 textfield->SetVisible(false);
205 AddChildView(textfield);
206 return textfield;
207 }
208 }
209
210 BoxLayoutExample::BoxLayoutExample() : ExampleBase("Box Layout") {}
211
212 BoxLayoutExample::~BoxLayoutExample() {}
213
214 void BoxLayoutExample::CreateExampleView(View* container) {
215 const int kSpacing = 5;
216 const int kPadding = 8;
217 container->SetLayoutManager(new FillLayout());
218 full_panel_ = new FullPanel();
219 container->AddChildView(full_panel_);
220
221 box_layout_panel_ = new View();
222 box_layout_panel_->SetBorder(CreateSolidBorder(1, SK_ColorLTGRAY));
223 full_panel_->AddChildView(box_layout_panel_);
224 control_panel_ = new View();
225 full_panel_->AddChildView(control_panel_);
226
227 int vertical_pos = kPadding;
228 add_button_ = MdTextButton::CreateSecondaryUiButton(this, L"Add");
229 add_button_->SetPosition(gfx::Point(kPadding, vertical_pos));
230 add_button_->SizeToPreferredSize();
231 control_panel_->AddChildView(add_button_);
232 vertical_pos += add_button_->height() + kSpacing;
233
234 Label* label = new Label(L"Orientation");
235 label->SetPosition(gfx::Point(kPadding, vertical_pos));
236 label->SizeToPreferredSize();
237 orientation_ = new Combobox(base::MakeUnique<ExampleModel>(
238 std::initializer_list<base::string16>({L"Horizontal", L"Vertical"})));
239 orientation_->SetPosition(
240 gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
241 orientation_->SizeToPreferredSize();
242 orientation_->set_listener(this);
243 label->SetSize(gfx::Size(label->width(), orientation_->height()));
244 control_panel_->AddChildView(label);
245 control_panel_->AddChildView(orientation_);
246 vertical_pos += orientation_->height() + kSpacing;
247
248 label = new Label(L"Main axis");
249 label->SetPosition(gfx::Point(kPadding, vertical_pos));
250 label->SizeToPreferredSize();
251 main_axis_alignment_ = new Combobox(base::MakeUnique<ExampleModel>(
252 std::initializer_list<base::string16>({L"Start", L"Center", L"End"})));
253 main_axis_alignment_->SetPosition(
254 gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
255 main_axis_alignment_->SizeToPreferredSize();
256 main_axis_alignment_->set_listener(this);
257 label->SetSize(gfx::Size(label->width(), main_axis_alignment_->height()));
258 control_panel_->AddChildView(label);
259 control_panel_->AddChildView(main_axis_alignment_);
260 vertical_pos += main_axis_alignment_->height() + kSpacing;
261
262 label = new Label(L"Cross axis");
263 label->SetPosition(gfx::Point(kPadding, vertical_pos));
264 label->SizeToPreferredSize();
265 cross_axis_alignment_ = new Combobox(
266 base::MakeUnique<ExampleModel>(std::initializer_list<base::string16>(
267 {L"Stretch", L"Start", L"Center", L"End"})));
268 cross_axis_alignment_->SetPosition(
269 gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
270 cross_axis_alignment_->SizeToPreferredSize();
271 cross_axis_alignment_->set_listener(this);
272 label->SetSize(gfx::Size(label->width(), cross_axis_alignment_->height()));
273 control_panel_->AddChildView(label);
274 control_panel_->AddChildView(cross_axis_alignment_);
275 vertical_pos += cross_axis_alignment_->height() + kSpacing;
276
277 label = new Label(L"Child spacing");
278 label->SetPosition(gfx::Point(kPadding, vertical_pos));
279 label->SizeToPreferredSize();
280 between_child_spacing_ = new Textfield();
281 between_child_spacing_->SetPosition(
282 gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
283 between_child_spacing_->set_default_width_in_chars(3);
284 between_child_spacing_->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
285 between_child_spacing_->SizeToPreferredSize();
286 between_child_spacing_->SetText(L"0");
287 between_child_spacing_->set_controller(this);
288 label->SetSize(gfx::Size(label->width(), between_child_spacing_->height()));
289 control_panel_->AddChildView(label);
290 control_panel_->AddChildView(between_child_spacing_);
291 vertical_pos += between_child_spacing_->height() + kSpacing;
292
293 label = new Label(L"Default flex");
294 label->SetPosition(gfx::Point(kPadding, vertical_pos));
295 label->SizeToPreferredSize();
296 default_flex_ = new Textfield();
297 default_flex_->SetPosition(
298 gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
299 default_flex_->set_default_width_in_chars(3);
300 default_flex_->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
301 default_flex_->SizeToPreferredSize();
302 default_flex_->SetText(L"0");
303 default_flex_->set_controller(this);
304 label->SetSize(gfx::Size(label->width(), default_flex_->height()));
305 control_panel_->AddChildView(label);
306 control_panel_->AddChildView(default_flex_);
307 vertical_pos += default_flex_->height() + kSpacing;
308
309 label = new Label(L"Min cross axis");
310 label->SetPosition(gfx::Point(kPadding, vertical_pos));
311 label->SizeToPreferredSize();
312 min_cross_axis_size_ = new Textfield();
313 min_cross_axis_size_->SetPosition(
314 gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
315 min_cross_axis_size_->set_default_width_in_chars(3);
316 min_cross_axis_size_->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
317 min_cross_axis_size_->SizeToPreferredSize();
318 min_cross_axis_size_->SetText(L"0");
319 min_cross_axis_size_->set_controller(this);
320 label->SetSize(gfx::Size(label->width(), min_cross_axis_size_->height()));
321 control_panel_->AddChildView(label);
322 control_panel_->AddChildView(min_cross_axis_size_);
323 vertical_pos += min_cross_axis_size_->height() + kSpacing;
324
325 collapse_margins_ = new Checkbox(L"Collapse margins");
326 collapse_margins_->SetPosition(gfx::Point(kPadding, vertical_pos));
327 collapse_margins_->SizeToPreferredSize();
328 collapse_margins_->set_listener(this);
329 control_panel_->AddChildView(collapse_margins_);
330
331 UpdateLayoutManager();
332 }
333
334 void BoxLayoutExample::ButtonPressed(Button* sender, const ui::Event& event) {
335 if (sender == add_button_) {
336 if (panel_count_ < 5) {
337 ++panel_count_;
338 ChildPanel* panel = new ChildPanel(this);
339 panel->set_listener(this);
340 panel->SetGroup(100);
341 box_layout_panel_->AddChildView(panel);
342 RefreshLayoutPanel();
343 } else {
344 PrintStatus("Only 5 panels may be added");
345 }
346 } else if (sender == collapse_margins_) {
347 UpdateLayoutManager();
348 RefreshLayoutPanel();
349 }
350 }
351
352 void BoxLayoutExample::OnPerformAction(Combobox* combobox) {
353 if (combobox == orientation_) {
354 UpdateLayoutManager();
355 } else if (combobox == main_axis_alignment_) {
356 layout_->set_main_axis_alignment(static_cast<BoxLayout::MainAxisAlignment>(
357 main_axis_alignment_->selected_index()));
358 } else if (combobox == cross_axis_alignment_) {
359 layout_->set_cross_axis_alignment(
360 static_cast<BoxLayout::CrossAxisAlignment>(
361 cross_axis_alignment_->selected_index()));
362 }
363 RefreshLayoutPanel();
364 }
365
366 void BoxLayoutExample::ViewSelected(View* view) {}
367
368 void BoxLayoutExample::ContentsChanged(Textfield* textfield,
369 const base::string16& new_contents) {
370 if (textfield == between_child_spacing_) {
371 UpdateLayoutManager();
372 } else if (textfield == default_flex_) {
373 int default_flex;
374 base::StringToInt(default_flex_->text(), &default_flex);
375 layout_->SetDefaultFlex(default_flex);
376 } else if (textfield == min_cross_axis_size_) {
377 int min_cross_size;
378 base::StringToInt(min_cross_axis_size_->text(), &min_cross_size);
379 layout_->set_minimum_cross_axis_size(min_cross_size);
380 }
381 RefreshLayoutPanel();
382 }
383
384 void BoxLayoutExample::RefreshLayoutPanel() {
385 box_layout_panel_->Layout();
386 box_layout_panel_->SchedulePaint();
387 }
388
389 void BoxLayoutExample::UpdateLayoutManager() {
390 int child_spacing;
391 int default_flex;
392 int min_cross_size;
393 base::StringToInt(between_child_spacing_->text(), &child_spacing);
sky 2017/05/09 19:26:03 Remember that conversion may fail and return false
kylix_rd 2017/05/09 20:07:06 According to the doc, errors will set |*output| to
394 base::StringToInt(default_flex_->text(), &default_flex);
395 base::StringToInt(min_cross_axis_size_->text(), &min_cross_size);
396 layout_ = new BoxLayout(orientation_->selected_index() == 0
397 ? BoxLayout::Orientation::kHorizontal
398 : BoxLayout::Orientation::kVertical,
399 0, 0, child_spacing, collapse_margins_->checked());
400 layout_->set_cross_axis_alignment(static_cast<BoxLayout::CrossAxisAlignment>(
401 cross_axis_alignment_->selected_index()));
402 layout_->set_main_axis_alignment(static_cast<BoxLayout::MainAxisAlignment>(
403 main_axis_alignment_->selected_index()));
404 layout_->SetDefaultFlex(default_flex);
405 layout_->set_minimum_cross_axis_size(min_cross_size);
406 for (int i = 0; i < box_layout_panel_->child_count(); ++i) {
407 ChildPanel* panel =
408 static_cast<ChildPanel*>(box_layout_panel_->child_at(i));
409 int flex = panel->GetFlex();
410 if (flex < 0)
411 layout_->ClearFlexForView(panel);
412 else
413 layout_->SetFlexForView(panel, flex);
414 }
415 box_layout_panel_->SetLayoutManager(layout_);
416 }
417
418 } // namespace examples
419 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698