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

Side by Side Diff: ui/views/window/dialog_client_view.cc

Issue 2706423002: Use GridLayout for DialogClientView's button row. (Closed)
Patch Set: Rollback delete extra_view_ experiment Created 3 years, 9 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/window/dialog_client_view.h" 5 #include "ui/views/window/dialog_client_view.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "build/build_config.h" 9 #include "build/build_config.h"
10 #include "ui/base/material_design/material_design_controller.h" 10 #include "ui/base/material_design/material_design_controller.h"
11 #include "ui/events/keycodes/keyboard_codes.h" 11 #include "ui/events/keycodes/keyboard_codes.h"
12 #include "ui/views/background.h" 12 #include "ui/views/background.h"
13 #include "ui/views/border.h" 13 #include "ui/views/border.h"
14 #include "ui/views/controls/button/blue_button.h" 14 #include "ui/views/controls/button/blue_button.h"
15 #include "ui/views/controls/button/custom_button.h" 15 #include "ui/views/controls/button/custom_button.h"
16 #include "ui/views/controls/button/label_button.h" 16 #include "ui/views/controls/button/label_button.h"
17 #include "ui/views/controls/button/md_text_button.h" 17 #include "ui/views/controls/button/md_text_button.h"
18 #include "ui/views/layout/grid_layout.h"
18 #include "ui/views/style/platform_style.h" 19 #include "ui/views/style/platform_style.h"
19 #include "ui/views/views_delegate.h" 20 #include "ui/views/views_delegate.h"
20 #include "ui/views/widget/widget.h" 21 #include "ui/views/widget/widget.h"
21 #include "ui/views/window/dialog_delegate.h" 22 #include "ui/views/window/dialog_delegate.h"
22 23
23 namespace views { 24 namespace views {
24 25
25 namespace { 26 namespace {
26 27
27 // The group used by the buttons. This name is chosen voluntarily big not to 28 // The group used by the buttons. This name is chosen voluntarily big not to
28 // conflict with other groups that could be in the dialog content. 29 // conflict with other groups that could be in the dialog content.
29 const int kButtonGroup = 6666; 30 const int kButtonGroup = 6666;
30 31
31 #if defined(OS_WIN) || defined(OS_CHROMEOS) 32 #if defined(OS_WIN) || defined(OS_CHROMEOS)
32 const bool kIsOkButtonOnLeftSide = true; 33 const bool kIsOkButtonOnLeftSide = true;
33 #else 34 #else
34 const bool kIsOkButtonOnLeftSide = false; 35 const bool kIsOkButtonOnLeftSide = false;
35 #endif 36 #endif
36 37
37 // Returns true if the given view should be shown (i.e. exists and is 38 // Returns true if the given view should be shown (i.e. exists and is
38 // visible). 39 // visible).
39 bool ShouldShow(View* view) { 40 bool ShouldShow(View* view) {
40 return view && view->visible(); 41 return view && view->visible();
41 } 42 }
42 43
43 // Do the layout for a button. 44 // Returns the bounding box required to contain |size1| and |size2|, placed one
44 void LayoutButton(LabelButton* button, 45 // atop the other.
45 gfx::Rect* row_bounds, 46 gfx::Size GetBoundingSizeForVerticalStack(const gfx::Size& size1,
46 int button_height) { 47 const gfx::Size& size2) {
47 if (!button) 48 return gfx::Size(std::max(size1.width(), size2.width()),
48 return; 49 size1.height() + size2.height());
49
50 const gfx::Size size = button->GetPreferredSize();
51 row_bounds->set_width(row_bounds->width() - size.width());
52 DCHECK_LE(button_height, row_bounds->height());
53 button->SetBounds(
54 row_bounds->right(),
55 row_bounds->y() + (row_bounds->height() - button_height) / 2,
56 size.width(), button_height);
57 const int spacing =
58 ViewsDelegate::GetInstance()->GetDialogRelatedButtonHorizontalSpacing();
59 row_bounds->set_width(row_bounds->width() - spacing);
60 } 50 }
61 51
62 } // namespace 52 } // namespace
63 53
54 // Simple container to bubble child view changes up the view hierarchy.
55 class DialogClientView::ButtonRowContainer : public View {
56 public:
57 explicit ButtonRowContainer(DialogClientView* owner) : owner_(owner) {}
58
59 // View:
60 void ChildPreferredSizeChanged(View* child) override {
61 owner_->ChildPreferredSizeChanged(child);
62 }
63 void ChildVisibilityChanged(View* child) override {
64 owner_->ChildVisibilityChanged(child);
65 }
66
67 private:
68 DialogClientView* const owner_;
69
70 DISALLOW_COPY_AND_ASSIGN(ButtonRowContainer);
71 };
72
64 /////////////////////////////////////////////////////////////////////////////// 73 ///////////////////////////////////////////////////////////////////////////////
65 // DialogClientView, public: 74 // DialogClientView, public:
66 75
67 DialogClientView::DialogClientView(Widget* owner, View* contents_view) 76 DialogClientView::DialogClientView(Widget* owner, View* contents_view)
68 : ClientView(owner, contents_view), 77 : ClientView(owner, contents_view),
69 button_row_insets_( 78 button_row_insets_(
70 ViewsDelegate::GetInstance()->GetDialogButtonInsets()) { 79 ViewsDelegate::GetInstance()->GetDialogButtonInsets()) {
71 // Doing this now ensures this accelerator will have lower priority than 80 // Doing this now ensures this accelerator will have lower priority than
72 // one set by the contents view. 81 // one set by the contents view.
73 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); 82 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
83 button_row_container_ = new ButtonRowContainer(this);
84 AddChildView(button_row_container_);
74 } 85 }
75 86
76 DialogClientView::~DialogClientView() { 87 DialogClientView::~DialogClientView() {
88 // The |extra_view_| can't participate in layout when it is not visible, so it
89 // might not be in the View hierarchy. Ensure it gets deleted.
90 delete extra_view_;
77 } 91 }
78 92
79 void DialogClientView::AcceptWindow() { 93 void DialogClientView::AcceptWindow() {
80 // Only notify the delegate once. See |delegate_allowed_close_|'s comment. 94 // Only notify the delegate once. See |delegate_allowed_close_|'s comment.
81 if (!delegate_allowed_close_ && GetDialogDelegate()->Accept()) { 95 if (!delegate_allowed_close_ && GetDialogDelegate()->Accept()) {
82 delegate_allowed_close_ = true; 96 delegate_allowed_close_ = true;
83 GetWidget()->Close(); 97 GetWidget()->Close();
84 } 98 }
85 } 99 }
86 100
87 void DialogClientView::CancelWindow() { 101 void DialogClientView::CancelWindow() {
88 // Only notify the delegate once. See |delegate_allowed_close_|'s comment. 102 // Only notify the delegate once. See |delegate_allowed_close_|'s comment.
89 if (!delegate_allowed_close_ && GetDialogDelegate()->Cancel()) { 103 if (!delegate_allowed_close_ && GetDialogDelegate()->Cancel()) {
90 delegate_allowed_close_ = true; 104 delegate_allowed_close_ = true;
91 GetWidget()->Close(); 105 GetWidget()->Close();
92 } 106 }
93 } 107 }
94 108
95 void DialogClientView::UpdateDialogButtons() { 109 void DialogClientView::UpdateDialogButtons() {
96 SetupViews(); 110 SetupLayout();
97 SetupFocusChain(); 111 InvalidateLayout();
98 } 112 }
99 113
100 /////////////////////////////////////////////////////////////////////////////// 114 ///////////////////////////////////////////////////////////////////////////////
101 // DialogClientView, ClientView overrides: 115 // DialogClientView, ClientView overrides:
102 116
103 bool DialogClientView::CanClose() { 117 bool DialogClientView::CanClose() {
104 // If the dialog is closing but no Accept or Cancel action has been performed 118 // If the dialog is closing but no Accept or Cancel action has been performed
105 // before, it's a Close action. 119 // before, it's a Close action.
106 if (!delegate_allowed_close_) 120 if (!delegate_allowed_close_)
107 delegate_allowed_close_ = GetDialogDelegate()->Close(); 121 delegate_allowed_close_ = GetDialogDelegate()->Close();
108 return delegate_allowed_close_; 122 return delegate_allowed_close_;
109 } 123 }
110 124
111 DialogClientView* DialogClientView::AsDialogClientView() { 125 DialogClientView* DialogClientView::AsDialogClientView() {
112 return this; 126 return this;
113 } 127 }
114 128
115 const DialogClientView* DialogClientView::AsDialogClientView() const { 129 const DialogClientView* DialogClientView::AsDialogClientView() const {
116 return this; 130 return this;
117 } 131 }
118 132
119 //////////////////////////////////////////////////////////////////////////////// 133 ////////////////////////////////////////////////////////////////////////////////
120 // DialogClientView, View overrides: 134 // DialogClientView, View overrides:
121 135
122 gfx::Size DialogClientView::GetPreferredSize() const { 136 gfx::Size DialogClientView::GetPreferredSize() const {
123 // Initialize the size to fit the buttons and extra view row. 137 return GetBoundingSizeForVerticalStack(
124 gfx::Size size( 138 ClientView::GetPreferredSize(),
125 (ok_button_ ? ok_button_->GetPreferredSize().width() : 0) + 139 button_row_container_->GetPreferredSize());
126 (cancel_button_ ? cancel_button_->GetPreferredSize().width() : 0) + 140 }
127 (cancel_button_ && ok_button_
128 ? ViewsDelegate::GetInstance()
129 ->GetDialogRelatedButtonHorizontalSpacing()
130 : 0) +
131 (ShouldShow(extra_view_) ? extra_view_->GetPreferredSize().width()
132 : 0) +
133 GetExtraViewSpacing(),
134 0);
135 141
136 int buttons_height = GetButtonsAndExtraViewRowHeight(); 142 gfx::Size DialogClientView::GetMinimumSize() const {
137 if (buttons_height != 0) { 143 return GetBoundingSizeForVerticalStack(
138 size.Enlarge(0, buttons_height); 144 ClientView::GetMinimumSize(), button_row_container_->GetMinimumSize());
139 // Inset the buttons and extra view. 145 }
140 const gfx::Insets insets = GetButtonRowInsets();
141 size.Enlarge(insets.width(), insets.height());
142 }
143 146
144 // Increase the size as needed to fit the contents view. 147 gfx::Size DialogClientView::GetMaximumSize() const {
145 // NOTE: The contents view is not inset on the top or side client view edges. 148 constexpr int kUnconstrained = 0;
146 gfx::Size contents_size = contents_view()->GetPreferredSize(); 149 // The button layout doesn't currently specify constraints on either axis.
147 size.Enlarge(0, contents_size.height()); 150 DCHECK(gfx::Size() == button_row_container_->GetMaximumSize());
Peter Kasting 2017/02/28 03:33:23 Nit: Since you declared kUnconstrained, maybe D
tapted 2017/02/28 06:52:42 Done.
148 size.set_width(std::max(size.width(), contents_size.width())); 151 gfx::Size max_size = ClientView::GetMaximumSize();
149 152
150 size.SetToMax(minimum_size_); 153 // If the height is constrained, add the button row height. Leave the width as
154 // it is (be it constrained or unconstrained).
155 if (max_size.height() != kUnconstrained)
156 max_size.Enlarge(0, button_row_container_->GetPreferredSize().height());
151 157
152 return size; 158 // The minimum size includes the button row width. Warn if the contents_view()
159 // says it must be smaller than that.
160 DLOG_IF(WARNING,
161 max_size.width() != kUnconstrained &&
162 max_size.width() < GetMinimumSize().width())
163 << "Constraints violation.";
164 return max_size;
153 } 165 }
154 166
155 void DialogClientView::Layout() { 167 void DialogClientView::Layout() {
156 gfx::Rect bounds = GetContentsBounds(); 168 button_row_container_->SetSize(
157 169 gfx::Size(width(), button_row_container_->GetHeightForWidth(width())));
158 // Layout the row containing the buttons and the extra view. 170 button_row_container_->SetY(height() - button_row_container_->height());
159 if (has_dialog_buttons() || ShouldShow(extra_view_)) { 171 if (contents_view())
160 gfx::Insets button_row_insets = GetButtonRowInsets(); 172 contents_view()->SetSize(gfx::Size(width(), button_row_container_->y()));
161 // Don't apply the top inset here because it's supposed to go above the
162 // buttons, not at the top of the dialog.
163 bounds.Inset(button_row_insets.left(), 0, button_row_insets.right(),
164 button_row_insets.bottom());
165 const int height = GetButtonsAndExtraViewRowHeight();
166 gfx::Rect row_bounds(bounds.x(), bounds.bottom() - height,
167 bounds.width(), height);
168 // If the |extra_view_| is a also button, then the |button_height| is the
169 // maximum height of the three buttons, otherwise it is the maximum height
170 // of the ok and cancel buttons.
171 const int button_height =
172 CustomButton::AsCustomButton(extra_view_) ? height : GetButtonHeight();
173 if (kIsOkButtonOnLeftSide) {
174 LayoutButton(cancel_button_, &row_bounds, button_height);
175 LayoutButton(ok_button_, &row_bounds, button_height);
176 } else {
177 LayoutButton(ok_button_, &row_bounds, button_height);
178 LayoutButton(cancel_button_, &row_bounds, button_height);
179 }
180 if (extra_view_) {
181 int custom_padding = 0;
182 if (has_dialog_buttons() &&
183 GetDialogDelegate()->GetExtraViewPadding(&custom_padding)) {
184 // The padding between buttons applied in LayoutButton() will already
185 // have accounted for some of the distance here.
186 custom_padding -= ViewsDelegate::GetInstance()
187 ->GetDialogRelatedButtonHorizontalSpacing();
188 row_bounds.set_width(row_bounds.width() - custom_padding);
189 }
190 row_bounds.set_width(std::min(row_bounds.width(),
191 extra_view_->GetPreferredSize().width()));
192 extra_view_->SetBoundsRect(row_bounds);
193 }
194
195 if (height > 0) {
196 // Inset to the top of the buttons, plus their top padding, in order to
197 // exclude that area from the content view's bounds.
198 bounds.Inset(0, 0, 0, height + button_row_insets.top());
199 }
200 }
201
202 // Layout the contents view to the top and side edges of the contents bounds.
203 // NOTE: The local insets do not apply to the contents view sides or top.
204 const gfx::Rect contents_bounds = GetContentsBounds();
205 contents_view()->SetBounds(contents_bounds.x(), contents_bounds.y(),
206 contents_bounds.width(), bounds.bottom() - contents_bounds.y());
207 } 173 }
208 174
209 bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) { 175 bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) {
210 DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE); 176 DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE);
211 177
212 GetWidget()->Close(); 178 GetWidget()->Close();
213 return true; 179 return true;
214 } 180 }
215 181
216 void DialogClientView::ViewHierarchyChanged( 182 void DialogClientView::ViewHierarchyChanged(
217 const ViewHierarchyChangedDetails& details) { 183 const ViewHierarchyChangedDetails& details) {
218 View* const child = details.child; 184 View* const child = details.child;
219 185
220 // Dialogs must add children to contents_view(), not client_view(). 186 ClientView::ViewHierarchyChanged(details);
221 if (details.is_add && details.parent == this) { 187
222 DCHECK(child == contents_view() || child == ok_button_ || 188 if (details.is_add) {
223 child == cancel_button_ || child == extra_view_); 189 if (child == this)
190 UpdateDialogButtons();
191 return;
224 } 192 }
225 193
226 ClientView::ViewHierarchyChanged(details); 194 if (details.parent != button_row_container_)
227 if (details.is_add && child == this) { 195 return;
228 UpdateDialogButtons(); 196
229 } else if (!details.is_add) { 197 // SetupViews() removes all children, managing data members itself.
230 if (child == ok_button_) 198 if (preserve_button_row_data_members_)
231 ok_button_ = nullptr; 199 return;
232 else if (child == cancel_button_) 200
233 cancel_button_ = nullptr; 201 // Otherwise, this should only happen during teardown. Ensure there are no
234 else if (child == extra_view_) 202 // references to deleted Views.
235 extra_view_ = nullptr; 203 button_row_container_->SetLayoutManager(nullptr);
236 } 204
205 if (child == ok_button_)
206 ok_button_ = nullptr;
207 else if (child == cancel_button_)
208 cancel_button_ = nullptr;
209 else if (child == extra_view_)
210 extra_view_ = nullptr;
237 } 211 }
238 212
239 void DialogClientView::OnNativeThemeChanged(const ui::NativeTheme* theme) { 213 void DialogClientView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
240 // The old dialog style needs an explicit background color, while the new 214 // The old dialog style needs an explicit background color, while the new
241 // dialog style simply inherits the bubble's frame view color. 215 // dialog style simply inherits the bubble's frame view color.
242 const DialogDelegate* dialog = GetDialogDelegate(); 216 const DialogDelegate* dialog = GetDialogDelegate();
243 217
244 if (dialog && !dialog->ShouldUseCustomFrame()) { 218 if (dialog && !dialog->ShouldUseCustomFrame()) {
245 set_background(views::Background::CreateSolidBackground(GetNativeTheme()-> 219 set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
246 GetSystemColor(ui::NativeTheme::kColorId_DialogBackground))); 220 GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)));
(...skipping 22 matching lines...) Expand all
269 DialogDelegate* DialogClientView::GetDialogDelegate() const { 243 DialogDelegate* DialogClientView::GetDialogDelegate() const {
270 return GetWidget()->widget_delegate()->AsDialogDelegate(); 244 return GetWidget()->widget_delegate()->AsDialogDelegate();
271 } 245 }
272 246
273 void DialogClientView::ChildPreferredSizeChanged(View* child) { 247 void DialogClientView::ChildPreferredSizeChanged(View* child) {
274 if (child == extra_view_) 248 if (child == extra_view_)
275 Layout(); 249 Layout();
276 } 250 }
277 251
278 void DialogClientView::ChildVisibilityChanged(View* child) { 252 void DialogClientView::ChildVisibilityChanged(View* child) {
253 // Showing or hiding |extra_view_| can alter which columns have linked sizes.
254 if (child == extra_view_)
255 UpdateDialogButtons();
279 ChildPreferredSizeChanged(child); 256 ChildPreferredSizeChanged(child);
280 } 257 }
281 258
282 LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) { 259 void DialogClientView::UpdateDialogButton(LabelButton** member,
283 const base::string16 title = GetDialogDelegate()->GetDialogButtonLabel(type); 260 ui::DialogButton type) {
261 DialogDelegate* const delegate = GetDialogDelegate();
262 if ((delegate->GetDialogButtons() & type) == 0) {
263 delete *member;
264 *member = nullptr;
265 return;
266 }
267
268 if (*member) {
Peter Kasting 2017/02/28 03:33:23 Nit: This is the rare case when I would find it cl
tapted 2017/02/28 06:52:43 Done.
269 delegate->UpdateButton(*member, type);
270 return;
271 }
272
273 const base::string16 title = delegate->GetDialogButtonLabel(type);
Peter Kasting 2017/02/28 03:33:23 Do we need to compute the correct button label, or
tapted 2017/02/28 06:52:42 Unfortunately UpdateButton can be overridden, one
Peter Kasting 2017/02/28 09:30:46 That just looks like a bug we should fix (though p
284 LabelButton* button = nullptr; 274 LabelButton* button = nullptr;
285 275
286 const bool is_default = 276 const bool is_default = delegate->GetDefaultDialogButton() == type &&
287 GetDialogDelegate()->GetDefaultDialogButton() == type && 277 (type != ui::DIALOG_BUTTON_CANCEL ||
288 (type != ui::DIALOG_BUTTON_CANCEL || 278 PlatformStyle::kDialogDefaultButtonCanBeCancel);
Peter Kasting 2017/02/28 03:33:23 Similarly, it seems like UpdateButton() should get
tapted 2017/02/28 06:52:42 Under non-MD, is_default gets used to determine wh
289 PlatformStyle::kDialogDefaultButtonCanBeCancel);
290 279
291 // The default button is always blue in Harmony. 280 // The default button is always blue in Harmony.
292 if (is_default && (ui::MaterialDesignController::IsSecondaryUiMaterial() || 281 if (is_default &&
293 GetDialogDelegate()->ShouldDefaultButtonBeBlue())) { 282 (ui::MaterialDesignController::IsSecondaryUiMaterial() ||
283 delegate->ShouldDefaultButtonBeBlue())) {
294 button = MdTextButton::CreateSecondaryUiBlueButton(this, title); 284 button = MdTextButton::CreateSecondaryUiBlueButton(this, title);
295 } else { 285 } else {
296 button = MdTextButton::CreateSecondaryUiButton(this, title); 286 button = MdTextButton::CreateSecondaryUiButton(this, title);
297 } 287 }
298 288
299 // TODO(bsep): Setting the minimum size is redundant with MdTextButton, so 289 // TODO(bsep): Setting the minimum size is redundant with MdTextButton, so
300 // this can be deleted when harmony is always on. 290 // this can be deleted when harmony is always on.
301 const int minimum_width = 291 const int minimum_width =
302 ViewsDelegate::GetInstance()->GetDialogButtonMinimumWidth(); 292 ViewsDelegate::GetInstance()->GetDialogButtonMinimumWidth();
303 button->SetMinSize(gfx::Size(minimum_width, 0)); 293 button->SetMinSize(gfx::Size(minimum_width, 0));
304 294
305 button->SetGroup(kButtonGroup); 295 button->SetGroup(kButtonGroup);
306 return button;
307 }
308 296
309 int DialogClientView::GetButtonHeight() const { 297 *member = button;
310 return std::max( 298 delegate->UpdateButton(button, type);
311 ok_button_ ? ok_button_->GetPreferredSize().height() : 0,
312 cancel_button_ ? cancel_button_->GetPreferredSize().height() : 0);
313 }
314
315 int DialogClientView::GetExtraViewHeight() const {
316 return ShouldShow(extra_view_) ? extra_view_->GetPreferredSize().height() : 0;
317 }
318
319 int DialogClientView::GetButtonsAndExtraViewRowHeight() const {
320 return std::max(GetExtraViewHeight(), GetButtonHeight());
321 }
322
323 gfx::Insets DialogClientView::GetButtonRowInsets() const {
324 if (GetButtonsAndExtraViewRowHeight() == 0)
325 return gfx::Insets();
326
327 // Some subclasses of DialogClientView, in order to do their own layout, set
328 // button_row_insets_ to gfx::Insets(). To avoid breaking behavior of those
329 // dialogs, supplying 0 for the top inset of the row falls back to
330 // ViewsDelegate::GetRelatedControlVerticalSpacing.
331 // TODO(bsep): The top inset should never be 0 when harmony is enabled.
332 const int top = button_row_insets_.top() == 0
333 ? ViewsDelegate::GetInstance()
334 ->GetDialogRelatedControlVerticalSpacing()
335 : button_row_insets_.top();
336 return gfx::Insets(top, button_row_insets_.left(),
337 button_row_insets_.bottom(), button_row_insets_.right());
338 }
339
340 void DialogClientView::SetupFocusChain() {
341 // Create a vector of child views in the order of intended focus.
342 std::vector<View*> child_views;
343 child_views.push_back(contents_view());
344 child_views.push_back(extra_view_);
345 if (kIsOkButtonOnLeftSide) {
346 child_views.push_back(ok_button_);
347 child_views.push_back(cancel_button_);
348 } else {
349 child_views.push_back(cancel_button_);
350 child_views.push_back(ok_button_);
351 }
352
353 // Remove all null views from the vector.
354 child_views.erase(
355 std::remove(child_views.begin(), child_views.end(), nullptr),
356 child_views.end());
357
358 // Setup focus by reordering views. It is not safe to use SetNextFocusableView
359 // since child views may be added externally to this view.
360 for (size_t i = 0; i < child_views.size(); i++)
361 ReorderChildView(child_views[i], i);
362 } 299 }
363 300
364 int DialogClientView::GetExtraViewSpacing() const { 301 int DialogClientView::GetExtraViewSpacing() const {
365 if (!ShouldShow(extra_view_) || !has_dialog_buttons()) 302 if (!ShouldShow(extra_view_) || !(ok_button_ || cancel_button_))
366 return 0; 303 return 0;
367 304
368 int extra_view_padding = 0; 305 int extra_view_padding = 0;
369 if (GetDialogDelegate()->GetExtraViewPadding(&extra_view_padding)) 306 if (GetDialogDelegate()->GetExtraViewPadding(&extra_view_padding))
370 return extra_view_padding; 307 return extra_view_padding;
371 308
372 return ViewsDelegate::GetInstance() 309 return ViewsDelegate::GetInstance()
373 ->GetDialogRelatedButtonHorizontalSpacing(); 310 ->GetDialogRelatedButtonHorizontalSpacing();
374 } 311 }
375 312
376 void DialogClientView::SetupViews() { 313 std::vector<View*> DialogClientView::GetButtonRowViews() {
377 const int buttons = GetDialogDelegate()->GetDialogButtons(); 314 View* first = ShouldShow(extra_view_) ? extra_view_ : nullptr;
315 View* second = cancel_button_;
316 View* third = ok_button_;
317 if (kIsOkButtonOnLeftSide)
318 std::swap(second, third);
319 std::vector<View*> views = {first, second, third};
378 320
379 if (buttons & ui::DIALOG_BUTTON_OK) { 321 // Remove all null views from the vector.
380 if (!ok_button_) { 322 views.erase(std::remove(views.begin(), views.end(), nullptr), views.end());
381 ok_button_ = CreateDialogButton(ui::DIALOG_BUTTON_OK); 323 return views;
382 AddChildView(ok_button_); 324 }
383 }
384 325
385 GetDialogDelegate()->UpdateButton(ok_button_, ui::DIALOG_BUTTON_OK); 326 void DialogClientView::SetupLayout() {
386 } else if (ok_button_) { 327 GridLayout* layout = new GridLayout(button_row_container_);
387 delete ok_button_; 328 layout->set_minimum_size(minimum_size_);
388 ok_button_ = nullptr; 329
330 // Clobber any existing LayoutManager since it has weak references to child
331 // Views which may be removed by SetupViews().
332 button_row_container_->SetLayoutManager(layout);
333 SetupViews();
334 const std::vector<View*> views = GetButtonRowViews();
335 if (views.empty())
336 return;
337
338 gfx::Insets insets = button_row_insets_;
339 // Support dialogs that clear |button_row_insets_| to do their own layout.
340 // They expect GetDialogRelatedControlVerticalSpacing() in this case.
341 // TODO(tapted): Remove this under Harmony.
342 if (insets.top() == 0) {
343 const int top =
344 ViewsDelegate::GetInstance()->GetDialogRelatedControlVerticalSpacing();
345 insets.Set(top, insets.left(), insets.bottom(), insets.right());
389 } 346 }
390 347
391 if (buttons & ui::DIALOG_BUTTON_CANCEL) { 348 // The |resize_percent| constants. There's only one stretchy column (padding
392 if (!cancel_button_) { 349 // to the left of ok/cancel buttons).
393 cancel_button_ = CreateDialogButton(ui::DIALOG_BUTTON_CANCEL); 350 constexpr float kFixed = 0.f;
394 AddChildView(cancel_button_); 351 constexpr float kStretchy = 1.f;
395 }
396 352
397 GetDialogDelegate()->UpdateButton(cancel_button_, ui::DIALOG_BUTTON_CANCEL); 353 // Button row is [ extra <pad+stretchy> second <pad> third ]. Ensure the <pad>
398 } else if (cancel_button_) { 354 // column is zero width if there isn't a button on either side.
399 delete cancel_button_; 355 // GetExtraViewSpacing() handles <pad+stretchy>.
400 cancel_button_ = nullptr; 356 const int button_spacing =
357 (ok_button_ && cancel_button_)
358 ? ViewsDelegate::GetInstance()
359 ->GetDialogRelatedButtonHorizontalSpacing()
360 : 0;
361
362 constexpr int kButtonRowId = 0;
363 ColumnSet* column_set = layout->AddColumnSet(kButtonRowId);
364
365 // Rather than giving |button_row_container_| a Border, incorporate the insets
366 // into the layout. This simplifies min/max size calculations.
367 column_set->AddPaddingColumn(kFixed, insets.left());
368 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
369 GridLayout::USE_PREF, 0, 0);
370 column_set->AddPaddingColumn(kStretchy, GetExtraViewSpacing());
371 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
372 GridLayout::USE_PREF, 0, 0);
373 column_set->AddPaddingColumn(kFixed, button_spacing);
374 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
375 GridLayout::USE_PREF, 0, 0);
376 column_set->AddPaddingColumn(kFixed, insets.right());
377
378 // Track which columns to link sizes under MD.
379 constexpr int kExtraViewColumnIndex = 1;
380 constexpr int kSecondColumnIndex = 3;
381 constexpr int kThirdColumnIndex = 5;
382 int link[] = {-1, -1, -1};
383 size_t index = 0;
384
385 layout->StartRowWithPadding(kFixed, kButtonRowId, kFixed, insets.top());
386
387 // First column is only used if there is an extra view.
388 if (ShouldShow(extra_view_)) {
389 layout->AddView(views[index]);
390 link[index] = kExtraViewColumnIndex;
391 ++index;
392 } else {
393 layout->SkipColumns(1);
401 } 394 }
402 395
396 // Second column is only used if there are 2 buttons.
397 if (ok_button_ && cancel_button_) {
398 layout->AddView(views[index]);
399 link[index] = kSecondColumnIndex;
400 ++index;
401 } else {
402 layout->SkipColumns(1);
403 }
404
405 // Last column is only used if a view remains (either OK or Cancel).
406 if (index < views.size()) {
407 layout->AddView(views[index]);
408 link[index] = kThirdColumnIndex;
409 }
410
411 if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
412 // Only link the extra view column if it is a button.
413 if (ShouldShow(extra_view_) && !CustomButton::AsCustomButton(extra_view_))
414 column_set->LinkColumnSizes(link[1], link[2], -1);
415 else
416 column_set->LinkColumnSizes(link[0], link[1], link[2], -1);
417 }
418 layout->AddPaddingRow(kFixed, insets.bottom());
419 }
420
421 void DialogClientView::SetupViews() {
422 {
423 base::AutoReset<bool> auto_reset(&preserve_button_row_data_members_, true);
424 button_row_container_->RemoveAllChildViews(false /* delete children */);
425 }
426
427 UpdateDialogButton(&ok_button_, ui::DIALOG_BUTTON_OK);
428 UpdateDialogButton(&cancel_button_, ui::DIALOG_BUTTON_CANCEL);
429
403 if (extra_view_) 430 if (extra_view_)
404 return; 431 return;
405 432
406 extra_view_ = GetDialogDelegate()->CreateExtraView(); 433 extra_view_ = GetDialogDelegate()->CreateExtraView();
407 if (extra_view_) { 434 if (extra_view_)
408 extra_view_->SetGroup(kButtonGroup); 435 extra_view_->SetGroup(kButtonGroup);
409 AddChildView(extra_view_);
410 }
411 } 436 }
412 437
413 } // namespace views 438 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698