1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/textctrl.cpp 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  17     #pragma implementation "textctrl.h" 
  20 // ---------------------------------------------------------------------------- 
  22 // ---------------------------------------------------------------------------- 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  31 #if wxUSE_TEXTCTRL && !(defined(__SMARTPHONE__) && defined(__WXWINCE__)) 
  34     #include "wx/textctrl.h" 
  35     #include "wx/settings.h" 
  45 #include "wx/module.h" 
  48     #include "wx/clipbrd.h" 
  51 #include "wx/textfile.h" 
  55 #include "wx/msw/private.h" 
  56 #include "wx/msw/winundef.h" 
  62 #include <sys/types.h> 
  67 // old mingw32 has richedit stuff directly in windows.h and doesn't have 
  69 #if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__) 
  73 #include "wx/msw/missing.h" 
  75 #endif // wxUSE_RICHEDIT 
  77 // ---------------------------------------------------------------------------- 
  79 // ---------------------------------------------------------------------------- 
  83 // this module initializes RichEdit DLL(s) if needed 
  84 class wxRichEditModule 
: public wxModule
 
  89         Version_1
,          // riched32.dll 
  90         Version_2or3
,       // both use riched20.dll 
  91         Version_41
,         // msftedit.dll (XP SP1 and Windows 2003) 
  95     virtual bool OnInit(); 
  96     virtual void OnExit(); 
  98     // load the richedit DLL for the specified version of rich edit 
  99     static bool Load(Version version
); 
 102     // the handles to richedit 1.0 and 2.0 (or 3.0) DLLs 
 103     static HINSTANCE ms_hRichEdit
[Version_Max
]; 
 105     DECLARE_DYNAMIC_CLASS(wxRichEditModule
) 
 108 HINSTANCE 
wxRichEditModule::ms_hRichEdit
[Version_Max
] = { NULL
, NULL
, NULL 
}; 
 110 IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule
, wxModule
) 
 112 #endif // wxUSE_RICHEDIT 
 114 // a small class used to set m_updatesCount to 0 (to filter duplicate events if 
 115 // necessary) and to reset it back to -1 afterwards 
 116 class UpdatesCountFilter
 
 119     UpdatesCountFilter(int& count
) 
 122         wxASSERT_MSG( m_count 
== -1, _T("wrong initial m_updatesCount value") ); 
 127     ~UpdatesCountFilter() 
 132     // return true if an event has been received 
 133     bool GotUpdate() const 
 141     DECLARE_NO_COPY_CLASS(UpdatesCountFilter
) 
 144 // ---------------------------------------------------------------------------- 
 145 // event tables and other macros 
 146 // ---------------------------------------------------------------------------- 
 148 #if wxUSE_EXTENDED_RTTI 
 149 WX_DEFINE_FLAGS( wxTextCtrlStyle 
) 
 151 wxBEGIN_FLAGS( wxTextCtrlStyle 
) 
 152     // new style border flags, we put them first to 
 153     // use them for streaming out 
 154     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
 155     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
 156     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
 157     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
 158     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
 159     wxFLAGS_MEMBER(wxBORDER_NONE
) 
 161     // old style border flags 
 162     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
 163     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
 164     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
 165     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
 166     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
 167     wxFLAGS_MEMBER(wxBORDER
) 
 169     // standard window styles 
 170     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
 171     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
 172     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
 173     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
 174     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
 175     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
 176     wxFLAGS_MEMBER(wxVSCROLL
) 
 177     wxFLAGS_MEMBER(wxHSCROLL
) 
 179     wxFLAGS_MEMBER(wxTE_PROCESS_ENTER
) 
 180     wxFLAGS_MEMBER(wxTE_PROCESS_TAB
) 
 181     wxFLAGS_MEMBER(wxTE_MULTILINE
) 
 182     wxFLAGS_MEMBER(wxTE_PASSWORD
) 
 183     wxFLAGS_MEMBER(wxTE_READONLY
) 
 184     wxFLAGS_MEMBER(wxHSCROLL
) 
 185     wxFLAGS_MEMBER(wxTE_RICH
) 
 186     wxFLAGS_MEMBER(wxTE_RICH2
) 
 187     wxFLAGS_MEMBER(wxTE_AUTO_URL
) 
 188     wxFLAGS_MEMBER(wxTE_NOHIDESEL
) 
 189     wxFLAGS_MEMBER(wxTE_LEFT
) 
 190     wxFLAGS_MEMBER(wxTE_CENTRE
) 
 191     wxFLAGS_MEMBER(wxTE_RIGHT
) 
 192     wxFLAGS_MEMBER(wxTE_DONTWRAP
) 
 193     wxFLAGS_MEMBER(wxTE_LINEWRAP
) 
 194     wxFLAGS_MEMBER(wxTE_WORDWRAP
) 
 196 wxEND_FLAGS( wxTextCtrlStyle 
) 
 198 IMPLEMENT_DYNAMIC_CLASS_XTI(wxTextCtrl
, wxControl
,"wx/textctrl.h") 
 200 wxBEGIN_PROPERTIES_TABLE(wxTextCtrl
) 
 201     wxEVENT_PROPERTY( TextUpdated 
, wxEVT_COMMAND_TEXT_UPDATED 
, wxCommandEvent 
) 
 202     wxEVENT_PROPERTY( TextEnter 
, wxEVT_COMMAND_TEXT_ENTER 
, wxCommandEvent 
) 
 204     wxPROPERTY( Font 
, wxFont 
, SetFont 
, GetFont  
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 205     wxPROPERTY( Value 
, wxString 
, SetValue
, GetValue
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 206     wxPROPERTY_FLAGS( WindowStyle 
, wxTextCtrlStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 207 wxEND_PROPERTIES_TABLE() 
 209 wxBEGIN_HANDLERS_TABLE(wxTextCtrl
) 
 210 wxEND_HANDLERS_TABLE() 
 212 wxCONSTRUCTOR_6( wxTextCtrl 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxString 
, Value 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle
) 
 214 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxControl
) 
 218 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
) 
 219     EVT_CHAR(wxTextCtrl::OnChar
) 
 220     EVT_DROP_FILES(wxTextCtrl::OnDropFiles
) 
 223     EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu
) 
 226     EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
) 
 227     EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
) 
 228     EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
) 
 229     EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
) 
 230     EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
) 
 231     EVT_MENU(wxID_CLEAR
, wxTextCtrl::OnDelete
) 
 232     EVT_MENU(wxID_SELECTALL
, wxTextCtrl::OnSelectAll
) 
 234     EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
) 
 235     EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
) 
 236     EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
) 
 237     EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
) 
 238     EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
) 
 239     EVT_UPDATE_UI(wxID_CLEAR
, wxTextCtrl::OnUpdateDelete
) 
 240     EVT_UPDATE_UI(wxID_SELECTALL
, wxTextCtrl::OnUpdateSelectAll
) 
 242     EVT_SET_FOCUS(wxTextCtrl::OnSetFocus
) 
 245 // ============================================================================ 
 247 // ============================================================================ 
 249 // ---------------------------------------------------------------------------- 
 251 // ---------------------------------------------------------------------------- 
 253 void wxTextCtrl::Init() 
 257 #endif // wxUSE_RICHEDIT 
 259     m_privateContextMenu 
= NULL
; 
 261     m_isNativeCaretShown 
= true; 
 264 wxTextCtrl::~wxTextCtrl() 
 266     delete m_privateContextMenu
; 
 269 bool wxTextCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 270                         const wxString
& value
, 
 274                         const wxValidator
& validator
, 
 275                         const wxString
& name
) 
 278     if ((style 
& wxBORDER_MASK
) == 0) 
 279         style 
|= wxBORDER_SIMPLE
; 
 282     // base initialization 
 283     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 286     // translate wxWin style flags to MSW ones 
 287     WXDWORD msStyle 
= MSWGetCreateWindowFlags(); 
 289     // do create the control - either an EDIT or RICHEDIT 
 290     wxString windowClass 
= wxT("EDIT"); 
 292 #if defined(__POCKETPC__) || defined(__SMARTPHONE__) 
 293     // A control that capitalizes the first letter 
 294     if (style 
& wxTE_CAPITALIZE
) 
 295         windowClass 
= wxT("CAPEDIT"); 
 299     if ( m_windowStyle 
& wxTE_AUTO_URL 
) 
 301         // automatic URL detection only works in RichEdit 2.0+ 
 302         m_windowStyle 
|= wxTE_RICH2
; 
 305     if ( m_windowStyle 
& wxTE_RICH2 
) 
 307         // using richedit 2.0 implies using wxTE_RICH 
 308         m_windowStyle 
|= wxTE_RICH
; 
 311     // we need to load the richedit DLL before creating the rich edit control 
 312     if ( m_windowStyle 
& wxTE_RICH 
) 
 314         // versions 2.0, 3.0 and 4.1 of rich edit are mostly compatible with 
 315         // each other but not with version 1.0, so we have separate flags for 
 316         // the version 1.0 and the others (and so m_verRichEdit may be 0 (plain 
 317         // EDIT control), 1 for version 1.0 or 2 for any higher version) 
 319         // notice that 1.0 has no Unicode support at all so in Unicode build we 
 320         // must use another version 
 324 #else // !wxUSE_UNICODE 
 325         m_verRichEdit 
= m_windowStyle 
& wxTE_RICH2 
? 2 : 1; 
 326 #endif // wxUSE_UNICODE/!wxUSE_UNICODE 
 328         if ( m_verRichEdit 
== 2 ) 
 330             if ( wxRichEditModule::Load(wxRichEditModule::Version_41
) ) 
 332                 // yes, class name for version 4.1 really is 5.0 
 333                 windowClass 
