1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/wince/textctrlce.cpp 
   3 // Purpose:     wxTextCtrl implementation for Smartphones 
   4 // Author:      Wlodzimierz ABX Skiba 
   8 // Copyright:   (c) Wlodzimierz Skiba 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  13 // ============================================================================ 
  15 // ============================================================================ 
  17 // ---------------------------------------------------------------------------- 
  19 // ---------------------------------------------------------------------------- 
  21 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  22     #pragma implementation "textctrlce.h" 
  25 // For compilers that support precompilation, includes "wx.h". 
  26 #include "wx/wxprec.h" 
  33     #include "wx/textctrl.h" 
  36 #include "wx/spinbutt.h" 
  37 #include "wx/textfile.h" 
  40 #include "wx/msw/missing.h" 
  41 #include "wx/msw/winundef.h" 
  43 #if wxUSE_TEXTCTRL && defined(__SMARTPHONE__) 
  45 #define GetBuddyHwnd()      (HWND)(m_hwndBuddy) 
  47 #define IsVertical(wxStyle) (true) 
  49 // ---------------------------------------------------------------------------- 
  50 // event tables and other macros 
  51 // ---------------------------------------------------------------------------- 
  53 #if wxUSE_EXTENDED_RTTI 
  56 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxControl
) 
  59 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
) 
  60     EVT_CHAR(wxTextCtrl::OnChar
) 
  62     EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
) 
  63     EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
) 
  64     EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
) 
  65     EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
) 
  66     EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
) 
  67     EVT_MENU(wxID_CLEAR
, wxTextCtrl::OnDelete
) 
  68     EVT_MENU(wxID_SELECTALL
, wxTextCtrl::OnSelectAll
) 
  70     EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
) 
  71     EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
) 
  72     EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
) 
  73     EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
) 
  74     EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
) 
  75     EVT_UPDATE_UI(wxID_CLEAR
, wxTextCtrl::OnUpdateDelete
) 
  76     EVT_UPDATE_UI(wxID_SELECTALL
, wxTextCtrl::OnUpdateSelectAll
) 
  78     EVT_SET_FOCUS(wxTextCtrl::OnSetFocus
) 
  81 // ---------------------------------------------------------------------------- 
  83 // ---------------------------------------------------------------------------- 
  85 // the margin between the up-down control and its buddy (can be arbitrary, 
  86 // choose what you like - or may be decide during run-time depending on the 
  88 static const int MARGIN_BETWEEN 
= 0; 
  90 // ============================================================================ 
  92 // ============================================================================ 
  94 wxArrayTextSpins 
wxTextCtrl::ms_allTextSpins
; 
  96 // ---------------------------------------------------------------------------- 
  97 // wnd proc for the buddy text ctrl 
  98 // ---------------------------------------------------------------------------- 
 100 LRESULT APIENTRY _EXPORT 
wxBuddyTextCtrlWndProc(HWND hwnd
, 
 105     wxTextCtrl 
*spin 
= (wxTextCtrl 
*)wxGetWindowUserData(hwnd
); 
 107     // forward some messages (the key and focus ones only so far) to 
 112             // if the focus comes from the spin control itself, don't set it 
 113             // back to it -- we don't want to go into an infinite loop 
 114             if ( (WXHWND
)wParam 
== spin
->GetHWND() ) 
 123             spin
->MSWWindowProc(message
, wParam
, lParam
); 
 125             // The control may have been deleted at this point, so check. 
 126             if ( !::IsWindow(hwnd
) || wxGetWindowUserData(hwnd
) != spin 
) 
 131             // we want to get WXK_RETURN in order to generate the event for it 
 132             return DLGC_WANTCHARS
; 
 135     return ::CallWindowProc(CASTWNDPROC spin
->GetBuddyWndProc(), 
 136                             hwnd
, message
, wParam
, lParam
); 
 139 // ---------------------------------------------------------------------------- 
 141 // ---------------------------------------------------------------------------- 
 143 void wxTextCtrl::Init() 
 145     m_suppressNextUpdate 
= false; 
 146     m_isNativeCaretShown 
= true; 
 149 wxTextCtrl::~wxTextCtrl() 
 153 bool wxTextCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 154                         const wxString
& value
, 
 158                         const wxValidator
& validator
, 
 159                         const wxString
& name
) 
 161     if ( (style 
& wxBORDER_MASK
) == wxBORDER_DEFAULT 
) 
 162         style 
