1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/wince/textctrlce.cpp 
   3 // Purpose:     wxTextCtrl implementation for smart phones driven by WinCE 
   4 // Author:      Wlodzimierz ABX Skiba 
   8 // Copyright:   (c) Wlodzimierz Skiba 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #if wxUSE_TEXTCTRL && defined(__SMARTPHONE__) && defined(__WXWINCE__) 
  29 #include "wx/textctrl.h" 
  32     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  35 #include "wx/spinbutt.h" 
  36 #include "wx/textfile.h" 
  38 #define GetBuddyHwnd()      (HWND)(m_hwndBuddy) 
  40 #define IsVertical(wxStyle) (true) 
  42 // ---------------------------------------------------------------------------- 
  43 // event tables and other macros 
  44 // ---------------------------------------------------------------------------- 
  46 #if wxUSE_EXTENDED_RTTI 
  49 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxControl
) 
  52 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
) 
  53     EVT_CHAR(wxTextCtrl::OnChar
) 
  55     EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
) 
  56     EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
) 
  57     EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
) 
  58     EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
) 
  59     EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
) 
  60     EVT_MENU(wxID_CLEAR
, wxTextCtrl::OnDelete
) 
  61     EVT_MENU(wxID_SELECTALL
, wxTextCtrl::OnSelectAll
) 
  63     EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
) 
  64     EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
) 
  65     EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
) 
  66     EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
) 
  67     EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
) 
  68     EVT_UPDATE_UI(wxID_CLEAR
, wxTextCtrl::OnUpdateDelete
) 
  69     EVT_UPDATE_UI(wxID_SELECTALL
, wxTextCtrl::OnUpdateSelectAll
) 
  71     EVT_SET_FOCUS(wxTextCtrl::OnSetFocus
) 
  74 // ---------------------------------------------------------------------------- 
  76 // ---------------------------------------------------------------------------- 
  78 // the margin between the up-down control and its buddy (can be arbitrary, 
  79 // choose what you like - or may be decide during run-time depending on the 
  81 static const int MARGIN_BETWEEN 
= 0; 
  83 // ============================================================================ 
  85 // ============================================================================ 
  87 wxArrayTextSpins 
wxTextCtrl::ms_allTextSpins
; 
  89 // ---------------------------------------------------------------------------- 
  90 // wnd proc for the buddy text ctrl 
  91 // ---------------------------------------------------------------------------- 
  93 LRESULT APIENTRY _EXPORT 
wxBuddyTextCtrlWndProc(HWND hwnd
, 
  98     wxTextCtrl 
*spin 
= (wxTextCtrl 
*)wxGetWindowUserData(hwnd
); 
 100     // forward some messages (the key and focus ones only so far) to 
 105             // if the focus comes from the spin control itself, don't set it 
 106             // back to it -- we don't want to go into an infinite loop 
 107             if ( (WXHWND
)wParam 
== spin
->GetHWND() ) 
 116             spin
->MSWWindowProc(message
, wParam
, lParam
); 
 118             // The control may have been deleted at this point, so check. 
 119             if ( !::IsWindow(hwnd
) || wxGetWindowUserData(hwnd
) != spin 
) 
 124             // we want to get WXK_RETURN in order to generate the event for it 
 125             return DLGC_WANTCHARS
; 
 128     return ::CallWindowProc(CASTWNDPROC spin
->GetBuddyWndProc(), 
 129                             hwnd
, message
, wParam
, lParam
); 
 132 // ---------------------------------------------------------------------------- 
 134 // ---------------------------------------------------------------------------- 
 136 void wxTextCtrl::Init() 
 138     m_suppressNextUpdate 
= false; 
 139     m_isNativeCaretShown 
= true; 
 142 wxTextCtrl::~wxTextCtrl() 
 146 bool wxTextCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 147                         const wxString
& value
, 
 151                         const wxValidator
& validator
, 
 152                         const wxString
& name
) 
 154     if ( (style 
& wxBORDER_MASK
) == wxBORDER_DEFAULT 
) 
 155         style 
|= wxBORDER_SIMPLE
; 
 157     SetWindowStyle(style
); 
 160     WXDWORD msStyle 
= MSWGetStyle(GetWindowStyle(), & exStyle
) ; 
 162     wxSize 
