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/dragdrop/drag_drop_types.h" | 15 #include "ui/base/dragdrop/drag_drop_types.h" |
16 #include "ui/base/range/range.h" | 16 #include "ui/base/range/range.h" |
17 #include "ui/gfx/canvas.h" | 17 #include "ui/gfx/canvas.h" |
18 #include "ui/gfx/insets.h" | 18 #include "ui/gfx/insets.h" |
19 #include "ui/gfx/render_text.h" | |
19 #include "views/background.h" | 20 #include "views/background.h" |
20 #include "views/border.h" | 21 #include "views/border.h" |
21 #include "views/controls/focusable_border.h" | 22 #include "views/controls/focusable_border.h" |
22 #include "views/controls/menu/menu_item_view.h" | 23 #include "views/controls/menu/menu_item_view.h" |
23 #include "views/controls/menu/menu_model_adapter.h" | 24 #include "views/controls/menu/menu_model_adapter.h" |
24 #include "views/controls/textfield/text_style.h" | |
25 #include "views/controls/textfield/textfield.h" | 25 #include "views/controls/textfield/textfield.h" |
26 #include "views/controls/textfield/textfield_controller.h" | 26 #include "views/controls/textfield/textfield_controller.h" |
27 #include "views/controls/textfield/textfield_views_model.h" | 27 #include "views/controls/textfield/textfield_views_model.h" |
28 #include "views/events/event.h" | 28 #include "views/events/event.h" |
29 #include "views/ime/input_method.h" | 29 #include "views/ime/input_method.h" |
30 #include "views/metrics.h" | 30 #include "views/metrics.h" |
31 #include "views/views_delegate.h" | 31 #include "views/views_delegate.h" |
32 #include "views/widget/widget.h" | 32 #include "views/widget/widget.h" |
33 | 33 |
34 #if defined(OS_LINUX) | 34 #if defined(OS_LINUX) |
35 #include "ui/gfx/gtk_util.h" | 35 #include "ui/gfx/gtk_util.h" |
36 #endif | 36 #endif |
37 | 37 |
38 namespace { | 38 namespace { |
39 | 39 |
40 // Color settings for text, backgrounds and cursor. | |
41 // These are tentative, and should be derived from theme, system | |
42 // settings and current settings. | |
43 // TODO(oshima): Change this to match the standard chrome | |
44 // before dogfooding textfield views. | |
45 const SkColor kSelectedTextColor = SK_ColorWHITE; | |
46 const SkColor kFocusedSelectionColor = SK_ColorCYAN; | |
47 const SkColor kUnfocusedSelectionColor = SK_ColorLTGRAY; | |
48 const SkColor kCursorColor = SK_ColorBLACK; | |
49 | |
50 // Parameters to control cursor blinking. | 40 // Parameters to control cursor blinking. |
51 const int kCursorVisibleTimeMs = 800; | 41 const int kCursorVisibleTimeMs = 800; |
52 const int kCursorInvisibleTimeMs = 500; | 42 const int kCursorInvisibleTimeMs = 500; |
53 | 43 |
54 } // namespace | 44 } // namespace |
55 | 45 |
56 namespace views { | 46 namespace views { |
57 | 47 |
58 const char NativeTextfieldViews::kViewClassName[] = | 48 const char NativeTextfieldViews::kViewClassName[] = |
59 "views/NativeTextfieldViews"; | 49 "views/NativeTextfieldViews"; |
60 | 50 |
61 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) | 51 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) |
62 : textfield_(parent), | 52 : textfield_(parent), |
63 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))), | 53 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))), |
64 text_border_(new FocusableBorder()), | 54 text_border_(new FocusableBorder()), |
65 text_offset_(0), | |
66 insert_(true), | |
67 is_cursor_visible_(false), | 55 is_cursor_visible_(false), |
68 skip_input_method_cancel_composition_(false), | 56 skip_input_method_cancel_composition_(false), |
69 initiating_drag_(false), | 57 initiating_drag_(false), |
70 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)), | 58 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)), |
71 aggregated_clicks_(0), | 59 aggregated_clicks_(0), |
72 last_click_time_(base::Time::FromInternalValue(0)), | 60 last_click_time_(base::Time::FromInternalValue(0)), |
73 last_click_location_(0, 0) { | 61 last_click_location_(0, 0) { |
74 set_border(text_border_); | 62 set_border(text_border_); |
75 | 63 |
76 // Lowercase is not supported. | 64 // Lowercase is not supported. |
77 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); | 65 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); |
78 | 66 |
67 // Set the default text style. | |
68 gfx::StyleRange default_style; | |
69 default_style.font = textfield_->font(); | |
70 default_style.foreground = textfield_->text_color(); | |
71 GetRenderText()->set_default_style(default_style); | |
72 | |
79 set_context_menu_controller(this); | 73 set_context_menu_controller(this); |
80 set_drag_controller(this); | 74 set_drag_controller(this); |
81 } | 75 } |
82 | 76 |
83 NativeTextfieldViews::~NativeTextfieldViews() { | 77 NativeTextfieldViews::~NativeTextfieldViews() { |
84 } | 78 } |
85 | 79 |
86 //////////////////////////////////////////////////////////////////////////////// | 80 //////////////////////////////////////////////////////////////////////////////// |
87 // NativeTextfieldViews, View overrides: | 81 // NativeTextfieldViews, View overrides: |
88 | 82 |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) { | 166 bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) { |
173 return textfield_->IsEnabled() && !textfield_->read_only() && | 167 return textfield_->IsEnabled() && !textfield_->read_only() && |
174 data.HasString(); | 168 data.HasString(); |
175 } | 169 } |
176 | 170 |
177 int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) { | 171 int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) { |
178 DCHECK(CanDrop(event.data())); | 172 DCHECK(CanDrop(event.data())); |
179 bool is_point_in_selection = IsPointInSelection(event.location()); | 173 bool is_point_in_selection = IsPointInSelection(event.location()); |
180 is_drop_cursor_visible_ = !is_point_in_selection; | 174 is_drop_cursor_visible_ = !is_point_in_selection; |
181 // TODO(msw): Pan over text when the user drags to the visible text edge. | 175 // TODO(msw): Pan over text when the user drags to the visible text edge. |
182 UpdateCursorBoundsAndTextOffset(FindCursorPosition(event.location()), true); | 176 size_t cursor_pos = GetRenderText()->FindCursorPosition(event.location()); |
177 OnCaretBoundsChanged(); | |
183 SchedulePaint(); | 178 SchedulePaint(); |
184 | 179 |
185 if (initiating_drag_) { | 180 if (initiating_drag_) { |
186 if (is_point_in_selection) | 181 if (is_point_in_selection) |
187 return ui::DragDropTypes::DRAG_NONE; | 182 return ui::DragDropTypes::DRAG_NONE; |
188 return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY : | 183 return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY : |
189 ui::DragDropTypes::DRAG_MOVE; | 184 ui::DragDropTypes::DRAG_MOVE; |
190 } | 185 } |
191 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE; | 186 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE; |
192 } | 187 } |
193 | 188 |
194 int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) { | 189 int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) { |
195 DCHECK(CanDrop(event.data())); | 190 DCHECK(CanDrop(event.data())); |
196 DCHECK(!initiating_drag_ || !IsPointInSelection(event.location())); | 191 DCHECK(!initiating_drag_ || !IsPointInSelection(event.location())); |
197 OnBeforeUserAction(); | 192 OnBeforeUserAction(); |
198 skip_input_method_cancel_composition_ = true; | 193 skip_input_method_cancel_composition_ = true; |
199 | 194 |
200 size_t drop_destination = FindCursorPosition(event.location()); | 195 size_t drop_destination = |
196 GetRenderText()->FindCursorPosition(event.location()); | |
201 string16 text; | 197 string16 text; |
202 event.data().GetString(&text); | 198 event.data().GetString(&text); |
203 | 199 |
204 // We'll delete the current selection for a drag and drop within this view. | 200 // We'll delete the current selection for a drag and drop within this view. |
205 bool move = initiating_drag_ && !event.IsControlDown() && | 201 bool move = initiating_drag_ && !event.IsControlDown() && |
206 event.source_operations() & ui::DragDropTypes::DRAG_MOVE; | 202 event.source_operations() & ui::DragDropTypes::DRAG_MOVE; |
207 if (move) { | 203 if (move) { |
208 ui::Range selected_range; | 204 ui::Range selected_range; |
209 model_->GetSelectedRange(&selected_range); | 205 model_->GetSelectedRange(&selected_range); |
210 // Adjust the drop destination if it is on or after the current selection. | 206 // Adjust the drop destination if it is on or after the current selection. |
211 if (selected_range.GetMax() <= drop_destination) | 207 if (selected_range.GetMax() <= drop_destination) |
212 drop_destination -= selected_range.length(); | 208 drop_destination -= selected_range.length(); |
213 else if (selected_range.GetMin() <= drop_destination) | 209 else if (selected_range.GetMin() <= drop_destination) |
214 drop_destination = selected_range.GetMin(); | 210 drop_destination = selected_range.GetMin(); |
215 model_->DeleteSelectionAndInsertTextAt(text, drop_destination); | 211 model_->DeleteSelectionAndInsertTextAt(text, drop_destination); |
216 } else { | 212 } else { |
217 model_->MoveCursorTo(drop_destination, false); | 213 model_->MoveCursorTo(drop_destination, false); |
218 // Drop always inserts a text even if insert_ == false. | 214 // Drop always inserts text even if the textfield is not in insert mode. |
219 model_->InsertText(text); | 215 model_->InsertText(text); |
220 } | 216 } |
221 skip_input_method_cancel_composition_ = false; | 217 skip_input_method_cancel_composition_ = false; |
222 UpdateAfterChange(true, true); | 218 UpdateAfterChange(true, true); |
223 OnAfterUserAction(); | 219 OnAfterUserAction(); |
224 return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY; | 220 return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY; |
225 } | 221 } |
226 | 222 |
227 void NativeTextfieldViews::OnDragDone() { | 223 void NativeTextfieldViews::OnDragDone() { |
228 initiating_drag_ = false; | 224 initiating_drag_ = false; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
292 bool NativeTextfieldViews::CanStartDragForView(View* sender, | 288 bool NativeTextfieldViews::CanStartDragForView(View* sender, |
293 const gfx::Point& press_pt, | 289 const gfx::Point& press_pt, |
294 const gfx::Point& p) { | 290 const gfx::Point& p) { |
295 return IsPointInSelection(press_pt); | 291 return IsPointInSelection(press_pt); |
296 } | 292 } |
297 | 293 |
298 ///////////////////////////////////////////////////////////////// | 294 ///////////////////////////////////////////////////////////////// |
299 // NativeTextfieldViews, NativeTextifieldWrapper overrides: | 295 // NativeTextfieldViews, NativeTextifieldWrapper overrides: |
300 | 296 |
301 string16 NativeTextfieldViews::GetText() const { | 297 string16 NativeTextfieldViews::GetText() const { |
302 return model_->text(); | 298 return model_->GetText(); |
303 } | 299 } |
304 | 300 |
305 void NativeTextfieldViews::UpdateText() { | 301 void NativeTextfieldViews::UpdateText() { |
306 model_->SetText(textfield_->text()); | 302 model_->SetText(textfield_->text()); |
307 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 303 OnCaretBoundsChanged(); |
308 SchedulePaint(); | 304 SchedulePaint(); |
309 } | 305 } |
310 | 306 |
311 void NativeTextfieldViews::AppendText(const string16& text) { | 307 void NativeTextfieldViews::AppendText(const string16& text) { |
312 if (text.empty()) | 308 if (text.empty()) |
313 return; | 309 return; |
314 model_->Append(text); | 310 model_->Append(text); |
315 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 311 OnCaretBoundsChanged(); |
316 SchedulePaint(); | 312 SchedulePaint(); |
317 } | 313 } |
318 | 314 |
319 string16 NativeTextfieldViews::GetSelectedText() const { | 315 string16 NativeTextfieldViews::GetSelectedText() const { |
320 return model_->GetSelectedText(); | 316 return model_->GetSelectedText(); |
321 } | 317 } |
322 | 318 |
323 void NativeTextfieldViews::SelectAll() { | 319 void NativeTextfieldViews::SelectAll() { |
324 model_->SelectAll(); | 320 model_->SelectAll(); |
325 SchedulePaint(); | 321 SchedulePaint(); |
(...skipping 25 matching lines...) Expand all Loading... | |
351 Background::CreateSolidBackground(textfield_->background_color())); | 347 Background::CreateSolidBackground(textfield_->background_color())); |
352 SchedulePaint(); | 348 SchedulePaint(); |
353 } | 349 } |
354 | 350 |
355 void NativeTextfieldViews::UpdateReadOnly() { | 351 void NativeTextfieldViews::UpdateReadOnly() { |
356 SchedulePaint(); | 352 SchedulePaint(); |
357 OnTextInputTypeChanged(); | 353 OnTextInputTypeChanged(); |
358 } | 354 } |
359 | 355 |
360 void NativeTextfieldViews::UpdateFont() { | 356 void NativeTextfieldViews::UpdateFont() { |
361 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 357 OnCaretBoundsChanged(); |
362 } | 358 } |
363 | 359 |
364 void NativeTextfieldViews::UpdateIsPassword() { | 360 void NativeTextfieldViews::UpdateIsPassword() { |
365 model_->set_is_password(textfield_->IsPassword()); | 361 model_->set_is_password(textfield_->IsPassword()); |
366 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 362 OnCaretBoundsChanged(); |
367 SchedulePaint(); | 363 SchedulePaint(); |
368 OnTextInputTypeChanged(); | 364 OnTextInputTypeChanged(); |
369 } | 365 } |
370 | 366 |
371 void NativeTextfieldViews::UpdateEnabled() { | 367 void NativeTextfieldViews::UpdateEnabled() { |
372 SetEnabled(textfield_->IsEnabled()); | 368 SetEnabled(textfield_->IsEnabled()); |
373 SchedulePaint(); | 369 SchedulePaint(); |
374 OnTextInputTypeChanged(); | 370 OnTextInputTypeChanged(); |
375 } | 371 } |
376 | 372 |
377 gfx::Insets NativeTextfieldViews::CalculateInsets() { | 373 gfx::Insets NativeTextfieldViews::CalculateInsets() { |
378 return GetInsets(); | 374 return GetInsets(); |
379 } | 375 } |
380 | 376 |
381 void NativeTextfieldViews::UpdateHorizontalMargins() { | 377 void NativeTextfieldViews::UpdateHorizontalMargins() { |
382 int left, right; | 378 int left, right; |
383 if (!textfield_->GetHorizontalMargins(&left, &right)) | 379 if (!textfield_->GetHorizontalMargins(&left, &right)) |
384 return; | 380 return; |
385 gfx::Insets inset = GetInsets(); | 381 gfx::Insets inset = GetInsets(); |
386 | 382 |
387 text_border_->SetInsets(inset.top(), left, inset.bottom(), right); | 383 text_border_->SetInsets(inset.top(), left, inset.bottom(), right); |
388 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 384 OnCaretBoundsChanged(); |
389 } | 385 } |
390 | 386 |
391 void NativeTextfieldViews::UpdateVerticalMargins() { | 387 void NativeTextfieldViews::UpdateVerticalMargins() { |
392 int top, bottom; | 388 int top, bottom; |
393 if (!textfield_->GetVerticalMargins(&top, &bottom)) | 389 if (!textfield_->GetVerticalMargins(&top, &bottom)) |
394 return; | 390 return; |
395 gfx::Insets inset = GetInsets(); | 391 gfx::Insets inset = GetInsets(); |
396 | |
397 text_border_->SetInsets(top, inset.left(), bottom, inset.right()); | 392 text_border_->SetInsets(top, inset.left(), bottom, inset.right()); |
398 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 393 OnCaretBoundsChanged(); |
399 } | 394 } |
400 | 395 |
401 bool NativeTextfieldViews::SetFocus() { | 396 bool NativeTextfieldViews::SetFocus() { |
402 return false; | 397 return false; |
403 } | 398 } |
404 | 399 |
405 View* NativeTextfieldViews::GetView() { | 400 View* NativeTextfieldViews::GetView() { |
406 return this; | 401 return this; |
407 } | 402 } |
408 | 403 |
409 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const { | 404 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const { |
410 NOTREACHED(); | 405 NOTREACHED(); |
411 return NULL; | 406 return NULL; |
412 } | 407 } |
413 | 408 |
414 bool NativeTextfieldViews::IsIMEComposing() const { | 409 bool NativeTextfieldViews::IsIMEComposing() const { |
415 return model_->HasCompositionText(); | 410 return model_->HasCompositionText(); |
416 } | 411 } |
417 | 412 |
418 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { | 413 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { |
419 model_->GetSelectedRange(range); | 414 model_->GetSelectedRange(range); |
420 } | 415 } |
421 | 416 |
422 void NativeTextfieldViews::SelectRange(const ui::Range& range) { | 417 void NativeTextfieldViews::SelectRange(const ui::Range& range) { |
423 model_->SelectRange(range); | 418 model_->SelectRange(range); |
424 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 419 OnCaretBoundsChanged(); |
425 SchedulePaint(); | 420 SchedulePaint(); |
426 } | 421 } |
427 | 422 |
428 size_t NativeTextfieldViews::GetCursorPosition() const { | 423 size_t NativeTextfieldViews::GetCursorPosition() const { |
429 return model_->cursor_pos(); | 424 return model_->GetCursorPosition(); |
430 } | 425 } |
431 | 426 |
432 bool NativeTextfieldViews::HandleKeyPressed(const KeyEvent& e) { | 427 bool NativeTextfieldViews::HandleKeyPressed(const KeyEvent& e) { |
433 TextfieldController* controller = textfield_->GetController(); | 428 TextfieldController* controller = textfield_->GetController(); |
434 bool handled = false; | 429 bool handled = false; |
435 if (controller) | 430 if (controller) |
436 handled = controller->HandleKeyEvent(textfield_, e); | 431 handled = controller->HandleKeyEvent(textfield_, e); |
437 return handled || HandleKeyEvent(e); | 432 return handled || HandleKeyEvent(e); |
438 } | 433 } |
439 | 434 |
440 bool NativeTextfieldViews::HandleKeyReleased(const KeyEvent& e) { | 435 bool NativeTextfieldViews::HandleKeyReleased(const KeyEvent& e) { |
441 return true; | 436 return true; |
442 } | 437 } |
443 | 438 |
444 void NativeTextfieldViews::HandleFocus() { | 439 void NativeTextfieldViews::HandleFocus() { |
440 GetRenderText()->set_focused(true); | |
445 is_cursor_visible_ = true; | 441 is_cursor_visible_ = true; |
446 SchedulePaint(); | 442 SchedulePaint(); |
447 OnCaretBoundsChanged(); | 443 OnCaretBoundsChanged(); |
448 // Start blinking cursor. | 444 // Start blinking cursor. |
449 MessageLoop::current()->PostDelayedTask( | 445 MessageLoop::current()->PostDelayedTask( |
450 FROM_HERE, | 446 FROM_HERE, |
451 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), | 447 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), |
452 kCursorVisibleTimeMs); | 448 kCursorVisibleTimeMs); |
453 } | 449 } |
454 | 450 |
455 void NativeTextfieldViews::HandleBlur() { | 451 void NativeTextfieldViews::HandleBlur() { |
452 GetRenderText()->set_focused(false); | |
456 // Stop blinking cursor. | 453 // Stop blinking cursor. |
457 cursor_timer_.RevokeAll(); | 454 cursor_timer_.RevokeAll(); |
458 if (is_cursor_visible_) { | 455 if (is_cursor_visible_) { |
459 is_cursor_visible_ = false; | 456 is_cursor_visible_ = false; |
460 RepaintCursor(); | 457 RepaintCursor(); |
461 } | 458 } |
462 } | 459 } |
463 | 460 |
464 TextInputClient* NativeTextfieldViews::GetTextInputClient() { | 461 TextInputClient* NativeTextfieldViews::GetTextInputClient() { |
465 return textfield_->read_only() ? NULL : this; | 462 return textfield_->read_only() ? NULL : this; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
529 default: | 526 default: |
530 NOTREACHED() << "unknown command: " << command_id; | 527 NOTREACHED() << "unknown command: " << command_id; |
531 break; | 528 break; |
532 } | 529 } |
533 | 530 |
534 // The cursor must have changed if text changed during cut/paste/delete. | 531 // The cursor must have changed if text changed during cut/paste/delete. |
535 UpdateAfterChange(text_changed, text_changed); | 532 UpdateAfterChange(text_changed, text_changed); |
536 OnAfterUserAction(); | 533 OnAfterUserAction(); |
537 } | 534 } |
538 | 535 |
539 TextStyle* NativeTextfieldViews::CreateTextStyle() { | 536 void NativeTextfieldViews::ApplyStyleRange(const gfx::StyleRange& style) { |
540 return model_->CreateTextStyle(); | 537 GetRenderText()->ApplyStyleRange(style); |
541 } | |
542 | |
543 void NativeTextfieldViews::ApplyTextStyle(const TextStyle* style, | |
544 const ui::Range& range) { | |
545 model_->ApplyTextStyle(style, range); | |
546 SchedulePaint(); | 538 SchedulePaint(); |
547 } | 539 } |
548 | 540 |
549 void NativeTextfieldViews::ClearAllTextStyles() { | 541 void NativeTextfieldViews::ApplyDefaultStyle() { |
550 model_->ClearAllTextStyles(); | 542 GetRenderText()->ApplyDefaultStyle(); |
551 SchedulePaint(); | 543 SchedulePaint(); |
552 } | 544 } |
553 | 545 |
554 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { | 546 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { |
555 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 547 // Set the RenderText display area. |
548 gfx::Insets insets = GetInsets(); | |
549 gfx::Rect display_rect(insets.left(), | |
550 insets.top(), | |
551 width() - insets.width(), | |
552 height() - insets.height()); | |
553 GetRenderText()->set_display_rect(display_rect); | |
554 OnCaretBoundsChanged(); | |
556 } | 555 } |
557 | 556 |
558 /////////////////////////////////////////////////////////////////////////////// | 557 /////////////////////////////////////////////////////////////////////////////// |
559 // NativeTextfieldViews, TextInputClient implementation, private: | 558 // NativeTextfieldViews, TextInputClient implementation, private: |
560 | 559 |
561 void NativeTextfieldViews::SetCompositionText( | 560 void NativeTextfieldViews::SetCompositionText( |
562 const ui::CompositionText& composition) { | 561 const ui::CompositionText& composition) { |
563 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) | 562 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) |
564 return; | 563 return; |
565 | 564 |
(...skipping 29 matching lines...) Expand all Loading... | |
595 OnAfterUserAction(); | 594 OnAfterUserAction(); |
596 } | 595 } |
597 | 596 |
598 void NativeTextfieldViews::InsertText(const string16& text) { | 597 void NativeTextfieldViews::InsertText(const string16& text) { |
599 // TODO(suzhe): Filter invalid characters. | 598 // TODO(suzhe): Filter invalid characters. |
600 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty()) | 599 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty()) |
601 return; | 600 return; |
602 | 601 |
603 OnBeforeUserAction(); | 602 OnBeforeUserAction(); |
604 skip_input_method_cancel_composition_ = true; | 603 skip_input_method_cancel_composition_ = true; |
605 if (insert_) | 604 if (GetRenderText()->get_insert_mode()) |
606 model_->InsertText(text); | 605 model_->InsertText(text); |
607 else | 606 else |
608 model_->ReplaceText(text); | 607 model_->ReplaceText(text); |
609 skip_input_method_cancel_composition_ = false; | 608 skip_input_method_cancel_composition_ = false; |
610 UpdateAfterChange(true, true); | 609 UpdateAfterChange(true, true); |
611 OnAfterUserAction(); | 610 OnAfterUserAction(); |
612 } | 611 } |
613 | 612 |
614 void NativeTextfieldViews::InsertChar(char16 ch, int flags) { | 613 void NativeTextfieldViews::InsertChar(char16 ch, int flags) { |
615 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || | 614 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || |
616 !ShouldInsertChar(ch, flags)) { | 615 !ShouldInsertChar(ch, flags)) { |
617 return; | 616 return; |
618 } | 617 } |
619 | 618 |
620 OnBeforeUserAction(); | 619 OnBeforeUserAction(); |
621 skip_input_method_cancel_composition_ = true; | 620 skip_input_method_cancel_composition_ = true; |
622 if (insert_) | 621 if (GetRenderText()->get_insert_mode()) |
623 model_->InsertChar(ch); | 622 model_->InsertChar(ch); |
624 else | 623 else |
625 model_->ReplaceChar(ch); | 624 model_->ReplaceChar(ch); |
626 skip_input_method_cancel_composition_ = false; | 625 skip_input_method_cancel_composition_ = false; |
627 UpdateAfterChange(true, true); | 626 UpdateAfterChange(true, true); |
628 OnAfterUserAction(); | 627 OnAfterUserAction(); |
629 } | 628 } |
630 | 629 |
631 ui::TextInputType NativeTextfieldViews::GetTextInputType() { | 630 ui::TextInputType NativeTextfieldViews::GetTextInputType() { |
632 if (textfield_->read_only() || !textfield_->IsEnabled()) | 631 if (textfield_->read_only() || !textfield_->IsEnabled()) |
633 return ui::TEXT_INPUT_TYPE_NONE; | 632 return ui::TEXT_INPUT_TYPE_NONE; |
634 else if (textfield_->IsPassword()) | 633 else if (textfield_->IsPassword()) |
635 return ui::TEXT_INPUT_TYPE_PASSWORD; | 634 return ui::TEXT_INPUT_TYPE_PASSWORD; |
636 return ui::TEXT_INPUT_TYPE_TEXT; | 635 return ui::TEXT_INPUT_TYPE_TEXT; |
637 } | 636 } |
638 | 637 |
639 gfx::Rect NativeTextfieldViews::GetCaretBounds() { | 638 gfx::Rect NativeTextfieldViews::GetCaretBounds() { |
640 return cursor_bounds_; | 639 gfx::RenderText* render_text = GetRenderText(); |
640 return render_text->GetCursorBounds(render_text->GetCursor(), | |
641 render_text->get_insert_mode()); | |
641 } | 642 } |
642 | 643 |
643 bool NativeTextfieldViews::HasCompositionText() { | 644 bool NativeTextfieldViews::HasCompositionText() { |
644 return model_->HasCompositionText(); | 645 return model_->HasCompositionText(); |
645 } | 646 } |
646 | 647 |
647 bool NativeTextfieldViews::GetTextRange(ui::Range* range) { | 648 bool NativeTextfieldViews::GetTextRange(ui::Range* range) { |
648 // We don't allow the input method to retrieve or delete content from a | 649 // We don't allow the input method to retrieve or delete content from a |
649 // password box. | 650 // password box. |
650 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT) | 651 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT) |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
718 return textfield_; | 719 return textfield_; |
719 } | 720 } |
720 | 721 |
721 void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() { | 722 void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() { |
722 if (skip_input_method_cancel_composition_) | 723 if (skip_input_method_cancel_composition_) |
723 return; | 724 return; |
724 DCHECK(textfield_->GetInputMethod()); | 725 DCHECK(textfield_->GetInputMethod()); |
725 textfield_->GetInputMethod()->CancelComposition(textfield_); | 726 textfield_->GetInputMethod()->CancelComposition(textfield_); |
726 } | 727 } |
727 | 728 |
728 const gfx::Font& NativeTextfieldViews::GetFont() const { | 729 gfx::RenderText* NativeTextfieldViews::GetRenderText() const { |
729 return textfield_->font(); | 730 return model_->get_render_text(); |
730 } | |
731 | |
732 SkColor NativeTextfieldViews::GetTextColor() const { | |
733 return textfield_->text_color(); | |
734 } | 731 } |
735 | 732 |
736 void NativeTextfieldViews::UpdateCursor() { | 733 void NativeTextfieldViews::UpdateCursor() { |
737 is_cursor_visible_ = !is_cursor_visible_; | 734 is_cursor_visible_ = !is_cursor_visible_; |
738 RepaintCursor(); | 735 RepaintCursor(); |
739 MessageLoop::current()->PostDelayedTask( | 736 MessageLoop::current()->PostDelayedTask( |
740 FROM_HERE, | 737 FROM_HERE, |
741 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), | 738 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), |
742 is_cursor_visible_ ? kCursorVisibleTimeMs : kCursorInvisibleTimeMs); | 739 is_cursor_visible_ ? kCursorVisibleTimeMs : kCursorInvisibleTimeMs); |
743 } | 740 } |
744 | 741 |
745 void NativeTextfieldViews::RepaintCursor() { | 742 void NativeTextfieldViews::RepaintCursor() { |
746 gfx::Rect r = cursor_bounds_; | 743 gfx::Rect r(GetCaretBounds()); |
747 r.Inset(-1, -1, -1, -1); | 744 r.Inset(-1, -1, -1, -1); |
748 SchedulePaintInRect(r); | 745 SchedulePaintInRect(r); |
749 } | 746 } |
750 | 747 |
751 gfx::Rect NativeTextfieldViews::GetCursorBounds(size_t cursor_pos, | |
752 bool insert_mode) const { | |
753 string16 text = model_->GetVisibleText(); | |
754 const gfx::Font& font = GetFont(); | |
755 int x = font.GetStringWidth(text.substr(0U, cursor_pos)); | |
756 DCHECK_GE(x, 0); | |
757 int h = std::min(height() - GetInsets().height(), font.GetHeight()); | |
758 gfx::Rect bounds(x, (height() - h) / 2, 0, h); | |
759 if (!insert_mode && text.length() != cursor_pos) | |
760 bounds.set_width(font.GetStringWidth(text.substr(0, cursor_pos + 1)) - x); | |
761 return bounds; | |
762 } | |
763 | |
764 | |
765 void NativeTextfieldViews::UpdateCursorBoundsAndTextOffset(size_t cursor_pos, | |
766 bool insert_mode) { | |
767 if (bounds().IsEmpty()) | |
768 return; | |
769 | |
770 // TODO(oshima): bidi | |
771 int width = bounds().width() - GetInsets().width(); | |
772 int full_width = GetFont().GetStringWidth(model_->GetVisibleText()); | |
773 cursor_bounds_ = GetCursorBounds(cursor_pos, insert_mode); | |
774 | |
775 if (full_width < width) { | |
776 // Show all text whenever the text fits to the size. | |
777 text_offset_ = 0; | |
778 } else if ((text_offset_ + cursor_bounds_.right()) > width) { | |
779 // when the cursor overflows to the right | |
780 text_offset_ = width - cursor_bounds_.right(); | |
781 } else if ((text_offset_ + cursor_bounds_.x()) < 0) { | |
782 // when the cursor overflows to the left | |
783 text_offset_ = -cursor_bounds_.x(); | |
784 } else if (full_width > width && text_offset_ + full_width < width) { | |
785 // when the cursor moves within the textfield with the text | |
786 // longer than the field. | |
787 text_offset_ = width - full_width; | |
788 } else { | |
789 // move cursor freely. | |
790 } | |
791 // shift cursor bounds to fit insets. | |
792 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + GetInsets().left()); | |
793 | |
794 OnCaretBoundsChanged(); | |
795 } | |
796 | |
797 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { | 748 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { |
798 gfx::Insets insets = GetInsets(); | |
799 | |
800 canvas->Save(); | 749 canvas->Save(); |
801 canvas->ClipRectInt(insets.left(), insets.top(), | 750 GetRenderText()->set_cursor_visible(is_drop_cursor_visible_ || |
802 width() - insets.width(), height() - insets.height()); | 751 (is_cursor_visible_ && !model_->HasSelection())); |
803 | 752 // Draw the text, cursor, and selection. |
804 // TODO(oshima): bidi support | 753 GetRenderText()->Draw(canvas); |
805 // TODO(varunjain): re-implement this so only that dirty text is painted. | |
806 TextfieldViewsModel::TextFragments fragments; | |
807 model_->GetFragments(&fragments); | |
808 int x_offset = text_offset_ + insets.left(); | |
809 int y = insets.top(); | |
810 int text_height = height() - insets.height(); | |
811 SkColor selection_color = | |
812 textfield_->HasFocus() ? | |
813 kFocusedSelectionColor : kUnfocusedSelectionColor; | |
814 gfx::Font font = GetFont(); | |
815 gfx::Rect selection_bounds = model_->GetSelectionBounds(font); | |
816 | |
817 if (!selection_bounds.IsEmpty()) { | |
818 canvas->FillRectInt(selection_color, | |
819 x_offset + selection_bounds.x(), | |
820 (height() - selection_bounds.height()) / 2, | |
821 selection_bounds.width(), | |
822 selection_bounds.height()); | |
823 } | |
824 | |
825 for (TextfieldViewsModel::TextFragments::const_iterator iter = | |
826 fragments.begin(); | |
827 iter != fragments.end(); | |
828 iter++) { | |
829 string16 text = model_->GetVisibleText(iter->range.start(), | |
830 iter->range.end()); | |
831 // TODO(oshima): This does not give the accurate position due to | |
832 // kerning. Figure out how to do. | |
833 int width = font.GetStringWidth(text); | |
834 iter->style->DrawString(canvas, text, font, textfield_->read_only(), | |
835 x_offset, y, width, text_height); | |
836 x_offset += width; | |
837 } | |
838 canvas->Restore(); | 754 canvas->Restore(); |
839 | |
840 // Paint cursor. Replace cursor is drawn as rectangle for now. | |
841 if (textfield_->IsEnabled() && (is_drop_cursor_visible_ || | |
842 (is_cursor_visible_ && !model_->HasSelection()))) | |
843 canvas->DrawRectInt(kCursorColor, | |
844 cursor_bounds_.x(), | |
845 cursor_bounds_.y(), | |
846 cursor_bounds_.width(), | |
847 cursor_bounds_.height()); | |
848 } | 755 } |
849 | 756 |
850 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { | 757 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { |
851 // TODO(oshima): Refactor and consolidate with ExecuteCommand. | 758 // TODO(oshima): Refactor and consolidate with ExecuteCommand. |
852 if (key_event.type() == ui::ET_KEY_PRESSED) { | 759 if (key_event.type() == ui::ET_KEY_PRESSED) { |
853 ui::KeyboardCode key_code = key_event.key_code(); | 760 ui::KeyboardCode key_code = key_event.key_code(); |
854 // TODO(oshima): shift-tab does not work. Figure out why and fix. | 761 // TODO(oshima): shift-tab does not work. Figure out why and fix. |
855 if (key_code == ui::VKEY_TAB) | 762 if (key_code == ui::VKEY_TAB) |
856 return false; | 763 return false; |
857 | 764 |
(...skipping 24 matching lines...) Expand all Loading... | |
882 break; | 789 break; |
883 case ui::VKEY_C: | 790 case ui::VKEY_C: |
884 if (control) | 791 if (control) |
885 model_->Copy(); | 792 model_->Copy(); |
886 break; | 793 break; |
887 case ui::VKEY_V: | 794 case ui::VKEY_V: |
888 if (control && editable) | 795 if (control && editable) |
889 cursor_changed = text_changed = Paste(); | 796 cursor_changed = text_changed = Paste(); |
890 break; | 797 break; |
891 case ui::VKEY_RIGHT: | 798 case ui::VKEY_RIGHT: |
892 control ? model_->MoveCursorToNextWord(selection) | 799 control ? model_->MoveCursorRightByWord(selection) |
893 : model_->MoveCursorRight(selection); | 800 : model_->MoveCursorRight(selection); |
894 cursor_changed = true; | 801 cursor_changed = true; |
895 break; | 802 break; |
896 case ui::VKEY_LEFT: | 803 case ui::VKEY_LEFT: |
897 control ? model_->MoveCursorToPreviousWord(selection) | 804 control ? model_->MoveCursorLeftByWord(selection) |
898 : model_->MoveCursorLeft(selection); | 805 : model_->MoveCursorLeft(selection); |
899 cursor_changed = true; | 806 cursor_changed = true; |
900 break; | 807 break; |
901 case ui::VKEY_END: | 808 case ui::VKEY_END: |
902 model_->MoveCursorToEnd(selection); | 809 model_->MoveCursorToRightEnd(selection); |
903 cursor_changed = true; | 810 cursor_changed = true; |
904 break; | 811 break; |
905 case ui::VKEY_HOME: | 812 case ui::VKEY_HOME: |
906 model_->MoveCursorToHome(selection); | 813 model_->MoveCursorToLeftEnd(selection); |
907 cursor_changed = true; | 814 cursor_changed = true; |
908 break; | 815 break; |
909 case ui::VKEY_BACK: | 816 case ui::VKEY_BACK: |
910 if (!editable) | 817 if (!editable) |
911 break; | 818 break; |
912 if (!model_->HasSelection()) { | 819 if (!model_->HasSelection()) { |
913 if (selection && control) { | 820 if (selection && control) { |
914 // If both shift and control are pressed, then erase upto the | 821 // If both shift and control are pressed, then erase upto the |
915 // beginning of the buffer in ChromeOS. In windows, do nothing. | 822 // beginning of the buffer in ChromeOS. In windows, do nothing. |
916 #if defined(OS_WIN) | 823 #if defined(OS_WIN) |
917 break; | 824 break; |
918 #else | 825 #else |
919 model_->MoveCursorToHome(true); | 826 model_->MoveCursorToLeftEnd(true); |
920 #endif | 827 #endif |
921 } else if (control) { | 828 } else if (control) { |
922 // If only control is pressed, then erase the previous word. | 829 // If only control is pressed, then erase the previous word. |
923 model_->MoveCursorToPreviousWord(true); | 830 model_->MoveCursorLeftByWord(true); |
924 } | 831 } |
925 } | 832 } |
926 text_changed = model_->Backspace(); | 833 text_changed = model_->Backspace(); |
927 cursor_changed = true; | 834 cursor_changed = true; |
928 break; | 835 break; |
929 case ui::VKEY_DELETE: | 836 case ui::VKEY_DELETE: |
930 if (!editable) | 837 if (!editable) |
931 break; | 838 break; |
932 if (!model_->HasSelection()) { | 839 if (!model_->HasSelection()) { |
933 if (selection && control) { | 840 if (selection && control) { |
934 // If both shift and control are pressed, then erase upto the | 841 // If both shift and control are pressed, then erase upto the |
935 // end of the buffer in ChromeOS. In windows, do nothing. | 842 // end of the buffer in ChromeOS. In windows, do nothing. |
936 #if defined(OS_WIN) | 843 #if defined(OS_WIN) |
937 break; | 844 break; |
938 #else | 845 #else |
939 model_->MoveCursorToEnd(true); | 846 model_->MoveCursorToRightEnd(true); |
940 #endif | 847 #endif |
941 } else if (control) { | 848 } else if (control) { |
942 // If only control is pressed, then erase the next word. | 849 // If only control is pressed, then erase the next word. |
943 model_->MoveCursorToNextWord(true); | 850 model_->MoveCursorRightByWord(true); |
944 } | 851 } |
945 } | 852 } |
946 cursor_changed = text_changed = model_->Delete(); | 853 cursor_changed = text_changed = model_->Delete(); |
947 break; | 854 break; |
948 case ui::VKEY_INSERT: | 855 case ui::VKEY_INSERT: |
949 insert_ = !insert_; | 856 GetRenderText()->set_insert_mode(!GetRenderText()->get_insert_mode()); |
oshima
2011/07/15 21:21:36
may be flip_insert_mode() is simpler.
msw
2011/07/19 07:11:22
Done.
| |
950 cursor_changed = true; | 857 cursor_changed = true; |
951 break; | 858 break; |
952 default: | 859 default: |
953 break; | 860 break; |
954 } | 861 } |
955 | 862 |
956 // We must have input method in order to support text input. | 863 // We must have input method in order to support text input. |
957 DCHECK(textfield_->GetInputMethod()); | 864 DCHECK(textfield_->GetInputMethod()); |
958 | 865 |
959 UpdateAfterChange(text_changed, cursor_changed); | 866 UpdateAfterChange(text_changed, cursor_changed); |
960 OnAfterUserAction(); | 867 OnAfterUserAction(); |
961 return (text_changed || cursor_changed); | 868 return (text_changed || cursor_changed); |
962 } | 869 } |
963 return false; | 870 return false; |
964 } | 871 } |
965 | 872 |
966 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { | |
967 // TODO(oshima): BIDI/i18n support. | |
968 gfx::Font font = GetFont(); | |
969 gfx::Insets insets = GetInsets(); | |
970 string16 text = model_->GetVisibleText(); | |
971 int left = 0; | |
972 int left_pos = 0; | |
973 int right = font.GetStringWidth(text); | |
974 int right_pos = text.length(); | |
975 | |
976 int x = point.x() - insets.left() - text_offset_; | |
977 if (x <= left) return left_pos; | |
978 if (x >= right) return right_pos; | |
979 // binary searching the cursor position. | |
980 // TODO(oshima): use the center of character instead of edge. | |
981 // Binary search may not work for language like arabic. | |
982 while (std::abs(static_cast<long>(right_pos - left_pos) > 1)) { | |
983 int pivot_pos = left_pos + (right_pos - left_pos) / 2; | |
984 int pivot = font.GetStringWidth(text.substr(0, pivot_pos)); | |
985 if (pivot < x) { | |
986 left = pivot; | |
987 left_pos = pivot_pos; | |
988 } else if (pivot == x) { | |
989 return pivot_pos; | |
990 } else { | |
991 right = pivot; | |
992 right_pos = pivot_pos; | |
993 } | |
994 } | |
995 return left_pos; | |
996 } | |
997 | |
998 bool NativeTextfieldViews::IsPointInSelection(const gfx::Point& point) const { | 873 bool NativeTextfieldViews::IsPointInSelection(const gfx::Point& point) const { |
999 ui::Range range; | 874 ui::Range range; |
1000 GetSelectedRange(&range); | 875 GetSelectedRange(&range); |
1001 size_t pos = FindCursorPosition(point); | 876 size_t pos = GetRenderText()->FindCursorPosition(point); |
1002 return (pos >= range.GetMin() && pos < range.GetMax()); | 877 return (pos >= range.GetMin() && pos < range.GetMax()); |
1003 } | 878 } |
1004 | 879 |
1005 bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) { | 880 bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) { |
1006 size_t pos = FindCursorPosition(point); | 881 size_t pos = GetRenderText()->FindCursorPosition(point); |
1007 if (model_->MoveCursorTo(pos, select)) { | 882 if (model_->MoveCursorTo(pos, select)) { |
1008 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 883 OnCaretBoundsChanged(); |
1009 return true; | 884 return true; |
1010 } | 885 } |
1011 return false; | 886 return false; |
1012 } | 887 } |
1013 | 888 |
1014 void NativeTextfieldViews::PropagateTextChange() { | 889 void NativeTextfieldViews::PropagateTextChange() { |
1015 textfield_->SyncText(); | 890 textfield_->SyncText(); |
1016 } | 891 } |
1017 | 892 |
1018 void NativeTextfieldViews::UpdateAfterChange(bool text_changed, | 893 void NativeTextfieldViews::UpdateAfterChange(bool text_changed, |
1019 bool cursor_changed) { | 894 bool cursor_changed) { |
1020 if (text_changed) | 895 if (text_changed) |
1021 PropagateTextChange(); | 896 PropagateTextChange(); |
1022 if (cursor_changed) { | 897 if (cursor_changed) { |
1023 is_cursor_visible_ = true; | 898 is_cursor_visible_ = true; |
1024 RepaintCursor(); | 899 RepaintCursor(); |
1025 } | 900 } |
1026 if (text_changed || cursor_changed) { | 901 if (text_changed || cursor_changed) { |
1027 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); | 902 OnCaretBoundsChanged(); |
1028 SchedulePaint(); | 903 SchedulePaint(); |
1029 } | 904 } |
1030 } | 905 } |
1031 | 906 |
1032 void NativeTextfieldViews::UpdateContextMenu() { | 907 void NativeTextfieldViews::UpdateContextMenu() { |
1033 if (!context_menu_contents_.get()) { | 908 if (!context_menu_contents_.get()) { |
1034 context_menu_contents_.reset(new ui::SimpleMenuModel(this)); | 909 context_menu_contents_.reset(new ui::SimpleMenuModel(this)); |
1035 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); | 910 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); |
1036 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); | 911 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); |
1037 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); | 912 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1071 TextfieldController* controller = textfield_->GetController(); | 946 TextfieldController* controller = textfield_->GetController(); |
1072 if (controller) | 947 if (controller) |
1073 controller->OnAfterUserAction(textfield_); | 948 controller->OnAfterUserAction(textfield_); |
1074 } | 949 } |
1075 | 950 |
1076 bool NativeTextfieldViews::Paste() { | 951 bool NativeTextfieldViews::Paste() { |
1077 const bool success = model_->Paste(); | 952 const bool success = model_->Paste(); |
1078 | 953 |
1079 // Calls TextfieldController::ContentsChanged() explicitly if the paste action | 954 // Calls TextfieldController::ContentsChanged() explicitly if the paste action |
1080 // did not change the content at all. See http://crbug.com/79002 | 955 // did not change the content at all. See http://crbug.com/79002 |
1081 if (success && model_->text() == textfield_->text()) { | 956 if (success && GetText() == textfield_->text()) { |
1082 TextfieldController* controller = textfield_->GetController(); | 957 TextfieldController* controller = textfield_->GetController(); |
1083 if (controller) | 958 if (controller) |
1084 controller->ContentsChanged(textfield_, textfield_->text()); | 959 controller->ContentsChanged(textfield_, textfield_->text()); |
1085 } | 960 } |
1086 return success; | 961 return success; |
1087 } | 962 } |
1088 | 963 |
1089 // static | 964 // static |
1090 bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) { | 965 bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) { |
1091 // Filter out all control characters, including tab and new line characters, | 966 // Filter out all control characters, including tab and new line characters, |
1092 // and all characters with Alt modifier. But we need to allow characters with | 967 // and all characters with Alt modifier. But we need to allow characters with |
1093 // AltGr modifier. | 968 // AltGr modifier. |
1094 // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different | 969 // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different |
1095 // flag that we don't care about. | 970 // flag that we don't care about. |
1096 return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && | 971 return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && |
1097 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; | 972 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; |
1098 } | 973 } |
1099 | 974 |
1100 } // namespace views | 975 } // namespace views |
OLD | NEW |