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 "chrome/browser/chromeos/frame/bubble_frame_view.h" 6 7 #include "chrome/browser/chromeos/frame/bubble_window.h" 8 #include "chrome/browser/chromeos/login/helper.h" 9 #include "chrome/browser/ui/views/bubble/bubble_border.h" 10 #include "grit/theme_resources.h" 11 #include "ui/base/resource/resource_bundle.h" 12 #include "ui/gfx/canvas_skia.h" 13 #include "ui/gfx/font.h" 14 #include "ui/gfx/insets.h" 15 #include "ui/gfx/path.h" 16 #include "ui/gfx/rect.h" 17 #include "views/controls/button/image_button.h" 18 #include "views/controls/label.h" 19 #include "views/controls/throbber.h" 20 #include "views/window/hit_test.h" 21 #include "views/window/window.h" 22 #include "views/window/window_delegate.h" 23 #include "third_party/skia/include/core/SkPaint.h" 24 25 namespace { 26 27 static const int kTitleTopPadding = 10; 28 static const int kTitleContentPadding = 10; 29 static const int kHorizontalPadding = 10; 30 31 // Title font size correction. 32 #if defined(CROS_FONTS_USING_BCI) 33 static const int kTitleFontSizeDelta = 0; 34 #else 35 static const int kTitleFontSizeDelta = 1; 36 #endif 37 38 } // namespace 39 40 namespace chromeos { 41 42 BubbleFrameView::BubbleFrameView(views::Window* frame, 43 BubbleWindow::Style style) 44 : frame_(frame), 45 style_(style), 46 title_(NULL), 47 close_button_(NULL), 48 throbber_(NULL) { 49 set_border(new BubbleBorder(BubbleBorder::NONE)); 50 51 if (frame_->window_delegate()->ShouldShowWindowTitle()) { 52 title_ = new views::Label(frame_->window_delegate()->GetWindowTitle()); 53 title_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 54 title_->SetFont(title_->font().DeriveFont(kFontSizeCorrectionDelta, 55 gfx::Font::BOLD)); 56 AddChildView(title_); 57 } 58 59 if (style_ & BubbleWindow::STYLE_XBAR) { 60 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 61 close_button_ = new views::ImageButton(this); 62 close_button_->SetImage(views::CustomButton::BS_NORMAL, 63 rb.GetBitmapNamed(IDR_CLOSE_BAR)); 64 close_button_->SetImage(views::CustomButton::BS_HOT, 65 rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); 66 close_button_->SetImage(views::CustomButton::BS_PUSHED, 67 rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); 68 AddChildView(close_button_); 69 } 70 71 if (style_ & BubbleWindow::STYLE_THROBBER) { 72 throbber_ = CreateDefaultSmoothedThrobber(); 73 AddChildView(throbber_); 74 } 75 } 76 77 BubbleFrameView::~BubbleFrameView() { 78 } 79 80 void BubbleFrameView::StartThrobber() { 81 DCHECK(throbber_ != NULL); 82 if (title_) 83 title_->SetText(std::wstring()); 84 throbber_->Start(); 85 } 86 87 void BubbleFrameView::StopThrobber() { 88 DCHECK(throbber_ != NULL); 89 throbber_->Stop(); 90 if (title_) 91 title_->SetText(frame_->window_delegate()->GetWindowTitle()); 92 } 93 94 gfx::Rect BubbleFrameView::GetBoundsForClientView() const { 95 return client_view_bounds_; 96 } 97 98 gfx::Rect BubbleFrameView::GetWindowBoundsForClientBounds( 99 const gfx::Rect& client_bounds) const { 100 gfx::Insets insets = GetInsets(); 101 102 gfx::Size title_size; 103 if (title_) 104 title_size = title_->GetPreferredSize(); 105 gfx::Size close_button_size; 106 if (close_button_) 107 close_button_size = close_button_->GetPreferredSize(); 108 gfx::Size throbber_size; 109 if (throbber_) 110 throbber_size = throbber_->GetPreferredSize(); 111 112 int top_height = insets.top(); 113 if (title_size.height() > 0 || 114 close_button_size.height() > 0 || 115 throbber_size.height() > 0) { 116 top_height += kTitleContentPadding + std::max( 117 std::max(title_size.height(), close_button_size.height()), 118 throbber_size.height()); 119 } 120 return gfx::Rect(std::max(0, client_bounds.x() - insets.left()), 121 std::max(0, client_bounds.y() - top_height), 122 client_bounds.width() + insets.width(), 123 client_bounds.height() + top_height + insets.bottom()); 124 } 125 126 int BubbleFrameView::NonClientHitTest(const gfx::Point& point) { 127 return HTNOWHERE; 128 } 129 130 void BubbleFrameView::GetWindowMask(const gfx::Size& size, 131 gfx::Path* window_mask) { 132 } 133 134 void BubbleFrameView::EnableClose(bool enable) { 135 } 136 137 void BubbleFrameView::ResetWindowControls() { 138 } 139 140 void BubbleFrameView::UpdateWindowIcon() { 141 } 142 143 gfx::Insets BubbleFrameView::GetInsets() const { 144 gfx::Insets border_insets; 145 border()->GetInsets(&border_insets); 146 147 gfx::Insets insets(kTitleTopPadding, 148 kHorizontalPadding, 149 0, 150 kHorizontalPadding); 151 insets += border_insets; 152 return insets; 153 } 154 155 gfx::Size BubbleFrameView::GetPreferredSize() { 156 gfx::Size pref = frame_->client_view()->GetPreferredSize(); 157 gfx::Rect bounds(0, 0, pref.width(), pref.height()); 158 return frame_->non_client_view()->GetWindowBoundsForClientBounds( 159 bounds).size(); 160 } 161 162 void BubbleFrameView::Layout() { 163 gfx::Insets insets = GetInsets(); 164 165 gfx::Size title_size; 166 if (title_) 167 title_size = title_->GetPreferredSize(); 168 gfx::Size close_button_size; 169 if (close_button_) 170 close_button_size = close_button_->GetPreferredSize(); 171 gfx::Size throbber_size; 172 if (throbber_) 173 throbber_size = throbber_->GetPreferredSize(); 174 175 if (title_) { 176 title_->SetBounds( 177 insets.left(), insets.top(), 178 std::max(0, width() - insets.width() - close_button_size.width()), 179 title_size.height()); 180 } 181 182 if (close_button_) { 183 close_button_->SetBounds( 184 width() - insets.right() - close_button_size.width(), insets.top(), 185 close_button_size.width(), close_button_size.height()); 186 } 187 188 if (throbber_) { 189 throbber_->SetBounds( 190 insets.left(), insets.top(), 191 std::min(throbber_size.width(), width()), 192 throbber_size.height()); 193 } 194 195 int top_height = insets.top(); 196 if (title_size.height() > 0 || 197 close_button_size.height() > 0 || 198 throbber_size.height() > 0) { 199 top_height += kTitleContentPadding + std::max( 200 std::max(title_size.height(), close_button_size.height()), 201 throbber_size.height()); 202 } 203 client_view_bounds_.SetRect(insets.left(), top_height, 204 std::max(0, width() - insets.width()), 205 std::max(0, height() - top_height - insets.bottom())); 206 } 207 208 void BubbleFrameView::OnPaint(gfx::Canvas* canvas) { 209 // The border of this view creates an anti-aliased round-rect region for the 210 // contents, which we need to fill with the background color. 211 SkPaint paint; 212 paint.setAntiAlias(true); 213 paint.setStyle(SkPaint::kFill_Style); 214 paint.setColor(BubbleWindow::kBackgroundColor); 215 gfx::Path path; 216 gfx::Rect bounds(GetContentsBounds()); 217 SkRect rect; 218 rect.set(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()), 219 SkIntToScalar(bounds.right()), SkIntToScalar(bounds.bottom())); 220 SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius()); 221 path.addRoundRect(rect, radius, radius); 222 canvas->AsCanvasSkia()->drawPath(path, paint); 223 224 OnPaintBorder(canvas); 225 } 226 227 void BubbleFrameView::ButtonPressed(views::Button* sender, 228 const views::Event& event) { 229 if (close_button_ != NULL && sender == close_button_) 230 frame_->CloseWindow(); 231 } 232 233 } // namespace chromeos 234