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
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_->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
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_->window_delegate()->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
140void BubbleFrameView::UpdateWindowIcon() {
141}
142
143gfx::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
155gfx::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
162void 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
208void 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
227void 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