sizeText(size
), sizeBtn(size
); 
 163     sizeBtn
.x 
= GetBestSpinnerSize(IsVertical(style
)).x 
/ 2; 
 165     if ( sizeText
.x 
== wxDefaultCoord 
) 
 167         // DEFAULT_ITEM_WIDTH is the default width for the text control 
 168         sizeText
.x 
= DEFAULT_ITEM_WIDTH 
+ MARGIN_BETWEEN 
+ sizeBtn
.x
; 
 171     sizeText
.x 
-= sizeBtn
.x 
+ MARGIN_BETWEEN
; 
 172     if ( sizeText
.x 
<= 0 ) 
 174         wxLogDebug(_T("not enough space for wxSpinCtrl!")); 
 178     posBtn
.x 
+= sizeText
.x 
+ MARGIN_BETWEEN
; 
 180     // we need to turn '\n's into "\r\n"s for the multiline controls 
 182     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 184         valueWin 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 191     // we must create the list control before the spin button for the purpose 
 192     // of the dialog navigation: if there is a static text just before the spin 
 193     // control, activating it by Alt-letter should give focus to the text 
 194     // control, not the spin and the dialog navigation code will give focus to 
 195     // the next control (at Windows level), not the one after it 
 197     // create the text window 
 199     m_hwndBuddy 
= (WXHWND
)::CreateWindowEx
 
 201                      exStyle
,                // sunken border 
 202                      _T("EDIT"),             // window class 
 203                      valueWin
,               // no window title 
 204                      msStyle
,                // style (will be shown later) 
 205                      pos
.x
, pos
.y
,           // position 
 206                      0, 0,                   // size (will be set later) 
 207                      GetHwndOf(parent
),      // parent 
 208                      (HMENU
)-1,              // control id 
 209                      wxGetInstance(),        // app instance 
 210                      NULL                    
// unused client data 
 215         wxLogLastError(wxT("CreateWindow(buddy text window)")); 
 220     // initialize wxControl 
 221     if ( !CreateControl(parent
, id
, posBtn
, sizeBtn
, style
, validator
, name
) ) 
 224     // now create the real HWND 
 225     WXDWORD spiner_style 
= WS_VISIBLE 
| 
 230     if ( !IsVertical(style
) ) 
 231         spiner_style 
|= UDS_HORZ
; 
 233     if ( style 
& wxSP_WRAP 
) 
 234         spiner_style 
|= UDS_WRAP
; 
 236     if ( !MSWCreateControl(UPDOWN_CLASS
, spiner_style
, posBtn
, sizeBtn
, _T(""), 0) ) 
 239     // subclass the text ctrl to be able to intercept some events 
 240     wxSetWindowUserData(GetBuddyHwnd(), this); 
 241     m_wndProcBuddy 
= (WXFARPROC
)wxSetWindowProc(GetBuddyHwnd(), 
 242                                                 wxBuddyTextCtrlWndProc
); 
 244     // set up fonts and colours  (This is nomally done in MSWCreateControl) 
 247         SetFont(GetDefaultAttributes().font
); 
 249     // set the size of the text window - can do it only now, because we 
 250     // couldn't call DoGetBestSize() before as font wasn't set 
 251     if ( sizeText
.y 
<= 0 ) 
 254         wxGetCharSize(GetHWND(), &cx
, &cy
, GetFont()); 
 256         sizeText
.y 
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
); 
 261     (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW
); 
 263     // associate the list window with the spin button 
 264     (void)::SendMessage(GetHwnd(), UDM_SETBUDDY
, (WPARAM
)GetBuddyHwnd(), 0); 
 266     // do it after finishing with m_hwndBuddy creation to avoid generating 
 267     // initial wxEVT_COMMAND_TEXT_UPDATED message 
 268     ms_allTextSpins
.Add(this); 
 273 // Make sure the window style (etc.) reflects the HWND style (roughly) 
 274 void wxTextCtrl::AdoptAttributesFromHWND() 
 276     wxWindow::AdoptAttributesFromHWND(); 
 278     long style 
= ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE
); 
 280     if (style 
& ES_MULTILINE
) 
 281         m_windowStyle 
|= wxTE_MULTILINE
; 
 282     if (style 
& ES_PASSWORD
) 
 283         m_windowStyle 
