+ HWND hWnd = GetHwnd();
+
+#ifdef __WIN32__
+#if wxUSE_RICHEDIT
+ if ( IsRich() )
+ {
+ CHARRANGE range;
+ range.cpMin = from;
+ range.cpMax = to;
+ SendMessage(hWnd, EM_EXSETSEL, 0, (LPARAM) &range);
+ }
+ else
+#endif // wxUSE_RICHEDIT
+ {
+ SendMessage(hWnd, EM_SETSEL, (WPARAM)from, (LPARAM)to);
+ }
+
+ if ( scrollCaret )
+ {
+ SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
+ }
+#else // Win16
+ // WPARAM is 0: selection is scrolled into view
+ SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(from, to));
+#endif // Win32/16
+}
+
+// ----------------------------------------------------------------------------
+// Editing
+// ----------------------------------------------------------------------------
+
+void wxTextCtrl::Replace(long from, long to, const wxString& value)
+{
+ // Set selection and remove it
+ DoSetSelection(from, to, FALSE /* don't scroll caret into view */);
+
+ SendMessage(GetHwnd(), EM_REPLACESEL,
+#ifdef __WIN32__
+ TRUE,
+#else
+ FALSE,
+#endif
+ (LPARAM)value.c_str());
+}
+
+void wxTextCtrl::Remove(long from, long to)
+{
+ Replace(from, to, _T(""));
+}
+
+bool wxTextCtrl::LoadFile(const wxString& file)
+{
+ if ( wxTextCtrlBase::LoadFile(file) )
+ {
+ // update the size limit if needed
+ AdjustSpaceLimit();
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+bool wxTextCtrl::IsModified() const
+{
+ return SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0;
+}
+
+// Makes 'unmodified'
+void wxTextCtrl::DiscardEdits()
+{
+ SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L);
+}
+
+int wxTextCtrl::GetNumberOfLines() const
+{
+ return (int)SendMessage(GetHwnd(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
+}
+
+long wxTextCtrl::XYToPosition(long x, long y) const
+{
+ // This gets the char index for the _beginning_ of this line
+ long charIndex = SendMessage(GetHwnd(), EM_LINEINDEX, (WPARAM)y, (LPARAM)0);
+
+ return charIndex + x;
+}
+
+bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
+{
+ HWND hWnd = GetHwnd();
+
+ // This gets the line number containing the character
+ long lineNo;
+#if wxUSE_RICHEDIT
+ if ( IsRich() )
+ {
+ lineNo = SendMessage(hWnd, EM_EXLINEFROMCHAR, 0, (LPARAM)pos);
+ }
+ else
+#endif // wxUSE_RICHEDIT
+ {
+ lineNo = SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, 0);
+ }
+
+ if ( lineNo == -1 )
+ {
+ // no such line
+ return FALSE;
+ }
+
+ // This gets the char index for the _beginning_ of this line
+ long charIndex = SendMessage(hWnd, EM_LINEINDEX, (WPARAM)lineNo, (LPARAM)0);
+ if ( charIndex == -1 )
+ {
+ return FALSE;
+ }
+
+ // The X position must therefore be the different between pos and charIndex
+ if ( x )
+ *x = pos - charIndex;
+ if ( y )
+ *y = lineNo;
+
+ return TRUE;
+}
+
+void wxTextCtrl::ShowPosition(long pos)
+{
+ HWND hWnd = GetHwnd();
+
+ // To scroll to a position, we pass the number of lines and characters
+ // to scroll *by*. This means that we need to:
+ // (1) Find the line position of the current line.
+ // (2) Find the line position of pos.
+ // (3) Scroll by (pos - current).
+ // For now, ignore the horizontal scrolling.
+
+ // Is this where scrolling is relative to - the line containing the caret?
+ // Or is the first visible line??? Try first visible line.
+// int currentLineLineNo1 = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)-1, (LPARAM)0L);
+
+ int currentLineLineNo = (int)SendMessage(hWnd, EM_GETFIRSTVISIBLELINE, (WPARAM)0, (LPARAM)0L);
+
+ int specifiedLineLineNo = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+
+ int linesToScroll = specifiedLineLineNo - currentLineLineNo;
+
+ if (linesToScroll != 0)
+ (void)SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll);
+}
+
+long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const
+{
+ return ::SendMessage(GetHwnd(), EM_LINELENGTH, (WPARAM)pos, 0);
+}
+
+int wxTextCtrl::GetLineLength(long lineNo) const
+{
+ long pos = XYToPosition(0, lineNo);
+
+ return GetLengthOfLineContainingPos(pos);
+}
+
+wxString wxTextCtrl::GetLineText(long lineNo) const
+{
+ size_t len = (size_t)GetLineLength(lineNo) + 1;
+
+ // there must be at least enough place for the length WORD in the
+ // buffer
+ len += sizeof(WORD);
+
+ wxString str;
+ wxChar *buf = str.GetWriteBuf(len);
+
+ *(WORD *)buf = (WORD)len;
+ len = (size_t)::SendMessage(GetHwnd(), EM_GETLINE, lineNo, (LPARAM)buf);
+ buf[len] = 0;
+
+ str.UngetWriteBuf(len);
+
+ return str;
+}
+
+void wxTextCtrl::SetMaxLength(unsigned long len)
+{
+ ::SendMessage(GetHwnd(), EM_LIMITTEXT, len, 0);
+}
+
+// ----------------------------------------------------------------------------
+// Undo/redo
+// ----------------------------------------------------------------------------
+
+void wxTextCtrl::Undo()
+{
+ if (CanUndo())
+ {
+ ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
+ }
+}
+
+void wxTextCtrl::Redo()
+{
+ if (CanRedo())
+ {
+ // Same as Undo, since Undo undoes the undo, i.e. a redo.
+ ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
+ }
+}
+
+bool wxTextCtrl::CanUndo() const
+{
+ return ::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0;
+}
+
+bool wxTextCtrl::CanRedo() const
+{
+ return ::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0;
+}
+
+// ----------------------------------------------------------------------------
+// implemenation details
+// ----------------------------------------------------------------------------
+
+void wxTextCtrl::Command(wxCommandEvent & event)
+{
+ SetValue(event.GetString());
+ ProcessCommand (event);
+}
+
+void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
+{
+ // By default, load the first file into the text window.
+ if (event.GetNumberOfFiles() > 0)
+ {
+ LoadFile(event.GetFiles()[0]);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// kbd input processing
+// ----------------------------------------------------------------------------
+
+bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG* pMsg)
+{
+ MSG *msg = (MSG *)pMsg;
+
+ // check for our special keys here: if we don't do it and the parent frame
+ // uses them as accelerators, they wouldn't work at all, so we disable
+ // usual preprocessing for them
+ if ( msg->message == WM_KEYDOWN )
+ {
+ WORD vkey = (WORD) msg->wParam;
+ if ( (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN )
+ {
+ if ( vkey == VK_BACK )
+ return FALSE;
+ }
+ else // no Alt