| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "ash/common/popup_message.h" | |
| 6 | |
| 7 #include "ash/common/wm_lookup.h" | |
| 8 #include "ash/common/wm_window.h" | |
| 9 #include "grit/ash_resources.h" | |
| 10 #include "ui/base/resource/resource_bundle.h" | |
| 11 #include "ui/gfx/geometry/insets.h" | |
| 12 #include "ui/views/bubble/bubble_dialog_delegate.h" | |
| 13 #include "ui/views/bubble/bubble_frame_view.h" | |
| 14 #include "ui/views/controls/image_view.h" | |
| 15 #include "ui/views/controls/label.h" | |
| 16 #include "ui/views/layout/box_layout.h" | |
| 17 #include "ui/views/widget/widget.h" | |
| 18 #include "ui/wm/core/window_animations.h" | |
| 19 | |
| 20 namespace ash { | |
| 21 namespace { | |
| 22 const int kMessageTopBottomMargin = 10; | |
| 23 const int kMessageLeftRightMargin = 10; | |
| 24 const int kMessageMinHeight = 29 - 2 * kMessageTopBottomMargin; | |
| 25 const SkColor kMessageTextColor = SkColorSetRGB(0x22, 0x22, 0x22); | |
| 26 | |
| 27 // The maximum width of the Message bubble. Borrowed the value from | |
| 28 // ash/message/message_controller.cc | |
| 29 const int kMessageMaxWidth = 250; | |
| 30 | |
| 31 // The offset for the Message bubble - making sure that the bubble is flush | |
| 32 // with the shelf. The offset includes the arrow size in pixels as well as | |
| 33 // the activation bar and other spacing elements. | |
| 34 const int kArrowOffsetLeftRight = 11; | |
| 35 const int kArrowOffsetTopBottom = 7; | |
| 36 | |
| 37 // The number of pixels between the icon and the text. | |
| 38 const int kHorizontalPopupPaddingBetweenItems = 10; | |
| 39 | |
| 40 // The number of pixels between the text items. | |
| 41 const int kVerticalPopupPaddingBetweenItems = 10; | |
| 42 } // namespace | |
| 43 | |
| 44 // The implementation of Message of the launcher. | |
| 45 class PopupMessage::MessageBubble : public views::BubbleDialogDelegateView { | |
| 46 public: | |
| 47 MessageBubble(const base::string16& caption, | |
| 48 const base::string16& message, | |
| 49 IconType message_type, | |
| 50 views::View* anchor, | |
| 51 views::BubbleBorder::Arrow arrow_orientation, | |
| 52 const gfx::Size& size_override, | |
| 53 int arrow_offset); | |
| 54 | |
| 55 void ClosePopup(); | |
| 56 | |
| 57 private: | |
| 58 // views::BubbleDialogDelegateView overrides: | |
| 59 gfx::Size GetPreferredSize() const override; | |
| 60 int GetDialogButtons() const override; | |
| 61 | |
| 62 // Each component (width/height) can force a size override for that component | |
| 63 // if not 0. | |
| 64 gfx::Size size_override_; | |
| 65 | |
| 66 DISALLOW_COPY_AND_ASSIGN(MessageBubble); | |
| 67 }; | |
| 68 | |
| 69 // static | |
| 70 const int PopupMessage::kCaptionLabelID = 1000; | |
| 71 const int PopupMessage::kMessageLabelID = 1001; | |
| 72 | |
| 73 PopupMessage::MessageBubble::MessageBubble(const base::string16& caption, | |
| 74 const base::string16& message, | |
| 75 IconType message_type, | |
| 76 views::View* anchor, | |
| 77 views::BubbleBorder::Arrow arrow, | |
| 78 const gfx::Size& size_override, | |
| 79 int arrow_offset) | |
| 80 : views::BubbleDialogDelegateView(anchor, arrow), | |
| 81 size_override_(size_override) { | |
| 82 gfx::Insets insets = | |
| 83 gfx::Insets(kArrowOffsetTopBottom, kArrowOffsetLeftRight, | |
| 84 kArrowOffsetTopBottom, kArrowOffsetLeftRight); | |
| 85 // An anchor can have an asymmetrical border for spacing reasons. Adjust the | |
| 86 // anchor location for this. | |
| 87 if (anchor->border()) | |
| 88 insets += anchor->border()->GetInsets(); | |
| 89 | |
| 90 set_anchor_view_insets(insets); | |
| 91 set_close_on_deactivate(false); | |
| 92 set_can_activate(false); | |
| 93 set_accept_events(false); | |
| 94 | |
| 95 set_margins(gfx::Insets(kMessageTopBottomMargin, kMessageLeftRightMargin, | |
| 96 kMessageTopBottomMargin, kMessageLeftRightMargin)); | |
| 97 set_shadow(views::BubbleBorder::SMALL_SHADOW); | |
| 98 | |
| 99 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
| 100 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, | |
| 101 kHorizontalPopupPaddingBetweenItems)); | |
| 102 | |
| 103 // Here is the layout: | |
| 104 // arrow_offset (if not 0) | |
| 105 // |-------------| | |
| 106 // | ^ | |
| 107 // +-------------------------------------------------+ | |
| 108 // -| |- | |
| 109 // icon | [!] Caption in bold which can be multi line | caption_label | |
| 110 // -| |- | |
| 111 // | Message text which can be multi line | message_label | |
| 112 // | as well. | | |
| 113 // | |- | |
| 114 // +-------------------------------------------------+ | |
| 115 // |------------details container--------------| | |
| 116 // Note that the icon, caption and message are optional. | |
| 117 | |
| 118 // Add the icon to the first column (if there is one). | |
| 119 if (message_type != ICON_NONE) { | |
| 120 views::ImageView* icon = new views::ImageView(); | |
| 121 icon->SetImage(bundle.GetImageNamed(IDR_AURA_WARNING_ICON).ToImageSkia()); | |
| 122 icon->SetVerticalAlignment(views::ImageView::LEADING); | |
| 123 AddChildView(icon); | |
| 124 } | |
| 125 | |
| 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)); | |
| 131 | |
| 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); | |
| 142 } | |
| 143 | |
| 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); | |
| 152 } | |
| 153 views::BubbleDialogDelegateView::CreateBubble(this); | |
| 154 | |
| 155 // Change the arrow offset if needed. | |
| 156 if (arrow_offset) { | |
| 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); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 void PopupMessage::MessageBubble::ClosePopup() { | |
| 168 if (GetWidget()) | |
| 169 GetWidget()->Close(); | |
| 170 } | |
| 171 | |
| 172 gfx::Size PopupMessage::MessageBubble::GetPreferredSize() const { | |
| 173 gfx::Size pref_size = views::BubbleDialogDelegateView::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); | |
| 180 | |
| 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); | |
| 185 | |
| 186 return pref_size; | |
| 187 } | |
| 188 | |
| 189 int PopupMessage::MessageBubble::GetDialogButtons() const { | |
| 190 return ui::DIALOG_BUTTON_NONE; | |
| 191 } | |
| 192 | |
| 193 PopupMessage::PopupMessage(const base::string16& caption, | |
| 194 const base::string16& message, | |
| 195 IconType message_type, | |
| 196 views::View* anchor, | |
| 197 views::BubbleBorder::Arrow arrow, | |
| 198 const gfx::Size& size_override, | |
| 199 int arrow_offset) | |
| 200 : view_(NULL) { | |
| 201 view_ = new MessageBubble(caption, message, message_type, anchor, arrow, | |
| 202 size_override, arrow_offset); | |
| 203 widget_ = view_->GetWidget(); | |
| 204 WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_); | |
| 205 window->SetVisibilityAnimationType( | |
| 206 ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); | |
| 207 window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE); | |
| 208 view_->GetWidget()->Show(); | |
| 209 } | |
| 210 | |
| 211 PopupMessage::~PopupMessage() { | |
| 212 CancelHidingAnimation(); | |
| 213 Close(); | |
| 214 } | |
| 215 | |
| 216 void PopupMessage::Close() { | |
| 217 if (view_) { | |
| 218 view_->ClosePopup(); | |
| 219 view_ = NULL; | |
| 220 widget_ = NULL; | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void PopupMessage::CancelHidingAnimation() { | |
| 225 if (!widget_) | |
| 226 return; | |
| 227 | |
| 228 WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_); | |
| 229 if (window) | |
| 230 window->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); | |
| 231 } | |
| 232 | |
| 233 } // namespace ash | |
| OLD | NEW |