Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: views/controls/textfield/native_textfield_views.cc

Issue 6982055: Draw a NativeTextfieldViews drop location cursor. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Init textfield bounds to fix NativeTextfieldViewsTest.DragAndDrop_AcceptDrop. Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 const char NativeTextfieldViews::kViewClassName[] = 60 const char NativeTextfieldViews::kViewClassName[] =
61 "views/NativeTextfieldViews"; 61 "views/NativeTextfieldViews";
62 62
63 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) 63 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
64 : textfield_(parent), 64 : textfield_(parent),
65 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))), 65 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))),
66 text_border_(new FocusableBorder()), 66 text_border_(new FocusableBorder()),
67 text_offset_(0), 67 text_offset_(0),
68 insert_(true), 68 insert_(true),
69 is_cursor_visible_(false), 69 is_cursor_visible_(false),
70 is_drop_cursor_visible_(false),
70 skip_input_method_cancel_composition_(false), 71 skip_input_method_cancel_composition_(false),
71 initiating_drag_(false), 72 initiating_drag_(false),
72 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)), 73 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)),
73 aggregated_clicks_(0), 74 aggregated_clicks_(0),
74 last_click_time_(base::Time::FromInternalValue(0)), 75 last_click_time_(base::Time::FromInternalValue(0)),
75 last_click_location_(0, 0) { 76 last_click_location_(0, 0) {
76 set_border(text_border_); 77 set_border(text_border_);
77 78
78 // Lowercase is not supported. 79 // Lowercase is not supported.
79 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); 80 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE);
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 *formats = ui::OSExchangeData::STRING; 171 *formats = ui::OSExchangeData::STRING;
171 return true; 172 return true;
172 } 173 }
173 174
174 bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) { 175 bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
175 return textfield_->IsEnabled() && !textfield_->read_only() && 176 return textfield_->IsEnabled() && !textfield_->read_only() &&
176 data.HasString(); 177 data.HasString();
177 } 178 }
178 179
179 int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) { 180 int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) {
180 // TODO(msw): retain unfocused selection, render secondary cursor...
181 DCHECK(CanDrop(event.data())); 181 DCHECK(CanDrop(event.data()));
182 bool is_point_in_selection = IsPointInSelection(event.location());
183 is_drop_cursor_visible_ = !is_point_in_selection;
184 drop_cursor_bounds_ = GetCursorBounds(FindCursorPosition(event.location()));
185 SchedulePaint();
186
182 if (initiating_drag_) { 187 if (initiating_drag_) {
183 if (IsPointInSelection(event.location())) 188 if (is_point_in_selection)
184 return ui::DragDropTypes::DRAG_NONE; 189 return ui::DragDropTypes::DRAG_NONE;
185 return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY : 190 return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
186 ui::DragDropTypes::DRAG_MOVE; 191 ui::DragDropTypes::DRAG_MOVE;
187 } 192 }
188 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE; 193 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
189 } 194 }
190 195
191 int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) { 196 int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) {
192 DCHECK(CanDrop(event.data())); 197 DCHECK(CanDrop(event.data()));
193 DCHECK(!initiating_drag_ || !IsPointInSelection(event.location())); 198 DCHECK(!initiating_drag_ || !IsPointInSelection(event.location()));
(...skipping 22 matching lines...) Expand all
216 model_->InsertText(text); 221 model_->InsertText(text);
217 } 222 }
218 skip_input_method_cancel_composition_ = false; 223 skip_input_method_cancel_composition_ = false;
219 UpdateAfterChange(true, true); 224 UpdateAfterChange(true, true);
220 OnAfterUserAction(); 225 OnAfterUserAction();
221 return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY; 226 return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
222 } 227 }
223 228
224 void NativeTextfieldViews::OnDragDone() { 229 void NativeTextfieldViews::OnDragDone() {
225 initiating_drag_ = false; 230 initiating_drag_ = false;
231 is_drop_cursor_visible_ = false;
226 } 232 }
227 233
228 void NativeTextfieldViews::OnPaint(gfx::Canvas* canvas) { 234 void NativeTextfieldViews::OnPaint(gfx::Canvas* canvas) {
229 text_border_->set_has_focus(textfield_->HasFocus()); 235 text_border_->set_has_focus(textfield_->HasFocus());
230 OnPaintBackground(canvas); 236 OnPaintBackground(canvas);
231 PaintTextAndCursor(canvas); 237 PaintTextAndCursor(canvas);
232 if (textfield_->draw_border()) 238 if (textfield_->draw_border())
233 OnPaintBorder(canvas); 239 OnPaintBorder(canvas);
234 } 240 }
235 241
(...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), 754 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor),
749 is_cursor_visible_ ? kCursorVisibleTimeMs : kCursorInvisibleTimeMs); 755 is_cursor_visible_ ? kCursorVisibleTimeMs : kCursorInvisibleTimeMs);
750 } 756 }
751 757
752 void NativeTextfieldViews::RepaintCursor() { 758 void NativeTextfieldViews::RepaintCursor() {
753 gfx::Rect r = cursor_bounds_; 759 gfx::Rect r = cursor_bounds_;
754 r.Inset(-1, -1, -1, -1); 760 r.Inset(-1, -1, -1, -1);
755 SchedulePaintInRect(r); 761 SchedulePaintInRect(r);
756 } 762 }
757 763
764 gfx::Rect NativeTextfieldViews::GetCursorBounds(size_t cursor_pos) const {
765 string16 text = model_->GetVisibleText();
766 const gfx::Font& font = GetFont();
767 int x = font.GetStringWidth(text.substr(0U, cursor_pos));
768 DCHECK(x >= 0);
oshima 2011/06/07 17:32:52 can you change to DCHECK_GE?
msw 2011/06/08 23:50:29 Done.
769 int h = std::min(height() - GetInsets().height(), font.GetHeight());
770 gfx::Rect bounds(x, (height() - h) / 2, 0, h);
771 if (text.length() != cursor_pos)
772 bounds.set_width(font.GetStringWidth(text.substr(0, cursor_pos + 1)) - x);
773 return bounds;
774 }
775
776
758 void NativeTextfieldViews::UpdateCursorBoundsAndTextOffset() { 777 void NativeTextfieldViews::UpdateCursorBoundsAndTextOffset() {
759 if (bounds().IsEmpty()) 778 if (bounds().IsEmpty())
760 return; 779 return;
761 780
762 gfx::Insets insets = GetInsets();
763
764 int width = bounds().width() - insets.width();
765
766 // TODO(oshima): bidi 781 // TODO(oshima): bidi
767 const gfx::Font& font = GetFont(); 782 int width = bounds().width() - GetInsets().width();
768 int full_width = font.GetStringWidth(model_->GetVisibleText()); 783 int full_width = GetFont().GetStringWidth(model_->GetVisibleText());
769 int cursor_height = std::min(height() - insets.height(), font.GetHeight()); 784 cursor_bounds_ = GetCursorBounds(model_->cursor_pos());
770
771 cursor_bounds_ = model_->GetCursorBounds(font);
772 cursor_bounds_.set_y((height() - cursor_height) / 2);
773 cursor_bounds_.set_height(cursor_height);
774
775 int x_right = text_offset_ + cursor_bounds_.right();
776 int x_left = text_offset_ + cursor_bounds_.x();
777 785
778 if (full_width < width) { 786 if (full_width < width) {
779 // Show all text whenever the text fits to the size. 787 // Show all text whenever the text fits to the size.
780 text_offset_ = 0; 788 text_offset_ = 0;
781 } else if (x_right > width) { 789 } else if ((text_offset_ + cursor_bounds_.right()) > width) {
782 // when the cursor overflows to the right 790 // when the cursor overflows to the right
783 text_offset_ = width - cursor_bounds_.right(); 791 text_offset_ = width - cursor_bounds_.right();
784 } else if (x_left < 0) { 792 } else if ((text_offset_ + cursor_bounds_.x()) < 0) {
785 // when the cursor overflows to the left 793 // when the cursor overflows to the left
786 text_offset_ = -cursor_bounds_.x(); 794 text_offset_ = -cursor_bounds_.x();
787 } else if (full_width > width && text_offset_ + full_width < width) { 795 } else if (full_width > width && text_offset_ + full_width < width) {
788 // when the cursor moves within the textfield with the text 796 // when the cursor moves within the textfield with the text
789 // longer than the field. 797 // longer than the field.
790 text_offset_ = width - full_width; 798 text_offset_ = width - full_width;
791 } else { 799 } else {
792 // move cursor freely. 800 // move cursor freely.
793 } 801 }
794 // shift cursor bounds to fit insets. 802 // shift cursor bounds to fit insets.
795 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + insets.left()); 803 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + GetInsets().left());
796 804
797 OnCaretBoundsChanged(); 805 OnCaretBoundsChanged();
798 } 806 }
799 807
800 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { 808 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
801 gfx::Insets insets = GetInsets(); 809 gfx::Insets insets = GetInsets();
802 810
803 canvas->Save(); 811 canvas->Save();
804 canvas->ClipRectInt(insets.left(), insets.top(), 812 canvas->ClipRectInt(insets.left(), insets.top(),
805 width() - insets.width(), height() - insets.height()); 813 width() - insets.width(), height() - insets.height());
(...skipping 26 matching lines...) Expand all
832 iter->range.end()); 840 iter->range.end());
833 // TODO(oshima): This does not give the accurate position due to 841 // TODO(oshima): This does not give the accurate position due to
834 // kerning. Figure out how to do. 842 // kerning. Figure out how to do.
835 int width = font.GetStringWidth(text); 843 int width = font.GetStringWidth(text);
836 iter->style->DrawString(canvas, text, font, textfield_->read_only(), 844 iter->style->DrawString(canvas, text, font, textfield_->read_only(),
837 x_offset, y, width, text_height); 845 x_offset, y, width, text_height);
838 x_offset += width; 846 x_offset += width;
839 } 847 }
840 canvas->Restore(); 848 canvas->Restore();
841 849
842 if (textfield_->IsEnabled() && is_cursor_visible_ && 850 if (textfield_->IsEnabled()) {
843 !model_->HasSelection()) { 851 // Paint cursor. Replace cursor is drawn as rectangle for now.
844 // Paint Cursor. Replace cursor is drawn as rectangle for now. 852 if (is_cursor_visible_ && !model_->HasSelection())
845 canvas->DrawRectInt(kCursorColor, 853 canvas->DrawRectInt(kCursorColor,
846 cursor_bounds_.x(), 854 cursor_bounds_.x(),
847 cursor_bounds_.y(), 855 cursor_bounds_.y(),
848 insert_ ? 0 : cursor_bounds_.width(), 856 insert_ ? 0 : cursor_bounds_.width(),
849 cursor_bounds_.height()); 857 cursor_bounds_.height());
858 // Paint drop cursor.
859 if (is_drop_cursor_visible_)
860 canvas->DrawRectInt(kCursorColor,
861 drop_cursor_bounds_.x(),
862 drop_cursor_bounds_.y(),
863 0,
864 drop_cursor_bounds_.height());
oshima 2011/06/07 17:32:52 basic question. Can both be visible at the same ti
msw 2011/06/08 23:50:29 Done.
850 } 865 }
851 } 866 }
852 867
853 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { 868 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
854 // TODO(oshima): Refactor and consolidate with ExecuteCommand. 869 // TODO(oshima): Refactor and consolidate with ExecuteCommand.
855 if (key_event.type() == ui::ET_KEY_PRESSED) { 870 if (key_event.type() == ui::ET_KEY_PRESSED) {
856 ui::KeyboardCode key_code = key_event.key_code(); 871 ui::KeyboardCode key_code = key_event.key_code();
857 // TODO(oshima): shift-tab does not work. Figure out why and fix. 872 // TODO(oshima): shift-tab does not work. Figure out why and fix.
858 if (key_code == ui::VKEY_TAB) 873 if (key_code == ui::VKEY_TAB)
859 return false; 874 return false;
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 // Filter out all control characters, including tab and new line characters, 1103 // Filter out all control characters, including tab and new line characters,
1089 // and all characters with Alt modifier. But we need to allow characters with 1104 // and all characters with Alt modifier. But we need to allow characters with
1090 // AltGr modifier. 1105 // AltGr modifier.
1091 // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different 1106 // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different
1092 // flag that we don't care about. 1107 // flag that we don't care about.
1093 return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && 1108 return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
1094 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; 1109 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN;
1095 } 1110 }
1096 1111
1097 } // namespace views 1112 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/textfield/native_textfield_views.h ('k') | views/controls/textfield/native_textfield_views_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698