|= wxTE_PASSWORD
; 
 284     if (style 
& ES_READONLY
) 
 285         m_windowStyle 
|= wxTE_READONLY
; 
 286     if (style 
& ES_WANTRETURN
) 
 287         m_windowStyle 
|= wxTE_PROCESS_ENTER
; 
 288     if (style 
& ES_CENTER
) 
 289         m_windowStyle 
|= wxTE_CENTRE
; 
 290     if (style 
& ES_RIGHT
) 
 291         m_windowStyle 
|= wxTE_RIGHT
; 
 294 WXDWORD 
wxTextCtrl::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 296     // we never have an external border 
 297     WXDWORD msStyle 
= wxControl::MSWGetStyle
 
 299                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
 
 302     msStyle 
|= WS_VISIBLE
; 
 304     // styles which we alaways add by default 
 305     if ( style 
& wxTE_MULTILINE 
) 
 307         wxASSERT_MSG( !(style 
& wxTE_PROCESS_ENTER
), 
 308                       wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") ); 
 310         msStyle 
|= ES_MULTILINE 
| ES_WANTRETURN
; 
 311         if ( !(style 
& wxTE_NO_VSCROLL
) ) 
 313             // always adjust the vertical scrollbar automatically if we have it 
 314             msStyle 
|= WS_VSCROLL 
| ES_AUTOVSCROLL
; 
 317         style 
|= wxTE_PROCESS_ENTER
; 
 321         // there is really no reason to not have this style for single line 
 323         msStyle 
|= ES_AUTOHSCROLL
; 
 326     // note that wxTE_DONTWRAP is the same as wxHSCROLL so if we have a horz 
 327     // scrollbar, there is no wrapping -- which makes sense 
 328     if ( style 
& wxTE_DONTWRAP 
) 
 330         // automatically scroll the control horizontally as necessary 
 332         // NB: ES_AUTOHSCROLL is needed for richedit controls or they don't 
 333         //     show horz scrollbar at all, even in spite of WS_HSCROLL, and as 
 334         //     it doesn't seem to do any harm for plain edit controls, add it 
 336         msStyle 
|= WS_HSCROLL 
| ES_AUTOHSCROLL
; 
 339     if ( style 
& wxTE_READONLY 
) 
 340         msStyle 
|= ES_READONLY
; 
 342     if ( style 
& wxTE_PASSWORD 
) 
 343         msStyle 
|= ES_PASSWORD
; 
 345     if ( style 
& wxTE_NOHIDESEL 
) 
 346         msStyle 
|= ES_NOHIDESEL
; 
 348     // note that we can't do do "& wxTE_LEFT" as wxTE_LEFT == 0 
 349     if ( style 
& wxTE_CENTRE 
) 
 350         msStyle 
|= ES_CENTER
; 
 351     else if ( style 
& wxTE_RIGHT 
) 
 354         msStyle 
|= ES_LEFT
; // ES_LEFT is 0 as well but for consistency... 
 359 // ---------------------------------------------------------------------------- 
 360 // set/get the controls text 
 361 // ---------------------------------------------------------------------------- 
 363 wxString 
wxTextCtrl::GetValue() const 
 365     // range 0..-1 is special for GetRange() and means to retrieve all text 
 366     return GetRange(0, -1); 
 369 wxString 
wxTextCtrl::GetRange(long from
, long to
) const 
 373     if ( from 
>= to 
&& to 
!= -1 ) 
 375         // nothing to retrieve 
 380     str 
= wxGetWindowText(GetBuddyHwnd()); 
 382     // need only a range? 
 385         str 
= str
.Mid(from
, to 
- from
); 
 388     // WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the 
 389     // canonical one (same one as above) for consistency with the other kinds 
 390     // of controls and, more importantly, with the other ports 
 391     str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 396 void wxTextCtrl::DoSetValue(const wxString
& value
, int flags
) 
 398     // if the text is long enough, it's faster to just set it instead of first 
 399     // comparing it with the old one (chances are that it will be different 
 400     // anyhow, this comparison is there to avoid flicker for small single-line 
 401     // edit controls mostly) 
 402     if ( (value
.length() > 0x400) || (value 
!= GetValue()) ) 
 404         DoWriteText(value
, flags
); 
 406         // for compatibility, don't move the cursor when doing SetValue() 
 407         SetInsertionPoint(0); 
 411         // still send an event for consistency 
 412         if ( flags 
& SetValue_SendEvent 
) 
 416     // we should reset the modified flag even if the value didn't really change 
 418     // mark the control as being not dirty - we changed its text, not the 
 423 void wxTextCtrl::WriteText(const wxString
& value
) 
 428 void wxTextCtrl::DoWriteText(const wxString
& value
, int flags
) 
 430     bool selectionOnly 
= (flags 
& SetValue_SelectionOnly
) != 0; 
 432     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 433         valueDos 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 437     // in some cases we get 2 EN_CHANGE notifications after the SendMessage 
 438     // call below which is confusing for the client code and so should be 
 441     if ( selectionOnly 
&& HasSelection() ) 
 443         m_suppressNextUpdate 
= true; 
 446     ::SendMessage(GetBuddyHwnd(), selectionOnly 
? EM_REPLACESEL 
: WM_SETTEXT
, 
 447                   0, (LPARAM
)valueDos
.c_str()); 
 449     if ( !selectionOnly 
&& !( flags 
& SetValue_SendEvent 
) ) 
 451         // Windows already sends an update event for single-line 
 453         if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 460 void wxTextCtrl::AppendText(const wxString
& text
) 
 462     SetInsertionPointEnd(); 
 467 void wxTextCtrl::Clear() 
 469     ::SetWindowText(GetBuddyHwnd(), wxEmptyString
); 
 471     // Windows already sends an update event for single-line 
 473     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 477 // ---------------------------------------------------------------------------- 
 478 // Clipboard operations 
 479 // ---------------------------------------------------------------------------- 
 481 void wxTextCtrl::Copy() 
 485         ::SendMessage(GetBuddyHwnd(), WM_COPY
, 0, 0L); 
 489 void wxTextCtrl::Cut() 
 493         ::SendMessage(GetBuddyHwnd(), WM_CUT
, 0, 0L); 
 497 void wxTextCtrl::Paste() 
 501         ::SendMessage(GetBuddyHwnd(), WM_PASTE
, 0, 0L); 
 505 bool wxTextCtrl::HasSelection() const 
 508     GetSelection(&from
, &to
); 
 512 bool wxTextCtrl::CanCopy() const 
 514     // Can copy if there's a selection 
 515     return HasSelection(); 
 518 bool wxTextCtrl::CanCut() const 
 520     return CanCopy() && IsEditable(); 
 523 bool wxTextCtrl::CanPaste() const 
 528     // Standard edit control: check for straight text on clipboard 
 529     if ( !::OpenClipboard(GetHwndOf(wxTheApp
->GetTopWindow())) ) 
 532     bool isTextAvailable 
= ::IsClipboardFormatAvailable(CF_TEXT
) != 0; 
 535     return isTextAvailable
; 
 538 // ---------------------------------------------------------------------------- 
 540 // ---------------------------------------------------------------------------- 
 542 void wxTextCtrl::SetEditable(bool editable
) 
 544     ::SendMessage(GetBuddyHwnd(), EM_SETREADONLY
, (WPARAM
)!editable
, (LPARAM
)0L); 
 547 void wxTextCtrl::SetInsertionPoint(long pos
) 
 549     DoSetSelection(pos
, pos
); 
 552 void wxTextCtrl::SetInsertionPointEnd() 
 554     if ( GetInsertionPoint() != GetLastPosition() ) 
 555         SetInsertionPoint(GetLastPosition()); 
 558 long wxTextCtrl::GetInsertionPoint() const 
 560     DWORD Pos 
= (DWORD
)::SendMessage(GetBuddyHwnd(), EM_GETSEL
, 0, 0L); 
 564 wxTextPos 
wxTextCtrl::GetLastPosition() const 
 566     int numLines 
= GetNumberOfLines(); 
 567     long posStartLastLine 
= XYToPosition(0, numLines 
- 1); 
 569     long lenLastLine 
= GetLengthOfLineContainingPos(posStartLastLine
); 
 571     return posStartLastLine 
+ lenLastLine
; 
 574 void wxTextCtrl::GetSelection(long* from
, long* to
) const 
 576     DWORD dwStart
, dwEnd
; 
 577     ::SendMessage(GetBuddyHwnd(), EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwEnd
); 
 583 bool wxTextCtrl::IsEditable() const 
 585     if ( !GetBuddyHwnd() ) 
 588     long style 
= ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE
); 
 590     return (style 
& ES_READONLY
) == 0; 
 593 // ---------------------------------------------------------------------------- 
 595 // ---------------------------------------------------------------------------- 
 597 void wxTextCtrl::SetSelection(long from
, long to
) 
 599     // if from and to are both -1, it means (in wxWidgets) that all text should 
 600     // be selected - translate into Windows convention 
 601     if ( (from 
== -1) && (to 
== -1) ) 
 607     DoSetSelection(from
, to
); 
 610 void wxTextCtrl::DoSetSelection(long from
, long to
, bool scrollCaret
) 
 612     ::SendMessage(GetBuddyHwnd(), EM_SETSEL
, (WPARAM
)from
, (LPARAM
)to
); 
 616         ::SendMessage(GetBuddyHwnd(), EM_SCROLLCARET
, (WPARAM
)0, (LPARAM
)0); 
 620 // ---------------------------------------------------------------------------- 
 621 // Working with files 
 622 // ---------------------------------------------------------------------------- 
 624 bool wxTextCtrl::LoadFile(const wxString
& file
) 
 626     if ( wxTextCtrlBase::LoadFile(file
) ) 
 628         // update the size limit if needed 
 637 // ---------------------------------------------------------------------------- 
 639 // ---------------------------------------------------------------------------- 
 641 void wxTextCtrl::Replace(long from
, long to
, const wxString
& value
) 
 643     // Set selection and remove it 
 644     DoSetSelection(from
, to
, false); 
 646     DoWriteText(value
, SetValue_SelectionOnly
); 
 649 void wxTextCtrl::Remove(long from
, long to
) 
 651     Replace(from
, to
, wxEmptyString
); 
 654 bool wxTextCtrl::IsModified() const 
 656     return ::SendMessage(GetBuddyHwnd(), EM_GETMODIFY
, 0, 0) != 0; 
 659 void wxTextCtrl::MarkDirty() 
 661     ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY
