Home | History | Annotate | Download | only in login
      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/take_photo_view.h"
      6 
      7 #include "base/utf_string_conversions.h"
      8 #include "chrome/browser/chromeos/login/helper.h"
      9 #include "grit/generated_resources.h"
     10 #include "grit/theme_resources.h"
     11 #include "skia/ext/image_operations.h"
     12 #include "ui/base/l10n/l10n_util.h"
     13 #include "ui/base/resource/resource_bundle.h"
     14 #include "ui/gfx/canvas.h"
     15 #include "views/background.h"
     16 #include "views/border.h"
     17 #include "views/controls/button/image_button.h"
     18 #include "views/controls/image_view.h"
     19 #include "views/controls/label.h"
     20 #include "views/controls/throbber.h"
     21 #include "views/layout/grid_layout.h"
     22 
     23 namespace {
     24 
     25 // Padding between horizontally neighboring elements.
     26 const int kHorizontalPadding = 10;
     27 // Padding between vertically neighboring elements.
     28 const int kVerticalPadding = 10;
     29 // Color of image view border.
     30 const SkColor kImageBorderColor = SkColorSetARGB(38, 0, 0, 0);
     31 
     32 // IDs of column sets for grid layout manager.
     33 enum ColumnSets {
     34   kTitleRow,    // Column set for screen title.
     35   kImageRow,    // Column set for image from camera and snapshot button.
     36 };
     37 
     38 }  // namespace
     39 
     40 namespace chromeos {
     41 
     42 // Image view that can show center throbber above itself or a message at its
     43 // bottom.
     44 class CameraImageView : public views::ImageView {
     45  public:
     46   CameraImageView()
     47       : throbber_(NULL),
     48         message_(NULL) {}
     49 
     50   ~CameraImageView() {}
     51 
     52   void Init() {
     53     DCHECK(NULL == throbber_);
     54     DCHECK(NULL == message_);
     55 
     56     set_border(views::Border::CreateSolidBorder(1, kImageBorderColor));
     57     set_background(views::Background::CreateSolidBackground(SK_ColorWHITE));
     58 
     59     throbber_ = CreateDefaultSmoothedThrobber();
     60     throbber_->SetVisible(false);
     61     AddChildView(throbber_);
     62 
     63     message_ = new views::Label();
     64     message_->SetMultiLine(true);
     65     message_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
     66     message_->SetVisible(false);
     67     CorrectLabelFontSize(message_);
     68     AddChildView(message_);
     69   }
     70 
     71   void SetInitializingState() {
     72     ShowThrobber();
     73     SetMessage(std::wstring());
     74     SetImage(
     75         ResourceBundle::GetSharedInstance().GetBitmapNamed(
     76             IDR_USER_IMAGE_INITIALIZING));
     77   }
     78 
     79   void SetNormalState() {
     80     HideThrobber();
     81     SetMessage(std::wstring());
     82   }
     83 
     84   void SetErrorState() {
     85     HideThrobber();
     86     SetMessage(UTF16ToWide(l10n_util::GetStringUTF16(IDS_USER_IMAGE_NO_VIDEO)));
     87     SetImage(
     88         ResourceBundle::GetSharedInstance().GetBitmapNamed(
     89             IDR_USER_IMAGE_NO_VIDEO));
     90   }
     91 
     92  private:
     93   void ShowThrobber() {
     94     DCHECK(throbber_);
     95     throbber_->SetVisible(true);
     96     throbber_->Start();
     97   }
     98 
     99   void HideThrobber() {
    100     DCHECK(throbber_);
    101     throbber_->Stop();
    102     throbber_->SetVisible(false);
    103   }
    104 
    105   void SetMessage(const std::wstring& message) {
    106     DCHECK(message_);
    107     message_->SetText(message);
    108     message_->SetVisible(!message.empty());
    109     Layout();
    110   }
    111 
    112   // views::View override:
    113   virtual void Layout() {
    114     gfx::Size size = GetPreferredSize();
    115     if (throbber_->IsVisible()) {
    116       gfx::Size throbber_size = throbber_->GetPreferredSize();
    117       int throbber_x = (size.width() - throbber_size.width()) / 2;
    118       int throbber_y = (size.height() - throbber_size.height()) / 2;
    119       throbber_->SetBounds(throbber_x,
    120                            throbber_y,
    121                            throbber_size.width(),
    122                            throbber_size.height());
    123     }
    124     if (message_->IsVisible()) {
    125       message_->SizeToFit(size.width() - kHorizontalPadding * 2);
    126       gfx::Size message_size = message_->GetPreferredSize();
    127       int message_y = size.height() - kVerticalPadding - message_size.height();
    128       message_->SetBounds(kHorizontalPadding,
    129                           message_y,
    130                           message_size.width(),
    131                           message_size.height());
    132     }
    133   }
    134 
    135   // Throbber centered within the view.
    136   views::Throbber* throbber_;
    137 
    138   // Message, multiline, aligned to the bottom of the view.
    139   views::Label* message_;
    140 
    141   DISALLOW_COPY_AND_ASSIGN(CameraImageView);
    142 };
    143 
    144 
    145 TakePhotoView::TakePhotoView(Delegate* delegate)
    146     : title_label_(NULL),
    147       snapshot_button_(NULL),
    148       user_image_(NULL),
    149       is_capturing_(false),
    150       show_title_(true),
    151       delegate_(delegate) {
    152 }
    153 
    154 TakePhotoView::~TakePhotoView() {
    155 }
    156 
    157 void TakePhotoView::Init() {
    158   if (show_title_) {
    159     title_label_ = new views::Label(
    160         UTF16ToWide(l10n_util::GetStringUTF16(IDS_USER_IMAGE_SCREEN_TITLE)));
    161     title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    162     title_label_->SetMultiLine(true);
    163     CorrectLabelFontSize(title_label_);
    164   }
    165 
    166   user_image_ = new CameraImageView();
    167   user_image_->SetImageSize(
    168       gfx::Size(login::kUserImageSize, login::kUserImageSize));
    169   user_image_->Init();
    170 
    171   snapshot_button_ = new views::ImageButton(this);
    172   snapshot_button_->SetFocusable(true);
    173   snapshot_button_->SetImage(views::CustomButton::BS_NORMAL,
    174                              ResourceBundle::GetSharedInstance().GetBitmapNamed(
    175                                  IDR_USER_IMAGE_CAPTURE));
    176   snapshot_button_->SetImage(views::CustomButton::BS_DISABLED,
    177                              ResourceBundle::GetSharedInstance().GetBitmapNamed(
    178                                  IDR_USER_IMAGE_CAPTURE_DISABLED));
    179   snapshot_button_->SetAccessibleName(l10n_util::GetStringUTF16(
    180       IDS_CHROMEOS_ACC_ACCOUNT_PICTURE));
    181 
    182   InitLayout();
    183   // Request focus only after the button is added to views hierarchy.
    184   snapshot_button_->RequestFocus();
    185 }
    186 
    187 void TakePhotoView::InitLayout() {
    188   views::GridLayout* layout = new views::GridLayout(this);
    189   layout->SetInsets(GetInsets());
    190   SetLayoutManager(layout);
    191 
    192   // The title is left-top aligned.
    193   if (show_title_) {
    194     views::ColumnSet* column_set = layout->AddColumnSet(kTitleRow);
    195     column_set->AddColumn(views::GridLayout::FILL,
    196                           views::GridLayout::LEADING,
    197                           1,
    198                           views::GridLayout::USE_PREF, 0, 0);
    199   }
    200 
    201   // User image and snapshot button are centered horizontally.
    202   views::ColumnSet* column_set = layout->AddColumnSet(kImageRow);
    203   column_set->AddColumn(views::GridLayout::CENTER,
    204                         views::GridLayout::LEADING,
    205                         1,
    206                         views::GridLayout::USE_PREF, 0, 0);
    207 
    208   // Fill the layout with rows and views now.
    209   if (show_title_) {
    210     layout->StartRow(0, kTitleRow);
    211     layout->AddView(title_label_);
    212   }
    213   layout->StartRowWithPadding(0, kImageRow, 0, kVerticalPadding);
    214   layout->AddView(user_image_);
    215   layout->StartRowWithPadding(1, kImageRow, 0, kVerticalPadding);
    216   layout->AddView(snapshot_button_);
    217 }
    218 
    219 void TakePhotoView::UpdateVideoFrame(const SkBitmap& frame) {
    220   if (!is_capturing_)
    221     return;
    222 
    223   if (!snapshot_button_->IsEnabled()) {
    224     user_image_->SetNormalState();
    225     snapshot_button_->SetEnabled(true);
    226     snapshot_button_->RequestFocus();
    227   }
    228   SkBitmap user_image =
    229       skia::ImageOperations::Resize(
    230           frame,
    231           skia::ImageOperations::RESIZE_BOX,
    232           login::kUserImageSize,
    233           login::kUserImageSize);
    234 
    235   user_image_->SetImage(&user_image);
    236 }
    237 
    238 void TakePhotoView::ShowCameraInitializing() {
    239   is_capturing_ = true;
    240   snapshot_button_->SetImage(views::CustomButton::BS_NORMAL,
    241                              ResourceBundle::GetSharedInstance().GetBitmapNamed(
    242                                  IDR_USER_IMAGE_CAPTURE));
    243   snapshot_button_->SetVisible(true);
    244   snapshot_button_->SetEnabled(false);
    245   user_image_->SetInitializingState();
    246 }
    247 
    248 void TakePhotoView::ShowCameraError() {
    249   if (!is_capturing_)
    250     return;
    251   snapshot_button_->SetEnabled(false);
    252   user_image_->SetErrorState();
    253 }
    254 
    255 const SkBitmap& TakePhotoView::GetImage() const {
    256   return user_image_->GetImage();
    257 }
    258 
    259 void TakePhotoView::SetImage(SkBitmap* image) {
    260   is_capturing_ = false;
    261   snapshot_button_->SetVisible(false);
    262   user_image_->SetNormalState();
    263   user_image_->SetImage(image);
    264 }
    265 
    266 gfx::Size TakePhotoView::GetPreferredSize() {
    267   return gfx::Size(width(), height());
    268 }
    269 
    270 void TakePhotoView::ButtonPressed(
    271     views::Button* sender, const views::Event& event) {
    272   DCHECK(delegate_);
    273   DCHECK(sender == snapshot_button_);
    274   is_capturing_ = !is_capturing_;
    275   if (is_capturing_) {
    276     snapshot_button_->SetImage(
    277         views::CustomButton::BS_NORMAL,
    278         ResourceBundle::GetSharedInstance().GetBitmapNamed(
    279             IDR_USER_IMAGE_CAPTURE));
    280     delegate_->OnCapturingStarted();
    281   } else {
    282     snapshot_button_->SetImage(
    283         views::CustomButton::BS_NORMAL,
    284         ResourceBundle::GetSharedInstance().GetBitmapNamed(
    285             IDR_USER_IMAGE_RECYCLE));
    286     delegate_->OnCapturingStopped();
    287   }
    288   snapshot_button_->SchedulePaint();
    289 }
    290 
    291 }  // namespace chromeos
    292