1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/textctrl.cpp 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #if wxUSE_TEXTCTRL && !(defined(__SMARTPHONE__) && defined(__WXWINCE__)) 
  30     #include "wx/textctrl.h" 
  31     #include "wx/settings.h" 
  39     #include "wx/module.h" 
  40     #include "wx/wxcrtvararg.h" 
  43 #include "wx/sysopt.h" 
  46     #include "wx/clipbrd.h" 
  49 #include "wx/textfile.h" 
  53 #include "wx/msw/private.h" 
  54 #include "wx/msw/winundef.h" 
  55 #include "wx/msw/mslu.h" 
  61 #include <sys/types.h> 
  67 #include "wx/dynlib.h" 
  70 // old mingw32 has richedit stuff directly in windows.h and doesn't have 
  72 #if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__) 
  76 #endif // wxUSE_RICHEDIT 
  78 #include "wx/msw/missing.h" 
  80 #if wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT 
  82 // dummy value used for m_dropTarget, different from any valid pointer value 
  83 // (which are all even under Windows) and NULL 
  85     wxRICHTEXT_DEFAULT_DROPTARGET 
= wx_reinterpret_cast(wxDropTarget 
*, 1); 
  87 #endif // wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT 
  89 // ---------------------------------------------------------------------------- 
  91 // ---------------------------------------------------------------------------- 
  95 // this module initializes RichEdit DLL(s) if needed 
  96 class wxRichEditModule 
: public wxModule
 
 101         Version_1
,          // riched32.dll 
 102         Version_2or3
,       // both use riched20.dll 
 103         Version_41
,         // msftedit.dll (XP SP1 and Windows 2003) 
 107     virtual bool OnInit(); 
 108     virtual void OnExit(); 
 110     // load the richedit DLL for the specified version of rich edit 
 111     static bool Load(Version version
); 
 114     // load the InkEdit library 
 115     static bool LoadInkEdit(); 
 119     // the handles to richedit 1.0 and 2.0 (or 3.0) DLLs 
 120     static HINSTANCE ms_hRichEdit
[Version_Max
]; 
 123     static wxDynamicLibrary ms_inkEditLib
; 
 124     static bool             ms_inkEditLibLoadAttemped
; 
 127     DECLARE_DYNAMIC_CLASS(wxRichEditModule
) 
 130 HINSTANCE 
wxRichEditModule::ms_hRichEdit
[Version_Max
] = { NULL
, NULL
, NULL 
}; 
 133 wxDynamicLibrary 
wxRichEditModule::ms_inkEditLib
; 
 134 bool             wxRichEditModule::ms_inkEditLibLoadAttemped 
= false; 
 137 IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule
, wxModule
) 
 139 #endif // wxUSE_RICHEDIT 
 141 // a small class used to set m_updatesCount to 0 (to filter duplicate events if 
 142 // necessary) and to reset it back to -1 afterwards 
 143 class UpdatesCountFilter
 
 146     UpdatesCountFilter(int& count
) 
 149         wxASSERT_MSG( m_count 
== -1 || m_count 
== -2, 
 150                       _T("wrong initial m_updatesCount value") ); 
 154         //else: we don't want to count how many update events we get as we're going 
 155         //      to ignore all of them 
 158     ~UpdatesCountFilter() 
 163     // return true if an event has been received 
 164     bool GotUpdate() const 
 172     DECLARE_NO_COPY_CLASS(UpdatesCountFilter
) 
 175 // ---------------------------------------------------------------------------- 
 176 // event tables and other macros 
 177 // ---------------------------------------------------------------------------- 
 179 #if wxUSE_EXTENDED_RTTI 
 180 WX_DEFINE_FLAGS( wxTextCtrlStyle 
) 
 182 wxBEGIN_FLAGS( wxTextCtrlStyle 
) 
 183     // new style border flags, we put them first to 
 184     // use them for streaming out 
 185     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
 186     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
 187     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
 188     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
 189     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
 190     wxFLAGS_MEMBER(wxBORDER_NONE
) 
 192     // old style border flags 
 193     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
 194     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
 195     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
 196     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
 197     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
 198     wxFLAGS_MEMBER(wxBORDER
) 
 200     // standard window styles 
 201     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
 202     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
 203     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
 204     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
 205     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
 206     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
 207     wxFLAGS_MEMBER(wxVSCROLL
) 
 208     wxFLAGS_MEMBER(wxHSCROLL
) 
 210     wxFLAGS_MEMBER(wxTE_PROCESS_ENTER
) 
 211     wxFLAGS_MEMBER(wxTE_PROCESS_TAB
) 
 212     wxFLAGS_MEMBER(wxTE_MULTILINE
) 
 213     wxFLAGS_MEMBER(wxTE_PASSWORD
) 
 214     wxFLAGS_MEMBER(wxTE_READONLY
) 
 215     wxFLAGS_MEMBER(wxHSCROLL
) 
 216     wxFLAGS_MEMBER(wxTE_RICH
) 
 217     wxFLAGS_MEMBER(wxTE_RICH2
) 
 218     wxFLAGS_MEMBER(wxTE_AUTO_URL
) 
 219     wxFLAGS_MEMBER(wxTE_NOHIDESEL
) 
 220     wxFLAGS_MEMBER(wxTE_LEFT
) 
 221     wxFLAGS_MEMBER(wxTE_CENTRE
) 
 222     wxFLAGS_MEMBER(wxTE_RIGHT
) 
 223     wxFLAGS_MEMBER(wxTE_DONTWRAP
) 
 224     wxFLAGS_MEMBER(wxTE_CHARWRAP
) 
 225     wxFLAGS_MEMBER(wxTE_WORDWRAP
) 
 227 wxEND_FLAGS( wxTextCtrlStyle 
) 
 229 IMPLEMENT_DYNAMIC_CLASS_XTI(wxTextCtrl
, wxControl
,"wx/textctrl.h") 
 231 wxBEGIN_PROPERTIES_TABLE(wxTextCtrl
) 
 232     wxEVENT_PROPERTY( TextUpdated 
, wxEVT_COMMAND_TEXT_UPDATED 
, wxCommandEvent 
) 
 233     wxEVENT_PROPERTY( TextEnter 
, wxEVT_COMMAND_TEXT_ENTER 
, wxCommandEvent 
) 
 235     wxPROPERTY( Font 
, wxFont 
, SetFont 
, GetFont  
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 236     wxPROPERTY( Value 
, wxString 
, SetValue
, GetValue
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 237     wxPROPERTY_FLAGS( WindowStyle 
, wxTextCtrlStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 238 wxEND_PROPERTIES_TABLE() 
 240 wxBEGIN_HANDLERS_TABLE(wxTextCtrl
) 
 241 wxEND_HANDLERS_TABLE() 
 243 wxCONSTRUCTOR_6( wxTextCtrl 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxString 
, Value 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle
) 
 245 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxTextCtrlBase
) 
 249 BEGIN_EVENT_TABLE(wxTextCtrl
, wxTextCtrlBase
) 
 250     EVT_CHAR(wxTextCtrl::OnChar
) 
 251     EVT_DROP_FILES(wxTextCtrl::OnDropFiles
) 
 254     EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu
) 
 257     EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
) 
 258     EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
) 
 259     EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
) 
 260     EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
) 
 261     EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
) 
 262     EVT_MENU(wxID_CLEAR
, wxTextCtrl::OnDelete
) 
 263     EVT_MENU(wxID_SELECTALL
, wxTextCtrl::OnSelectAll
) 
 265     EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
) 
 266     EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
) 
 267     EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
) 
 268     EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
) 
 269     EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
) 
 270     EVT_UPDATE_UI(wxID_CLEAR
, wxTextCtrl::OnUpdateDelete
) 
 271     EVT_UPDATE_UI(wxID_SELECTALL
, wxTextCtrl::OnUpdateSelectAll
) 
 273     EVT_SET_FOCUS(wxTextCtrl::OnSetFocus
) 
 276 // ============================================================================ 
 278 // ============================================================================ 
 280 // ---------------------------------------------------------------------------- 
 282 // ---------------------------------------------------------------------------- 
 284 void wxTextCtrl::Init() 
 288 #endif // wxUSE_RICHEDIT 
 290 #if wxUSE_INKEDIT && wxUSE_RICHEDIT 
 294     m_privateContextMenu 
= NULL
; 
 296     m_isNativeCaretShown 
= true; 
 299 wxTextCtrl::~wxTextCtrl() 
 301 #if wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT 
 302     if ( m_dropTarget 
== wxRICHTEXT_DEFAULT_DROPTARGET 
) 
 304         // don't try to destroy this dummy pointer in the base class dtor 
 307 #endif // wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT 
 309     delete m_privateContextMenu
; 
 312 bool wxTextCtrl::Create(wxWindow 
*parent
, 
 314                         const wxString
& value
, 
 318                         const wxValidator
& validator
, 
 319                         const wxString
& name
) 
 321     // base initialization 
 322     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 325     if ( !MSWCreateText(value
, pos
, size
) ) 
 328 #if wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT 
 331         // rich text controls have a default associated drop target which 
 332         // allows them to receive (rich) text dropped on them, which is nice, 
 333         // but prevents us from associating a user-defined drop target with 
 334         // them as we need to unregister the old one first 
 336         // to make it work, we set m_dropTarget to this special value initially 
 337         // and check for it in our SetDropTarget() 
 338         m_dropTarget 