, TRUE
, 0L); 
 664 void wxTextCtrl::DiscardEdits() 
 666     ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY
, FALSE
, 0L); 
 669 int wxTextCtrl::GetNumberOfLines() const 
 671     return (int)::SendMessage(GetBuddyHwnd(), EM_GETLINECOUNT
, 0, 0L); 
 674 // ---------------------------------------------------------------------------- 
 675 // Positions <-> coords 
 676 // ---------------------------------------------------------------------------- 
 678 long wxTextCtrl::XYToPosition(long x
, long y
) const 
 680     // This gets the char index for the _beginning_ of this line 
 681     long charIndex 
= ::SendMessage(GetBuddyHwnd(), EM_LINEINDEX
, (WPARAM
)y
, (LPARAM
)0); 
 683     return charIndex 
+ x
; 
 686 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
 688     // This gets the line number containing the character 
 689     long lineNo 
= ::SendMessage(GetBuddyHwnd(), EM_LINEFROMCHAR
, (WPARAM
)pos
, 0); 
 697     // This gets the char index for the _beginning_ of this line 
 698     long charIndex 
= ::SendMessage(GetBuddyHwnd(), EM_LINEINDEX
, (WPARAM
)lineNo
, (LPARAM
)0); 
 699     if ( charIndex 
== -1 ) 
 704     // The X position must therefore be the different between pos and charIndex 
 706         *x 
