diff options
Diffstat (limited to 'wx+/no_flicker.h')
-rw-r--r-- | wx+/no_flicker.h | 81 |
1 files changed, 79 insertions, 2 deletions
diff --git a/wx+/no_flicker.h b/wx+/no_flicker.h index 03969c00..53e47bb5 100644 --- a/wx+/no_flicker.h +++ b/wx+/no_flicker.h @@ -7,13 +7,18 @@ #ifndef NO_FLICKER_H_893421590321532 #define NO_FLICKER_H_893421590321532 +#include <zen/string_tools.h> +#include <zen/scope_guard.h> #include <wx/textctrl.h> #include <wx/stattext.h> +#include <wx/richtext/richtextctrl.h> +#include <wx/wupdlock.h> namespace zen { -inline +namespace +{ void setText(wxTextCtrl& control, const wxString& newText, bool* additionalLayoutChange = nullptr) { const wxString& label = control.GetValue(); //perf: don't call twice! @@ -24,7 +29,7 @@ void setText(wxTextCtrl& control, const wxString& newText, bool* additionalLayou control.ChangeValue(newText); } -inline + void setText(wxStaticText& control, wxString newText, bool* additionalLayoutChange = nullptr) { @@ -35,6 +40,78 @@ void setText(wxStaticText& control, wxString newText, bool* additionalLayoutChan if (label != newText) control.SetLabel(newText); } + + +void setTextWithUrls(wxRichTextCtrl& richCtrl, const wxString& newText) +{ + enum class BlockType + { + text, + url, + }; + std::vector<std::pair<BlockType, wxString>> blocks; + + for (auto it = newText.begin();;) + { + const wchar_t urlPrefix[] = L"https://"; + const auto itUrl = std::search(it, newText.end(), + urlPrefix, urlPrefix + strLength(urlPrefix)); + if (it != itUrl) + blocks.emplace_back(BlockType::text, wxString(it, itUrl)); + + if (itUrl == newText.end()) + break; + + auto itUrlEnd = std::find_if(itUrl, newText.end(), [](wchar_t c) { return isWhiteSpace(c); }); + blocks.emplace_back(BlockType::url, wxString(itUrl, itUrlEnd)); + it = itUrlEnd; + } + richCtrl.BeginSuppressUndo(); + ZEN_ON_SCOPE_EXIT(richCtrl.EndSuppressUndo()); + + //fix mouse scroll speed: why the FUCK is this even necessary! + richCtrl.SetLineHeight(richCtrl.GetCharHeight()); + + //get rid of margins and space between text blocks/"paragraphs" + richCtrl.SetMargins({0, 0}); + richCtrl.BeginParagraphSpacing(0, 0); + ZEN_ON_SCOPE_EXIT(richCtrl.EndParagraphSpacing()); + + richCtrl.Clear(); + + if (std::any_of(blocks.begin(), blocks.end(), [](const auto& item) { return item.first == BlockType::url; })) + { + wxRichTextAttr urlStyle; + urlStyle.SetTextColour(*wxBLUE); + urlStyle.SetFontUnderlined(true); + + for (const auto& [type, text] : blocks) + switch (type) + { + case BlockType::text: + richCtrl.WriteText(text); + break; + + case BlockType::url: + richCtrl.BeginStyle(urlStyle); + ZEN_ON_SCOPE_EXIT(richCtrl.EndStyle()); + richCtrl.BeginURL(text); + ZEN_ON_SCOPE_EXIT(richCtrl.EndURL()); + richCtrl.WriteText(text); + break; + } + + //register only once! => use a global function pointer, so that Unbind() works correctly: + using LaunchUrlFun = void(*)(wxTextUrlEvent& event); + static const LaunchUrlFun launchUrl = [](wxTextUrlEvent& event) { wxLaunchDefaultBrowser(event.GetString()); }; + + [[maybe_unused]] const bool unbindOk = richCtrl.Unbind(wxEVT_TEXT_URL, launchUrl); + richCtrl.Bind(wxEVT_TEXT_URL, launchUrl); + } + else + richCtrl.WriteText(newText); +} +} } #endif //NO_FLICKER_H_893421590321532 |