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