|= wxBORDER_SIMPLE
; 
 164     SetWindowStyle(style
); 
 167     WXDWORD msStyle 
= MSWGetStyle(GetWindowStyle(), & exStyle
) ; 
 169     wxSize 
sizeText(size
), sizeBtn(size
); 
 170     sizeBtn
.x 
= GetBestSpinerSize(IsVertical(style
)).x 
/ 2; 
 172     if ( sizeText
.x 
== wxDefaultCoord 
) 
 174         // DEFAULT_ITEM_WIDTH is the default width for the text control 
 175         sizeText
.x 
= DEFAULT_ITEM_WIDTH 
+ MARGIN_BETWEEN 
+ sizeBtn
.x
; 
 178     sizeText
.x 
-= sizeBtn
.x 
+ MARGIN_BETWEEN
; 
 179     if ( sizeText
.x 
<= 0 ) 
 181         wxLogDebug(_T("not enough space for wxSpinCtrl!")); 
 185     posBtn
.x 
+= sizeText
.x 
+ MARGIN_BETWEEN
; 
 187     // we need to turn '\n's into "\r\n"s for the multiline controls 
 189     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 191         valueWin 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 198     // we must create the list control before the spin button for the purpose 
 199     // of the dialog navigation: if there is a static text just before the spin 
 200     // control, activating it by Alt-letter should give focus to the text 
 201     // control, not the spin and the dialog navigation code will give focus to 
 202     // the next control (at Windows level), not the one after it 
 204     // create the text window 
 206     m_hwndBuddy 
= (WXHWND
)::CreateWindowEx
 
 208                      exStyle
,                // sunken border 
 209                      _T("EDIT"),             // window class 
 210                      valueWin
,               // no window title 
 211                      msStyle
,                // style (will be shown later) 
 212                      pos
.x
, pos
.y
,           // position 
 213                      0, 0,                   // size (will be set later) 
 214                      GetHwndOf(parent
),      // parent 
 215                      (HMENU
)-1,              // control id 
 216                      wxGetInstance(),        // app instance 
 217                      NULL                    
// unused client data 
 222         wxLogLastError(wxT("CreateWindow(buddy text window)")); 
 227     // initialize wxControl 
 228     if ( !CreateControl(parent
, id
, posBtn
, sizeBtn
, style
, validator
, name
) ) 
 231     // now create the real HWND 
 232     WXDWORD spiner_style 
= WS_VISIBLE 
| 
 237     if ( !IsVertical(style
) ) 
 238         spiner_style 
|= UDS_HORZ
; 
 240     if ( style 
& wxSP_WRAP 
) 
 241         spiner_style 
|= UDS_WRAP
; 
 243     if ( !MSWCreateControl(UPDOWN_CLASS
, spiner_style
, posBtn
, sizeBtn
, _T(""), 0) ) 
 246     // subclass the text ctrl to be able to intercept some events 
 247     wxSetWindowUserData(GetBuddyHwnd(), this); 
 248     m_wndProcBuddy 
= (WXFARPROC
)wxSetWindowProc(GetBuddyHwnd(), 
 249                                                 wxBuddyTextCtrlWndProc
); 
 251     // set up fonts and colours  (This is nomally done in MSWCreateControl) 
 254         SetFont(GetDefaultAttributes().font
); 
 256     // set the size of the text window - can do it only now, because we 
 257     // couldn't call DoGetBestSize() before as font wasn't set 
 258     if ( sizeText
.y 
<= 0 ) 
 261         wxGetCharSize(GetHWND(), &cx
, &cy
, GetFont()); 
 263         sizeText
.y 
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
); 
 268     (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW
); 
 270     // associate the list window with the spin button 
 271     (void)::SendMessage(GetHwnd(), UDM_SETBUDDY
, (WPARAM
)GetBuddyHwnd(), 0); 
 273     // do it after finishing with m_hwndBuddy creation to avoid generating 
 274     // initial wxEVT_COMMAND_TEXT_UPDATED message 
 275     ms_allTextSpins
.Add(this); 
 280 // Make sure the window style (etc.) reflects the HWND style (roughly) 
 281 void wxTextCtrl::AdoptAttributesFromHWND() 
 283     wxWindow::AdoptAttributesFromHWND(); 
 285     long style 
= ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE
); 
 287     if (style 
& ES_MULTILINE
) 
 288         m_windowStyle 
|= wxTE_MULTILINE
; 
 289     if (style 
& ES_PASSWORD
) 
 290         m_windowStyle 
