1 // Copyright 2014 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.
5 #include "chrome/browser/ui/views/app_list/app_list_dialog_container.h"
7 #include "chrome/browser/ui/host_desktop.h"
8 #include "third_party/skia/include/core/SkPaint.h"
9 #include "ui/app_list/app_list_constants.h"
10 #include "ui/base/accelerators/accelerator.h"
11 #include "ui/base/resource/resource_bundle.h"
12 #include "ui/base/ui_base_types.h"
13 #include "ui/events/event_constants.h"
14 #include "ui/events/keycodes/keyboard_codes.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/resources/grit/ui_resources.h"
17 #include "ui/views/background.h"
18 #include "ui/views/border.h"
19 #include "ui/views/bubble/bubble_border.h"
20 #include "ui/views/bubble/bubble_frame_view.h"
21 #include "ui/views/controls/button/label_button.h"
22 #include "ui/views/layout/fill_layout.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/views/window/client_view.h"
25 #include "ui/views/window/dialog_delegate.h"
26 #include "ui/views/window/native_frame_view.h"
27 #include "ui/views/window/non_client_view.h"
31 // The background for App List dialogs, which appears as a rounded rectangle
32 // with the same border radius and color as the app list contents.
33 class AppListOverlayBackground : public views::Background {
35 AppListOverlayBackground() {}
36 ~AppListOverlayBackground() override {}
38 // Overridden from views::Background:
39 void Paint(gfx::Canvas* canvas, views::View* view) const override {
40 // The radius of the app list overlay (the dialog's background).
41 // TODO(sashab): Using SupportsShadow() from app_list_view.cc, make this
42 // 1px smaller on platforms that support shadows.
43 const int kAppListOverlayBorderRadius = 3;
46 paint.setStyle(SkPaint::kFill_Style);
47 paint.setColor(app_list::kContentsBackgroundColor);
48 canvas->DrawRoundRect(
49 view->GetContentsBounds(), kAppListOverlayBorderRadius, paint);
53 DISALLOW_COPY_AND_ASSIGN(AppListOverlayBackground);
56 // The contents view for an App List Dialog, which covers the entire app list
57 // and adds a close button.
58 class AppListDialogContainer : public views::DialogDelegateView,
59 public views::ButtonListener {
61 AppListDialogContainer(views::View* dialog_body,
62 const base::Closure& close_callback)
63 : dialog_body_(dialog_body),
65 close_callback_(close_callback) {
66 set_background(new AppListOverlayBackground());
67 AddChildView(dialog_body_);
69 close_button_ = views::BubbleFrameView::CreateCloseButton(this);
70 ui::Accelerator escape(ui::VKEY_ESCAPE, ui::EF_NONE);
71 close_button_->AddAccelerator(escape);
72 AddChildView(close_button_);
74 ~AppListDialogContainer() override {}
77 // Overridden from views::View:
78 void Layout() override {
79 // Margin of the close button from the top right-hand corner of the dialog.
80 const int kCloseButtonDialogMargin = 10;
82 close_button_->SetPosition(
83 gfx::Point(width() - close_button_->width() - kCloseButtonDialogMargin,
84 kCloseButtonDialogMargin));
86 dialog_body_->SetBoundsRect(GetContentsBounds());
87 views::DialogDelegateView::Layout();
89 void ViewHierarchyChanged(
90 const ViewHierarchyChangedDetails& details) override {
91 views::DialogDelegateView::ViewHierarchyChanged(details);
92 if (details.is_add && details.child == this)
93 GetFocusManager()->AdvanceFocus(false);
96 // Overridden from views::WidgetDelegate:
97 views::View* GetInitiallyFocusedView() override { return NULL; }
98 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
99 void WindowClosing() override {
100 if (!close_callback_.is_null())
101 close_callback_.Run();
103 views::ClientView* CreateClientView(views::Widget* widget) override {
104 return new views::ClientView(widget, GetContentsView());
106 views::NonClientFrameView* CreateNonClientFrameView(
107 views::Widget* widget) override {
108 return new views::NativeFrameView(widget);
111 // Overridden from views::ButtonListener:
112 void ButtonPressed(views::Button* sender, const ui::Event& event) override {
113 if (sender == close_button_) {
114 GetWidget()->Close();
120 views::View* dialog_body_;
121 views::LabelButton* close_button_;
122 const base::Closure close_callback_;
124 DISALLOW_COPY_AND_ASSIGN(AppListDialogContainer);
127 // A BubbleFrameView that allows its client view to extend all the way to the
128 // top of the dialog, overlapping the BubbleFrameView's close button. This
129 // allows dialog content to appear closer to the top, in place of a title.
130 class FullSizeBubbleFrameView : public views::BubbleFrameView {
132 FullSizeBubbleFrameView() : views::BubbleFrameView(gfx::Insets()) {}
133 ~FullSizeBubbleFrameView() override {}
136 // Overridden from views::ViewTargeterDelegate:
137 bool DoesIntersectRect(const View* target,
138 const gfx::Rect& rect) const override {
139 // Make sure click events can still reach the close button, even if the
140 // ClientView overlaps it.
141 if (IsCloseButtonVisible() && GetCloseButtonBounds().Intersects(rect))
143 return views::BubbleFrameView::DoesIntersectRect(target, rect);
146 // Overridden from views::View:
147 gfx::Insets GetInsets() const override { return gfx::Insets(); }
149 DISALLOW_COPY_AND_ASSIGN(FullSizeBubbleFrameView);
152 // A container view for a native dialog, which sizes to the given fixed |size|.
153 class NativeDialogContainer : public views::DialogDelegateView {
155 NativeDialogContainer(views::View* dialog_body,
156 const gfx::Size& size,
157 const base::Closure& close_callback)
159 dialog_body_(dialog_body),
160 close_callback_(close_callback) {
161 SetLayoutManager(new views::FillLayout());
162 AddChildView(dialog_body_);
164 ~NativeDialogContainer() override {}
167 // Overridden from views::View:
168 gfx::Size GetPreferredSize() const override { return size_; }
169 void ViewHierarchyChanged(
170 const ViewHierarchyChangedDetails& details) override {
171 views::DialogDelegateView::ViewHierarchyChanged(details);
172 if (details.is_add && details.child == this)
173 GetFocusManager()->AdvanceFocus(false);
176 // Overridden from views::WidgetDelegate:
177 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; }
178 void WindowClosing() override {
179 if (!close_callback_.is_null())
180 close_callback_.Run();
183 // Overridden from views::DialogDelegate:
184 int GetDialogButtons() const override { return ui::DIALOG_BUTTON_NONE; }
185 views::NonClientFrameView* CreateNonClientFrameView(
186 views::Widget* widget) override {
187 FullSizeBubbleFrameView* frame = new FullSizeBubbleFrameView();
188 scoped_ptr<views::BubbleBorder> border(
189 new views::BubbleBorder(views::BubbleBorder::FLOAT,
190 views::BubbleBorder::SMALL_SHADOW,
192 border->set_use_theme_background_color(true);
193 frame->SetBubbleBorder(border.Pass());
197 const gfx::Size size_;
198 views::View* dialog_body_;
199 const base::Closure close_callback_;
201 DISALLOW_COPY_AND_ASSIGN(NativeDialogContainer);
206 views::DialogDelegateView* CreateAppListContainerForView(
208 const base::Closure& close_callback) {
209 return new AppListDialogContainer(view, close_callback);
212 views::DialogDelegateView* CreateDialogContainerForView(
214 const gfx::Size& size,
215 const base::Closure& close_callback) {
216 return new NativeDialogContainer(view, size, close_callback);