Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / mojo / examples / keyboard / keyboard_view.cc
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