bubble_frame_view.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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_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
25namespace {
26
27static const int kTitleTopPadding = 10;
28static const int kTitleContentPadding = 10;
29static const int kHorizontalPadding = 10;
30
31// Title font size correction.
32#if defined(CROS_FONTS_USING_BCI)
33static const int kTitleFontSizeDelta = 0;
34#else
35static const int kTitleFontSizeDelta = 1;
36#endif
37
38}  // namespace
39
40namespace chromeos {
41
42BubbleFrameView::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_->GetDelegate()->ShouldShowWindowTitle()) {
52    title_ = new views::Label(frame_->GetDelegate()->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
77BubbleFrameView::~BubbleFrameView() {
78}
79
80void BubbleFrameView::StartThrobber() {
81  DCHECK(throbber_ != NULL);
82  if (title_)
83    title_->SetText(std::wstring());
84  throbber_->Start();
85}
86
87void BubbleFrameView::StopThrobber() {
88  DCHECK(throbber_ != NULL);
89  throbber_->Stop();
90  if (title_)
91    title_->SetText(frame_->GetDelegate()->GetWindowTitle());
92}
93
94gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
95  return client_view_bounds_;
96}
97
98gfx::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
126int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
127  return HTNOWHERE;
128}
129
130void BubbleFrameView::GetWindowMask(const gfx::Size& size,
131                                    gfx::Path* window_mask) {
132}
133
134void BubbleFrameView::EnableClose(bool enable) {
135}
136
137void BubbleFrameView::ResetWindowControls() {
138}
139
140gfx::Insets BubbleFrameView::GetInsets() const {
141  gfx::Insets border_insets;
142  border()->GetInsets(&border_insets);
143
144  gfx::Insets insets(kTitleTopPadding,
145                     kHorizontalPadding,
146                     0,
147                     kHorizontalPadding);
148  insets += border_insets;
149  return insets;
150}
151
152gfx::Size BubbleFrameView::GetPreferredSize() {
153  gfx::Size pref = frame_->GetClientView()->GetPreferredSize();
154  gfx::Rect bounds(0, 0, pref.width(), pref.height());
155  return frame_->GetNonClientView()->GetWindowBoundsForClientBounds(
156      bounds).size();
157}
158
159void BubbleFrameView::Layout() {
160  gfx::Insets insets = GetInsets();
161
162  gfx::Size title_size;
163  if (title_)
164    title_size = title_->GetPreferredSize();
165  gfx::Size close_button_size;
166  if (close_button_)
167    close_button_size = close_button_->GetPreferredSize();
168  gfx::Size throbber_size;
169  if (throbber_)
170    throbber_size = throbber_->GetPreferredSize();
171
172  if (title_) {
173    title_->SetBounds(
174        insets.left(), insets.top(),
175        std::max(0, width() - insets.width() - close_button_size.width()),
176        title_size.height());
177  }
178
179  if (close_button_) {
180    close_button_->SetBounds(
181        width() - insets.right() - close_button_size.width(), insets.top(),
182        close_button_size.width(), close_button_size.height());
183  }
184
185  if (throbber_) {
186    throbber_->SetBounds(
187        insets.left(), insets.top(),
188        std::min(throbber_size.width(), width()),
189        throbber_size.height());
190  }
191
192  int top_height = insets.top();
193  if (title_size.height() > 0 ||
194      close_button_size.height() > 0 ||
195      throbber_size.height() > 0) {
196    top_height += kTitleContentPadding + std::max(
197        std::max(title_size.height(), close_button_size.height()),
198        throbber_size.height());
199  }
200  client_view_bounds_.SetRect(insets.left(), top_height,
201      std::max(0, width() - insets.width()),
202      std::max(0, height() - top_height - insets.bottom()));
203}
204
205void BubbleFrameView::Paint(gfx::Canvas* canvas) {
206  // The border of this view creates an anti-aliased round-rect region for the
207  // contents, which we need to fill with the background color.
208  SkPaint paint;
209  paint.setAntiAlias(true);
210  paint.setStyle(SkPaint::kFill_Style);
211  paint.setColor(BubbleWindow::kBackgroundColor);
212  gfx::Path path;
213  gfx::Rect bounds(GetContentsBounds());
214  SkRect rect;
215  rect.set(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()),
216           SkIntToScalar(bounds.right()), SkIntToScalar(bounds.bottom()));
217  SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
218  path.addRoundRect(rect, radius, radius);
219  canvas->AsCanvasSkia()->drawPath(path, paint);
220
221  PaintBorder(canvas);
222}
223
224void BubbleFrameView::ButtonPressed(views::Button* sender,
225                                    const views::Event& event) {
226  if (close_button_ != NULL && sender == close_button_)
227    frame_->Close();
228}
229
230}  // namespace chromeos
231