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