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 "mojo/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 "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" | |
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 |