Introduce new SPDY Version UMA histogram.
[chromium-blink-merge.git] / mojo / examples / keyboard / keyboard_view.cc
blob3a0d71ac48d5458733ab3b71daa72ca101cc4aee
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.
5 #include "mojo/examples/keyboard/keyboard_view.h"
7 #include <algorithm>
9 #include "base/strings/string16.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "mojo/examples/keyboard/keyboard_delegate.h"
12 #include "mojo/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"
20 namespace mojo {
21 namespace examples {
23 namespace {
25 const int kHorizontalPadding = 6;
26 const int kVerticalPadding = 8;
28 base::string16 GetDisplayString(int key_code, int flags) {
29 return base::string16(1, ui::GetCharacterFromKeyCode(
30 static_cast<ui::KeyboardCode>(key_code), flags));
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);
43 return last_font;
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;
54 } // namespace
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());
64 KeyboardView::~KeyboardView() {
67 void KeyboardView::Layout() {
68 if (width() == 0 || height() == 0 || rows_.empty() ||
69 last_layout_size_ == bounds().size())
70 return;
72 last_layout_size_ = bounds().size();
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);
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);
99 void KeyboardView::SetLayout(KeyboardLayout keyboard_layout) {
100 if (keyboard_layout_ == keyboard_layout)
101 return;
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();
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;
127 button->SetBounds(x, y, actual_width, button_height);
128 x += actual_width + kHorizontalPadding;
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());
139 last_layout_size_ = gfx::Size();
141 rows_ = rows;
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]);
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;
171 button->SetState(views::Button::STATE_NORMAL);
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;
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));
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++;
205 return rows_[row]->keys[index];
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;
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;
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());
255 } // namespace examples
256 } // namespace mojo