= wxRICHTEXT_DEFAULT_DROPTARGET
; 
 340 #endif // wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT 
 345 // returns true if the platform should explicitly apply a theme border 
 346 bool wxTextCtrl::CanApplyThemeBorder() const 
 351     // Standard text control already handles theming 
 352     return ((GetWindowStyle() & (wxTE_RICH
|wxTE_RICH2
)) != 0); 
 356 bool wxTextCtrl::MSWCreateText(const wxString
& value
, 
 360     // translate wxWin style flags to MSW ones 
 361     WXDWORD msStyle 
= MSWGetCreateWindowFlags(); 
 363     // do create the control - either an EDIT or RICHEDIT 
 364     wxString windowClass 
= wxT("EDIT"); 
 366 #if defined(__POCKETPC__) || defined(__SMARTPHONE__) 
 367     // A control that capitalizes the first letter 
 368     if ( HasFlag(wxTE_CAPITALIZE
) ) 
 369         windowClass 
= wxT("CAPEDIT"); 
 373     if ( m_windowStyle 
& wxTE_AUTO_URL 
) 
 375         // automatic URL detection only works in RichEdit 2.0+ 
 376         m_windowStyle 
|= wxTE_RICH2
; 
 379     if ( m_windowStyle 
& wxTE_RICH2 
) 
 381         // using richedit 2.0 implies using wxTE_RICH 
 382         m_windowStyle 
|= wxTE_RICH
; 
 385     // we need to load the richedit DLL before creating the rich edit control 
 386     if ( m_windowStyle 
& wxTE_RICH 
) 
 388         // versions 2.0, 3.0 and 4.1 of rich edit are mostly compatible with 
 389         // each other but not with version 1.0, so we have separate flags for 
 390         // the version 1.0 and the others (and so m_verRichEdit may be 0 (plain 
 391         // EDIT control), 1 for version 1.0 or 2 for any higher version) 
 393         // notice that 1.0 has no Unicode support at all so in Unicode build we 
 394         // must use another version 
 398 #else // !wxUSE_UNICODE 
 399         m_verRichEdit 
= m_windowStyle 
& wxTE_RICH2 
? 2 : 1; 
 400 #endif // wxUSE_UNICODE/!wxUSE_UNICODE 
 403         // First test if we can load an ink edit control. Normally, all edit 
 404         // controls will be made ink edit controls if a tablet environment is 
 405         // found (or if msw.inkedit != 0 and the InkEd.dll is present). 
 406         // However, an application can veto ink edit controls by either specifying 
 407         // msw.inkedit = 0 or by removing wxTE_RICH[2] from the style. 
 409         if ((wxSystemSettings::HasFeature(wxSYS_TABLET_PRESENT
) || wxSystemOptions::GetOptionInt(wxT("msw.inkedit")) != 0) && 
 410             !(wxSystemOptions::HasOption(wxT("msw.inkedit")) && wxSystemOptions::GetOptionInt(wxT("msw.inkedit")) == 0)) 
 412             if (wxRichEditModule::LoadInkEdit()) 
 414                 windowClass 
= INKEDIT_CLASS
; 
 416 #if wxUSE_INKEDIT && wxUSE_RICHEDIT 
 420                 // Fake rich text version for other calls 
 428             if ( m_verRichEdit 
== 2 ) 
 430                 if ( wxRichEditModule::Load(wxRichEditModule::Version_41
) ) 
 432                     // yes, class name for version 4.1 really is 5.0 
 433                     windowClass 
= _T("RICHEDIT50W"); 
 435                 else if ( wxRichEditModule::Load(wxRichEditModule::Version_2or3
) ) 
 437                     windowClass 
= _T("RichEdit20") 
 442 #endif // Unicode/ANSI 
 444                 else // failed to load msftedit.dll and riched20.dll 
 450             if ( m_verRichEdit 
== 1 ) 
 452                 if ( wxRichEditModule::Load(wxRichEditModule::Version_1
) ) 
 454                     windowClass 
= _T("RICHEDIT"); 
 456                 else // failed to load any richedit control DLL 
 458                     // only give the error msg once if the DLL can't be loaded 
 459                     static bool s_errorGiven 
= false; // MT ok as only used by GUI 
 463                         wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll")); 
 473 #endif // wxUSE_RICHEDIT 
 475     // we need to turn '\n's into "\r\n"s for the multiline controls 
 477     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 479         valueWin 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 486     if ( !MSWCreateControl(windowClass
.wx_str(), msStyle
, pos
, size
, valueWin
) ) 
 495             // Pass IEM_InsertText (0) as wParam, in order to have the ink always 
 496             // converted to text. 
 497             ::SendMessage(GetHwnd(), EM_SETINKINSERTMODE
, 0, 0); 
 499             // Make sure the mouse can be used for input 
 500             ::SendMessage(GetHwnd(), EM_SETUSEMOUSEFORINPUT
, 1, 0); 
 504         // enable the events we're interested in: we want to get EN_CHANGE as 
 505         // for the normal controls 
 506         LPARAM mask 
= ENM_CHANGE
; 
 508         if (GetRichVersion() == 1 && !IsInkEdit()) 
 510             // we also need EN_MSGFILTER for richedit 1.0 for the reasons 
 511             // explained in its handler 
 512            mask 
|= ENM_MOUSEEVENTS
; 
 514            // we also need to force the appearance of the vertical scrollbar 
 515            // initially as otherwise the control doesn't refresh correctly 
 516            // after resize: but once the vertical scrollbar had been shown 
 517            // (even if it's subsequently hidden) it does 
 519            // this is clearly a bug and for now it has been only noticed under 
 520            // Windows XP, so if we're sure it works correctly under other 
 521            // systems we could do this only for XP 
 522            SetSize(-1, 1); // 1 is small enough to force vert scrollbar 
 523            SetInitialSize(size
); 
 525         else if ( m_windowStyle 
& wxTE_AUTO_URL 
) 
 529             ::SendMessage(GetHwnd(), EM_AUTOURLDETECT
, TRUE
, 0); 
 532         ::SendMessage(GetHwnd(), EM_SETEVENTMASK
, 0, mask
); 
 534 #endif // wxUSE_RICHEDIT 
 537     // Without this, if we pass the size in the constructor and then don't change it, 
 538     // the themed borders will be drawn incorrectly. 
 539     SetWindowPos(GetHwnd(), NULL
, 0, 0, 0, 0, 
 540                 SWP_NOZORDER
|SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOACTIVATE
| 
 547 // Make sure the window style (etc.) reflects the HWND style (roughly) 
 548 void wxTextCtrl::AdoptAttributesFromHWND() 
 550     wxWindow::AdoptAttributesFromHWND(); 
 552     HWND hWnd 
= GetHwnd(); 
 553     long style 
= ::GetWindowLong(hWnd
, GWL_STYLE
); 
 555     // retrieve the style to see whether this is an edit or richedit ctrl 
 557     wxString classname 
= wxGetWindowClass(GetHWND()); 
 559     if ( classname
.IsSameAs(_T("EDIT"), false /* no case */) ) 
 566         if ( wxSscanf(classname
, _T("RichEdit%d0%c"), &m_verRichEdit
, &c
) != 2 ) 
 568             wxLogDebug(_T("Unknown edit control '%s'."), classname
.c_str()); 
 573 #endif // wxUSE_RICHEDIT 
 575     if (style 
& ES_MULTILINE
) 
 576         m_windowStyle 
|= wxTE_MULTILINE
; 
 577     if (style 
& ES_PASSWORD
) 
 578         m_windowStyle 
|= wxTE_PASSWORD
; 
 579     if (style 
& ES_READONLY
) 
 580         m_windowStyle 
|= wxTE_READONLY
; 
 581     if (style 
& ES_WANTRETURN
) 
 582         m_windowStyle 
|= wxTE_PROCESS_ENTER
; 
 583     if (style 
& ES_CENTER
) 
 584         m_windowStyle 
|= wxTE_CENTRE
; 
 585     if (style 
& ES_RIGHT
) 
 586         m_windowStyle 
|= wxTE_RIGHT
; 
 589 WXDWORD 
wxTextCtrl::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 591     long msStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 593     // styles which we always add by default 
 594     if ( style 
& wxTE_MULTILINE 
) 
 596         msStyle 
|= ES_MULTILINE 
| ES_WANTRETURN
; 
 597         if ( !(style 
& wxTE_NO_VSCROLL
) ) 
 599             // always adjust the vertical scrollbar automatically if we have it 
 600             msStyle 
|= WS_VSCROLL 
| ES_AUTOVSCROLL
; 
 603             // we have to use this style for the rich edit controls because 
 604             // without it the vertical scrollbar never appears at all in 
 605             // richedit 3.0 because of our ECO_NOHIDESEL hack (search for it) 
 606             if ( style 
& wxTE_RICH2 
) 
 608                 msStyle 
|= ES_DISABLENOSCROLL
; 
 610 #endif // wxUSE_RICHEDIT 
 613         style 
|= wxTE_PROCESS_ENTER
; 
 617         // there is really no reason to not have this style for single line 
 619         msStyle 
|= ES_AUTOHSCROLL
; 
 622     // note that wxTE_DONTWRAP is the same as wxHSCROLL so if we have a horz 
 623     // scrollbar, there is no wrapping -- which makes sense 
 624     if ( style 
& wxTE_DONTWRAP 
) 
 626         // automatically scroll the control horizontally as necessary 
 628         // NB: ES_AUTOHSCROLL is needed for richedit controls or they don't 
 629         //     show horz scrollbar at all, even in spite of WS_HSCROLL, and as 
 630         //     it doesn't seem to do any harm for plain edit controls, add it 
 632         msStyle 
|= WS_HSCROLL 
| ES_AUTOHSCROLL
; 
 635     if ( style 
& wxTE_READONLY 
) 
 636         msStyle 
|= ES_READONLY
; 
 638     if ( style 
& wxTE_PASSWORD 
) 
 639         msStyle 
|= ES_PASSWORD
; 
 641     if ( style 
& wxTE_NOHIDESEL 
) 
 642         msStyle 
|= ES_NOHIDESEL
; 
 644     // note that we can't do do "& wxTE_LEFT" as wxTE_LEFT == 0 
 645     if ( style 
& wxTE_CENTRE 
) 
 646         msStyle 
|= ES_CENTER
; 
 647     else if ( style 
& wxTE_RIGHT 
) 
 650         msStyle 
|= ES_LEFT
; // ES_LEFT is 0 as well but for consistency... 
 655 void wxTextCtrl::SetWindowStyleFlag(long style
) 
 657     // changing the alignment of the control dynamically works under Win2003 
 658     // (but not older Windows version: it seems to work under some versions of 
 659     // XP but not other ones, and we have no way to determine it so be 
 660     // conservative here) and only for plain EDIT controls (not RICH ones) and 
 661     // we have to recreate the control to make it always work 
 662     if ( IsRich() || wxGetWinVersion() < wxWinVersion_2003 
) 
 664         const long alignMask 
= wxTE_LEFT 
| wxTE_CENTRE 
| wxTE_RIGHT
; 
 665         if ( (style 
& alignMask
) != (GetWindowStyle() & alignMask
) ) 
 667             const wxString value 
= GetValue(); 
 668             const wxPoint pos 
= GetPosition(); 
 669             const wxSize size 
= GetSize(); 
 671             // delete the old window 
 672             HWND hwnd 
= GetHwnd(); 
 674             ::DestroyWindow(hwnd
); 
 676             // create the new one with the updated flags 
 677             m_windowStyle 
= style
; 
 678             MSWCreateText(value
, pos
, size
); 
 680             // and make sure it has the same attributes as before 
 683                 // calling SetFont(m_font) would do nothing as the code would 
 684                 // notice that the font didn't change, so force it to believe 
 686                 wxFont font 
= m_font
; 
 693                 wxColour colFg 
= m_foregroundColour
; 
 694                 m_foregroundColour 
= wxNullColour
; 
 695                 SetForegroundColour(colFg
); 
 700                 wxColour colBg 
= m_backgroundColour
; 
 701                 m_backgroundColour 
= wxNullColour
; 
 702                 SetBackgroundColour(colBg
); 
 705             // note that text styles are lost but this is probably not a big 
 706             // problem: if you use styles, you probably don't use nor change 
 707             // alignment flags anyhow 
 714     // we have to deal with some styles separately because they can't be 
 715     // changed by simply calling SetWindowLong(GWL_STYLE) but can be changed 
 716     // using richedit-specific EM_SETOPTIONS 
 718             ((style 
& wxTE_NOHIDESEL
) != (GetWindowStyle() & wxTE_NOHIDESEL
)) ) 
 720         bool set 
= (style 
& wxTE_NOHIDESEL
) != 0; 
 722         ::SendMessage(GetHwnd(), EM_SETOPTIONS
, set 
? ECOOP_OR 
: ECOOP_AND
, 
 723                       set 
? ECO_NOHIDESEL 
: ~ECO_NOHIDESEL
); 
 725 #endif // wxUSE_RICHEDIT 
 727     wxControl::SetWindowStyleFlag(style
); 
 730 // ---------------------------------------------------------------------------- 
 731 // set/get the controls text 
 732 // ---------------------------------------------------------------------------- 
 734 bool wxTextCtrl::IsEmpty() const 
 736     // this is an optimization for multiline controls containing a lot of text 
 737     if ( IsMultiLine() && GetNumberOfLines() != 1 ) 
 740     return wxTextCtrlBase::IsEmpty(); 
 743 wxString 
wxTextCtrl::GetValue() const 
 745     // range 0..-1 is special for GetRange() and means to retrieve all text 
 746     return GetRange(0, -1); 
 749 wxString 
wxTextCtrl::GetRange(long from
, long to
) const 
 753     if ( from 
>= to 
&& to 
!= -1 ) 
 755         // nothing to retrieve 
 762         int len 
= GetWindowTextLength(GetHwnd()); 
 769             // we must use EM_STREAMOUT if we don't want to lose all characters 
 770             // not representable in the current character set (EM_GETTEXTRANGE 
 771             // simply replaces them with question marks...) 
 772             if ( GetRichVersion() > 1 ) 
 774                 // we must have some encoding, otherwise any 8bit chars in the 
 775                 // control are simply *lost* (replaced by '?') 
 776                 wxFontEncoding encoding 
= wxFONTENCODING_SYSTEM
; 
 778                 wxFont font 
= m_defaultStyle
.GetFont(); 
 784                    encoding 
= font
.GetEncoding(); 
 787                 if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 789                     encoding 
= wxLocale::GetSystemEncoding(); 
 792                 if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 794                     encoding 
= wxFONTENCODING_ISO8859_1
; 
 797                 str 
= StreamOut(encoding
); 
 801                     // we have to manually extract the required part, luckily 
 802                     // this is easy in this case as EOL characters in str are 
 803                     // just LFs because we remove CRs in wxRichEditStreamOut 
 804                     str 
= str
.Mid(from
, to 
- from
); 
 808             // StreamOut() wasn't used or failed, try to do it in normal way 
 810 #endif // !wxUSE_UNICODE 
 812                 // alloc one extra WORD as needed by the control 
 813                 wxStringBuffer 
tmp(str
, ++len
); 
 817                 textRange
.chrg
.cpMin 
= from
; 
 818                 textRange
.chrg
.cpMax 
= to
; 
 819                 textRange
.lpstrText 
= p
; 
 821                 (void)::SendMessage(GetHwnd(), EM_GETTEXTRANGE
, 
 822                                     0, (LPARAM
)&textRange
); 
 824                 if ( m_verRichEdit 
> 1 ) 
 826                     // RichEdit 2.0 uses just CR ('\r') for the 
 827                     // newlines which is neither Unix nor Windows 
 828                     // style - convert it to something reasonable 
 831                         if ( *p 
== _T('\r') ) 
 837             if ( m_verRichEdit 
== 1 ) 
 839                 // convert to the canonical form - see comment below 
 840                 str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 843         //else: no text at all, leave the string empty 
 846 #endif // wxUSE_RICHEDIT 
 849         str 
= wxGetWindowText(GetHWND()); 
 851         // need only a range? 
 854             str 
= str
.Mid(from
, to 
- from
); 
 857         // WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the 
 858         // canonical one (same one as above) for consistency with the other kinds 
 859         // of controls and, more importantly, with the other ports 
 860         str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 866 void wxTextCtrl::DoSetValue(const wxString
& value
, int flags
) 
 868     // if the text is long enough, it's faster to just set it instead of first 
 869     // comparing it with the old one (chances are that it will be different 
 870     // anyhow, this comparison is there to avoid flicker for small single-line 
 871     // edit controls mostly) 
 872     if ( (value
.length() > 0x400) || (value 
!= GetValue()) ) 
 874         DoWriteText(value
, flags 
/* doesn't include SelectionOnly here */); 
 876         // mark the control as being not dirty - we changed its text, not the 
 880         // for compatibility, don't move the cursor when doing SetValue() 
 881         SetInsertionPoint(0); 
 885         // still reset the modified flag even if the value didn't really change 
 886         // because now it comes from the program and not the user (and do it 
 887         // before generating the event so that the event handler could get the 
 888         // expected value from IsModified()) 
 891         // still send an event for consistency 
 892         if (flags 
& SetValue_SendEvent
) 
 897 #if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU) 
 899 // TODO: using memcpy() would improve performance a lot for big amounts of text 
 902 wxRichEditStreamIn(DWORD dwCookie
, BYTE 
*buf
, LONG cb
, LONG 
*pcb
) 
 906     const wchar_t ** const ppws 
= (const wchar_t **)dwCookie
; 
 908     wchar_t *wbuf 
= (wchar_t *)buf
; 
 909     const wchar_t *wpc 
= *ppws
; 
 914         cb 
-= sizeof(wchar_t); 
 915         (*pcb
) += sizeof(wchar_t); 
 923 // helper struct used to pass parameters from wxTextCtrl to wxRichEditStreamOut 
 924 struct wxStreamOutData
 
 931 wxRichEditStreamOut(DWORD_PTR dwCookie
, BYTE 
*buf
, LONG cb
, LONG 
*pcb
) 
 935     wxStreamOutData 
*data 
= (wxStreamOutData 
*)dwCookie
; 
 937     const wchar_t *wbuf 
= (const wchar_t *)buf
; 
 938     wchar_t *wpc 
= data
->wpc
; 
 941         wchar_t wch 
= *wbuf
++; 
 943         // turn "\r\n" into "\n" on the fly 
 949         cb 
-= sizeof(wchar_t); 
 950         (*pcb
) += sizeof(wchar_t); 
 959 #if wxUSE_UNICODE_MSLU 
 960     #define UNUSED_IF_MSLU(param) 
 962     #define UNUSED_IF_MSLU(param) param 
 966 wxTextCtrl::StreamIn(const wxString
& value
, 
 967                      wxFontEncoding 
UNUSED_IF_MSLU(encoding
), 
 970 #if wxUSE_UNICODE_MSLU 
 971     const wchar_t *wpc 
= value
.c_str(); 
 972 #else // !wxUSE_UNICODE_MSLU 
 973     wxCSConv 
conv(encoding
); 
 975     const size_t len 
= conv
.MB2WC(NULL
, value
.mb_str(), value
.length()); 
 977     if (len 
== wxCONV_FAILED
) 
 981     wxWCharBuffer 
wchBuf(len
); 
 982     wchar_t *wpc 
= wchBuf
.data(); 
 984     wchar_t *wchBuf 
= (wchar_t *)malloc((len 
+ 1)*sizeof(wchar_t)); 
 985     wchar_t *wpc 
= wchBuf
; 
 988     conv
.MB2WC(wpc
, value
.mb_str(), value
.length()); 
 989 #endif // wxUSE_UNICODE_MSLU 
 991     // finally, stream it in the control 
 994     eds
.dwCookie 
= (DWORD
)&wpc
; 
 995     // the cast below is needed for broken (very) old mingw32 headers 
 996     eds
.pfnCallback 
= (EDITSTREAMCALLBACK
)wxRichEditStreamIn
; 
 998     // same problem as in DoWriteText(): we can get multiple events here 
 999     UpdatesCountFilter 
ucf(m_updatesCount
); 
1001     ::SendMessage(GetHwnd(), EM_STREAMIN
, 
1004                   (selectionOnly 
? SFF_SELECTION 
: 0), 
1007     // It's okay for EN_UPDATE to not be sent if the selection is empty and 
1008     // the text is empty, otherwise warn the programmer about it. 
1009     wxASSERT_MSG( ucf
.GotUpdate() || ( !HasSelection() && value
.empty() ), 
1010                   _T("EM_STREAMIN didn't send EN_UPDATE?") ); 
1014         wxLogLastError(_T("EM_STREAMIN")); 
1019 #endif // !wxUSE_WCHAR_T 
1024 #if !wxUSE_UNICODE_MSLU 
1027 wxTextCtrl::StreamOut(wxFontEncoding encoding
, bool selectionOnly
) const 
1031     const int len 
= GetWindowTextLength(GetHwnd()); 
1034     wxWCharBuffer 
wchBuf(len
); 
1035     wchar_t *wpc 
= wchBuf
.data(); 
1037     wchar_t *wchBuf 
= (wchar_t *)malloc((len 
+ 1)*sizeof(wchar_t)); 
1038     wchar_t *wpc 
= wchBuf
; 
1041     wxStreamOutData data
; 
1047     eds
.dwCookie 
= (DWORD
)&data
; 
1048     eds
.pfnCallback 
= wxRichEditStreamOut
; 
1054         SF_TEXT 
| SF_UNICODE 
| (selectionOnly 
? SFF_SELECTION 
: 0), 
1060         wxLogLastError(_T("EM_STREAMOUT")); 
1062     else // streamed out ok 
1064         // NUL-terminate the string because its length could have been 
1065         // decreased by wxRichEditStreamOut 
1066         *(wchBuf
.data() + data
.len
) = L
'\0'; 
1068         // now convert to the given encoding (this is a possibly lossful 
1069         // conversion but what else can we do) 
1070         wxCSConv 
conv(encoding
); 
1071         size_t lenNeeded 
= conv
.WC2MB(NULL
, wchBuf
, 0); 
1073         if ( lenNeeded 
!= wxCONV_FAILED 
&& lenNeeded
++ ) 
1075             conv
.WC2MB(wxStringBuffer(out
, lenNeeded
), wchBuf
, lenNeeded
); 
1081 #endif // !wxUSE_WCHAR_T 
1086 #endif // !wxUSE_UNICODE_MSLU 
1088 #endif // wxUSE_RICHEDIT 
1090 void wxTextCtrl::WriteText(const wxString
& value
) 
1095 void wxTextCtrl::DoWriteText(const wxString
& value
, int flags
) 
1097     bool selectionOnly 
= (flags 
& SetValue_SelectionOnly
) != 0; 
1099     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1100         valueDos 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
1105     // there are several complications with the rich edit controls here 
1109         // first, ensure that the new text will be in the default style 
1110         if ( !m_defaultStyle
.IsDefault() ) 
1113             GetSelection(&start
, &end
); 
1114             SetStyle(start
, end
, m_defaultStyle
); 
1117 #if wxUSE_UNICODE_MSLU 
1118         // RichEdit doesn't have Unicode version of EM_REPLACESEL on Win9x, 
1119         // but EM_STREAMIN works 
1120         if ( wxUsingUnicowsDll() && GetRichVersion() > 1 ) 
1122            done 
= StreamIn(valueDos
, wxFONTENCODING_SYSTEM
, selectionOnly
); 
1124 #endif // wxUSE_UNICODE_MSLU 
1127         // next check if the text we're inserting must be shown in a non 
1128         // default charset -- this only works for RichEdit > 1.0 
1129         if ( GetRichVersion() > 1 ) 
1131             wxFont font 
= m_defaultStyle
.GetFont(); 
1137                wxFontEncoding encoding 
= font
.GetEncoding(); 
1138                if ( encoding 
!= wxFONTENCODING_SYSTEM 
) 
1140                    // we have to use EM_STREAMIN to force richedit control 2.0+ 
1141                    // to show any text in the non default charset -- otherwise 
1142                    // it thinks it knows better than we do and always shows it 
1143                    // in the default one 
1144                    done 
= StreamIn(valueDos
, encoding
, selectionOnly
); 
1148 #endif // !wxUSE_UNICODE 
1152 #endif // wxUSE_RICHEDIT 
1154         // in some cases we get 2 EN_CHANGE notifications after the SendMessage 
1155         // call (this happens for plain EDITs with EM_REPLACESEL and under some 
1156         // -- undetermined -- conditions with rich edit) and sometimes we don't 
1157         // get any events at all (plain EDIT with WM_SETTEXT), so ensure that 
1158         // we generate exactly one of them by ignoring all but the first one in 
1159         // SendUpdateEvent() and generating one ourselves if we hadn't got any 
1160         // notifications from Windows 
1161         if ( !(flags 
& SetValue_SendEvent
) ) 
1162             m_updatesCount 
= -2;        // suppress any update event 
1164         UpdatesCountFilter 
ucf(m_updatesCount
); 
1166         ::SendMessage(GetHwnd(), selectionOnly 
? EM_REPLACESEL 
: WM_SETTEXT
, 
1167                       // EM_REPLACESEL takes 1 to indicate the operation should be redoable 
1168                       selectionOnly 
? 1 : 0, (LPARAM
)valueDos
.wx_str()); 
1170         if ( !ucf
.GotUpdate() && (flags 
& SetValue_SendEvent
) ) 
1177 void wxTextCtrl::AppendText(const wxString
& text
) 
1179     wxTextEntry::AppendText(text
); 
1182     // don't do this if we're frozen, saves some time 
1183     if ( !IsFrozen() && IsMultiLine() && GetRichVersion() > 1 ) 
1185         // setting the caret to the end and showing it simply doesn't work for 
1186         // RichEdit 2.0 -- force it to still do what we want 
1187         ::SendMessage(GetHwnd(), EM_LINESCROLL
, 0, GetNumberOfLines()); 
1189 #endif // wxUSE_RICHEDIT 
1192 void wxTextCtrl::Clear() 
1194     ::SetWindowText(GetHwnd(), wxEmptyString
); 
1196     if ( IsMultiLine() && !IsRich() ) 
1198         // rich edit controls send EN_UPDATE from WM_SETTEXT handler themselves 
1199         // but the normal ones don't -- make Clear() behaviour consistent by 
1200         // always sending this event 
1207 bool wxTextCtrl::EmulateKeyPress(const wxKeyEvent
& event
) 
1211     size_t lenOld 
= GetValue().length(); 
1213     wxUint32 code 
= event
.GetRawKeyCode(); 
1214     ::keybd_event((BYTE
)code
, 0, 0 /* key press */, 0); 
1215     ::keybd_event((BYTE
)code
, 0, KEYEVENTF_KEYUP
, 0); 
1217     // assume that any alphanumeric key changes the total number of characters 
1218     // in the control - this should work in 99% of cases 
1219     return GetValue().length() != lenOld
; 
1224 // ---------------------------------------------------------------------------- 
1226 // ---------------------------------------------------------------------------- 
1228 void wxTextCtrl::SetInsertionPointEnd() 
1230     // we must not do anything if the caret is already there because calling 
1231     // SetInsertionPoint() thaws the controls if Freeze() had been called even 
1232     // if it doesn't actually move the caret anywhere and so the simple fact of 
1233     // doing it results in horrible flicker when appending big amounts of text 
1234     // to the control in a few chunks (see DoAddText() test in the text sample) 
1235     const wxTextPos lastPosition 
= GetLastPosition(); 
1236     if ( GetInsertionPoint() == lastPosition 
) 
1241     SetInsertionPoint(lastPosition
); 
1244 long wxTextCtrl::GetInsertionPoint() const 
1252         ::SendMessage(GetHwnd(), EM_EXGETSEL
, 0, (LPARAM
) &range
); 
1255 #endif // wxUSE_RICHEDIT 
1257     return wxTextEntry::GetInsertionPoint(); 
1260 wxTextPos 
wxTextCtrl::GetLastPosition() const 
1262     if ( IsMultiLine() ) 
1264         int numLines 
= GetNumberOfLines(); 
1265         long posStartLastLine 
= XYToPosition(0, numLines 
- 1); 
1267         long lenLastLine 
= GetLengthOfLineContainingPos(posStartLastLine
); 
1269         return posStartLastLine 
+ lenLastLine
; 
1272     return wxTextEntry::GetLastPosition(); 
1275 // If the return values from and to are the same, there is no 
1277 void wxTextCtrl::GetSelection(long *from
, long *to
) const 
1282         CHARRANGE charRange
; 
1283         ::SendMessage(GetHwnd(), EM_EXGETSEL
, 0, (LPARAM
) &charRange
); 
1285         *from 
= charRange
.cpMin
; 
1286         *to 
= charRange
.cpMax
; 
1289 #endif // !wxUSE_RICHEDIT 
1291         wxTextEntry::GetSelection(from
, to
); 
1295 // ---------------------------------------------------------------------------- 
1297 // ---------------------------------------------------------------------------- 
1299 void wxTextCtrl::DoSetSelection(long from
, long to
, int flags
) 
1301     HWND hWnd 
= GetHwnd(); 
1309         ::SendMessage(hWnd
, EM_EXSETSEL
, 0, (LPARAM
)&range
); 
1312 #endif // wxUSE_RICHEDIT 
1314         wxTextEntry::DoSetSelection(from
, to
, flags
); 
1317     if ( (flags 
& SetSel_Scroll
) && !IsFrozen() ) 
1320         // richedit 3.0 (i.e. the version living in riched20.dll distributed 
1321         // with Windows 2000 and beyond) doesn't honour EM_SCROLLCARET when 
1322         // emulating richedit 2.0 unless the control has focus or ECO_NOHIDESEL 
1323         // option is set (but it does work ok in richedit 1.0 mode...) 
1325         // so to make it work we either need to give focus to it here which 
1326         // will probably create many problems (dummy focus events; window 
1327         // containing the text control being brought to foreground 
1328         // unexpectedly; ...) or to temporarily set ECO_NOHIDESEL which may 
1329         // create other problems too -- and in fact it does because if we turn 
1330         // on/off this style while appending the text to the control, the 
1331         // vertical scrollbar never appears in it even if we append tons of 
1332         // text and to work around this the only solution I found was to use 
1333         // ES_DISABLENOSCROLL 
1335         // this is very ugly but I don't see any other way to make this work 
1337         if ( GetRichVersion() > 1 ) 
1339             if ( !HasFlag(wxTE_NOHIDESEL
) ) 
1341                 // setting ECO_NOHIDESEL also sets WS_VISIBLE and possibly 
1342                 // others, remember the style so we can reset it later if needed 
1343                 style 
= ::GetWindowLong(GetHwnd(), GWL_STYLE
); 
1344                 ::SendMessage(GetHwnd(), EM_SETOPTIONS
, 
1345                               ECOOP_OR
, ECO_NOHIDESEL
); 
1347             //else: everything is already ok 
1349 #endif // wxUSE_RICHEDIT 
1351         ::SendMessage(hWnd
, EM_SCROLLCARET
, 0, (LPARAM
)0); 
1354         // restore ECO_NOHIDESEL if we changed it 
1355         if ( GetRichVersion() > 1 && !HasFlag(wxTE_NOHIDESEL
) ) 
1357             ::SendMessage(GetHwnd(), EM_SETOPTIONS
, 
1358                           ECOOP_AND
, ~ECO_NOHIDESEL
); 
1359             if ( style 
!= ::GetWindowLong(GetHwnd(), GWL_STYLE
) ) 
1360                 ::SetWindowLong(GetHwnd(), GWL_STYLE
, style
); 
1362 #endif // wxUSE_RICHEDIT 
1366 // ---------------------------------------------------------------------------- 
1367 // Working with files 
1368 // ---------------------------------------------------------------------------- 
1370 bool wxTextCtrl::DoLoadFile(const wxString
& file
, int fileType
) 
1372     if ( wxTextCtrlBase::DoLoadFile(file
, fileType
) ) 
1374         // update the size limit if needed 
1383 // ---------------------------------------------------------------------------- 
1385 // ---------------------------------------------------------------------------- 
1387 bool wxTextCtrl::IsModified() const 
1389     return ::SendMessage(GetHwnd(), EM_GETMODIFY
, 0, 0) != 0; 
1392 void wxTextCtrl::MarkDirty() 
1394     ::SendMessage(GetHwnd(), EM_SETMODIFY
, TRUE
, 0); 
1397 void wxTextCtrl::DiscardEdits() 
1399     ::SendMessage(GetHwnd(), EM_SETMODIFY
, FALSE
, 0); 
1402 // ---------------------------------------------------------------------------- 
1403 // Positions <-> coords 
1404 // ---------------------------------------------------------------------------- 
1406 int wxTextCtrl::GetNumberOfLines() const 
1408     return (int)::SendMessage(GetHwnd(), EM_GETLINECOUNT
, 0, 0); 
1411 long wxTextCtrl::XYToPosition(long x
, long y
) const 
1413     // This gets the char index for the _beginning_ of this line 
1414     long charIndex 
= ::SendMessage(GetHwnd(), EM_LINEINDEX
, y
, 0); 
1416     return charIndex 
+ x
; 
1419 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
1421     HWND hWnd 
= GetHwnd(); 
1423     // This gets the line number containing the character 
1428         lineNo 
= ::SendMessage(hWnd
, EM_EXLINEFROMCHAR
, 0, pos
); 
1431 #endif // wxUSE_RICHEDIT 
1433         lineNo 
= ::SendMessage(hWnd
, EM_LINEFROMCHAR
, pos
, 0); 
1442     // This gets the char index for the _beginning_ of this line 
1443     long charIndex 
= ::SendMessage(hWnd
, EM_LINEINDEX
, lineNo
, 0); 
1444     if ( charIndex 
== -1 ) 
1449     // The X position must therefore be the different between pos and charIndex 
1451         *x 
= pos 
- charIndex
; 
1458 wxTextCtrlHitTestResult
 
1459 wxTextCtrl::HitTest(const wxPoint
& pt
, long *posOut
) const 
1461     // first get the position from Windows 
1468         // for rich edit controls the position is passed iva the struct fields 
1471         lParam 
= (LPARAM
)&ptl
; 
1474 #endif // wxUSE_RICHEDIT 
1476         // for the plain ones, we are limited to 16 bit positions which are 
1477         // combined in a single 32 bit value 
1478         lParam 
= MAKELPARAM(pt
.x
, pt
.y
); 
1481     LRESULT pos 
= ::SendMessage(GetHwnd(), EM_CHARFROMPOS
, 0, lParam
); 
1485         // this seems to indicate an error... 
1486         return wxTE_HT_UNKNOWN
; 
1491 #endif // wxUSE_RICHEDIT 
1493         // for plain EDIT controls the higher word contains something else 
1498     // next determine where it is relatively to our point: EM_CHARFROMPOS 
1499     // always returns the closest character but we need to be more precise, so 
1500     // double check that we really are where it pretends 
1504     // FIXME: we need to distinguish between richedit 2 and 3 here somehow but 
1505     //        we don't know how to do it 
1508         ::SendMessage(GetHwnd(), EM_POSFROMCHAR
, (WPARAM
)&ptReal
, pos
); 
1511 #endif // wxUSE_RICHEDIT 
1513         LRESULT lRc 
= ::SendMessage(GetHwnd(), EM_POSFROMCHAR
, pos
, 0); 
1517             // this is apparently returned when pos corresponds to the last 
1524             ptReal
.x 
= LOWORD(lRc
); 
1525             ptReal
.y 
= HIWORD(lRc
); 
1529     wxTextCtrlHitTestResult rc
; 
1531     if ( pt
.y 
> ptReal
.y 
+ GetCharHeight() ) 
1533     else if ( pt
.x 
> ptReal
.x 
+ GetCharWidth() ) 
1534         rc 
= wxTE_HT_BEYOND
; 
1536         rc 
= wxTE_HT_ON_TEXT
; 
1544 // ---------------------------------------------------------------------------- 
1546 // ---------------------------------------------------------------------------- 
1548 void wxTextCtrl::ShowPosition(long pos
) 
1550     HWND hWnd 
= GetHwnd(); 
1552     // To scroll to a position, we pass the number of lines and characters 
1553     // to scroll *by*. This means that we need to: 
1554     // (1) Find the line position of the current line. 
1555     // (2) Find the line position of pos. 
1556     // (3) Scroll by (pos - current). 
1557     // For now, ignore the horizontal scrolling. 
1559     // Is this where scrolling is relative to - the line containing the caret? 
1560     // Or is the first visible line??? Try first visible line. 
1561 //    int currentLineLineNo1 = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, -1, 0L); 
1563     int currentLineLineNo 
= (int)::SendMessage(hWnd
, EM_GETFIRSTVISIBLELINE
, 0, 0); 
1565     int specifiedLineLineNo 
= (int)::SendMessage(hWnd
, EM_LINEFROMCHAR
, pos
, 0); 
1567     int linesToScroll 
= specifiedLineLineNo 
- currentLineLineNo
; 
1569     if (linesToScroll 
!= 0) 
1570       ::SendMessage(hWnd
, EM_LINESCROLL
, 0, linesToScroll
); 
1573 long wxTextCtrl::GetLengthOfLineContainingPos(long pos
) const 
1575     return ::SendMessage(GetHwnd(), EM_LINELENGTH
, pos
, 0); 
1578 int wxTextCtrl::GetLineLength(long lineNo
) const 
1580     long pos 
= XYToPosition(0, lineNo
); 
1582     return GetLengthOfLineContainingPos(pos
); 
1585 wxString 
wxTextCtrl::GetLineText(long lineNo
) const 
1587     size_t len 
= (size_t)GetLineLength(lineNo
) + 1; 
1589     // there must be at least enough place for the length WORD in the 
1591     len 
+= sizeof(WORD
); 
1595         wxStringBufferLength 
tmp(str
, len
); 
1598         *(WORD 
*)buf 
= (WORD
)len
; 
1599         len 
= (size_t)::SendMessage(GetHwnd(), EM_GETLINE
, lineNo
, (LPARAM
)buf
); 
1604             // remove the '\r' returned by the rich edit control, the user code 
1605             // should never see it 
1606             if ( buf
[len 
- 2] == _T('\r') && buf
[len 
- 1] == _T('\n') ) 
1608                 // richedit 1.0 uses "\r\n" as line terminator, so remove "\r" 
1609                 // here and "\n" below 
1610                 buf
[len 
- 2] = _T('\n'); 
1613             else if ( buf
[len 
- 1] == _T('\r') ) 
1615                 // richedit 2.0+ uses only "\r", replace it with "\n" 
1616                 buf
[len 
- 1] = _T('\n'); 
1619 #endif // wxUSE_RICHEDIT 
1621         // remove the '\n' at the end, if any (this is how this function is 
1622         // supposed to work according to the docs) 
1623         if ( buf
[len 
- 1] == _T('\n') ) 
1635 void wxTextCtrl::SetMaxLength(unsigned long len
) 
1640         ::SendMessage(GetHwnd(), EM_EXLIMITTEXT
, 0, len 
? len 
: 0x7fffffff); 
1643 #endif // wxUSE_RICHEDIT 
1645         wxTextEntry::SetMaxLength(len
); 
1649 // ---------------------------------------------------------------------------- 
1651 // ---------------------------------------------------------------------------- 
1653 void wxTextCtrl::Redo() 
1656     if ( GetRichVersion() > 1 ) 
1658         ::SendMessage(GetHwnd(), EM_REDO
, 0, 0); 
1661 #endif // wxUSE_RICHEDIT 
1663     wxTextEntry::Redo(); 
1666 bool wxTextCtrl::CanRedo() const 
1669     if ( GetRichVersion() > 1 ) 
1670         return ::SendMessage(GetHwnd(), EM_CANREDO
, 0, 0) != 0; 
1671 #endif // wxUSE_RICHEDIT 
1673     return wxTextEntry::CanRedo(); 
1676 // ---------------------------------------------------------------------------- 
1677 // caret handling (Windows only) 
1678 // ---------------------------------------------------------------------------- 
1680 bool wxTextCtrl::ShowNativeCaret(bool show
) 
1682     if ( show 
!= m_isNativeCaretShown 
) 
1684         if ( !(show 
? ::ShowCaret(GetHwnd()) : ::HideCaret(GetHwnd())) ) 
1686             // not an error, may simply indicate that it's not shown/hidden 
1687             // yet (i.e. it had been hidden/shown 2 times before) 
1691         m_isNativeCaretShown 
= show
; 
1697 // ---------------------------------------------------------------------------- 
1698 // implementation details 
1699 // ---------------------------------------------------------------------------- 
1701 void wxTextCtrl::Command(wxCommandEvent 
& event
) 
1703     SetValue(event
.GetString()); 
1704     ProcessCommand (event
); 
1707 void wxTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
1709     // By default, load the first file into the text window. 
1710     if (event
.GetNumberOfFiles() > 0) 
1712         LoadFile(event
.GetFiles()[0]); 
1716 // ---------------------------------------------------------------------------- 
1717 // kbd input processing 
1718 // ---------------------------------------------------------------------------- 
1720 bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG
* msg
) 
1722     // check for our special keys here: if we don't do it and the parent frame 
1723     // uses them as accelerators, they wouldn't work at all, so we disable 
1724     // usual preprocessing for them 
1725     if ( msg
->message 
== WM_KEYDOWN 
) 
1727         const WPARAM vkey 
= msg
->wParam
; 
1728         if ( HIWORD(msg
->lParam
) & KF_ALTDOWN 
) 
1730             // Alt-Backspace is accelerator for "Undo" 
1731             if ( vkey 
== VK_BACK 
) 
1736             // we want to process some Ctrl-foo and Shift-bar but no key 
1737             // combinations without either Ctrl or Shift nor with both of them 
1739             const int ctrl 
= wxIsCtrlDown(), 
1740                       shift 
= wxIsShiftDown(); 
1741             switch ( ctrl 
+ shift 
) 
1744                     wxFAIL_MSG( _T("how many modifiers have we got?") ); 
1748                     if ( IsMultiLine() && vkey 
== VK_RETURN 
) 
1755                     // either Ctrl or Shift pressed 
1770                     else // Shift is pressed 
1772                         if ( vkey 
== VK_INSERT 
|| vkey 
== VK_DELETE 
) 
1779     return wxControl::MSWShouldPreProcessMessage(msg
); 
1782 void wxTextCtrl::OnChar(wxKeyEvent
& event
) 
1784     switch ( event
.GetKeyCode() ) 
1788                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
); 
1789                 InitCommandEvent(event
); 
1790                 event
.SetString(GetValue()); 
1791                 if ( HandleWindowEvent(event
) ) 
1792                 if ( !HasFlag(wxTE_MULTILINE
) ) 
1794                 //else: multiline controls need Enter for themselves 
1799             // ok, so this is getting absolutely ridiculous but I don't see 
1800             // any other way to fix this bug: when a multiline text control is 
1801             // inside a wxFrame, we need to generate the navigation event as 
1802             // otherwise nothing happens at all, but when the same control is 
1803             // created inside a dialog, IsDialogMessage() *does* switch focus 
1804             // all by itself and so if we do it here as well, it is advanced 
1805             // twice and goes to the next control... to prevent this from 
1806             // happening we're doing this ugly check, the logic being that if 
1807             // we don't have focus then it had been already changed to the next 
1810             // the right thing to do would, of course, be to understand what 
1811             // the hell is IsDialogMessage() doing but this is beyond my feeble 
1812             // forces at the moment unfortunately 
1813             if ( !(m_windowStyle 
& wxTE_PROCESS_TAB
)) 
1815                 if ( FindFocus() == this ) 
1818                     if (!event
.ShiftDown()) 
1819                         flags 
|= wxNavigationKeyEvent::IsForward 
; 
1820                     if (event
.ControlDown()) 
1821                         flags 
|= wxNavigationKeyEvent::WinChange 
; 
1822                     if (Navigate(flags
)) 
1828                 // Insert tab since calling the default Windows handler 
1829                 // doesn't seem to do it 
1830                 WriteText(wxT("\t")); 
1836     // no, we didn't process it 
1840 WXLRESULT 
wxTextCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
1842     WXLRESULT lRc 
= wxTextCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
1848                 // we always want the chars and the arrows: the arrows for 
1849                 // navigation and the chars because we want Ctrl-C to work even 
1850                 // in a read only control 
1851                 long lDlgCode 
= DLGC_WANTCHARS 
| DLGC_WANTARROWS
; 
1855                     // we may have several different cases: 
1856                     // 1. normal: both TAB and ENTER are used for navigation 
1857                     // 2. ctrl wants TAB for itself: ENTER is used to pass to 
1858                     //    the next control in the dialog 
1859                     // 3. ctrl wants ENTER for itself: TAB is used for dialog 
1861                     // 4. ctrl wants both TAB and ENTER: Ctrl-ENTER is used to 
1862                     //    go to the next control (we need some way to do it) 
1864                     // multiline controls should always get ENTER for themselves 
1865                     if ( HasFlag(wxTE_PROCESS_ENTER
) || HasFlag(wxTE_MULTILINE
) ) 
1866                         lDlgCode 
|= DLGC_WANTMESSAGE
; 
1868                     if ( HasFlag(wxTE_PROCESS_TAB
) ) 
1869                         lDlgCode 
|= DLGC_WANTTAB
; 
1875                     // NB: use "=", not "|=" as the base class version returns 
1876                     //     the same flags is this state as usual (i.e. 
1877                     //     including DLGC_WANTMESSAGE). This is strange (how 
1878                     //     does it work in the native Win32 apps?) but for now 
1888             if ( HandleClipboardEvent(nMsg
) ) 
1896 // ---------------------------------------------------------------------------- 
1897 // text control event processing 
1898 // ---------------------------------------------------------------------------- 
1900 bool wxTextCtrl::SendUpdateEvent() 
1902     switch ( m_updatesCount 
) 
1905             // remember that we've got an update 
1910             // we had already sent one event since the last control modification 
1914             wxFAIL_MSG( _T("unexpected wxTextCtrl::m_updatesCount value") ); 
1918             // we hadn't updated the control ourselves, this event comes from 
1919             // the user, don't need to ignore it nor update the count 
1923             // the control was updated programmatically and we do NOT want to 
1928     return SendTextUpdatedEvent(); 
1931 bool wxTextCtrl::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
1940             // the text size limit has been hit -- try to increase it 
1941             if ( !AdjustSpaceLimit() ) 
1943                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_MAXLEN
, m_windowId
); 
1944                 InitCommandEvent(event
); 
1945                 event
.SetString(GetValue()); 
1946                 ProcessCommand(event
); 
1950             // the other edit notification messages are not processed (or, in 
1951             // the case of EN_{SET/KILL}FOCUS were already handled at WM_SET/ 
1961 WXHBRUSH 
wxTextCtrl::MSWControlColor(WXHDC hDC
, WXHWND hWnd
) 
1963     if ( !IsEnabled() && !HasFlag(wxTE_MULTILINE
) ) 
1964         return MSWControlColorDisabled(hDC
); 
1966     return wxTextCtrlBase::MSWControlColor(hDC
, hWnd
); 
1969 bool wxTextCtrl::HasSpaceLimit(unsigned int *len
) const 
1971     // HACK: we try to automatically extend the limit for the amount of text 
1972     //       to allow (interactively) entering more than 64Kb of text under 
1973     //       Win9x but we shouldn't reset the text limit which was previously 
1974     //       set explicitly with SetMaxLength() 
1976     //       Unfortunately there is no EM_GETLIMITTEXTSETBYUSER and so we don't 
1977     //       know the limit we set (if any). We could solve this by storing the 
1978     //       limit we set in wxTextCtrl but to save space we prefer to simply 
1979     //       test here the actual limit value: we consider that SetMaxLength() 
1980     //       can only be called for small values while EN_MAXTEXT is only sent 
1981     //       for large values (in practice the default limit seems to be 30000 
1982     //       but make it smaller just to be on the safe side) 
1983     *len 
= ::SendMessage(GetHwnd(), EM_GETLIMITTEXT
, 0, 0); 
1984     return *len 
< 10001; 
1988 bool wxTextCtrl::AdjustSpaceLimit() 
1991     if ( HasSpaceLimit(&limit
) ) 
1994     unsigned int len 
= ::GetWindowTextLength(GetHwnd()); 
1997         // increment in 32Kb chunks 
1998         SetMaxLength(len 
+ 0x8000); 
2001     // we changed the limit 
2005 bool wxTextCtrl::AcceptsFocusFromKeyboard() const 
2007     // we don't want focus if we can't be edited unless we're a multiline 
2008     // control because then it might be still nice to get focus from keyboard 
2009     // to be able to scroll it without mouse 
2010     return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus(); 
2013 wxSize 
wxTextCtrl::DoGetBestSize() const 
2016     wxGetCharSize(GetHWND(), &cx
, &cy
, GetFont()); 
2018     int wText 
= DEFAULT_ITEM_WIDTH
; 
2021     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
2023         hText 
*= wxMax(wxMin(GetNumberOfLines(), 10), 2); 
2025     //else: for single line control everything is ok 
2027     // we have to add the adjustments for the control height only once, not 
2028     // once per line, so do it after multiplication above 
2029     hText 
+= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
) - cy
; 
2031     return wxSize(wText
, hText
); 
2034 // ---------------------------------------------------------------------------- 
2035 // standard handlers for standard edit menu events 
2036 // ---------------------------------------------------------------------------- 
2038 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
2043 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
2048 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
2053 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
2058 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
2063 void wxTextCtrl::OnDelete(wxCommandEvent
& WXUNUSED(event
)) 
2066     GetSelection(& from
, & to
); 
2067     if (from 
!= -1 && to 
!= -1) 
2071 void wxTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
2073     SetSelection(-1, -1); 
2076 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
2078     event
.Enable( CanCut() ); 
2081 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
2083     event
.Enable( CanCopy() ); 
2086 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
2088     event
.Enable( CanPaste() ); 
2091 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
2093     event
.Enable( CanUndo() ); 
2096 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
2098     event
.Enable( CanRedo() ); 
2101 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent
& event
) 
2104     GetSelection(& from
, & to
); 
2105     event
.Enable(from 
!= -1 && to 
!= -1 && from 
!= to 
&& IsEditable()) ; 
2108 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
2110     event
.Enable(GetLastPosition() > 0); 
2113 void wxTextCtrl::OnContextMenu(wxContextMenuEvent
& event
) 
2118         if (!m_privateContextMenu
) 
2120             m_privateContextMenu 
= new wxMenu
; 
2121             m_privateContextMenu
->Append(wxID_UNDO
, _("&Undo")); 
2122             m_privateContextMenu
->Append(wxID_REDO
, _("&Redo")); 
2123             m_privateContextMenu
->AppendSeparator(); 
2124             m_privateContextMenu
->Append(wxID_CUT
, _("Cu&t")); 
2125             m_privateContextMenu
->Append(wxID_COPY
, _("&Copy")); 
2126             m_privateContextMenu
->Append(wxID_PASTE
, _("&Paste")); 
2127             m_privateContextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
2128             m_privateContextMenu
->AppendSeparator(); 
2129             m_privateContextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
2131         PopupMenu(m_privateContextMenu
); 
2139 void wxTextCtrl::OnSetFocus(wxFocusEvent
& event
) 
2141     // be sure the caret remains invisible if the user had hidden it 
2142     if ( !m_isNativeCaretShown 
) 
2144         ::HideCaret(GetHwnd()); 
2150 // ---------------------------------------------------------------------------- 
2151 // Default colors for MSW text control 
2153 // Set default background color to the native white instead of 
2154 // the default wxSYS_COLOUR_BTNFACE (is triggered with wxNullColour). 
2155 // ---------------------------------------------------------------------------- 
2157 wxVisualAttributes 
wxTextCtrl::GetDefaultAttributes() const 
2159     wxVisualAttributes attrs
; 
2160     attrs
.font 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
2161     attrs
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
2162     attrs
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
); //white 
2167 // the rest of the file only deals with the rich edit controls 
2170 // ---------------------------------------------------------------------------- 
2171 // EN_LINK processing 
2172 // ---------------------------------------------------------------------------- 
2174 bool wxTextCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
) 
2176     NMHDR 
*hdr 
= (NMHDR
* )lParam
; 
2177     switch ( hdr
->code 
) 
2181                 const MSGFILTER 
*msgf 
= (MSGFILTER 
*)lParam
; 
2182                 UINT msg 
= msgf
->msg
; 
2184                 // this is a bit crazy but richedit 1.0 sends us all mouse 
2185                 // events _except_ WM_LBUTTONUP (don't ask me why) so we have 
2186                 // generate the wxWin events for this message manually 
2188                 // NB: in fact, this is still not totally correct as it does 
2189                 //     send us WM_LBUTTONUP if the selection was cleared by the 
2190                 //     last click -- so currently we get 2 events in this case, 
2191                 //     but as I don't see any obvious way to check for this I 
2192                 //     leave this code in place because it's still better than 
2193                 //     not getting left up events at all 
2194                 if ( msg 
== WM_LBUTTONUP 
) 
2196                     WXUINT flags 
= msgf
->wParam
; 
2197                     int x 
= GET_X_LPARAM(msgf
->lParam
), 
2198                         y 
= GET_Y_LPARAM(msgf
->lParam
); 
2200                     HandleMouseEvent(msg
, x
, y
, flags
); 
2204             // return true to process the event (and false to ignore it) 
2209                 const ENLINK 
*enlink 
= (ENLINK 
*)hdr
; 
2211                 switch ( enlink
->msg 
) 
2214                         // ok, so it is hardcoded - do we really nee to 
2217                             wxCursor 
cur(wxCURSOR_HAND
); 
2218                             ::SetCursor(GetHcursorOf(cur
)); 
2224                     case WM_LBUTTONDOWN
: 
2226                     case WM_LBUTTONDBLCLK
: 
2227                     case WM_RBUTTONDOWN
: 
2229                     case WM_RBUTTONDBLCLK
: 
2230                         // send a mouse event 
2232                             static const wxEventType eventsMouse
[] = 
2243                             // the event ids are consecutive 
2245                                 evtMouse(eventsMouse
[enlink
->msg 
- WM_MOUSEMOVE
]); 
2247                             InitMouseEvent(evtMouse
, 
2248                                            GET_X_LPARAM(enlink
->lParam
), 
2249                                            GET_Y_LPARAM(enlink
->lParam
), 
2252                             wxTextUrlEvent 
event(m_windowId
, evtMouse
, 
2254                                                  enlink
->chrg
.cpMax
); 
2256                             InitCommandEvent(event
); 
2258                             *result 
= ProcessCommand(event
); 
2266     // not processed, leave it to the base class 
2267     return wxTextCtrlBase::MSWOnNotify(idCtrl
, lParam
, result
); 
2270 #if wxUSE_DRAG_AND_DROP 
2272 void wxTextCtrl::SetDropTarget(wxDropTarget 
*dropTarget
) 
2274     if ( m_dropTarget 
== wxRICHTEXT_DEFAULT_DROPTARGET 
) 
2276         // get rid of the built-in drop target 
2277         ::RevokeDragDrop(GetHwnd()); 
2278         m_dropTarget 
= NULL
; 
2281     wxTextCtrlBase::SetDropTarget(dropTarget
); 
2284 #endif // wxUSE_DRAG_AND_DROP 
2286 // ---------------------------------------------------------------------------- 
2287 // colour setting for the rich edit controls 
2288 // ---------------------------------------------------------------------------- 
2290 bool wxTextCtrl::SetBackgroundColour(const wxColour
& colour
) 
2292     if ( !wxTextCtrlBase::SetBackgroundColour(colour
) ) 
2294         // colour didn't really change 
2300         // rich edit doesn't use WM_CTLCOLOR, hence we need to send 
2301         // EM_SETBKGNDCOLOR additionally 
2302         ::SendMessage(GetHwnd(), EM_SETBKGNDCOLOR
, 0, wxColourToRGB(colour
)); 
2308 bool wxTextCtrl::SetForegroundColour(const wxColour
& colour
) 
2310     if ( !wxTextCtrlBase::SetForegroundColour(colour
) ) 
2312         // colour didn't really change 
2318         // change the colour of everything 
2321         cf
.cbSize 
= sizeof(cf
); 
2322         cf
.dwMask 
= CFM_COLOR
; 
2323         cf
.crTextColor 
= wxColourToRGB(colour
); 
2324         ::SendMessage(GetHwnd(), EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf
); 
2330 // ---------------------------------------------------------------------------- 
2331 // styling support for rich edit controls 
2332 // ---------------------------------------------------------------------------- 
2334 bool wxTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
2338         // can't do it with normal text control 
2342     // the richedit 1.0 doesn't handle setting background colour, so don't 
2343     // even try to do anything if it's the only thing we want to change 
2344     if ( m_verRichEdit 
== 1 && !style
.HasFont() && !style
.HasTextColour() && 
2345         !style
.HasLeftIndent() && !style
.HasRightIndent() && !style
.HasAlignment() && 
2348         // nothing to do: return true if there was really nothing to do and 
2349         // false if we failed to set bg colour 
2350         return !style
.HasBackgroundColour(); 
2353     // order the range if needed 
2361     // we can only change the format of the selection, so select the range we 
2362     // want and restore the old selection later 
2363     long startOld
, endOld
; 
2364     GetSelection(&startOld
, &endOld
); 
2366     // but do we really have to change the selection? 
2367     bool changeSel 
= start 
!= startOld 
|| end 
!= endOld
; 
2371         DoSetSelection(start
, end
, SetSel_NoScroll
); 
2374     // initialize CHARFORMAT struct 
2383     // we can't use CHARFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2384     // CHARFORMAT in that case 
2386     if ( m_verRichEdit 
== 1 ) 
2388         // this is the only thing the control is going to grok 
2389         cf
.cbSize 
= sizeof(CHARFORMAT
); 
2394         // CHARFORMAT or CHARFORMAT2 
2395         cf
.cbSize 
= sizeof(cf
); 
2398     if ( style
.HasFont() ) 
2400         // VZ: CFM_CHARSET doesn't seem to do anything at all in RichEdit 2.0 
2401         //     but using it doesn't seem to hurt neither so leaving it for now 
2403         cf
.dwMask 
|= CFM_FACE 
| CFM_SIZE 
| CFM_CHARSET 
| 
2404                      CFM_ITALIC 
| CFM_BOLD 
| CFM_UNDERLINE
; 
2406         // fill in data from LOGFONT but recalculate lfHeight because we need 
2407         // the real height in twips and not the negative number which 
2408         // wxFillLogFont() returns (this is correct in general and works with 
2409         // the Windows font mapper, but not here) 
2411         wxFont 
font(style
.GetFont()); 
2414         wxFillLogFont(&lf
, &font
); 
2415         cf
.yHeight 
= 20*font
.GetPointSize(); // 1 pt = 20 twips 
2416         cf
.bCharSet 
= lf
.lfCharSet
; 
2417         cf
.bPitchAndFamily 
= lf
.lfPitchAndFamily
; 
2418         wxStrncpy( cf
.szFaceName
, lf
.lfFaceName
, WXSIZEOF(cf
.szFaceName
) ); 
2420         // also deal with underline/italic/bold attributes: note that we must 
2421         // always set CFM_ITALIC &c bits in dwMask, even if we don't set the 
2422         // style to allow clearing it 
2425             cf
.dwEffects 
|= CFE_ITALIC
; 
2428         if ( lf
.lfWeight 
== FW_BOLD 
) 
2430             cf
.dwEffects 
|= CFE_BOLD
; 
2433         if ( lf
.lfUnderline 
) 
2435             cf
.dwEffects 
|= CFE_UNDERLINE
; 
2438         // strikeout fonts are not supported by wxWidgets 
2441     if ( style
.HasTextColour() ) 
2443         cf
.dwMask 
|= CFM_COLOR
; 
2444         cf
.crTextColor 
= wxColourToRGB(style
.GetTextColour()); 
2448     if ( m_verRichEdit 
!= 1 && style
.HasBackgroundColour() ) 
2450         cf
.dwMask 
|= CFM_BACKCOLOR
; 
2451         cf
.crBackColor 
= wxColourToRGB(style
.GetBackgroundColour()); 
2453 #endif // wxUSE_RICHEDIT2 
2455     // do format the selection 
2456     bool ok 
= ::SendMessage(GetHwnd(), EM_SETCHARFORMAT
, 
2457                             SCF_SELECTION
, (LPARAM
)&cf
) != 0; 
2460         wxLogDebug(_T("SendMessage(EM_SETCHARFORMAT, SCF_SELECTION) failed")); 
2463     // now do the paragraph formatting 
2466     // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2467     // PARAFORMAT in that case 
2469     if ( m_verRichEdit 
== 1 ) 
2471         // this is the only thing the control is going to grok 
2472         pf
.cbSize 
= sizeof(PARAFORMAT
); 
2477         // PARAFORMAT or PARAFORMAT2 
2478         pf
.cbSize 
= sizeof(pf
); 
2481     if (style
.HasAlignment()) 
2483         pf
.dwMask 
|= PFM_ALIGNMENT
; 
2484         if (style
.GetAlignment() == wxTEXT_ALIGNMENT_RIGHT
) 
2485             pf
.wAlignment 
= PFA_RIGHT
; 
2486         else if (style
.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
) 
2487             pf
.wAlignment 
= PFA_CENTER
; 
2488         else if (style
.GetAlignment() == wxTEXT_ALIGNMENT_JUSTIFIED
) 
2489             pf
.wAlignment 
= PFA_JUSTIFY
; 
2491             pf
.wAlignment 
= PFA_LEFT
; 
2494     if (style
.HasLeftIndent()) 
2496         pf
.dwMask 
|= PFM_STARTINDENT 
| PFM_OFFSET
; 
2498         // Convert from 1/10 mm to TWIPS 
2499         pf
.dxStartIndent 
= (int) (((double) style
.GetLeftIndent()) * mm2twips 
/ 10.0) ; 
2500         pf
.dxOffset 
= (int) (((double) style
.GetLeftSubIndent()) * mm2twips 
/ 10.0) ; 
2503     if (style
.HasRightIndent()) 
2505         pf
.dwMask 
|= PFM_RIGHTINDENT
; 
2507         // Convert from 1/10 mm to TWIPS 
2508         pf
.dxRightIndent 
= (int) (((double) style
.GetRightIndent()) * mm2twips 
/ 10.0) ; 
2511     if (style
.HasTabs()) 
2513         pf
.dwMask 
|= PFM_TABSTOPS
; 
2515         const wxArrayInt
& tabs 
= style
.GetTabs(); 
2517         pf
.cTabCount 
= (SHORT
)wxMin(tabs
.GetCount(), MAX_TAB_STOPS
); 
2519         for (i 
= 0; i 
< (size_t) pf
.cTabCount
; i
++) 
2521             // Convert from 1/10 mm to TWIPS 
2522             pf
.rgxTabs
[i
] = (int) (((double) tabs
[i
]) * mm2twips 
/ 10.0) ; 
2527     if ( m_verRichEdit 
> 1 ) 
2529         if ( wxTheApp
->GetLayoutDirection() == wxLayout_RightToLeft 
) 
2531             // Use RTL paragraphs in RTL mode to get proper layout 
2532             pf
.dwMask 
|= PFM_RTLPARA
; 
2533             pf
.wEffects 
|= PFE_RTLPARA
; 
2536 #endif // wxUSE_RICHEDIT2 
2540         // do format the selection 
2541         bool ok 
= ::SendMessage(GetHwnd(), EM_SETPARAFORMAT
, 
2542                                 0, (LPARAM
) &pf
) != 0; 
2545             wxLogDebug(_T("SendMessage(EM_SETPARAFORMAT, 0) failed")); 
2551         // restore the original selection 
2552         DoSetSelection(startOld
, endOld
, SetSel_NoScroll
); 
2558 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
2560     if ( !wxTextCtrlBase::SetDefaultStyle(style
) ) 
2565         // we have to do this or the style wouldn't apply for the text typed by 
2567         wxTextPos posLast 
= GetLastPosition(); 
2568         SetStyle(posLast
, posLast
, m_defaultStyle
); 
2574 bool wxTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
2578         // can't do it with normal text control 
2582     // initialize CHARFORMAT struct 
2591     // we can't use CHARFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2592     // CHARFORMAT in that case 
2594     if ( m_verRichEdit 
== 1 ) 
2596         // this is the only thing the control is going to grok 
2597         cf
.cbSize 
= sizeof(CHARFORMAT
); 
2602         // CHARFORMAT or CHARFORMAT2 
2603         cf
.cbSize 
= sizeof(cf
); 
2605     // we can only change the format of the selection, so select the range we 
2606     // want and restore the old selection later 
2607     long startOld
, endOld
; 
2608     GetSelection(&startOld
, &endOld
); 
2610     // but do we really have to change the selection? 
2611     bool changeSel 
= position 
!= startOld 
|| position 
!= endOld
; 
2615         DoSetSelection(position
, position 
+ 1, SetSel_NoScroll
); 
2618     // get the selection formatting 
2619     (void) ::SendMessage(GetHwnd(), EM_GETCHARFORMAT
, 
2620                             SCF_SELECTION
, (LPARAM
)&cf
) ; 
2624     lf
.lfHeight 
= cf
.yHeight
; 
2626     lf
.lfCharSet 
= ANSI_CHARSET
; // FIXME: how to get correct charset? 
2627     lf
.lfClipPrecision 
= 0; 
2628     lf
.lfEscapement 
= 0; 
2629     wxStrcpy(lf
.lfFaceName
, cf
.szFaceName
); 
2631     //NOTE:  we _MUST_ set each of these values to _something_ since we 
2632     //do not call wxZeroMemory on the LOGFONT lf 
2633     if (cf
.dwEffects 
& CFE_ITALIC
) 
2636         lf
.lfItalic 
= FALSE
; 
2638     lf
.lfOrientation 
= 0; 
2639     lf
.lfPitchAndFamily 
= cf
.bPitchAndFamily
; 
2642     if (cf
.dwEffects 
& CFE_STRIKEOUT
) 
2643         lf
.lfStrikeOut 
= TRUE
; 
2645         lf
.lfStrikeOut 
= FALSE
; 
2647     if (cf
.dwEffects 
& CFE_UNDERLINE
) 
2648         lf
.lfUnderline 
= TRUE
; 
2650         lf
.lfUnderline 
= FALSE
; 
2652     if (cf
.dwEffects 
& CFE_BOLD
) 
2653         lf
.lfWeight 
= FW_BOLD
; 
2655         lf
.lfWeight 
= FW_NORMAL
; 
2657     wxFont font 
= wxCreateFontFromLogFont(& lf
); 
2660         style
.SetFont(font
); 
2662     style
.SetTextColour(wxColour(cf
.crTextColor
)); 
2665     if ( m_verRichEdit 
!= 1 ) 
2667         // cf.dwMask |= CFM_BACKCOLOR; 
2668         style
.SetBackgroundColour(wxColour(cf
.crBackColor
)); 
2670 #endif // wxUSE_RICHEDIT2 
2672     // now get the paragraph formatting 
2675     // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2676     // PARAFORMAT in that case 
2678     if ( m_verRichEdit 
== 1 ) 
2680         // this is the only thing the control is going to grok 
2681         pf
.cbSize 
= sizeof(PARAFORMAT
); 
2686         // PARAFORMAT or PARAFORMAT2 
2687         pf
.cbSize 
= sizeof(pf
); 
2690     // do format the selection 
2691     (void) ::SendMessage(GetHwnd(), EM_GETPARAFORMAT
, 0, (LPARAM
) &pf
) ; 
2693     style
.SetLeftIndent( (int) ((double) pf
.dxStartIndent 
* twips2mm 
* 10.0), (int) ((double) pf
.dxOffset 
* twips2mm 
* 10.0) ); 
2694     style
.SetRightIndent( (int) ((double) pf
.dxRightIndent 
* twips2mm 
* 10.0) ); 
2696     if (pf
.wAlignment 
== PFA_CENTER
) 
2697         style
.SetAlignment(wxTEXT_ALIGNMENT_CENTRE
); 
2698     else if (pf
.wAlignment 
== PFA_RIGHT
) 
2699         style
.SetAlignment(wxTEXT_ALIGNMENT_RIGHT
); 
2700     else if (pf
.wAlignment 
== PFA_JUSTIFY
) 
2701         style
.SetAlignment(wxTEXT_ALIGNMENT_JUSTIFIED
); 
2703         style
.SetAlignment(wxTEXT_ALIGNMENT_LEFT
); 
2705     wxArrayInt tabStops
; 
2707     for (i 
= 0; i 
< (size_t) pf
.cTabCount
; i
++) 
2709         tabStops
.Add( (int) ((double) (pf
.rgxTabs
[i
] & 0xFFFF) * twips2mm 
* 10.0) ); 
2714         // restore the original selection 
2715         DoSetSelection(startOld
, endOld
, SetSel_NoScroll
); 
2721 // ---------------------------------------------------------------------------- 
2723 // ---------------------------------------------------------------------------- 
2725 static const HINSTANCE INVALID_HINSTANCE 
= (HINSTANCE
)-1; 
2727 bool wxRichEditModule::OnInit() 
2729     // don't do anything - we will load it when needed 
2733 void wxRichEditModule::OnExit() 
2735     for ( size_t i 
= 0; i 
< WXSIZEOF(ms_hRichEdit
); i
++ ) 
2737         if ( ms_hRichEdit
[i
] && ms_hRichEdit
[i
] != INVALID_HINSTANCE 
) 
2739             ::FreeLibrary(ms_hRichEdit
[i
]); 
2740             ms_hRichEdit
[i
] = NULL
; 
2744     if (ms_inkEditLib
.IsLoaded()) 
2745         ms_inkEditLib
.Unload(); 
2750 bool wxRichEditModule::Load(Version version
) 
2752     if ( ms_hRichEdit
[version
] == INVALID_HINSTANCE 
) 
2754         // we had already tried to load it and failed 
2758     if ( ms_hRichEdit
[version
] ) 
2760         // we've already got this one 
2764     static const wxChar 
*dllnames
[] = 
2771     wxCOMPILE_TIME_ASSERT( WXSIZEOF(dllnames
) == Version_Max
, 
2772                             RichEditDllNamesVersionsMismatch 
); 
2774     ms_hRichEdit
[version
] = ::LoadLibrary(dllnames
[version
]); 
2776     if ( !ms_hRichEdit
[version
] ) 
2778         ms_hRichEdit
[version
] = INVALID_HINSTANCE
; 
2787 // load the InkEdit library 
2788 bool wxRichEditModule::LoadInkEdit() 
2790     static wxDynamicLibrary ms_inkEditLib
; 
2791     static bool             ms_inkEditLibLoadAttemped
; 
2792     if (ms_inkEditLibLoadAttemped
) 
2793         ms_inkEditLib
.IsLoaded(); 
2795     ms_inkEditLibLoadAttemped 
= true; 
2798     return ms_inkEditLib
.Load(wxT("inked")); 
2800 #endif // wxUSE_INKEDIT 
2803 #endif // wxUSE_RICHEDIT 
2805 #endif // wxUSE_TEXTCTRL && !(__SMARTPHONE__ && __WXWINCE__)