Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "views/controls/textfield/native_textfield_views.h" | 5 #include "views/controls/textfield/native_textfield_views.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "grit/app_strings.h" | 13 #include "grit/app_strings.h" |
| 14 #include "ui/base/clipboard/clipboard.h" | 14 #include "ui/base/clipboard/clipboard.h" |
| 15 #include "ui/base/range/range.h" | 15 #include "ui/base/range/range.h" |
| 16 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
| 17 #include "ui/gfx/canvas_skia.h" | 17 #include "ui/gfx/canvas_skia.h" |
| 18 #include "ui/gfx/insets.h" | 18 #include "ui/gfx/insets.h" |
| 19 #include "views/background.h" | 19 #include "views/background.h" |
| 20 #include "views/border.h" | 20 #include "views/border.h" |
| 21 #include "views/controls/menu/menu_2.h" | 21 #include "views/controls/menu/menu_2.h" |
| 22 #include "views/controls/textfield/textfield.h" | 22 #include "views/controls/textfield/textfield.h" |
| 23 #include "views/controls/textfield/textfield_controller.h" | 23 #include "views/controls/textfield/textfield_controller.h" |
| 24 #include "views/controls/textfield/textfield_views_model.h" | 24 #include "views/controls/textfield/textfield_views_model.h" |
| 25 #include "views/events/event.h" | 25 #include "views/events/event.h" |
| 26 #include "views/ime/input_method.h" | |
| 26 #include "views/metrics.h" | 27 #include "views/metrics.h" |
| 27 #include "views/views_delegate.h" | 28 #include "views/views_delegate.h" |
| 28 | 29 |
| 29 #if defined(OS_LINUX) | 30 #if defined(OS_LINUX) |
| 30 #include "ui/gfx/gtk_util.h" | 31 #include "ui/gfx/gtk_util.h" |
| 31 #endif | 32 #endif |
| 32 | 33 |
| 33 namespace { | 34 namespace { |
| 34 | 35 |
| 35 // A global flag to switch the Textfield wrapper to TextfieldViews. | 36 // A global flag to switch the Textfield wrapper to TextfieldViews. |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 54 const char kEnableViewsBasedTextfieldSwitch[] = "enable-textfield-views"; | 55 const char kEnableViewsBasedTextfieldSwitch[] = "enable-textfield-views"; |
| 55 } // namespace | 56 } // namespace |
| 56 | 57 |
| 57 namespace views { | 58 namespace views { |
| 58 | 59 |
| 59 const char NativeTextfieldViews::kViewClassName[] = | 60 const char NativeTextfieldViews::kViewClassName[] = |
| 60 "views/NativeTextfieldViews"; | 61 "views/NativeTextfieldViews"; |
| 61 | 62 |
| 62 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) | 63 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) |
| 63 : textfield_(parent), | 64 : textfield_(parent), |
| 64 model_(new TextfieldViewsModel()), | 65 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))), |
| 65 text_border_(new TextfieldBorder()), | 66 text_border_(new TextfieldBorder()), |
| 66 text_offset_(0), | 67 text_offset_(0), |
| 67 insert_(true), | 68 insert_(true), |
| 68 is_cursor_visible_(false), | 69 is_cursor_visible_(false), |
| 70 skip_cancel_composition_(false), | |
| 69 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)), | 71 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)), |
| 70 last_mouse_press_time_(base::Time::FromInternalValue(0)), | 72 last_mouse_press_time_(base::Time::FromInternalValue(0)), |
| 71 click_state_(NONE) { | 73 click_state_(NONE) { |
| 72 set_border(text_border_); | 74 set_border(text_border_); |
| 73 | 75 |
| 74 // Multiline is not supported. | 76 // Multiline is not supported. |
| 75 DCHECK_NE(parent->style(), Textfield::STYLE_MULTILINE); | 77 DCHECK_NE(parent->style(), Textfield::STYLE_MULTILINE); |
| 76 // Lowercase is not supported. | 78 // Lowercase is not supported. |
| 77 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); | 79 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); |
| 78 | 80 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 } | 159 } |
| 158 | 160 |
| 159 ///////////////////////////////////////////////////////////////// | 161 ///////////////////////////////////////////////////////////////// |
| 160 // NativeTextfieldViews, NativeTextifieldWrapper overrides: | 162 // NativeTextfieldViews, NativeTextifieldWrapper overrides: |
| 161 | 163 |
| 162 string16 NativeTextfieldViews::GetText() const { | 164 string16 NativeTextfieldViews::GetText() const { |
| 163 return model_->text(); | 165 return model_->text(); |
| 164 } | 166 } |
| 165 | 167 |
| 166 void NativeTextfieldViews::UpdateText() { | 168 void NativeTextfieldViews::UpdateText() { |
| 167 bool changed = model_->SetText(textfield_->text()); | 169 model_->SetText(textfield_->text()); |
| 168 UpdateCursorBoundsAndTextOffset(); | 170 UpdateCursorBoundsAndTextOffset(); |
| 169 SchedulePaint(); | 171 SchedulePaint(); |
| 170 if (changed) { | |
| 171 TextfieldController* controller = textfield_->GetController(); | |
| 172 if (controller) | |
| 173 controller->ContentsChanged(textfield_, GetText()); | |
| 174 } | |
| 175 } | 172 } |
| 176 | 173 |
| 177 void NativeTextfieldViews::AppendText(const string16& text) { | 174 void NativeTextfieldViews::AppendText(const string16& text) { |
| 178 if (text.empty()) | 175 if (text.empty()) |
| 179 return; | 176 return; |
| 180 model_->Append(text); | 177 model_->Append(text); |
| 181 UpdateCursorBoundsAndTextOffset(); | 178 UpdateCursorBoundsAndTextOffset(); |
| 182 SchedulePaint(); | 179 SchedulePaint(); |
| 183 | |
| 184 TextfieldController* controller = textfield_->GetController(); | |
| 185 if (controller) | |
| 186 controller->ContentsChanged(textfield_, GetText()); | |
| 187 } | 180 } |
| 188 | 181 |
| 189 string16 NativeTextfieldViews::GetSelectedText() const { | 182 string16 NativeTextfieldViews::GetSelectedText() const { |
| 190 return model_->GetSelectedText(); | 183 return model_->GetSelectedText(); |
| 191 } | 184 } |
| 192 | 185 |
| 193 void NativeTextfieldViews::SelectAll() { | 186 void NativeTextfieldViews::SelectAll() { |
| 194 model_->SelectAll(); | 187 model_->SelectAll(); |
| 195 SchedulePaint(); | 188 SchedulePaint(); |
| 196 } | 189 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 217 | 210 |
| 218 void NativeTextfieldViews::UpdateBackgroundColor() { | 211 void NativeTextfieldViews::UpdateBackgroundColor() { |
| 219 // TODO(oshima): Background has to match the border's shape. | 212 // TODO(oshima): Background has to match the border's shape. |
| 220 set_background( | 213 set_background( |
| 221 Background::CreateSolidBackground(textfield_->background_color())); | 214 Background::CreateSolidBackground(textfield_->background_color())); |
| 222 SchedulePaint(); | 215 SchedulePaint(); |
| 223 } | 216 } |
| 224 | 217 |
| 225 void NativeTextfieldViews::UpdateReadOnly() { | 218 void NativeTextfieldViews::UpdateReadOnly() { |
| 226 SchedulePaint(); | 219 SchedulePaint(); |
| 220 OnTextInputTypeChanged(); | |
| 227 } | 221 } |
| 228 | 222 |
| 229 void NativeTextfieldViews::UpdateFont() { | 223 void NativeTextfieldViews::UpdateFont() { |
| 230 UpdateCursorBoundsAndTextOffset(); | 224 UpdateCursorBoundsAndTextOffset(); |
| 231 } | 225 } |
| 232 | 226 |
| 233 void NativeTextfieldViews::UpdateIsPassword() { | 227 void NativeTextfieldViews::UpdateIsPassword() { |
| 234 model_->set_is_password(textfield_->IsPassword()); | 228 model_->set_is_password(textfield_->IsPassword()); |
| 235 UpdateCursorBoundsAndTextOffset(); | 229 UpdateCursorBoundsAndTextOffset(); |
| 236 SchedulePaint(); | 230 SchedulePaint(); |
| 231 OnTextInputTypeChanged(); | |
| 237 } | 232 } |
| 238 | 233 |
| 239 void NativeTextfieldViews::UpdateEnabled() { | 234 void NativeTextfieldViews::UpdateEnabled() { |
| 240 SetEnabled(textfield_->IsEnabled()); | 235 SetEnabled(textfield_->IsEnabled()); |
| 241 SchedulePaint(); | 236 SchedulePaint(); |
| 237 OnTextInputTypeChanged(); | |
| 242 } | 238 } |
| 243 | 239 |
| 244 gfx::Insets NativeTextfieldViews::CalculateInsets() { | 240 gfx::Insets NativeTextfieldViews::CalculateInsets() { |
| 245 return GetInsets(); | 241 return GetInsets(); |
| 246 } | 242 } |
| 247 | 243 |
| 248 void NativeTextfieldViews::UpdateHorizontalMargins() { | 244 void NativeTextfieldViews::UpdateHorizontalMargins() { |
| 249 int left, right; | 245 int left, right; |
| 250 if (!textfield_->GetHorizontalMargins(&left, &right)) | 246 if (!textfield_->GetHorizontalMargins(&left, &right)) |
| 251 return; | 247 return; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 272 View* NativeTextfieldViews::GetView() { | 268 View* NativeTextfieldViews::GetView() { |
| 273 return this; | 269 return this; |
| 274 } | 270 } |
| 275 | 271 |
| 276 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const { | 272 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const { |
| 277 NOTREACHED(); | 273 NOTREACHED(); |
| 278 return NULL; | 274 return NULL; |
| 279 } | 275 } |
| 280 | 276 |
| 281 bool NativeTextfieldViews::IsIMEComposing() const { | 277 bool NativeTextfieldViews::IsIMEComposing() const { |
| 282 return false; | 278 return model_->HasComposition(); |
| 283 } | 279 } |
| 284 | 280 |
| 285 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { | 281 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { |
| 286 model_->GetSelectedRange(range); | 282 model_->GetSelectedRange(range); |
| 287 } | 283 } |
| 288 | 284 |
| 289 void NativeTextfieldViews::SelectRange(const ui::Range& range) { | 285 void NativeTextfieldViews::SelectRange(const ui::Range& range) { |
| 290 model_->SelectRange(range); | 286 model_->SelectRange(range); |
| 291 UpdateCursorBoundsAndTextOffset(); | 287 UpdateCursorBoundsAndTextOffset(); |
| 292 SchedulePaint(); | 288 SchedulePaint(); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 304 return handled || HandleKeyEvent(e); | 300 return handled || HandleKeyEvent(e); |
| 305 } | 301 } |
| 306 | 302 |
| 307 bool NativeTextfieldViews::HandleKeyReleased(const views::KeyEvent& e) { | 303 bool NativeTextfieldViews::HandleKeyReleased(const views::KeyEvent& e) { |
| 308 return true; | 304 return true; |
| 309 } | 305 } |
| 310 | 306 |
| 311 void NativeTextfieldViews::HandleFocus() { | 307 void NativeTextfieldViews::HandleFocus() { |
| 312 is_cursor_visible_ = true; | 308 is_cursor_visible_ = true; |
| 313 SchedulePaint(); | 309 SchedulePaint(); |
| 310 OnCaretBoundsChanged(); | |
| 314 // Start blinking cursor. | 311 // Start blinking cursor. |
| 315 MessageLoop::current()->PostDelayedTask( | 312 MessageLoop::current()->PostDelayedTask( |
| 316 FROM_HERE, | 313 FROM_HERE, |
| 317 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), | 314 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), |
| 318 kCursorVisibleTimeMs); | 315 kCursorVisibleTimeMs); |
| 319 } | 316 } |
| 320 | 317 |
| 321 void NativeTextfieldViews::HandleBlur() { | 318 void NativeTextfieldViews::HandleBlur() { |
| 322 // Stop blinking cursor. | 319 // Stop blinking cursor. |
| 323 cursor_timer_.RevokeAll(); | 320 cursor_timer_.RevokeAll(); |
| 324 if (is_cursor_visible_) { | 321 if (is_cursor_visible_) { |
| 325 is_cursor_visible_ = false; | 322 is_cursor_visible_ = false; |
| 326 RepaintCursor(); | 323 RepaintCursor(); |
| 327 } | 324 } |
| 328 } | 325 } |
| 329 | 326 |
| 327 TextInputClient* NativeTextfieldViews::GetTextInputClient() { | |
| 328 return textfield_->read_only() ? NULL : this; | |
| 329 } | |
| 330 | |
| 330 ///////////////////////////////////////////////////////////////// | 331 ///////////////////////////////////////////////////////////////// |
| 331 // NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides: | 332 // NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides: |
| 332 | 333 |
| 333 bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const { | 334 bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const { |
| 334 return true; | 335 return true; |
| 335 } | 336 } |
| 336 | 337 |
| 337 bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const { | 338 bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const { |
| 338 bool editable = !textfield_->read_only(); | 339 bool editable = !textfield_->read_only(); |
| 339 string16 result; | 340 string16 result; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 void NativeTextfieldViews::SetEnableTextfieldViews(bool enabled) { | 410 void NativeTextfieldViews::SetEnableTextfieldViews(bool enabled) { |
| 410 textfield_view_enabled = enabled; | 411 textfield_view_enabled = enabled; |
| 411 } | 412 } |
| 412 | 413 |
| 413 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { | 414 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { |
| 414 UpdateCursorBoundsAndTextOffset(); | 415 UpdateCursorBoundsAndTextOffset(); |
| 415 } | 416 } |
| 416 | 417 |
| 417 | 418 |
| 418 /////////////////////////////////////////////////////////////////////////////// | 419 /////////////////////////////////////////////////////////////////////////////// |
| 419 // NativeTextfieldViews private: | 420 // NativeTextfieldViews private: |
|
oshima
2011/03/22 01:50:39
NativeTextfieldViews, TextInputClient implementati
James Su
2011/03/22 08:41:14
Done.
| |
| 420 | 421 |
| 422 void NativeTextfieldViews::SetComposition(const ui::Composition& composition) { | |
| 423 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) | |
| 424 return; | |
| 425 | |
| 426 OnBeforeUserAction(); | |
| 427 skip_cancel_composition_ = true; | |
| 428 model_->SetComposition(composition); | |
| 429 skip_cancel_composition_ = false; | |
| 430 UpdateAfterChange(true, true); | |
| 431 OnAfterUserAction(); | |
| 432 } | |
| 433 | |
| 434 void NativeTextfieldViews::ConfirmComposition() { | |
| 435 if (!model_->HasComposition()) | |
| 436 return; | |
| 437 | |
| 438 OnBeforeUserAction(); | |
| 439 skip_cancel_composition_ = true; | |
| 440 model_->ConfirmComposition(); | |
| 441 skip_cancel_composition_ = false; | |
| 442 UpdateAfterChange(true, true); | |
| 443 OnAfterUserAction(); | |
| 444 } | |
| 445 | |
| 446 void NativeTextfieldViews::ClearComposition() { | |
| 447 if (!model_->HasComposition()) | |
| 448 return; | |
| 449 | |
| 450 OnBeforeUserAction(); | |
| 451 skip_cancel_composition_ = true; | |
| 452 model_->ClearComposition(); | |
| 453 skip_cancel_composition_ = false; | |
| 454 UpdateAfterChange(true, true); | |
| 455 OnAfterUserAction(); | |
| 456 } | |
| 457 | |
| 458 void NativeTextfieldViews::InsertText(const string16& text) { | |
| 459 // TODO(suzhe): Filter invalid characters. | |
| 460 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty()) | |
| 461 return; | |
| 462 | |
| 463 OnBeforeUserAction(); | |
| 464 skip_cancel_composition_ = true; | |
| 465 if (insert_) | |
| 466 model_->InsertText(text); | |
| 467 else | |
| 468 model_->ReplaceText(text); | |
| 469 skip_cancel_composition_ = false; | |
| 470 UpdateAfterChange(true, true); | |
| 471 OnAfterUserAction(); | |
| 472 } | |
| 473 | |
| 474 void NativeTextfieldViews::InsertChar(char16 ch, int flags) { | |
| 475 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || !IsValidChar(ch, flags)) | |
| 476 return; | |
| 477 | |
| 478 OnBeforeUserAction(); | |
| 479 skip_cancel_composition_ = true; | |
| 480 if (insert_) | |
| 481 model_->InsertChar(ch); | |
| 482 else | |
| 483 model_->ReplaceChar(ch); | |
| 484 skip_cancel_composition_ = false; | |
| 485 UpdateAfterChange(true, true); | |
| 486 OnAfterUserAction(); | |
| 487 } | |
| 488 | |
| 489 ui::TextInputType NativeTextfieldViews::GetTextInputType() { | |
| 490 if (textfield_->read_only() || !textfield_->IsEnabled()) | |
| 491 return ui::TEXT_INPUT_TYPE_NONE; | |
| 492 else if (textfield_->IsPassword()) | |
| 493 return ui::TEXT_INPUT_TYPE_PASSWORD; | |
| 494 return ui::TEXT_INPUT_TYPE_TEXT; | |
| 495 } | |
| 496 | |
| 497 gfx::Rect NativeTextfieldViews::GetCaretBounds() { | |
| 498 return cursor_bounds_; | |
| 499 } | |
| 500 | |
| 501 bool NativeTextfieldViews::HasComposition() { | |
| 502 return model_->HasComposition(); | |
| 503 } | |
| 504 | |
| 505 bool NativeTextfieldViews::GetTextRange(ui::Range* range) { | |
| 506 // We don't allow the input method to retrieve or delete content from a | |
| 507 // password box. | |
| 508 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT) | |
| 509 return false; | |
| 510 | |
| 511 model_->GetTextRange(range); | |
| 512 return true; | |
| 513 } | |
| 514 | |
| 515 bool NativeTextfieldViews::GetCompositionRange(ui::Range* range) { | |
| 516 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT) | |
| 517 return false; | |
| 518 | |
| 519 model_->GetCompositionRange(range); | |
| 520 return true; | |
| 521 } | |
| 522 | |
| 523 bool NativeTextfieldViews::GetSelectionRange(ui::Range* range) { | |
| 524 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT) | |
| 525 return false; | |
| 526 | |
| 527 model_->GetSelectedRange(range); | |
| 528 return true; | |
| 529 } | |
| 530 | |
| 531 bool NativeTextfieldViews::SetSelectionRange(const ui::Range& range) { | |
| 532 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || !range.IsValid()) | |
| 533 return false; | |
| 534 | |
| 535 OnBeforeUserAction(); | |
| 536 SelectRange(range); | |
| 537 OnAfterUserAction(); | |
| 538 return true; | |
| 539 } | |
| 540 | |
| 541 bool NativeTextfieldViews::DeleteRange(const ui::Range& range) { | |
| 542 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || range.is_empty()) | |
| 543 return false; | |
| 544 | |
| 545 OnBeforeUserAction(); | |
| 546 model_->SelectRange(range); | |
| 547 if (model_->HasSelection()) { | |
| 548 model_->DeleteSelection(); | |
| 549 UpdateAfterChange(true, true); | |
| 550 } | |
| 551 OnAfterUserAction(); | |
| 552 return true; | |
| 553 } | |
| 554 | |
| 555 bool NativeTextfieldViews::GetTextFromRange( | |
| 556 const ui::Range& range, | |
| 557 const base::Callback<void(string16)>& callback) { | |
| 558 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || range.is_empty()) | |
| 559 return false; | |
| 560 | |
| 561 callback.Run(model_->GetTextFromRange(range)); | |
| 562 return true; | |
| 563 } | |
| 564 | |
| 565 void NativeTextfieldViews::OnInputMethodChanged() { | |
| 566 NOTIMPLEMENTED(); | |
| 567 } | |
| 568 | |
| 569 bool NativeTextfieldViews::ChangeTextDirectionAndLayoutAlignment( | |
| 570 base::i18n::TextDirection direction) { | |
| 571 NOTIMPLEMENTED(); | |
| 572 return false; | |
| 573 } | |
| 574 | |
| 575 void NativeTextfieldViews::OnCompositionConfirmedOrCleared() { | |
| 576 if (!skip_cancel_composition_) | |
| 577 CancelComposition(); | |
| 578 } | |
| 579 | |
| 421 const gfx::Font& NativeTextfieldViews::GetFont() const { | 580 const gfx::Font& NativeTextfieldViews::GetFont() const { |
| 422 return textfield_->font(); | 581 return textfield_->font(); |
| 423 } | 582 } |
| 424 | 583 |
| 425 SkColor NativeTextfieldViews::GetTextColor() const { | 584 SkColor NativeTextfieldViews::GetTextColor() const { |
| 426 return textfield_->text_color(); | 585 return textfield_->text_color(); |
| 427 } | 586 } |
| 428 | 587 |
| 429 void NativeTextfieldViews::UpdateCursor() { | 588 void NativeTextfieldViews::UpdateCursor() { |
| 430 is_cursor_visible_ = !is_cursor_visible_; | 589 is_cursor_visible_ = !is_cursor_visible_; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 469 text_offset_ = -cursor_bounds_.x(); | 628 text_offset_ = -cursor_bounds_.x(); |
| 470 } else if(full_width > width && text_offset_ + full_width < width) { | 629 } else if(full_width > width && text_offset_ + full_width < width) { |
| 471 // when the cursor moves within the textfield with the text | 630 // when the cursor moves within the textfield with the text |
| 472 // longer than the field. | 631 // longer than the field. |
| 473 text_offset_ = width - full_width; | 632 text_offset_ = width - full_width; |
| 474 } else { | 633 } else { |
| 475 // move cursor freely. | 634 // move cursor freely. |
| 476 } | 635 } |
| 477 // shift cursor bounds to fit insets. | 636 // shift cursor bounds to fit insets. |
| 478 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + insets.left()); | 637 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + insets.left()); |
| 638 | |
| 639 OnCaretBoundsChanged(); | |
| 479 } | 640 } |
| 480 | 641 |
| 481 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { | 642 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { |
| 482 gfx::Insets insets = GetInsets(); | 643 gfx::Insets insets = GetInsets(); |
| 483 | 644 |
| 484 canvas->Save(); | 645 canvas->Save(); |
| 485 canvas->ClipRectInt(insets.left(), insets.top(), | 646 canvas->ClipRectInt(insets.left(), insets.top(), |
| 486 width() - insets.width(), height() - insets.height()); | 647 width() - insets.width(), height() - insets.height()); |
| 487 | 648 |
| 488 // TODO(oshima): bidi support | 649 // TODO(oshima): bidi support |
| 489 // TODO(varunjain): re-implement this so only that dirty text is painted. | 650 // TODO(varunjain): re-implement this so only that dirty text is painted. |
| 490 TextfieldViewsModel::TextFragments fragments; | 651 TextfieldViewsModel::TextFragments fragments; |
| 491 model_->GetFragments(&fragments); | 652 model_->GetFragments(&fragments); |
| 492 int x_offset = text_offset_ + insets.left(); | 653 int x_offset = text_offset_ + insets.left(); |
| 493 int y = insets.top(); | 654 int y = insets.top(); |
| 494 int text_height = height() - insets.height(); | 655 int text_height = height() - insets.height(); |
| 495 SkColor selection_color = | 656 SkColor selection_color = |
| 496 textfield_->HasFocus() ? | 657 textfield_->HasFocus() ? |
| 497 kFocusedSelectionColor : kUnfocusedSelectionColor; | 658 kFocusedSelectionColor : kUnfocusedSelectionColor; |
| 498 SkColor text_color = | 659 SkColor text_color = |
| 499 textfield_->read_only() ? kReadonlyTextColor : GetTextColor(); | 660 textfield_->read_only() ? kReadonlyTextColor : GetTextColor(); |
| 500 | 661 |
| 501 for (TextfieldViewsModel::TextFragments::const_iterator iter = | 662 for (TextfieldViewsModel::TextFragments::const_iterator iter = |
| 502 fragments.begin(); | 663 fragments.begin(); |
| 503 iter != fragments.end(); | 664 iter != fragments.end(); |
| 504 iter++) { | 665 iter++) { |
| 505 string16 text = model_->GetVisibleText((*iter).begin, (*iter).end); | 666 string16 text = model_->GetVisibleText(iter->start, iter->end); |
| 667 | |
| 668 gfx::Font font = GetFont(); | |
| 669 if (iter->underline) | |
| 670 font = font.DeriveFont(0, font.GetStyle() | gfx::Font::UNDERLINED); | |
| 671 | |
| 506 // TODO(oshima): This does not give the accurate position due to | 672 // TODO(oshima): This does not give the accurate position due to |
| 507 // kerning. Figure out how webkit does this with skia. | 673 // kerning. Figure out how webkit does this with skia. |
| 508 int width = GetFont().GetStringWidth(text); | 674 int width = font.GetStringWidth(text); |
| 509 | 675 |
| 510 if ((*iter).selected) { | 676 if (iter->selected) { |
| 511 canvas->FillRectInt(selection_color, x_offset, y, width, text_height); | 677 canvas->FillRectInt(selection_color, x_offset, y, width, text_height); |
| 512 canvas->DrawStringInt(text, GetFont(), kSelectedTextColor, | 678 canvas->DrawStringInt(text, font, kSelectedTextColor, |
| 513 x_offset, y, width, text_height); | 679 x_offset, y, width, text_height); |
| 514 } else { | 680 } else { |
| 515 canvas->DrawStringInt(text, GetFont(), text_color, | 681 canvas->DrawStringInt(text, font, text_color, |
| 516 x_offset, y, width, text_height); | 682 x_offset, y, width, text_height); |
| 517 } | 683 } |
| 518 x_offset += width; | 684 x_offset += width; |
| 519 } | 685 } |
| 520 canvas->Restore(); | 686 canvas->Restore(); |
| 521 | 687 |
| 522 if (textfield_->IsEnabled() && is_cursor_visible_ && | 688 if (textfield_->IsEnabled() && is_cursor_visible_ && |
| 523 !model_->HasSelection()) { | 689 !model_->HasSelection()) { |
| 524 // Paint Cursor. Replace cursor is drawn as rectangle for now. | 690 // Paint Cursor. Replace cursor is drawn as rectangle for now. |
| 525 canvas->DrawRectInt(kCursorColor, | 691 canvas->DrawRectInt(kCursorColor, |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 571 case ui::VKEY_LEFT: | 737 case ui::VKEY_LEFT: |
| 572 control ? model_->MoveCursorToPreviousWord(selection) | 738 control ? model_->MoveCursorToPreviousWord(selection) |
| 573 : model_->MoveCursorLeft(selection); | 739 : model_->MoveCursorLeft(selection); |
| 574 cursor_changed = true; | 740 cursor_changed = true; |
| 575 break; | 741 break; |
| 576 case ui::VKEY_END: | 742 case ui::VKEY_END: |
| 577 model_->MoveCursorToEnd(selection); | 743 model_->MoveCursorToEnd(selection); |
| 578 cursor_changed = true; | 744 cursor_changed = true; |
| 579 break; | 745 break; |
| 580 case ui::VKEY_HOME: | 746 case ui::VKEY_HOME: |
| 581 model_->MoveCursorToStart(selection); | 747 model_->MoveCursorToHome(selection); |
| 582 cursor_changed = true; | 748 cursor_changed = true; |
| 583 break; | 749 break; |
| 584 case ui::VKEY_BACK: | 750 case ui::VKEY_BACK: |
| 585 if (!editable) | 751 if (!editable) |
| 586 break; | 752 break; |
| 587 if (!model_->HasSelection()) { | 753 if (!model_->HasSelection()) { |
| 588 if (selection && control) { | 754 if (selection && control) { |
| 589 // If both shift and control are pressed, then erase upto the | 755 // If both shift and control are pressed, then erase upto the |
| 590 // beginning of the buffer in ChromeOS. In windows, do nothing. | 756 // beginning of the buffer in ChromeOS. In windows, do nothing. |
| 591 #if defined(OS_WIN) | 757 #if defined(OS_WIN) |
| 592 break; | 758 break; |
| 593 #else | 759 #else |
| 594 model_->MoveCursorToStart(true); | 760 model_->MoveCursorToHome(true); |
| 595 #endif | 761 #endif |
| 596 } else if (control) { | 762 } else if (control) { |
| 597 // If only control is pressed, then erase the previous word. | 763 // If only control is pressed, then erase the previous word. |
| 598 model_->MoveCursorToPreviousWord(true); | 764 model_->MoveCursorToPreviousWord(true); |
| 599 } | 765 } |
| 600 } | 766 } |
| 601 text_changed = model_->Backspace(); | 767 text_changed = model_->Backspace(); |
| 602 cursor_changed = true; | 768 cursor_changed = true; |
| 603 break; | 769 break; |
| 604 case ui::VKEY_DELETE: | 770 case ui::VKEY_DELETE: |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 620 } | 786 } |
| 621 cursor_changed = text_changed = model_->Delete(); | 787 cursor_changed = text_changed = model_->Delete(); |
| 622 break; | 788 break; |
| 623 case ui::VKEY_INSERT: | 789 case ui::VKEY_INSERT: |
| 624 insert_ = !insert_; | 790 insert_ = !insert_; |
| 625 cursor_changed = true; | 791 cursor_changed = true; |
| 626 break; | 792 break; |
| 627 default: | 793 default: |
| 628 break; | 794 break; |
| 629 } | 795 } |
| 630 char16 ch = key_event.GetCharacter(); | 796 |
| 631 if (!control && editable && IsValidChar(ch, key_event.flags())) { | 797 // Only handle text input by ourselves if there is no input method. |
| 632 if (insert_) | 798 if (!textfield_->GetInputMethod()) { |
| 633 model_->Insert(ch); | 799 char16 ch = key_event.GetCharacter(); |
| 634 else | 800 if (!control && editable && IsValidChar(ch, key_event.flags())) { |
| 635 model_->Replace(ch); | 801 if (insert_) |
| 636 text_changed = true; | 802 model_->InsertChar(ch); |
| 803 else | |
| 804 model_->ReplaceChar(ch); | |
| 805 text_changed = true; | |
| 806 } | |
| 637 } | 807 } |
| 638 | 808 |
| 639 UpdateAfterChange(text_changed, cursor_changed); | 809 UpdateAfterChange(text_changed, cursor_changed); |
| 640 OnAfterUserAction(); | 810 OnAfterUserAction(); |
| 641 return (text_changed || cursor_changed); | 811 return (text_changed || cursor_changed); |
| 642 } | 812 } |
| 643 return false; | 813 return false; |
| 644 } | 814 } |
| 645 | 815 |
| 646 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { | 816 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 | 881 |
| 712 void NativeTextfieldViews::SetCursorForMouseClick(const views::MouseEvent& e) { | 882 void NativeTextfieldViews::SetCursorForMouseClick(const views::MouseEvent& e) { |
| 713 size_t pos = FindCursorPosition(e.location()); | 883 size_t pos = FindCursorPosition(e.location()); |
| 714 if (model_->MoveCursorTo(pos, false)) { | 884 if (model_->MoveCursorTo(pos, false)) { |
| 715 UpdateCursorBoundsAndTextOffset(); | 885 UpdateCursorBoundsAndTextOffset(); |
| 716 } | 886 } |
| 717 } | 887 } |
| 718 | 888 |
| 719 void NativeTextfieldViews::PropagateTextChange() { | 889 void NativeTextfieldViews::PropagateTextChange() { |
| 720 textfield_->SyncText(); | 890 textfield_->SyncText(); |
| 721 TextfieldController* controller = textfield_->GetController(); | |
| 722 if (controller) | |
| 723 controller->ContentsChanged(textfield_, GetText()); | |
| 724 } | 891 } |
| 725 | 892 |
| 726 void NativeTextfieldViews::UpdateAfterChange(bool text_changed, | 893 void NativeTextfieldViews::UpdateAfterChange(bool text_changed, |
| 727 bool cursor_changed) { | 894 bool cursor_changed) { |
| 728 if (text_changed) | 895 if (text_changed) |
| 729 PropagateTextChange(); | 896 PropagateTextChange(); |
| 730 if (cursor_changed) { | 897 if (cursor_changed) { |
| 731 is_cursor_visible_ = true; | 898 is_cursor_visible_ = true; |
| 732 RepaintCursor(); | 899 RepaintCursor(); |
| 733 } | 900 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 744 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); | 911 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); |
| 745 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); | 912 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); |
| 746 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); | 913 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); |
| 747 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE); | 914 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE); |
| 748 context_menu_contents_->AddSeparator(); | 915 context_menu_contents_->AddSeparator(); |
| 749 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, | 916 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, |
| 750 IDS_APP_SELECT_ALL); | 917 IDS_APP_SELECT_ALL); |
| 751 context_menu_menu_.reset(new Menu2(context_menu_contents_.get())); | 918 context_menu_menu_.reset(new Menu2(context_menu_contents_.get())); |
| 752 } | 919 } |
| 753 | 920 |
| 921 void NativeTextfieldViews::OnTextInputTypeChanged() { | |
| 922 if (!textfield_->HasFocus()) | |
| 923 return; | |
| 924 | |
| 925 InputMethod* input_method = textfield_->GetInputMethod(); | |
| 926 if (input_method) | |
| 927 input_method->OnTextInputTypeChanged(textfield_); | |
| 928 } | |
| 929 | |
| 930 void NativeTextfieldViews::OnCaretBoundsChanged() { | |
| 931 if (!textfield_->HasFocus()) | |
| 932 return; | |
| 933 | |
| 934 InputMethod* input_method = textfield_->GetInputMethod(); | |
| 935 if (input_method) | |
| 936 input_method->OnCaretBoundsChanged(textfield_); | |
| 937 } | |
| 938 | |
| 939 void NativeTextfieldViews::CancelComposition() { | |
| 940 if (!textfield_->HasFocus()) | |
| 941 return; | |
| 942 | |
| 943 InputMethod* input_method = textfield_->GetInputMethod(); | |
| 944 if (input_method) | |
| 945 input_method->CancelComposition(textfield_); | |
| 946 } | |
| 947 | |
| 754 void NativeTextfieldViews::OnBeforeUserAction() { | 948 void NativeTextfieldViews::OnBeforeUserAction() { |
| 755 TextfieldController* controller = textfield_->GetController(); | 949 TextfieldController* controller = textfield_->GetController(); |
| 756 if (controller) | 950 if (controller) |
| 757 controller->OnBeforeUserAction(textfield_); | 951 controller->OnBeforeUserAction(textfield_); |
| 758 } | 952 } |
| 759 | 953 |
| 760 void NativeTextfieldViews::OnAfterUserAction() { | 954 void NativeTextfieldViews::OnAfterUserAction() { |
| 761 TextfieldController* controller = textfield_->GetController(); | 955 TextfieldController* controller = textfield_->GetController(); |
| 762 if (controller) | 956 if (controller) |
| 763 controller->OnAfterUserAction(textfield_); | 957 controller->OnAfterUserAction(textfield_); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 822 } | 1016 } |
| 823 | 1017 |
| 824 void NativeTextfieldViews::TextfieldBorder::SetInsets(int top, | 1018 void NativeTextfieldViews::TextfieldBorder::SetInsets(int top, |
| 825 int left, | 1019 int left, |
| 826 int bottom, | 1020 int bottom, |
| 827 int right) { | 1021 int right) { |
| 828 insets_.Set(top, left, bottom, right); | 1022 insets_.Set(top, left, bottom, right); |
| 829 } | 1023 } |
| 830 | 1024 |
| 831 } // namespace views | 1025 } // namespace views |
| OLD | NEW |