|= wxTE_PASSWORD
; 
 291     if (style 
& ES_READONLY
) 
 292         m_windowStyle 
|= wxTE_READONLY
; 
 293     if (style 
& ES_WANTRETURN
) 
 294         m_windowStyle 
|= wxTE_PROCESS_ENTER
; 
 295     if (style 
& ES_CENTER
) 
 296         m_windowStyle 
|= wxTE_CENTRE
; 
 297     if (style 
& ES_RIGHT
) 
 298         m_windowStyle 
|= wxTE_RIGHT
; 
 301 WXDWORD 
wxTextCtrl::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 303     // we never have an external border 
 304     WXDWORD msStyle 
= wxControl::MSWGetStyle
 
 306                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
 
 309     msStyle 
|= WS_VISIBLE
; 
 311     // styles which we alaways add by default 
 312     if ( style 
& wxTE_MULTILINE 
) 
 314         wxASSERT_MSG( !(style 
& wxTE_PROCESS_ENTER
), 
 315                       wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") ); 
 317         msStyle 
|= ES_MULTILINE 
| ES_WANTRETURN
; 
 318         if ( !(style 
& wxTE_NO_VSCROLL
) ) 
 320             // always adjust the vertical scrollbar automatically if we have it 
 321             msStyle 
|= WS_VSCROLL 
| ES_AUTOVSCROLL
; 
 324         style 
|= wxTE_PROCESS_ENTER
; 
 328         // there is really no reason to not have this style for single line 
 330         msStyle 
|= ES_AUTOHSCROLL
; 
 333     // note that wxTE_DONTWRAP is the same as wxHSCROLL so if we have a horz 
 334     // scrollbar, there is no wrapping -- which makes sense 
 335     if ( style 
& wxTE_DONTWRAP 
) 
 337         // automatically scroll the control horizontally as necessary 
 339         // NB: ES_AUTOHSCROLL is needed for richedit controls or they don't 
 340         //     show horz scrollbar at all, even in spite of WS_HSCROLL, and as 
 341         //     it doesn't seem to do any harm for plain edit controls, add it 
 343         msStyle 
|= WS_HSCROLL 
| ES_AUTOHSCROLL
; 
 346     if ( style 
& wxTE_READONLY 
) 
 347         msStyle 
|= ES_READONLY
; 
 349     if ( style 
& wxTE_PASSWORD 
) 
 350         msStyle 
|= ES_PASSWORD
; 
 352     if ( style 
& wxTE_NOHIDESEL 
) 
 353         msStyle 
|= ES_NOHIDESEL
; 
 355     // note that we can't do do "& wxTE_LEFT" as wxTE_LEFT == 0 
 356     if ( style 
& wxTE_CENTRE 
) 
 357         msStyle 
|= ES_CENTER
; 
 358     else if ( style 
& wxTE_RIGHT 
) 
 361         msStyle 
|= ES_LEFT
; // ES_LEFT is 0 as well but for consistency... 
 366 // ---------------------------------------------------------------------------- 
 367 // set/get the controls text 
 368 // ---------------------------------------------------------------------------- 
 370 wxString 
wxTextCtrl::GetValue() const 
 372     // range 0..-1 is special for GetRange() and means to retrieve all text 
 373     return GetRange(0, -1); 
 376 wxString 
wxTextCtrl::GetRange(long from
, long to
) const 
 380     if ( from 
>= to 
&& to 
!= -1 ) 
 382         // nothing to retrieve 
 387     str 
= wxGetWindowText(GetBuddyHwnd()); 
 389     // need only a range? 
 392         str 
= str
.Mid(from
, to 
- from
); 
 395     // WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the 
 396     // canonical one (same one as above) for consistency with the other kinds 
 397     // of controls and, more importantly, with the other ports 
 398     str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 403 void wxTextCtrl::SetValue(const wxString
& value
) 
 405     // if the text is long enough, it's faster to just set it instead of first 
 406     // comparing it with the old one (chances are that it will be different 
 407     // anyhow, this comparison is there to avoid flicker for small single-line 
 408     // edit controls mostly) 
 409     if ( (value
.length() > 0x400) || (value 
!= GetValue()) ) 
 411         DoWriteText(value
, false); 
 413         // for compatibility, don't move the cursor when doing SetValue() 
 414         SetInsertionPoint(0); 
 418         // still send an event for consistency 
 422     // we should reset the modified flag even if the value didn't really change 
 424     // mark the control as being not dirty - we changed its text, not the 
 429 void wxTextCtrl::WriteText(const wxString
& value
) 
 434 void wxTextCtrl::DoWriteText(const wxString
& value
, bool selectionOnly
) 
 437     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 438         valueDos 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 442     // in some cases we get 2 EN_CHANGE notifications after the SendMessage 
 443     // call below which is confusing for the client code and so should be 
 446     if ( ( selectionOnly 
&& HasSelection() ) ) 
 448         m_suppressNextUpdate 
= true; 
 451     ::SendMessage(GetBuddyHwnd(), selectionOnly 
? EM_REPLACESEL 
: WM_SETTEXT
, 
 452                   0, (LPARAM
)valueDos
.c_str()); 
 454     if ( !selectionOnly 
) 
 456         // Windows already sends an update event for single-line 
 458         if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 465 void wxTextCtrl::AppendText(const wxString
& text
) 
 467     SetInsertionPointEnd(); 
 472 void wxTextCtrl::Clear() 
 474     ::SetWindowText(GetBuddyHwnd(), wxEmptyString
); 
 476     // Windows already sends an update event for single-line 
 478     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 482 // ---------------------------------------------------------------------------- 
 483 // Clipboard operations 
 484 // ---------------------------------------------------------------------------- 
 486 void wxTextCtrl::Copy() 
 490         ::SendMessage(GetBuddyHwnd(), WM_COPY
, 0, 0L); 
 494 void wxTextCtrl::Cut() 
 498         ::SendMessage(GetBuddyHwnd(), WM_CUT
, 0, 0L); 
 502 void wxTextCtrl::Paste() 
 506         ::SendMessage(GetBuddyHwnd(), WM_PASTE
, 0, 0L); 
 510 bool wxTextCtrl::HasSelection() const 
 513     GetSelection(&from
, &to
); 
 517 bool wxTextCtrl::CanCopy() const 
 519     // Can copy if there's a selection 
 520     return HasSelection(); 
 523 bool wxTextCtrl::CanCut() const 
 525     return CanCopy() && IsEditable(); 
 528 bool wxTextCtrl::CanPaste() const 
 533     // Standard edit control: check for straight text on clipboard 
 534     if ( !::OpenClipboard(GetHwndOf(wxTheApp
->GetTopWindow())) ) 
 537     bool isTextAvailable 
= ::IsClipboardFormatAvailable(CF_TEXT
) != 0; 
 540     return isTextAvailable
; 
 543 // ---------------------------------------------------------------------------- 
 545 // ---------------------------------------------------------------------------- 
 547 void wxTextCtrl::SetEditable(bool editable
) 
 549     ::SendMessage(GetBuddyHwnd(), EM_SETREADONLY
, (WPARAM
)!editable
, (LPARAM
)0L); 
 552 void wxTextCtrl::SetInsertionPoint(long pos
) 
 554     DoSetSelection(pos
, pos
); 
 557 void wxTextCtrl::SetInsertionPointEnd() 
 559     if ( GetInsertionPoint() != GetLastPosition() ) 
 560         SetInsertionPoint(GetLastPosition()); 
 563 long wxTextCtrl::GetInsertionPoint() const 
 565     DWORD Pos 
= (DWORD
)::SendMessage(GetBuddyHwnd(), EM_GETSEL
, 0, 0L); 
 569 long wxTextCtrl::GetLastPosition() const 
 571     int numLines 
= GetNumberOfLines(); 
 572     long posStartLastLine 
= XYToPosition(0, numLines 
- 1); 
 574     long lenLastLine 
= GetLengthOfLineContainingPos(posStartLastLine
); 
 576     return posStartLastLine 
+ lenLastLine
; 
 579 void wxTextCtrl::GetSelection(long* from
, long* to
) const 
 581     DWORD dwStart
, dwEnd
; 
 582     ::SendMessage(GetBuddyHwnd(), EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwEnd
); 
 588 bool wxTextCtrl::IsEditable() const 
 590     if ( !GetBuddyHwnd() ) 
 593     long style 
= ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE
); 
 595     return (style 
& ES_READONLY
) == 0; 
 598 // ---------------------------------------------------------------------------- 
 600 // ---------------------------------------------------------------------------- 
 602 void wxTextCtrl::SetSelection(long from
, long to
) 
 604     // if from and to are both -1, it means (in wxWidgets) that all text should 
 605     // be selected - translate into Windows convention 
 606     if ( (from 
== -1) && (to 
== -1) ) 
 612     DoSetSelection(from
, to
); 
 615 void wxTextCtrl::DoSetSelection(long from
, long to
, bool scrollCaret
) 
 617     ::SendMessage(GetBuddyHwnd(), EM_SETSEL
, (WPARAM
)from
, (LPARAM
)to
); 
 621         ::SendMessage(GetBuddyHwnd(), EM_SCROLLCARET
, (WPARAM
)0, (LPARAM
)0); 
 625 // ---------------------------------------------------------------------------- 
 626 // Working with files 
 627 // ---------------------------------------------------------------------------- 
 629 bool wxTextCtrl::LoadFile(const wxString
& file
) 
 631     if ( wxTextCtrlBase::LoadFile(file
) ) 
 633         // update the size limit if needed 
 642 // ---------------------------------------------------------------------------- 
 644 // ---------------------------------------------------------------------------- 
 646 void wxTextCtrl::Replace(long from
, long to
, const wxString
& value
) 
 648     // Set selection and remove it 
 649     DoSetSelection(from
, to
, false); 
 651     DoWriteText(value
, true); 
 654 void wxTextCtrl::Remove(long from
, long to
) 
 656     Replace(from
, to
, wxEmptyString
); 
 659 bool wxTextCtrl::IsModified() const 
 661     return ::SendMessage(GetBuddyHwnd(), EM_GETMODIFY
, 0, 0) != 0; 
 664 void wxTextCtrl::MarkDirty() 
 666     ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY
, TRUE
, 0L); 
 669 void wxTextCtrl::DiscardEdits() 
 671     ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY
, FALSE
, 0L); 
 674 int wxTextCtrl::GetNumberOfLines() const 
 676     return (int)::SendMessage(GetBuddyHwnd(), EM_GETLINECOUNT
, 0, 0L); 
 679 // ---------------------------------------------------------------------------- 
 680 // Positions <-> coords 
 681 // ---------------------------------------------------------------------------- 
 683 long wxTextCtrl::XYToPosition(long x
, long y
) const 
 685     // This gets the char index for the _beginning_ of this line 
 686     long charIndex 
= ::SendMessage(GetBuddyHwnd(), EM_LINEINDEX
, (WPARAM
)y
, (LPARAM
)0); 
 688     return charIndex 
+ x
; 
 691 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
 693     // This gets the line number containing the character 
 694     long lineNo 
= ::SendMessage(GetBuddyHwnd(), EM_LINEFROMCHAR
, (WPARAM
)pos
, 0); 
 702     // This gets the char index for the _beginning_ of this line 
 703     long charIndex 
= ::SendMessage(GetBuddyHwnd(), EM_LINEINDEX
, (WPARAM
)lineNo
, (LPARAM
)0); 
 704     if ( charIndex 
== -1 ) 
 709     // The X position must therefore be the different between pos and charIndex 
 711         *x 
