summaryrefslogtreecommitdiff
path: root/wx+/no_flicker.h
diff options
context:
space:
mode:
Diffstat (limited to 'wx+/no_flicker.h')
-rw-r--r--wx+/no_flicker.h81
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
bgstack15