textctrl.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,166 行 · 第 1/5 页
CPP
2,166 行
#if wxUSE_RICHEDIT
wxString classname = wxGetWindowClass(GetHWND());
if ( classname.IsSameAs(_T("EDIT"), false /* no case */) )
{
m_verRichEdit = 0;
}
else // rich edit?
{
wxChar c;
if ( wxSscanf(classname, _T("RichEdit%d0%c"), &m_verRichEdit, &c) != 2 )
{
wxLogDebug(_T("Unknown edit control '%s'."), classname.c_str());
m_verRichEdit = 0;
}
}
#endif // wxUSE_RICHEDIT
if (style & ES_MULTILINE)
m_windowStyle |= wxTE_MULTILINE;
if (style & ES_PASSWORD)
m_windowStyle |= wxTE_PASSWORD;
if (style & ES_READONLY)
m_windowStyle |= wxTE_READONLY;
if (style & ES_WANTRETURN)
m_windowStyle |= wxTE_PROCESS_ENTER;
if (style & ES_CENTER)
m_windowStyle |= wxTE_CENTRE;
if (style & ES_RIGHT)
m_windowStyle |= wxTE_RIGHT;
}
WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
{
long msStyle = wxControl::MSWGetStyle(style, exstyle);
// styles which we alaways add by default
if ( style & wxTE_MULTILINE )
{
wxASSERT_MSG( !(style & wxTE_PROCESS_ENTER),
wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
msStyle |= ES_MULTILINE | ES_WANTRETURN;
if ( !(style & wxTE_NO_VSCROLL) )
{
// always adjust the vertical scrollbar automatically if we have it
msStyle |= WS_VSCROLL | ES_AUTOVSCROLL;
#if wxUSE_RICHEDIT
// we have to use this style for the rich edit controls because
// without it the vertical scrollbar never appears at all in
// richedit 3.0 because of our ECO_NOHIDESEL hack (search for it)
if ( style & wxTE_RICH2 )
{
msStyle |= ES_DISABLENOSCROLL;
}
#endif // wxUSE_RICHEDIT
}
style |= wxTE_PROCESS_ENTER;
}
else // !multiline
{
// there is really no reason to not have this style for single line
// text controls
msStyle |= ES_AUTOHSCROLL;
}
// note that wxTE_DONTWRAP is the same as wxHSCROLL so if we have a horz
// scrollbar, there is no wrapping -- which makes sense
if ( style & wxTE_DONTWRAP )
{
// automatically scroll the control horizontally as necessary
//
// NB: ES_AUTOHSCROLL is needed for richedit controls or they don't
// show horz scrollbar at all, even in spite of WS_HSCROLL, and as
// it doesn't seem to do any harm for plain edit controls, add it
// always
msStyle |= WS_HSCROLL | ES_AUTOHSCROLL;
}
if ( style & wxTE_READONLY )
msStyle |= ES_READONLY;
if ( style & wxTE_PASSWORD )
msStyle |= ES_PASSWORD;
if ( style & wxTE_NOHIDESEL )
msStyle |= ES_NOHIDESEL;
// note that we can't do do "& wxTE_LEFT" as wxTE_LEFT == 0
if ( style & wxTE_CENTRE )
msStyle |= ES_CENTER;
else if ( style & wxTE_RIGHT )
msStyle |= ES_RIGHT;
else
msStyle |= ES_LEFT; // ES_LEFT is 0 as well but for consistency...
return msStyle;
}
void wxTextCtrl::SetWindowStyleFlag(long style)
{
#if wxUSE_RICHEDIT
// we have to deal with some styles separately because they can't be
// changed by simply calling SetWindowLong(GWL_STYLE) but can be changed
// using richedit-specific EM_SETOPTIONS
if ( IsRich() &&
((style & wxTE_NOHIDESEL) != (GetWindowStyle() & wxTE_NOHIDESEL)) )
{
bool set = (style & wxTE_NOHIDESEL) != 0;
::SendMessage(GetHwnd(), EM_SETOPTIONS, set ? ECOOP_OR : ECOOP_AND,
set ? ECO_NOHIDESEL : ~ECO_NOHIDESEL);
}
#endif // wxUSE_RICHEDIT
wxControl::SetWindowStyleFlag(style);
}
// ----------------------------------------------------------------------------
// set/get the controls text
// ----------------------------------------------------------------------------
wxString wxTextCtrl::GetValue() const
{
// range 0..-1 is special for GetRange() and means to retrieve all text
return GetRange(0, -1);
}
wxString wxTextCtrl::GetRange(long from, long to) const
{
wxString str;
if ( from >= to && to != -1 )
{
// nothing to retrieve
return str;
}
#if wxUSE_RICHEDIT
if ( IsRich() )
{
int len = GetWindowTextLength(GetHwnd());
if ( len > from )
{
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...)
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() )
{
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);
wxChar *p = tmp;
TEXTRANGE textRange;
textRange.chrg.cpMin = from;
textRange.chrg.cpMax = to;
textRange.lpstrText = p;
(void)::SendMessage(GetHwnd(), EM_GETTEXTRANGE,
0, (LPARAM)&textRange);
if ( m_verRichEdit > 1 )
{
// RichEdit 2.0 uses just CR ('\r') for the
// newlines which is neither Unix nor Windows
// style - convert it to something reasonable
for ( ; *p; p++ )
{
if ( *p == _T('\r') )
*p = _T('\n');
}
}
}
if ( m_verRichEdit == 1 )
{
// convert to the canonical form - see comment below
str = wxTextFile::Translate(str, wxTextFileType_Unix);
}
}
//else: no text at all, leave the string empty
}
else
#endif // wxUSE_RICHEDIT
{
// retrieve all text
str = wxGetWindowText(GetHWND());
// need only a range?
if ( from < to )
{
str = str.Mid(from, to - from);
}
// WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the
// canonical one (same one as above) for consistency with the other kinds
// of controls and, more importantly, with the other ports
str = wxTextFile::Translate(str, wxTextFileType_Unix);
}
return str;
}
void wxTextCtrl::SetValue(const wxString& value)
{
// if the text is long enough, it's faster to just set it instead of first
// comparing it with the old one (chances are that it will be different
// anyhow, this comparison is there to avoid flicker for small single-line
// edit controls mostly)
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
{
// still send an event for consistency
SendUpdateEvent();
}
// we should reset the modified flag even if the value didn't really change
// mark the control as being not dirty - we changed its text, not the
// user
DiscardEdits();
}
#if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU)
// TODO: using memcpy() would improve performance a lot for big amounts of text
DWORD CALLBACK
wxRichEditStreamIn(DWORD dwCookie, BYTE *buf, LONG cb, LONG *pcb)
{
*pcb = 0;
const wchar_t ** const ppws = (const wchar_t **)dwCookie;
wchar_t *wbuf = (wchar_t *)buf;
const wchar_t *wpc = *ppws;
while ( cb && *wpc )
{
*wbuf++ = *wpc++;
cb -= sizeof(wchar_t);
(*pcb) += sizeof(wchar_t);
}
*ppws = wpc;
return 0;
}
// helper struct used to pass parameters from wxTextCtrl to wxRichEditStreamOut
struct wxStreamOutData
{
wchar_t *wpc;
size_t len;
};
DWORD CALLBACK
wxRichEditStreamOut(DWORD_PTR dwCookie, BYTE *buf, LONG cb, LONG *pcb)
{
*pcb = 0;
wxStreamOutData *data = (wxStreamOutData *)dwCookie;
const wchar_t *wbuf = (const wchar_t *)buf;
wchar_t *wpc = data->wpc;
while ( cb )
{
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);
}
data->wpc = wpc;
return 0;
}
#if wxUSE_UNICODE_MSLU
#define UNUSED_IF_MSLU(param)
#else
#define UNUSED_IF_MSLU(param) param
#endif
bool
wxTextCtrl::StreamIn(const wxString& value,
wxFontEncoding UNUSED_IF_MSLU(encoding),
bool selectionOnly)
{
#if wxUSE_UNICODE_MSLU
const wchar_t *wpc = value.c_str();
#else // !wxUSE_UNICODE_MSLU
wxCSConv conv(encoding);
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
conv.MB2WC(wpc, value, value.length());
#endif // wxUSE_UNICODE_MSLU
// finally, stream it in the control
EDITSTREAM eds;
wxZeroMemory(eds);
eds.dwCookie = (DWORD)&wpc;
// the cast below is needed for broken (very) old mingw32 headers
eds.pfnCallback = (EDITSTREAMCALLBACK)wxRichEditStreamIn;
// same problem as in DoWriteText(): we can get multiple events here
UpdatesCountFilter ucf(m_updatesCount);
::SendMessage(GetHwnd(), EM_STREAMIN,
SF_TEXT |
SF_UNICODE |
(selectionOnly ? SFF_SELECTION : 0),
(LPARAM)&eds);
// It's okay for EN_UPDATE to not be sent if the selection is empty and
// the text is empty, otherwise warn the programmer about it.
wxASSERT_MSG( ucf.GotUpdate() || ( !HasSelection() && value.empty() ),
_T("EM_STREAMIN didn't send EN_UPDATE?") );
if ( eds.dwError )
{
wxLogLastError(_T("EM_STREAMIN"));
}
#if !wxUSE_WCHAR_T
free(wchBuf);
#endif // !wxUSE_WCHAR_T
return true;
}
#if !wxUSE_UNICODE_MSLU
wxString
wxTextCtrl::StreamOut(wxFontEncoding encoding, bool selectionOnly) const
{
wxString out;
const int len = GetWindowTextLength(GetHwnd());
#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
wxStreamOutData data;
data.wpc = wpc;
data.len = len;
EDITSTREAM eds;
wxZeroMemory(eds);
eds.dwCookie = (DWORD)&data;
eds.pfnCallback = wxRichEditStreamOut;
::SendMessage
(
GetHwnd(),
EM_STREAMOUT,
SF_TEXT | SF_UNICODE | (selectionOnly ? SFF_SELECTION : 0),
(LPARAM)&eds
);
if ( eds.dwError )
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?