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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: views/controls/textfield/textfield_view.cc
diff --git a/views/controls/textfield/textfield_view.cc b/views/controls/textfield/textfield_view.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7c578f6d532516d85710a55b08db2c4626b95739
--- /dev/null
+++ b/views/controls/textfield/textfield_view.cc
@@ -0,0 +1,492 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/controls/textfield/textfield_view.h"
+
+namespace views {
+
+const char TextfieldView::kViewClassName[] = "views/TextfieldView";
+
+TextfieldView::TextfieldView() {
+ Init(L"");
+}
+
+TextfieldView::TextfieldView(const std::wstring& text) {
+ Init(text);
+}
+
+TextfieldView::TextfieldView(TextfieldModel* model) {
+ Init(L"");
+ model_.reset(model);
+}
+
+void TextfieldView::Init(const std::wstring& text) {
+ controller_.reset(NULL);
+ selection_on_ = false;
+ model_.reset(new TextfieldModel(text));
+ set_background(Background::CreateSolidBackground(255, 255, 255, 255));
+ SetHorizontalAlignment(ALIGN_LEFT);
+ this->SetFocusable(true);
+ RequestFocus();
+ onscreen_cursor_pos_ = font().GetStringWidth(text);
+}
+
+void TextfieldView::SetController(TextfieldController* controller) {
+ controller_.reset(controller);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// View overrides:
+
+bool TextfieldView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
+ return true;
+}
+
+// TODO(varunjain): implement mouse and focus events related methods.
+bool TextfieldView::OnMousePressed(const views::MouseEvent& e) {
+ return true;
+}
+
+bool TextfieldView::OnMouseDragged(const views::MouseEvent& e) {
+ return true;
+}
+
+void TextfieldView::OnMouseReleased(const views::MouseEvent& e, bool canceled) {
+ RequestFocus();
+}
+
+bool TextfieldView::OnKeyPressed(const views::KeyEvent& e) {
+ bool handled = HandleKeyEvent(e);
+ this->SetText(model_->text());
+ SchedulePaint();
+ return handled;
+}
+
+bool TextfieldView::OnKeyReleased(const views::KeyEvent& e) {
+ return true;
+}
+
+void TextfieldView::WillGainFocus() {
+}
+
+void TextfieldView::DidGainFocus() {
+}
+
+void TextfieldView::WillLoseFocus() {
+}
+
+std::wstring TextfieldView::GetText() {
+ return model_->text();
+}
+
+gfx::Rect TextfieldView::GetTextBounds() {
+ gfx::Insets insets = View::GetInsets();
+ int text_height = font().GetHeight();
+ int text_y = std::max(0, (bounds().height() - text_height)) / 2;
+ gfx::Rect text_bounds(insets.left(), text_y,
+ bounds().width() - insets.width(), text_height);
+ return text_bounds;
+}
+
+void TextfieldView::PaintTextAndCursor(gfx::Canvas* canvas) {
+ // TODO(varunjain): re-implement this so that only dirty text is painted.
+ std::wstring str = model_->text();
+ gfx::Rect text_bounds = GetTextBounds();
+ int onscreen_cursor_pos = onscreen_cursor_pos_ + View::GetInsets().left();
+
+ // Get string to the left of cursor.
+ std::wstring left_string = GetStringToLeftOfCursor(str,
+ model_->GetCurrentCursorPos(), onscreen_cursor_pos, text_bounds);
+ int left_str_width = font().GetStringWidth(left_string);
+
+ // Get string to the right of cursor.
+ std::wstring right_string = GetStringToRightOfCursor(str,
+ model_->GetCurrentCursorPos(), onscreen_cursor_pos, text_bounds);
+
+ // Paint the complete string.
+ visible_text_ = left_string + right_string;
+ canvas->DrawStringInt(visible_text_, font(), GetColor(), text_bounds.x(),
+ text_bounds.y(), text_bounds.width(), text_bounds.height(), 0);
+
+ // Paint Cursor.
+ if (HasFocus()) {
+ canvas->DrawLineInt(SK_ColorBLUE, text_bounds.x() + left_str_width, 0,
+ text_bounds.x() + left_str_width, bounds().height());
+ }
+}
+
+void TextfieldView::Paint(gfx::Canvas* canvas) {
+ set_border(HasFocus() ? Border::CreateSolidBorder(2, SK_ColorGRAY)
+ : Border::CreateSolidBorder(1, SK_ColorBLACK));
+ PaintBackground(canvas);
+ PaintTextAndCursor(canvas);
+ PaintBorder(canvas);
+}
+
+std::wstring TextfieldView::GetStringToLeftOfCursor(std::wstring text,
+ int cursor_pos, int onscreen_cursor_pos, gfx::Rect text_bounds) {
+ std::wstring str = L"";
tfarina 2010/11/18 11:55:31 I think when you do: std::wstring str; it is alrea
+ int available_size = onscreen_cursor_pos - text_bounds.x();
+ for (int pos = cursor_pos; pos > 0; pos--) {
tfarina 2010/11/18 11:55:31 --pos
+ if (font().GetStringWidth(str + text[pos - 1]) <= available_size) {
+ str += text[pos - 1];
+ } else {
+ break;
+ }
+ }
+ for (unsigned i = 0; i < str.length() / 2.0; i++) {
tfarina 2010/11/18 11:55:31 ++i
+ wchar_t temp = str[i];
+ str[i] = str[str.length() - i - 1];
+ str[str.length() - i - 1] = temp;
+ }
+ return str;
+}
+
+std::wstring TextfieldView::GetStringToRightOfCursor(std::wstring text,
+ int cursor_pos, int onscreen_cursor_pos, gfx::Rect text_bounds) {
+ std::wstring str;
+ int available_size = text_bounds.x() + text_bounds.width()
+ - onscreen_cursor_pos;
+ for (unsigned pos = cursor_pos; pos < text.length(); pos++) {
tfarina 2010/11/18 11:55:31 ++pos
+ if (font().GetStringWidth(str + text[pos]) <= available_size) {
+ str += text[pos];
+ } else {
+ break;
+ }
+ }
+ return str;
+}
+
+bool TextfieldView::HandleKeyEvent(const KeyEvent& key_event) {
+ int current_cursor_pos = model_->GetCurrentCursorPos();
+ std::wstring removed_str = L"";
+ bool need_cursor_repositioning = true;
+ bool text_changed = false;
+ if (key_event.GetType() == views::Event::ET_KEY_PRESSED) {
+ app::KeyboardCode key_code = key_event.GetKeyCode();
+ if (key_code == app::VKEY_TAB) {
+ return false;
+ }
+ switch (key_code) {
+ case app::VKEY_RIGHT:
+ key_event.IsControlDown() ? model_->MoveCursorToNextWord()
+ : model_->MoveCursorRight();
+ break;
+ case app::VKEY_LEFT:
+ key_event.IsControlDown() ? model_->MoveCursorToPreviousWord()
+ : model_->MoveCursorLeft();
+ break;
+ case app::VKEY_END:
+ model_->MoveCursorToEnd();
+ break;
+ case app::VKEY_HOME:
+ model_->MoveCursorToStart();
+ break;
+ case app::VKEY_BACK:
+ removed_str += model_->InsertBackspace();
+ if (font().GetStringWidth(model_->text())
+ <= bounds().width() - View::GetInsets().width()) {
+ SafeDecCursorPos(font().GetStringWidth(removed_str));
+ }
+ need_cursor_repositioning = false;
+ break;
+ case app::VKEY_DELETE:
+ removed_str += model_->InsertDelete();
+ default:
+ break;
+ }
+ if (IsWritable(key_code)) {
+ model_->Insert(GetWritableChar(key_event));
+ text_changed = true;
+ }
+ if (key_event.IsShiftDown() && !selection_on_ &&
+ IsDirectionalKey(key_code)) {
+ selection_on_ = true;
+ selection_start_ = model_->GetCurrentCursorPos();
+ }
+ if (removed_str.length() > 0) {
+ text_changed = true;
+ }
+
+ // Move the onscreen cursor to new position if required.
+ if (need_cursor_repositioning) {
+ std::wstring text = model_->text();
+ int new_cursor_pos = model_->GetCurrentCursorPos();
+ std::wstring str_diff;
+ if (new_cursor_pos > current_cursor_pos) {
+ for (int i = current_cursor_pos; i < new_cursor_pos; i++) {
+ str_diff += text[i];
+ }
+ SafeIncCursorPos(font().GetStringWidth(str_diff));
+ } else if (new_cursor_pos < current_cursor_pos) {
+ for (int i = new_cursor_pos; i < current_cursor_pos; i++) {
+ str_diff += text[i];
+ }
+ SafeDecCursorPos(font().GetStringWidth(str_diff));
+ }
+ }
+
+ // Send notification to the controller if text has changed.
+ if (controller_.get() && text_changed) {
+ controller_->TextChanged(model_->text());
+ }
+ }
+ return true;
+}
+
+void TextfieldView::SafeIncCursorPos(int inc) {
+ if (onscreen_cursor_pos_ + inc
+ < bounds().width() - View::GetInsets().width()) {
tfarina 2010/11/18 11:55:31 put this < in the line above?
+ onscreen_cursor_pos_ += inc;
+ } else {
+ onscreen_cursor_pos_ = bounds().width() - View::GetInsets().width();
+ }
+}
+
+void TextfieldView::SafeDecCursorPos(int dec) {
+ if (onscreen_cursor_pos_ - dec > 0) {
+ onscreen_cursor_pos_ -= dec;
+ } else {
+ onscreen_cursor_pos_ = 0;
+ }
+}
+
+bool TextfieldView::IsDirectionalKey(app::KeyboardCode key_code) {
+ switch (key_code) {
+ case app::VKEY_RIGHT:
+ case app::VKEY_LEFT:
+ case app::VKEY_END:
+ case app::VKEY_HOME:
+ return true;
+ break;
tfarina 2010/11/18 11:55:31 I think the break is not necessary here, it won't
+ default:
+ return false;
+ }
+}
+
+bool TextfieldView::IsWritable(app::KeyboardCode key_code) {
+ return (key_code >= app::VKEY_0 && key_code <= app::VKEY_Z)
+ || (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
+ || (key_code >= app::VKEY_OEM_1 && key_code <= app::VKEY_OEM_8)
+ || key_code == app::VKEY_SPACE;
+}
+
+wchar_t TextfieldView::GetWritableChar(const KeyEvent& key_event) {
+ app::KeyboardCode key_code = key_event.GetKeyCode();
+ bool shift = false;
+ if ((key_code >= app::VKEY_0 && key_code <= app::VKEY_9)
+ || (key_code >= app::VKEY_OEM_1 && key_code <= app::VKEY_OEM_8)) {
+ shift = key_event.IsShiftDown();
+ } else if (key_code >= app::VKEY_A && key_code <= app::VKEY_Z) {
+ shift = (key_event.IsLockDown() && !key_event.IsShiftDown())
+ || (!key_event.IsLockDown() && key_event.IsShiftDown());
+ }
+ return GetWritableChar(key_code, shift);
+}
+
+wchar_t TextfieldView::GetWritableChar(app::KeyboardCode key_code,
+ bool shift) {
tfarina 2010/11/18 11:55:31 You can align shift with app::KeyboardCode. Also p
+ switch (key_code) {
+ case app::VKEY_NUMPAD0:
+ return '0';
+ case app::VKEY_NUMPAD1:
+ return '1';
+ case app::VKEY_NUMPAD2:
+ return '2';
+ case app::VKEY_NUMPAD3:
+ return '3';
+ case app::VKEY_NUMPAD4:
+ return '4';
+ case app::VKEY_NUMPAD5:
+ return '5';
+ case app::VKEY_NUMPAD6:
+ return '6';
+ case app::VKEY_NUMPAD7:
+ return '7';
+ case app::VKEY_NUMPAD8:
+ return '8';
+ case app::VKEY_NUMPAD9:
+ return '9';
+ case app::VKEY_MULTIPLY:
+ return '*';
+ case app::VKEY_ADD:
+ return '+';
+ case app::VKEY_SUBTRACT:
+ return '-';
+ case app::VKEY_DECIMAL:
+ return '.';
+ case app::VKEY_DIVIDE:
+ return '/';
+
+// case app::VKEY_BACK:
tfarina 2010/11/18 11:55:31 Why this big block of comment? If it isn't used. P
+// return GDK_BackSpace;
+// case app::VKEY_TAB:
+// return shift ? GDK_ISO_Left_Tab : GDK_Tab;
+// case app::VKEY_CLEAR:
+// return GDK_Clear;
+// case app::VKEY_RETURN:
+// return GDK_Return;
+// case app::VKEY_SHIFT:
+// return GDK_Shift_L;
+// case app::VKEY_CONTROL:
+// return GDK_Control_L;
+// case app::VKEY_MENU:
+// return GDK_Alt_L;
+// case app::VKEY_APPS:
+// return GDK_Menu;
+//
+// case app::VKEY_PAUSE:
+// return GDK_Pause;
+// case app::VKEY_CAPITAL:
+// return GDK_Caps_Lock;
+// case app::VKEY_KANA:
+// return GDK_Kana_Lock;
+// case app::VKEY_HANJA:
+// return GDK_Hangul_Hanja;
+// case app::VKEY_ESCAPE:
+// return GDK_Escape;
+ case app::VKEY_SPACE:
+ return ' ';
+// case app::VKEY_PRIOR:
+// return GDK_Page_Up;
+// case app::VKEY_NEXT:
+// return GDK_Page_Down;
+// case app::VKEY_END:
+// return GDK_End;
+// case app::VKEY_HOME:
+// return GDK_Home;
+// case app::VKEY_LEFT:
+// return GDK_Left;
+// case app::VKEY_UP:
+// return GDK_Up;
+// case app::VKEY_RIGHT:
+// return GDK_Right;
+// case app::VKEY_DOWN:
+// return GDK_Down;
+// case app::VKEY_SELECT:
+// return GDK_Select;
+// case app::VKEY_PRINT:
+// return GDK_Print;
+// case app::VKEY_EXECUTE:
+// return GDK_Execute;
+// case app::VKEY_INSERT:
+// return GDK_Insert;
+// case app::VKEY_DELETE:
+// return GDK_Delete;
+// case app::VKEY_HELP:
+// return GDK_Help;
+ case app::VKEY_0:
+ return shift ? ')' : '0';
+ case app::VKEY_1:
+ return shift ? '!' : '1';
+ case app::VKEY_2:
+ return shift ? '@' : '2';
+ case app::VKEY_3:
+ return shift ? '#' : '3';
+ case app::VKEY_4:
+ return shift ? '$' : '4';
+ case app::VKEY_5:
+ return shift ? '%' : '5';
+ case app::VKEY_6:
+ return shift ? '^' : '6';
+ case app::VKEY_7:
+ return shift ? '&' : '7';
+ case app::VKEY_8:
+ return shift ? '*' : '8';
+ case app::VKEY_9:
+ return shift ? '(' : '9';
+
+ case app::VKEY_A:
+ case app::VKEY_B:
+ case app::VKEY_C:
+ case app::VKEY_D:
+ case app::VKEY_E:
+ case app::VKEY_F:
+ case app::VKEY_G:
+ case app::VKEY_H:
+ case app::VKEY_I:
+ case app::VKEY_J:
+ case app::VKEY_K:
+ case app::VKEY_L:
+ case app::VKEY_M:
+ case app::VKEY_N:
+ case app::VKEY_O:
+ case app::VKEY_P:
+ case app::VKEY_Q:
+ case app::VKEY_R:
+ case app::VKEY_S:
+ case app::VKEY_T:
+ case app::VKEY_U:
+ case app::VKEY_V:
+ case app::VKEY_W:
+ case app::VKEY_X:
+ case app::VKEY_Y:
+ case app::VKEY_Z:
+ return (shift ? 'A' : 'a') + (key_code - app::VKEY_A);
+
+// case app::VKEY_LWIN:
+// return GDK_Meta_L;
+// case app::VKEY_RWIN:
+// return GDK_Meta_R;
+//
+// case app::VKEY_NUMLOCK:
+// return GDK_Num_Lock;
+//
+// case app::VKEY_SCROLL:
+// return GDK_Scroll_Lock;
+//
+ case app::VKEY_OEM_1:
+ return shift ? ':' : ';';
+ case app::VKEY_OEM_PLUS:
+ return shift ? '+' : '=';
+ case app::VKEY_OEM_COMMA:
+ return shift ? '<' : ',';
+ case app::VKEY_OEM_MINUS:
+ return shift ? '_' : '-';
+ case app::VKEY_OEM_PERIOD:
+ return shift ? '>' : '.';
+ case app::VKEY_OEM_2:
+ return shift ? '?' : '/';
+ case app::VKEY_OEM_3:
+ return shift ? '~' : '`';
+ case app::VKEY_OEM_4:
+ return shift ? '}' : ']';
+ case app::VKEY_OEM_5:
+ return shift ? '|' : '\\';
+ case app::VKEY_OEM_6:
+ return shift ? '{' : '[';
+ case app::VKEY_OEM_7:
+ return shift ? '"' : '\'';
+//
+// case app::VKEY_F1:
+// case app::VKEY_F2:
+// case app::VKEY_F3:
+// case app::VKEY_F4:
+// case app::VKEY_F5:
+// case app::VKEY_F6:
+// case app::VKEY_F7:
+// case app::VKEY_F8:
+// case app::VKEY_F9:
+// case app::VKEY_F10:
+// case app::VKEY_F11:
+// case app::VKEY_F12:
+// case app::VKEY_F13:
+// case app::VKEY_F14:
+// case app::VKEY_F15:
+// case app::VKEY_F16:
+// case app::VKEY_F17:
+// case app::VKEY_F18:
+// case app::VKEY_F19:
+// case app::VKEY_F20:
+// case app::VKEY_F21:
+// case app::VKEY_F22:
+// case app::VKEY_F23:
+// case app::VKEY_F24:
+// return GDK_F1 + (keycode - app::VKEY_F1);
+
+ default:
+ return 0;
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698