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 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 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 84 DefaultImagesView::DefaultImagesView(Delegate* delegate) 85 : selected_image_index_(-1), 86 delegate_(delegate) { 87 } 88 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 105 int DefaultImagesView::GetDefaultImageIndex() const { 106 if (selected_image_index_ == -1) 107 return -1; 108 else 109 return selected_image_index_ - kNonDefaultImageButtonsCount; 110 } 111 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 118 void DefaultImagesView::ClearSelection() { 119 selected_image_index_ = -1; 120 } 121 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 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 155 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 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