= pos 
- charIndex
; 
 718 wxTextCtrlHitTestResult
 
 719 wxTextCtrl::HitTest(const wxPoint
& pt
, long *posOut
) const 
 721     // first get the position from Windows 
 722     // for the plain ones, we are limited to 16 bit positions which are 
 723     // combined in a single 32 bit value 
 724     LPARAM lParam 
= MAKELPARAM(pt
.x
, pt
.y
); 
 726     LRESULT pos 
= ::SendMessage(GetBuddyHwnd(), EM_CHARFROMPOS
, 0, lParam
); 
 730         // this seems to indicate an error... 
 731         return wxTE_HT_UNKNOWN
; 
 734     // for plain EDIT controls the higher word contains something else 
 738     // next determine where it is relatively to our point: EM_CHARFROMPOS 
 739     // always returns the closest character but we need to be more precise, so 
 740     // double check that we really are where it pretends 
 743     LRESULT lRc 
= ::SendMessage(GetBuddyHwnd(), EM_POSFROMCHAR
, pos
, 0); 
 747         // this is apparently returned when pos corresponds to the last 
 754         ptReal
.x 
= LOWORD(lRc
); 
 755         ptReal
.y 
= HIWORD(lRc
); 
 758     wxTextCtrlHitTestResult rc
; 
 760     if ( pt
.y 
> ptReal
.y 
+ GetCharHeight() ) 
 762     else if ( pt
.x 
> ptReal
.x 
+ GetCharWidth() ) 
 765         rc 