= pos 
- charIndex
; 
 713 wxTextCtrlHitTestResult
 
 714 wxTextCtrl::HitTest(const wxPoint
& pt
, long *posOut
) const 
 716     // first get the position from Windows 
 717     // for the plain ones, we are limited to 16 bit positions which are 
 718     // combined in a single 32 bit value 
 719     LPARAM lParam 
= MAKELPARAM(pt
.x
, pt
.y
); 
 721     LRESULT pos 
= ::SendMessage(GetBuddyHwnd(), EM_CHARFROMPOS
, 0, lParam
); 
 725         // this seems to indicate an error... 
 726         return wxTE_HT_UNKNOWN
; 
 729     // for plain EDIT controls the higher word contains something else 
 733     // next determine where it is relatively to our point: EM_CHARFROMPOS 
 734     // always returns the closest character but we need to be more precise, so 
 735     // double check that we really are where it pretends 
 738     LRESULT lRc 
= ::SendMessage(GetBuddyHwnd(), EM_POSFROMCHAR
, pos
, 0); 
 742         // this is apparently returned when pos corresponds to the last 
 749         ptReal
.x 
= LOWORD(lRc
); 
 750         ptReal
.y 
= HIWORD(lRc
); 
 753     wxTextCtrlHitTestResult rc
