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

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

Issue 3142008: Model, View and Controller for a Gap Buffer based one line text field in view... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: added files that were missed in the last patch Created 10 years, 1 month 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
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "views/controls/textfield/textfield_view.h"
6
7 namespace views {
8
9 const char TextfieldView::kViewClassName[] = "views/TextfieldView";
10
11 TextfieldView::TextfieldView() {
12 Init(L"");
13 }
14
15 TextfieldView::TextfieldView(const std::wstring& text) {
16 Init(text);
17 }
18
19 TextfieldView::TextfieldView(TextfieldModel* model) {
20 Init(L"");
21 model_.reset(model);
22 }
23
24 void TextfieldView::Init(const std::wstring& text) {
25 controller_.reset(NULL);
26 selection_on_ = false;
27 model_.reset(new TextfieldModel(text));
28 set_background(Background::CreateSolidBackground(255, 255, 255, 255));
29 SetHorizontalAlignment(ALIGN_LEFT);
30 this->SetFocusable(true);
31 RequestFocus();
32 onscreen_cursor_pos_ = font().GetStringWidth(text);
33 }
34
35 void TextfieldView::SetController(TextfieldController* controller) {
36 controller_.reset(controller);
37 }
38
39 ////////////////////////////////////////////////////////////////////////////////
40 // View overrides:
41
42 bool TextfieldView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
43 return true;
44 }
45
46 // TODO(varunjain): implement mouse and focus events related methods.
47 bool TextfieldView::OnMousePressed(const views::MouseEvent& e) {
48 return true;
49 }
50
51 bool TextfieldView::OnMouseDragged(const views::MouseEvent& e) {
52 return true;
53 }
54
55 void TextfieldView::OnMouseReleased(const views::MouseEvent& e, bool canceled) {
56 RequestFocus();
57 }
58
59 bool TextfieldView::OnKeyPressed(const views::KeyEvent& e) {
60 bool handled = HandleKeyEvent(e);
61 this->SetText(model_->text());
62 SchedulePaint();
63 return handled;
64 }
65
66 bool TextfieldView::OnKeyReleased(const views::KeyEvent& e) {
67 return true;
68 }
69
70 void TextfieldView::WillGainFocus() {
71 }
72
73 void TextfieldView::DidGainFocus() {
74 }
75
76 void TextfieldView::WillLoseFocus() {
77 }
78
79 std::wstring TextfieldView::GetText() {
80 return model_->text();
81 }
82
83 gfx::Rect TextfieldView::GetTextBounds() {
84 gfx::Insets insets = View::GetInsets();
85 int text_height = font().GetHeight();
86 int text_y = std::max(0, (bounds().height() - text_height)) / 2;
87 gfx::Rect text_bounds(insets.left(), text_y,
88 bounds().width() - insets.width(), text_height);
89 return text_bounds;
90 }
91
92 void TextfieldView::PaintTextAndCursor(gfx::Canvas* canvas) {
93 // TODO(varunjain): re-implement this so that only dirty text is painted.
94 std::wstring str = model_->text();
95 gfx::Rect text_bounds = GetTextBounds();
96 int onscreen_cursor_pos = onscreen_cursor_pos_ + View::GetInsets().left();
97
98 // Get string to the left of cursor.
99 std::wstring left_string = GetStringToLeftOfCursor(str,
100 model_->GetCurrentCursorPos(), onscreen_cursor_pos, text_bounds);
101 int left_str_width = font().GetStringWidth(left_string);
102
103 // Get string to the right of cursor.
104 std::wstring right_string = GetStringToRightOfCursor(str,
105 model_->GetCurrentCursorPos(), onscreen_cursor_pos, text_bounds);
106
107 // Paint the complete string.
108 visible_text_ = left_string + right_string;
109 canvas->DrawStringInt(visible_text_, font(), GetColor(), text_bounds.x(),
110 text_bounds.y(), text_bounds.width(), text_bounds.height(), 0);
111
112 // Paint Cursor.
113 if (HasFocus()) {
114 canvas->DrawLineInt(SK_ColorBLUE, text_bounds.x() + left_str_width, 0,
115 text_bounds.x() + left_str_width, bounds().height());
116 }
117 }
118
119 void TextfieldView::Paint(gfx::Canvas* canvas) {
120 set_border(HasFocus() ? Border::CreateSolidBorder(2, SK_ColorGRAY)
121 : Border::CreateSolidBorder(1, SK_ColorBLACK));
122 PaintBackground(canvas);
123 PaintTextAndCursor(canvas);
124 PaintBorder(canvas);
125 }
126
127 std::wstring TextfieldView::GetStringToLeftOfCursor(std::wstring text,
128 int cursor_pos, int onscreen_cursor_pos, gfx::Rect text_bounds) {
129 std::wstring str = L"";
tfarina 2010/11/18 11:55:31 I think when you do: std::wstring str; it is alrea
130 int available_size = onscreen_cursor_pos - text_bounds.x();
131 for (int pos = cursor_pos; pos > 0; pos--) {
tfarina 2010/11/18 11:55:31 --pos
132 if (font().GetStringWidth(str + text[pos - 1]) <= available_size) {
133 str += text[pos - 1];
134 } else {
135 break;
136 }
137 }
138 for (unsigned i = 0; i < str.length() / 2.0; i++) {
tfarina 2010/11/18 11:55:31 ++i
139 wchar_t temp = str[i];
140 str[i] = str[str.length() - i - 1];
141 str[str.length() - i - 1] = temp;
142 }
143 return str;
144 }
145
146 std::wstring TextfieldView::GetStringToRightOfCursor(std::wstring text,
147 int cursor_pos, int onscreen_cursor_pos, gfx::Rect text_bounds) {
148 std::wstring str;
149 int available_size = text_bounds.x() + text_bounds.width()
150 - onscreen_cursor_pos;
151 for (unsigned pos = cursor_pos; pos < text.length(); pos++) {
tfarina 2010/11/18 11:55:31 ++pos
152 if (font().GetStringWidth(str + text[pos]) <= available_size) {
153 str += text[pos];
154 } else {
155 break;
156 }
157 }
158 return str;
159 }
160
161 bool TextfieldView::HandleKeyEvent(const KeyEvent& key_event) {
162 int current_cursor_pos = model_->GetCurrentCursorPos();
163 std::wstring removed_str = L"";
164 bool need_cursor_repositioning = true;
165 bool text_changed = false;
166 if (key_event.GetType() == views::Event::ET_KEY_PRESSED) {
167 app::KeyboardCode key_code = key_event.GetKeyCode();
168 if (key_code == app::VKEY_TAB) {
169 return false;
170 }
171 switch (key_code) {
172 case app::VKEY_RIGHT:
173 key_event.IsControlDown() ? model_->MoveCursorToNextWord()
174 : model_->MoveCursorRight();
175 break;
176 case app::VKEY_LEFT:
177 key_event.IsControlDown() ? model_->MoveCursorToPreviousWord()
178 : model_->MoveCursorLeft();
179 break;
180 case app::VKEY_END:
181 model_->MoveCursorToEnd();
182 break;
183 case app::VKEY_HOME:
184 model_->MoveCursorToStart();
185 break;
186 case app::VKEY_BACK:
187 removed_str += model_->InsertBackspace();
188 if (font().GetStringWidth(model_->text())
189 <= bounds().width() - View::GetInsets().width()) {
190 SafeDecCursorPos(font().GetStringWidth(removed_str));
191 }
192 need_cursor_repositioning = false;
193 break;
194 case app::VKEY_DELETE:
195 removed_str += model_->InsertDelete();
196 default:
197 break;
198 }
199 if (IsWritable(key_code)) {
200 model_->Insert(GetWritableChar(key_event));
201 text_changed = true;
202 }
203 if (key_event.IsShiftDown() && !selection_on_ &&
204 IsDirectionalKey(key_code)) {
205 selection_on_ = true;
206 selection_start_ = model_->GetCurrentCursorPos();
207 }
208 if (removed_str.length() > 0) {
209 text_changed = true;
210 }
211
212 // Move the onscreen cursor to new position if required.
213 if (need_cursor_repositioning) {
214 std::wstring text = model_->text();
215 int new_cursor_pos = model_->GetCurrentCursorPos();
216 std::wstring str_diff;
217 if (new_cursor_pos > current_cursor_pos) {
218 for (int i = current_cursor_pos; i < new_cursor_pos; i++) {
219 str_diff += text[i];
220 }
221 SafeIncCursorPos(font().GetStringWidth(str_diff));
222 } else if (new_cursor_pos < current_cursor_pos) {
223 for (int i = new_cursor_pos; i < current_cursor_pos; i++) {
224 str_diff += text[i];
225 }
226 SafeDecCursorPos(font().GetStringWidth(str_diff));
227 }
228 }
229
230 // Send notification to the controller if text has changed.
231 if (controller_.get() && text_changed) {
232 controller_->TextChanged(model_->text());
233 }
234 }
235 return true;
236 }
237
238 void TextfieldView::SafeIncCursorPos(int inc) {
239 if (onscreen_cursor_pos_ + inc
240 < bounds().width() - View::GetInsets().width()) {
tfarina 2010/11/18 11:55:31 put this < in the line above?
241 onscreen_cursor_pos_ += inc;
242 } else {
243 onscreen_cursor_pos_ = bounds().width() - View::GetInsets().width();
244 }
245 }
246
247 void TextfieldView::SafeDecCursorPos(int dec) {
248 if (onscreen_cursor_pos_ - dec > 0) {
249 onscreen_cursor_pos_ -= dec;
250 } else {
251 onscreen_cursor_pos_ = 0;
252 }
253 }
254
255 bool TextfieldView::IsDirectionalKey(app::KeyboardCode key_code) {
256 switch (key_code) {
257 case app::VKEY_RIGHT:
258 case app::VKEY_LEFT:
259 case app::VKEY_END:
260 case app::VKEY_HOME:
261 return true;
262 break;
tfarina 2010/11/18 11:55:31 I think the break is not necessary here, it won't
263 default:
264 return false;
265 }
266 }
267
268 bool TextfieldView::IsWritable(app::KeyboardCode key_code) {
269 return (key_code >= app::VKEY_0 && key_code <= app::VKEY_Z)
270 || (key_code >= app::VKEY_NUMPAD0 && key_code <= app::VKEY_DIVIDE)
tfarina 2010/11/18 11:55:31 Please, fix all the occurrences in this file. This
271 || (key_code >= app::VKEY_OEM_1 && key_code <= app::VKEY_OEM_8)
272 || key_code == app::VKEY_SPACE;
273 }
274
275 wchar_t TextfieldView::GetWritableChar(const KeyEvent& key_event) {
276 app::KeyboardCode key_code = key_event.GetKeyCode();
277 bool shift = false;
278 if ((key_code >= app::VKEY_0 && key_code <= app::VKEY_9)
279 || (key_code >= app::VKEY_OEM_1 && key_code <= app::VKEY_OEM_8)) {
280 shift = key_event.IsShiftDown();
281 } else if (key_code >= app::VKEY_A && key_code <= app::VKEY_Z) {
282 shift = (key_event.IsLockDown() && !key_event.IsShiftDown())
283 || (!key_event.IsLockDown() && key_event.IsShiftDown());
284 }
285 return GetWritableChar(key_code, shift);
286 }
287
288 wchar_t TextfieldView::GetWritableChar(app::KeyboardCode key_code,
289 bool shift) {
tfarina 2010/11/18 11:55:31 You can align shift with app::KeyboardCode. Also p
290 switch (key_code) {
291 case app::VKEY_NUMPAD0:
292 return '0';
293 case app::VKEY_NUMPAD1:
294 return '1';
295 case app::VKEY_NUMPAD2:
296 return '2';
297 case app::VKEY_NUMPAD3:
298 return '3';
299 case app::VKEY_NUMPAD4:
300 return '4';
301 case app::VKEY_NUMPAD5:
302 return '5';
303 case app::VKEY_NUMPAD6:
304 return '6';
305 case app::VKEY_NUMPAD7:
306 return '7';
307 case app::VKEY_NUMPAD8:
308 return '8';
309 case app::VKEY_NUMPAD9:
310 return '9';
311 case app::VKEY_MULTIPLY:
312 return '*';
313 case app::VKEY_ADD:
314 return '+';
315 case app::VKEY_SUBTRACT:
316 return '-';
317 case app::VKEY_DECIMAL:
318 return '.';
319 case app::VKEY_DIVIDE:
320 return '/';
321
322 // case app::VKEY_BACK:
tfarina 2010/11/18 11:55:31 Why this big block of comment? If it isn't used. P
323 // return GDK_BackSpace;
324 // case app::VKEY_TAB:
325 // return shift ? GDK_ISO_Left_Tab : GDK_Tab;
326 // case app::VKEY_CLEAR:
327 // return GDK_Clear;
328 // case app::VKEY_RETURN:
329 // return GDK_Return;
330 // case app::VKEY_SHIFT:
331 // return GDK_Shift_L;
332 // case app::VKEY_CONTROL:
333 // return GDK_Control_L;
334 // case app::VKEY_MENU:
335 // return GDK_Alt_L;
336 // case app::VKEY_APPS:
337 // return GDK_Menu;
338 //
339 // case app::VKEY_PAUSE:
340 // return GDK_Pause;
341 // case app::VKEY_CAPITAL:
342 // return GDK_Caps_Lock;
343 // case app::VKEY_KANA:
344 // return GDK_Kana_Lock;
345 // case app::VKEY_HANJA:
346 // return GDK_Hangul_Hanja;
347 // case app::VKEY_ESCAPE:
348 // return GDK_Escape;
349 case app::VKEY_SPACE:
350 return ' ';
351 // case app::VKEY_PRIOR:
352 // return GDK_Page_Up;
353 // case app::VKEY_NEXT:
354 // return GDK_Page_Down;
355 // case app::VKEY_END:
356 // return GDK_End;
357 // case app::VKEY_HOME:
358 // return GDK_Home;
359 // case app::VKEY_LEFT:
360 // return GDK_Left;
361 // case app::VKEY_UP:
362 // return GDK_Up;
363 // case app::VKEY_RIGHT:
364 // return GDK_Right;
365 // case app::VKEY_DOWN:
366 // return GDK_Down;
367 // case app::VKEY_SELECT:
368 // return GDK_Select;
369 // case app::VKEY_PRINT:
370 // return GDK_Print;
371 // case app::VKEY_EXECUTE:
372 // return GDK_Execute;
373 // case app::VKEY_INSERT:
374 // return GDK_Insert;
375 // case app::VKEY_DELETE:
376 // return GDK_Delete;
377 // case app::VKEY_HELP:
378 // return GDK_Help;
379 case app::VKEY_0:
380 return shift ? ')' : '0';
381 case app::VKEY_1:
382 return shift ? '!' : '1';
383 case app::VKEY_2:
384 return shift ? '@' : '2';
385 case app::VKEY_3:
386 return shift ? '#' : '3';
387 case app::VKEY_4:
388 return shift ? '$' : '4';
389 case app::VKEY_5:
390 return shift ? '%' : '5';
391 case app::VKEY_6:
392 return shift ? '^' : '6';
393 case app::VKEY_7:
394 return shift ? '&' : '7';
395 case app::VKEY_8:
396 return shift ? '*' : '8';
397 case app::VKEY_9:
398 return shift ? '(' : '9';
399
400 case app::VKEY_A:
401 case app::VKEY_B:
402 case app::VKEY_C:
403 case app::VKEY_D:
404 case app::VKEY_E:
405 case app::VKEY_F:
406 case app::VKEY_G:
407 case app::VKEY_H:
408 case app::VKEY_I:
409 case app::VKEY_J:
410 case app::VKEY_K:
411 case app::VKEY_L:
412 case app::VKEY_M:
413 case app::VKEY_N:
414 case app::VKEY_O:
415 case app::VKEY_P:
416 case app::VKEY_Q:
417 case app::VKEY_R:
418 case app::VKEY_S:
419 case app::VKEY_T:
420 case app::VKEY_U:
421 case app::VKEY_V:
422 case app::VKEY_W:
423 case app::VKEY_X:
424 case app::VKEY_Y:
425 case app::VKEY_Z:
426 return (shift ? 'A' : 'a') + (key_code - app::VKEY_A);
427
428 // case app::VKEY_LWIN:
429 // return GDK_Meta_L;
430 // case app::VKEY_RWIN:
431 // return GDK_Meta_R;
432 //
433 // case app::VKEY_NUMLOCK:
434 // return GDK_Num_Lock;
435 //
436 // case app::VKEY_SCROLL:
437 // return GDK_Scroll_Lock;
438 //
439 case app::VKEY_OEM_1:
440 return shift ? ':' : ';';
441 case app::VKEY_OEM_PLUS:
442 return shift ? '+' : '=';
443 case app::VKEY_OEM_COMMA:
444 return shift ? '<' : ',';
445 case app::VKEY_OEM_MINUS:
446 return shift ? '_' : '-';
447 case app::VKEY_OEM_PERIOD:
448 return shift ? '>' : '.';
449 case app::VKEY_OEM_2:
450 return shift ? '?' : '/';
451 case app::VKEY_OEM_3:
452 return shift ? '~' : '`';
453 case app::VKEY_OEM_4:
454 return shift ? '}' : ']';
455 case app::VKEY_OEM_5:
456 return shift ? '|' : '\\';
457 case app::VKEY_OEM_6:
458 return shift ? '{' : '[';
459 case app::VKEY_OEM_7:
460 return shift ? '"' : '\'';
461 //
462 // case app::VKEY_F1:
463 // case app::VKEY_F2:
464 // case app::VKEY_F3:
465 // case app::VKEY_F4:
466 // case app::VKEY_F5:
467 // case app::VKEY_F6:
468 // case app::VKEY_F7:
469 // case app::VKEY_F8:
470 // case app::VKEY_F9:
471 // case app::VKEY_F10:
472 // case app::VKEY_F11:
473 // case app::VKEY_F12:
474 // case app::VKEY_F13:
475 // case app::VKEY_F14:
476 // case app::VKEY_F15:
477 // case app::VKEY_F16:
478 // case app::VKEY_F17:
479 // case app::VKEY_F18:
480 // case app::VKEY_F19:
481 // case app::VKEY_F20:
482 // case app::VKEY_F21:
483 // case app::VKEY_F22:
484 // case app::VKEY_F23:
485 // case app::VKEY_F24:
486 // return GDK_F1 + (keycode - app::VKEY_F1);
487
488 default:
489 return 0;
490 }
491 }
492 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698