= wxTE_HT_ON_TEXT
; 
 773 void wxTextCtrl::ShowPosition(long pos
) 
 775     int currentLineLineNo 
= (int)::SendMessage(GetBuddyHwnd(), EM_GETFIRSTVISIBLELINE
, 0, 0L); 
 777     int specifiedLineLineNo 
= (int)::SendMessage(GetBuddyHwnd(), EM_LINEFROMCHAR
, (WPARAM
)pos
, 0L); 
 779     int linesToScroll 
= specifiedLineLineNo 
- currentLineLineNo
; 
 781     if (linesToScroll 
!= 0) 
 782         (void)::SendMessage(GetBuddyHwnd(), EM_LINESCROLL
, 0, (LPARAM
)linesToScroll
); 
 785 long wxTextCtrl::GetLengthOfLineContainingPos(long pos
) const 
 787     return ::SendMessage(GetBuddyHwnd(), EM_LINELENGTH
, (WPARAM
)pos
, 0L); 
 790 int wxTextCtrl::GetLineLength(long lineNo
) const 
 792     long pos 
= XYToPosition(0, lineNo
); 
 794     return GetLengthOfLineContainingPos(pos
); 
 797 wxString 
wxTextCtrl::GetLineText(long lineNo
) const 
 799     size_t len 
= (size_t)GetLineLength(lineNo
) + 1; 
 801     // there must be at least enough place for the length WORD in the 
 807         wxStringBufferLength 
tmp(str
, len
); 
 810         *(WORD 
*)buf 
= (WORD
)len
; 
 811         len 
= (size_t)::SendMessage(GetBuddyHwnd(), EM_GETLINE
, lineNo
, (LPARAM
)buf
); 
 813         // remove the '\n' at the end, if any (this is how this function is 
 814         // supposed to work according to the docs) 
 815         if ( buf
[len 
- 1] == _T('\n') ) 
 827 void wxTextCtrl::SetMaxLength(unsigned long len
) 
 829     ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT
, len
, 0); 
 832 // ---------------------------------------------------------------------------- 
 834 // ---------------------------------------------------------------------------- 
 836 void wxTextCtrl::Undo() 
 840         ::SendMessage(GetBuddyHwnd(), EM_UNDO
, 0, 0); 
 844 void wxTextCtrl::Redo() 
 848         ::SendMessage(GetBuddyHwnd(), EM_UNDO
, 0, 0); 
 852 bool wxTextCtrl::CanUndo() const 
 854     return ::SendMessage(GetBuddyHwnd(), EM_CANUNDO
, 0, 0) != 0; 
 857 bool wxTextCtrl::CanRedo() const 
 859     return ::SendMessage(GetBuddyHwnd(), EM_CANUNDO
, 0, 0) != 0; 
 862 // ---------------------------------------------------------------------------- 
 864 // ---------------------------------------------------------------------------- 
 866 // ---------------------------------------------------------------------------- 
 867 // implemenation details 
 868 // ---------------------------------------------------------------------------- 
 870 void wxTextCtrl::Command(wxCommandEvent 
& event
) 
 872     SetValue(event
.GetString()); 
 873     ProcessCommand (event
); 
 876 // ---------------------------------------------------------------------------- 
 877 // kbd input processing 
 878 // ---------------------------------------------------------------------------- 
 880 void wxTextCtrl::OnChar(wxKeyEvent
& event
) 
 882     switch ( event
.GetKeyCode() ) 
 885             if ( !HasFlag(wxTE_MULTILINE
) ) 
 887                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
); 
 888                 InitCommandEvent(event
); 
 889                 event
.SetString(GetValue()); 
 890                 if ( GetEventHandler()->ProcessEvent(event
) ) 
 893             //else: multiline controls need Enter for themselves 
 898             // ok, so this is getting absolutely ridiculous but I don't see 
 899             // any other way to fix this bug: when a multiline text control is 
 900             // inside a wxFrame, we need to generate the navigation event as 
 901             // otherwise nothing happens at all, but when the same control is 
 902             // created inside a dialog, IsDialogMessage() *does* switch focus 
 903             // all by itself and so if we do it here as well, it is advanced 
 904             // twice and goes to the next control... to prevent this from 
 905             // happening we're doing this ugly check, the logic being that if 
 906             // we don't have focus then it had been already changed to the next 
 909             // the right thing to do would, of course, be to understand what 
 910             // the hell is IsDialogMessage() doing but this is beyond my feeble 
 911             // forces at the moment unfortunately 
 912             if ( !(m_windowStyle 
& wxTE_PROCESS_TAB
)) 
 914                 if ( FindFocus() == this ) 
 917                     if (!event
.ShiftDown()) 
 918                         flags 