; 
 755     if ( pt
.y 
> ptReal
.y 
+ GetCharHeight() ) 
 757     else if ( pt
.x 
> ptReal
.x 
+ GetCharWidth() ) 
 760         rc 
= wxTE_HT_ON_TEXT
; 
 768 void wxTextCtrl::ShowPosition(long pos
) 
 770     int currentLineLineNo 
= (int)::SendMessage(GetBuddyHwnd(), EM_GETFIRSTVISIBLELINE
, 0, 0L); 
 772     int specifiedLineLineNo 
= (int)::SendMessage(GetBuddyHwnd(), EM_LINEFROMCHAR
, (WPARAM
)pos
, 0L); 
 774     int linesToScroll 
= specifiedLineLineNo 
- currentLineLineNo
; 
 776     if (linesToScroll 
!= 0) 
 777         (void)::SendMessage(GetBuddyHwnd(), EM_LINESCROLL
, 0, (LPARAM
)linesToScroll
); 
 780 long wxTextCtrl::GetLengthOfLineContainingPos(long pos
) const 
 782     return ::SendMessage(GetBuddyHwnd(), EM_LINELENGTH
, (WPARAM
)pos
, 0L); 
 785 int wxTextCtrl::GetLineLength(long lineNo
) const 
 787     long pos 
= XYToPosition(0, lineNo
); 
 789     return GetLengthOfLineContainingPos(pos
); 
 792 wxString 
wxTextCtrl::GetLineText(long lineNo
) const 
 794     size_t len 
= (size_t)GetLineLength(lineNo
) + 1; 
 796     // there must be at least enough place for the length WORD in the 
 802         wxStringBufferLength 
tmp(str
, len
); 
 805         *(WORD 
*)buf 
= (WORD
)len
; 
 806         len 
= (size_t)::SendMessage(GetBuddyHwnd(), EM_GETLINE
, lineNo
, (LPARAM
)buf
); 
 808         // remove the '\n' at the end, if any (this is how this function is 
 809         // supposed to work according to the docs) 
 810         if ( buf
[len 
- 1] == _T('\n') ) 
 822 void wxTextCtrl::SetMaxLength(unsigned long len
) 
 824     ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT
, len
, 0); 
 827 // ---------------------------------------------------------------------------- 
 829 // ---------------------------------------------------------------------------- 
 831 void wxTextCtrl::Undo() 
 835         ::SendMessage(GetBuddyHwnd(), EM_UNDO
, 0, 0); 
 839 void wxTextCtrl::Redo() 
 843         ::SendMessage(GetBuddyHwnd(), EM_UNDO
, 0, 0); 
 847 bool wxTextCtrl::CanUndo() const 
 849     return ::SendMessage(GetBuddyHwnd(), EM_CANUNDO
, 0, 0) != 0; 
 852 bool wxTextCtrl::CanRedo() const 
 854     return ::SendMessage(GetBuddyHwnd(), EM_CANUNDO
, 0, 0) != 0; 
 857 // ---------------------------------------------------------------------------- 
 859 // ---------------------------------------------------------------------------- 
 861 // ---------------------------------------------------------------------------- 
 862 // implemenation details 
 863 // ---------------------------------------------------------------------------- 
 865 void wxTextCtrl::Command(wxCommandEvent 
& event
) 
 867     SetValue(event
.GetString()); 
 868     ProcessCommand (event
); 
 871 // ---------------------------------------------------------------------------- 
 872 // kbd input processing 
 873 // ---------------------------------------------------------------------------- 
 875 void wxTextCtrl::OnChar(wxKeyEvent
& event
) 
 877     switch ( event
.GetKeyCode() ) 
 880             if ( !HasFlag(wxTE_MULTILINE
) ) 
 882                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
); 
 883                 InitCommandEvent(event
); 
 884                 event
