// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/login/take_photo_view.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "skia/ext/image_operations.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "views/background.h"
#include "views/border.h"
#include "views/controls/button/image_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/controls/throbber.h"
#include "views/layout/grid_layout.h"
namespace {
// Padding between horizontally neighboring elements.
const int kHorizontalPadding = 10;
// Padding between vertically neighboring elements.
const int kVerticalPadding = 10;
// Color of image view border.
const SkColor kImageBorderColor = SkColorSetARGB(38, 0, 0, 0);
// IDs of column sets for grid layout manager.
enum ColumnSets {
kTitleRow, // Column set for screen title.
kImageRow, // Column set for image from camera and snapshot button.
};
} // namespace
namespace chromeos {
// Image view that can show center throbber above itself or a message at its
// bottom.
class CameraImageView : public views::ImageView {
public:
CameraImageView()
: throbber_(NULL),
message_(NULL) {}
~CameraImageView() {}
void Init() {
DCHECK(NULL == throbber_);
DCHECK(NULL == message_);
set_border(views::Border::CreateSolidBorder(1, kImageBorderColor));
set_background(views::Background::CreateSolidBackground(SK_ColorWHITE));
throbber_ = CreateDefaultSmoothedThrobber();
throbber_->SetVisible(false);
AddChildView(throbber_);
message_ = new views::Label();
message_->SetMultiLine(true);
message_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
message_->SetVisible(false);
CorrectLabelFontSize(message_);
AddChildView(message_);
}
void SetInitializingState() {
ShowThrobber();
SetMessage(std::wstring());
SetImage(
ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_USER_IMAGE_INITIALIZING));
}
void SetNormalState() {
HideThrobber();
SetMessage(std::wstring());
}
void SetErrorState() {
HideThrobber();
SetMessage(UTF16ToWide(l10n_util::GetStringUTF16(IDS_USER_IMAGE_NO_VIDEO)));
SetImage(
ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_USER_IMAGE_NO_VIDEO));
}
private:
void ShowThrobber() {
DCHECK(throbber_);
throbber_->SetVisible(true);
throbber_->Start();
}
void HideThrobber() {
DCHECK(throbber_);
throbber_->Stop();
throbber_->SetVisible(false);
}
void SetMessage(const std::wstring& message) {
DCHECK(message_);
message_->SetText(message);
message_->SetVisible(!message.empty());
Layout();
}
// views::View override:
virtual void Layout() {
gfx::Size size = GetPreferredSize();
if (throbber_->IsVisible()) {
gfx::Size throbber_size = throbber_->GetPreferredSize();
int throbber_x = (size.width() - throbber_size.width()) / 2;
int throbber_y = (size.height() - throbber_size.height()) / 2;
throbber_->SetBounds(throbber_x,
throbber_y,
throbber_size.width(),
throbber_size.height());
}
if (message_->IsVisible()) {
message_->SizeToFit(size.width() - kHorizontalPadding * 2);
gfx::Size message_size = message_->GetPreferredSize();
int message_y = size.height() - kVerticalPadding - message_size.height();
message_->SetBounds(kHorizontalPadding,
message_y,
message_size.width(),
message_size.height());
}
}
// Throbber centered within the view.
views::Throbber* throbber_;
// Message, multiline, aligned to the bottom of the view.
views::Label* message_;
DISALLOW_COPY_AND_ASSIGN(CameraImageView);
};
TakePhotoView::TakePhotoView(Delegate* delegate)
: title_label_(NULL),
snapshot_button_(NULL),
user_image_(NULL),
is_capturing_(false),
show_title_(true),
delegate_(delegate) {
}
TakePhotoView::~TakePhotoView() {
}
void TakePhotoView::Init() {
if (show_title_) {
title_label_ = new views::Label(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_USER_IMAGE_SCREEN_TITLE)));
title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
title_label_->SetMultiLine(true);
CorrectLabelFontSize(title_label_);
}
user_image_ = new CameraImageView();
user_image_->SetImageSize(
gfx::Size(login::kUserImageSize, login::kUserImageSize));
user_image_->Init();
snapshot_button_ = new views::ImageButton(this);
snapshot_button_->SetFocusable(true);
snapshot_button_->SetImage(views::CustomButton::BS_NORMAL,
ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_USER_IMAGE_CAPTURE));
snapshot_button_->SetImage(views::CustomButton::BS_DISABLED,
ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_USER_IMAGE_CAPTURE_DISABLED));
snapshot_button_->SetAccessibleName(l10n_util::GetStringUTF16(
IDS_CHROMEOS_ACC_ACCOUNT_PICTURE));
InitLayout();
// Request focus only after the button is added to views hierarchy.
snapshot_button_->RequestFocus();
}
void TakePhotoView::InitLayout() {
views::GridLayout* layout = new views::GridLayout(this);
layout->SetInsets(GetInsets());
SetLayoutManager(layout);
// The title is left-top aligned.
if (show_title_) {
views::ColumnSet* column_set = layout->AddColumnSet(kTitleRow);
column_set->AddColumn(views::GridLayout::FILL,
views::GridLayout::LEADING,
1,
views::GridLayout::USE_PREF, 0, 0);
}
// User image and snapshot button are centered horizontally.
views::ColumnSet* column_set = layout->AddColumnSet(kImageRow);
column_set->AddColumn(views::GridLayout::CENTER,
views::GridLayout::LEADING,
1,
views::GridLayout::USE_PREF, 0, 0);
// Fill the layout with rows and views now.
if (show_title_) {
layout->StartRow(0, kTitleRow);
layout->AddView(title_label_);
}
layout->StartRowWithPadding(0, kImageRow, 0, kVerticalPadding);
layout->AddView(user_image_);
layout->StartRowWithPadding(1, kImageRow, 0, kVerticalPadding);
layout->AddView(snapshot_button_);
}
void TakePhotoView::UpdateVideoFrame(const SkBitmap& frame) {
if (!is_capturing_)
return;
if (!snapshot_button_->IsEnabled()) {
user_image_->SetNormalState();
snapshot_button_->SetEnabled(true);
snapshot_button_->RequestFocus();
}
SkBitmap user_image =
skia::ImageOperations::Resize(
frame,
skia::ImageOperations::RESIZE_BOX,
login::kUserImageSize,
login::kUserImageSize);
user_image_->SetImage(&user_image);
}
void TakePhotoView::ShowCameraInitializing() {
is_capturing_ = true;
snapshot_button_->SetImage(views::CustomButton::BS_NORMAL,
ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_USER_IMAGE_CAPTURE));
snapshot_button_->SetVisible(true);
snapshot_button_->SetEnabled(false);
user_image_->SetInitializingState();
}
void TakePhotoView::ShowCameraError() {
if (!is_capturing_)
return;
snapshot_button_->SetEnabled(false);
user_image_->SetErrorState();
}
const SkBitmap& TakePhotoView::GetImage() const {
return user_image_->GetImage();
}
void TakePhotoView::SetImage(SkBitmap* image) {
is_capturing_ = false;
snapshot_button_->SetVisible(false);
user_image_->SetNormalState();
user_image_->SetImage(image);
}
gfx::Size TakePhotoView::GetPreferredSize() {
return gfx::Size(width(), height());
}
void TakePhotoView::ButtonPressed(
views::Button* sender, const views::Event& event) {
DCHECK(delegate_);
DCHECK(sender == snapshot_button_);
is_capturing_ = !is_capturing_;
if (is_capturing_) {
snapshot_button_->SetImage(
views::CustomButton::BS_NORMAL,
ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_USER_IMAGE_CAPTURE));
delegate_->OnCapturingStarted();
} else {
snapshot_button_->SetImage(
views::CustomButton::BS_NORMAL,
ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_USER_IMAGE_RECYCLE));
delegate_->OnCapturingStopped();
}
snapshot_button_->SchedulePaint();
}
} // namespace chromeos