Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/payments/editor_view_controller.h" | 5 #include "chrome/browser/ui/views/payments/editor_view_controller.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 54 | 54 |
| 55 std::unique_ptr<views::View> EditorViewController::CreateView() { | 55 std::unique_ptr<views::View> EditorViewController::CreateView() { |
| 56 std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>(); | 56 std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>(); |
| 57 | 57 |
| 58 views::BoxLayout* layout = | 58 views::BoxLayout* layout = |
| 59 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); | 59 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); |
| 60 layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); | 60 layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); |
| 61 layout->set_cross_axis_alignment( | 61 layout->set_cross_axis_alignment( |
| 62 views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); | 62 views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); |
| 63 content_view->SetLayoutManager(layout); | 63 content_view->SetLayoutManager(layout); |
| 64 // No insets. Child views below are responsible for their padding. | |
| 64 | 65 |
| 66 // An editor can optionally have a header view specific to it. | |
| 65 content_view->AddChildView(CreateHeaderView().release()); | 67 content_view->AddChildView(CreateHeaderView().release()); |
| 66 | 68 |
| 67 // Create an input label/textfield for each field definition. | 69 // The heart of the editor dialog: all the input fields with their labels. |
| 68 std::vector<EditorField> fields = GetFieldDefinitions(); | 70 content_view->AddChildView(CreateEditorView().release()); |
| 69 for (const auto& field : fields) { | |
| 70 content_view->AddChildView(CreateInputField(field).release()); | |
| 71 } | |
| 72 | 71 |
| 73 return CreatePaymentView( | 72 return CreatePaymentView( |
| 74 CreateSheetHeaderView( | 73 CreateSheetHeaderView( |
| 75 true, l10n_util::GetStringUTF16( | 74 true, l10n_util::GetStringUTF16( |
| 76 IDS_PAYMENT_REQUEST_CREDIT_CARD_EDITOR_ADD_TITLE), | 75 IDS_PAYMENT_REQUEST_CREDIT_CARD_EDITOR_ADD_TITLE), |
| 77 this), | 76 this), |
| 78 std::move(content_view)); | 77 std::move(content_view)); |
| 79 } | 78 } |
| 80 | 79 |
| 81 // Adds the "required fields" label in disabled text, to obtain this result. | 80 // Adds the "required fields" label in disabled text, to obtain this result. |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 95 // Adds the "* indicates a required field" label in "disabled" grey text. | 94 // Adds the "* indicates a required field" label in "disabled" grey text. |
| 96 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>( | 95 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>( |
| 97 l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE)); | 96 l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE)); |
| 98 label->SetDisabledColor(label->GetNativeTheme()->GetSystemColor( | 97 label->SetDisabledColor(label->GetNativeTheme()->GetSystemColor( |
| 99 ui::NativeTheme::kColorId_LabelDisabledColor)); | 98 ui::NativeTheme::kColorId_LabelDisabledColor)); |
| 100 label->SetEnabled(false); | 99 label->SetEnabled(false); |
| 101 content_view->AddChildView(label.release()); | 100 content_view->AddChildView(label.release()); |
| 102 return content_view; | 101 return content_view; |
| 103 } | 102 } |
| 104 | 103 |
| 104 void EditorViewController::DisplayErrorMessageForField( | |
| 105 const EditorField& field, | |
| 106 const base::string16& error_message) { | |
| 107 const auto& label_it = error_labels_.find(field); | |
| 108 DCHECK(label_it != error_labels_.end()); | |
| 109 label_it->second->SetText(error_message); | |
| 110 label_it->second->SchedulePaint(); | |
| 111 dialog()->Layout(); | |
| 112 } | |
| 113 | |
| 105 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() { | 114 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() { |
| 106 std::unique_ptr<views::Button> button( | 115 std::unique_ptr<views::Button> button( |
| 107 views::MdTextButton::CreateSecondaryUiBlueButton( | 116 views::MdTextButton::CreateSecondaryUiBlueButton( |
| 108 this, l10n_util::GetStringUTF16(IDS_DONE))); | 117 this, l10n_util::GetStringUTF16(IDS_DONE))); |
| 109 button->set_tag(static_cast<int>(EditorViewControllerTags::SAVE_BUTTON)); | 118 button->set_tag(static_cast<int>(EditorViewControllerTags::SAVE_BUTTON)); |
| 110 button->set_id(static_cast<int>(DialogViewID::EDITOR_SAVE_BUTTON)); | 119 button->set_id(static_cast<int>(DialogViewID::EDITOR_SAVE_BUTTON)); |
| 111 return button; | 120 return button; |
| 112 } | 121 } |
| 113 | 122 |
| 114 void EditorViewController::ButtonPressed(views::Button* sender, | 123 void EditorViewController::ButtonPressed(views::Button* sender, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 126 | 135 |
| 127 void EditorViewController::ContentsChanged(views::Textfield* sender, | 136 void EditorViewController::ContentsChanged(views::Textfield* sender, |
| 128 const base::string16& new_contents) { | 137 const base::string16& new_contents) { |
| 129 static_cast<ValidatingTextfield*>(sender)->OnContentsChanged(); | 138 static_cast<ValidatingTextfield*>(sender)->OnContentsChanged(); |
| 130 } | 139 } |
| 131 | 140 |
| 132 void EditorViewController::OnPerformAction(views::Combobox* sender) { | 141 void EditorViewController::OnPerformAction(views::Combobox* sender) { |
| 133 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged(); | 142 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged(); |
| 134 } | 143 } |
| 135 | 144 |
| 136 std::unique_ptr<views::View> EditorViewController::CreateInputField( | 145 std::unique_ptr<views::View> EditorViewController::CreateEditorView() { |
| 137 const EditorField& field) { | 146 std::unique_ptr<views::View> editor_view = base::MakeUnique<views::View>(); |
| 138 std::unique_ptr<views::View> row = base::MakeUnique<views::View>(); | |
| 139 | 147 |
| 140 row->SetBorder(payments::CreatePaymentRequestRowBorder()); | 148 views::GridLayout* editor_layout = new views::GridLayout(editor_view.get()); |
| 141 | 149 |
| 142 views::GridLayout* layout = new views::GridLayout(row.get()); | 150 // The editor grid layout is padded vertically from the top and bottom, and |
| 151 // horizontally inset like other content views. The top padding needs to be | |
| 152 // added to the top padding of the first row. | |
| 153 constexpr int kEditorVerticalInset = 16; | |
| 154 editor_layout->SetInsets( | |
| 155 kEditorVerticalInset, payments::kPaymentRequestRowHorizontalInsets, | |
| 156 kEditorVerticalInset, payments::kPaymentRequestRowHorizontalInsets); | |
| 143 | 157 |
| 144 // The vertical spacing for these rows is slightly different than the spacing | 158 editor_view->SetLayoutManager(editor_layout); |
| 145 // spacing for clickable rows, so don't use kPaymentRequestRowVerticalInsets. | 159 views::ColumnSet* columns = editor_layout->AddColumnSet(0); |
| 146 constexpr int kRowVerticalInset = 12; | |
| 147 layout->SetInsets( | |
| 148 kRowVerticalInset, payments::kPaymentRequestRowHorizontalInsets, | |
| 149 kRowVerticalInset, payments::kPaymentRequestRowHorizontalInsets); | |
| 150 | |
| 151 row->SetLayoutManager(layout); | |
| 152 views::ColumnSet* columns = layout->AddColumnSet(0); | |
| 153 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, | 160 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, |
| 154 views::GridLayout::USE_PREF, 0, 0); | 161 views::GridLayout::USE_PREF, 0, 0); |
| 155 columns->AddPaddingColumn(1, 0); | 162 |
| 156 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, | 163 // This is the horizontal padding between the label and the input field. |
| 164 constexpr int kLabelInputFieldHorizontalPadding = 16; | |
| 165 columns->AddPaddingColumn(0, kLabelInputFieldHorizontalPadding); | |
| 166 | |
| 167 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, | |
| 157 views::GridLayout::USE_PREF, 0, 0); | 168 views::GridLayout::USE_PREF, 0, 0); |
| 158 | 169 |
| 159 layout->StartRow(0, 0); | 170 std::vector<EditorField> fields = GetFieldDefinitions(); |
| 160 layout->AddView(new views::Label(field.label)); | 171 for (const auto& field : fields) { |
| 172 CreateInputField(editor_layout, field); | |
| 173 } | |
| 174 | |
| 175 return editor_view; | |
| 176 } | |
| 177 | |
| 178 // Each input field is a 4-quadrant grid. | |
| 179 // +----------------------------------------------------------+ | |
| 180 // | Field Label | Input field (textfield/combobox) | | |
| 181 // |_______________________|__________________________________| | |
| 182 // | (empty) | Error label | | |
| 183 // +----------------------------------------------------------+ | |
| 184 void EditorViewController::CreateInputField(views::GridLayout* layout, | |
| 185 const EditorField& field) { | |
| 186 // This is the top padding for every row. | |
| 187 constexpr int kInputRowSpacing = 6; | |
| 188 layout->StartRowWithPadding(0, 0, 0, kInputRowSpacing); | |
| 189 | |
| 190 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>( | |
| 191 field.required ? field.label + base::ASCIIToUTF16("*") : field.label); | |
| 192 // A very long label will wrap. | |
| 193 label->SetMultiLine(true); | |
|
anthonyvd
2017/02/22 19:32:45
I don't see where the max width of the label is se
Mathieu
2017/02/22 20:08:59
Correct! I've set a max width now.
| |
| 194 layout->AddView(label.release()); | |
| 161 | 195 |
| 162 if (field.control_type == EditorField::ControlType::TEXTFIELD) { | 196 if (field.control_type == EditorField::ControlType::TEXTFIELD) { |
| 163 ValidatingTextfield* text_field = | 197 ValidatingTextfield* text_field = |
| 164 new ValidatingTextfield(CreateValidationDelegate(field)); | 198 new ValidatingTextfield(CreateValidationDelegate(field, this)); |
| 165 text_field->set_controller(this); | 199 text_field->set_controller(this); |
| 166 // Using autofill field type as a view ID (for testing). | 200 // Using autofill field type as a view ID (for testing). |
| 167 text_field->set_id(static_cast<int>(field.type)); | 201 text_field->set_id(static_cast<int>(field.type)); |
| 168 text_field->set_default_width_in_chars( | 202 text_field->set_default_width_in_chars( |
| 169 field.length_hint == EditorField::LengthHint::HINT_SHORT | 203 field.length_hint == EditorField::LengthHint::HINT_SHORT |
| 170 ? kNumCharactersInShortField | 204 ? kNumCharactersInShortField |
| 171 : kNumCharactersInLongField); | 205 : kNumCharactersInLongField); |
| 172 | 206 |
| 173 text_fields_.insert(std::make_pair(text_field, field)); | 207 text_fields_.insert(std::make_pair(text_field, field)); |
| 174 // |text_field| will now be owned by |row|. | 208 // |text_field| will now be owned by |row|. |
| 175 layout->AddView(text_field); | 209 layout->AddView(text_field); |
| 176 } else if (field.control_type == EditorField::ControlType::COMBOBOX) { | 210 } else if (field.control_type == EditorField::ControlType::COMBOBOX) { |
| 177 ValidatingCombobox* combobox = new ValidatingCombobox( | 211 ValidatingCombobox* combobox = |
| 178 GetComboboxModelForType(field.type), CreateValidationDelegate(field)); | 212 new ValidatingCombobox(GetComboboxModelForType(field.type), |
| 213 CreateValidationDelegate(field, this)); | |
| 179 // Using autofill field type as a view ID (for testing). | 214 // Using autofill field type as a view ID (for testing). |
| 180 combobox->set_id(static_cast<int>(field.type)); | 215 combobox->set_id(static_cast<int>(field.type)); |
| 181 combobox->set_listener(this); | 216 combobox->set_listener(this); |
| 182 comboboxes_.insert(std::make_pair(combobox, field)); | 217 comboboxes_.insert(std::make_pair(combobox, field)); |
| 183 // |combobox| will now be owned by |row|. | 218 // |combobox| will now be owned by |row|. |
| 184 layout->AddView(combobox); | 219 layout->AddView(combobox); |
| 185 } else { | 220 } else { |
| 186 NOTREACHED(); | 221 NOTREACHED(); |
| 187 } | 222 } |
| 188 | 223 |
| 189 return row; | 224 // This is the vertical space between the input field and its error label. |
| 225 constexpr int kInputErrorLabelPadding = 6; | |
| 226 layout->StartRowWithPadding(0, 0, 0, kInputErrorLabelPadding); | |
| 227 layout->SkipColumns(1); | |
| 228 // Error label is initially empty. | |
| 229 std::unique_ptr<views::Label> error_label = | |
| 230 base::MakeUnique<views::Label>(base::ASCIIToUTF16("")); | |
| 231 error_label->set_id(static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET) + | |
| 232 field.type); | |
|
anthonyvd
2017/02/22 19:32:45
Are all fields guaranteed to have a different type
Mathieu
2017/02/22 20:08:59
Yes they all have different type, it's the autofil
| |
| 233 error_label->SetFontList( | |
| 234 error_label->GetDefaultFontList().DeriveWithSizeDelta(-1)); | |
| 235 error_label->SetEnabledColor(error_label->GetNativeTheme()->GetSystemColor( | |
| 236 ui::NativeTheme::kColorId_AlertSeverityHigh)); | |
| 237 error_labels_[field] = error_label.get(); | |
| 238 | |
| 239 layout->AddView(error_label.release()); | |
| 190 } | 240 } |
| 191 | 241 |
| 192 } // namespace payments | 242 } // namespace payments |
| OLD | NEW |