.SetString(GetValue()); 
 885                 if ( GetEventHandler()->ProcessEvent(event
) ) 
 888             //else: multiline controls need Enter for themselves 
 893             // ok, so this is getting absolutely ridiculous but I don't see 
 894             // any other way to fix this bug: when a multiline text control is 
 895             // inside a wxFrame, we need to generate the navigation event as 
 896             // otherwise nothing happens at all, but when the same control is 
 897             // created inside a dialog, IsDialogMessage() *does* switch focus 
 898             // all by itself and so if we do it here as well, it is advanced 
 899             // twice and goes to the next control... to prevent this from 
 900             // happening we're doing this ugly check, the logic being that if 
 901             // we don't have focus then it had been already changed to the next 
 904             // the right thing to do would, of course, be to understand what 
 905             // the hell is IsDialogMessage() doing but this is beyond my feeble 
 906             // forces at the moment unfortunately 
 907             if ( !(m_windowStyle 
& wxTE_PROCESS_TAB
)) 
 909                 if ( FindFocus() == this ) 
 912                     if (!event
.ShiftDown()) 
 913                         flags 
|= wxNavigationKeyEvent::IsForward 
; 
 914                     if (event
.ControlDown()) 
 915                         flags 
|= wxNavigationKeyEvent::WinChange 
; 
 922                 // Insert tab since calling the default Windows handler 
 923                 // doesn't seem to do it 
 924                 WriteText(wxT("\t")); 
 929     // no, we didn't process it 
 933 WXLRESULT 
wxTextCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 935     WXLRESULT lRc 
= wxTextCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
 937     if ( nMsg 
== WM_GETDLGCODE 
) 
 939         // we always want the chars and the arrows: the arrows for navigation 
 940         // and the chars because we want Ctrl-C to work even in a read only 
 942         long lDlgCode 
= DLGC_WANTCHARS 
| DLGC_WANTARROWS
; 
 946             // we may have several different cases: 
 947             // 1. normal case: both TAB and ENTER are used for dlg navigation 
 948             // 2. ctrl which wants TAB for itself: ENTER is used to pass to the 
 949             //    next control in the dialog 
 950             // 3. ctrl which wants ENTER for itself: TAB is used for dialog 
 952             // 4. ctrl which wants both TAB and ENTER: Ctrl-ENTER is used to go 
 953             //    to the next control 
 955             // the multiline edit control should always get <Return> for itself 
 956             if ( HasFlag(wxTE_PROCESS_ENTER
) || HasFlag(wxTE_MULTILINE
) ) 
 957                 lDlgCode 
|= DLGC_WANTMESSAGE
; 
 959             if ( HasFlag(wxTE_PROCESS_TAB
) ) 
 960                 lDlgCode 
|= DLGC_WANTTAB
; 
 966             // NB: use "=", not "|=" as the base class version returns the 
 967             //     same flags is this state as usual (i.e. including 
 968             //     DLGC_WANTMESSAGE). This is strange (how does it work in the 
 969             //     native Win32 apps?) but for now live with it. 
 977 // ---------------------------------------------------------------------------- 
 978 // text control event processing 
 979 // ---------------------------------------------------------------------------- 
 981 bool wxTextCtrl::SendUpdateEvent() 
 983     // is event reporting suspended? 
 984     if ( m_suppressNextUpdate 
) 
 986         // do process the next one 
 987         m_suppressNextUpdate 
= false; 
 992     wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, GetId()); 
 993     InitCommandEvent(event
); 
 994     event
.SetString(GetValue()); 
 996     return ProcessCommand(event
); 
 999 bool wxTextCtrl::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
