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
22 namespace chromeos {
23
24 namespace {
25
26 // Size of the default image within the view.
27 const int kDefaultImageSize = 64;
28 // Margin from left and right sides to the view contents.
29 const int kHorizontalMargin = 10;
30 // Margin from top and bottom sides to the view contents.
31 const int kVerticalMargin = 10;
32 // Padding between image columns.
33 const int kHorizontalPadding = 20;
34 // Padding between image rows.
35 const int kVerticalPadding = 15;
36 // Number of columns in a row of default images.
37 const int kColumnsCount = 5;
38 // Size of the border around default image.
39 const int kImageBorderSize = 1;
40 // Color of default image border.
41 const SkColor kImageBorderColor = SkColorSetARGB(38, 0, 0, 0);
42 // Color of default image background.
43 const 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.
46 const int kImageStartId = 100;
47 // ID for image control for video capture.
48 const 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).
51 const 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.
57 class 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
UserImageButton(views::ButtonListener * listener)68 UserImageButton::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
GetPreferredSize()77 gfx::Size UserImageButton::GetPreferredSize() {
78 gfx::Size size = views::ImageButton::GetPreferredSize();
79 size.Enlarge(GetInsets().width(), GetInsets().height());
80 return size;
81 }
82
83
DefaultImagesView(Delegate * delegate)84 DefaultImagesView::DefaultImagesView(Delegate* delegate)
85 : selected_image_index_(-1),
86 delegate_(delegate) {
87 }
88
Init()89 void 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
GetDefaultImageIndex() const105 int DefaultImagesView::GetDefaultImageIndex() const {
106 if (selected_image_index_ == -1)
107 return -1;
108 else
109 return selected_image_index_ - kNonDefaultImageButtonsCount;
110 }
111
SetDefaultImageIndex(int image_index)112 void DefaultImagesView::SetDefaultImageIndex(int image_index) {
113 selected_image_index_ = image_index + kNonDefaultImageButtonsCount;
114 if (delegate_)
115 delegate_->OnImageSelected(image_index % kDefaultImagesCount);
116 }
117
ClearSelection()118 void DefaultImagesView::ClearSelection() {
119 selected_image_index_ = -1;
120 }
121
GetPreferredSize()122 gfx::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
ButtonPressed(views::Button * sender,const views::Event & event)134 void 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
InitButton(int resource_id,UserImageButton * button) const155 void 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
InitLayout()168 void 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