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/login/helper.h"
6
7#include "base/file_util.h"
8#include "chrome/browser/chromeos/cros/network_library.h"
9#include "chrome/browser/chromeos/system_access.h"
10#include "chrome/browser/google/google_util.h"
11#include "googleurl/src/gurl.h"
12#include "grit/generated_resources.h"
13#include "grit/theme_resources.h"
14#include "third_party/skia/include/effects/SkGradientShader.h"
15#include "ui/base/l10n/l10n_util.h"
16#include "ui/base/resource/resource_bundle.h"
17#include "ui/gfx/canvas_skia.h"
18#include "views/controls/button/menu_button.h"
19#include "views/controls/button/native_button.h"
20#include "views/controls/label.h"
21#include "views/controls/textfield/textfield.h"
22#include "views/controls/throbber.h"
23#include "views/painter.h"
24#include "views/screen.h"
25#include "views/widget/widget.h"
26#include "views/widget/widget_gtk.h"
27
28namespace chromeos {
29
30namespace {
31
32// Time in ms per throbber frame.
33const int kThrobberFrameMs = 60;
34
35// Time in ms before smoothed throbber is shown.
36const int kThrobberStartDelayMs = 500;
37
38const SkColor kBackgroundCenterColor = SkColorSetRGB(41, 50, 67);
39const SkColor kBackgroundEdgeColor = SK_ColorBLACK;
40
41const char kAccountRecoveryHelpUrl[] =
42    "https://www.google.com/support/accounts/bin/answer.py?answer=48598";
43
44class BackgroundPainter : public views::Painter {
45 public:
46  BackgroundPainter() {}
47
48  virtual void Paint(int w, int h, gfx::Canvas* canvas) {
49    SkRect rect;
50    rect.set(SkIntToScalar(0),
51             SkIntToScalar(0),
52             SkIntToScalar(w),
53             SkIntToScalar(h));
54    SkPaint paint;
55    paint.setStyle(SkPaint::kFill_Style);
56    paint.setFlags(SkPaint::kAntiAlias_Flag);
57    SkColor colors[2] = { kBackgroundCenterColor, kBackgroundEdgeColor };
58    SkShader* s = SkGradientShader::CreateRadial(
59        SkPoint::Make(SkIntToScalar(w / 2), SkIntToScalar(h / 2)),
60        SkIntToScalar(w / 2),
61        colors,
62        NULL,
63        2,
64        SkShader::kClamp_TileMode,
65        NULL);
66    paint.setShader(s);
67    s->unref();
68    canvas->AsCanvasSkia()->drawRect(rect, paint);
69  }
70
71 private:
72  DISALLOW_COPY_AND_ASSIGN(BackgroundPainter);
73};
74
75}  // namespace
76
77ThrobberHostView::ThrobberHostView()
78    : host_view_(this),
79      throbber_widget_(NULL) {
80}
81
82ThrobberHostView::~ThrobberHostView() {
83  StopThrobber();
84}
85
86void ThrobberHostView::StartThrobber() {
87  StopThrobber();
88
89  views::Widget* host_widget = host_view_->GetWidget();
90  if (!host_widget) {
91    LOG(WARNING) << "Failed to start the throbber: no Widget";
92    return;
93  }
94
95  GtkWidget* host_gtk_window = host_widget->GetNativeView();
96  while (host_gtk_window && !GTK_IS_WINDOW(host_gtk_window))
97    host_gtk_window = gtk_widget_get_parent(host_gtk_window);
98  if (!host_gtk_window) {
99    LOG(WARNING) << "Failed to start the throbber: no GtkWindow";
100    return;
101  }
102
103  views::SmoothedThrobber* throbber = CreateDefaultSmoothedThrobber();
104  throbber->set_stop_delay_ms(0);
105  gfx::Rect throbber_bounds = CalculateThrobberBounds(throbber);
106
107  views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP);
108  params.transparent = true;
109  throbber_widget_ = views::Widget::CreateWidget(params);
110  static_cast<views::WidgetGtk*>(throbber_widget_)->make_transient_to_parent();
111
112  throbber_bounds.Offset(host_view_->GetScreenBounds().origin());
113  throbber_widget_->Init(host_gtk_window, throbber_bounds);
114  throbber_widget_->SetContentsView(throbber);
115  // This keeps the window from flashing at startup.
116  gdk_window_set_back_pixmap(
117      throbber_widget_->GetNativeView()->window, NULL, false);
118  throbber_widget_->Show();
119  // WM can ignore bounds before widget is shown.
120  throbber_widget_->SetBounds(throbber_bounds);
121  throbber->Start();
122}
123
124void ThrobberHostView::StopThrobber() {
125  if (throbber_widget_) {
126    throbber_widget_->Close();
127    throbber_widget_ = NULL;
128  }
129}
130
131gfx::Rect ThrobberHostView::CalculateThrobberBounds(views::Throbber* throbber) {
132  gfx::Rect bounds(throbber->GetPreferredSize());
133  bounds.set_x(
134      host_view_->width() - login::kThrobberRightMargin - bounds.width());
135  bounds.set_y((host_view_->height() - bounds.height()) / 2);
136  return bounds;
137}
138
139views::SmoothedThrobber* CreateDefaultSmoothedThrobber() {
140  views::SmoothedThrobber* throbber =
141      new views::SmoothedThrobber(kThrobberFrameMs);
142  throbber->SetFrames(
143      ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_SPINNER));
144  throbber->set_start_delay_ms(kThrobberStartDelayMs);
145  return throbber;
146}
147
148views::Throbber* CreateDefaultThrobber() {
149  views::Throbber* throbber = new views::Throbber(kThrobberFrameMs, false);
150  throbber->SetFrames(
151      ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_SPINNER));
152  return throbber;
153}
154
155views::Painter* CreateBackgroundPainter() {
156  return new BackgroundPainter();
157}
158
159gfx::Rect CalculateScreenBounds(const gfx::Size& size) {
160  gfx::Rect bounds(views::Screen::GetMonitorWorkAreaNearestWindow(NULL));
161  if (!size.IsEmpty()) {
162    int horizontal_diff = bounds.width() - size.width();
163    int vertical_diff = bounds.height() - size.height();
164    bounds.Inset(horizontal_diff / 2, vertical_diff / 2);
165  }
166  return bounds;
167}
168
169void CorrectLabelFontSize(views::Label* label) {
170  if (label)
171    label->SetFont(label->font().DeriveFont(kFontSizeCorrectionDelta));
172}
173
174void CorrectMenuButtonFontSize(views::MenuButton* button) {
175  if (button)
176    button->SetFont(button->font().DeriveFont(kFontSizeCorrectionDelta));
177}
178
179void CorrectNativeButtonFontSize(views::NativeButton* button) {
180  if (button)
181    button->set_font(button->font().DeriveFont(kFontSizeCorrectionDelta));
182}
183
184void CorrectTextfieldFontSize(views::Textfield* textfield) {
185  if (textfield)
186    textfield->SetFont(textfield->font().DeriveFont(kFontSizeCorrectionDelta));
187}
188
189void SetAndCorrectTextfieldFont(views::Textfield* textfield,
190                                const gfx::Font& font) {
191  if (textfield)
192    textfield->SetFont(font.DeriveFont(kFontSizeCorrectionDelta));
193}
194
195GURL GetAccountRecoveryHelpUrl() {
196  return google_util::AppendGoogleLocaleParam(GURL(kAccountRecoveryHelpUrl));
197}
198
199string16 GetCurrentNetworkName(NetworkLibrary* network_library) {
200  if (!network_library)
201    return string16();
202
203  if (network_library->ethernet_connected()) {
204    return l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
205  } else if (network_library->wifi_connected()) {
206    return UTF8ToUTF16(network_library->wifi_network()->name());
207  } else if (network_library->cellular_connected()) {
208    return UTF8ToUTF16(network_library->cellular_network()->name());
209  } else if (network_library->ethernet_connecting()) {
210    return l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
211  } else if (network_library->wifi_connecting()) {
212    return UTF8ToUTF16(network_library->wifi_network()->name());
213  } else if (network_library->cellular_connecting()) {
214    return UTF8ToUTF16(network_library->cellular_network()->name());
215  } else {
216    return string16();
217  }
218}
219
220namespace login {
221
222gfx::Size WideButton::GetPreferredSize() {
223  gfx::Size preferred_size = NativeButton::GetPreferredSize();
224  // Set minimal width.
225  if (preferred_size.width() < kButtonMinWidth)
226    preferred_size.set_width(kButtonMinWidth);
227  return preferred_size;
228}
229
230}  // namespace login
231
232}  // namespace chromeos
233