1006                 wxFocusEvent 
event(param 
== EN_KILLFOCUS 
? wxEVT_KILL_FOCUS
 
1009                 event
.SetEventObject(this); 
1010                 GetEventHandler()->ProcessEvent(event
); 
1019             // the text size limit has been hit -- try to increase it 
1020             if ( !AdjustSpaceLimit() ) 
1022                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_MAXLEN
, m_windowId
); 
1023                 InitCommandEvent(event
); 
1024                 event
.SetString(GetValue()); 
1025                 ProcessCommand(event
); 
1029             // the other edit notification messages are not processed 
1038 bool wxTextCtrl::AdjustSpaceLimit() 
1040     unsigned int limit 
= ::SendMessage(GetBuddyHwnd(), EM_GETLIMITTEXT
, 0, 0); 
1042     // HACK: we try to automatically extend the limit for the amount of text 
1043     //       to allow (interactively) entering more than 64Kb of text under 
1044     //       Win9x but we shouldn't reset the text limit which was previously 
1045     //       set explicitly with SetMaxLength() 
1047     //       we could solve this by storing the limit we set in wxTextCtrl but 
1048     //       to save space we prefer to simply test here the actual limit 
1049     //       value: we consider that SetMaxLength() can only be called for 
1051     if ( limit 
< 0x8000 ) 
1053         // we've got more text than limit set by SetMaxLength() 
1057     unsigned int len 
= ::GetWindowTextLength(GetBuddyHwnd()); 
1060         limit 
= len 
+ 0x8000;    // 32Kb 
1062         if ( limit 
> 0xffff ) 
1064             // this will set it to a platform-dependent maximum (much more 
1065             // than 64Kb under NT) 
1069         ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT
, limit
, 0L); 
1072     // we changed the limit 
1076 bool wxTextCtrl::AcceptsFocus() const 
1078     // we don't want focus if we can't be edited unless we're a multiline 
1079     // control because then it might be still nice to get focus from keyboard 
1080     // to be able to scroll it without mouse 
1081     return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus(); 
1084 void wxTextCtrl::DoMoveWindow(int x
, int y
, int width
, int height
) 
1086     int widthBtn 
= GetBestSpinnerSize(IsVertical(GetWindowStyle())).x 
/ 2; 
1087     int widthText 
= width 
- widthBtn 
- MARGIN_BETWEEN
; 
1088     if ( widthText 
<= 0 ) 
1090         wxLogDebug(_T("not enough space for wxSpinCtrl!")); 
1093     if ( !::MoveWindow(GetBuddyHwnd(), x
, y
, widthText
, height
, TRUE
) ) 
1095         wxLogLastError(wxT("MoveWindow(buddy)")); 
1098     x 
+= widthText 
+ MARGIN_BETWEEN
; 
1099     if ( !::MoveWindow(GetHwnd(), x
, y
, widthBtn
, height
, TRUE
) ) 
1101         wxLogLastError(wxT("MoveWindow")); 
1105 wxSize 
wxTextCtrl::DoGetBestSize() const 
1108     wxGetCharSize(GetBuddyHwnd(), &cx
, &cy
, GetFont()); 
1110     int wText 
= DEFAULT_ITEM_WIDTH
; 
1113     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1115         hText 
*= wxMax(GetNumberOfLines(), 5); 
1117     //else: for single line control everything is ok 
1119     // we have to add the adjustments for the control height only once, not 
1120     // once per line, so do it after multiplication above 
1121     hText 
+= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
) - cy
; 
1123     return wxSize(wText
, hText
); 
1126 // ---------------------------------------------------------------------------- 
1127 // standard handlers for standard edit menu events 
1128 // ---------------------------------------------------------------------------- 
1130 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
1135 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
1140 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
1145 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
1150 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
1155 void wxTextCtrl::OnDelete(wxCommandEvent
& WXUNUSED(event
)) 
1158     GetSelection(& from
, & to
); 
1159     if (from 
!= -1 && to 
!= -1) 
1163 void wxTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
1165     SetSelection(-1, -1); 
1168 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
1170     event
.Enable( CanCut() ); 
1173 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
1175     event
.Enable( CanCopy() ); 
1178 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
1180     event
.Enable( CanPaste() ); 
1183 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
1185     event
.Enable( CanUndo() ); 
1188 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
1190     event
.Enable( CanRedo() ); 
1193 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent
& event
) 
1196     GetSelection(& from
, & to
); 
1197     event
.Enable(from 
!= -1 && to 
!= -1 && from 
!= to 
&& IsEditable()) ; 
1200 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
1202     event
.Enable(GetLastPosition() > 0); 
1205 void wxTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
1207     // be sure the caret remains invisible if the user had hidden it 
1208     if ( !m_isNativeCaretShown 
) 
1210         ::HideCaret(GetBuddyHwnd()); 
1214 #endif // wxUSE_TEXTCTRL && __SMARTPHONE__ && __WXWINCE__