wxFLAGS_MEMBER(wxDOUBLE_BORDER)
wxFLAGS_MEMBER(wxRAISED_BORDER)
wxFLAGS_MEMBER(wxSTATIC_BORDER)
- wxFLAGS_MEMBER(wxNO_BORDER)
+ wxFLAGS_MEMBER(wxBORDER)
// standard window styles
wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
wxFLAGS_MEMBER(wxCLIP_CHILDREN)
wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
wxFLAGS_MEMBER(wxWANTS_CHARS)
- wxFLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE)
+ wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
wxFLAGS_MEMBER(wxVSCROLL)
wxFLAGS_MEMBER(wxHSCROLL)
if ( to == -1 )
to = len;
+#if !wxUSE_UNICODE
// we must use EM_STREAMOUT if we don't want to lose all characters
// not representable in the current character set (EM_GETTEXTRANGE
// simply replaces them with question marks...)
- //
- // as EM_STREAMOUT only works for the entire controls contents (or
- // just the selection but it's probably a bad idea to play games
- // with selection here...), we can't use it unless we're called
- // from GetValue(), i.e. we want to retrieve all text
- if ( GetRichVersion() > 1 && (from == 0 && to >= len) )
+ if ( GetRichVersion() > 1 )
{
+ // we must have some encoding, otherwise any 8bit chars in the
+ // control are simply *lost* (replaced by '?')
+ wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
+
wxFont font = m_defaultStyle.GetFont();
if ( !font.Ok() )
font = GetFont();
if ( font.Ok() )
{
- wxFontEncoding encoding = font.GetEncoding();
- if ( encoding != wxFONTENCODING_SYSTEM )
- {
- str = StreamOut(encoding);
- }
+ encoding = font.GetEncoding();
+ }
+
+ if ( encoding == wxFONTENCODING_SYSTEM )
+ {
+ encoding = wxLocale::GetSystemEncoding();
+ }
+
+ if ( encoding == wxFONTENCODING_SYSTEM )
+ {
+ encoding = wxFONTENCODING_ISO8859_1;
+ }
+
+ str = StreamOut(encoding);
+
+ if ( !str.empty() )
+ {
+ // we have to manually extract the required part, luckily
+ // this is easy in this case as EOL characters in str are
+ // just LFs because we remove CRs in wxRichEditStreamOut
+ str = str.Mid(from, to - from);
}
}
// StreamOut() wasn't used or failed, try to do it in normal way
if ( str.empty() )
+#endif // !wxUSE_UNICODE
{
// alloc one extra WORD as needed by the control
wxStringBuffer tmp(str, ++len);
TEXTRANGE textRange;
textRange.chrg.cpMin = from;
- textRange.chrg.cpMax = to == -1 ? len : to;
+ textRange.chrg.cpMax = to;
textRange.lpstrText = p;
(void)SendMessage(GetHwnd(), EM_GETTEXTRANGE,
if ( (value.length() > 0x400) || (value != GetValue()) )
{
DoWriteText(value, FALSE /* not selection only */);
+
+ // for compatibility, don't move the cursor when doing SetValue()
+ SetInsertionPoint(0);
}
else // same text
{
// mark the control as being not dirty - we changed its text, not the
// user
DiscardEdits();
-
- // for compatibility, don't move the cursor when doing SetValue()
- SetInsertionPoint(0);
}
#if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU)
return 0;
}
+// helper struct used to pass parameters from wxTextCtrl to wxRichEditStreamOut
+struct wxStreamOutData
+{
+ wchar_t *wpc;
+ size_t len;
+};
+
DWORD CALLBACK
wxRichEditStreamOut(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb)
{
*pcb = 0;
- wchar_t ** const ppws = (wchar_t **)dwCookie;
+ wxStreamOutData *data = (wxStreamOutData *)dwCookie;
const wchar_t *wbuf = (const wchar_t *)buf;
- wchar_t *wpc = *ppws;
- while ( cb && *wpc )
+ wchar_t *wpc = data->wpc;
+ while ( cb )
{
- *wpc++ = *wbuf++;
+ wchar_t wch = *wbuf++;
+
+ // turn "\r\n" into "\n" on the fly
+ if ( wch != L'\r' )
+ *wpc++ = wch;
+ else
+ data->len--;
cb -= sizeof(wchar_t);
(*pcb) += sizeof(wchar_t);
}
- *ppws = wpc;
+ data->wpc = wpc;
return 0;
}
-// from utils.cpp
-extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding);
-
#if wxUSE_UNICODE_MSLU
#define UNUSED_IF_MSLU(param)
#else
#if wxUSE_UNICODE_MSLU
const wchar_t *wpc = value.c_str();
#else // !wxUSE_UNICODE_MSLU
- // we have to use EM_STREAMIN to force richedit control 2.0+ to show any
- // text in the non default charset -- otherwise it thinks it knows better
- // than we do and always shows it in the default one
+ wxCSConv conv(encoding);
- // first get the Windows code page for this encoding
- long codepage = wxEncodingToCodepage(encoding);
- if ( codepage == -1 )
- {
- // unknown encoding
- return FALSE;
- }
-
- // next translate to Unicode using this code page
- int len = ::MultiByteToWideChar(codepage, 0, value, -1, NULL, 0);
+ const size_t len = conv.MB2WC(NULL, value, value.length());
#if wxUSE_WCHAR_T
wxWCharBuffer wchBuf(len);
+ wchar_t *wpc = wchBuf.data();
#else
wchar_t *wchBuf = (wchar_t *)malloc((len + 1)*sizeof(wchar_t));
+ wchar_t *wpc = wchBuf;
#endif
- if ( !::MultiByteToWideChar(codepage, 0, value, -1,
- (wchar_t *)(const wchar_t *)wchBuf, len) )
- {
- wxLogLastError(_T("MultiByteToWideChar"));
- }
-
- // finally, stream it in the control
- const wchar_t *wpc = wchBuf;
+ conv.MB2WC(wpc, value, value.length());
#endif // wxUSE_UNICODE_MSLU
+ // finally, stream it in the control
EDITSTREAM eds;
wxZeroMemory(eds);
eds.dwCookie = (DWORD)&wpc;
wchar_t *wpc = wchBuf;
#endif
+ wxStreamOutData data;
+ data.wpc = wpc;
+ data.len = len;
+
EDITSTREAM eds;
wxZeroMemory(eds);
- eds.dwCookie = (DWORD)&wpc;
+ eds.dwCookie = (DWORD)&data;
eds.pfnCallback = wxRichEditStreamOut;
::SendMessage
}
else // streamed out ok
{
- // now convert to the given encoding (this is a lossful conversion but
- // what else can we do)
+ // NUL-terminate the string because its length could have been
+ // decreased by wxRichEditStreamOut
+ *(wchBuf.data() + data.len) = L'\0';
+
+ // now convert to the given encoding (this is a possibly lossful
+ // conversion but what else can we do)
wxCSConv conv(encoding);
- size_t lenNeeded = conv.WC2MB(NULL, wchBuf, len);
- if ( lenNeeded )
+ size_t lenNeeded = conv.WC2MB(NULL, wchBuf, 0);
+ if ( lenNeeded++ )
{
- conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, len);
+ conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, lenNeeded);
}
}
wxFontEncoding encoding = font.GetEncoding();
if ( encoding != wxFONTENCODING_SYSTEM )
{
+ // we have to use EM_STREAMIN to force richedit control 2.0+
+ // to show any text in the non default charset -- otherwise
+ // it thinks it knows better than we do and always shows it
+ // in the default one
done = StreamIn(valueDos, encoding, selectionOnly);
}
}
#endif // Win32/16
}
+// ----------------------------------------------------------------------------
+// Working with files
+// ----------------------------------------------------------------------------
+
+bool wxTextCtrl::LoadFile(const wxString& file)
+{
+ if ( wxTextCtrlBase::LoadFile(file) )
+ {
+ // update the size limit if needed
+ AdjustSpaceLimit();
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
// ----------------------------------------------------------------------------
// Editing
// ----------------------------------------------------------------------------
// 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());
+ DoWriteText(value, TRUE /* selection only */);
}
void wxTextCtrl::Remove(long from, long to)
Replace(from, to, wxEmptyString);
}
-bool wxTextCtrl::LoadFile(const wxString& file)
+bool wxTextCtrl::IsModified() const
{
- if ( wxTextCtrlBase::LoadFile(file) )
- {
- // update the size limit if needed
- AdjustSpaceLimit();
-
- return TRUE;
- }
-
- return FALSE;
+ return SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0;
}
-bool wxTextCtrl::IsModified() const
+void wxTextCtrl::MarkDirty()
{
- return SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0;
+ SendMessage(GetHwnd(), EM_SETMODIFY, TRUE, 0L);
}
-// Makes 'unmodified'
void wxTextCtrl::DiscardEdits()
{
SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L);
return (int)SendMessage(GetHwnd(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
}
+// ----------------------------------------------------------------------------
+// Positions <-> coords
+// ----------------------------------------------------------------------------
+
long wxTextCtrl::XYToPosition(long x, long y) const
{
// This gets the char index for the _beginning_ of this line
return TRUE;
}
+wxTextCtrlHitTestResult
+wxTextCtrl::HitTest(const wxPoint& pt, wxTextCoord *col, wxTextCoord *row) const
+{
+ // first get the position from Windows
+ LPARAM lParam;
+
+#if wxUSE_RICHEDIT
+ POINTL ptl;
+ if ( IsRich() )
+ {
+ // for rich edit controls the position is passed iva the struct fields
+ ptl.x = pt.x;
+ ptl.y = pt.y;
+ lParam = (LPARAM)&ptl;
+ }
+ else
+#endif // wxUSE_RICHEDIT
+ {
+ // for the plain ones, we are limited to 16 bit positions which are
+ // combined in a single 32 bit value
+ lParam = MAKELPARAM(pt.x, pt.y);
+ }
+
+ LRESULT pos = SendMessage(GetHwnd(), EM_CHARFROMPOS, 0, lParam);
+
+ if ( pos == -1 )
+ {
+ // this seems to indicate an error...
+ return wxTE_HT_UNKNOWN;
+ }
+
+#if wxUSE_RICHEDIT
+ if ( !IsRich() )
+#endif // wxUSE_RICHEDIT
+ {
+ // for plain EDIT controls the higher word contains something else
+ pos = LOWORD(pos);
+ }
+
+
+ // next determine where it is relatively to our point: EM_CHARFROMPOS
+ // always returns the closest character but we need to be more precise, so
+ // double check that we really are where it pretends
+ POINTL ptReal;
+
+#if wxUSE_RICHEDIT
+ // FIXME: we need to distinguish between richedit 2 and 3 here somehow but
+ // we don't know how to do it
+ if ( IsRich() )
+ {
+ SendMessage(GetHwnd(), EM_POSFROMCHAR, (WPARAM)&ptReal, pos);
+ }
+ else
+#endif // wxUSE_RICHEDIT
+ {
+ LRESULT lRc = SendMessage(GetHwnd(), EM_POSFROMCHAR, pos, 0);
+
+ if ( lRc == -1 )
+ {
+ // this is apparently returned when pos corresponds to the last
+ // position
+ ptReal.x =
+ ptReal.y = 0;
+ }
+ else
+ {
+ ptReal.x = LOWORD(lRc);
+ ptReal.y = HIWORD(lRc);
+ }
+ }
+
+ wxTextCtrlHitTestResult rc;
+
+ if ( pt.y > ptReal.y + GetCharHeight() )
+ rc = wxTE_HT_BELOW;
+ else if ( pt.x > ptReal.x + GetCharWidth() )
+ rc = wxTE_HT_BEYOND;
+ else
+ rc = wxTE_HT_ON_TEXT;
+
+ // finally translate to column/row
+ if ( !PositionToXY(pos, col, row) )
+ {
+ wxFAIL_MSG( _T("PositionToXY() not expected to fail in HitTest()") );
+ }
+
+ return rc;
+}
+
+// ----------------------------------------------------------------------------
+//
+// ----------------------------------------------------------------------------
+
void wxTextCtrl::ShowPosition(long pos)
{
HWND hWnd = GetHwnd();
switch ( event.GetKeyCode() )
{
case WXK_RETURN:
- if ( !(m_windowStyle & wxTE_MULTILINE) )
+ if ( !HasFlag(wxTE_MULTILINE) )
{
wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
InitCommandEvent(event);
break;
case WXK_TAB:
- // always produce navigation event - even if we process TAB
+ // always produce navigation event -- even if we process TAB
// ourselves the fact that we got here means that the user code
- // decided to skip processing of this TAB - probably to let it
+ // decided to skip processing of this TAB -- probably to let it
// do its default job.
+
+ // ok, so this is getting absolutely ridiculous but I don't see
+ // any other way to fix this bug: when a multiline text control is
+ // inside a wxFrame, we need to generate the navigation event as
+ // otherwise nothing happens at all, but when the same control is
+ // created inside a dialog, IsDialogMessage() *does* switch focus
+ // all by itself and so if we do it here as well, it is advanced
+ // twice and goes to the next control... to prevent this from
+ // happening we're doing this ugly check, the logic being that if
+ // we don't have focus then it had been already changed to the next
+ // control
+ //
+ // the right thing to do would, of course, be to understand what
+ // the hell is IsDialogMessage() doing but this is beyond my feeble
+ // forces at the moment unfortunately
+ if ( FindFocus() == this )
{
wxNavigationKeyEvent eventNav;
eventNav.SetDirection(!event.ShiftDown());