From 5aac3422aa702e5c09b968239604bdf69d4d0ee9 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Tue, 30 Jan 2024 11:58:01 +0100 Subject: [PATCH] allow "copy file" which sets the text/uri-list with the file path --- src/chat_gui4.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++----- src/chat_gui4.hpp | 13 ++++++++- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/chat_gui4.cpp b/src/chat_gui4.cpp index 4a91c69e..a11625ba 100644 --- a/src/chat_gui4.cpp +++ b/src/chat_gui4.cpp @@ -17,10 +17,8 @@ #include "./media_meta_info_loader.hpp" #include "./sdl_clipboard_utils.hpp" -#include "SDL_clipboard.h" #include -#include #include #include #include @@ -28,10 +26,7 @@ #include #include #include -#include #include -#include - namespace Components { @@ -72,6 +67,48 @@ static std::string file_path_url_escape(const std::string&& value) { return escaped.str(); } +const void* clipboard_callback(void* userdata, const char* mime_type, size_t* size) { + if (mime_type == nullptr) { + // cleared or new data is set + return nullptr; + } + + if (userdata == nullptr) { + // error + return nullptr; + } + + auto* cg = static_cast(userdata); + std::lock_guard lg{cg->_set_clipboard_data_mutex}; + if (!cg->_set_clipboard_data.count(mime_type)) { + return nullptr; + } + + const auto& sh_vec = cg->_set_clipboard_data.at(mime_type); + if (!static_cast(sh_vec)) { + // error, empty shared pointer + return nullptr; + } + + *size = sh_vec->size(); + + return sh_vec->data(); +} + +void ChatGui4::setClipboardData(std::vector mime_types, std::shared_ptr>&& data) { + std::vector tmp_mimetype_list; + for (const auto& mime_type : mime_types) { + tmp_mimetype_list.push_back(mime_type.data()); + } + + std::lock_guard lg{_set_clipboard_data_mutex}; + for (const auto& mime_type : mime_types) { + _set_clipboard_data[mime_type] = data; + } + + SDL_SetClipboardData(clipboard_callback, nullptr, this, tmp_mimetype_list.data(), tmp_mimetype_list.size()); +} + ChatGui4::ChatGui4( ConfigModelI& conf, RegistryMessageModel& rmm, @@ -80,6 +117,17 @@ ChatGui4::ChatGui4( ) : _conf(conf), _rmm(rmm), _cr(cr), _tal(_cr), _contact_tc(_tal, tu), _msg_tc(_mil, tu), _sip(tu) { } +ChatGui4::~ChatGui4(void) { + // TODO: this is bs + SDL_ClearClipboardData(); + + // this might be better, need to see if this works (docs needs improving) + //for (const auto& [k, _] : _set_clipboard_data) { + //const auto* tmp_mime_type = k.c_str(); + //SDL_SetClipboardData(nullptr, nullptr, nullptr, &tmp_mime_type, 1); + //} +} + void ChatGui4::render(float time_delta) { if (!_cr.storage().empty()) { // handle force-reloads for avatars std::vector to_purge; @@ -761,10 +809,19 @@ void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) { const auto& local_info = reg.get(e); if (local_info.file_list.size() > i && ImGui::BeginPopupContextItem("##file_c")) { if (ImGui::MenuItem("open")) { - std::string url{"file://" + file_path_url_escape(std::filesystem::canonical(local_info.file_list.at(i)).u8string())}; + const std::string url{"file://" + file_path_url_escape(std::filesystem::canonical(local_info.file_list.at(i)).u8string())}; std::cout << "opening file '" << url << "'\n"; SDL_OpenURL(url.c_str()); } + if (ImGui::MenuItem("copy file")) { + const std::string url{"file://" + file_path_url_escape(std::filesystem::canonical(local_info.file_list.at(i)).u8string())}; + //ImGui::SetClipboardText(url.c_str()); + setClipboardData({"text/uri-list", "text/x-moz-url"}, std::make_shared>(url.begin(), url.end())); + } + if (ImGui::MenuItem("copy filepath")) { + const auto file_path = std::filesystem::canonical(local_info.file_list.at(i)).u8string(); + ImGui::SetClipboardText(file_path.c_str()); + } ImGui::EndPopup(); } } diff --git a/src/chat_gui4.hpp b/src/chat_gui4.hpp index 2ae8a030..8cb355d6 100644 --- a/src/chat_gui4.hpp +++ b/src/chat_gui4.hpp @@ -9,9 +9,13 @@ #include "./message_image_loader.hpp" #include "./file_selector.hpp" #include "./send_image_popup.hpp" +#include "entt/container/dense_map.hpp" +#include #include -#include +#include +#include +#include class ChatGui4 { ConfigModelI& _conf; @@ -37,6 +41,12 @@ class ChatGui4 { float TEXT_BASE_WIDTH {1}; float TEXT_BASE_HEIGHT {1}; + // mimetype -> data + entt::dense_map>> _set_clipboard_data; + std::mutex _set_clipboard_data_mutex; // might be called out of order + friend const void* clipboard_callback(void* userdata, const char* mime_type, size_t* size); + void setClipboardData(std::vector mime_types, std::shared_ptr>&& data); + public: ChatGui4( ConfigModelI& conf, @@ -44,6 +54,7 @@ class ChatGui4 { Contact3Registry& cr, TextureUploaderI& tu ); + ~ChatGui4(void); public: void render(float time_delta);