mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-03-22 07:37:29 +08:00
[feat] support drag-and-drop file sending, refs #63
This commit is contained in:
@@ -996,7 +996,13 @@ int Render::SetupFontAndStyle(bool main_window) {
|
||||
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
|
||||
io.Fonts->GetGlyphRangesChineseFull());
|
||||
if (main_windows_system_chinese_font_ != nullptr) {
|
||||
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
|
||||
// Merge FontAwesome icons into the Chinese font
|
||||
config.MergeMode = true;
|
||||
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
||||
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
||||
font_size, &config, icon_ranges);
|
||||
config.MergeMode = false;
|
||||
LOG_INFO("Loaded system Chinese font with icons: {}", font_paths[i]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -1004,7 +1010,13 @@ int Render::SetupFontAndStyle(bool main_window) {
|
||||
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
|
||||
io.Fonts->GetGlyphRangesChineseFull());
|
||||
if (stream_windows_system_chinese_font_ != nullptr) {
|
||||
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
|
||||
// Merge FontAwesome icons into the Chinese font
|
||||
config.MergeMode = true;
|
||||
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
||||
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
||||
font_size, &config, icon_ranges);
|
||||
config.MergeMode = false;
|
||||
LOG_INFO("Loaded system Chinese font with icons: {}", font_paths[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1015,12 +1027,24 @@ int Render::SetupFontAndStyle(bool main_window) {
|
||||
if (main_window) {
|
||||
if (main_windows_system_chinese_font_ == nullptr) {
|
||||
main_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config);
|
||||
LOG_WARN("System Chinese font not found, using default font");
|
||||
// Merge FontAwesome icons into the default font
|
||||
config.MergeMode = true;
|
||||
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
||||
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
||||
font_size, &config, icon_ranges);
|
||||
config.MergeMode = false;
|
||||
LOG_WARN("System Chinese font not found, using default font with icons");
|
||||
}
|
||||
} else {
|
||||
if (stream_windows_system_chinese_font_ == nullptr) {
|
||||
stream_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config);
|
||||
LOG_WARN("System Chinese font not found, using default font");
|
||||
// Merge FontAwesome icons into the default font
|
||||
config.MergeMode = true;
|
||||
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
||||
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
||||
font_size, &config, icon_ranges);
|
||||
config.MergeMode = false;
|
||||
LOG_WARN("System Chinese font not found, using default font with icons");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1900,7 +1924,7 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
|
||||
case SDL_EVENT_DROP_FILE:
|
||||
if (stream_window_ &&
|
||||
SDL_GetWindowID(stream_window_) == event.window.windowID) {
|
||||
printf("SDL_EVENT_DROP_FILE (%s)\n", event.drop.data);
|
||||
ProcessFileDropEvent(event);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1983,4 +2007,63 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Render::ProcessFileDropEvent(const SDL_Event& event) {
|
||||
if (event.type != SDL_EVENT_DROP_FILE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stream_window_inited_) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_lock lock(client_properties_mutex_);
|
||||
for (auto& [_, props] : client_properties_) {
|
||||
if (props->tab_selected_) {
|
||||
if (event.drop.data == nullptr) {
|
||||
LOG_ERROR("ProcessFileDropEvent: drop event data is null");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!props || !props->peer_) {
|
||||
LOG_ERROR("ProcessFileDropEvent: invalid props or peer");
|
||||
break;
|
||||
}
|
||||
|
||||
std::string utf8_path = static_cast<const char*>(event.drop.data);
|
||||
std::filesystem::path file_path = std::filesystem::u8path(utf8_path);
|
||||
|
||||
// Check if file exists
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::exists(file_path, ec)) {
|
||||
LOG_ERROR("ProcessFileDropEvent: file does not exist: {}",
|
||||
file_path.string().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if it's a regular file
|
||||
if (!std::filesystem::is_regular_file(file_path, ec)) {
|
||||
LOG_ERROR("ProcessFileDropEvent: path is not a regular file: {}",
|
||||
file_path.string().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
// Get file size
|
||||
uint64_t file_size = std::filesystem::file_size(file_path, ec);
|
||||
if (ec) {
|
||||
LOG_ERROR("ProcessFileDropEvent: failed to get file size: {}",
|
||||
ec.message().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_INFO("Drop file [{}] to send (size: {} bytes)", event.drop.data,
|
||||
file_size);
|
||||
|
||||
// Use ProcessSelectedFile to handle the file processing
|
||||
ProcessSelectedFile(utf8_path, props, props->file_label_);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace crossdesk
|
||||
@@ -190,6 +190,12 @@ class Render {
|
||||
void UpdateRenderRect();
|
||||
void ProcessSdlEvent(const SDL_Event& event);
|
||||
|
||||
void ProcessFileDropEvent(const SDL_Event& event);
|
||||
|
||||
void ProcessSelectedFile(const std::string& path,
|
||||
std::shared_ptr<SubStreamWindowProperties>& props,
|
||||
const std::string& file_label);
|
||||
|
||||
private:
|
||||
int CreateStreamRenderWindow();
|
||||
int TitleBar(bool main_window);
|
||||
|
||||
@@ -53,6 +53,77 @@ int LossRateDisplay(float loss_rate) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Render::ProcessSelectedFile(
|
||||
const std::string& path, std::shared_ptr<SubStreamWindowProperties>& props,
|
||||
const std::string& file_label) {
|
||||
if (path.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Selected file: {}", path.c_str());
|
||||
|
||||
std::filesystem::path file_path = std::filesystem::u8path(path);
|
||||
|
||||
// Get file size
|
||||
std::error_code ec;
|
||||
uint64_t file_size = std::filesystem::file_size(file_path, ec);
|
||||
if (ec) {
|
||||
LOG_ERROR("Failed to get file size: {}", ec.message().c_str());
|
||||
file_size = 0;
|
||||
}
|
||||
|
||||
// Add file to transfer list
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(props->file_transfer_list_mutex_);
|
||||
SubStreamWindowProperties::FileTransferInfo info;
|
||||
info.file_name = file_path.filename().u8string();
|
||||
info.file_path = file_path; // Store full path for precise matching
|
||||
info.file_size = file_size;
|
||||
info.status = SubStreamWindowProperties::FileTransferStatus::Queued;
|
||||
info.sent_bytes = 0;
|
||||
info.file_id = 0;
|
||||
info.rate_bps = 0;
|
||||
props->file_transfer_list_.push_back(info);
|
||||
}
|
||||
props->file_transfer_window_visible_ = true;
|
||||
|
||||
if (props->file_sending_.load()) {
|
||||
// Add to queue
|
||||
size_t queue_size = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(props->file_queue_mutex_);
|
||||
SubStreamWindowProperties::QueuedFile queued_file;
|
||||
queued_file.file_path = file_path;
|
||||
queued_file.file_label = file_label;
|
||||
props->file_send_queue_.push(queued_file);
|
||||
queue_size = props->file_send_queue_.size();
|
||||
}
|
||||
LOG_INFO("File added to queue: {} ({} files in queue)",
|
||||
file_path.filename().string().c_str(), queue_size);
|
||||
} else {
|
||||
StartFileTransfer(props, file_path, file_label);
|
||||
|
||||
if (props->file_sending_.load()) {
|
||||
} else {
|
||||
// Failed to start (race condition: another file started between
|
||||
// check and call) Add to queue
|
||||
size_t queue_size = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(props->file_queue_mutex_);
|
||||
SubStreamWindowProperties::QueuedFile queued_file;
|
||||
queued_file.file_path = file_path;
|
||||
queued_file.file_label = file_label;
|
||||
props->file_send_queue_.push(queued_file);
|
||||
queue_size = props->file_send_queue_.size();
|
||||
}
|
||||
LOG_INFO(
|
||||
"File added to queue after race condition: {} ({} files in "
|
||||
"queue)",
|
||||
file_path.filename().string().c_str(), queue_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
||||
float button_width = title_bar_height_ * 0.8f;
|
||||
float button_height = title_bar_height_ * 0.8f;
|
||||
@@ -204,71 +275,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
||||
std::string title =
|
||||
localization::select_file[localization_language_index_];
|
||||
std::string path = OpenFileDialog(title);
|
||||
if (!path.empty()) {
|
||||
LOG_INFO("Selected file: {}", path.c_str());
|
||||
|
||||
std::filesystem::path file_path = std::filesystem::path(path);
|
||||
std::string file_label = file_label_;
|
||||
|
||||
// Get file size
|
||||
std::error_code ec;
|
||||
uint64_t file_size = std::filesystem::file_size(file_path, ec);
|
||||
if (ec) {
|
||||
LOG_ERROR("Failed to get file size: {}", ec.message().c_str());
|
||||
file_size = 0;
|
||||
}
|
||||
|
||||
// Add file to transfer list
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(props->file_transfer_list_mutex_);
|
||||
SubStreamWindowProperties::FileTransferInfo info;
|
||||
info.file_name = file_path.filename().string();
|
||||
info.file_path = file_path; // Store full path for precise matching
|
||||
info.file_size = file_size;
|
||||
info.status = SubStreamWindowProperties::FileTransferStatus::Queued;
|
||||
info.sent_bytes = 0;
|
||||
info.file_id = 0;
|
||||
info.rate_bps = 0;
|
||||
props->file_transfer_list_.push_back(info);
|
||||
}
|
||||
props->file_transfer_window_visible_ = true;
|
||||
|
||||
if (props->file_sending_.load()) {
|
||||
// Add to queue
|
||||
size_t queue_size = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(props->file_queue_mutex_);
|
||||
SubStreamWindowProperties::QueuedFile queued_file;
|
||||
queued_file.file_path = file_path;
|
||||
queued_file.file_label = file_label;
|
||||
props->file_send_queue_.push(queued_file);
|
||||
queue_size = props->file_send_queue_.size();
|
||||
}
|
||||
LOG_INFO("File added to queue: {} ({} files in queue)",
|
||||
file_path.filename().string().c_str(), queue_size);
|
||||
} else {
|
||||
StartFileTransfer(props, file_path, file_label);
|
||||
|
||||
if (props->file_sending_.load()) {
|
||||
} else {
|
||||
// Failed to start (race condition: another file started between
|
||||
// check and call) Add to queue
|
||||
size_t queue_size = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(props->file_queue_mutex_);
|
||||
SubStreamWindowProperties::QueuedFile queued_file;
|
||||
queued_file.file_path = file_path;
|
||||
queued_file.file_label = file_label;
|
||||
props->file_send_queue_.push(queued_file);
|
||||
queue_size = props->file_send_queue_.size();
|
||||
}
|
||||
LOG_INFO(
|
||||
"File added to queue after race condition: {} ({} files in "
|
||||
"queue)",
|
||||
file_path.filename().string().c_str(), queue_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->ProcessSelectedFile(path, props, file_label_);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
@@ -87,6 +87,11 @@ int Render::FileTransferWindow(
|
||||
ImVec2(file_transfer_window_width, file_transfer_window_height),
|
||||
ImGuiCond_Always);
|
||||
|
||||
// Set Chinese font for proper display
|
||||
if (stream_windows_system_chinese_font_) {
|
||||
ImGui::PushFont(stream_windows_system_chinese_font_);
|
||||
}
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 0.9f));
|
||||
@@ -121,9 +126,9 @@ int Render::FileTransferWindow(
|
||||
} else {
|
||||
// Use a scrollable child window for the file list
|
||||
ImGui::SetWindowFontScale(0.5f);
|
||||
ImGui::BeginChild("FileList",
|
||||
ImVec2(0, file_transfer_window_height * 0.75f),
|
||||
ImGuiChildFlags_Border);
|
||||
ImGui::BeginChild(
|
||||
"FileList", ImVec2(0, file_transfer_window_height * 0.75f),
|
||||
ImGuiChildFlags_Border, ImGuiWindowFlags_HorizontalScrollbar);
|
||||
ImGui::SetWindowFontScale(1.0f);
|
||||
ImGui::SetWindowFontScale(0.5f);
|
||||
|
||||
@@ -220,6 +225,11 @@ int Render::FileTransferWindow(
|
||||
ImGui::SetWindowFontScale(0.5f);
|
||||
ImGui::End();
|
||||
ImGui::SetWindowFontScale(1.0f);
|
||||
|
||||
// Pop Chinese font if it was pushed
|
||||
if (stream_windows_system_chinese_font_) {
|
||||
ImGui::PopFont();
|
||||
}
|
||||
} else {
|
||||
ImGui::PopStyleColor(4);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
Reference in New Issue
Block a user