= _T("RICHEDIT50W"); 
 335             else if ( wxRichEditModule::Load(wxRichEditModule::Version_2or3
) ) 
 337                 windowClass 
= _T("RichEdit20") 
 342 #endif // Unicode/ANSI 
 344             else // failed to load msftedit.dll and riched20.dll 
 350         if ( m_verRichEdit 
== 1 ) 
 352             if ( wxRichEditModule::Load(wxRichEditModule::Version_1
) ) 
 354                 windowClass 
= _T("RICHEDIT"); 
 356             else // failed to load any richedit control DLL 
 358                 // only give the error msg once if the DLL can't be loaded 
 359                 static bool s_errorGiven 
= false; // MT ok as only used by GUI 
 361                 wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll")); 
 369 #endif // wxUSE_RICHEDIT 
 371     // we need to turn '\n's into "\r\n"s for the multiline controls 
 373     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 375         valueWin 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 382     if ( !MSWCreateControl(windowClass
, msStyle
, pos
, size
, valueWin
) ) 
 388         // enable the events we're interested in: we want to get EN_CHANGE as 
 389         // for the normal controls 
 390         LPARAM mask 
= ENM_CHANGE
; 
 392         if ( GetRichVersion() == 1 ) 
 394             // we also need EN_MSGFILTER for richedit 1.0 for the reasons 
 395             // explained in its handler 
 396            mask 
|= ENM_MOUSEEVENTS
; 
 398            // we also need to force the appearance of the vertical scrollbar 
 399            // initially as otherwise the control doesn't refresh correctly 
 400            // after resize: but once the vertical scrollbar had been shown 
 401            // (even if it's subsequently hidden) it does 
 403            // this is clearly a bug and for now it has been only noticed under 
 404            // Windows XP, so if we're sure it works correctly under other 
 405            // systems we could do this only for XP 
 406            SetSize(-1, 1); // 1 is small enough to force vert scrollbar 
 409         else if ( m_windowStyle 
& wxTE_AUTO_URL 
) 
 413             ::SendMessage(GetHwnd(), EM_AUTOURLDETECT
, TRUE
, 0); 
 416         ::SendMessage(GetHwnd(), EM_SETEVENTMASK
, 0, mask
); 
 418 #endif // wxUSE_RICHEDIT 
 423 // Make sure the window style (etc.) reflects the HWND style (roughly) 
 424 void wxTextCtrl::AdoptAttributesFromHWND() 
 426     wxWindow::AdoptAttributesFromHWND(); 
 428     HWND hWnd 
= GetHwnd(); 
 429     long style 
= ::GetWindowLong(hWnd
, GWL_STYLE
); 
 431     // retrieve the style to see whether this is an edit or richedit ctrl 
 433     wxString classname 
= wxGetWindowClass(GetHWND()); 
 435     if ( classname
.IsSameAs(_T("EDIT"), false /* no case */) ) 
 442         if ( wxSscanf(classname
, _T("RichEdit%d0%c"), &m_verRichEdit
, &c
) != 2 ) 
 444             wxLogDebug(_T("Unknown edit control '%s'."), classname
.c_str()); 
 449 #endif // wxUSE_RICHEDIT 
 451     if (style 
& ES_MULTILINE
) 
 452         m_windowStyle 
|= wxTE_MULTILINE
; 
 453     if (style 
& ES_PASSWORD
) 
 454         m_windowStyle 
|= wxTE_PASSWORD
; 
 455     if (style 
& ES_READONLY
) 
 456         m_windowStyle 
|= wxTE_READONLY
; 
 457     if (style 
& ES_WANTRETURN
) 
 458         m_windowStyle 
|= wxTE_PROCESS_ENTER
; 
 459     if (style 
& ES_CENTER
) 
 460         m_windowStyle 
|= wxTE_CENTRE
; 
 461     if (style 
& ES_RIGHT
) 
 462         m_windowStyle 
|= wxTE_RIGHT
; 
 465 WXDWORD 
wxTextCtrl::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 467     long msStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 469     // styles which we alaways add by default 
 470     if ( style 
& wxTE_MULTILINE 
) 
 472         wxASSERT_MSG( !(style 
& wxTE_PROCESS_ENTER
), 
 473                       wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") ); 
 475         msStyle 
|= ES_MULTILINE 
| ES_WANTRETURN
; 
 476         if ( !(style 
& wxTE_NO_VSCROLL
) ) 
 478             // always adjust the vertical scrollbar automatically if we have it 
 479             msStyle 
|= WS_VSCROLL 
| ES_AUTOVSCROLL
; 
 482             // we have to use this style for the rich edit controls because 
 483             // without it the vertical scrollbar never appears at all in 
 484             // richedit 3.0 because of our ECO_NOHIDESEL hack (search for it) 
 485             if ( style 
& wxTE_RICH2 
) 
 487                 msStyle 
|= ES_DISABLENOSCROLL
; 
 489 #endif // wxUSE_RICHEDIT 
 492         style 
|= wxTE_PROCESS_ENTER
; 
 496         // there is really no reason to not have this style for single line 
 498         msStyle 
|= ES_AUTOHSCROLL
; 
 501     // note that wxTE_DONTWRAP is the same as wxHSCROLL so if we have a horz 
 502     // scrollbar, there is no wrapping -- which makes sense 
 503     if ( style 
& wxTE_DONTWRAP 
) 
 505         // automatically scroll the control horizontally as necessary 
 507         // NB: ES_AUTOHSCROLL is needed for richedit controls or they don't 
 508         //     show horz scrollbar at all, even in spite of WS_HSCROLL, and as 
 509         //     it doesn't seem to do any harm for plain edit controls, add it 
 511         msStyle 
|= WS_HSCROLL 
| ES_AUTOHSCROLL
; 
 514     if ( style 
& wxTE_READONLY 
) 
 515         msStyle 
|= ES_READONLY
; 
 517     if ( style 
& wxTE_PASSWORD 
) 
 518         msStyle 
|= ES_PASSWORD
; 
 520     if ( style 
& wxTE_NOHIDESEL 
) 
 521         msStyle 
|= ES_NOHIDESEL
; 
 523     // note that we can't do do "& wxTE_LEFT" as wxTE_LEFT == 0 
 524     if ( style 
& wxTE_CENTRE 
) 
 525         msStyle 
|= ES_CENTER
; 
 526     else if ( style 
& wxTE_RIGHT 
) 
 529         msStyle 
|= ES_LEFT
; // ES_LEFT is 0 as well but for consistency... 
 534 void wxTextCtrl::SetWindowStyleFlag(long style
) 
 537     // we have to deal with some styles separately because they can't be 
 538     // changed by simply calling SetWindowLong(GWL_STYLE) but can be changed 
 539     // using richedit-specific EM_SETOPTIONS 
 541             ((style 
& wxTE_NOHIDESEL
) != (GetWindowStyle() & wxTE_NOHIDESEL
)) ) 
 543         bool set 
= (style 
& wxTE_NOHIDESEL
) != 0; 
 545         ::SendMessage(GetHwnd(), EM_SETOPTIONS
, set 
? ECOOP_OR 
: ECOOP_AND
, 
 546                       set 
? ECO_NOHIDESEL 
: ~ECO_NOHIDESEL
); 
 548 #endif // wxUSE_RICHEDIT 
 550     wxControl::SetWindowStyleFlag(style
); 
 553 // ---------------------------------------------------------------------------- 
 554 // set/get the controls text 
 555 // ---------------------------------------------------------------------------- 
 557 wxString 
wxTextCtrl::GetValue() const 
 559     // range 0..-1 is special for GetRange() and means to retrieve all text 
 560     return GetRange(0, -1); 
 563 wxString 
wxTextCtrl::GetRange(long from
, long to
) const 
 567     if ( from 
>= to 
&& to 
!= -1 ) 
 569         // nothing to retrieve 
 576         int len 
= GetWindowTextLength(GetHwnd()); 
 583             // we must use EM_STREAMOUT if we don't want to lose all characters 
 584             // not representable in the current character set (EM_GETTEXTRANGE 
 585             // simply replaces them with question marks...) 
 586             if ( GetRichVersion() > 1 ) 
 588                 // we must have some encoding, otherwise any 8bit chars in the 
 589                 // control are simply *lost* (replaced by '?') 
 590                 wxFontEncoding encoding 
= wxFONTENCODING_SYSTEM
; 
 592                 wxFont font 
= m_defaultStyle
.GetFont(); 
 598                    encoding 
= font
.GetEncoding(); 
 601                 if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 603                     encoding 
= wxLocale::GetSystemEncoding(); 
 606                 if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 608                     encoding 
= wxFONTENCODING_ISO8859_1
; 
 611                 str 
= StreamOut(encoding
); 
 615                     // we have to manually extract the required part, luckily 
 616                     // this is easy in this case as EOL characters in str are 
 617                     // just LFs because we remove CRs in wxRichEditStreamOut 
 618                     str 
= str
.Mid(from
, to 
- from
); 
 622             // StreamOut() wasn't used or failed, try to do it in normal way 
 624 #endif // !wxUSE_UNICODE 
 626                 // alloc one extra WORD as needed by the control 
 627                 wxStringBuffer 
tmp(str
, ++len
); 
 631                 textRange
.chrg
.cpMin 
= from
; 
 632                 textRange
.chrg
.cpMax 
= to
; 
 633                 textRange
