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"
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"
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
) {
37 gfx::FontList last_font
;
38 while (gfx::Canvas::GetStringWidth(text
, font
) < width
&&
39 font
.GetHeight() < height
) {
41 font
= font
.DeriveWithSizeDelta(2);
46 // Returns the total number of keys in |rows|.
47 int NumKeys(const std::vector
<const Row
*>& rows
) {
49 for (size_t i
= 0; i
< rows
.size(); ++i
)
50 result
+= static_cast<int>(rows
[i
]->num_keys
);
56 KeyboardView::KeyboardView(KeyboardDelegate
* delegate
)
57 : delegate_(delegate
),
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())
72 last_layout_size_
= bounds().size();
74 const int button_width
=
75 (width() - (max_keys_in_row_
- 1) * kHorizontalPadding
) /
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
,
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"));
96 ResetFonts(font
, special_font
);
99 void KeyboardView::SetLayout(KeyboardLayout keyboard_layout
) {
100 if (keyboard_layout_
== keyboard_layout
)
103 keyboard_layout_
= keyboard_layout
;
104 last_layout_size_
= gfx::Size();
105 if (keyboard_layout_
== KEYBOARD_LAYOUT_NUMERIC
)
106 SetRows(GetNumericRows());
108 SetRows(GetQWERTYRows());
113 void KeyboardView::LayoutRow(const Row
& row
,
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();
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
:
158 button
->SetText(base::string16());
160 case SPECIAL_KEY_NUMERIC
:
161 button
->SetText(base::ASCIIToUTF16("?123"));
163 case SPECIAL_KEY_ALPHA
:
164 button
->SetText(base::ASCIIToUTF16("ABC"));
167 button
->SetText(GetDisplayString(key
.display_code
,
168 key
.event_flags
| event_flags()));
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
186 button
->SetAnimationDuration(0);
190 views::LabelButton
* KeyboardView::GetButton(int row
, int 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
);
201 while (index
>= static_cast<int>(rows_
[row
]->num_keys
)) {
202 index
-= static_cast<int>(rows_
[row
]->num_keys
);
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
);
221 button
->SetFontList(button_font
);
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
);
236 case SPECIAL_KEY_ALPHA
:
237 SetLayout(KEYBOARD_LAYOUT_ALPHA
);
239 case SPECIAL_KEY_NUMERIC
:
240 SetLayout(KEYBOARD_LAYOUT_NUMERIC
);
246 // Windows isn't happy if we pass in the flags used to get the display string.
248 int key_event_flags
= 0;
250 int key_event_flags
= key
.event_flags
;
252 delegate_
->OnKeyPressed(key
.keyboard_code(), key_event_flags
| event_flags());
255 } // namespace examples