Add RTF support to wxMSW wxTextCtrl too

Make IsRTFSupported() non-static function as RTF is only supported by
some (rich), but not all, wxTextCtrls under Windows.

Closes #24718.
This commit is contained in:
Blake-Madden
2024-08-12 01:16:24 +02:00
committed by Vadim Zeitlin
parent 78bc9f24f3
commit 44a16be3d8
8 changed files with 108 additions and 24 deletions
+6
View File
@@ -40,6 +40,12 @@ public:
virtual wxString GetValue() const override;
virtual wxString GetRange(long from, long to) const override;
#if wxUSE_RICHEDIT
virtual wxString GetRTFValue() const override;
virtual void SetRTFValue(const wxString& val) override;
virtual bool IsRTFSupported() override { return IsRich(); }
#endif // wxUSE_RICHEDIT
virtual bool IsEmpty() const;
virtual void WriteText(const wxString& text) override;
+2
View File
@@ -718,6 +718,8 @@ public :
virtual bool CanClipMaxLength() const { return false; }
virtual void SetMaxLength(unsigned long WXUNUSED(len)) {}
virtual bool IsRTFSupported() { return false; }
virtual bool CanForceUpper() { return false; }
virtual void ForceUpper() {}
+1
View File
@@ -111,6 +111,7 @@ public:
virtual wxString GetRTFValue() const override;
virtual void SetRTFValue(const wxString& val) override;
virtual bool IsRTFSupported() override { return IsMultiLine(); }
// callbacks
void OnDropFiles(wxDropFilesEvent& event);
+4 -4
View File
@@ -103,10 +103,10 @@ const wxTextCoord wxInvalidTextCoord = -2;
// wxTextCtrl file types
// ----------------------------------------------------------------------------
// For now only wxOSX supports RTF in wxTextCtrl.
#ifdef __WXOSX__
// wxOSX and wxMSW support RTF in wxTextCtrl.
#if defined(__WXOSX__) || (defined(__WXMSW__) && wxUSE_RICHEDIT)
#define wxHAS_TEXTCTRL_RTF
#endif // __WXOSX__
#endif
enum wxTextCtrlFileType
{
@@ -691,7 +691,7 @@ public:
virtual void SetValue(const wxString& value) = 0;
// Returns whether the RTF-related functions below can be used.
static bool IsRTFSupported();
virtual bool IsRTFSupported() { return false; }
// Base class implementations simply assert, if IsRTFSupported() returns
// true, the port must override these functions to really implement them.
+5 -4
View File
@@ -76,7 +76,7 @@ enum wxTextCtrlFileType
/**
Rich Text Format.
This format is only supported under macOS currently.
This format is only supported under macOS and MSW.
@since 3.3.0
*/
@@ -1659,14 +1659,15 @@ public:
Returns @c true if text controls support reading and writing RTF (Rich
Text Format).
Currently this function only returns true in wxOSX, which is the only
port implementing RTF support in wxTextCtrl.
This function only returns @true in wxOSX (for multiline contrls) and
wxMSW (for rich controls), which are the only ports implementing
RTF support in wxTextCtrl.
@since 3.3.0
@see GetRTFValue(), SetRTFValue()
*/
static bool IsRTFSupported();
bool IsRTFSupported();
/**
Returns the content of a multiline text control as RTF (Rich Text
+4 -6
View File
@@ -479,13 +479,12 @@ bool MyApp::OnInit()
file_menu->Append(TEXT_LOAD, "&Load file\tCtrl-O",
"Load the sample file into text control");
if ( wxTextCtrl::IsRTFSupported() )
{
#ifdef wxHAS_TEXTCTRL_RTF
file_menu->Append(TEXT_SAVE_RTF, "&Save file as RTF",
"Save the text control contents to file");
file_menu->Append(TEXT_LOAD_RTF, "&Load RTF file",
"Load the sample file into text control");
}
#endif
file_menu->AppendSeparator();
file_menu->Append(TEXT_RICH_TEXT_TEST, "Show Rich Text Editor");
@@ -534,11 +533,10 @@ bool MyApp::OnInit()
menuText->Append(TEXT_SELECT, "&Select characters 4 to 8\tCtrl-I");
menuText->Append(TEXT_SET, "&Set the first text zone value\tCtrl-E");
menuText->Append(TEXT_CHANGE, "&Change the first text zone value\tShift-Ctrl-E");
if ( wxTextCtrl::IsRTFSupported() )
{
#ifdef wxHAS_TEXTCTRL_RTF
menuText->AppendSeparator();
menuText->Append(TEXT_SET_RTF, "Set the rich text zone value from rich text formatted content");
}
#endif
menuText->AppendSeparator();
menuText->Append(TEXT_MOVE_ENDTEXT, "Move cursor to the end of &text");
menuText->Append(TEXT_MOVE_ENDENTRY, "Move cursor to the end of &entry");
-10
View File
@@ -931,16 +931,6 @@ bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style)
return true;
}
// static
bool wxTextAreaBase::IsRTFSupported()
{
#ifdef wxHAS_TEXTCTRL_RTF
return true;
#else
return false;
#endif
}
wxString wxTextAreaBase::GetRTFValue() const
{
wxFAIL_MSG("Not implemented for the current platform.");
+86
View File
@@ -1114,6 +1114,92 @@ void wxTextCtrl::DoSetValue(const wxString& value, int flags)
}
}
#if wxUSE_RICHEDIT
DWORD wxCALLBACK MSWEditStreamOutCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
LONG cb, LONG* pcb)
{
// write the text
std::string* psEntry = reinterpret_cast<std::string*>(dwCookie);
psEntry->append(reinterpret_cast<const char*>(pbBuff), cb);
*pcb = cb;
return 0;
}
wxString wxTextCtrl::GetRTFValue() const
{
if ( !IsRich() )
{
wxFAIL_MSG("RTF support is only available for rich controls!");
return wxEmptyString;
}
// The Rich Edit control must write to a char buffer,
// which we will later convert to a Unicode wxString using the current code page.
//
// We will reserve enough space assuming that the RTF will be twice as large
// as the unencoded content.
std::string buffer;
buffer.reserve(GetLastPosition() * 2);
// Use a EDITSTREAMCALLBACK to stream text out from the control.
EDITSTREAM es{ 0 };
es.dwError = 0;
es.pfnCallback = MSWEditStreamOutCallback;
// our callback will write to a char buffer (i.e., std::string)
es.dwCookie = reinterpret_cast<DWORD_PTR>(&buffer);
// Do NOT call with "(CP_UTF8 << 16) | SF_USECODEPAGE", as this will format the
// output RTF to UTF-8 with a "urtf1" header (note the 'u').
// Although this is a more modern format, few programs
// (including Microsoft Wordpad) recognize it.
//
// Instead, write the content to an ANSI string using the current code page
// (which will use a "rtf1" header). The control will encode any Unicode values
// outside of the current code page with "\'[0-9A-F][0-9A-F]" syntax that most
// parsers would support.
//
// Finally, use SFF_PLAINRTF so that the generated RTF is more portable between
// RTF readers.
::SendMessage(GetHwnd(), EM_STREAMOUT,
(WPARAM)(SF_RTF | SFF_PLAINRTF), (LPARAM)&es);
// Valid RTF is supposed to consist of 7-bit ASCII characters only,
// anything else is escaped.
return wxString::FromAscii(buffer.c_str(), buffer.length());
}
void wxTextCtrl::SetRTFValue(const wxString& val)
{
wxCHECK_RET(IsRich(), "RTF support is only available for rich controls!");
SETTEXTEX textInfo{ 0 };
textInfo.flags = ST_DEFAULT | ST_UNICODE;
textInfo.codepage = 1200;
// Setting from Unicode will fail if control is read-only
// (this is an undocumented "feature"), so we need to toggle that temporarily.
const bool
isReadOnly = (::GetWindowLong(GetHwnd(), GWL_STYLE) & ES_READONLY) != 0;
if ( isReadOnly )
{
::SendMessage(GetHwnd(), EM_SETREADONLY, FALSE, 0);
}
::SendMessage(GetHwnd(), EM_SETTEXTEX, (WPARAM)&textInfo,
(LPARAM)static_cast<const wchar_t*>(val.wc_str()));
if ( isReadOnly )
{
::SendMessage(GetHwnd(), EM_SETREADONLY, TRUE, 0);
}
SetInsertionPoint(0);
}
#endif // wxUSE_RICHEDIT
void wxTextCtrl::WriteText(const wxString& value)
{
DoWriteText(value);