| Index: views/controls/textfield/textfield_view.cc
|
| ===================================================================
|
| --- views/controls/textfield/textfield_view.cc (revision 0)
|
| +++ views/controls/textfield/textfield_view.cc (revision 0)
|
| @@ -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"";
|
| + int available_size = onscreen_cursor_pos - text_bounds.x();
|
| + for (int pos = cursor_pos; pos > 0; 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++) {
|
| + 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++) {
|
| + 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) {
|
| + base::KeyboardCode key_code = key_event.GetKeyCode();
|
| + if (key_code == base::VKEY_TAB) {
|
| + return false;
|
| + }
|
| + switch (key_code) {
|
| + case base::VKEY_RIGHT:
|
| + key_event.IsControlDown() ? model_->MoveCursorToNextWord()
|
| + : model_->MoveCursorRight();
|
| + break;
|
| + case base::VKEY_LEFT:
|
| + key_event.IsControlDown() ? model_->MoveCursorToPreviousWord()
|
| + : model_->MoveCursorLeft();
|
| + break;
|
| + case base::VKEY_END:
|
| + model_->MoveCursorToEnd();
|
| + break;
|
| + case base::VKEY_HOME:
|
| + model_->MoveCursorToStart();
|
| + break;
|
| + case base::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 base::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()) {
|
| + 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(base::KeyboardCode key_code) {
|
| + switch (key_code) {
|
| + case base::VKEY_RIGHT:
|
| + case base::VKEY_LEFT:
|
| + case base::VKEY_END:
|
| + case base::VKEY_HOME:
|
| + return true;
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +bool TextfieldView::IsWritable(base::KeyboardCode key_code) {
|
| + return (key_code >= base::VKEY_0 && key_code <= base::VKEY_Z)
|
| + || (key_code >= base::VKEY_NUMPAD0 && key_code <= base::VKEY_DIVIDE)
|
| + || (key_code >= base::VKEY_OEM_1 && key_code <= base::VKEY_OEM_8)
|
| + || key_code == base::VKEY_SPACE;
|
| +}
|
| +
|
| +wchar_t TextfieldView::GetWritableChar(const KeyEvent& key_event) {
|
| + base::KeyboardCode key_code = key_event.GetKeyCode();
|
| + bool shift = false;
|
| + if ((key_code >= base::VKEY_0 && key_code <= base::VKEY_9)
|
| + || (key_code >= base::VKEY_OEM_1 && key_code <= base::VKEY_OEM_8)) {
|
| + shift = key_event.IsShiftDown();
|
| + } else if (key_code >= base::VKEY_A && key_code <= base::VKEY_Z) {
|
| + shift = (key_event.IsLockDown() && !key_event.IsShiftDown())
|
| + || (!key_event.IsLockDown() && key_event.IsShiftDown());
|
| + }
|
| + return GetWritableChar(key_code, shift);
|
| +}
|
| +
|
| +wchar_t TextfieldView::GetWritableChar(base::KeyboardCode key_code,
|
| + bool shift) {
|
| + switch (key_code) {
|
| + case base::VKEY_NUMPAD0:
|
| + return '0';
|
| + case base::VKEY_NUMPAD1:
|
| + return '1';
|
| + case base::VKEY_NUMPAD2:
|
| + return '2';
|
| + case base::VKEY_NUMPAD3:
|
| + return '3';
|
| + case base::VKEY_NUMPAD4:
|
| + return '4';
|
| + case base::VKEY_NUMPAD5:
|
| + return '5';
|
| + case base::VKEY_NUMPAD6:
|
| + return '6';
|
| + case base::VKEY_NUMPAD7:
|
| + return '7';
|
| + case base::VKEY_NUMPAD8:
|
| + return '8';
|
| + case base::VKEY_NUMPAD9:
|
| + return '9';
|
| + case base::VKEY_MULTIPLY:
|
| + return '*';
|
| + case base::VKEY_ADD:
|
| + return '+';
|
| + case base::VKEY_SUBTRACT:
|
| + return '-';
|
| + case base::VKEY_DECIMAL:
|
| + return '.';
|
| + case base::VKEY_DIVIDE:
|
| + return '/';
|
| +
|
| +// case base::VKEY_BACK:
|
| +// return GDK_BackSpace;
|
| +// case base::VKEY_TAB:
|
| +// return shift ? GDK_ISO_Left_Tab : GDK_Tab;
|
| +// case base::VKEY_CLEAR:
|
| +// return GDK_Clear;
|
| +// case base::VKEY_RETURN:
|
| +// return GDK_Return;
|
| +// case base::VKEY_SHIFT:
|
| +// return GDK_Shift_L;
|
| +// case base::VKEY_CONTROL:
|
| +// return GDK_Control_L;
|
| +// case base::VKEY_MENU:
|
| +// return GDK_Alt_L;
|
| +// case base::VKEY_APPS:
|
| +// return GDK_Menu;
|
| +//
|
| +// case base::VKEY_PAUSE:
|
| +// return GDK_Pause;
|
| +// case base::VKEY_CAPITAL:
|
| +// return GDK_Caps_Lock;
|
| +// case base::VKEY_KANA:
|
| +// return GDK_Kana_Lock;
|
| +// case base::VKEY_HANJA:
|
| +// return GDK_Hangul_Hanja;
|
| +// case base::VKEY_ESCAPE:
|
| +// return GDK_Escape;
|
| + case base::VKEY_SPACE:
|
| + return ' ';
|
| +// case base::VKEY_PRIOR:
|
| +// return GDK_Page_Up;
|
| +// case base::VKEY_NEXT:
|
| +// return GDK_Page_Down;
|
| +// case base::VKEY_END:
|
| +// return GDK_End;
|
| +// case base::VKEY_HOME:
|
| +// return GDK_Home;
|
| +// case base::VKEY_LEFT:
|
| +// return GDK_Left;
|
| +// case base::VKEY_UP:
|
| +// return GDK_Up;
|
| +// case base::VKEY_RIGHT:
|
| +// return GDK_Right;
|
| +// case base::VKEY_DOWN:
|
| +// return GDK_Down;
|
| +// case base::VKEY_SELECT:
|
| +// return GDK_Select;
|
| +// case base::VKEY_PRINT:
|
| +// return GDK_Print;
|
| +// case base::VKEY_EXECUTE:
|
| +// return GDK_Execute;
|
| +// case base::VKEY_INSERT:
|
| +// return GDK_Insert;
|
| +// case base::VKEY_DELETE:
|
| +// return GDK_Delete;
|
| +// case base::VKEY_HELP:
|
| +// return GDK_Help;
|
| + case base::VKEY_0:
|
| + return shift ? ')' : '0';
|
| + case base::VKEY_1:
|
| + return shift ? '!' : '1';
|
| + case base::VKEY_2:
|
| + return shift ? '@' : '2';
|
| + case base::VKEY_3:
|
| + return shift ? '#' : '3';
|
| + case base::VKEY_4:
|
| + return shift ? '$' : '4';
|
| + case base::VKEY_5:
|
| + return shift ? '%' : '5';
|
| + case base::VKEY_6:
|
| + return shift ? '^' : '6';
|
| + case base::VKEY_7:
|
| + return shift ? '&' : '7';
|
| + case base::VKEY_8:
|
| + return shift ? '*' : '8';
|
| + case base::VKEY_9:
|
| + return shift ? '(' : '9';
|
| +
|
| + case base::VKEY_A:
|
| + case base::VKEY_B:
|
| + case base::VKEY_C:
|
| + case base::VKEY_D:
|
| + case base::VKEY_E:
|
| + case base::VKEY_F:
|
| + case base::VKEY_G:
|
| + case base::VKEY_H:
|
| + case base::VKEY_I:
|
| + case base::VKEY_J:
|
| + case base::VKEY_K:
|
| + case base::VKEY_L:
|
| + case base::VKEY_M:
|
| + case base::VKEY_N:
|
| + case base::VKEY_O:
|
| + case base::VKEY_P:
|
| + case base::VKEY_Q:
|
| + case base::VKEY_R:
|
| + case base::VKEY_S:
|
| + case base::VKEY_T:
|
| + case base::VKEY_U:
|
| + case base::VKEY_V:
|
| + case base::VKEY_W:
|
| + case base::VKEY_X:
|
| + case base::VKEY_Y:
|
| + case base::VKEY_Z:
|
| + return (shift ? 'A' : 'a') + (key_code - base::VKEY_A);
|
| +
|
| +// case base::VKEY_LWIN:
|
| +// return GDK_Meta_L;
|
| +// case base::VKEY_RWIN:
|
| +// return GDK_Meta_R;
|
| +//
|
| +// case base::VKEY_NUMLOCK:
|
| +// return GDK_Num_Lock;
|
| +//
|
| +// case base::VKEY_SCROLL:
|
| +// return GDK_Scroll_Lock;
|
| +//
|
| + case base::VKEY_OEM_1:
|
| + return shift ? ':' : ';';
|
| + case base::VKEY_OEM_PLUS:
|
| + return shift ? '+' : '=';
|
| + case base::VKEY_OEM_COMMA:
|
| + return shift ? '<' : ',';
|
| + case base::VKEY_OEM_MINUS:
|
| + return shift ? '_' : '-';
|
| + case base::VKEY_OEM_PERIOD:
|
| + return shift ? '>' : '.';
|
| + case base::VKEY_OEM_2:
|
| + return shift ? '?' : '/';
|
| + case base::VKEY_OEM_3:
|
| + return shift ? '~' : '`';
|
| + case base::VKEY_OEM_4:
|
| + return shift ? '}' : ']';
|
| + case base::VKEY_OEM_5:
|
| + return shift ? '|' : '\\';
|
| + case base::VKEY_OEM_6:
|
| + return shift ? '{' : '[';
|
| + case base::VKEY_OEM_7:
|
| + return shift ? '"' : '\'';
|
| +//
|
| +// case base::VKEY_F1:
|
| +// case base::VKEY_F2:
|
| +// case base::VKEY_F3:
|
| +// case base::VKEY_F4:
|
| +// case base::VKEY_F5:
|
| +// case base::VKEY_F6:
|
| +// case base::VKEY_F7:
|
| +// case base::VKEY_F8:
|
| +// case base::VKEY_F9:
|
| +// case base::VKEY_F10:
|
| +// case base::VKEY_F11:
|
| +// case base::VKEY_F12:
|
| +// case base::VKEY_F13:
|
| +// case base::VKEY_F14:
|
| +// case base::VKEY_F15:
|
| +// case base::VKEY_F16:
|
| +// case base::VKEY_F17:
|
| +// case base::VKEY_F18:
|
| +// case base::VKEY_F19:
|
| +// case base::VKEY_F20:
|
| +// case base::VKEY_F21:
|
| +// case base::VKEY_F22:
|
| +// case base::VKEY_F23:
|
| +// case base::VKEY_F24:
|
| +// return GDK_F1 + (keycode - base::VKEY_F1);
|
| +
|
| + default:
|
| + return 0;
|
| + }
|
| + }
|
| +}
|
|
|
| Property changes on: views/controls/textfield/textfield_view.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|