Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(406)

Side by Side Diff: views/controls/combobox/native_combobox_views.cc

Issue 8682011: views: Move combobox directory to ui/views/controls/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "views/controls/combobox/native_combobox_views.h"
6
7 #include <algorithm>
8
9 #include "base/command_line.h"
10 #include "base/utf_string_conversions.h"
11 #include "ui/base/keycodes/keyboard_codes.h"
12 #include "ui/base/models/combobox_model.h"
13 #include "ui/base/resource/resource_bundle.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/gfx/canvas_skia.h"
16 #include "ui/gfx/font.h"
17 #include "ui/gfx/path.h"
18 #include "ui/views/widget/root_view.h"
19 #include "ui/views/widget/widget.h"
20 #include "views/background.h"
21 #include "views/border.h"
22 #include "views/controls/combobox/combobox.h"
23 #include "views/controls/focusable_border.h"
24 #include "views/controls/menu/menu_runner.h"
25 #include "views/controls/menu/submenu_view.h"
26
27 #if defined(OS_LINUX)
28 #include "ui/gfx/gtk_util.h"
29 #endif
30
31 namespace {
32
33 // Define the size of the insets.
34 const int kTopInsetSize = 4;
35 const int kLeftInsetSize = 4;
36 const int kBottomInsetSize = 4;
37 const int kRightInsetSize = 4;
38
39 // Limit how small a combobox can be.
40 const int kMinComboboxWidth = 148;
41
42 // Size of the combobox arrow.
43 const int kComboboxArrowSize = 9;
44 const int kComboboxArrowOffset = 7;
45 const int kComboboxArrowMargin = 12;
46
47 // Color settings for text and border.
48 // These are tentative, and should be derived from theme, system
49 // settings and current settings.
50 const SkColor kDefaultBorderColor = SK_ColorGRAY;
51 const SkColor kTextColor = SK_ColorBLACK;
52
53 // Define the id of the first item in the menu (since it needs to be > 0)
54 const int kFirstMenuItemId = 1000;
55
56 } // namespace
57
58 namespace views {
59
60 const char NativeComboboxViews::kViewClassName[] =
61 "views/NativeComboboxViews";
62
63 NativeComboboxViews::NativeComboboxViews(Combobox* parent)
64 : combobox_(parent),
65 text_border_(new FocusableBorder()),
66 dropdown_open_(false),
67 selected_item_(-1),
68 content_width_(0),
69 content_height_(0) {
70 set_border(text_border_);
71 }
72
73 NativeComboboxViews::~NativeComboboxViews() {
74 }
75
76 ////////////////////////////////////////////////////////////////////////////////
77 // NativeComboboxViews, View overrides:
78
79 bool NativeComboboxViews::OnMousePressed(const views::MouseEvent& mouse_event) {
80 combobox_->RequestFocus();
81 if (mouse_event.IsLeftMouseButton()) {
82 UpdateFromModel();
83 ShowDropDownMenu();
84 }
85
86 return true;
87 }
88
89 bool NativeComboboxViews::OnMouseDragged(const views::MouseEvent& mouse_event) {
90 return true;
91 }
92
93 bool NativeComboboxViews::OnKeyPressed(const views::KeyEvent& key_event) {
94 // TODO(oshima): handle IME.
95 DCHECK(key_event.type() == ui::ET_KEY_PRESSED);
96
97 // Check if we are in the default state (-1) and set to first item.
98 if(selected_item_ == -1)
99 selected_item_ = 0;
100
101 int new_item = selected_item_;
102 switch(key_event.key_code()){
103
104 // move to the next element if any
105 case ui::VKEY_DOWN:
106 if (new_item < (combobox_->model()->GetItemCount() - 1))
107 new_item++;
108 break;
109
110 // move to the end of the list
111 case ui::VKEY_END:
112 case ui::VKEY_NEXT:
113 new_item = combobox_->model()->GetItemCount() - 1;
114 break;
115
116 // move to the top of the list
117 case ui::VKEY_HOME:
118 case ui::VKEY_PRIOR:
119 new_item = 0;
120 break;
121
122 // move to the previous element if any
123 case ui::VKEY_UP:
124 if (new_item > 0)
125 new_item--;
126 break;
127
128 default:
129 return false;
130
131 }
132
133 if(new_item != selected_item_) {
134 selected_item_ = new_item;
135 combobox_->SelectionChanged();
136 SchedulePaint();
137 }
138
139 return true;
140 }
141
142 bool NativeComboboxViews::OnKeyReleased(const views::KeyEvent& key_event) {
143 return true;
144 }
145
146 void NativeComboboxViews::OnPaint(gfx::Canvas* canvas) {
147 text_border_->set_has_focus(combobox_->HasFocus());
148 OnPaintBackground(canvas);
149 PaintText(canvas);
150 OnPaintBorder(canvas);
151 }
152
153 void NativeComboboxViews::OnFocus() {
154 NOTREACHED();
155 }
156
157 void NativeComboboxViews::OnBlur() {
158 NOTREACHED();
159 }
160
161 /////////////////////////////////////////////////////////////////
162 // NativeComboboxViews, NativeComboboxWrapper overrides:
163
164 void NativeComboboxViews::UpdateFromModel() {
165 int max_width = 0;
166 const gfx::Font &font = GetFont();
167
168 MenuItemView* menu = new MenuItemView(this);
169 // MenuRunner owns |menu|.
170 dropdown_list_menu_runner_.reset(new MenuRunner(menu));
171
172 int num_items = combobox_->model()->GetItemCount();
173 for (int i = 0; i < num_items; ++i) {
174 string16 text = combobox_->model()->GetItemAt(i);
175
176 // Inserting the Unicode formatting characters if necessary so that the
177 // text is displayed correctly in right-to-left UIs.
178 base::i18n::AdjustStringForLocaleDirection(&text);
179
180 menu->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL);
181 max_width = std::max(max_width, font.GetStringWidth(text));
182 }
183
184 content_width_ = max_width;
185 content_height_ = font.GetFontSize();
186 }
187
188 void NativeComboboxViews::UpdateSelectedItem() {
189 selected_item_ = combobox_->selected_item();
190 }
191
192 void NativeComboboxViews::UpdateEnabled() {
193 SetEnabled(combobox_->IsEnabled());
194 }
195
196 int NativeComboboxViews::GetSelectedItem() const {
197 return selected_item_;
198 }
199
200 bool NativeComboboxViews::IsDropdownOpen() const {
201 return dropdown_open_;
202 }
203
204 gfx::Size NativeComboboxViews::GetPreferredSize() {
205 if (content_width_ == 0)
206 UpdateFromModel();
207
208 // TODO(saintlou) the preferred size will drive the local bounds
209 // which in turn is used to set the minimum width for the dropdown
210 gfx::Insets insets = GetInsets();
211 return gfx::Size(std::min(kMinComboboxWidth,
212 content_width_ + 2 * (insets.width())),
213 content_height_ + 2 * (insets.height()));
214 }
215
216 View* NativeComboboxViews::GetView() {
217 return this;
218 }
219
220 void NativeComboboxViews::SetFocus() {
221 text_border_->set_has_focus(true);
222 }
223
224 bool NativeComboboxViews::HandleKeyPressed(const KeyEvent& e) {
225 return OnKeyPressed(e);
226 }
227
228 bool NativeComboboxViews::HandleKeyReleased(const KeyEvent& e) {
229 return true;
230 }
231
232 void NativeComboboxViews::HandleFocus() {
233 SchedulePaint();
234 }
235
236 void NativeComboboxViews::HandleBlur() {
237 }
238
239 gfx::NativeView NativeComboboxViews::GetTestingHandle() const {
240 NOTREACHED();
241 return NULL;
242 }
243
244 /////////////////////////////////////////////////////////////////
245 // NativeComboboxViews, views::MenuDelegate overrides:
246 // (note that the id received is offset by kFirstMenuItemId)
247
248 bool NativeComboboxViews::IsItemChecked(int id) const {
249 return false;
250 }
251
252 bool NativeComboboxViews::IsCommandEnabled(int id) const {
253 return true;
254 }
255
256 void NativeComboboxViews::ExecuteCommand(int id) {
257 // revert menu offset to map back to combobox model
258 id -= kFirstMenuItemId;
259 DCHECK_LT(id, combobox_->model()->GetItemCount());
260 selected_item_ = id;
261 combobox_->SelectionChanged();
262 SchedulePaint();
263 }
264
265 bool NativeComboboxViews::GetAccelerator(int id, ui::Accelerator* accel) {
266 return false;
267 }
268
269 /////////////////////////////////////////////////////////////////
270 // NativeComboboxViews private methods:
271
272 const gfx::Font& NativeComboboxViews::GetFont() const {
273 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
274 return rb.GetFont(ResourceBundle::BaseFont);
275 }
276
277 // tip_x and tip_y are the coordinates of the tip of an arrow head which is
278 // drawn as an isoscele triangle
279 // shift_x and shift_y are offset from tip_x and tip_y to specify the relative
280 // positions of the 2 equal angles (ie not the angle at the tip of the arrow)
281 // Note: the width of the base (the side opposite the tip) is 2 * shift_x
282 void NativeComboboxViews::DrawArrow(gfx::Canvas* canvas,
283 int tip_x,
284 int tip_y,
285 int shift_x,
286 int shift_y) const {
287 SkPaint paint;
288 paint.setStyle(SkPaint::kStrokeAndFill_Style);
289 paint.setColor(kTextColor);
290 paint.setAntiAlias(true);
291 gfx::Path path;
292 path.incReserve(4);
293 path.moveTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
294 path.lineTo(SkIntToScalar(tip_x + shift_x), SkIntToScalar(tip_y + shift_y));
295 path.lineTo(SkIntToScalar(tip_x - shift_x), SkIntToScalar(tip_y + shift_y));
296 path.close();
297 canvas->GetSkCanvas()->drawPath(path, paint);
298 }
299
300
301 void NativeComboboxViews::PaintText(gfx::Canvas* canvas) {
302 gfx::Insets insets = GetInsets();
303
304 canvas->Save();
305 canvas->ClipRect(GetContentsBounds());
306
307 int x = insets.left();
308 int y = insets.top();
309 int text_height = height() - insets.height();
310 SkColor text_color = kTextColor;
311
312 int index = GetSelectedItem();
313 if (index < 0 || index > combobox_->model()->GetItemCount())
314 index = 0;
315 string16 text = combobox_->model()->GetItemAt(index);
316
317 const gfx::Font& font = GetFont();
318 int width = font.GetStringWidth(text);
319
320 canvas->DrawStringInt(text, font, text_color, x, y, width, text_height);
321
322 // draw the double arrow
323 gfx::Rect lb = GetLocalBounds();
324 DrawArrow(canvas,
325 lb.width() - (kComboboxArrowSize / 2) - kComboboxArrowOffset,
326 lb.height() / 2 - kComboboxArrowSize,
327 kComboboxArrowSize / 2,
328 kComboboxArrowSize - 2);
329 DrawArrow(canvas,
330 lb.width() - (kComboboxArrowSize / 2) - kComboboxArrowOffset,
331 lb.height() / 2 + kComboboxArrowSize,
332 -kComboboxArrowSize / 2,
333 -(kComboboxArrowSize - 2));
334
335 // draw the margin
336 canvas->DrawLineInt(kDefaultBorderColor,
337 lb.width() - kComboboxArrowSize - kComboboxArrowMargin,
338 kTopInsetSize,
339 lb.width() - kComboboxArrowSize - kComboboxArrowMargin,
340 lb.height() - kBottomInsetSize);
341
342 canvas->Restore();
343 }
344
345 void NativeComboboxViews::ShowDropDownMenu() {
346
347 if (!dropdown_list_menu_runner_.get())
348 UpdateFromModel();
349
350 // Extend the menu to the width of the combobox.
351 SubmenuView* submenu = dropdown_list_menu_runner_->GetMenu()->CreateSubmenu();
352 submenu->set_minimum_preferred_width(size().width());
353
354 gfx::Rect lb = GetLocalBounds();
355 gfx::Point menu_position(lb.origin());
356 View::ConvertPointToScreen(this, &menu_position);
357 if (menu_position.x() < 0)
358 menu_position.set_x(0);
359
360 gfx::Rect bounds(menu_position, lb.size());
361
362 dropdown_open_ = true;
363 if (dropdown_list_menu_runner_->RunMenuAt(
364 NULL, NULL, bounds, MenuItemView::TOPLEFT,
365 MenuRunner::HAS_MNEMONICS) == MenuRunner::MENU_DELETED)
366 return;
367 dropdown_open_ = false;
368
369 // Need to explicitly clear mouse handler so that events get sent
370 // properly after the menu finishes running. If we don't do this, then
371 // the first click to other parts of the UI is eaten.
372 SetMouseHandler(NULL);
373 }
374
375 ////////////////////////////////////////////////////////////////////////////////
376 // NativeComboboxWrapper, public:
377
378 #if defined(USE_AURA)
379 // static
380 NativeComboboxWrapper* NativeComboboxWrapper::CreateWrapper(
381 Combobox* combobox) {
382 return new NativeComboboxViews(combobox);
383 }
384 #endif
385
386 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/combobox/native_combobox_views.h ('k') | views/controls/combobox/native_combobox_views_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698