|= wxNavigationKeyEvent::IsForward 
; 
 919                     if (event
.ControlDown()) 
 920                         flags 
|= wxNavigationKeyEvent::WinChange 
; 
 927                 // Insert tab since calling the default Windows handler 
 928                 // doesn't seem to do it 
 929                 WriteText(wxT("\t")); 
 934     // no, we didn't process it 
 938 WXLRESULT 
wxTextCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 940     WXLRESULT lRc 
= wxTextCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
 942     if ( nMsg 
== WM_GETDLGCODE 
) 
 944         // we always want the chars and the arrows: the arrows for navigation 
 945         // and the chars because we want Ctrl-C to work even in a read only 
 947         long lDlgCode 
= DLGC_WANTCHARS 
| DLGC_WANTARROWS
; 
 951             // we may have several different cases: 
 952             // 1. normal case: both TAB and ENTER are used for dlg navigation 
 953             // 2. ctrl which wants TAB for itself: ENTER is used to pass to the 
 954             //    next control in the dialog 
 955             // 3. ctrl which wants ENTER for itself: TAB is used for dialog 
 957             // 4. ctrl which wants both TAB and ENTER: Ctrl-ENTER is used to go 
 958             //    to the next control 
 960             // the multiline edit control should always get <Return> for itself 
 961             if ( HasFlag(wxTE_PROCESS_ENTER
) || HasFlag(wxTE_MULTILINE
) ) 
 962                 lDlgCode 
|= DLGC_WANTMESSAGE
; 
 964             if ( HasFlag(wxTE_PROCESS_TAB
) ) 
 965                 lDlgCode 
|= DLGC_WANTTAB
; 
 971             // NB: use "=", not "|=" as the base class version returns the 
 972             //     same flags is this state as usual (i.e. including 
 973             //     DLGC_WANTMESSAGE). This is strange (how does it work in the 
 974             //     native Win32 apps?) but for now live with it. 
 982 // ---------------------------------------------------------------------------- 
 983 // text control event processing 
 984 // ---------------------------------------------------------------------------- 
 986 bool wxTextCtrl::SendUpdateEvent() 
 988     // is event reporting suspended? 
 989     if ( m_suppressNextUpdate 
) 
 991         // do process the next one 
 992         m_suppressNextUpdate 
= false; 
 997     wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, GetId()); 
 998     InitCommandEvent(event
); 
 999     event
