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

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

Issue 8552005: views: Move views/window/ to ui/views/window directory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « views/window/dialog_client_view.h ('k') | views/window/dialog_delegate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "views/window/dialog_client_view.h"
6
7 #include "build/build_config.h"
8
9 #if defined(OS_WIN)
10 #include <windows.h>
11 #include <uxtheme.h>
12 #include <vsstyle.h>
13 #elif defined(TOOLKIT_USES_GTK)
14 #include <gtk/gtk.h>
15 #endif
16
17 #include <algorithm>
18
19 #include "base/utf_string_conversions.h"
20 #include "grit/ui_strings.h"
21 #include "ui/base/hit_test.h"
22 #include "ui/base/keycodes/keyboard_codes.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/gfx/canvas_skia.h"
26 #include "ui/gfx/font.h"
27 #include "views/controls/button/text_button.h"
28 #include "views/layout/layout_constants.h"
29 #include "views/widget/root_view.h"
30 #include "views/widget/widget.h"
31 #include "views/window/dialog_delegate.h"
32
33 #if defined(OS_WIN)
34 #include "ui/gfx/native_theme.h"
35 #else
36 #include "ui/gfx/skia_utils_gtk.h"
37 #endif
38
39 namespace views {
40 namespace {
41
42 // Updates any of the standard buttons according to the delegate.
43 void UpdateButtonHelper(NativeTextButton* button_view,
44 DialogDelegate* delegate,
45 ui::DialogButton button) {
46 string16 label = delegate->GetDialogButtonLabel(button);
47 if (!label.empty())
48 button_view->SetText(label);
49 button_view->SetEnabled(delegate->IsDialogButtonEnabled(button));
50 button_view->SetVisible(delegate->IsDialogButtonVisible(button));
51 }
52
53 #if defined(OS_WIN)
54 void FillViewWithSysColor(gfx::Canvas* canvas, View* view, COLORREF color) {
55 SkColor sk_color =
56 SkColorSetRGB(GetRValue(color), GetGValue(color), GetBValue(color));
57 canvas->FillRect(sk_color, view->GetLocalBounds());
58 }
59 #endif
60
61 // DialogButton ----------------------------------------------------------------
62
63 // DialogButtons is used for the ok/cancel buttons of the window. DialogButton
64 // forwards AcceleratorPressed to the delegate.
65
66 class DialogButton : public NativeTextButton {
67 public:
68 DialogButton(ButtonListener* listener,
69 Widget* owner,
70 ui::DialogButton type,
71 const string16& title,
72 bool is_default)
73 : NativeTextButton(listener, title),
74 owner_(owner),
75 type_(type) {
76 SetIsDefault(is_default);
77 }
78
79 // Overridden to forward to the delegate.
80 virtual bool AcceleratorPressed(const Accelerator& accelerator) {
81 if (!owner_->widget_delegate()->AsDialogDelegate()->
82 AreAcceleratorsEnabled(type_)) {
83 return false;
84 }
85 return NativeTextButton::AcceleratorPressed(accelerator);
86 }
87
88 private:
89 Widget* owner_;
90 const ui::DialogButton type_;
91
92 DISALLOW_COPY_AND_ASSIGN(DialogButton);
93 };
94
95 } // namespace
96
97 // static
98 gfx::Font* DialogClientView::dialog_button_font_ = NULL;
99 static const int kDialogMinButtonWidth = 75;
100 static const int kDialogButtonLabelSpacing = 16;
101 static const int kDialogButtonContentSpacing = 5;
102
103 // The group used by the buttons. This name is chosen voluntarily big not to
104 // conflict with other groups that could be in the dialog content.
105 static const int kButtonGroup = 6666;
106
107 ///////////////////////////////////////////////////////////////////////////////
108 // DialogClientView, public:
109
110 DialogClientView::DialogClientView(Widget* owner, View* contents_view)
111 : ClientView(owner, contents_view),
112 ok_button_(NULL),
113 cancel_button_(NULL),
114 default_button_(NULL),
115 extra_view_(NULL),
116 size_extra_view_height_to_buttons_(false),
117 notified_delegate_(false),
118 listening_to_focus_(false),
119 saved_focus_manager_(NULL),
120 bottom_view_(NULL) {
121 InitClass();
122 }
123
124 DialogClientView::~DialogClientView() {
125 }
126
127 void DialogClientView::ShowDialogButtons() {
128 DialogDelegate* dd = GetDialogDelegate();
129 int buttons = dd->GetDialogButtons();
130 if (buttons & ui::DIALOG_BUTTON_OK && !ok_button_) {
131 string16 label = dd->GetDialogButtonLabel(ui::DIALOG_BUTTON_OK);
132 if (label.empty())
133 label = l10n_util::GetStringUTF16(IDS_APP_OK);
134 bool is_default_button =
135 (dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_OK) != 0;
136 ok_button_ = new DialogButton(this,
137 GetWidget(),
138 ui::DIALOG_BUTTON_OK,
139 label,
140 is_default_button);
141 ok_button_->SetGroup(kButtonGroup);
142 if (is_default_button)
143 default_button_ = ok_button_;
144 if (!(buttons & ui::DIALOG_BUTTON_CANCEL))
145 ok_button_->AddAccelerator(Accelerator(ui::VKEY_ESCAPE,
146 false, false, false));
147 AddChildView(ok_button_);
148 }
149 if (buttons & ui::DIALOG_BUTTON_CANCEL && !cancel_button_) {
150 string16 label =
151 dd->GetDialogButtonLabel(ui::DIALOG_BUTTON_CANCEL);
152 if (label.empty()) {
153 if (buttons & ui::DIALOG_BUTTON_OK) {
154 label = l10n_util::GetStringUTF16(IDS_APP_CANCEL);
155 } else {
156 label = l10n_util::GetStringUTF16(IDS_APP_CLOSE);
157 }
158 }
159 bool is_default_button =
160 (dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_CANCEL)
161 != 0;
162 cancel_button_ = new DialogButton(this,
163 GetWidget(),
164 ui::DIALOG_BUTTON_CANCEL,
165 label,
166 is_default_button);
167 cancel_button_->SetGroup(kButtonGroup);
168 cancel_button_->AddAccelerator(Accelerator(ui::VKEY_ESCAPE,
169 false, false, false));
170 if (is_default_button)
171 default_button_ = ok_button_;
172 AddChildView(cancel_button_);
173 }
174 if (!buttons) {
175 // Register the escape key as an accelerator which will close the window
176 // if there are no dialog buttons.
177 AddAccelerator(Accelerator(ui::VKEY_ESCAPE, false, false, false));
178 }
179 }
180
181 void DialogClientView::SetDefaultButton(NativeTextButton* new_default_button) {
182 if (default_button_ && default_button_ != new_default_button) {
183 default_button_->SetIsDefault(false);
184 default_button_ = NULL;
185 }
186
187 if (new_default_button) {
188 default_button_ = new_default_button;
189 default_button_->SetIsDefault(true);
190 }
191 }
192
193 void DialogClientView::OnWillChangeFocus(View* focused_before,
194 View* focused_now) {
195 NativeTextButton* new_default_button = NULL;
196 if (focused_now &&
197 focused_now->GetClassName() == NativeTextButton::kViewClassName) {
198 new_default_button = static_cast<NativeTextButton*>(focused_now);
199 } else {
200 // The focused view is not a button, get the default button from the
201 // delegate.
202 DialogDelegate* dd = GetDialogDelegate();
203 if ((dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_OK) != 0)
204 new_default_button = ok_button_;
205 if ((dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_CANCEL)
206 != 0)
207 new_default_button = cancel_button_;
208 }
209 SetDefaultButton(new_default_button);
210 }
211
212 void DialogClientView::OnDidChangeFocus(View* focused_before,
213 View* focused_now) {
214 }
215
216 // Changing dialog labels will change button widths.
217 void DialogClientView::UpdateDialogButtons() {
218 DialogDelegate* dd = GetDialogDelegate();
219 int buttons = dd->GetDialogButtons();
220
221 if (buttons & ui::DIALOG_BUTTON_OK)
222 UpdateButtonHelper(ok_button_, dd, ui::DIALOG_BUTTON_OK);
223
224 if (buttons & ui::DIALOG_BUTTON_CANCEL) {
225 UpdateButtonHelper(cancel_button_, dd, ui::DIALOG_BUTTON_CANCEL);
226 }
227
228 LayoutDialogButtons();
229 SchedulePaint();
230 }
231
232 void DialogClientView::AcceptWindow() {
233 if (notified_delegate_) {
234 // Only notify the delegate once. See comment in header above
235 // notified_delegate_ for details.
236 return;
237 }
238 if (GetDialogDelegate()->Accept(false)) {
239 notified_delegate_ = true;
240 Close();
241 }
242 }
243
244 void DialogClientView::CancelWindow() {
245 // Call the standard Close handler, which checks with the delegate before
246 // proceeding. This checking _isn't_ done here, but in the WM_CLOSE handler,
247 // so that the close box on the window also shares this code path.
248 Close();
249 }
250
251 void DialogClientView::SetBottomView(View* bottom_view) {
252 if (bottom_view_) {
253 RemoveChildView(bottom_view_);
254 delete bottom_view_;
255 }
256 bottom_view_ = bottom_view;
257 if (bottom_view_)
258 AddChildView(bottom_view_);
259 }
260
261 ///////////////////////////////////////////////////////////////////////////////
262 // DialogClientView, View overrides:
263
264 void DialogClientView::NativeViewHierarchyChanged(
265 bool attached,
266 gfx::NativeView native_view,
267 internal::RootView* root_view) {
268 if (attached) {
269 UpdateFocusListener();
270 }
271 }
272
273 ///////////////////////////////////////////////////////////////////////////////
274 // DialogClientView, ClientView overrides:
275
276 bool DialogClientView::CanClose() {
277 if (notified_delegate_)
278 return true;
279
280 DialogDelegate* dd = GetDialogDelegate();
281 int buttons = dd->GetDialogButtons();
282 bool close = true;
283 if (buttons & ui::DIALOG_BUTTON_CANCEL)
284 close = dd->Cancel();
285 else if (buttons & ui::DIALOG_BUTTON_OK)
286 close = dd->Accept(true);
287 notified_delegate_ = close;
288 return close;
289 }
290
291 void DialogClientView::WidgetClosing() {
292 if (listening_to_focus_) {
293 DCHECK(saved_focus_manager_);
294 if (saved_focus_manager_)
295 saved_focus_manager_->RemoveFocusChangeListener(this);
296 }
297 }
298
299 int DialogClientView::NonClientHitTest(const gfx::Point& point) {
300 if (size_box_bounds_.Contains(point.x() - x(), point.y() - y()))
301 return HTBOTTOMRIGHT;
302 return ClientView::NonClientHitTest(point);
303 }
304
305 DialogClientView* DialogClientView::AsDialogClientView() {
306 return this;
307 }
308
309 const DialogClientView* DialogClientView::AsDialogClientView() const {
310 return this;
311 }
312
313 ////////////////////////////////////////////////////////////////////////////////
314 // DialogClientView, View overrides:
315
316 void DialogClientView::OnPaint(gfx::Canvas* canvas) {
317 #if defined(OS_WIN)
318 FillViewWithSysColor(canvas, this, GetSysColor(COLOR_3DFACE));
319 #elif defined(USE_WAYLAND) || defined(USE_AURA)
320 SkColor sk_color = SkColorSetARGB(200, 255, 255, 255);
321 canvas->FillRect(sk_color, GetLocalBounds());
322 #else
323 GtkWidget* widget = GetWidget()->GetNativeView();
324 if (GTK_IS_WINDOW(widget)) {
325 GtkStyle* window_style = gtk_widget_get_style(widget);
326 canvas->FillRect(gfx::GdkColorToSkColor(window_style->bg[GTK_STATE_NORMAL]),
327 GetLocalBounds());
328 }
329 #endif
330 }
331
332 void DialogClientView::PaintChildren(gfx::Canvas* canvas) {
333 View::PaintChildren(canvas);
334 if (!GetWidget()->IsMaximized() && !GetWidget()->IsMinimized())
335 PaintSizeBox(canvas);
336 }
337
338 void DialogClientView::Layout() {
339 if (has_dialog_buttons())
340 LayoutDialogButtons();
341 if (bottom_view_) {
342 gfx::Rect bounds = GetContentsBounds();
343 gfx::Size pref = bottom_view_->GetPreferredSize();
344 bottom_view_->SetBounds(bounds.x(),
345 bounds.bottom() - pref.height() - kButtonVEdgeMargin,
346 bounds.width(), pref.height());
347 }
348 LayoutContentsView();
349 }
350
351 void DialogClientView::ViewHierarchyChanged(bool is_add, View* parent,
352 View* child) {
353 if (is_add && child == this) {
354 // Can only add and update the dialog buttons _after_ they are added to the
355 // view hierarchy since they are native controls and require the
356 // Container's HWND.
357 ShowDialogButtons();
358 ClientView::ViewHierarchyChanged(is_add, parent, child);
359
360 UpdateFocusListener();
361
362 // The "extra view" must be created and installed after the contents view
363 // has been inserted into the view hierarchy.
364 CreateExtraView();
365 UpdateDialogButtons();
366 Layout();
367 }
368 }
369
370 gfx::Size DialogClientView::GetPreferredSize() {
371 gfx::Size prefsize = contents_view()->GetPreferredSize();
372 int button_height = 0;
373 if (has_dialog_buttons()) {
374 if (cancel_button_)
375 button_height = cancel_button_->height();
376 else
377 button_height = ok_button_->height();
378 // Account for padding above and below the button.
379 button_height += kDialogButtonContentSpacing + kButtonVEdgeMargin;
380
381 // Make sure the view is sized to the buttons's width if they are wider than
382 // the contents.
383 int width = 0;
384 if (cancel_button_)
385 width += GetButtonWidth(ui::DIALOG_BUTTON_CANCEL);
386 if (ok_button_) {
387 width += GetButtonWidth(ui::DIALOG_BUTTON_OK);
388 if (cancel_button_)
389 width += kRelatedButtonHSpacing;
390 }
391 if (extra_view_) {
392 width += extra_view_->GetPreferredSize().width();
393 if (cancel_button_ || ok_button_)
394 width += kRelatedButtonHSpacing;
395 }
396 if (width > 0) {
397 width += 2 * kButtonHEdgeMargin;
398 prefsize.set_width(std::max(prefsize.width(), width));
399 }
400 }
401 if (bottom_view_) {
402 gfx::Size bottom_pref = bottom_view_->GetPreferredSize();
403 prefsize.Enlarge(0, bottom_pref.height() + kButtonVEdgeMargin);
404 }
405 prefsize.Enlarge(0, button_height);
406 return prefsize;
407 }
408
409 bool DialogClientView::AcceleratorPressed(const Accelerator& accelerator) {
410 // We only expect Escape key.
411 DCHECK(accelerator.key_code() == ui::VKEY_ESCAPE);
412 Close();
413 return true;
414 }
415
416 ////////////////////////////////////////////////////////////////////////////////
417 // DialogClientView, ButtonListener implementation:
418
419 void DialogClientView::ButtonPressed(
420 Button* sender, const views::Event& event) {
421 // We NULL check the delegate here since the buttons can receive WM_COMMAND
422 // messages even after they (and the window containing us) are destroyed.
423 if (!GetDialogDelegate())
424 return;
425
426 if (sender == ok_button_) {
427 AcceptWindow();
428 } else if (sender == cancel_button_) {
429 CancelWindow();
430 } else {
431 NOTREACHED();
432 }
433 }
434
435 ////////////////////////////////////////////////////////////////////////////////
436 // DialogClientView, private:
437
438 void DialogClientView::PaintSizeBox(gfx::Canvas* canvas) {
439 if (GetWidget()->widget_delegate()->CanResize() ||
440 GetWidget()->widget_delegate()->CanMaximize()) {
441 #if defined(OS_WIN)
442 gfx::NativeTheme::ExtraParams extra;
443 gfx::Size gripper_size = gfx::NativeTheme::instance()->GetPartSize(
444 gfx::NativeTheme::kWindowResizeGripper, gfx::NativeTheme::kNormal,
445 extra);
446
447 // TODO(beng): (http://b/1085509) In "classic" rendering mode, there isn't
448 // a theme-supplied gripper. We should probably improvise
449 // something, which would also require changing |gripper_size|
450 // to have different default values, too...
451 size_box_bounds_ = GetContentsBounds();
452 size_box_bounds_.set_x(size_box_bounds_.right() - gripper_size.width());
453 size_box_bounds_.set_y(size_box_bounds_.bottom() - gripper_size.height());
454
455 gfx::NativeTheme::instance()->Paint(canvas->GetSkCanvas(),
456 gfx::NativeTheme::kWindowResizeGripper,
457 gfx::NativeTheme::kNormal,
458 size_box_bounds_,
459 extra);
460 #else
461 NOTIMPLEMENTED();
462 // TODO(port): paint size box
463 #endif
464 }
465 }
466
467 int DialogClientView::GetButtonWidth(int button) const {
468 DialogDelegate* dd = GetDialogDelegate();
469 string16 button_label = dd->GetDialogButtonLabel(
470 static_cast<ui::DialogButton>(button));
471 int string_width = dialog_button_font_->GetStringWidth(button_label);
472 return std::max(string_width + kDialogButtonLabelSpacing,
473 kDialogMinButtonWidth);
474 }
475
476 int DialogClientView::GetButtonsHeight() const {
477 if (has_dialog_buttons()) {
478 if (cancel_button_)
479 return cancel_button_->height() + kDialogButtonContentSpacing;
480 return ok_button_->height() + kDialogButtonContentSpacing;
481 }
482 return 0;
483 }
484
485 void DialogClientView::LayoutDialogButtons() {
486 gfx::Rect lb = GetContentsBounds();
487 gfx::Rect extra_bounds;
488 int bottom_y = lb.bottom() - kButtonVEdgeMargin;
489 int button_height = 0;
490 if (bottom_view_) {
491 gfx::Size bottom_pref = bottom_view_->GetPreferredSize();
492 bottom_y -= bottom_pref.height() + kButtonVEdgeMargin + kButtonVEdgeMargin;
493 }
494 if (cancel_button_) {
495 gfx::Size ps = cancel_button_->GetPreferredSize();
496 int button_width = std::max(
497 GetButtonWidth(ui::DIALOG_BUTTON_CANCEL), ps.width());
498 int button_x = lb.right() - button_width - kButtonHEdgeMargin;
499 int button_y = bottom_y - ps.height();
500 cancel_button_->SetBounds(button_x, button_y, button_width, ps.height());
501 // The extra view bounds are dependent on this button.
502 extra_bounds.set_width(std::max(0, cancel_button_->x()));
503 extra_bounds.set_y(cancel_button_->y());
504 button_height = std::max(button_height, ps.height());
505 }
506 if (ok_button_) {
507 gfx::Size ps = ok_button_->GetPreferredSize();
508 int button_width = std::max(
509 GetButtonWidth(ui::DIALOG_BUTTON_OK), ps.width());
510 int ok_button_right = lb.right() - kButtonHEdgeMargin;
511 if (cancel_button_)
512 ok_button_right = cancel_button_->x() - kRelatedButtonHSpacing;
513 int button_x = ok_button_right - button_width;
514 int button_y = bottom_y - ps.height();
515 ok_button_->SetBounds(button_x, button_y, ok_button_right - button_x,
516 ps.height());
517 // The extra view bounds are dependent on this button.
518 extra_bounds.set_width(std::max(0, ok_button_->x()));
519 extra_bounds.set_y(ok_button_->y());
520 button_height = std::max(button_height, ps.height());
521 }
522 if (extra_view_) {
523 gfx::Size ps = extra_view_->GetPreferredSize();
524 extra_bounds.set_x(lb.x() + kButtonHEdgeMargin);
525 int height = size_extra_view_height_to_buttons_ ?
526 std::max(ps.height(), button_height) : ps.height();
527 extra_bounds.set_height(height);
528 extra_view_->SetBoundsRect(extra_bounds);
529 }
530 }
531
532 void DialogClientView::LayoutContentsView() {
533 gfx::Rect lb = GetContentsBounds();
534 lb.set_height(std::max(0, lb.height() - GetButtonsHeight()));
535 contents_view()->SetBoundsRect(lb);
536 contents_view()->Layout();
537 }
538
539 void DialogClientView::CreateExtraView() {
540 View* extra_view = GetDialogDelegate()->GetExtraView();
541 if (extra_view && !extra_view_) {
542 extra_view_ = extra_view;
543 extra_view_->SetGroup(kButtonGroup);
544 AddChildView(extra_view_);
545 size_extra_view_height_to_buttons_ =
546 GetDialogDelegate()->GetSizeExtraViewHeightToButtons();
547 }
548 }
549
550 DialogDelegate* DialogClientView::GetDialogDelegate() const {
551 return GetWidget()->widget_delegate()->AsDialogDelegate();
552 }
553
554 void DialogClientView::Close() {
555 GetWidget()->Close();
556 GetDialogDelegate()->OnClose();
557 }
558
559 void DialogClientView::UpdateFocusListener() {
560 FocusManager* focus_manager = GetFocusManager();
561 // Listen for focus change events so we can update the default button.
562 // focus_manager can be NULL when the dialog is created on un-shown view.
563 // We start listening for focus changes when the page is visible.
564 // Focus manager could also change if window host changes a parent.
565 if (listening_to_focus_) {
566 if (saved_focus_manager_ == focus_manager)
567 return;
568 DCHECK(saved_focus_manager_);
569 if (saved_focus_manager_)
570 saved_focus_manager_->RemoveFocusChangeListener(this);
571 listening_to_focus_ = false;
572 }
573 saved_focus_manager_ = focus_manager;
574 // Listen for focus change events so we can update the default button.
575 if (focus_manager) {
576 focus_manager->AddFocusChangeListener(this);
577 listening_to_focus_ = true;
578 }
579 }
580
581 // static
582 void DialogClientView::InitClass() {
583 static bool initialized = false;
584 if (!initialized) {
585 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
586 dialog_button_font_ = new gfx::Font(rb.GetFont(ResourceBundle::BaseFont));
587 initialized = true;
588 }
589 }
590
591 } // namespace views
OLDNEW
« no previous file with comments | « views/window/dialog_client_view.h ('k') | views/window/dialog_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698