OLD | NEW |
---|---|
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 // Arrange two sizes vertically and return the bounding box. |
Peter Kasting
2017/02/25 06:04:07
Nit: Descriptive ("Arranges"), not imperative.
Ma
tapted
2017/02/27 10:04:19
Done.
| |
44 void LayoutButton(LabelButton* button, | 45 gfx::Size ArrangeVertically(const gfx::Size& above, const gfx::Size& below) { |
Peter Kasting
2017/02/25 06:04:07
Nit: Trivial, but it technically doesn't matter th
tapted
2017/02/27 10:04:19
Done.
| |
45 gfx::Rect* row_bounds, | 46 return gfx::Size(std::max(above.width(), below.width()), |
46 int button_height) { | 47 above.height() + below.height()); |
47 if (!button) | |
48 return; | |
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 } | 48 } |
61 | 49 |
62 } // namespace | 50 } // namespace |
63 | 51 |
52 // Simple container to bubble child view changes up the view hierarchy. | |
53 class DialogClientView::ButtonRowContainer : public View { | |
54 public: | |
55 ButtonRowContainer() {} | |
56 | |
57 // Downcast so that ButtonRowContainer can call protected methods as a friend. | |
58 DialogClientView* parent() { | |
59 return static_cast<DialogClientView*>(View::parent()); | |
Peter Kasting
2017/02/25 06:04:07
Nit: It would be safer to take the DialogClientVie
tapted
2017/02/27 10:04:19
Done.
| |
60 } | |
61 | |
62 // View: | |
63 void ChildPreferredSizeChanged(View* child) override { | |
64 parent()->ChildPreferredSizeChanged(child); | |
Peter Kasting
2017/02/25 06:04:07
Nit: Optional, but seems like the only reason we n
tapted
2017/02/27 10:04:19
This crossed my mind too.. but I decided not to at
Peter Kasting
2017/02/28 03:33:23
I'm fine leaving it to a followup. I think it's w
tapted
2017/02/28 06:52:42
Acknowledged.
| |
65 } | |
66 void ChildVisibilityChanged(View* child) override { | |
67 parent()->ChildVisibilityChanged(child); | |
68 } | |
69 | |
70 private: | |
71 DISALLOW_COPY_AND_ASSIGN(ButtonRowContainer); | |
72 }; | |
73 | |
64 /////////////////////////////////////////////////////////////////////////////// | 74 /////////////////////////////////////////////////////////////////////////////// |
65 // DialogClientView, public: | 75 // DialogClientView, public: |
66 | 76 |
67 DialogClientView::DialogClientView(Widget* owner, View* contents_view) | 77 DialogClientView::DialogClientView(Widget* owner, View* contents_view) |
68 : ClientView(owner, contents_view), | 78 : ClientView(owner, contents_view), |
69 button_row_insets_( | 79 button_row_insets_( |
70 ViewsDelegate::GetInstance()->GetDialogButtonInsets()) { | 80 ViewsDelegate::GetInstance()->GetDialogButtonInsets()) { |
71 // Doing this now ensures this accelerator will have lower priority than | 81 // Doing this now ensures this accelerator will have lower priority than |
72 // one set by the contents view. | 82 // one set by the contents view. |
73 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); | 83 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); |
84 button_row_container_ = new ButtonRowContainer(); | |
85 AddChildView(button_row_container_); | |
74 } | 86 } |
75 | 87 |
76 DialogClientView::~DialogClientView() { | 88 DialogClientView::~DialogClientView() { |
89 // The |extra_view_| can't participate in layout when it is not visible, so it | |
90 // might not be in the View hierarchy. Ensure it gets deleted. | |
91 delete extra_view_; | |
Peter Kasting
2017/02/25 06:04:07
I'm confused.
Visibility and being part of the vi
tapted
2017/02/27 10:04:19
This is to satisfy some existing use-cases for Dia
Peter Kasting
2017/02/28 03:33:23
Where does this happen?
Basically, I'm trying to
tapted
2017/02/28 06:52:42
Most overrides of DCV::CreateExtraView() hold on t
| |
77 } | 92 } |
78 | 93 |
79 void DialogClientView::AcceptWindow() { | 94 void DialogClientView::AcceptWindow() { |
80 // Only notify the delegate once. See |delegate_allowed_close_|'s comment. | 95 // Only notify the delegate once. See |delegate_allowed_close_|'s comment. |
81 if (!delegate_allowed_close_ && GetDialogDelegate()->Accept()) { | 96 if (!delegate_allowed_close_ && GetDialogDelegate()->Accept()) { |
82 delegate_allowed_close_ = true; | 97 delegate_allowed_close_ = true; |
83 GetWidget()->Close(); | 98 GetWidget()->Close(); |
84 } | 99 } |
85 } | 100 } |
86 | 101 |
87 void DialogClientView::CancelWindow() { | 102 void DialogClientView::CancelWindow() { |
88 // Only notify the delegate once. See |delegate_allowed_close_|'s comment. | 103 // Only notify the delegate once. See |delegate_allowed_close_|'s comment. |
89 if (!delegate_allowed_close_ && GetDialogDelegate()->Cancel()) { | 104 if (!delegate_allowed_close_ && GetDialogDelegate()->Cancel()) { |
90 delegate_allowed_close_ = true; | 105 delegate_allowed_close_ = true; |
91 GetWidget()->Close(); | 106 GetWidget()->Close(); |
92 } | 107 } |
93 } | 108 } |
94 | 109 |
95 void DialogClientView::UpdateDialogButtons() { | 110 void DialogClientView::UpdateDialogButtons() { |
96 SetupViews(); | 111 SetupLayout(); |
97 SetupFocusChain(); | 112 InvalidateLayout(); |
98 } | 113 } |
99 | 114 |
100 /////////////////////////////////////////////////////////////////////////////// | 115 /////////////////////////////////////////////////////////////////////////////// |
101 // DialogClientView, ClientView overrides: | 116 // DialogClientView, ClientView overrides: |
102 | 117 |
103 bool DialogClientView::CanClose() { | 118 bool DialogClientView::CanClose() { |
104 // If the dialog is closing but no Accept or Cancel action has been performed | 119 // If the dialog is closing but no Accept or Cancel action has been performed |
105 // before, it's a Close action. | 120 // before, it's a Close action. |
106 if (!delegate_allowed_close_) | 121 if (!delegate_allowed_close_) |
107 delegate_allowed_close_ = GetDialogDelegate()->Close(); | 122 delegate_allowed_close_ = GetDialogDelegate()->Close(); |
108 return delegate_allowed_close_; | 123 return delegate_allowed_close_; |
109 } | 124 } |
110 | 125 |
111 DialogClientView* DialogClientView::AsDialogClientView() { | 126 DialogClientView* DialogClientView::AsDialogClientView() { |
112 return this; | 127 return this; |
113 } | 128 } |
114 | 129 |
115 const DialogClientView* DialogClientView::AsDialogClientView() const { | 130 const DialogClientView* DialogClientView::AsDialogClientView() const { |
116 return this; | 131 return this; |
117 } | 132 } |
118 | 133 |
119 //////////////////////////////////////////////////////////////////////////////// | 134 //////////////////////////////////////////////////////////////////////////////// |
120 // DialogClientView, View overrides: | 135 // DialogClientView, View overrides: |
121 | 136 |
122 gfx::Size DialogClientView::GetPreferredSize() const { | 137 gfx::Size DialogClientView::GetPreferredSize() const { |
123 // Initialize the size to fit the buttons and extra view row. | 138 return ArrangeVertically(ClientView::GetPreferredSize(), |
124 gfx::Size size( | 139 button_row_container_->GetPreferredSize()); |
125 (ok_button_ ? ok_button_->GetPreferredSize().width() : 0) + | 140 } |
126 (cancel_button_ ? cancel_button_->GetPreferredSize().width() : 0) + | |
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 ArrangeVertically(ClientView::GetMinimumSize(), |
138 size.Enlarge(0, buttons_height); | 144 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 // The button layout doesn't currently have a maximum size. |
Peter Kasting
2017/02/25 06:04:07
Maybe it should? Then we could probably just use
tapted
2017/02/27 10:04:19
Maximum size would need slightly different logic (
| |
146 gfx::Size contents_size = contents_view()->GetPreferredSize(); | 149 DCHECK(gfx::Size() == button_row_container_->GetMaximumSize()); |
Peter Kasting
2017/02/25 06:04:07
Nit: DCHECK(button_row_container_->GetMaximumSize(
tapted
2017/02/27 10:04:19
The maximum size can be constrained in a single di
| |
147 size.Enlarge(0, contents_size.height()); | 150 gfx::Size max_size = ClientView::GetMaximumSize(); |
148 size.set_width(std::max(size.width(), contents_size.width())); | 151 if (max_size != gfx::Size()) |
Peter Kasting
2017/02/25 06:04:07
Nit: !IsEmpty()?
tapted
2017/02/27 10:04:19
Changed this to
if (max_size.height() != 0)
an
Peter Kasting
2017/02/28 03:33:23
I don't think we should add a DLOG, because it's n
tapted
2017/02/28 06:52:42
Yeah the DLOG would only be an indicator for devel
| |
149 | 152 max_size.Enlarge(0, button_row_container_->GetPreferredSize().height()); |
150 size.SetToMax(minimum_size_); | 153 return max_size; |
151 | |
152 return size; | |
153 } | 154 } |
154 | 155 |
155 void DialogClientView::Layout() { | 156 void DialogClientView::Layout() { |
156 gfx::Rect bounds = GetContentsBounds(); | 157 button_row_container_->SetSize( |
157 | 158 gfx::Size(width(), button_row_container_->GetHeightForWidth(width()))); |
158 // Layout the row containing the buttons and the extra view. | 159 button_row_container_->SetY(height() - button_row_container_->height()); |
159 if (has_dialog_buttons() || ShouldShow(extra_view_)) { | 160 if (contents_view()) |
160 gfx::Insets button_row_insets = GetButtonRowInsets(); | 161 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 } | 162 } |
208 | 163 |
209 bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) { | 164 bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) { |
210 DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE); | 165 DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE); |
211 | 166 |
212 GetWidget()->Close(); | 167 GetWidget()->Close(); |
213 return true; | 168 return true; |
214 } | 169 } |
215 | 170 |
216 void DialogClientView::ViewHierarchyChanged( | 171 void DialogClientView::ViewHierarchyChanged( |
217 const ViewHierarchyChangedDetails& details) { | 172 const ViewHierarchyChangedDetails& details) { |
218 View* const child = details.child; | 173 View* const child = details.child; |
219 | 174 |
220 // Dialogs must add children to contents_view(), not client_view(). | 175 ClientView::ViewHierarchyChanged(details); |
221 if (details.is_add && details.parent == this) { | 176 |
222 DCHECK(child == contents_view() || child == ok_button_ || | 177 if (details.is_add) { |
tapted
2017/02/24 06:55:10
Ah, this DCHECK I added to get a jump on dialogs t
| |
223 child == cancel_button_ || child == extra_view_); | 178 if (child == this) |
179 UpdateDialogButtons(); | |
180 return; | |
224 } | 181 } |
225 | 182 |
226 ClientView::ViewHierarchyChanged(details); | 183 if (details.parent != button_row_container_) |
227 if (details.is_add && child == this) { | 184 return; |
228 UpdateDialogButtons(); | 185 |
229 } else if (!details.is_add) { | 186 // SetupViews() removes all children, managing data members itself. |
230 if (child == ok_button_) | 187 if (in_setup_views_) |
231 ok_button_ = nullptr; | 188 return; |
232 else if (child == cancel_button_) | 189 |
233 cancel_button_ = nullptr; | 190 // Otherwise, this should only happen during teardown. Ensure there are no |
234 else if (child == extra_view_) | 191 // references to deleted Views. |
Peter Kasting
2017/02/25 06:04:07
Is this important? Are there races or something t
tapted
2017/02/27 10:04:19
It looks like this trend started a long time ago w
Peter Kasting
2017/02/28 03:33:23
Hmm, I didn't realize we had public accessors for
tapted
2017/02/28 06:52:42
Acknowledged.
| |
235 extra_view_ = nullptr; | 192 button_row_container_->SetLayoutManager(nullptr); |
236 } | 193 |
194 if (child == ok_button_) | |
195 ok_button_ = nullptr; | |
196 else if (child == cancel_button_) | |
197 cancel_button_ = nullptr; | |
198 else if (child == extra_view_) | |
199 extra_view_ = nullptr; | |
237 } | 200 } |
238 | 201 |
239 void DialogClientView::OnNativeThemeChanged(const ui::NativeTheme* theme) { | 202 void DialogClientView::OnNativeThemeChanged(const ui::NativeTheme* theme) { |
240 // The old dialog style needs an explicit background color, while the new | 203 // The old dialog style needs an explicit background color, while the new |
241 // dialog style simply inherits the bubble's frame view color. | 204 // dialog style simply inherits the bubble's frame view color. |
242 const DialogDelegate* dialog = GetDialogDelegate(); | 205 const DialogDelegate* dialog = GetDialogDelegate(); |
243 | 206 |
244 if (dialog && !dialog->ShouldUseCustomFrame()) { | 207 if (dialog && !dialog->ShouldUseCustomFrame()) { |
245 set_background(views::Background::CreateSolidBackground(GetNativeTheme()-> | 208 set_background(views::Background::CreateSolidBackground(GetNativeTheme()-> |
246 GetSystemColor(ui::NativeTheme::kColorId_DialogBackground))); | 209 GetSystemColor(ui::NativeTheme::kColorId_DialogBackground))); |
(...skipping 22 matching lines...) Expand all Loading... | |
269 DialogDelegate* DialogClientView::GetDialogDelegate() const { | 232 DialogDelegate* DialogClientView::GetDialogDelegate() const { |
270 return GetWidget()->widget_delegate()->AsDialogDelegate(); | 233 return GetWidget()->widget_delegate()->AsDialogDelegate(); |
271 } | 234 } |
272 | 235 |
273 void DialogClientView::ChildPreferredSizeChanged(View* child) { | 236 void DialogClientView::ChildPreferredSizeChanged(View* child) { |
274 if (child == extra_view_) | 237 if (child == extra_view_) |
275 Layout(); | 238 Layout(); |
276 } | 239 } |
277 | 240 |
278 void DialogClientView::ChildVisibilityChanged(View* child) { | 241 void DialogClientView::ChildVisibilityChanged(View* child) { |
242 // Showing or hiding |extra_view_| can alter which columns have linked sizes. | |
243 if (child == extra_view_) | |
244 UpdateDialogButtons(); | |
279 ChildPreferredSizeChanged(child); | 245 ChildPreferredSizeChanged(child); |
280 } | 246 } |
281 | 247 |
282 LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) { | 248 void DialogClientView::UpdateDialogButton(LabelButton** member, |
283 const base::string16 title = GetDialogDelegate()->GetDialogButtonLabel(type); | 249 ui::DialogButton type) { |
250 DialogDelegate* const delegate = GetDialogDelegate(); | |
251 if ((delegate->GetDialogButtons() & type) == 0) { | |
252 delete *member; | |
253 *member = nullptr; | |
254 return; | |
255 } | |
256 | |
257 if (*member) { | |
258 delegate->UpdateButton(*member, type); | |
259 return; | |
260 } | |
261 | |
262 const base::string16 title = delegate->GetDialogButtonLabel(type); | |
284 LabelButton* button = nullptr; | 263 LabelButton* button = nullptr; |
285 | 264 |
286 const bool is_default = | 265 const bool is_default = delegate->GetDefaultDialogButton() == type && |
287 GetDialogDelegate()->GetDefaultDialogButton() == type && | 266 (type != ui::DIALOG_BUTTON_CANCEL || |
288 (type != ui::DIALOG_BUTTON_CANCEL || | 267 PlatformStyle::kDialogDefaultButtonCanBeCancel); |
289 PlatformStyle::kDialogDefaultButtonCanBeCancel); | |
290 | 268 |
291 // The default button is always blue in Harmony. | 269 // The default button is always blue in Harmony. |
292 if (is_default && (ui::MaterialDesignController::IsSecondaryUiMaterial() || | 270 if (is_default && |
293 GetDialogDelegate()->ShouldDefaultButtonBeBlue())) { | 271 (ui::MaterialDesignController::IsSecondaryUiMaterial() || |
272 delegate->ShouldDefaultButtonBeBlue())) { | |
294 button = MdTextButton::CreateSecondaryUiBlueButton(this, title); | 273 button = MdTextButton::CreateSecondaryUiBlueButton(this, title); |
295 } else { | 274 } else { |
296 button = MdTextButton::CreateSecondaryUiButton(this, title); | 275 button = MdTextButton::CreateSecondaryUiButton(this, title); |
297 } | 276 } |
298 | 277 |
299 // TODO(bsep): Setting the minimum size is redundant with MdTextButton, so | 278 // TODO(bsep): Setting the minimum size is redundant with MdTextButton, so |
300 // this can be deleted when harmony is always on. | 279 // this can be deleted when harmony is always on. |
301 const int minimum_width = | 280 const int minimum_width = |
302 ViewsDelegate::GetInstance()->GetDialogButtonMinimumWidth(); | 281 ViewsDelegate::GetInstance()->GetDialogButtonMinimumWidth(); |
303 button->SetMinSize(gfx::Size(minimum_width, 0)); | 282 button->SetMinSize(gfx::Size(minimum_width, 0)); |
304 | 283 |
305 button->SetGroup(kButtonGroup); | 284 button->SetGroup(kButtonGroup); |
306 return button; | |
307 } | |
308 | 285 |
309 int DialogClientView::GetButtonHeight() const { | 286 *member = button; |
310 return std::max( | 287 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 } | 288 } |
363 | 289 |
364 int DialogClientView::GetExtraViewSpacing() const { | 290 int DialogClientView::GetExtraViewSpacing() const { |
365 if (!ShouldShow(extra_view_) || !has_dialog_buttons()) | 291 if (!ShouldShow(extra_view_) || !(ok_button_ || cancel_button_)) |
366 return 0; | 292 return 0; |
367 | 293 |
368 int extra_view_padding = 0; | 294 int extra_view_padding = 0; |
369 if (GetDialogDelegate()->GetExtraViewPadding(&extra_view_padding)) | 295 if (GetDialogDelegate()->GetExtraViewPadding(&extra_view_padding)) |
370 return extra_view_padding; | 296 return extra_view_padding; |
371 | 297 |
372 return ViewsDelegate::GetInstance() | 298 return ViewsDelegate::GetInstance() |
373 ->GetDialogRelatedButtonHorizontalSpacing(); | 299 ->GetDialogRelatedButtonHorizontalSpacing(); |
374 } | 300 } |
375 | 301 |
376 void DialogClientView::SetupViews() { | 302 std::vector<View*> DialogClientView::ButtonRowViews() { |
377 const int buttons = GetDialogDelegate()->GetDialogButtons(); | 303 View* first = ShouldShow(extra_view_) ? extra_view_ : nullptr; |
304 View* second = cancel_button_; | |
305 View* third = ok_button_; | |
306 if (kIsOkButtonOnLeftSide) | |
307 std::swap(second, third); | |
308 std::vector<View*> views = {first, second, third}; | |
378 | 309 |
379 if (buttons & ui::DIALOG_BUTTON_OK) { | 310 // Remove all null views from the vector. |
380 if (!ok_button_) { | 311 views.erase(std::remove(views.begin(), views.end(), nullptr), views.end()); |
381 ok_button_ = CreateDialogButton(ui::DIALOG_BUTTON_OK); | 312 return views; |
382 AddChildView(ok_button_); | 313 } |
383 } | |
384 | 314 |
385 GetDialogDelegate()->UpdateButton(ok_button_, ui::DIALOG_BUTTON_OK); | 315 void DialogClientView::SetupLayout() { |
386 } else if (ok_button_) { | 316 GridLayout* layout = new GridLayout(button_row_container_); |
387 delete ok_button_; | 317 layout->set_minimum_size(minimum_size_); |
388 ok_button_ = nullptr; | 318 |
319 // Clobber any existing LayoutManager since it has weak references to child | |
320 // Views which may be removed by SetupViews(). | |
321 button_row_container_->SetLayoutManager(layout); | |
322 SetupViews(); | |
323 const std::vector<View*> views = ButtonRowViews(); | |
324 if (views.empty()) | |
325 return; | |
326 | |
327 gfx::Insets insets = button_row_insets_; | |
328 // Support dialogs that clear |button_row_insets_| to do their own layout. | |
329 // They expect GetDialogRelatedControlVerticalSpacing() in this case. | |
330 // TODO(tapted): Remove this under Harmony. | |
331 if (insets.top() == 0) { | |
332 const int top = | |
333 ViewsDelegate::GetInstance()->GetDialogRelatedControlVerticalSpacing(); | |
334 insets.Set(top, insets.left(), insets.bottom(), insets.right()); | |
Peter Kasting
2017/02/25 06:04:07
Nit: We should probably just add per-side setters
tapted
2017/02/27 10:04:19
I hunted through codesearch, and did some "brutefo
Peter Kasting
2017/02/28 03:33:23
Hmm. I just wanted to set one side the other day,
| |
389 } | 335 } |
390 | 336 |
391 if (buttons & ui::DIALOG_BUTTON_CANCEL) { | 337 // The |resize_percent| constants. There's only one stretchy column (padding |
392 if (!cancel_button_) { | 338 // to the left of ok/cancel buttons). |
393 cancel_button_ = CreateDialogButton(ui::DIALOG_BUTTON_CANCEL); | 339 constexpr float kFixed = 0.f; |
394 AddChildView(cancel_button_); | 340 constexpr float kStretchy = 1.f; |
395 } | |
396 | 341 |
397 GetDialogDelegate()->UpdateButton(cancel_button_, ui::DIALOG_BUTTON_CANCEL); | 342 // Button row is [ extra <pad+stretchy> second <pad> third ]. Ensure the <pad> |
398 } else if (cancel_button_) { | 343 // column is zero width if there isn't a button on either side. |
399 delete cancel_button_; | 344 // GetExtraViewSpacing() handles <pad+stretchy>. |
400 cancel_button_ = nullptr; | 345 const int button_spacing = |
346 (ok_button_ && cancel_button_) | |
347 ? ViewsDelegate::GetInstance() | |
348 ->GetDialogRelatedButtonHorizontalSpacing() | |
349 : 0; | |
350 | |
351 constexpr int kButtonRowId = 0; | |
352 ColumnSet* column_set = layout->AddColumnSet(kButtonRowId); | |
353 | |
354 // Rather than giving |button_row_container_| a Border, incorporate the insets | |
355 // into the layout. This simplifies min/max size calculations. | |
356 column_set->AddPaddingColumn(kFixed, insets.left()); | |
357 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed, | |
358 GridLayout::USE_PREF, 0, 0); | |
359 column_set->AddPaddingColumn(kStretchy, GetExtraViewSpacing()); | |
360 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed, | |
361 GridLayout::USE_PREF, 0, 0); | |
362 column_set->AddPaddingColumn(kFixed, button_spacing); | |
363 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed, | |
364 GridLayout::USE_PREF, 0, 0); | |
365 column_set->AddPaddingColumn(kFixed, insets.right()); | |
366 | |
367 // Track which columns to link sizes under MD. | |
368 constexpr int kExtraViewColumnIndex = 1; | |
369 constexpr int kSecondColumnIndex = 3; | |
370 constexpr int kThirdColumnIndex = 5; | |
371 int link[] = {-1, -1, -1}; | |
372 size_t index = 0; | |
373 | |
374 layout->StartRowWithPadding(kFixed, kButtonRowId, kFixed, insets.top()); | |
375 | |
376 // First column is only used if there is an extra view. | |
Peter Kasting
2017/02/25 06:04:07
I feel like with some cleverness this block and th
tapted
2017/02/27 10:04:19
I'd toyed with this a bit.. The ButtonRowViews() a
Peter Kasting
2017/02/28 03:33:23
OK.
tapted
2017/02/28 06:52:42
I got an idea for this. (extra_view_ gets in the w
| |
377 if (ShouldShow(extra_view_)) { | |
378 layout->AddView(views[index]); | |
379 link[index] = kExtraViewColumnIndex; | |
380 ++index; | |
381 } else { | |
382 layout->SkipColumns(1); | |
401 } | 383 } |
402 | 384 |
385 // Second column is only used if there are 2 buttons. | |
386 if (ok_button_ && cancel_button_) { | |
387 layout->AddView(views[index]); | |
388 link[index] = kSecondColumnIndex; | |
389 ++index; | |
390 } else { | |
391 layout->SkipColumns(1); | |
392 } | |
393 | |
394 // Last column is only used if a view remains (either OK or Cancel). | |
395 if (index < views.size()) { | |
396 layout->AddView(views[index]); | |
397 link[index] = kThirdColumnIndex; | |
398 } | |
399 | |
400 if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { | |
Peter Kasting
2017/02/25 06:04:08
Should we just go ahead and link the column sizes
tapted
2017/02/27 10:04:19
Hm - that scares me a little. It's not just that s
Peter Kasting
2017/02/28 03:33:23
Well, we're only enlarging linked widths when they
tapted
2017/02/28 06:52:42
That does tend to be the case. I couldn't find any
Peter Kasting
2017/02/28 09:30:46
Man, we really shouldn't have a button saying "Cre
| |
401 // Only link the extra view column if it is a button. | |
402 if (ShouldShow(extra_view_) && !CustomButton::AsCustomButton(extra_view_)) | |
403 column_set->LinkColumnSizes(link[1], link[2], -1); | |
404 else | |
405 column_set->LinkColumnSizes(link[0], link[1], link[2], -1); | |
406 } | |
407 layout->AddPaddingRow(kFixed, insets.bottom()); | |
408 } | |
409 | |
410 void DialogClientView::SetupViews() { | |
411 { | |
412 base::AutoReset<bool> auto_reset(&in_setup_views_, true); | |
413 button_row_container_->RemoveAllChildViews(false /* delete children */); | |
414 } | |
415 | |
416 UpdateDialogButton(&ok_button_, ui::DIALOG_BUTTON_OK); | |
417 UpdateDialogButton(&cancel_button_, ui::DIALOG_BUTTON_CANCEL); | |
418 | |
403 if (extra_view_) | 419 if (extra_view_) |
404 return; | 420 return; |
405 | 421 |
406 extra_view_ = GetDialogDelegate()->CreateExtraView(); | 422 extra_view_ = GetDialogDelegate()->CreateExtraView(); |
407 if (extra_view_) { | 423 if (extra_view_) |
408 extra_view_->SetGroup(kButtonGroup); | 424 extra_view_->SetGroup(kButtonGroup); |
409 AddChildView(extra_view_); | |
410 } | |
411 } | 425 } |
412 | 426 |
413 } // namespace views | 427 } // namespace views |
OLD | NEW |