OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "views/controls/text_field.h" | 5 #include "views/controls/textfield/textfield.h" |
6 | 6 |
7 #include <atlbase.h> | 7 #include <atlbase.h> |
8 #include <atlapp.h> | 8 #include <atlapp.h> |
9 #include <atlcrack.h> | 9 #include <atlcrack.h> |
10 #include <atlctrls.h> | 10 #include <atlctrls.h> |
11 #include <atlmisc.h> | 11 #include <atlmisc.h> |
12 #include <tom.h> // For ITextDocument, a COM interface to CRichEditCtrl | 12 #include <tom.h> // For ITextDocument, a COM interface to CRichEditCtrl |
13 #include <vsstyle.h> | 13 #include <vsstyle.h> |
14 | 14 |
15 #include "app/gfx/insets.h" | 15 #include "app/gfx/insets.h" |
(...skipping 12 matching lines...) Expand all Loading... |
28 #include "views/focus/focus_util_win.h" | 28 #include "views/focus/focus_util_win.h" |
29 #include "views/views_delegate.h" | 29 #include "views/views_delegate.h" |
30 #include "views/widget/widget.h" | 30 #include "views/widget/widget.h" |
31 | 31 |
32 using gfx::NativeTheme; | 32 using gfx::NativeTheme; |
33 | 33 |
34 namespace views { | 34 namespace views { |
35 | 35 |
36 static const int kDefaultEditStyle = WS_CHILD | WS_VISIBLE; | 36 static const int kDefaultEditStyle = WS_CHILD | WS_VISIBLE; |
37 | 37 |
38 class TextField::Edit | 38 class Textfield::Edit |
39 : public CWindowImpl<TextField::Edit, CRichEditCtrl, | 39 : public CWindowImpl<Textfield::Edit, CRichEditCtrl, |
40 CWinTraits<kDefaultEditStyle> >, | 40 CWinTraits<kDefaultEditStyle> >, |
41 public CRichEditCommands<TextField::Edit>, | 41 public CRichEditCommands<Textfield::Edit>, |
42 public Menu::Delegate { | 42 public Menu::Delegate { |
43 public: | 43 public: |
44 DECLARE_WND_CLASS(L"ChromeViewsTextFieldEdit"); | 44 DECLARE_WND_CLASS(L"ChromeViewsTextfieldEdit"); |
45 | 45 |
46 Edit(TextField* parent, bool draw_border); | 46 Edit(Textfield* parent, bool draw_border); |
47 ~Edit(); | 47 ~Edit(); |
48 | 48 |
49 std::wstring GetText() const; | 49 std::wstring GetText() const; |
50 void SetText(const std::wstring& text); | 50 void SetText(const std::wstring& text); |
51 void AppendText(const std::wstring& text); | 51 void AppendText(const std::wstring& text); |
52 | 52 |
53 std::wstring GetSelectedText() const; | 53 std::wstring GetSelectedText() const; |
54 | 54 |
55 // Selects all the text in the edit. Use this in place of SetSelAll() to | 55 // Selects all the text in the edit. Use this in place of SetSelAll() to |
56 // avoid selecting the "phantom newline" at the end of the edit. | 56 // avoid selecting the "phantom newline" at the end of the edit. |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 bool can_discard_mousemove_; | 179 bool can_discard_mousemove_; |
180 | 180 |
181 // The text of this control before a possible change. | 181 // The text of this control before a possible change. |
182 std::wstring text_before_change_; | 182 std::wstring text_before_change_; |
183 | 183 |
184 // If true, the mouse is over the edit. | 184 // If true, the mouse is over the edit. |
185 bool contains_mouse_; | 185 bool contains_mouse_; |
186 | 186 |
187 static bool did_load_library_; | 187 static bool did_load_library_; |
188 | 188 |
189 TextField* parent_; | 189 Textfield* parent_; |
190 | 190 |
191 // The context menu for the edit. | 191 // The context menu for the edit. |
192 scoped_ptr<Menu> context_menu_; | 192 scoped_ptr<Menu> context_menu_; |
193 | 193 |
194 // Border insets. | 194 // Border insets. |
195 gfx::Insets content_insets_; | 195 gfx::Insets content_insets_; |
196 | 196 |
197 // Whether the border is drawn. | 197 // Whether the border is drawn. |
198 bool draw_border_; | 198 bool draw_border_; |
199 | 199 |
200 // This interface is useful for accessing the CRichEditCtrl at a low level. | 200 // This interface is useful for accessing the CRichEditCtrl at a low level. |
201 mutable CComQIPtr<ITextDocument> text_object_model_; | 201 mutable CComQIPtr<ITextDocument> text_object_model_; |
202 | 202 |
203 // The position and the length of the ongoing composition string. | 203 // The position and the length of the ongoing composition string. |
204 // These values are used for removing a composition string from a search | 204 // These values are used for removing a composition string from a search |
205 // text to emulate Firefox. | 205 // text to emulate Firefox. |
206 bool ime_discard_composition_; | 206 bool ime_discard_composition_; |
207 int ime_composition_start_; | 207 int ime_composition_start_; |
208 int ime_composition_length_; | 208 int ime_composition_length_; |
209 | 209 |
210 COLORREF bg_color_; | 210 COLORREF bg_color_; |
211 | 211 |
212 DISALLOW_COPY_AND_ASSIGN(Edit); | 212 DISALLOW_COPY_AND_ASSIGN(Edit); |
213 }; | 213 }; |
214 | 214 |
215 /////////////////////////////////////////////////////////////////////////////// | 215 /////////////////////////////////////////////////////////////////////////////// |
216 // Helper classes | 216 // Helper classes |
217 | 217 |
218 TextField::Edit::ScopedFreeze::ScopedFreeze(TextField::Edit* edit, | 218 Textfield::Edit::ScopedFreeze::ScopedFreeze(Textfield::Edit* edit, |
219 ITextDocument* text_object_model) | 219 ITextDocument* text_object_model) |
220 : edit_(edit), | 220 : edit_(edit), |
221 text_object_model_(text_object_model) { | 221 text_object_model_(text_object_model) { |
222 // Freeze the screen. | 222 // Freeze the screen. |
223 if (text_object_model_) { | 223 if (text_object_model_) { |
224 long count; | 224 long count; |
225 text_object_model_->Freeze(&count); | 225 text_object_model_->Freeze(&count); |
226 } | 226 } |
227 } | 227 } |
228 | 228 |
229 TextField::Edit::ScopedFreeze::~ScopedFreeze() { | 229 Textfield::Edit::ScopedFreeze::~ScopedFreeze() { |
230 // Unfreeze the screen. | 230 // Unfreeze the screen. |
231 if (text_object_model_) { | 231 if (text_object_model_) { |
232 long count; | 232 long count; |
233 text_object_model_->Unfreeze(&count); | 233 text_object_model_->Unfreeze(&count); |
234 if (count == 0) { | 234 if (count == 0) { |
235 // We need to UpdateWindow() here instead of InvalidateRect() because, as | 235 // We need to UpdateWindow() here instead of InvalidateRect() because, as |
236 // far as I can tell, the edit likes to synchronously erase its background | 236 // far as I can tell, the edit likes to synchronously erase its background |
237 // when unfreezing, thus requiring us to synchronously redraw if we don't | 237 // when unfreezing, thus requiring us to synchronously redraw if we don't |
238 // want flicker. | 238 // want flicker. |
239 edit_->UpdateWindow(); | 239 edit_->UpdateWindow(); |
240 } | 240 } |
241 } | 241 } |
242 } | 242 } |
243 | 243 |
244 /////////////////////////////////////////////////////////////////////////////// | 244 /////////////////////////////////////////////////////////////////////////////// |
245 // TextField::Edit | 245 // Textfield::Edit |
246 | 246 |
247 bool TextField::Edit::did_load_library_ = false; | 247 bool Textfield::Edit::did_load_library_ = false; |
248 | 248 |
249 TextField::Edit::Edit(TextField* parent, bool draw_border) | 249 Textfield::Edit::Edit(Textfield* parent, bool draw_border) |
250 : parent_(parent), | 250 : parent_(parent), |
251 tracking_double_click_(false), | 251 tracking_double_click_(false), |
252 double_click_time_(0), | 252 double_click_time_(0), |
253 can_discard_mousemove_(false), | 253 can_discard_mousemove_(false), |
254 contains_mouse_(false), | 254 contains_mouse_(false), |
255 draw_border_(draw_border), | 255 draw_border_(draw_border), |
256 ime_discard_composition_(false), | 256 ime_discard_composition_(false), |
257 ime_composition_start_(0), | 257 ime_composition_start_(0), |
258 ime_composition_length_(0), | 258 ime_composition_length_(0), |
259 bg_color_(0) { | 259 bg_color_(0) { |
260 if (!did_load_library_) | 260 if (!did_load_library_) |
261 did_load_library_ = !!LoadLibrary(L"riched20.dll"); | 261 did_load_library_ = !!LoadLibrary(L"riched20.dll"); |
262 | 262 |
263 DWORD style = kDefaultEditStyle; | 263 DWORD style = kDefaultEditStyle; |
264 if (parent->GetStyle() & TextField::STYLE_PASSWORD) | 264 if (parent->GetStyle() & Textfield::STYLE_PASSWORD) |
265 style |= ES_PASSWORD; | 265 style |= ES_PASSWORD; |
266 | 266 |
267 if (parent->read_only_) | 267 if (parent->read_only_) |
268 style |= ES_READONLY; | 268 style |= ES_READONLY; |
269 | 269 |
270 if (parent->GetStyle() & TextField::STYLE_MULTILINE) | 270 if (parent->GetStyle() & Textfield::STYLE_MULTILINE) |
271 style |= ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL; | 271 style |= ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL; |
272 else | 272 else |
273 style |= ES_AUTOHSCROLL; | 273 style |= ES_AUTOHSCROLL; |
274 // Make sure we apply RTL related extended window styles if necessary. | 274 // Make sure we apply RTL related extended window styles if necessary. |
275 DWORD ex_style = l10n_util::GetExtendedStyles(); | 275 DWORD ex_style = l10n_util::GetExtendedStyles(); |
276 | 276 |
277 RECT r = {0, 0, parent_->width(), parent_->height()}; | 277 RECT r = {0, 0, parent_->width(), parent_->height()}; |
278 Create(parent_->GetWidget()->GetNativeView(), r, NULL, style, ex_style); | 278 Create(parent_->GetWidget()->GetNativeView(), r, NULL, style, ex_style); |
279 | 279 |
280 if (parent->GetStyle() & TextField::STYLE_LOWERCASE) { | 280 if (parent->GetStyle() & Textfield::STYLE_LOWERCASE) { |
281 DCHECK((parent->GetStyle() & TextField::STYLE_PASSWORD) == 0); | 281 DCHECK((parent->GetStyle() & Textfield::STYLE_PASSWORD) == 0); |
282 SetEditStyle(SES_LOWERCASE, SES_LOWERCASE); | 282 SetEditStyle(SES_LOWERCASE, SES_LOWERCASE); |
283 } | 283 } |
284 | 284 |
285 // Set up the text_object_model_. | 285 // Set up the text_object_model_. |
286 CComPtr<IRichEditOle> ole_interface; | 286 CComPtr<IRichEditOle> ole_interface; |
287 ole_interface.Attach(GetOleInterface()); | 287 ole_interface.Attach(GetOleInterface()); |
288 text_object_model_ = ole_interface; | 288 text_object_model_ = ole_interface; |
289 | 289 |
290 context_menu_.reset(new MenuWin(this, Menu::TOPLEFT, m_hWnd)); | 290 context_menu_.reset(new MenuWin(this, Menu::TOPLEFT, m_hWnd)); |
291 context_menu_->AppendMenuItemWithLabel(IDS_APP_UNDO, | 291 context_menu_->AppendMenuItemWithLabel(IDS_APP_UNDO, |
292 l10n_util::GetString(IDS_APP_UNDO)); | 292 l10n_util::GetString(IDS_APP_UNDO)); |
293 context_menu_->AppendSeparator(); | 293 context_menu_->AppendSeparator(); |
294 context_menu_->AppendMenuItemWithLabel(IDS_APP_CUT, | 294 context_menu_->AppendMenuItemWithLabel(IDS_APP_CUT, |
295 l10n_util::GetString(IDS_APP_CUT)); | 295 l10n_util::GetString(IDS_APP_CUT)); |
296 context_menu_->AppendMenuItemWithLabel(IDS_APP_COPY, | 296 context_menu_->AppendMenuItemWithLabel(IDS_APP_COPY, |
297 l10n_util::GetString(IDS_APP_COPY)); | 297 l10n_util::GetString(IDS_APP_COPY)); |
298 context_menu_->AppendMenuItemWithLabel(IDS_APP_PASTE, | 298 context_menu_->AppendMenuItemWithLabel(IDS_APP_PASTE, |
299 l10n_util::GetString(IDS_APP_PASTE)); | 299 l10n_util::GetString(IDS_APP_PASTE)); |
300 context_menu_->AppendSeparator(); | 300 context_menu_->AppendSeparator(); |
301 context_menu_->AppendMenuItemWithLabel(IDS_APP_SELECT_ALL, | 301 context_menu_->AppendMenuItemWithLabel(IDS_APP_SELECT_ALL, |
302 l10n_util::GetString(IDS_APP_SELECT_ALL
)); | 302 l10n_util::GetString(IDS_APP_SELECT_ALL
)); |
303 } | 303 } |
304 | 304 |
305 TextField::Edit::~Edit() { | 305 Textfield::Edit::~Edit() { |
306 } | 306 } |
307 | 307 |
308 std::wstring TextField::Edit::GetText() const { | 308 std::wstring Textfield::Edit::GetText() const { |
309 int len = GetTextLength() + 1; | 309 int len = GetTextLength() + 1; |
310 std::wstring str; | 310 std::wstring str; |
311 GetWindowText(WriteInto(&str, len), len); | 311 GetWindowText(WriteInto(&str, len), len); |
312 return str; | 312 return str; |
313 } | 313 } |
314 | 314 |
315 void TextField::Edit::SetText(const std::wstring& text) { | 315 void Textfield::Edit::SetText(const std::wstring& text) { |
316 // Adjusting the string direction before setting the text in order to make | 316 // Adjusting the string direction before setting the text in order to make |
317 // sure both RTL and LTR strings are displayed properly. | 317 // sure both RTL and LTR strings are displayed properly. |
318 std::wstring text_to_set; | 318 std::wstring text_to_set; |
319 if (!l10n_util::AdjustStringForLocaleDirection(text, &text_to_set)) | 319 if (!l10n_util::AdjustStringForLocaleDirection(text, &text_to_set)) |
320 text_to_set = text; | 320 text_to_set = text; |
321 if (parent_->GetStyle() & STYLE_LOWERCASE) | 321 if (parent_->GetStyle() & STYLE_LOWERCASE) |
322 text_to_set = l10n_util::ToLower(text_to_set); | 322 text_to_set = l10n_util::ToLower(text_to_set); |
323 SetWindowText(text_to_set.c_str()); | 323 SetWindowText(text_to_set.c_str()); |
324 } | 324 } |
325 | 325 |
326 void TextField::Edit::AppendText(const std::wstring& text) { | 326 void Textfield::Edit::AppendText(const std::wstring& text) { |
327 int text_length = GetWindowTextLength(); | 327 int text_length = GetWindowTextLength(); |
328 ::SendMessage(m_hWnd, TBM_SETSEL, true, MAKELPARAM(text_length, text_length)); | 328 ::SendMessage(m_hWnd, TBM_SETSEL, true, MAKELPARAM(text_length, text_length)); |
329 ::SendMessage(m_hWnd, EM_REPLACESEL, false, | 329 ::SendMessage(m_hWnd, EM_REPLACESEL, false, |
330 reinterpret_cast<LPARAM>(text.c_str())); | 330 reinterpret_cast<LPARAM>(text.c_str())); |
331 } | 331 } |
332 | 332 |
333 std::wstring TextField::Edit::GetSelectedText() const { | 333 std::wstring Textfield::Edit::GetSelectedText() const { |
334 // Figure out the length of the selection. | 334 // Figure out the length of the selection. |
335 long start; | 335 long start; |
336 long end; | 336 long end; |
337 GetSel(start, end); | 337 GetSel(start, end); |
338 | 338 |
339 // Grab the selected text. | 339 // Grab the selected text. |
340 std::wstring str; | 340 std::wstring str; |
341 GetSelText(WriteInto(&str, end - start + 1)); | 341 GetSelText(WriteInto(&str, end - start + 1)); |
342 | 342 |
343 return str; | 343 return str; |
344 } | 344 } |
345 | 345 |
346 void TextField::Edit::SelectAll() { | 346 void Textfield::Edit::SelectAll() { |
347 // Select from the end to the front so that the first part of the text is | 347 // Select from the end to the front so that the first part of the text is |
348 // always visible. | 348 // always visible. |
349 SetSel(GetTextLength(), 0); | 349 SetSel(GetTextLength(), 0); |
350 } | 350 } |
351 | 351 |
352 void TextField::Edit::ClearSelection() { | 352 void Textfield::Edit::ClearSelection() { |
353 SetSel(GetTextLength(), GetTextLength()); | 353 SetSel(GetTextLength(), GetTextLength()); |
354 } | 354 } |
355 | 355 |
356 void TextField::Edit::RemoveBorder() { | 356 void Textfield::Edit::RemoveBorder() { |
357 if (!draw_border_) | 357 if (!draw_border_) |
358 return; | 358 return; |
359 | 359 |
360 draw_border_ = false; | 360 draw_border_ = false; |
361 SetWindowPos(NULL, 0, 0, 0, 0, | 361 SetWindowPos(NULL, 0, 0, 0, 0, |
362 SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOACTIVATE | | 362 SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOACTIVATE | |
363 SWP_NOOWNERZORDER | SWP_NOSIZE); | 363 SWP_NOOWNERZORDER | SWP_NOSIZE); |
364 } | 364 } |
365 | 365 |
366 void TextField::Edit::SetEnabled(bool enabled) { | 366 void Textfield::Edit::SetEnabled(bool enabled) { |
367 SendMessage(parent_->GetNativeComponent(), WM_ENABLE, | 367 SendMessage(parent_->GetNativeComponent(), WM_ENABLE, |
368 static_cast<WPARAM>(enabled), 0); | 368 static_cast<WPARAM>(enabled), 0); |
369 } | 369 } |
370 | 370 |
371 // static | 371 // static |
372 bool TextField::IsKeystrokeEnter(const Keystroke& key) { | 372 bool Textfield::IsKeystrokeEnter(const Keystroke& key) { |
373 return key.key == VK_RETURN; | 373 return key.key == VK_RETURN; |
374 } | 374 } |
375 | 375 |
376 // static | 376 // static |
377 bool TextField::IsKeystrokeEscape(const Keystroke& key) { | 377 bool Textfield::IsKeystrokeEscape(const Keystroke& key) { |
378 return key.key == VK_ESCAPE; | 378 return key.key == VK_ESCAPE; |
379 } | 379 } |
380 | 380 |
381 void TextField::Edit::SetBackgroundColor(COLORREF bg_color) { | 381 void Textfield::Edit::SetBackgroundColor(COLORREF bg_color) { |
382 CRichEditCtrl::SetBackgroundColor(bg_color); | 382 CRichEditCtrl::SetBackgroundColor(bg_color); |
383 bg_color_ = bg_color; | 383 bg_color_ = bg_color; |
384 } | 384 } |
385 | 385 |
386 bool TextField::Edit::IsCommandEnabled(int id) const { | 386 bool Textfield::Edit::IsCommandEnabled(int id) const { |
387 switch (id) { | 387 switch (id) { |
388 case IDS_APP_UNDO: return !parent_->IsReadOnly() && !!CanUndo(); | 388 case IDS_APP_UNDO: return !parent_->IsReadOnly() && !!CanUndo(); |
389 case IDS_APP_CUT: return !parent_->IsReadOnly() && | 389 case IDS_APP_CUT: return !parent_->IsReadOnly() && |
390 !parent_->IsPassword() && !!CanCut(); | 390 !parent_->IsPassword() && !!CanCut(); |
391 case IDS_APP_COPY: return !!CanCopy() && !parent_->IsPassword(); | 391 case IDS_APP_COPY: return !!CanCopy() && !parent_->IsPassword(); |
392 case IDS_APP_PASTE: return !parent_->IsReadOnly() && !!CanPaste(); | 392 case IDS_APP_PASTE: return !parent_->IsReadOnly() && !!CanPaste(); |
393 case IDS_APP_SELECT_ALL: return !!CanSelectAll(); | 393 case IDS_APP_SELECT_ALL: return !!CanSelectAll(); |
394 default: NOTREACHED(); | 394 default: NOTREACHED(); |
395 return false; | 395 return false; |
396 } | 396 } |
397 } | 397 } |
398 | 398 |
399 void TextField::Edit::ExecuteCommand(int id) { | 399 void Textfield::Edit::ExecuteCommand(int id) { |
400 ScopedFreeze freeze(this, GetTextObjectModel()); | 400 ScopedFreeze freeze(this, GetTextObjectModel()); |
401 OnBeforePossibleChange(); | 401 OnBeforePossibleChange(); |
402 switch (id) { | 402 switch (id) { |
403 case IDS_APP_UNDO: Undo(); break; | 403 case IDS_APP_UNDO: Undo(); break; |
404 case IDS_APP_CUT: Cut(); break; | 404 case IDS_APP_CUT: Cut(); break; |
405 case IDS_APP_COPY: Copy(); break; | 405 case IDS_APP_COPY: Copy(); break; |
406 case IDS_APP_PASTE: Paste(); break; | 406 case IDS_APP_PASTE: Paste(); break; |
407 case IDS_APP_SELECT_ALL: SelectAll(); break; | 407 case IDS_APP_SELECT_ALL: SelectAll(); break; |
408 default: NOTREACHED(); break; | 408 default: NOTREACHED(); break; |
409 } | 409 } |
410 OnAfterPossibleChange(); | 410 OnAfterPossibleChange(); |
411 } | 411 } |
412 | 412 |
413 void TextField::Edit::OnChar(TCHAR ch, UINT repeat_count, UINT flags) { | 413 void Textfield::Edit::OnChar(TCHAR ch, UINT repeat_count, UINT flags) { |
414 HandleKeystroke(GetCurrentMessage()->message, ch, repeat_count, flags); | 414 HandleKeystroke(GetCurrentMessage()->message, ch, repeat_count, flags); |
415 } | 415 } |
416 | 416 |
417 void TextField::Edit::OnContextMenu(HWND window, const CPoint& point) { | 417 void Textfield::Edit::OnContextMenu(HWND window, const CPoint& point) { |
418 CPoint p(point); | 418 CPoint p(point); |
419 if (point.x == -1 || point.y == -1) { | 419 if (point.x == -1 || point.y == -1) { |
420 GetCaretPos(&p); | 420 GetCaretPos(&p); |
421 MapWindowPoints(HWND_DESKTOP, &p, 1); | 421 MapWindowPoints(HWND_DESKTOP, &p, 1); |
422 } | 422 } |
423 context_menu_->RunMenuAt(p.x, p.y); | 423 context_menu_->RunMenuAt(p.x, p.y); |
424 } | 424 } |
425 | 425 |
426 void TextField::Edit::OnCopy() { | 426 void Textfield::Edit::OnCopy() { |
427 if (parent_->IsPassword()) | 427 if (parent_->IsPassword()) |
428 return; | 428 return; |
429 | 429 |
430 const std::wstring text(GetSelectedText()); | 430 const std::wstring text(GetSelectedText()); |
431 | 431 |
432 if (!text.empty() && ViewsDelegate::views_delegate) { | 432 if (!text.empty() && ViewsDelegate::views_delegate) { |
433 ScopedClipboardWriter scw(ViewsDelegate::views_delegate->GetClipboard()); | 433 ScopedClipboardWriter scw(ViewsDelegate::views_delegate->GetClipboard()); |
434 scw.WriteText(text); | 434 scw.WriteText(text); |
435 } | 435 } |
436 } | 436 } |
437 | 437 |
438 void TextField::Edit::OnCut() { | 438 void Textfield::Edit::OnCut() { |
439 if (parent_->IsReadOnly() || parent_->IsPassword()) | 439 if (parent_->IsReadOnly() || parent_->IsPassword()) |
440 return; | 440 return; |
441 | 441 |
442 OnCopy(); | 442 OnCopy(); |
443 | 443 |
444 // This replace selection will have no effect (even on the undo stack) if the | 444 // This replace selection will have no effect (even on the undo stack) if the |
445 // current selection is empty. | 445 // current selection is empty. |
446 ReplaceSel(L"", true); | 446 ReplaceSel(L"", true); |
447 } | 447 } |
448 | 448 |
449 LRESULT TextField::Edit::OnImeChar(UINT message, WPARAM wparam, LPARAM lparam) { | 449 LRESULT Textfield::Edit::OnImeChar(UINT message, WPARAM wparam, LPARAM lparam) { |
450 // http://crbug.com/7707: a rich-edit control may crash when it receives a | 450 // http://crbug.com/7707: a rich-edit control may crash when it receives a |
451 // WM_IME_CHAR message while it is processing a WM_IME_COMPOSITION message. | 451 // WM_IME_CHAR message while it is processing a WM_IME_COMPOSITION message. |
452 // Since view controls don't need WM_IME_CHAR messages, we prevent WM_IME_CHAR | 452 // Since view controls don't need WM_IME_CHAR messages, we prevent WM_IME_CHAR |
453 // messages from being dispatched to view controls via the CallWindowProc() | 453 // messages from being dispatched to view controls via the CallWindowProc() |
454 // call. | 454 // call. |
455 return 0; | 455 return 0; |
456 } | 456 } |
457 | 457 |
458 LRESULT TextField::Edit::OnImeStartComposition(UINT message, | 458 LRESULT Textfield::Edit::OnImeStartComposition(UINT message, |
459 WPARAM wparam, | 459 WPARAM wparam, |
460 LPARAM lparam) { | 460 LPARAM lparam) { |
461 // Users may press alt+shift or control+shift keys to change their keyboard | 461 // Users may press alt+shift or control+shift keys to change their keyboard |
462 // layouts. So, we retrieve the input locale identifier everytime we start | 462 // layouts. So, we retrieve the input locale identifier everytime we start |
463 // an IME composition. | 463 // an IME composition. |
464 int language_id = PRIMARYLANGID(GetKeyboardLayout(0)); | 464 int language_id = PRIMARYLANGID(GetKeyboardLayout(0)); |
465 ime_discard_composition_ = | 465 ime_discard_composition_ = |
466 language_id == LANG_JAPANESE || language_id == LANG_CHINESE; | 466 language_id == LANG_JAPANESE || language_id == LANG_CHINESE; |
467 ime_composition_start_ = 0; | 467 ime_composition_start_ = 0; |
468 ime_composition_length_ = 0; | 468 ime_composition_length_ = 0; |
469 | 469 |
470 return DefWindowProc(message, wparam, lparam); | 470 return DefWindowProc(message, wparam, lparam); |
471 } | 471 } |
472 | 472 |
473 LRESULT TextField::Edit::OnImeComposition(UINT message, | 473 LRESULT Textfield::Edit::OnImeComposition(UINT message, |
474 WPARAM wparam, | 474 WPARAM wparam, |
475 LPARAM lparam) { | 475 LPARAM lparam) { |
476 text_before_change_.clear(); | 476 text_before_change_.clear(); |
477 LRESULT result = DefWindowProc(message, wparam, lparam); | 477 LRESULT result = DefWindowProc(message, wparam, lparam); |
478 | 478 |
479 ime_composition_start_ = 0; | 479 ime_composition_start_ = 0; |
480 ime_composition_length_ = 0; | 480 ime_composition_length_ = 0; |
481 if (ime_discard_composition_) { | 481 if (ime_discard_composition_) { |
482 // Call IMM32 functions to retrieve the position and the length of the | 482 // Call IMM32 functions to retrieve the position and the length of the |
483 // ongoing composition string and notify the OnAfterPossibleChange() | 483 // ongoing composition string and notify the OnAfterPossibleChange() |
(...skipping 15 matching lines...) Expand all Loading... |
499 ime_composition_length_ = composition_size / sizeof(wchar_t); | 499 ime_composition_length_ = composition_size / sizeof(wchar_t); |
500 | 500 |
501 ImmReleaseContext(m_hWnd, imm_context); | 501 ImmReleaseContext(m_hWnd, imm_context); |
502 } | 502 } |
503 } | 503 } |
504 | 504 |
505 OnAfterPossibleChange(); | 505 OnAfterPossibleChange(); |
506 return result; | 506 return result; |
507 } | 507 } |
508 | 508 |
509 LRESULT TextField::Edit::OnImeEndComposition(UINT message, | 509 LRESULT Textfield::Edit::OnImeEndComposition(UINT message, |
510 WPARAM wparam, | 510 WPARAM wparam, |
511 LPARAM lparam) { | 511 LPARAM lparam) { |
512 // Bug 11863: Korean IMEs send a WM_IME_ENDCOMPOSITION message without | 512 // Bug 11863: Korean IMEs send a WM_IME_ENDCOMPOSITION message without |
513 // sending any WM_IME_COMPOSITION messages when a user deletes all | 513 // sending any WM_IME_COMPOSITION messages when a user deletes all |
514 // composition characters, i.e. a composition string becomes empty. To handle | 514 // composition characters, i.e. a composition string becomes empty. To handle |
515 // this case, we need to update the find results when a composition is | 515 // this case, we need to update the find results when a composition is |
516 // finished or canceled. | 516 // finished or canceled. |
517 parent_->SyncText(); | 517 parent_->SyncText(); |
518 if (parent_->GetController()) | 518 if (parent_->GetController()) |
519 parent_->GetController()->ContentsChanged(parent_, GetText()); | 519 parent_->GetController()->ContentsChanged(parent_, GetText()); |
520 return DefWindowProc(message, wparam, lparam); | 520 return DefWindowProc(message, wparam, lparam); |
521 } | 521 } |
522 | 522 |
523 void TextField::Edit::OnKeyDown(TCHAR key, UINT repeat_count, UINT flags) { | 523 void Textfield::Edit::OnKeyDown(TCHAR key, UINT repeat_count, UINT flags) { |
524 // NOTE: Annoyingly, ctrl-alt-<key> generates WM_KEYDOWN rather than | 524 // NOTE: Annoyingly, ctrl-alt-<key> generates WM_KEYDOWN rather than |
525 // WM_SYSKEYDOWN, so we need to check (flags & KF_ALTDOWN) in various places | 525 // WM_SYSKEYDOWN, so we need to check (flags & KF_ALTDOWN) in various places |
526 // in this function even with a WM_SYSKEYDOWN handler. | 526 // in this function even with a WM_SYSKEYDOWN handler. |
527 | 527 |
528 switch (key) { | 528 switch (key) { |
529 case VK_RETURN: | 529 case VK_RETURN: |
530 // If we are multi-line, we want to let returns through so they start a | 530 // If we are multi-line, we want to let returns through so they start a |
531 // new line. | 531 // new line. |
532 if (parent_->IsMultiLine()) | 532 if (parent_->IsMultiLine()) |
533 break; | 533 break; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 // We ignore this event because an IME sends WM_IME_COMPOSITION messages | 592 // We ignore this event because an IME sends WM_IME_COMPOSITION messages |
593 // when it updates the CRichEditCtrl text. | 593 // when it updates the CRichEditCtrl text. |
594 return; | 594 return; |
595 } | 595 } |
596 | 596 |
597 // CRichEditCtrl changes its text on WM_KEYDOWN instead of WM_CHAR for many | 597 // CRichEditCtrl changes its text on WM_KEYDOWN instead of WM_CHAR for many |
598 // different keys (backspace, ctrl-v, ...), so we call this in both cases. | 598 // different keys (backspace, ctrl-v, ...), so we call this in both cases. |
599 HandleKeystroke(GetCurrentMessage()->message, key, repeat_count, flags); | 599 HandleKeystroke(GetCurrentMessage()->message, key, repeat_count, flags); |
600 } | 600 } |
601 | 601 |
602 void TextField::Edit::OnLButtonDblClk(UINT keys, const CPoint& point) { | 602 void Textfield::Edit::OnLButtonDblClk(UINT keys, const CPoint& point) { |
603 // Save the double click info for later triple-click detection. | 603 // Save the double click info for later triple-click detection. |
604 tracking_double_click_ = true; | 604 tracking_double_click_ = true; |
605 double_click_point_ = point; | 605 double_click_point_ = point; |
606 double_click_time_ = GetCurrentMessage()->time; | 606 double_click_time_ = GetCurrentMessage()->time; |
607 | 607 |
608 ScopedFreeze freeze(this, GetTextObjectModel()); | 608 ScopedFreeze freeze(this, GetTextObjectModel()); |
609 OnBeforePossibleChange(); | 609 OnBeforePossibleChange(); |
610 DefWindowProc(WM_LBUTTONDBLCLK, keys, | 610 DefWindowProc(WM_LBUTTONDBLCLK, keys, |
611 MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y)); | 611 MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y)); |
612 OnAfterPossibleChange(); | 612 OnAfterPossibleChange(); |
613 } | 613 } |
614 | 614 |
615 void TextField::Edit::OnLButtonDown(UINT keys, const CPoint& point) { | 615 void Textfield::Edit::OnLButtonDown(UINT keys, const CPoint& point) { |
616 // Check for triple click, then reset tracker. Should be safe to subtract | 616 // Check for triple click, then reset tracker. Should be safe to subtract |
617 // double_click_time_ from the current message's time even if the timer has | 617 // double_click_time_ from the current message's time even if the timer has |
618 // wrapped in between. | 618 // wrapped in between. |
619 const bool is_triple_click = tracking_double_click_ && | 619 const bool is_triple_click = tracking_double_click_ && |
620 win_util::IsDoubleClick(double_click_point_, point, | 620 win_util::IsDoubleClick(double_click_point_, point, |
621 GetCurrentMessage()->time - double_click_time_); | 621 GetCurrentMessage()->time - double_click_time_); |
622 tracking_double_click_ = false; | 622 tracking_double_click_ = false; |
623 | 623 |
624 ScopedFreeze freeze(this, GetTextObjectModel()); | 624 ScopedFreeze freeze(this, GetTextObjectModel()); |
625 OnBeforePossibleChange(); | 625 OnBeforePossibleChange(); |
626 DefWindowProc(WM_LBUTTONDOWN, keys, | 626 DefWindowProc(WM_LBUTTONDOWN, keys, |
627 MAKELPARAM(ClipXCoordToVisibleText(point.x, is_triple_click), | 627 MAKELPARAM(ClipXCoordToVisibleText(point.x, is_triple_click), |
628 point.y)); | 628 point.y)); |
629 OnAfterPossibleChange(); | 629 OnAfterPossibleChange(); |
630 } | 630 } |
631 | 631 |
632 void TextField::Edit::OnLButtonUp(UINT keys, const CPoint& point) { | 632 void Textfield::Edit::OnLButtonUp(UINT keys, const CPoint& point) { |
633 ScopedFreeze freeze(this, GetTextObjectModel()); | 633 ScopedFreeze freeze(this, GetTextObjectModel()); |
634 OnBeforePossibleChange(); | 634 OnBeforePossibleChange(); |
635 DefWindowProc(WM_LBUTTONUP, keys, | 635 DefWindowProc(WM_LBUTTONUP, keys, |
636 MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y)); | 636 MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y)); |
637 OnAfterPossibleChange(); | 637 OnAfterPossibleChange(); |
638 } | 638 } |
639 | 639 |
640 void TextField::Edit::OnMouseLeave() { | 640 void Textfield::Edit::OnMouseLeave() { |
641 SetContainsMouse(false); | 641 SetContainsMouse(false); |
642 } | 642 } |
643 | 643 |
644 LRESULT TextField::Edit::OnMouseWheel(UINT message, | 644 LRESULT Textfield::Edit::OnMouseWheel(UINT message, |
645 WPARAM w_param, LPARAM l_param) { | 645 WPARAM w_param, LPARAM l_param) { |
646 // Reroute the mouse-wheel to the window under the mouse pointer if | 646 // Reroute the mouse-wheel to the window under the mouse pointer if |
647 // applicable. | 647 // applicable. |
648 if (views::RerouteMouseWheel(m_hWnd, w_param, l_param)) | 648 if (views::RerouteMouseWheel(m_hWnd, w_param, l_param)) |
649 return 0; | 649 return 0; |
650 return DefWindowProc(message, w_param, l_param);; | 650 return DefWindowProc(message, w_param, l_param);; |
651 } | 651 } |
652 | 652 |
653 void TextField::Edit::OnMouseMove(UINT keys, const CPoint& point) { | 653 void Textfield::Edit::OnMouseMove(UINT keys, const CPoint& point) { |
654 SetContainsMouse(true); | 654 SetContainsMouse(true); |
655 // Clamp the selection to the visible text so the user can't drag to select | 655 // Clamp the selection to the visible text so the user can't drag to select |
656 // the "phantom newline". In theory we could achieve this by clipping the X | 656 // the "phantom newline". In theory we could achieve this by clipping the X |
657 // coordinate, but in practice the edit seems to behave nondeterministically | 657 // coordinate, but in practice the edit seems to behave nondeterministically |
658 // with similar sequences of clipped input coordinates fed to it. Maybe it's | 658 // with similar sequences of clipped input coordinates fed to it. Maybe it's |
659 // reading the mouse cursor position directly? | 659 // reading the mouse cursor position directly? |
660 // | 660 // |
661 // This solution has a minor visual flaw, however: if there's a visible | 661 // This solution has a minor visual flaw, however: if there's a visible |
662 // cursor at the edge of the text (only true when there's no selection), | 662 // cursor at the edge of the text (only true when there's no selection), |
663 // dragging the mouse around outside that edge repaints the cursor on every | 663 // dragging the mouse around outside that edge repaints the cursor on every |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
697 // just a few pixels vertically end up selecting the "phantom newline"... | 697 // just a few pixels vertically end up selecting the "phantom newline"... |
698 // sometimes. | 698 // sometimes. |
699 RECT r; | 699 RECT r; |
700 GetRect(&r); | 700 GetRect(&r); |
701 DefWindowProc(WM_MOUSEMOVE, keys, | 701 DefWindowProc(WM_MOUSEMOVE, keys, |
702 MAKELPARAM(point.x, (r.bottom - r.top) / 2)); | 702 MAKELPARAM(point.x, (r.bottom - r.top) / 2)); |
703 OnAfterPossibleChange(); | 703 OnAfterPossibleChange(); |
704 } | 704 } |
705 } | 705 } |
706 | 706 |
707 int TextField::Edit::OnNCCalcSize(BOOL w_param, LPARAM l_param) { | 707 int Textfield::Edit::OnNCCalcSize(BOOL w_param, LPARAM l_param) { |
708 content_insets_.Set(0, 0, 0, 0); | 708 content_insets_.Set(0, 0, 0, 0); |
709 parent_->CalculateInsets(&content_insets_); | 709 parent_->CalculateInsets(&content_insets_); |
710 if (w_param) { | 710 if (w_param) { |
711 NCCALCSIZE_PARAMS* nc_params = | 711 NCCALCSIZE_PARAMS* nc_params = |
712 reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param); | 712 reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param); |
713 nc_params->rgrc[0].left += content_insets_.left(); | 713 nc_params->rgrc[0].left += content_insets_.left(); |
714 nc_params->rgrc[0].right -= content_insets_.right(); | 714 nc_params->rgrc[0].right -= content_insets_.right(); |
715 nc_params->rgrc[0].top += content_insets_.top(); | 715 nc_params->rgrc[0].top += content_insets_.top(); |
716 nc_params->rgrc[0].bottom -= content_insets_.bottom(); | 716 nc_params->rgrc[0].bottom -= content_insets_.bottom(); |
717 } else { | 717 } else { |
718 RECT* rect = reinterpret_cast<RECT*>(l_param); | 718 RECT* rect = reinterpret_cast<RECT*>(l_param); |
719 rect->left += content_insets_.left(); | 719 rect->left += content_insets_.left(); |
720 rect->right -= content_insets_.right(); | 720 rect->right -= content_insets_.right(); |
721 rect->top += content_insets_.top(); | 721 rect->top += content_insets_.top(); |
722 rect->bottom -= content_insets_.bottom(); | 722 rect->bottom -= content_insets_.bottom(); |
723 } | 723 } |
724 return 0; | 724 return 0; |
725 } | 725 } |
726 | 726 |
727 void TextField::Edit::OnNCPaint(HRGN region) { | 727 void Textfield::Edit::OnNCPaint(HRGN region) { |
728 if (!draw_border_) | 728 if (!draw_border_) |
729 return; | 729 return; |
730 | 730 |
731 HDC hdc = GetWindowDC(); | 731 HDC hdc = GetWindowDC(); |
732 | 732 |
733 CRect window_rect; | 733 CRect window_rect; |
734 GetWindowRect(&window_rect); | 734 GetWindowRect(&window_rect); |
735 // Convert to be relative to 0x0. | 735 // Convert to be relative to 0x0. |
736 window_rect.MoveToXY(0, 0); | 736 window_rect.MoveToXY(0, 0); |
737 | 737 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
779 NativeTheme::instance()->PaintTextField(hdc, part, state, classic_state, | 779 NativeTheme::instance()->PaintTextField(hdc, part, state, classic_state, |
780 &window_rect, bg_color_, false, | 780 &window_rect, bg_color_, false, |
781 true); | 781 true); |
782 | 782 |
783 // NOTE: I tried checking the transparent property of the theme and invoking | 783 // NOTE: I tried checking the transparent property of the theme and invoking |
784 // drawParentBackground, but it didn't seem to make a difference. | 784 // drawParentBackground, but it didn't seem to make a difference. |
785 | 785 |
786 ReleaseDC(hdc); | 786 ReleaseDC(hdc); |
787 } | 787 } |
788 | 788 |
789 void TextField::Edit::OnNonLButtonDown(UINT keys, const CPoint& point) { | 789 void Textfield::Edit::OnNonLButtonDown(UINT keys, const CPoint& point) { |
790 // Interestingly, the edit doesn't seem to cancel triple clicking when the | 790 // Interestingly, the edit doesn't seem to cancel triple clicking when the |
791 // x-buttons (which usually means "thumb buttons") are pressed, so we only | 791 // x-buttons (which usually means "thumb buttons") are pressed, so we only |
792 // call this for M and R down. | 792 // call this for M and R down. |
793 tracking_double_click_ = false; | 793 tracking_double_click_ = false; |
794 SetMsgHandled(false); | 794 SetMsgHandled(false); |
795 } | 795 } |
796 | 796 |
797 void TextField::Edit::OnPaste() { | 797 void Textfield::Edit::OnPaste() { |
798 if (parent_->IsReadOnly() || !ViewsDelegate::views_delegate) | 798 if (parent_->IsReadOnly() || !ViewsDelegate::views_delegate) |
799 return; | 799 return; |
800 | 800 |
801 Clipboard* clipboard = ViewsDelegate::views_delegate->GetClipboard(); | 801 Clipboard* clipboard = ViewsDelegate::views_delegate->GetClipboard(); |
802 | 802 |
803 if (!clipboard->IsFormatAvailable(Clipboard::GetPlainTextWFormatType())) | 803 if (!clipboard->IsFormatAvailable(Clipboard::GetPlainTextWFormatType())) |
804 return; | 804 return; |
805 | 805 |
806 std::wstring clipboard_str; | 806 std::wstring clipboard_str; |
807 clipboard->ReadText(&clipboard_str); | 807 clipboard->ReadText(&clipboard_str); |
808 if (!clipboard_str.empty()) { | 808 if (!clipboard_str.empty()) { |
809 std::wstring collapsed(CollapseWhitespace(clipboard_str, false)); | 809 std::wstring collapsed(CollapseWhitespace(clipboard_str, false)); |
810 if (parent_->GetStyle() & STYLE_LOWERCASE) | 810 if (parent_->GetStyle() & STYLE_LOWERCASE) |
811 collapsed = l10n_util::ToLower(collapsed); | 811 collapsed = l10n_util::ToLower(collapsed); |
812 // Force a Paste operation to trigger OnContentsChanged, even if identical | 812 // Force a Paste operation to trigger OnContentsChanged, even if identical |
813 // contents are pasted into the text box. | 813 // contents are pasted into the text box. |
814 text_before_change_.clear(); | 814 text_before_change_.clear(); |
815 ReplaceSel(collapsed.c_str(), true); | 815 ReplaceSel(collapsed.c_str(), true); |
816 } | 816 } |
817 } | 817 } |
818 | 818 |
819 void TextField::Edit::OnSysChar(TCHAR ch, UINT repeat_count, UINT flags) { | 819 void Textfield::Edit::OnSysChar(TCHAR ch, UINT repeat_count, UINT flags) { |
820 // Nearly all alt-<xxx> combos result in beeping rather than doing something | 820 // Nearly all alt-<xxx> combos result in beeping rather than doing something |
821 // useful, so we discard most. Exceptions: | 821 // useful, so we discard most. Exceptions: |
822 // * ctrl-alt-<xxx>, which is sometimes important, generates WM_CHAR instead | 822 // * ctrl-alt-<xxx>, which is sometimes important, generates WM_CHAR instead |
823 // of WM_SYSCHAR, so it doesn't need to be handled here. | 823 // of WM_SYSCHAR, so it doesn't need to be handled here. |
824 // * alt-space gets translated by the default WM_SYSCHAR handler to a | 824 // * alt-space gets translated by the default WM_SYSCHAR handler to a |
825 // WM_SYSCOMMAND to open the application context menu, so we need to allow | 825 // WM_SYSCOMMAND to open the application context menu, so we need to allow |
826 // it through. | 826 // it through. |
827 if (ch == VK_SPACE) | 827 if (ch == VK_SPACE) |
828 SetMsgHandled(false); | 828 SetMsgHandled(false); |
829 } | 829 } |
830 | 830 |
831 void TextField::Edit::HandleKeystroke(UINT message, | 831 void Textfield::Edit::HandleKeystroke(UINT message, |
832 TCHAR key, | 832 TCHAR key, |
833 UINT repeat_count, | 833 UINT repeat_count, |
834 UINT flags) { | 834 UINT flags) { |
835 ScopedFreeze freeze(this, GetTextObjectModel()); | 835 ScopedFreeze freeze(this, GetTextObjectModel()); |
836 | 836 |
837 TextField::Controller* controller = parent_->GetController(); | 837 Textfield::Controller* controller = parent_->GetController(); |
838 bool handled = false; | 838 bool handled = false; |
839 if (controller) { | 839 if (controller) { |
840 handled = controller->HandleKeystroke(parent_, | 840 handled = controller->HandleKeystroke(parent_, |
841 TextField::Keystroke(message, key, repeat_count, flags)); | 841 Textfield::Keystroke(message, key, repeat_count, flags)); |
842 } | 842 } |
843 | 843 |
844 if (!handled) { | 844 if (!handled) { |
845 OnBeforePossibleChange(); | 845 OnBeforePossibleChange(); |
846 DefWindowProc(message, key, MAKELPARAM(repeat_count, flags)); | 846 DefWindowProc(message, key, MAKELPARAM(repeat_count, flags)); |
847 OnAfterPossibleChange(); | 847 OnAfterPossibleChange(); |
848 } | 848 } |
849 } | 849 } |
850 | 850 |
851 void TextField::Edit::OnBeforePossibleChange() { | 851 void Textfield::Edit::OnBeforePossibleChange() { |
852 // Record our state. | 852 // Record our state. |
853 text_before_change_ = GetText(); | 853 text_before_change_ = GetText(); |
854 } | 854 } |
855 | 855 |
856 void TextField::Edit::OnAfterPossibleChange() { | 856 void Textfield::Edit::OnAfterPossibleChange() { |
857 // Prevent the user from selecting the "phantom newline" at the end of the | 857 // Prevent the user from selecting the "phantom newline" at the end of the |
858 // edit. If they try, we just silently move the end of the selection back to | 858 // edit. If they try, we just silently move the end of the selection back to |
859 // the end of the real text. | 859 // the end of the real text. |
860 CHARRANGE new_sel; | 860 CHARRANGE new_sel; |
861 GetSel(new_sel); | 861 GetSel(new_sel); |
862 const int length = GetTextLength(); | 862 const int length = GetTextLength(); |
863 if (new_sel.cpMax > length) { | 863 if (new_sel.cpMax > length) { |
864 new_sel.cpMax = length; | 864 new_sel.cpMax = length; |
865 if (new_sel.cpMin > length) | 865 if (new_sel.cpMin > length) |
866 new_sel.cpMin = length; | 866 new_sel.cpMin = length; |
(...skipping 12 matching lines...) Expand all Loading... |
879 ime_composition_length_ = 0; | 879 ime_composition_length_ = 0; |
880 if (new_text.empty()) | 880 if (new_text.empty()) |
881 return; | 881 return; |
882 } | 882 } |
883 parent_->SyncText(); | 883 parent_->SyncText(); |
884 if (parent_->GetController()) | 884 if (parent_->GetController()) |
885 parent_->GetController()->ContentsChanged(parent_, new_text); | 885 parent_->GetController()->ContentsChanged(parent_, new_text); |
886 } | 886 } |
887 } | 887 } |
888 | 888 |
889 LONG TextField::Edit::ClipXCoordToVisibleText(LONG x, | 889 LONG Textfield::Edit::ClipXCoordToVisibleText(LONG x, |
890 bool is_triple_click) const { | 890 bool is_triple_click) const { |
891 // Clip the X coordinate to the left edge of the text. Careful: | 891 // Clip the X coordinate to the left edge of the text. Careful: |
892 // PosFromChar(0) may return a negative X coordinate if the beginning of the | 892 // PosFromChar(0) may return a negative X coordinate if the beginning of the |
893 // text has scrolled off the edit, so don't go past the clip rect's edge. | 893 // text has scrolled off the edit, so don't go past the clip rect's edge. |
894 PARAFORMAT2 pf2; | 894 PARAFORMAT2 pf2; |
895 GetParaFormat(pf2); | 895 GetParaFormat(pf2); |
896 // Calculation of the clipped coordinate is more complicated if the paragraph | 896 // Calculation of the clipped coordinate is more complicated if the paragraph |
897 // layout is RTL layout, or if there is RTL characters inside the LTR layout | 897 // layout is RTL layout, or if there is RTL characters inside the LTR layout |
898 // paragraph. | 898 // paragraph. |
899 bool ltr_text_in_ltr_layout = true; | 899 bool ltr_text_in_ltr_layout = true; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
935 // the end of the text, but triple-click will still work. | 935 // the end of the text, but triple-click will still work. |
936 if (x < left_bound) { | 936 if (x < left_bound) { |
937 return (is_triple_click && ltr_text_in_ltr_layout) ? left_bound - 1 : | 937 return (is_triple_click && ltr_text_in_ltr_layout) ? left_bound - 1 : |
938 left_bound; | 938 left_bound; |
939 } | 939 } |
940 if ((length == 0) || (x < right_bound)) | 940 if ((length == 0) || (x < right_bound)) |
941 return x; | 941 return x; |
942 return is_triple_click ? (right_bound - 1) : right_bound; | 942 return is_triple_click ? (right_bound - 1) : right_bound; |
943 } | 943 } |
944 | 944 |
945 void TextField::Edit::SetContainsMouse(bool contains_mouse) { | 945 void Textfield::Edit::SetContainsMouse(bool contains_mouse) { |
946 if (contains_mouse == contains_mouse_) | 946 if (contains_mouse == contains_mouse_) |
947 return; | 947 return; |
948 | 948 |
949 contains_mouse_ = contains_mouse; | 949 contains_mouse_ = contains_mouse; |
950 | 950 |
951 if (!draw_border_) | 951 if (!draw_border_) |
952 return; | 952 return; |
953 | 953 |
954 if (contains_mouse_) { | 954 if (contains_mouse_) { |
955 // Register for notification when the mouse leaves. Need to do this so | 955 // Register for notification when the mouse leaves. Need to do this so |
956 // that we can reset contains mouse properly. | 956 // that we can reset contains mouse properly. |
957 TRACKMOUSEEVENT tme; | 957 TRACKMOUSEEVENT tme; |
958 tme.cbSize = sizeof(tme); | 958 tme.cbSize = sizeof(tme); |
959 tme.dwFlags = TME_LEAVE; | 959 tme.dwFlags = TME_LEAVE; |
960 tme.hwndTrack = m_hWnd; | 960 tme.hwndTrack = m_hWnd; |
961 tme.dwHoverTime = 0; | 961 tme.dwHoverTime = 0; |
962 TrackMouseEvent(&tme); | 962 TrackMouseEvent(&tme); |
963 } | 963 } |
964 RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME); | 964 RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME); |
965 } | 965 } |
966 | 966 |
967 ITextDocument* TextField::Edit::GetTextObjectModel() const { | 967 ITextDocument* Textfield::Edit::GetTextObjectModel() const { |
968 if (!text_object_model_) { | 968 if (!text_object_model_) { |
969 CComPtr<IRichEditOle> ole_interface; | 969 CComPtr<IRichEditOle> ole_interface; |
970 ole_interface.Attach(GetOleInterface()); | 970 ole_interface.Attach(GetOleInterface()); |
971 text_object_model_ = ole_interface; | 971 text_object_model_ = ole_interface; |
972 } | 972 } |
973 return text_object_model_; | 973 return text_object_model_; |
974 } | 974 } |
975 | 975 |
976 ///////////////////////////////////////////////////////////////////////////// | 976 ///////////////////////////////////////////////////////////////////////////// |
977 // TextField | 977 // Textfield |
978 | 978 |
979 TextField::~TextField() { | 979 Textfield::~Textfield() { |
980 if (edit_) { | 980 if (edit_) { |
981 // If the edit hwnd still exists, we need to destroy it explicitly. | 981 // If the edit hwnd still exists, we need to destroy it explicitly. |
982 if (*edit_) | 982 if (*edit_) |
983 edit_->DestroyWindow(); | 983 edit_->DestroyWindow(); |
984 delete edit_; | 984 delete edit_; |
985 } | 985 } |
986 } | 986 } |
987 | 987 |
988 void TextField::ViewHierarchyChanged(bool is_add, View* parent, View* child) { | 988 void Textfield::ViewHierarchyChanged(bool is_add, View* parent, View* child) { |
989 Widget* widget; | 989 Widget* widget; |
990 | 990 |
991 if (is_add && (widget = GetWidget())) { | 991 if (is_add && (widget = GetWidget())) { |
992 // This notification is called from the AddChildView call below. Ignore it. | 992 // This notification is called from the AddChildView call below. Ignore it. |
993 if (native_view_ && !edit_) | 993 if (native_view_ && !edit_) |
994 return; | 994 return; |
995 | 995 |
996 if (!native_view_) { | 996 if (!native_view_) { |
997 native_view_ = new HWNDView(); // Deleted from our superclass destructor | 997 native_view_ = new HWNDView(); // Deleted from our superclass destructor |
998 AddChildView(native_view_); | 998 AddChildView(native_view_); |
(...skipping 16 matching lines...) Expand all Loading... |
1015 if (!text_.empty()) | 1015 if (!text_.empty()) |
1016 edit_->SetText(text_); | 1016 edit_->SetText(text_); |
1017 UpdateEditBackgroundColor(); | 1017 UpdateEditBackgroundColor(); |
1018 Layout(); | 1018 Layout(); |
1019 } | 1019 } |
1020 } else if (!is_add && edit_ && IsWindow(edit_->m_hWnd)) { | 1020 } else if (!is_add && edit_ && IsWindow(edit_->m_hWnd)) { |
1021 edit_->SetParent(NULL); | 1021 edit_->SetParent(NULL); |
1022 } | 1022 } |
1023 } | 1023 } |
1024 | 1024 |
1025 void TextField::Layout() { | 1025 void Textfield::Layout() { |
1026 if (native_view_) { | 1026 if (native_view_) { |
1027 native_view_->SetBounds(GetLocalBounds(true)); | 1027 native_view_->SetBounds(GetLocalBounds(true)); |
1028 native_view_->Layout(); | 1028 native_view_->Layout(); |
1029 } | 1029 } |
1030 } | 1030 } |
1031 | 1031 |
1032 gfx::Size TextField::GetPreferredSize() { | 1032 gfx::Size Textfield::GetPreferredSize() { |
1033 gfx::Insets insets; | 1033 gfx::Insets insets; |
1034 CalculateInsets(&insets); | 1034 CalculateInsets(&insets); |
1035 return gfx::Size(font_.GetExpectedTextWidth(default_width_in_chars_) + | 1035 return gfx::Size(font_.GetExpectedTextWidth(default_width_in_chars_) + |
1036 insets.width(), | 1036 insets.width(), |
1037 num_lines_ * font_.height() + insets.height()); | 1037 num_lines_ * font_.height() + insets.height()); |
1038 } | 1038 } |
1039 | 1039 |
1040 std::wstring TextField::GetText() const { | 1040 std::wstring Textfield::GetText() const { |
1041 return text_; | 1041 return text_; |
1042 } | 1042 } |
1043 | 1043 |
1044 void TextField::SetText(const std::wstring& text) { | 1044 void Textfield::SetText(const std::wstring& text) { |
1045 text_ = text; | 1045 text_ = text; |
1046 if (edit_) | 1046 if (edit_) |
1047 edit_->SetText(text); | 1047 edit_->SetText(text); |
1048 } | 1048 } |
1049 | 1049 |
1050 void TextField::AppendText(const std::wstring& text) { | 1050 void Textfield::AppendText(const std::wstring& text) { |
1051 text_ += text; | 1051 text_ += text; |
1052 if (edit_) | 1052 if (edit_) |
1053 edit_->AppendText(text); | 1053 edit_->AppendText(text); |
1054 } | 1054 } |
1055 | 1055 |
1056 void TextField::CalculateInsets(gfx::Insets* insets) { | 1056 void Textfield::CalculateInsets(gfx::Insets* insets) { |
1057 DCHECK(insets); | 1057 DCHECK(insets); |
1058 | 1058 |
1059 if (!draw_border_) | 1059 if (!draw_border_) |
1060 return; | 1060 return; |
1061 | 1061 |
1062 // NOTE: One would think GetThemeMargins would return the insets we should | 1062 // NOTE: One would think GetThemeMargins would return the insets we should |
1063 // use, but it doesn't. The margins returned by GetThemeMargins are always | 1063 // use, but it doesn't. The margins returned by GetThemeMargins are always |
1064 // 0. | 1064 // 0. |
1065 | 1065 |
1066 // This appears to be the insets used by Windows. | 1066 // This appears to be the insets used by Windows. |
1067 insets->Set(3, 3, 3, 3); | 1067 insets->Set(3, 3, 3, 3); |
1068 } | 1068 } |
1069 | 1069 |
1070 void TextField::SyncText() { | 1070 void Textfield::SyncText() { |
1071 if (edit_) | 1071 if (edit_) |
1072 text_ = edit_->GetText(); | 1072 text_ = edit_->GetText(); |
1073 } | 1073 } |
1074 | 1074 |
1075 void TextField::SetController(Controller* controller) { | 1075 void Textfield::SetController(Controller* controller) { |
1076 controller_ = controller; | 1076 controller_ = controller; |
1077 } | 1077 } |
1078 | 1078 |
1079 TextField::Controller* TextField::GetController() const { | 1079 Textfield::Controller* Textfield::GetController() const { |
1080 return controller_; | 1080 return controller_; |
1081 } | 1081 } |
1082 | 1082 |
1083 bool TextField::IsReadOnly() const { | 1083 bool Textfield::IsReadOnly() const { |
1084 return edit_ ? ((edit_->GetStyle() & ES_READONLY) != 0) : read_only_; | 1084 return edit_ ? ((edit_->GetStyle() & ES_READONLY) != 0) : read_only_; |
1085 } | 1085 } |
1086 | 1086 |
1087 bool TextField::IsPassword() const { | 1087 bool Textfield::IsPassword() const { |
1088 return GetStyle() & TextField::STYLE_PASSWORD; | 1088 return GetStyle() & Textfield::STYLE_PASSWORD; |
1089 } | 1089 } |
1090 | 1090 |
1091 bool TextField::IsMultiLine() const { | 1091 bool Textfield::IsMultiLine() const { |
1092 return (style_ & STYLE_MULTILINE) != 0; | 1092 return (style_ & STYLE_MULTILINE) != 0; |
1093 } | 1093 } |
1094 | 1094 |
1095 void TextField::SetReadOnly(bool read_only) { | 1095 void Textfield::SetReadOnly(bool read_only) { |
1096 read_only_ = read_only; | 1096 read_only_ = read_only; |
1097 if (edit_) { | 1097 if (edit_) { |
1098 edit_->SetReadOnly(read_only); | 1098 edit_->SetReadOnly(read_only); |
1099 UpdateEditBackgroundColor(); | 1099 UpdateEditBackgroundColor(); |
1100 } | 1100 } |
1101 } | 1101 } |
1102 | 1102 |
1103 void TextField::Focus() { | 1103 void Textfield::Focus() { |
1104 ::SetFocus(native_view_->GetHWND()); | 1104 ::SetFocus(native_view_->GetHWND()); |
1105 } | 1105 } |
1106 | 1106 |
1107 void TextField::SelectAll() { | 1107 void Textfield::SelectAll() { |
1108 if (edit_) | 1108 if (edit_) |
1109 edit_->SelectAll(); | 1109 edit_->SelectAll(); |
1110 } | 1110 } |
1111 | 1111 |
1112 void TextField::ClearSelection() const { | 1112 void Textfield::ClearSelection() const { |
1113 if (edit_) | 1113 if (edit_) |
1114 edit_->ClearSelection(); | 1114 edit_->ClearSelection(); |
1115 } | 1115 } |
1116 | 1116 |
1117 HWND TextField::GetNativeComponent() { | 1117 HWND Textfield::GetNativeComponent() { |
1118 return native_view_->GetHWND(); | 1118 return native_view_->GetHWND(); |
1119 } | 1119 } |
1120 | 1120 |
1121 void TextField::SetBackgroundColor(SkColor color) { | 1121 void Textfield::SetBackgroundColor(SkColor color) { |
1122 background_color_ = color; | 1122 background_color_ = color; |
1123 use_default_background_color_ = false; | 1123 use_default_background_color_ = false; |
1124 UpdateEditBackgroundColor(); | 1124 UpdateEditBackgroundColor(); |
1125 } | 1125 } |
1126 | 1126 |
1127 void TextField::SetDefaultBackgroundColor() { | 1127 void Textfield::SetDefaultBackgroundColor() { |
1128 use_default_background_color_ = true; | 1128 use_default_background_color_ = true; |
1129 UpdateEditBackgroundColor(); | 1129 UpdateEditBackgroundColor(); |
1130 } | 1130 } |
1131 | 1131 |
1132 void TextField::SetFont(const gfx::Font& font) { | 1132 void Textfield::SetFont(const gfx::Font& font) { |
1133 font_ = font; | 1133 font_ = font; |
1134 if (edit_) | 1134 if (edit_) |
1135 edit_->SetFont(font.hfont()); | 1135 edit_->SetFont(font.hfont()); |
1136 } | 1136 } |
1137 | 1137 |
1138 gfx::Font TextField::GetFont() const { | 1138 gfx::Font Textfield::GetFont() const { |
1139 return font_; | 1139 return font_; |
1140 } | 1140 } |
1141 | 1141 |
1142 bool TextField::SetHorizontalMargins(int left, int right) { | 1142 bool Textfield::SetHorizontalMargins(int left, int right) { |
1143 // SendMessage expects the two values to be packed into one using MAKELONG | 1143 // SendMessage expects the two values to be packed into one using MAKELONG |
1144 // so we truncate to 16 bits if necessary. | 1144 // so we truncate to 16 bits if necessary. |
1145 return ERROR_SUCCESS == SendMessage(GetNativeComponent(), | 1145 return ERROR_SUCCESS == SendMessage(GetNativeComponent(), |
1146 (UINT) EM_SETMARGINS, | 1146 (UINT) EM_SETMARGINS, |
1147 (WPARAM) EC_LEFTMARGIN | EC_RIGHTMARGIN, | 1147 (WPARAM) EC_LEFTMARGIN | EC_RIGHTMARGIN, |
1148 (LPARAM) MAKELONG(left & 0xFFFF, | 1148 (LPARAM) MAKELONG(left & 0xFFFF, |
1149 right & 0xFFFF)); | 1149 right & 0xFFFF)); |
1150 } | 1150 } |
1151 | 1151 |
1152 void TextField::SetHeightInLines(int num_lines) { | 1152 void Textfield::SetHeightInLines(int num_lines) { |
1153 DCHECK(IsMultiLine()); | 1153 DCHECK(IsMultiLine()); |
1154 num_lines_ = num_lines; | 1154 num_lines_ = num_lines; |
1155 } | 1155 } |
1156 | 1156 |
1157 void TextField::RemoveBorder() { | 1157 void Textfield::RemoveBorder() { |
1158 if (!draw_border_) | 1158 if (!draw_border_) |
1159 return; | 1159 return; |
1160 | 1160 |
1161 draw_border_ = false; | 1161 draw_border_ = false; |
1162 if (edit_) | 1162 if (edit_) |
1163 edit_->RemoveBorder(); | 1163 edit_->RemoveBorder(); |
1164 } | 1164 } |
1165 | 1165 |
1166 void TextField::SetEnabled(bool enabled) { | 1166 void Textfield::SetEnabled(bool enabled) { |
1167 View::SetEnabled(enabled); | 1167 View::SetEnabled(enabled); |
1168 edit_->SetEnabled(enabled); | 1168 edit_->SetEnabled(enabled); |
1169 } | 1169 } |
1170 | 1170 |
1171 bool TextField::IsFocusable() const { | 1171 bool Textfield::IsFocusable() const { |
1172 return IsEnabled() && !IsReadOnly(); | 1172 return IsEnabled() && !IsReadOnly(); |
1173 } | 1173 } |
1174 | 1174 |
1175 void TextField::AboutToRequestFocusFromTabTraversal(bool reverse) { | 1175 void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) { |
1176 SelectAll(); | 1176 SelectAll(); |
1177 } | 1177 } |
1178 | 1178 |
1179 bool TextField::SkipDefaultKeyEventProcessing(const KeyEvent& e) { | 1179 bool Textfield::SkipDefaultKeyEventProcessing(const KeyEvent& e) { |
1180 // TODO(hamaji): Figure out which keyboard combinations we need to add here, | 1180 // TODO(hamaji): Figure out which keyboard combinations we need to add here, |
1181 // similar to LocationBarView::SkipDefaultKeyEventProcessing. | 1181 // similar to LocationBarView::SkipDefaultKeyEventProcessing. |
1182 if (e.GetCharacter() == VK_BACK) | 1182 if (e.GetCharacter() == VK_BACK) |
1183 return true; // We'll handle BackSpace ourselves. | 1183 return true; // We'll handle BackSpace ourselves. |
1184 | 1184 |
1185 // We don't translate accelerators for ALT + NumPad digit, they are used for | 1185 // We don't translate accelerators for ALT + NumPad digit, they are used for |
1186 // entering special characters. | 1186 // entering special characters. |
1187 if (e.IsAltDown() && | 1187 if (e.IsAltDown() && |
1188 win_util::IsNumPadDigit(e.GetCharacter(), e.IsExtendedKey())) | 1188 win_util::IsNumPadDigit(e.GetCharacter(), e.IsExtendedKey())) |
1189 return true; | 1189 return true; |
1190 | 1190 |
1191 return false; | 1191 return false; |
1192 } | 1192 } |
1193 | 1193 |
1194 void TextField::UpdateEditBackgroundColor() { | 1194 void Textfield::UpdateEditBackgroundColor() { |
1195 if (!edit_) | 1195 if (!edit_) |
1196 return; | 1196 return; |
1197 | 1197 |
1198 COLORREF bg_color; | 1198 COLORREF bg_color; |
1199 if (!use_default_background_color_) | 1199 if (!use_default_background_color_) |
1200 bg_color = skia::SkColorToCOLORREF(background_color_); | 1200 bg_color = skia::SkColorToCOLORREF(background_color_); |
1201 else | 1201 else |
1202 bg_color = GetSysColor(read_only_ ? COLOR_3DFACE : COLOR_WINDOW); | 1202 bg_color = GetSysColor(read_only_ ? COLOR_3DFACE : COLOR_WINDOW); |
1203 edit_->SetBackgroundColor(bg_color); | 1203 edit_->SetBackgroundColor(bg_color); |
1204 } | 1204 } |
1205 | 1205 |
1206 } // namespace views | 1206 } // namespace views |
OLD | NEW |