.lpstrText 
= p
; 
 635                 (void)::SendMessage(GetHwnd(), EM_GETTEXTRANGE
, 
 636                                     0, (LPARAM
)&textRange
); 
 638                 if ( m_verRichEdit 
> 1 ) 
 640                     // RichEdit 2.0 uses just CR ('\r') for the 
 641                     // newlines which is neither Unix nor Windows 
 642                     // style - convert it to something reasonable 
 645                         if ( *p 
== _T('\r') ) 
 651             if ( m_verRichEdit 
== 1 ) 
 653                 // convert to the canonical form - see comment below 
 654                 str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 657         //else: no text at all, leave the string empty 
 660 #endif // wxUSE_RICHEDIT 
 663         str 
= wxGetWindowText(GetHWND()); 
 665         // need only a range? 
 668             str 
= str
.Mid(from
, to 
- from
); 
 671         // WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the 
 672         // canonical one (same one as above) for consistency with the other kinds 
 673         // of controls and, more importantly, with the other ports 
 674         str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 680 void wxTextCtrl::SetValue(const wxString
& value
) 
 682     // if the text is long enough, it's faster to just set it instead of first 
 683     // comparing it with the old one (chances are that it will be different 
 684     // anyhow, this comparison is there to avoid flicker for small single-line 
 685     // edit controls mostly) 
 686     if ( (value
.length() > 0x400) || (value 
!= GetValue()) ) 
 688         DoWriteText(value
, false /* not selection only */); 
 690         // for compatibility, don't move the cursor when doing SetValue() 
 691         SetInsertionPoint(0); 
 695         // still send an event for consistency 
 699     // we should reset the modified flag even if the value didn't really change 
 701     // mark the control as being not dirty - we changed its text, not the 
 706 #if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU) 
 708 // TODO: using memcpy() would improve performance a lot for big amounts of text 
 711 wxRichEditStreamIn(DWORD dwCookie
, BYTE 
*buf
, LONG cb
, LONG 
*pcb
) 
 715     const wchar_t ** const ppws 
= (const wchar_t **)dwCookie
; 
 717     wchar_t *wbuf 
= (wchar_t *)buf
; 
 718     const wchar_t *wpc 
= *ppws
; 
 723         cb 
-= sizeof(wchar_t); 
 724         (*pcb
) += sizeof(wchar_t); 
 732 // helper struct used to pass parameters from wxTextCtrl to wxRichEditStreamOut 
 733 struct wxStreamOutData
 
 740 wxRichEditStreamOut(DWORD_PTR dwCookie
, BYTE 
*buf
, LONG cb
, LONG 
*pcb
) 
 744     wxStreamOutData 
*data 
= (wxStreamOutData 
*)dwCookie
; 
 746     const wchar_t *wbuf 
= (const wchar_t *)buf
; 
 747     wchar_t *wpc 
= data
->wpc
; 
 750         wchar_t wch 
= *wbuf
++; 
 752         // turn "\r\n" into "\n" on the fly 
 758         cb 
