| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "examples/keyboard/keyboard_view.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/strings/string16.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "examples/keyboard/keyboard_delegate.h" | |
| 12 #include "examples/keyboard/keys.h" | |
| 13 #include "ui/events/keycodes/keyboard_code_conversion.h" | |
| 14 #include "ui/events/keycodes/keyboard_codes.h" | |
| 15 #include "ui/gfx/canvas.h" | |
| 16 #include "ui/views/background.h" | |
| 17 #include "ui/views/controls/button/label_button.h" | |
| 18 #include "ui/views/controls/button/label_button_border.h" | |
| 19 | |
| 20 namespace mojo { | |
| 21 namespace examples { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 const int kHorizontalPadding = 6; | |
| 26 const int kVerticalPadding = 8; | |
| 27 | |
| 28 base::string16 GetDisplayString(int key_code, int flags) { | |
| 29 return base::string16(1, ui::GetCharacterFromKeyCode( | |
| 30 static_cast<ui::KeyboardCode>(key_code), flags)); | |
| 31 } | |
| 32 | |
| 33 // Returns a font that fits in the space provided. |text| is used as a basis | |
| 34 // for determing the size. | |
| 35 gfx::FontList CalculateFont(int width, int height, const base::string16& text) { | |
| 36 gfx::FontList font; | |
| 37 gfx::FontList last_font; | |
| 38 while (gfx::Canvas::GetStringWidth(text, font) < width && | |
| 39 font.GetHeight() < height) { | |
| 40 last_font = font; | |
| 41 font = font.DeriveWithSizeDelta(2); | |
| 42 } | |
| 43 return last_font; | |
| 44 } | |
| 45 | |
| 46 // Returns the total number of keys in |rows|. | |
| 47 int NumKeys(const std::vector<const Row*>& rows) { | |
| 48 int result = 0; | |
| 49 for (size_t i = 0; i < rows.size(); ++i) | |
| 50 result += static_cast<int>(rows[i]->num_keys); | |
| 51 return result; | |
| 52 } | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 KeyboardView::KeyboardView(KeyboardDelegate* delegate) | |
| 57 : delegate_(delegate), | |
| 58 max_keys_in_row_(0), | |
| 59 keyboard_layout_(KEYBOARD_LAYOUT_ALPHA) { | |
| 60 set_background(views::Background::CreateSolidBackground(SK_ColorBLACK)); | |
| 61 SetRows(GetQWERTYRows()); | |
| 62 } | |
| 63 | |
| 64 KeyboardView::~KeyboardView() { | |
| 65 } | |
| 66 | |
| 67 void KeyboardView::Layout() { | |
| 68 if (width() == 0 || height() == 0 || rows_.empty() || | |
| 69 last_layout_size_ == bounds().size()) | |
| 70 return; | |
| 71 | |
| 72 last_layout_size_ = bounds().size(); | |
| 73 | |
| 74 const int button_width = | |
| 75 (width() - (max_keys_in_row_ - 1) * kHorizontalPadding) / | |
| 76 max_keys_in_row_; | |
| 77 const int button_height = | |
| 78 (height() - (static_cast<int>(rows_.size() - 1) * kVerticalPadding)) / | |
| 79 static_cast<int>(rows_.size()); | |
| 80 const int initial_x = (width() - button_width * max_keys_in_row_ - | |
| 81 kHorizontalPadding * (max_keys_in_row_ - 1)) / 2; | |
| 82 for (size_t i = 0; i < rows_.size(); ++i) { | |
| 83 LayoutRow(*(rows_[i]), static_cast<int>(i), initial_x, button_width, | |
| 84 button_height); | |
| 85 } | |
| 86 | |
| 87 views::LabelButtonBorder border(views::Button::STYLE_TEXTBUTTON); | |
| 88 gfx::Insets insets(border.GetInsets()); | |
| 89 gfx::FontList font = CalculateFont(button_width - insets.width(), | |
| 90 button_height - insets.height(), | |
| 91 base::ASCIIToUTF16("W")); | |
| 92 gfx::FontList special_font = CalculateFont(button_width - insets.width(), | |
| 93 button_height - insets.height(), | |
| 94 base::ASCIIToUTF16("?123")); | |
| 95 button_font_ = font; | |
| 96 ResetFonts(font, special_font); | |
| 97 } | |
| 98 | |
| 99 void KeyboardView::SetLayout(KeyboardLayout keyboard_layout) { | |
| 100 if (keyboard_layout_ == keyboard_layout) | |
| 101 return; | |
| 102 | |
| 103 keyboard_layout_ = keyboard_layout; | |
| 104 last_layout_size_ = gfx::Size(); | |
| 105 if (keyboard_layout_ == KEYBOARD_LAYOUT_NUMERIC) | |
| 106 SetRows(GetNumericRows()); | |
| 107 else | |
| 108 SetRows(GetQWERTYRows()); | |
| 109 Layout(); | |
| 110 SchedulePaint(); | |
| 111 } | |
| 112 | |
| 113 void KeyboardView::LayoutRow(const Row& row, | |
| 114 int row_index, | |
| 115 int initial_x, | |
| 116 int button_width, | |
| 117 int button_height) { | |
| 118 int x = initial_x + row.padding * (button_width + kHorizontalPadding); | |
| 119 const int y = row_index * (button_height + kVerticalPadding); | |
| 120 for (size_t i = 0; i < row.num_keys; ++i) { | |
| 121 views::View* button = GetButton(row_index, static_cast<int>(i)); | |
| 122 int actual_width = button_width; | |
| 123 if (row.keys[i].size > 1) { | |
| 124 actual_width = (button_width + kHorizontalPadding) * | |
| 125 row.keys[i].size - kHorizontalPadding; | |
| 126 } | |
| 127 button->SetBounds(x, y, actual_width, button_height); | |
| 128 x += actual_width + kHorizontalPadding; | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 void KeyboardView::SetRows(const std::vector<const Row*>& rows) { | |
| 133 const int num_keys = NumKeys(rows); | |
| 134 while (child_count() > num_keys) | |
| 135 delete child_at(child_count() - 1); | |
| 136 for (int i = child_count(); i < num_keys; ++i) | |
| 137 AddChildView(CreateButton()); | |
| 138 | |
| 139 last_layout_size_ = gfx::Size(); | |
| 140 | |
| 141 rows_ = rows; | |
| 142 | |
| 143 max_keys_in_row_ = 0; | |
| 144 for (size_t i = 0; i < rows_.size(); ++i) { | |
| 145 max_keys_in_row_ = std::max(max_keys_in_row_, | |
| 146 static_cast<int>(rows_[i]->num_keys)); | |
| 147 ConfigureButtonsInRow(static_cast<int>(i), *rows_[i]); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 void KeyboardView::ConfigureButtonsInRow(int row_index, const Row& row) { | |
| 152 for (size_t i = 0; i < row.num_keys; ++i) { | |
| 153 views::LabelButton* button = GetButton(row_index, static_cast<int>(i)); | |
| 154 const Key& key(row.keys[i]); | |
| 155 switch (key.display_code) { | |
| 156 case SPECIAL_KEY_SHIFT: | |
| 157 // TODO: need image. | |
| 158 button->SetText(base::string16()); | |
| 159 break; | |
| 160 case SPECIAL_KEY_NUMERIC: | |
| 161 button->SetText(base::ASCIIToUTF16("?123")); | |
| 162 break; | |
| 163 case SPECIAL_KEY_ALPHA: | |
| 164 button->SetText(base::ASCIIToUTF16("ABC")); | |
| 165 break; | |
| 166 default: | |
| 167 button->SetText(GetDisplayString(key.display_code, | |
| 168 key.event_flags | event_flags())); | |
| 169 break; | |
| 170 } | |
| 171 button->SetState(views::Button::STATE_NORMAL); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 views::View* KeyboardView::CreateButton() { | |
| 176 views::LabelButton* button = new views::LabelButton(this, base::string16()); | |
| 177 button->SetTextColor(views::Button::STATE_NORMAL, SK_ColorWHITE); | |
| 178 button->SetHorizontalAlignment(gfx::ALIGN_CENTER); | |
| 179 button->set_background(views::Background::CreateSolidBackground(78, 78, 78)); | |
| 180 button->SetFontList(button_font_); | |
| 181 // button->SetHaloColor(SK_ColorBLACK); | |
| 182 // Turn off animations as we reuse buttons in different layouts. If we didn't | |
| 183 // do this and you click a button to change the layout then the button you | |
| 184 // clicked on would animate the transition even though it may now represent a | |
| 185 // different key. | |
| 186 button->SetAnimationDuration(0); | |
| 187 return button; | |
| 188 } | |
| 189 | |
| 190 views::LabelButton* KeyboardView::GetButton(int row, int column) { | |
| 191 int offset = column; | |
| 192 for (int i = 0; i < row; ++i) | |
| 193 offset += static_cast<int>(rows_[i]->num_keys); | |
| 194 return static_cast<views::LabelButton*>(child_at(offset)); | |
| 195 } | |
| 196 | |
| 197 const Key& KeyboardView::GetKeyForButton(views::Button* button) const { | |
| 198 int index = GetIndexOf(button); | |
| 199 DCHECK_NE(-1, index); | |
| 200 int row = 0; | |
| 201 while (index >= static_cast<int>(rows_[row]->num_keys)) { | |
| 202 index -= static_cast<int>(rows_[row]->num_keys); | |
| 203 row++; | |
| 204 } | |
| 205 return rows_[row]->keys[index]; | |
| 206 } | |
| 207 | |
| 208 void KeyboardView::ResetFonts(const gfx::FontList& button_font, | |
| 209 const gfx::FontList& special_font) { | |
| 210 for (size_t i = 0; i < rows_.size(); ++i) { | |
| 211 for (size_t j = 0; j < rows_[i]->num_keys; ++j) { | |
| 212 views::LabelButton* button = GetButton(static_cast<int>(i), | |
| 213 static_cast<int>(j)); | |
| 214 const Key& key(GetKeyForButton(button)); | |
| 215 switch (key.display_code) { | |
| 216 case SPECIAL_KEY_ALPHA: | |
| 217 case SPECIAL_KEY_NUMERIC: | |
| 218 button->SetFontList(special_font); | |
| 219 break; | |
| 220 default: | |
| 221 button->SetFontList(button_font); | |
| 222 break; | |
| 223 } | |
| 224 } | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 void KeyboardView::ButtonPressed(views::Button* sender, | |
| 229 const ui::Event& event) { | |
| 230 const Key& key(GetKeyForButton(sender)); | |
| 231 switch (key.display_code) { | |
| 232 case SPECIAL_KEY_SHIFT: | |
| 233 SetLayout((keyboard_layout_ == KEYBOARD_LAYOUT_SHIFT) ? | |
| 234 KEYBOARD_LAYOUT_ALPHA : KEYBOARD_LAYOUT_SHIFT); | |
| 235 return; | |
| 236 case SPECIAL_KEY_ALPHA: | |
| 237 SetLayout(KEYBOARD_LAYOUT_ALPHA); | |
| 238 return; | |
| 239 case SPECIAL_KEY_NUMERIC: | |
| 240 SetLayout(KEYBOARD_LAYOUT_NUMERIC); | |
| 241 return; | |
| 242 default: | |
| 243 break; | |
| 244 } | |
| 245 | |
| 246 // Windows isn't happy if we pass in the flags used to get the display string. | |
| 247 #if defined(OS_WIN) | |
| 248 int key_event_flags = 0; | |
| 249 #else | |
| 250 int key_event_flags = key.event_flags; | |
| 251 #endif | |
| 252 delegate_->OnKeyPressed(key.keyboard_code(), key_event_flags | event_flags()); | |
| 253 } | |
| 254 | |
| 255 } // namespace examples | |
| 256 } // namespace mojo | |
| OLD | NEW |