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

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

Issue 2701373002: Add a DialogExample example to views_examples (Closed)
Patch Set: Update assuming we fix DialogClientView (remove the workarounds for existing bugs fixed by crbug/67… Created 3 years, 10 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 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 "ui/views/examples/dialog_example.h"
6
7 #include "base/macros.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "ui/views/bubble/bubble_dialog_delegate.h"
10 #include "ui/views/controls/button/checkbox.h"
11 #include "ui/views/controls/button/label_button.h"
12 #include "ui/views/controls/button/md_text_button.h"
13 #include "ui/views/controls/combobox/combobox.h"
14 #include "ui/views/controls/label.h"
15 #include "ui/views/controls/textfield/textfield.h"
16 #include "ui/views/layout/fill_layout.h"
17 #include "ui/views/layout/grid_layout.h"
18 #include "ui/views/layout/layout_constants.h"
19 #include "ui/views/views_delegate.h"
20 #include "ui/views/widget/widget.h"
21 #include "ui/views/window/dialog_client_view.h"
22
23 using base::ASCIIToUTF16;
24
25 namespace views {
26 namespace examples {
27 namespace {
28
29 constexpr int kFieldsColumnId = 0;
30 constexpr int kButtonsColumnId = 1;
31 constexpr int kFakeModeless = ui::MODAL_TYPE_SYSTEM + 1;
32
33 } // namespace
34
35 template <class DialogType>
36 class DialogExample::Delegate : public virtual DialogType {
37 public:
38 explicit Delegate(DialogExample* parent) : parent_(parent) {}
39
40 void InitDelegate() {
41 LayoutManager* fill_layout = new FillLayout();
42 this->SetLayoutManager(fill_layout);
Patti Lor 2017/02/22 05:58:34 Is the "this->" needed here? (and below?)
tapted 2017/02/22 22:45:30 Yup - because the parent is a template argument, t
43 Label* body = new Label(parent_->body_->text());
44 body->SetMultiLine(true);
45 body->SetHorizontalAlignment(gfx::ALIGN_LEFT);
46 body->set_background(Background::CreateSolidBackground(0, 255, 255));
47 this->AddChildView(body);
48
49 // Give the example code a way to change the body text.
50 parent_->last_body_label_ = body;
51 }
52
53 protected:
54 // WidgetDelegate:
55 ui::ModalType GetModalType() const override {
56 return parent_->GetModalType();
57 }
58
59 base::string16 GetWindowTitle() const override {
60 return parent_->title_->text();
61 }
62
63 // DialogDelegate:
64 View* CreateExtraView() {
65 if (!parent_->has_extra_button_->checked())
66 return nullptr;
67 return MdTextButton::Create(nullptr, parent_->extra_button_label_->text());
Patti Lor 2017/02/22 05:58:34 I realise this is for testing MD/Harmony stuff, bu
tapted 2017/02/22 22:45:30 ooh good point - this should use MdTextButton::Cre
68 }
69
70 bool Cancel() override { return parent_->AllowDialogClose(false); }
71 bool Accept() override { return parent_->AllowDialogClose(true); }
72 int GetDialogButtons() const override { return parent_->GetDialogButtons(); }
73 base::string16 GetDialogButtonLabel(ui::DialogButton button) const override {
74 if (button == ui::DIALOG_BUTTON_OK)
75 return parent_->ok_button_label_->text();
76 if (button == ui::DIALOG_BUTTON_CANCEL)
77 return parent_->cancel_button_label_->text();
78 return base::string16();
79 }
80
81 private:
82 DialogExample* parent_;
83
84 DISALLOW_COPY_AND_ASSIGN(Delegate);
85 };
86
87 class DialogExample::Bubble : public Delegate<BubbleDialogDelegateView> {
88 public:
89 Bubble(DialogExample* parent, View* anchor)
90 : BubbleDialogDelegateView(anchor, BubbleBorder::TOP_LEFT),
91 Delegate(parent) {
92 set_close_on_deactivate(!parent->persistent_bubble_->checked());
93 }
94
95 // BubbleDialogDelegateView:
96 void Init() override { InitDelegate(); }
97
98 private:
99 DISALLOW_COPY_AND_ASSIGN(Bubble);
100 };
101
102 class DialogExample::Dialog : public Delegate<DialogDelegateView> {
103 public:
104 explicit Dialog(DialogExample* parent) : Delegate(parent) {}
105
106 // WidgetDelgate:
Patti Lor 2017/02/22 05:58:34 WidgetDelegate (typo)
tapted 2017/02/22 22:45:30 Done.
107 bool CanResize() const override {
108 // Mac supports resizing of modal dialogs (parent or window-modal). On other
109 // platforms this will be weird unless the modal type is "none", but helps
110 // test layout.
111 return true;
112 }
113
114 private:
115 DISALLOW_COPY_AND_ASSIGN(Dialog);
116 };
117
118 DialogExample::DialogExample()
119 : ExampleBase("Dialog"),
120 mode_model_({
121 base::ASCIIToUTF16("Modeless"), base::ASCIIToUTF16("Window Modal"),
122 base::ASCIIToUTF16("Child Modal"), base::ASCIIToUTF16("System Modal"),
123 base::ASCIIToUTF16("Fake Modeless (non-bubbles)"),
124 }) {}
125
126 DialogExample::~DialogExample() {}
127
128 void DialogExample::CreateExampleView(View* container) {
129 // GridLayout |resize_percent| constants.
130 const float kFixed = 0.f;
131 const float kStretchy = 1.f;
132
133 const int horizontal_spacing =
134 ViewsDelegate::GetInstance()->GetDialogRelatedButtonHorizontalSpacing();
135 GridLayout* layout = GridLayout::CreatePanel(container);
136 container->SetLayoutManager(layout);
137 ColumnSet* column_set = layout->AddColumnSet(kFieldsColumnId);
138 column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, kFixed,
139 GridLayout::USE_PREF, 0, 0);
140 column_set->AddPaddingColumn(kFixed, horizontal_spacing);
141 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kStretchy,
142 GridLayout::USE_PREF, 0, 0);
143 column_set->AddPaddingColumn(kFixed, horizontal_spacing);
144 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
145 GridLayout::USE_PREF, 0, 0);
146 StartTextfieldRow(layout, &title_, "Dialog Title", "Title");
147 StartTextfieldRow(layout, &body_, "Dialog Body Text", "Body Text");
148
149 StartTextfieldRow(layout, &ok_button_label_, "OK Button Label", "Done");
150 AddCheckbox(layout, &has_ok_button_);
151
152 StartTextfieldRow(layout, &cancel_button_label_, "Cancel Button Label",
153 "Cancel");
154 AddCheckbox(layout, &has_cancel_button_);
155
156 StartTextfieldRow(layout, &extra_button_label_, "Extra Button Label", "Edit");
157 AddCheckbox(layout, &has_extra_button_);
158
159 StartRowWithLabel(layout, "Modal Type");
160 mode_ = new Combobox(&mode_model_);
161 mode_->set_listener(this);
162 mode_->SetSelectedIndex(ui::MODAL_TYPE_CHILD);
163 layout->AddView(mode_);
164
165 StartRowWithLabel(layout, "Bubble");
166 AddCheckbox(layout, &bubble_);
167 AddCheckbox(layout, &persistent_bubble_);
168 persistent_bubble_->SetText(base::ASCIIToUTF16("Persistent"));
169
170 column_set = layout->AddColumnSet(kButtonsColumnId);
171 column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, kStretchy,
172 GridLayout::USE_PREF, 0, 0);
173 layout->StartRowWithPadding(kFixed, kButtonsColumnId, kFixed,
174 kUnrelatedControlVerticalSpacing);
175 show_ = MdTextButton::Create(this, base::ASCIIToUTF16("Show"));
176 layout->AddView(show_);
177
178 // Grow the dialog a bit when this example is first selected, so it all fits.
179 gfx::Size dialog_size = container->GetWidget()->GetRestoredBounds().size();
180 dialog_size.set_height(dialog_size.height() + 80);
181 container->GetWidget()->SetSize(dialog_size);
182 }
183
184 void DialogExample::StartRowWithLabel(GridLayout* layout, const char* label) {
185 const float kFixedVerticalResize = 0.f;
186 layout->StartRowWithPadding(
187 kFixedVerticalResize, kFieldsColumnId, kFixedVerticalResize,
188 ViewsDelegate::GetInstance()->GetDialogRelatedControlVerticalSpacing());
189 layout->AddView(new Label(base::ASCIIToUTF16(label)));
190 }
191
192 void DialogExample::StartTextfieldRow(GridLayout* layout,
193 Textfield** member,
194 const char* label,
195 const char* value) {
196 StartRowWithLabel(layout, label);
197 Textfield* textfield = new Textfield();
198 layout->AddView(textfield);
199 textfield->set_controller(this);
200 textfield->SetText(base::ASCIIToUTF16(value));
201 *member = textfield;
202 }
203
204 void DialogExample::AddCheckbox(GridLayout* layout, Checkbox** member) {
205 Checkbox* checkbox = new Checkbox(base::string16());
206 checkbox->set_listener(this);
207 checkbox->SetChecked(true);
208 layout->AddView(checkbox);
209 *member = checkbox;
210 }
211
212 ui::ModalType DialogExample::GetModalType() const {
213 // "Fake" modeless happens when a DialogDelegate specifies window-modal, but
214 // doesn't provide a parent window.
215 if (mode_->selected_index() == kFakeModeless)
216 return ui::MODAL_TYPE_WINDOW;
217
218 return static_cast<ui::ModalType>(mode_->selected_index());
219 }
220
221 int DialogExample::GetDialogButtons() const {
222 int buttons = 0;
223 if (has_ok_button_->checked())
224 buttons |= ui::DIALOG_BUTTON_OK;
225 if (has_cancel_button_->checked())
226 buttons |= ui::DIALOG_BUTTON_CANCEL;
227 return buttons;
228 }
229
230 bool DialogExample::AllowDialogClose(bool accept) {
231 PrintStatus("Dialog closed with %s.", accept ? "Accept" : "Cancel");
232 last_dialog_ = nullptr;
233 last_body_label_ = nullptr;
234 return true;
235 }
236
237 void DialogExample::ResizeDialog() {
238 DCHECK(last_dialog_);
239 Widget* widget = last_dialog_->GetWidget();
240 gfx::Rect preferred_bounds(widget->GetRestoredBounds());
241 preferred_bounds.set_size(widget->non_client_view()->GetPreferredSize());
242
243 // Q: Do we need NonClientFrameView::GetWindowBoundsForClientBounds() here?
244 // A: When DialogCientView properly feeds back sizes, we do not.
245 widget->SetBoundsConstrained(preferred_bounds);
246 }
247
248 void DialogExample::ButtonPressed(Button* sender, const ui::Event& event) {
249 if (sender == show_) {
250 if (bubble_->checked()) {
251 Bubble* bubble = new Bubble(this, sender);
252 last_dialog_ = bubble;
253 BubbleDialogDelegateView::CreateBubble(bubble);
254 } else {
255 Dialog* dialog = new Dialog(this);
256 last_dialog_ = dialog;
257 dialog->InitDelegate();
258
259 // constrained_window::CreateBrowserModalDialogViews() allows dialogs to
260 // be created as MODAL_TYPE_WINDOW without specifying a parent.
261 gfx::NativeView parent = nullptr;
262 if (mode_->selected_index() != kFakeModeless)
263 parent = container()->GetWidget()->GetNativeView();
264
265 DialogDelegate::CreateDialogWidget(
266 dialog, container()->GetWidget()->GetNativeWindow(), parent);
267 }
268 last_dialog_->GetWidget()->Show();
269 return;
270 }
271
272 if (sender == bubble_) {
273 if (bubble_->checked() && GetModalType() != ui::MODAL_TYPE_CHILD) {
274 mode_->SetSelectedIndex(ui::MODAL_TYPE_CHILD);
275 PrintStatus("You nearly always want Child Modal for bubbles.");
276 }
277 persistent_bubble_->SetEnabled(bubble_->checked());
278 OnPerformAction(mode_); // Validate the modal type.
279
280 if (!bubble_->checked() && GetModalType() == ui::MODAL_TYPE_CHILD) {
281 // Do something reasonable when simply unchecking bubble and re-enable.
282 mode_->SetSelectedIndex(ui::MODAL_TYPE_WINDOW);
283 OnPerformAction(mode_);
284 }
285 return;
286 }
287
288 // Other buttons are all checkboxes. Update the dialog if there is one.
289 if (last_dialog_) {
290 last_dialog_->GetDialogClientView()->UpdateDialogButtons();
291 ResizeDialog();
292 }
293 }
294
295 void DialogExample::ContentsChanged(Textfield* sender,
296 const base::string16& new_contents) {
297 if (!last_dialog_)
298 return;
299
300 if (sender == extra_button_label_)
301 PrintStatus("DialogClientView can never refresh the extra view.");
302
303 if (sender == title_) {
304 last_dialog_->GetWidget()->UpdateWindowTitle();
305 } else if (sender == body_) {
306 last_body_label_->SetText(new_contents);
307 } else {
308 last_dialog_->GetDialogClientView()->UpdateDialogButtons();
309 }
310
311 ResizeDialog();
312 }
313
314 void DialogExample::OnPerformAction(Combobox* combobox) {
315 bool enable = bubble_->checked() || GetModalType() != ui::MODAL_TYPE_CHILD;
316 #if defined(OS_MACOSX)
317 enable = enable && GetModalType() != ui::MODAL_TYPE_SYSTEM;
318 #endif
319 show_->SetEnabled(enable);
320 if (!enable && GetModalType() == ui::MODAL_TYPE_CHILD)
321 PrintStatus("MODAL_TYPE_CHILD can't be used with non-bubbles.");
322 if (!enable && GetModalType() == ui::MODAL_TYPE_SYSTEM)
323 PrintStatus("MODAL_TYPE_SYSTEM isn't supported on Mac.");
324 }
325
326 } // namespace examples
327 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698