diff --git a/src/GUIStuff/Elements/ColorPicker.hpp b/src/GUIStuff/Elements/ColorPicker.hpp index 8916072..d906f35 100644 --- a/src/GUIStuff/Elements/ColorPicker.hpp +++ b/src/GUIStuff/Elements/ColorPicker.hpp @@ -26,7 +26,7 @@ template class ColorPicker : public Element { .layout = { .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) } }, - .aspectRatio = 1.0f, + .aspectRatio = {1.0f}, .custom = { .customData = this } }) { selection.update(Clay_Hovered(), io.mouse.leftClick, io.mouse.leftHeld); diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 5e37b92..75eef0b 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -141,6 +141,7 @@ std::string InputManager::get_clipboard_data_for_mimetype(const std::string& mim void InputManager::set_clipboard_str(std::string_view s) { #ifdef __EMSCRIPTEN__ emscripten_browser_clipboard::copy(std::string(s)); + lastCopiedRichText = std::nullopt; #else SDL_SetClipboardText(s.data()); #endif @@ -150,13 +151,14 @@ std::string InputManager::get_infpnt_richtext_mimetype() { return "web text/infpnt"; } -void InputManager::set_clipboard_plain_and_richtext_pair(const std::pair& plainAndRichtextPair) { +void InputManager::set_clipboard_plain_and_richtext_pair(const std::pair& plainAndRichtextPair) { #ifdef __EMSCRIPTEN__ set_clipboard_str(plainAndRichtextPair.first); + lastCopiedRichText = plainAndRichtextPair.second; #else std::unordered_map clipboardData; clipboardData["text/plain"] = plainAndRichtextPair.first; - clipboardData[get_infpnt_richtext_mimetype()] = plainAndRichtextPair.second; + clipboardData[get_infpnt_richtext_mimetype()] = plainAndRichtextPair.second.get_serialized(); set_clipboard_data(clipboardData); #endif } @@ -385,11 +387,24 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) { void InputManager::process_text_paste() { if(text.textBox) { - std::string richTextClipboard = get_clipboard_data_for_mimetype(get_infpnt_richtext_mimetype()); - if(!richTextClipboard.empty()) - text.textBox->process_rich_text_input(*text.cursor, richTextClipboard); - else - text.textBox->process_text_input(*text.cursor, get_clipboard_data_for_mimetype("text/plain"), text.modMap); + #ifdef __EMSCRIPTEN__ + // Workaround for not being able to copy richtext to system clipboard, this should at least work within the application itself + std::string plainClipboardStr = get_clipboard_str(); + if(lastCopiedRichText.has_value()) { + if(lastCopiedRichText.value().get_plain_text() == plainClipboardStr) + text.textBox->process_rich_text_input(*text.cursor, lastCopiedRichText.value()); + else + text.textBox->process_text_input(*text.cursor, plainClipboardStr, text.modMap); + } + else + text.textBox->process_text_input(*text.cursor, plainClipboardStr, text.modMap); + #else + std::string richTextClipboard = get_clipboard_data_for_mimetype(get_infpnt_richtext_mimetype()); + if(!richTextClipboard.empty()) + text.textBox->process_rich_text_input(*text.cursor, RichText::TextData::deserialize_string(richTextClipboard)); + else + text.textBox->process_text_input(*text.cursor, get_clipboard_data_for_mimetype("text/plain"), text.modMap); + #endif } } diff --git a/src/InputManager.hpp b/src/InputManager.hpp index 8a1c479..f9e8bed 100644 --- a/src/InputManager.hpp +++ b/src/InputManager.hpp @@ -199,7 +199,7 @@ struct InputManager { std::string get_clipboard_data_for_mimetype(const std::string& mimeType); void set_clipboard_str(std::string_view s); - void set_clipboard_plain_and_richtext_pair(const std::pair& plainAndRichtextPair); + void set_clipboard_plain_and_richtext_pair(const std::pair& plainAndRichtextPair); void set_clipboard_data(const std::unordered_map& newClipboardData); void process_text_paste(); @@ -210,6 +210,7 @@ struct InputManager { #ifdef __EMSCRIPTEN__ bool clipboardPasteEventHappened = false; std::unordered_map clipboardPasteEventData; + std::optional lastCopiedRichText; #endif std::string key_assignment_to_str(const Vector2ui32& k); diff --git a/src/RichText/TextBox.cpp b/src/RichText/TextBox.cpp index 9d38002..9035812 100644 --- a/src/RichText/TextBox.cpp +++ b/src/RichText/TextBox.cpp @@ -1,4 +1,5 @@ #include "TextBox.hpp" +#include "Helpers/Networking/ByteStream.hpp" #include "TextStyleModifier.hpp" #include "cereal/archives/portable_binary.hpp" #include @@ -16,7 +17,7 @@ namespace RichText { -std::string TextData::get_serialized() { +std::string TextData::get_serialized() const { std::stringstream s; { cereal::PortableBinaryOutputArchive a(s); @@ -54,6 +55,33 @@ void TextData::load(cereal::PortableBinaryInputArchive& a) { } } +TextData TextData::deserialize_string(std::string& s) { + if(s.empty()) { + RichText::TextData textData; + textData.paragraphs.emplace_back(); + return textData; + } + RichText::TextData textData; + ByteMemStream ss(s.data(), s.length()); + { + cereal::PortableBinaryInputArchive a(ss); + a(textData); + } + return textData; +} + +std::string TextData::get_plain_text() const { + if(paragraphs.empty()) + return ""; + std::string toRet; + for(auto& p : paragraphs) { + toRet += p.text; + toRet += '\n'; + } + toRet.pop_back(); + return toRet; +} + bool TextPosition::operator<(const TextPosition& o) const { return (this->fParagraphIndex < o.fParagraphIndex) || (this->fParagraphIndex == o.fParagraphIndex && this->fTextByteIndex < o.fTextByteIndex); } @@ -151,11 +179,11 @@ void TextBox::process_mouse_left_button(Cursor& cur, const Vector2f& pos, bool c } } -std::pair TextBox::process_copy(Cursor& cur) { - return {get_text_between(cur.selectionBeginPos, cur.selectionEndPos), get_rich_text_data_between(cur.selectionBeginPos, cur.selectionEndPos).get_serialized()}; +std::pair TextBox::process_copy(Cursor& cur) { + return {get_text_between(cur.selectionBeginPos, cur.selectionEndPos), get_rich_text_data_between(cur.selectionBeginPos, cur.selectionEndPos)}; } -std::pair TextBox::process_cut(Cursor& cur) { +std::pair TextBox::process_cut(Cursor& cur) { auto toRet = process_copy(cur); if(cur.selectionBeginPos != cur.selectionEndPos) { cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos); @@ -175,17 +203,11 @@ void TextBox::process_text_input(Cursor& cur, const std::string& in, const std:: } } -void TextBox::process_rich_text_input(Cursor& cur, const std::string& serializedRichText) { - if(!serializedRichText.empty()) { +void TextBox::process_rich_text_input(Cursor& cur, const TextData& richText) { + if(!richText.paragraphs.empty() && !(richText.paragraphs.size() == 1 && richText.paragraphs[0].text.empty())) { if(cur.selectionBeginPos != cur.selectionEndPos) cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos); - RichText::TextData textData; - std::stringstream ss(serializedRichText); - { - cereal::PortableBinaryInputArchive a(ss); - a(textData); - } - cur.selectionEndPos = cur.selectionBeginPos = cur.pos = insert_rich_text(cur.pos, textData); + cur.selectionEndPos = cur.selectionBeginPos = cur.pos = insert_rich_text(cur.pos, richText); cur.previousX = std::nullopt; inputChangedTextBox = true; } diff --git a/src/RichText/TextBox.hpp b/src/RichText/TextBox.hpp index 16806e7..38b6f11 100644 --- a/src/RichText/TextBox.hpp +++ b/src/RichText/TextBox.hpp @@ -48,7 +48,9 @@ class TextData { a(text, pStyleData); } }; - std::string get_serialized(); + std::string get_serialized() const; + static TextData deserialize_string(std::string& s); + std::string get_plain_text() const; void save(cereal::PortableBinaryOutputArchive& a) const; void load(cereal::PortableBinaryInputArchive& a); TextStyleModContainer tStyleMods; @@ -133,13 +135,13 @@ class TextBox { void process_mouse_left_button(Cursor& cur, const Vector2f& pos, bool clicked, bool held, bool shift); void process_key_input(Cursor& cur, InputKey in, bool ctrl, bool shift, const std::optional& inputModMap = std::nullopt); - std::pair process_copy(Cursor& cur); - std::pair process_cut(Cursor& cur); + std::pair process_copy(Cursor& cur); + std::pair process_cut(Cursor& cur); std::string get_text_between(TextPosition p1, TextPosition p2); std::string get_string(); void set_tab_space_width(unsigned newTabWidth); void process_text_input(Cursor& cur, const std::string& in, const std::optional& inputModMap = std::nullopt); - void process_rich_text_input(Cursor& cur, const std::string& serializedRichText); + void process_rich_text_input(Cursor& cur, const TextData& richText); private: std::pair get_start_end_text_pos(TextPosition p1, TextPosition p2);