1 // Copyright (c) 2013 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 "ash/popup_message.h"
7 #include "ash/wm/window_animations.h"
8 #include "grit/ash_resources.h"
9 #include "ui/base/resource/resource_bundle.h"
10 #include "ui/gfx/geometry/insets.h"
11 #include "ui/views/bubble/bubble_delegate.h"
12 #include "ui/views/bubble/bubble_frame_view.h"
13 #include "ui/views/controls/image_view.h"
14 #include "ui/views/controls/label.h"
15 #include "ui/views/layout/box_layout.h"
16 #include "ui/views/widget/widget.h"
20 const int kMessageTopBottomMargin
= 10;
21 const int kMessageLeftRightMargin
= 10;
22 const int kMessageMinHeight
= 29 - 2 * kMessageTopBottomMargin
;
23 const SkColor kMessageTextColor
= SkColorSetRGB(0x22, 0x22, 0x22);
25 // The maximum width of the Message bubble. Borrowed the value from
26 // ash/message/message_controller.cc
27 const int kMessageMaxWidth
= 250;
29 // The offset for the Message bubble - making sure that the bubble is flush
30 // with the shelf. The offset includes the arrow size in pixels as well as
31 // the activation bar and other spacing elements.
32 const int kArrowOffsetLeftRight
= 11;
33 const int kArrowOffsetTopBottom
= 7;
35 // The number of pixels between the icon and the text.
36 const int kHorizontalPopupPaddingBetweenItems
= 10;
38 // The number of pixels between the text items.
39 const int kVerticalPopupPaddingBetweenItems
= 10;
42 // The implementation of Message of the launcher.
43 class PopupMessage::MessageBubble
: public views::BubbleDelegateView
{
45 MessageBubble(const base::string16
& caption
,
46 const base::string16
& message
,
47 IconType message_type
,
49 views::BubbleBorder::Arrow arrow_orientation
,
50 const gfx::Size
& size_override
,
56 // views::View overrides:
57 gfx::Size
GetPreferredSize() const override
;
59 // Each component (width/height) can force a size override for that component
61 gfx::Size size_override_
;
63 DISALLOW_COPY_AND_ASSIGN(MessageBubble
);
67 const int PopupMessage::kCaptionLabelID
= 1000;
68 const int PopupMessage::kMessageLabelID
= 1001;
70 PopupMessage::MessageBubble::MessageBubble(const base::string16
& caption
,
71 const base::string16
& message
,
72 IconType message_type
,
74 views::BubbleBorder::Arrow arrow
,
75 const gfx::Size
& size_override
,
77 : views::BubbleDelegateView(anchor
, arrow
),
78 size_override_(size_override
) {
79 gfx::Insets insets
= gfx::Insets(kArrowOffsetTopBottom
,
80 kArrowOffsetLeftRight
,
81 kArrowOffsetTopBottom
,
82 kArrowOffsetLeftRight
);
83 // An anchor can have an asymmetrical border for spacing reasons. Adjust the
84 // anchor location for this.
86 insets
+= anchor
->border()->GetInsets();
88 set_anchor_view_insets(insets
);
89 set_close_on_esc(false);
90 set_close_on_deactivate(false);
91 set_can_activate(false);
92 set_accept_events(false);
94 set_margins(gfx::Insets(kMessageTopBottomMargin
, kMessageLeftRightMargin
,
95 kMessageTopBottomMargin
, kMessageLeftRightMargin
));
96 set_shadow(views::BubbleBorder::SMALL_SHADOW
);
98 ui::ResourceBundle
& bundle
= ui::ResourceBundle::GetSharedInstance();
99 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal
, 0, 0,
100 kHorizontalPopupPaddingBetweenItems
));
102 // Here is the layout:
103 // arrow_offset (if not 0)
106 // +-------------------------------------------------+
108 // icon | [!] Caption in bold which can be multi line | caption_label
110 // | Message text which can be multi line | message_label
113 // +-------------------------------------------------+
114 // |------------details container--------------|
115 // Note that the icon, caption and message are optional.
117 // Add the icon to the first column (if there is one).
118 if (message_type
!= ICON_NONE
) {
119 views::ImageView
* icon
= new views::ImageView();
121 bundle
.GetImageNamed(IDR_AURA_WARNING_ICON
).ToImageSkia());
122 icon
->SetVerticalAlignment(views::ImageView::LEADING
);
126 // Create a container for the text items and use it as second column.
127 views::View
* details
= new views::View();
128 AddChildView(details
);
129 details
->SetLayoutManager(new views::BoxLayout(
130 views::BoxLayout::kVertical
, 0, 0, kVerticalPopupPaddingBetweenItems
));
132 // The caption label.
133 if (!caption
.empty()) {
134 views::Label
* caption_label
= new views::Label(caption
);
135 caption_label
->set_id(kCaptionLabelID
);
136 caption_label
->SetMultiLine(true);
137 caption_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
138 caption_label
->SetFontList(
139 bundle
.GetFontList(ui::ResourceBundle::BoldFont
));
140 caption_label
->SetEnabledColor(kMessageTextColor
);
141 details
->AddChildView(caption_label
);
144 // The message label.
145 if (!message
.empty()) {
146 views::Label
* message_label
= new views::Label(message
);
147 message_label
->set_id(kMessageLabelID
);
148 message_label
->SetMultiLine(true);
149 message_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
150 message_label
->SetEnabledColor(kMessageTextColor
);
151 details
->AddChildView(message_label
);
153 views::BubbleDelegateView::CreateBubble(this);
155 // Change the arrow offset if needed.
157 // With the creation of the bubble, the bubble got already placed (and
158 // possibly re-oriented to fit on the screen). Since it is not possible to
159 // set the arrow offset before the creation, we need to set the offset,
160 // and the orientation variables again and force a re-placement.
161 GetBubbleFrameView()->bubble_border()->set_arrow_offset(arrow_offset
);
162 GetBubbleFrameView()->bubble_border()->set_arrow(arrow
);
163 SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR
);
167 void PopupMessage::MessageBubble::Close() {
169 GetWidget()->Close();
172 gfx::Size
PopupMessage::MessageBubble::GetPreferredSize() const {
173 gfx::Size pref_size
= views::BubbleDelegateView::GetPreferredSize();
174 // Override the size with either the provided size or adjust it to not
175 // violate our minimum / maximum sizes.
176 if (size_override_
.height())
177 pref_size
.set_height(size_override_
.height());
178 else if (pref_size
.height() < kMessageMinHeight
)
179 pref_size
.set_height(kMessageMinHeight
);
181 if (size_override_
.width())
182 pref_size
.set_width(size_override_
.width());
183 else if (pref_size
.width() > kMessageMaxWidth
)
184 pref_size
.set_width(kMessageMaxWidth
);
189 PopupMessage::PopupMessage(const base::string16
& caption
,
190 const base::string16
& message
,
191 IconType message_type
,
193 views::BubbleBorder::Arrow arrow
,
194 const gfx::Size
& size_override
,
197 view_
= new MessageBubble(
198 caption
, message
, message_type
, anchor
, arrow
, size_override
,
200 widget_
= view_
->GetWidget();
202 gfx::NativeView native_view
= widget_
->GetNativeView();
203 wm::SetWindowVisibilityAnimationType(
204 native_view
, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL
);
205 wm::SetWindowVisibilityAnimationTransition(
206 native_view
, wm::ANIMATE_HIDE
);
207 view_
->GetWidget()->Show();
210 PopupMessage::~PopupMessage() {
211 CancelHidingAnimation();
215 void PopupMessage::Close() {
223 void PopupMessage::CancelHidingAnimation() {
224 if (!widget_
|| !widget_
->GetNativeView())
227 gfx::NativeView native_view
= widget_
->GetNativeView();
228 wm::SetWindowVisibilityAnimationTransition(
229 native_view
, wm::ANIMATE_NONE
);