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/default_images_view.h"
6
7#include "base/logging.h"
8#include "base/utf_string_conversions.h"
9#include "chrome/browser/chromeos/login/default_user_images.h"
10#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
11#include "grit/theme_resources.h"
12#include "grit/generated_resources.h"
13#include "skia/ext/image_operations.h"
14#include "third_party/skia/include/core/SkColor.h"
15#include "ui/base/l10n/l10n_util.h"
16#include "ui/base/resource/resource_bundle.h"
17#include "views/border.h"
18#include "views/background.h"
19#include "views/controls/button/image_button.h"
20#include "views/layout/grid_layout.h"
21
22namespace chromeos {
23
24namespace {
25
26// Size of the default image within the view.
27const int kDefaultImageSize = 64;
28// Margin from left and right sides to the view contents.
29const int kHorizontalMargin = 10;
30// Margin from top and bottom sides to the view contents.
31const int kVerticalMargin = 10;
32// Padding between image columns.
33const int kHorizontalPadding = 20;
34// Padding between image rows.
35const int kVerticalPadding = 15;
36// Number of columns in a row of default images.
37const int kColumnsCount = 5;
38// Size of the border around default image.
39const int kImageBorderSize = 1;
40// Color of default image border.
41const SkColor kImageBorderColor = SkColorSetARGB(38, 0, 0, 0);
42// Color of default image background.
43const SkColor kImageBackgroundColor = SK_ColorWHITE;
44// We give each image control an ID so we could distinguish them. Since 0 is
45// the default ID we want an offset for IDs we set.
46const int kImageStartId = 100;
47// ID for image control for video capture.
48const int kCaptureButtonId = 1000;
49// A number of the first buttons that don't correspond to any default image
50// (i.e. button to take a photo).
51const int kNonDefaultImageButtonsCount = 1;
52
53}  // namespace
54
55// Image button with border and background. Corrects view size by border
56// insets as ImageButton ignores it.
57class UserImageButton : public views::ImageButton {
58 public:
59  explicit UserImageButton(views::ButtonListener* listener);
60
61  // Overridden from views::View:
62  virtual gfx::Size GetPreferredSize();
63
64 private:
65  DISALLOW_COPY_AND_ASSIGN(UserImageButton);
66};
67
68UserImageButton::UserImageButton(views::ButtonListener* listener)
69    : ImageButton(listener) {
70  set_border(
71      views::Border::CreateSolidBorder(kImageBorderSize, kImageBorderColor));
72  set_background(
73      views::Background::CreateSolidBackground(kImageBackgroundColor));
74  SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
75}
76
77gfx::Size UserImageButton::GetPreferredSize() {
78  gfx::Size size = views::ImageButton::GetPreferredSize();
79  size.Enlarge(GetInsets().width(), GetInsets().height());
80  return size;
81}
82
83
84DefaultImagesView::DefaultImagesView(Delegate* delegate)
85    : selected_image_index_(-1),
86      delegate_(delegate) {
87}
88
89void DefaultImagesView::Init() {
90  UserImageButton* capture_button = new UserImageButton(this);
91  capture_button->SetID(kCaptureButtonId);
92  capture_button->SetTooltipText(UTF16ToWide(
93      l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE_TAKE_PHOTO)));
94  InitButton(IDR_BUTTON_USER_IMAGE_TAKE_PHOTO, capture_button);
95  default_images_.push_back(capture_button);
96  for (int i = 0; i < kDefaultImagesCount; ++i) {
97    UserImageButton* image_button = new UserImageButton(this);
98    image_button->SetID(i + kImageStartId);
99    InitButton(kDefaultImageResources[i], image_button);
100    default_images_.push_back(image_button);
101  }
102  InitLayout();
103}
104
105int DefaultImagesView::GetDefaultImageIndex() const {
106  if (selected_image_index_ == -1)
107    return -1;
108  else
109    return selected_image_index_ - kNonDefaultImageButtonsCount;
110}
111
112void DefaultImagesView::SetDefaultImageIndex(int image_index) {
113  selected_image_index_ = image_index + kNonDefaultImageButtonsCount;
114  if (delegate_)
115    delegate_->OnImageSelected(image_index % kDefaultImagesCount);
116}
117
118void DefaultImagesView::ClearSelection() {
119  selected_image_index_ = -1;
120}
121
122gfx::Size DefaultImagesView::GetPreferredSize() {
123  int image_size_with_margin = (kDefaultImageSize + 2 * kImageBorderSize);
124  int width = kColumnsCount * image_size_with_margin +
125              (kColumnsCount - 1) * kHorizontalPadding;
126  size_t image_count = default_images_.size();
127  int rows_count = (image_count + kColumnsCount - 1) / kColumnsCount;
128  int height = rows_count * image_size_with_margin +
129               (rows_count - 1) * kVerticalPadding;
130  return gfx::Size(width + 2 * kHorizontalMargin,
131                   height + 2 * kVerticalMargin);
132}
133
134void DefaultImagesView::ButtonPressed(views::Button* sender,
135                                      const views::Event& event) {
136  if (selected_image_index_ != -1 &&
137      default_images_[selected_image_index_] == sender)
138    return;
139  ClearSelection();
140
141  if (sender->GetID() == kCaptureButtonId) {
142    if (delegate_)
143      delegate_->OnCaptureButtonClicked();
144  } else {
145    int image_index = sender->GetID() - kImageStartId;
146    int images_count = static_cast<int>(default_images_.size());
147    if (image_index < 0 || image_index >= images_count) {
148      NOTREACHED() << "Got ButtonPressed event from a view with wrong id.";
149      return;
150    }
151    SetDefaultImageIndex(image_index);
152  }
153}
154
155void DefaultImagesView::InitButton(int resource_id,
156                                   UserImageButton* button) const {
157  const SkBitmap* original_image =
158      ResourceBundle::GetSharedInstance().GetBitmapNamed(resource_id);
159  SkBitmap resized_image = skia::ImageOperations::Resize(
160      *original_image,
161      skia::ImageOperations::RESIZE_BEST,
162      kDefaultImageSize, kDefaultImageSize);
163  button->SetImage(
164      views::CustomButton::BS_NORMAL,
165      &resized_image);
166}
167
168void DefaultImagesView::InitLayout() {
169  views::GridLayout* layout = new views::GridLayout(this);
170  layout->SetInsets(gfx::Insets(kVerticalMargin,
171                                kHorizontalMargin,
172                                kVerticalMargin,
173                                kHorizontalMargin));
174  SetLayoutManager(layout);
175
176  size_t current_image = 0;
177  size_t image_count = default_images_.size();
178  int rows_count = (image_count + kColumnsCount - 1) / kColumnsCount;
179  for (int row = 0; row < rows_count; ++row) {
180    views::ColumnSet* column_set = layout->AddColumnSet(row);
181    for (int column = 0; column < kColumnsCount; ++column) {
182      if (column != 0)
183        column_set->AddPaddingColumn(1, kHorizontalPadding);
184      if (current_image < image_count) {
185        column_set->AddColumn(
186            views::GridLayout::LEADING,
187            views::GridLayout::LEADING,
188            1,
189            views::GridLayout::USE_PREF,
190            0,
191            0);
192      } else {
193        int placeholders_count = kColumnsCount - column;
194        int placeholders_width = placeholders_count *
195                                 (kDefaultImageSize + 2 * kImageBorderSize);
196        int padding_width = (placeholders_count - 1) * kHorizontalPadding;
197        column_set->AddPaddingColumn(1, placeholders_width + padding_width);
198        break;
199      }
200      ++current_image;
201    }
202  }
203  current_image = 0;
204  for (int row = 0; row < rows_count; ++row) {
205    if (row != 0)
206      layout->AddPaddingRow(1, kVerticalPadding);
207    layout->StartRow(0, row);
208    for (int column = 0; column < kColumnsCount; ++column) {
209      if (current_image >= image_count)
210        break;
211      layout->AddView(default_images_[current_image]);
212      ++current_image;
213    }
214  }
215}
216
217}  // namespace chromeos
218