-= sizeof(wchar_t); 
 759         (*pcb
) += sizeof(wchar_t); 
 768 #if wxUSE_UNICODE_MSLU 
 769     #define UNUSED_IF_MSLU(param) 
 771     #define UNUSED_IF_MSLU(param) param 
 775 wxTextCtrl::StreamIn(const wxString
& value
, 
 776                      wxFontEncoding 
UNUSED_IF_MSLU(encoding
), 
 779 #if wxUSE_UNICODE_MSLU 
 780     const wchar_t *wpc 
= value
.c_str(); 
 781 #else // !wxUSE_UNICODE_MSLU 
 782     wxCSConv 
conv(encoding
); 
 784     const size_t len 
= conv
.MB2WC(NULL
, value
, value
.length()); 
 787     wxWCharBuffer 
wchBuf(len
); 
 788     wchar_t *wpc 
= wchBuf
.data(); 
 790     wchar_t *wchBuf 
= (wchar_t *)malloc((len 
+ 1)*sizeof(wchar_t)); 
 791     wchar_t *wpc 
= wchBuf
; 
 794     conv
.MB2WC(wpc
, value
, value
.length()); 
 795 #endif // wxUSE_UNICODE_MSLU 
 797     // finally, stream it in the control 
 800     eds
.dwCookie 
= (DWORD
)&wpc
; 
 801     // the cast below is needed for broken (very) old mingw32 headers 
 802     eds
.pfnCallback 
= (EDITSTREAMCALLBACK
)wxRichEditStreamIn
; 
 804     // same problem as in DoWriteText(): we can get multiple events here 
 805     UpdatesCountFilter 
ucf(m_updatesCount
); 
 807     ::SendMessage(GetHwnd(), EM_STREAMIN
, 
 810                   (selectionOnly 
? SFF_SELECTION 
: 0), 
 813     wxASSERT_MSG( ucf
.GotUpdate(), _T("EM_STREAMIN didn't send EN_UPDATE?") ); 
 817         wxLogLastError(_T("EM_STREAMIN")); 
 822 #endif // !wxUSE_WCHAR_T 
 827 #if !wxUSE_UNICODE_MSLU 
 830 wxTextCtrl::StreamOut(wxFontEncoding encoding
, bool selectionOnly
) const 
 834     const int len 
= GetWindowTextLength(GetHwnd()); 
 837     wxWCharBuffer 
wchBuf(len
); 
 838     wchar_t *wpc 
= wchBuf
.data(); 
 840     wchar_t *wchBuf 
= (wchar_t *)malloc((len 
+ 1)*sizeof(wchar_t)); 
 841     wchar_t *wpc 
= wchBuf
; 
 844     wxStreamOutData data
; 
 850     eds
.dwCookie 
= (DWORD
)&data
; 
 851     eds
.pfnCallback 
= wxRichEditStreamOut
; 
 857         SF_TEXT 
| SF_UNICODE 
| (selectionOnly 
? SFF_SELECTION 
: 0), 
 863         wxLogLastError(_T("EM_STREAMOUT")); 
 865     else // streamed out ok 
 867         // NUL-terminate the string because its length could have been 
 868         // decreased by wxRichEditStreamOut 
 869         *(wchBuf
.data() + data
.len
) = L
'\0'; 
 871         // now convert to the given encoding (this is a possibly lossful 
 872         // conversion but what else can we do) 
 873         wxCSConv 
conv(encoding
); 
 874         size_t lenNeeded 
= conv
.WC2MB(NULL
, wchBuf
, 0); 
 877             conv
.WC2MB(wxStringBuffer(out
, lenNeeded
), wchBuf
, lenNeeded
); 
 883 #endif // !wxUSE_WCHAR_T 
 888 #endif // !wxUSE_UNICODE_MSLU 
 890 #endif // wxUSE_RICHEDIT 
 892 void wxTextCtrl::WriteText(const wxString
& value
) 
 897 void wxTextCtrl::DoWriteText(const wxString
& value
, bool selectionOnly
) 
 900     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 901         valueDos 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 906     // there are several complications with the rich edit controls here 
 910         // first, ensure that the new text will be in the default style 
 911         if ( !m_defaultStyle
.IsDefault() ) 
 914             GetSelection(&start
, &end
); 
 915             SetStyle(start
, end
, m_defaultStyle
); 
 918 #if wxUSE_UNICODE_MSLU 
 919         // RichEdit doesn't have Unicode version of EM_REPLACESEL on Win9x, 
 920         // but EM_STREAMIN works 
 921         if ( wxUsingUnicowsDll() && GetRichVersion() > 1 ) 
 923            done 
= StreamIn(valueDos
, wxFONTENCODING_SYSTEM
, selectionOnly
); 
 925 #endif // wxUSE_UNICODE_MSLU 
 928         // next check if the text we're inserting must be shown in a non 
 929         // default charset -- this only works for RichEdit > 1.0 
 930         if ( GetRichVersion() > 1 ) 
 932             wxFont font 
= m_defaultStyle
.GetFont(); 
 938                wxFontEncoding encoding 
= font
.GetEncoding(); 
 939                if ( encoding 
!= wxFONTENCODING_SYSTEM 
) 
 941                    // we have to use EM_STREAMIN to force richedit control 2.0+ 
 942                    // to show any text in the non default charset -- otherwise 
 943                    // it thinks it knows better than we do and always shows it 
 944                    // in the default one 
 945                    done 
= StreamIn(valueDos
, encoding
, selectionOnly
); 
 949 #endif // !wxUSE_UNICODE 
 953 #endif // wxUSE_RICHEDIT 
 955         // in some cases we get 2 EN_CHANGE notifications after the SendMessage 
 956         // call (this happens for plain EDITs with EM_REPLACESEL and under some 
 957         // -- undetermined -- conditions with rich edit) and sometimes we don't 
 958         // get any events at all (plain EDIT with WM_SETTEXT), so ensure that 
 959         // we generate exactly one of them by ignoring all but the first one in 
 960         // SendUpdateEvent() and generating one ourselves if we hadn't got any 
 961         // notifications from Windows 
 962         UpdatesCountFilter 
ucf(m_updatesCount
); 
 964         ::SendMessage(GetHwnd(), selectionOnly 
? EM_REPLACESEL 
: WM_SETTEXT
, 
 965                       0, (LPARAM
)valueDos
.c_str()); 
 967         if ( !ucf
.GotUpdate() ) 
 974 void wxTextCtrl::AppendText(const wxString
& text
) 
 976     SetInsertionPointEnd(); 
 981     // don't do this if we're frozen, saves some time 
 982     if ( !IsFrozen() && IsMultiLine() && GetRichVersion() > 1 ) 
 984         // setting the caret to the end and showing it simply doesn't work for 
 985         // RichEdit 2.0 -- force it to still do what we want 
 986         ::SendMessage(GetHwnd(), EM_LINESCROLL
, 0, GetNumberOfLines()); 
 988 #endif // wxUSE_RICHEDIT 
 991 void wxTextCtrl::Clear() 
 993     ::SetWindowText(GetHwnd(), wxEmptyString
); 
 997 #endif // wxUSE_RICHEDIT 
 999         // rich edit controls send EN_UPDATE from WM_SETTEXT handler themselves 
1000         // but the normal ones don't -- make Clear() behaviour consistent by 
1001         // always sending this event 
1003         // Windows already sends an update event for single-line 
1005         if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1012 bool wxTextCtrl::EmulateKeyPress(const wxKeyEvent
& event
) 
1016     size_t lenOld 
= GetValue().length(); 
1018     wxUint32 code 
= event
.GetRawKeyCode(); 
1019     ::keybd_event((BYTE
)code
, 0, 0 /* key press */, 0); 
1020     ::keybd_event((BYTE
)code
, 0, KEYEVENTF_KEYUP
, 0); 
1022     // assume that any alphanumeric key changes the total number of characters 
1023     // in the control - this should work in 99% of cases 
1024     return GetValue().length() != lenOld
; 
1029 // ---------------------------------------------------------------------------- 
1030 // Clipboard operations 
1031 // ---------------------------------------------------------------------------- 
1033 void wxTextCtrl::Copy() 
1037         ::SendMessage(GetHwnd(), WM_COPY
, 0, 0L); 
1041 void wxTextCtrl::Cut() 
1045         ::SendMessage(GetHwnd(), WM_CUT
, 0, 0L); 
1049 void wxTextCtrl::Paste() 
1053         ::SendMessage(GetHwnd(), WM_PASTE
, 0, 0L); 
1057 bool wxTextCtrl::HasSelection() const 
1060     GetSelection(&from
, &to
); 
1064 bool wxTextCtrl::CanCopy() const 
1066     // Can copy if there's a selection 
1067     return HasSelection(); 
1070 bool wxTextCtrl::CanCut() const 
1072     return CanCopy() && IsEditable(); 
1075 bool wxTextCtrl::CanPaste() const 
1077     if ( !IsEditable() ) 
1083         UINT cf 
= 0; // 0 == any format 
1085         return ::SendMessage(GetHwnd(), EM_CANPASTE
, cf
, 0) != 0; 
1087 #endif // wxUSE_RICHEDIT 
1089     // Standard edit control: check for straight text on clipboard 
1090     if ( !::OpenClipboard(GetHwndOf(wxTheApp
->GetTopWindow())) ) 
1093     bool isTextAvailable 
= ::IsClipboardFormatAvailable(CF_TEXT
) != 0; 
1096     return isTextAvailable
; 
1099 // ---------------------------------------------------------------------------- 
1101 // ---------------------------------------------------------------------------- 
1103 void wxTextCtrl::SetEditable(bool editable
) 
1105     HWND hWnd 
= GetHwnd(); 
1106     ::SendMessage(hWnd
, EM_SETREADONLY
, (WPARAM
)!editable
, (LPARAM
)0L); 
1109 void wxTextCtrl::SetInsertionPoint(long pos
) 
1111     DoSetSelection(pos
, pos
); 
1114 void wxTextCtrl::SetInsertionPointEnd() 
1116     // we must not do anything if the caret is already there because calling 
1117     // SetInsertionPoint() thaws the controls if Freeze() had been called even 
1118     // if it doesn't actually move the caret anywhere and so the simple fact of 
1119     // doing it results in horrible flicker when appending big amounts of text 
1120     // to the control in a few chunks (see DoAddText() test in the text sample) 
1121     if ( GetInsertionPoint() == GetLastPosition() ) 
1129     if ( m_verRichEdit 
== 1 ) 
1131         // we don't have to waste time calling GetLastPosition() in this case 
1134     else // !RichEdit 1.0 
1135 #endif // wxUSE_RICHEDIT 
1137         pos 
= GetLastPosition(); 
1140     SetInsertionPoint(pos
); 
1143 long wxTextCtrl::GetInsertionPoint() const 
1151         ::SendMessage(GetHwnd(), EM_EXGETSEL
, 0, (LPARAM
) &range
); 
1154 #endif // wxUSE_RICHEDIT 
1156     DWORD Pos 
= (DWORD
)::SendMessage(GetHwnd(), EM_GETSEL
, 0, 0L); 
1157     return Pos 
& 0xFFFF; 
1160 wxTextPos 
wxTextCtrl::GetLastPosition() const 
1162     int numLines 
= GetNumberOfLines(); 
1163     long posStartLastLine 
= XYToPosition(0, numLines 
- 1); 
1165     long lenLastLine 
= GetLengthOfLineContainingPos(posStartLastLine
); 
1167     return posStartLastLine 
+ lenLastLine
; 
1170 // If the return values from and to are the same, there is no 
1172 void wxTextCtrl::GetSelection(long* from
, long* to
) const 
1177         CHARRANGE charRange
; 
1178         ::SendMessage(GetHwnd(), EM_EXGETSEL
, 0, (LPARAM
) &charRange
); 
1180         *from 
= charRange
.cpMin
; 
1181         *to 
= charRange
.cpMax
; 
1184 #endif // !wxUSE_RICHEDIT 
1186         DWORD dwStart
, dwEnd
; 
1187         ::SendMessage(GetHwnd(), EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwEnd
); 
1194 bool wxTextCtrl::IsEditable() const 
1196     // strangely enough, we may be called before the control is created: our 
1197     // own Create() calls MSWGetStyle() which calls AcceptsFocus() which calls 
1202     long style 
= ::GetWindowLong(GetHwnd(), GWL_STYLE
); 
1204     return (style 
& ES_READONLY
) == 0; 
1207 // ---------------------------------------------------------------------------- 
1209 // ---------------------------------------------------------------------------- 
1211 void wxTextCtrl::SetSelection(long from
, long to
) 
1213     // if from and to are both -1, it means (in wxWidgets) that all text should 
1214     // be selected - translate into Windows convention 
1215     if ( (from 
== -1) && (to 
== -1) ) 
1221     DoSetSelection(from
, to
); 
1224 void wxTextCtrl::DoSetSelection(long from
, long to
, bool scrollCaret
) 
1226     HWND hWnd 
= GetHwnd(); 
1234         ::SendMessage(hWnd
, EM_EXSETSEL
, 0, (LPARAM
) &range
); 
1237 #endif // wxUSE_RICHEDIT 
1239         ::SendMessage(hWnd
, EM_SETSEL
, (WPARAM
)from
, (LPARAM
)to
); 
1242     if ( scrollCaret 
&& !IsFrozen() ) 
1245         // richedit 3.0 (i.e. the version living in riched20.dll distributed 
1246         // with Windows 2000 and beyond) doesn't honour EM_SCROLLCARET when 
1247         // emulating richedit 2.0 unless the control has focus or ECO_NOHIDESEL 
1248         // option is set (but it does work ok in richedit 1.0 mode...) 
1250         // so to make it work we either need to give focus to it here which 
1251         // will probably create many problems (dummy focus events; window 
1252         // containing the text control being brought to foreground 
1253         // unexpectedly; ...) or to temporarily set ECO_NOHIDESEL which may 
1254         // create other problems too -- and in fact it does because if we turn 
1255         // on/off this style while appending the text to the control, the 
1256         // vertical scrollbar never appears in it even if we append tons of 
1257         // text and to work around this the only solution I found was to use 
1258         // ES_DISABLENOSCROLL 
1260         // this is very ugly but I don't see any other way to make this work 
1261         if ( GetRichVersion() > 1 ) 
1263             if ( !HasFlag(wxTE_NOHIDESEL
) ) 
1265                 ::SendMessage(GetHwnd(), EM_SETOPTIONS
, 
1266                               ECOOP_OR
, ECO_NOHIDESEL
); 
1268             //else: everything is already ok 
1270 #endif // wxUSE_RICHEDIT 
1272         ::SendMessage(hWnd
, EM_SCROLLCARET
, (WPARAM
)0, (LPARAM
)0); 
1275         // restore ECO_NOHIDESEL if we changed it 
1276         if ( GetRichVersion() > 1 && !HasFlag(wxTE_NOHIDESEL
) ) 
1278             ::SendMessage(GetHwnd(), EM_SETOPTIONS
, 
1279                           ECOOP_AND
, ~ECO_NOHIDESEL
); 
1281 #endif // wxUSE_RICHEDIT 
1285 // ---------------------------------------------------------------------------- 
1286 // Working with files 
1287 // ---------------------------------------------------------------------------- 
1289 bool wxTextCtrl::LoadFile(const wxString
& file
) 
1291     if ( wxTextCtrlBase::LoadFile(file
) ) 
1293         // update the size limit if needed 
1302 // ---------------------------------------------------------------------------- 
1304 // ---------------------------------------------------------------------------- 
1306 void wxTextCtrl::Replace(long from
, long to
, const wxString
& value
) 
1308     // Set selection and remove it 
1309     DoSetSelection(from
, to
, false /* don't scroll caret into view */); 
1311     DoWriteText(value
, true /* selection only */); 
1314 void wxTextCtrl::Remove(long from
, long to
) 
1316     Replace(from
, to
, wxEmptyString
); 
1319 bool wxTextCtrl::IsModified() const 
1321     return ::SendMessage(GetHwnd(), EM_GETMODIFY
, 0, 0) != 0; 
1324 void wxTextCtrl::MarkDirty() 
1326     ::SendMessage(GetHwnd(), EM_SETMODIFY
, TRUE
, 0L); 
1329 void wxTextCtrl::DiscardEdits() 
1331     ::SendMessage(GetHwnd(), EM_SETMODIFY
, FALSE
, 0L); 
1334 int wxTextCtrl::GetNumberOfLines() const 
1336     return (int)::SendMessage(GetHwnd(), EM_GETLINECOUNT
, (WPARAM
)0, (LPARAM
)0); 
1339 // ---------------------------------------------------------------------------- 
1340 // Positions <-> coords 
1341 // ---------------------------------------------------------------------------- 
1343 long wxTextCtrl::XYToPosition(long x
, long y
) const 
1345     // This gets the char index for the _beginning_ of this line 
1346     long charIndex 
= ::SendMessage(GetHwnd(), EM_LINEINDEX
, (WPARAM
)y
, (LPARAM
)0); 
1348     return charIndex 
+ x
; 
1351 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
1353     HWND hWnd 
= GetHwnd(); 
1355     // This gets the line number containing the character 
1360         lineNo 
= ::SendMessage(hWnd
, EM_EXLINEFROMCHAR
, 0, (LPARAM
)pos
); 
1363 #endif // wxUSE_RICHEDIT 
1365         lineNo 
= ::SendMessage(hWnd
, EM_LINEFROMCHAR
, (WPARAM
)pos
, 0); 
1374     // This gets the char index for the _beginning_ of this line 
1375     long charIndex 
= ::SendMessage(hWnd
, EM_LINEINDEX
, (WPARAM
)lineNo
, (LPARAM
)0); 
1376     if ( charIndex 
== -1 ) 
1381     // The X position must therefore be the different between pos and charIndex 
1383         *x 
= pos 
- charIndex
; 
1390 wxTextCtrlHitTestResult
 
1391 wxTextCtrl::HitTest(const wxPoint
& pt
, long *posOut
) const 
1393     // first get the position from Windows 
1400         // for rich edit controls the position is passed iva the struct fields 
1403         lParam 
= (LPARAM
)&ptl
; 
1406 #endif // wxUSE_RICHEDIT 
1408         // for the plain ones, we are limited to 16 bit positions which are 
1409         // combined in a single 32 bit value 
1410         lParam 
= MAKELPARAM(pt
.x
, pt
.y
); 
1413     LRESULT pos 
= ::SendMessage(GetHwnd(), EM_CHARFROMPOS
, 0, lParam
); 
1417         // this seems to indicate an error... 
1418         return wxTE_HT_UNKNOWN
; 
1423 #endif // wxUSE_RICHEDIT 
1425         // for plain EDIT controls the higher word contains something else 
1430     // next determine where it is relatively to our point: EM_CHARFROMPOS 
1431     // always returns the closest character but we need to be more precise, so 
1432     // double check that we really are where it pretends 
1436     // FIXME: we need to distinguish between richedit 2 and 3 here somehow but 
1437     //        we don't know how to do it 
1440         ::SendMessage(GetHwnd(), EM_POSFROMCHAR
, (WPARAM
)&ptReal
, pos
); 
1443 #endif // wxUSE_RICHEDIT 
1445         LRESULT lRc 
= ::SendMessage(GetHwnd(), EM_POSFROMCHAR
, pos
, 0); 
1449             // this is apparently returned when pos corresponds to the last 
1456             ptReal
.x 
= LOWORD(lRc
); 
1457             ptReal
.y 
= HIWORD(lRc
); 
1461     wxTextCtrlHitTestResult rc
; 
1463     if ( pt
.y 
> ptReal
.y 
+ GetCharHeight() ) 
1465     else if ( pt
.x 
> ptReal
.x 
+ GetCharWidth() ) 
1466         rc 
= wxTE_HT_BEYOND
; 
1468         rc 
= wxTE_HT_ON_TEXT
; 
1476 // ---------------------------------------------------------------------------- 
1478 // ---------------------------------------------------------------------------- 
1480 void wxTextCtrl::ShowPosition(long pos
) 
1482     HWND hWnd 
= GetHwnd(); 
1484     // To scroll to a position, we pass the number of lines and characters 
1485     // to scroll *by*. This means that we need to: 
1486     // (1) Find the line position of the current line. 
1487     // (2) Find the line position of pos. 
1488     // (3) Scroll by (pos - current). 
1489     // For now, ignore the horizontal scrolling. 
1491     // Is this where scrolling is relative to - the line containing the caret? 
1492     // Or is the first visible line??? Try first visible line. 
1493 //    int currentLineLineNo1 = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)-1, (LPARAM)0L); 
1495     int currentLineLineNo 
= (int)::SendMessage(hWnd
, EM_GETFIRSTVISIBLELINE
, (WPARAM
)0, (LPARAM
)0L); 
1497     int specifiedLineLineNo 
= (int)::SendMessage(hWnd
, EM_LINEFROMCHAR
, (WPARAM
)pos
, (LPARAM
)0L); 
1499     int linesToScroll 
= specifiedLineLineNo 
- currentLineLineNo
; 
1501     if (linesToScroll 
!= 0) 
1502       (void)::SendMessage(hWnd
, EM_LINESCROLL
, (WPARAM
)0, (LPARAM
)linesToScroll
); 
1505 long wxTextCtrl::GetLengthOfLineContainingPos(long pos
) const 
1507     return ::SendMessage(GetHwnd(), EM_LINELENGTH
, (WPARAM
)pos
, 0); 
1510 int wxTextCtrl::GetLineLength(long lineNo
) const 
1512     long pos 
= XYToPosition(0, lineNo
); 
1514     return GetLengthOfLineContainingPos(pos
); 
1517 wxString 
wxTextCtrl::GetLineText(long lineNo
) const 
1519     size_t len 
= (size_t)GetLineLength(lineNo
) + 1; 
1521     // there must be at least enough place for the length WORD in the 
1523     len 
+= sizeof(WORD
); 
1527         wxStringBufferLength 
tmp(str
, len
); 
1530         *(WORD 
*)buf 
= (WORD
)len
; 
1531         len 
= (size_t)::SendMessage(GetHwnd(), EM_GETLINE
, lineNo
, (LPARAM
)buf
); 
1536             // remove the '\r' returned by the rich edit control, the user code 
1537             // should never see it 
1538             if ( buf
[len 
- 2] == _T('\r') && buf
[len 
- 1] == _T('\n') ) 
1540                 buf
[len 
- 2] = _T('\n'); 
1544 #endif // wxUSE_RICHEDIT 
1546         // remove the '\n' at the end, if any (this is how this function is 
1547         // supposed to work according to the docs) 
1548         if ( buf
[len 
- 1] == _T('\n') ) 
1560 void wxTextCtrl::SetMaxLength(unsigned long len
) 
1564         ::SendMessage(GetHwnd(), EM_EXLIMITTEXT
, 0, (LPARAM
) (DWORD
) len
); 
1567     ::SendMessage(GetHwnd(), EM_LIMITTEXT
, len
, 0); 
1570 // ---------------------------------------------------------------------------- 
1572 // ---------------------------------------------------------------------------- 
1574 void wxTextCtrl::Undo() 
1578         ::SendMessage(GetHwnd(), EM_UNDO
, 0, 0); 
1582 void wxTextCtrl::Redo() 
1587         if (GetRichVersion() > 1) 
1588             ::SendMessage(GetHwnd(), EM_REDO
, 0, 0); 
1591         // Same as Undo, since Undo undoes the undo, i.e. a redo. 
1592         ::SendMessage(GetHwnd(), EM_UNDO
, 0, 0); 
1596 bool wxTextCtrl::CanUndo() const 
1598     return ::SendMessage(GetHwnd(), EM_CANUNDO
, 0, 0) != 0; 
1601 bool wxTextCtrl::CanRedo() const 
1604     if (GetRichVersion() > 1) 
1605         return ::SendMessage(GetHwnd(), EM_CANREDO
, 0, 0) != 0; 
1608     return ::SendMessage(GetHwnd(), EM_CANUNDO
, 0, 0) != 0; 
1611 // ---------------------------------------------------------------------------- 
1612 // caret handling (Windows only) 
1613 // ---------------------------------------------------------------------------- 
1615 bool wxTextCtrl::ShowNativeCaret(bool show
) 
1617     if ( show 
!= m_isNativeCaretShown 
) 
1619         if ( !(show 
? ::ShowCaret(GetHwnd()) : ::HideCaret(GetHwnd())) ) 
1621             // not an error, may simply indicate that it's not shown/hidden 
1622             // yet (i.e. it had been hidden/showh 2 times before) 
1626         m_isNativeCaretShown 
= show
; 
1632 // ---------------------------------------------------------------------------- 
1633 // implemenation details 
1634 // ---------------------------------------------------------------------------- 
1636 void wxTextCtrl::Command(wxCommandEvent 
& event
) 
1638     SetValue(event
.GetString()); 
1639     ProcessCommand (event
); 
1642 void wxTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
1644     // By default, load the first file into the text window. 
1645     if (event
.GetNumberOfFiles() > 0) 
1647         LoadFile(event
.GetFiles()[0]); 
1651 // ---------------------------------------------------------------------------- 
1652 // kbd input processing 
1653 // ---------------------------------------------------------------------------- 
1655 bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG
* pMsg
) 
1657     MSG 
*msg 
= (MSG 
*)pMsg
; 
1659     // check for our special keys here: if we don't do it and the parent frame 
1660     // uses them as accelerators, they wouldn't work at all, so we disable 
1661     // usual preprocessing for them 
1662     if ( msg
->message 
== WM_KEYDOWN 
) 
1664         WORD vkey 
= (WORD
) msg
->wParam
; 
1665         if ( (HIWORD(msg
->lParam
) & KF_ALTDOWN
) == KF_ALTDOWN 
) 
1667             if ( vkey 
== VK_BACK 
) 
1672             // we want to process some Ctrl-foo and Shift-bar but no key 
1673             // combinations without either Ctrl or Shift nor with both of them 
1675             const int ctrl 
= wxIsCtrlDown(), 
1676                       shift 
= wxIsShiftDown(); 
1677             switch ( ctrl 
+ shift 
) 
1680                     wxFAIL_MSG( _T("how many modifiers have we got?") ); 
1688                     // either Ctrl or Shift pressed 
1703                     else // Shift is pressed 
1705                         if ( vkey 
== VK_INSERT 
|| vkey 
== VK_DELETE 
) 
1712     return wxControl::MSWShouldPreProcessMessage(pMsg
); 
1715 void wxTextCtrl::OnChar(wxKeyEvent
& event
) 
1717     switch ( event
.GetKeyCode() ) 
1720             if ( !HasFlag(wxTE_MULTILINE
) ) 
1722                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
); 
1723                 InitCommandEvent(event
); 
1724                 event
.SetString(GetValue()); 
1725                 if ( GetEventHandler()->ProcessEvent(event
) ) 
1728             //else: multiline controls need Enter for themselves 
1733             // ok, so this is getting absolutely ridiculous but I don't see 
1734             // any other way to fix this bug: when a multiline text control is 
1735             // inside a wxFrame, we need to generate the navigation event as 
1736             // otherwise nothing happens at all, but when the same control is 
1737             // created inside a dialog, IsDialogMessage() *does* switch focus 
1738             // all by itself and so if we do it here as well, it is advanced 
1739             // twice and goes to the next control... to prevent this from 
1740             // happening we're doing this ugly check, the logic being that if 
1741             // we don't have focus then it had been already changed to the next 
1744             // the right thing to do would, of course, be to understand what 
1745             // the hell is IsDialogMessage() doing but this is beyond my feeble 
1746             // forces at the moment unfortunately 
1747             if ( !(m_windowStyle 
& wxTE_PROCESS_TAB
)) 
1749                 if ( FindFocus() == this ) 
1752                     if (!event
.ShiftDown()) 
1753                         flags 
|= wxNavigationKeyEvent::IsForward 
; 
1754                     if (event
.ControlDown()) 
1755                         flags 
|= wxNavigationKeyEvent::WinChange 
; 
1756                     if (Navigate(flags
)) 
1762                 // Insert tab since calling the default Windows handler 
1763                 // doesn't seem to do it 
1764                 WriteText(wxT("\t")); 
1769     // no, we didn't process it 
1773 WXLRESULT 
wxTextCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
1775     WXLRESULT lRc 
= wxTextCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
1777     if ( nMsg 
== WM_GETDLGCODE 
) 
1779         // we always want the chars and the arrows: the arrows for navigation 
1780         // and the chars because we want Ctrl-C to work even in a read only 
1782         long lDlgCode 
= DLGC_WANTCHARS 
| DLGC_WANTARROWS
; 
1786             // we may have several different cases: 
1787             // 1. normal case: both TAB and ENTER are used for dlg navigation 
1788             // 2. ctrl which wants TAB for itself: ENTER is used to pass to the 
1789             //    next control in the dialog 
1790             // 3. ctrl which wants ENTER for itself: TAB is used for dialog 
1792             // 4. ctrl which wants both TAB and ENTER: Ctrl-ENTER is used to go 
1793             //    to the next control 
1795             // the multiline edit control should always get <Return> for itself 
1796             if ( HasFlag(wxTE_PROCESS_ENTER
) || HasFlag(wxTE_MULTILINE
) ) 
1797                 lDlgCode 
|= DLGC_WANTMESSAGE
; 
1799             if ( HasFlag(wxTE_PROCESS_TAB
) ) 
1800                 lDlgCode 
|= DLGC_WANTTAB
; 
1806             // NB: use "=", not "|=" as the base class version returns the 
1807             //     same flags is this state as usual (i.e. including 
1808             //     DLGC_WANTMESSAGE). This is strange (how does it work in the 
1809             //     native Win32 apps?) but for now live with it. 
1817 // ---------------------------------------------------------------------------- 
1818 // text control event processing 
1819 // ---------------------------------------------------------------------------- 
1821 bool wxTextCtrl::SendUpdateEvent() 
1823     switch ( m_updatesCount 
) 
1826             // remember that we've got an update 
1831             // we had already sent one event since the last control modification 
1835             wxFAIL_MSG( _T("unexpected wxTextCtrl::m_updatesCount value") ); 
1839             // we hadn't updated the control ourselves, this event comes from 
1840             // the user, don't need to ignore it nor update the count 
1844     wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, GetId()); 
1845     InitCommandEvent(event
); 
1847     return ProcessCommand(event
); 
1850 bool wxTextCtrl::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
1857                 wxFocusEvent 
event(param 
== EN_KILLFOCUS 
? wxEVT_KILL_FOCUS
 
1860                 event
.SetEventObject(this); 
1861                 GetEventHandler()->ProcessEvent(event
); 
1870             // the text size limit has been hit -- try to increase it 
1871             if ( !AdjustSpaceLimit() ) 
1873                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_MAXLEN
, m_windowId
); 
1874                 InitCommandEvent(event
); 
1875                 event
.SetString(GetValue()); 
1876                 ProcessCommand(event
); 
1880             // the other edit notification messages are not processed 
1889 WXHBRUSH 
wxTextCtrl::MSWControlColor(WXHDC hDC
, WXHWND hWnd
) 
1891     if ( !IsEnabled() && !HasFlag(wxTE_MULTILINE
) ) 
1892         return MSWControlColorDisabled(hDC
); 
1894     return wxTextCtrlBase::MSWControlColor(hDC
, hWnd
); 
1897 bool wxTextCtrl::AdjustSpaceLimit() 
1899     unsigned int limit 
= ::SendMessage(GetHwnd(), EM_GETLIMITTEXT
, 0, 0); 
1901     // HACK: we try to automatically extend the limit for the amount of text 
1902     //       to allow (interactively) entering more than 64Kb of text under 
1903     //       Win9x but we shouldn't reset the text limit which was previously 
1904     //       set explicitly with SetMaxLength() 
1906     //       we could solve this by storing the limit we set in wxTextCtrl but 
1907     //       to save space we prefer to simply test here the actual limit 
1908     //       value: we consider that SetMaxLength() can only be called for 
1910     if ( limit 
< 0x8000 ) 
1912         // we've got more text than limit set by SetMaxLength() 
1916     unsigned int len 
= ::GetWindowTextLength(GetHwnd()); 
1919         limit 
= len 
+ 0x8000;    // 32Kb 
1924             // as a nice side effect, this also allows passing limit > 64Kb 
1925             ::SendMessage(GetHwnd(), EM_EXLIMITTEXT
, 0, limit
); 
1928 #endif // wxUSE_RICHEDIT 
1930             if ( limit 
> 0xffff ) 
1932                 // this will set it to a platform-dependent maximum (much more 
1933                 // than 64Kb under NT) 
1937             ::SendMessage(GetHwnd(), EM_LIMITTEXT
, limit
, 0); 
1941     // we changed the limit 
1945 bool wxTextCtrl::AcceptsFocus() const 
1947     // we don't want focus if we can't be edited unless we're a multiline 
1948     // control because then it might be still nice to get focus from keyboard 
1949     // to be able to scroll it without mouse 
1950     return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus(); 
1953 wxSize 
wxTextCtrl::DoGetBestSize() const 
1956     wxGetCharSize(GetHWND(), &cx
, &cy
, GetFont()); 
1958     int wText 
= DEFAULT_ITEM_WIDTH
; 
1961     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1963         hText 
*= wxMax(wxMin(GetNumberOfLines(), 10), 2);  
1965     //else: for single line control everything is ok 
1967     // we have to add the adjustments for the control height only once, not 
1968     // once per line, so do it after multiplication above 
1969     hText 
+= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
) - cy
; 
1971     return wxSize(wText
, hText
); 
1974 // ---------------------------------------------------------------------------- 
1975 // standard handlers for standard edit menu events 
1976 // ---------------------------------------------------------------------------- 
1978 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
1983 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
1988 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
1993 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
1998 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
2003 void wxTextCtrl::OnDelete(wxCommandEvent
& WXUNUSED(event
)) 
2006     GetSelection(& from
, & to
); 
2007     if (from 
!= -1 && to 
!= -1) 
2011 void wxTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
2013     SetSelection(-1, -1); 
2016 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
2018     event
.Enable( CanCut() ); 
2021 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
2023     event
.Enable( CanCopy() ); 
2026 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
2028     event
.Enable( CanPaste() ); 
2031 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
2033     event
.Enable( CanUndo() ); 
2036 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
2038     event
.Enable( CanRedo() ); 
2041 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent
& event
) 
2044     GetSelection(& from
, & to
); 
2045     event
.Enable(from 
!= -1 && to 
!= -1 && from 
!= to 
&& IsEditable()) ; 
2048 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
2050     event
.Enable(GetLastPosition() > 0); 
2053 void wxTextCtrl::OnContextMenu(wxContextMenuEvent
& event
) 
2058         if (!m_privateContextMenu
) 
2060             m_privateContextMenu 
= new wxMenu
; 
2061             m_privateContextMenu
->Append(wxID_UNDO
, _("&Undo")); 
2062             m_privateContextMenu
->Append(wxID_REDO
, _("&Redo")); 
2063             m_privateContextMenu
->AppendSeparator(); 
2064             m_privateContextMenu
->Append(wxID_CUT
, _("Cu&t")); 
2065             m_privateContextMenu
->Append(wxID_COPY
, _("&Copy")); 
2066             m_privateContextMenu
->Append(wxID_PASTE
, _("&Paste")); 
2067             m_privateContextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
2068             m_privateContextMenu
->AppendSeparator(); 
2069             m_privateContextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
2071         PopupMenu(m_privateContextMenu
); 
2079 void wxTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
2081     // be sure the caret remains invisible if the user had hidden it 
2082     if ( !m_isNativeCaretShown 
) 
2084         ::HideCaret(GetHwnd()); 
2088 // ---------------------------------------------------------------------------- 
2089 // Default colors for MSW text control 
2091 // Set default background color to the native white instead of 
2092 // the default wxSYS_COLOUR_BTNFACE (is triggered with wxNullColour). 
2093 // ---------------------------------------------------------------------------- 
2095 wxVisualAttributes 
wxTextCtrl::GetDefaultAttributes() const 
2097     wxVisualAttributes attrs
; 
2098     attrs
.font 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
2099     attrs
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
2100     attrs
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
); //white 
2105 // the rest of the file only deals with the rich edit controls 
2108 // ---------------------------------------------------------------------------- 
2109 // EN_LINK processing 
2110 // ---------------------------------------------------------------------------- 
2112 bool wxTextCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
) 
2114     NMHDR 
*hdr 
= (NMHDR
* )lParam
; 
2115     switch ( hdr
->code 
) 
2119                 const MSGFILTER 
*msgf 
= (MSGFILTER 
*)lParam
; 
2120                 UINT msg 
= msgf
->msg
; 
2122                 // this is a bit crazy but richedit 1.0 sends us all mouse 
2123                 // events _except_ WM_LBUTTONUP (don't ask me why) so we have 
2124                 // generate the wxWin events for this message manually 
2126                 // NB: in fact, this is still not totally correct as it does 
2127                 //     send us WM_LBUTTONUP if the selection was cleared by the 
2128                 //     last click -- so currently we get 2 events in this case, 
2129                 //     but as I don't see any obvious way to check for this I 
2130                 //     leave this code in place because it's still better than 
2131                 //     not getting left up events at all 
2132                 if ( msg 
== WM_LBUTTONUP 
) 
2134                     WXUINT flags 
= msgf
->wParam
; 
2135                     int x 
= GET_X_LPARAM(msgf
->lParam
), 
2136                         y 
= GET_Y_LPARAM(msgf
->lParam
); 
2138                     HandleMouseEvent(msg
, x
, y
, flags
); 
2142             // return true to process the event (and false to ignore it) 
2147                 const ENLINK 
*enlink 
= (ENLINK 
*)hdr
; 
2149                 switch ( enlink
->msg 
) 
2152                         // ok, so it is hardcoded - do we really nee to 
2155                             wxCursor 
cur(wxCURSOR_HAND
); 
2156                             ::SetCursor(GetHcursorOf(cur
)); 
2162                     case WM_LBUTTONDOWN
: 
2164                     case WM_LBUTTONDBLCLK
: 
2165                     case WM_RBUTTONDOWN
: 
2167                     case WM_RBUTTONDBLCLK
: 
2168                         // send a mouse event 
2170                             static const wxEventType eventsMouse
[] = 
2181                             // the event ids are consecutive 
2183                                 evtMouse(eventsMouse
[enlink
->msg 
- WM_MOUSEMOVE
]); 
2185                             InitMouseEvent(evtMouse
, 
2186                                            GET_X_LPARAM(enlink
->lParam
), 
2187                                            GET_Y_LPARAM(enlink
->lParam
), 
2190                             wxTextUrlEvent 
event(m_windowId
, evtMouse
, 
2192                                                  enlink
->chrg
.cpMax
); 
2194                             InitCommandEvent(event
); 
2196                             *result 
= ProcessCommand(event
); 
2204     // not processed, leave it to the base class 
2205     return wxTextCtrlBase::MSWOnNotify(idCtrl
, lParam
, result
); 
2208 // ---------------------------------------------------------------------------- 
2209 // colour setting for the rich edit controls 
2210 // ---------------------------------------------------------------------------- 
2212 bool wxTextCtrl::SetBackgroundColour(const wxColour
& colour
) 
2214     if ( !wxTextCtrlBase::SetBackgroundColour(colour
) ) 
2216         // colour didn't really change 
2222         // rich edit doesn't use WM_CTLCOLOR, hence we need to send 
2223         // EM_SETBKGNDCOLOR additionally 
2224         ::SendMessage(GetHwnd(), EM_SETBKGNDCOLOR
, 0, wxColourToRGB(colour
)); 
2230 bool wxTextCtrl::SetForegroundColour(const wxColour
& colour
) 
2232     if ( !wxTextCtrlBase::SetForegroundColour(colour
) ) 
2234         // colour didn't really change 
2240         // change the colour of everything 
2243         cf
.cbSize 
= sizeof(cf
); 
2244         cf
.dwMask 
= CFM_COLOR
; 
2245         cf
.crTextColor 
= wxColourToRGB(colour
); 
2246         ::SendMessage(GetHwnd(), EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf
); 
2252 // ---------------------------------------------------------------------------- 
2253 // styling support for rich edit controls 
2254 // ---------------------------------------------------------------------------- 
2258 bool wxTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
2262         // can't do it with normal text control 
2266     // the richedit 1.0 doesn't handle setting background colour, so don't 
2267     // even try to do anything if it's the only thing we want to change 
2268     if ( m_verRichEdit 
== 1 && !style
.HasFont() && !style
.HasTextColour() && 
2269         !style
.HasLeftIndent() && !style
.HasRightIndent() && !style
.HasAlignment() && 
2272         // nothing to do: return true if there was really nothing to do and 
2273         // false if we failed to set bg colour 
2274         return !style
.HasBackgroundColour(); 
2277     // order the range if needed 
2285     // we can only change the format of the selection, so select the range we 
2286     // want and restore the old selection later 
2287     long startOld
, endOld
; 
2288     GetSelection(&startOld
, &endOld
); 
2290     // but do we really have to change the selection? 
2291     bool changeSel 
= start 
!= startOld 
|| end 
!= endOld
; 
2295         DoSetSelection(start
, end
, false /* don't scroll caret into view */); 
2298     // initialize CHARFORMAT struct 
2307     // we can't use CHARFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2308     // CHARFORMAT in that case 
2310     if ( m_verRichEdit 
== 1 ) 
2312         // this is the only thing the control is going to grok 
2313         cf
.cbSize 
= sizeof(CHARFORMAT
); 
2318         // CHARFORMAT or CHARFORMAT2 
2319         cf
.cbSize 
= sizeof(cf
); 
2322     if ( style
.HasFont() ) 
2324         // VZ: CFM_CHARSET doesn't seem to do anything at all in RichEdit 2.0 
2325         //     but using it doesn't seem to hurt neither so leaving it for now 
2327         cf
.dwMask 
|= CFM_FACE 
| CFM_SIZE 
| CFM_CHARSET 
| 
2328                      CFM_ITALIC 
| CFM_BOLD 
| CFM_UNDERLINE
; 
2330         // fill in data from LOGFONT but recalculate lfHeight because we need 
2331         // the real height in twips and not the negative number which 
2332         // wxFillLogFont() returns (this is correct in general and works with 
2333         // the Windows font mapper, but not here) 
2335         wxFillLogFont(&lf
, &style
.GetFont()); 
2336         cf
.yHeight 
= 20*style
.GetFont().GetPointSize(); // 1 pt = 20 twips 
2337         cf
.bCharSet 
= lf
.lfCharSet
; 
2338         cf
.bPitchAndFamily 
= lf
.lfPitchAndFamily
; 
2339         wxStrncpy( cf
.szFaceName
, lf
.lfFaceName
, WXSIZEOF(cf
.szFaceName
) ); 
2341         // also deal with underline/italic/bold attributes: note that we must 
2342         // always set CFM_ITALIC &c bits in dwMask, even if we don't set the 
2343         // style to allow clearing it 
2346             cf
.dwEffects 
|= CFE_ITALIC
; 
2349         if ( lf
.lfWeight 
== FW_BOLD 
) 
2351             cf
.dwEffects 
|= CFE_BOLD
; 
2354         if ( lf
.lfUnderline 
) 
2356             cf
.dwEffects 
|= CFE_UNDERLINE
; 
2359         // strikeout fonts are not supported by wxWidgets 
2362     if ( style
.HasTextColour() ) 
2364         cf
.dwMask 
|= CFM_COLOR
; 
2365         cf
.crTextColor 
= wxColourToRGB(style
.GetTextColour()); 
2369     if ( m_verRichEdit 
!= 1 && style
.HasBackgroundColour() ) 
2371         cf
.dwMask 
|= CFM_BACKCOLOR
; 
2372         cf
.crBackColor 
= wxColourToRGB(style
.GetBackgroundColour()); 
2374 #endif // wxUSE_RICHEDIT2 
2376     // do format the selection 
2377     bool ok 
= ::SendMessage(GetHwnd(), EM_SETCHARFORMAT
, 
2378                             SCF_SELECTION
, (LPARAM
)&cf
) != 0; 
2381         wxLogDebug(_T("SendMessage(EM_SETCHARFORMAT, SCF_SELECTION) failed")); 
2384     // now do the paragraph formatting 
2387     // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2388     // PARAFORMAT in that case 
2390     if ( m_verRichEdit 
== 1 ) 
2392         // this is the only thing the control is going to grok 
2393         pf
.cbSize 
= sizeof(PARAFORMAT
); 
2398         // PARAFORMAT or PARAFORMAT2 
2399         pf
.cbSize 
= sizeof(pf
); 
2402     if (style
.HasAlignment()) 
2404         pf
.dwMask 
|= PFM_ALIGNMENT
; 
2405         if (style
.GetAlignment() == wxTEXT_ALIGNMENT_RIGHT
) 
2406             pf
.wAlignment 
= PFA_RIGHT
; 
2407         else if (style
.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
) 
2408             pf
.wAlignment 
= PFA_CENTER
; 
2409         else if (style
.GetAlignment() == wxTEXT_ALIGNMENT_JUSTIFIED
) 
2410             pf
.wAlignment 
= PFA_JUSTIFY
; 
2412             pf
.wAlignment 
= PFA_LEFT
; 
2415     if (style
.HasLeftIndent()) 
2417         pf
.dwMask 
|= PFM_STARTINDENT 
| PFM_OFFSET
; 
2419         // Convert from 1/10 mm to TWIPS 
2420         pf
.dxStartIndent 
= (int) (((double) style
.GetLeftIndent()) * mm2twips 
/ 10.0) ; 
2421         pf
.dxOffset 
= (int) (((double) style
.GetLeftSubIndent()) * mm2twips 
/ 10.0) ; 
2424     if (style
.HasRightIndent()) 
2426         pf
.dwMask 
|= PFM_RIGHTINDENT
; 
2428         // Convert from 1/10 mm to TWIPS 
2429         pf
.dxRightIndent 
= (int) (((double) style
.GetRightIndent()) * mm2twips 
/ 10.0) ; 
2432     if (style
.HasTabs()) 
2434         pf
.dwMask 
|= PFM_TABSTOPS
; 
2436         const wxArrayInt
& tabs 
= style
.GetTabs(); 
2438         pf
.cTabCount 
= (SHORT
)wxMin(tabs
.GetCount(), MAX_TAB_STOPS
); 
2440         for (i 
= 0; i 
< (size_t) pf
.cTabCount
; i
++) 
2442             // Convert from 1/10 mm to TWIPS 
2443             pf
.rgxTabs
[i
] = (int) (((double) tabs
[i
]) * mm2twips 
/ 10.0) ; 
2449         // do format the selection 
2450         bool ok 
= ::SendMessage(GetHwnd(), EM_SETPARAFORMAT
, 
2451             0, (LPARAM
) &pf
) != 0; 
2454             wxLogDebug(_T("SendMessage(EM_SETPARAFORMAT, 0) failed")); 
2460         // restore the original selection 
2461         DoSetSelection(startOld
, endOld
, false); 
2467 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
2469     if ( !wxTextCtrlBase::SetDefaultStyle(style
) ) 
2474         // we have to do this or the style wouldn't apply for the text typed by 
2476         wxTextPos posLast 
= GetLastPosition(); 
2477         SetStyle(posLast
, posLast
, m_defaultStyle
); 
2483 bool wxTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
2487         // can't do it with normal text control 
2491     // initialize CHARFORMAT struct 
2500     // we can't use CHARFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2501     // CHARFORMAT in that case 
2503     if ( m_verRichEdit 
== 1 ) 
2505         // this is the only thing the control is going to grok 
2506         cf
.cbSize 
= sizeof(CHARFORMAT
); 
2511         // CHARFORMAT or CHARFORMAT2 
2512         cf
.cbSize 
= sizeof(cf
); 
2514     // we can only change the format of the selection, so select the range we 
2515     // want and restore the old selection later 
2516     long startOld
, endOld
; 
2517     GetSelection(&startOld
, &endOld
); 
2519     // but do we really have to change the selection? 
2520     bool changeSel 
= position 
!= startOld 
|| position 
!= endOld
; 
2524         DoSetSelection(position
, position
, false /* don't scroll caret into view */); 
2527     // get the selection formatting 
2528     (void) ::SendMessage(GetHwnd(), EM_GETCHARFORMAT
, 
2529                             SCF_SELECTION
, (LPARAM
)&cf
) ; 
2533     lf
.lfHeight 
= cf
.yHeight
; 
2535     lf
.lfCharSet 
= ANSI_CHARSET
; // FIXME: how to get correct charset? 
2536     lf
.lfClipPrecision 
= 0; 
2537     lf
.lfEscapement 
= 0; 
2538     wxStrcpy(lf
.lfFaceName
, cf
.szFaceName
); 
2540     //NOTE:  we _MUST_ set each of these values to _something_ since we 
2541     //do not call wxZeroMemory on the LOGFONT lf 
2542     if (cf
.dwEffects 
& CFE_ITALIC
) 
2545         lf
.lfItalic 
= FALSE
; 
2547     lf
.lfOrientation 
= 0; 
2548     lf
.lfPitchAndFamily 
= cf
.bPitchAndFamily
; 
2551     if (cf
.dwEffects 
& CFE_STRIKEOUT
) 
2552         lf
.lfStrikeOut 
= TRUE
; 
2554         lf
.lfStrikeOut 
= FALSE
; 
2556     if (cf
.dwEffects 
& CFE_UNDERLINE
) 
2557         lf
.lfUnderline 
= TRUE
; 
2559         lf
.lfUnderline 
= FALSE
; 
2561     if (cf
.dwEffects 
& CFE_BOLD
) 
2562         lf
.lfWeight 
= FW_BOLD
; 
2564         lf
.lfWeight 
= FW_NORMAL
; 
2566     wxFont font 
= wxCreateFontFromLogFont(& lf
); 
2569         style
.SetFont(font
); 
2571     style
.SetTextColour(wxColour(cf
.crTextColor
)); 
2574     if ( m_verRichEdit 
!= 1 ) 
2576         // cf.dwMask |= CFM_BACKCOLOR; 
2577         style
.SetBackgroundColour(wxColour(cf
.crBackColor
)); 
2579 #endif // wxUSE_RICHEDIT2 
2581     // now get the paragraph formatting 
2584     // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2585     // PARAFORMAT in that case 
2587     if ( m_verRichEdit 
== 1 ) 
2589         // this is the only thing the control is going to grok 
2590         pf
.cbSize 
= sizeof(PARAFORMAT
); 
2595         // PARAFORMAT or PARAFORMAT2 
2596         pf
.cbSize 
= sizeof(pf
); 
2599     // do format the selection 
2600     (void) ::SendMessage(GetHwnd(), EM_GETPARAFORMAT
, 0, (LPARAM
) &pf
) ; 
2602     style
.SetLeftIndent( (int) ((double) pf
.dxStartIndent 
* twips2mm 
* 10.0), (int) ((double) pf
.dxOffset 
* twips2mm 
* 10.0) ); 
2603     style
.SetRightIndent( (int) ((double) pf
.dxRightIndent 
* twips2mm 
* 10.0) ); 
2605     if (pf
.wAlignment 
== PFA_CENTER
) 
2606         style
.SetAlignment(wxTEXT_ALIGNMENT_CENTRE
); 
2607     else if (pf
.wAlignment 
== PFA_RIGHT
) 
2608         style
.SetAlignment(wxTEXT_ALIGNMENT_RIGHT
); 
2609     else if (pf
.wAlignment 
== PFA_JUSTIFY
) 
2610         style
.SetAlignment(wxTEXT_ALIGNMENT_JUSTIFIED
); 
2612         style
.SetAlignment(wxTEXT_ALIGNMENT_LEFT
); 
2614     wxArrayInt tabStops
; 
2616     for (i 
= 0; i 
< (size_t) pf
.cTabCount
; i
++) 
2618         tabStops
.Add( (int) ((double) (pf
.rgxTabs
[i
] & 0xFFFF) * twips2mm 
* 10.0) ); 
2623         // restore the original selection 
2624         DoSetSelection(startOld
, endOld
, false); 
2632 // ---------------------------------------------------------------------------- 
2634 // ---------------------------------------------------------------------------- 
2636 static const HINSTANCE INVALID_HINSTANCE 
= (HINSTANCE
)-1; 
2638 bool wxRichEditModule::OnInit() 
2640     // don't do anything - we will load it when needed 
2644 void wxRichEditModule::OnExit() 
2646     for ( size_t i 
= 0; i 
< WXSIZEOF(ms_hRichEdit
); i
++ ) 
2648         if ( ms_hRichEdit
[i
] && ms_hRichEdit
[i
] != INVALID_HINSTANCE 
) 
2650             ::FreeLibrary(ms_hRichEdit
[i
]); 
2651             ms_hRichEdit
[i
] = NULL
; 
2657 bool wxRichEditModule::Load(Version version
) 
2659     if ( ms_hRichEdit
[version
] == INVALID_HINSTANCE 
) 
2661         // we had already tried to load it and failed 
2665     if ( ms_hRichEdit
[version
] ) 
2667         // we've already got this one 
2671     static const wxChar 
*dllnames
[] = 
2678     wxCOMPILE_TIME_ASSERT( WXSIZEOF(dllnames
) == Version_Max
, 
2679                             RichEditDllNamesVersionsMismatch 
); 
2681     ms_hRichEdit
[version
] = ::LoadLibrary(dllnames
[version
]); 
2683     if ( !ms_hRichEdit
[version
] ) 
2685         ms_hRichEdit
[version
] = INVALID_HINSTANCE
; 
2693 #endif // wxUSE_RICHEDIT 
2695 #endif // wxUSE_TEXTCTRL && !(__SMARTPHONE__ && __WXWINCE__)