.SetString(GetValue()); 
1001     return ProcessCommand(event
); 
1004 bool wxTextCtrl::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
1011                 wxFocusEvent 
event(param 
== EN_KILLFOCUS 
? wxEVT_KILL_FOCUS
 
1014                 event
.SetEventObject(this); 
1015                 GetEventHandler()->ProcessEvent(event
); 
1024             // the text size limit has been hit -- try to increase it 
1025             if ( !AdjustSpaceLimit() ) 
1027                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_MAXLEN
, m_windowId
); 
1028                 InitCommandEvent(event
); 
1029                 event
.SetString(GetValue()); 
1030                 ProcessCommand(event
); 
1034             // the other edit notification messages are not processed 
1043 WXHBRUSH 
wxTextCtrl::OnCtlColor(WXHDC pDC
, WXHWND 
WXUNUSED(pWnd
), WXUINT 
WXUNUSED(nCtlColor
), 
1049                                WXUINT 
WXUNUSED(message
), 
1050                                WXWPARAM 
WXUNUSED(wParam
), 
1051                                WXLPARAM 
WXUNUSED(lParam
) 
1058         HBRUSH hbrush 
= Ctl3dCtlColorEx(message
, wParam
, lParam
); 
1059         return (WXHBRUSH
) hbrush
; 
1061 #endif // wxUSE_CTL3D 
1064     wxColour colBack 
= GetBackgroundColour(); 
1066     if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE
) == 0) 
1067         colBack 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
1069     ::SetBkColor(hdc
, wxColourToRGB(colBack
)); 
1070     ::SetTextColor(hdc
, wxColourToRGB(GetForegroundColour())); 
1072     wxBrush 
*brush 
= wxTheBrushList
->FindOrCreateBrush(colBack
, wxSOLID
); 
1074     return (WXHBRUSH
)brush
->GetResourceHandle(); 
1077 bool wxTextCtrl::AdjustSpaceLimit() 
1079     unsigned int limit 
= ::SendMessage(GetBuddyHwnd(), EM_GETLIMITTEXT
, 0, 0); 
1081     // HACK: we try to automatically extend the limit for the amount of text 
1082     //       to allow (interactively) entering more than 64Kb of text under 
1083     //       Win9x but we shouldn't reset the text limit which was previously 
1084     //       set explicitly with SetMaxLength() 
1086     //       we could solve this by storing the limit we set in wxTextCtrl but 
1087     //       to save space we prefer to simply test here the actual limit 
1088     //       value: we consider that SetMaxLength() can only be called for 
1090     if ( limit 
< 0x8000 ) 
1092         // we've got more text than limit set by SetMaxLength() 
1096     unsigned int len 
= ::GetWindowTextLength(GetBuddyHwnd()); 
1099         limit 
= len 
+ 0x8000;    // 32Kb 
1101         if ( limit 
> 0xffff ) 
1103             // this will set it to a platform-dependent maximum (much more 
1104             // than 64Kb under NT) 
1108         ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT
, limit
, 0L); 
1111     // we changed the limit 
1115 bool wxTextCtrl::AcceptsFocus() const 
1117     // we don't want focus if we can't be edited unless we're a multiline 
1118     // control because then it might be still nice to get focus from keyboard 
1119     // to be able to scroll it without mouse 
1120     return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus(); 
1123 void wxTextCtrl::DoMoveWindow(int x
, int y
, int width
, int height
) 
1125     int widthBtn 
= GetBestSpinerSize(IsVertical(GetWindowStyle())).x 
/ 2; 
1126     int widthText 
= width 
- widthBtn 
- MARGIN_BETWEEN
; 
1127     if ( widthText 
<= 0 ) 
1129         wxLogDebug(_T("not enough space for wxSpinCtrl!")); 
1132     if ( !::MoveWindow(GetBuddyHwnd(), x
, y
, widthText
, height
, TRUE
) ) 
1134         wxLogLastError(wxT("MoveWindow(buddy)")); 
1137     x 
+= widthText 
+ MARGIN_BETWEEN
; 
1138     if ( !::MoveWindow(GetHwnd(), x
, y
, widthBtn
, height
, TRUE
) ) 
1140         wxLogLastError(wxT("MoveWindow")); 
1144 wxSize 
wxTextCtrl::DoGetBestSize() const 
1147     wxGetCharSize(GetBuddyHwnd(), &cx
, &cy
, GetFont()); 
1149     int wText 
= DEFAULT_ITEM_WIDTH
; 
1152     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1154         hText 
*= wxMax(GetNumberOfLines(), 5); 
1156     //else: for single line control everything is ok 
1158     // we have to add the adjustments for the control height only once, not 
1159     // once per line, so do it after multiplication above 
1160     hText 
+= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
) - cy
; 
1162     return wxSize(wText
, hText
); 
1165 // ---------------------------------------------------------------------------- 
1166 // standard handlers for standard edit menu events 
1167 // ---------------------------------------------------------------------------- 
1169 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
1174 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
1179 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
1184 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
1189 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
1194 void wxTextCtrl::OnDelete(wxCommandEvent
& WXUNUSED(event
)) 
1197     GetSelection(& from
, & to
); 
1198     if (from 
!= -1 && to 
!= -1) 
1202 void wxTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
1204     SetSelection(-1, -1); 
1207 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
1209     event
.Enable( CanCut() ); 
1212 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
1214     event
.Enable( CanCopy() ); 
1217 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
1219     event
.Enable( CanPaste() ); 
1222 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
1224     event
.Enable( CanUndo() ); 
1227 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
1229     event
.Enable( CanRedo() ); 
1232 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent
& event
) 
1235     GetSelection(& from
, & to
); 
1236     event
.Enable(from 
!= -1 && to 
!= -1 && from 
!= to 
&& IsEditable()) ; 
1239 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
1241     event
.Enable(GetLastPosition() > 0); 
1244 void wxTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
1246     // be sure the caret remains invisible if the user had hidden it 
1247     if ( !m_isNativeCaretShown 
) 
1249         ::HideCaret(GetBuddyHwnd()); 
1253 #endif // wxUSE_TEXTCTRL && __SMARTPHONE__