[feat] add controller info and file transfer in server window

This commit is contained in:
dijunkun
2026-01-20 21:22:20 +08:00
parent 9b69596af1
commit 619e54dc0e
9 changed files with 511 additions and 228 deletions

View File

@@ -1,50 +1,11 @@
#include "layout_relative.h"
#include "localization.h"
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
namespace {
constexpr float kDragThresholdPx = 3.0f;
// Handles dragging for the *last submitted ImGui item*.
// `reset_on_deactivate` should be false when the caller needs to know whether a
// deactivation was a click (no drag) vs a drag-release (dragging==true).
inline void HandleWindowDragForLastItem(SDL_Window* window, bool& dragging,
float& start_mouse_x,
float& start_mouse_y, int& start_win_x,
int& start_win_y,
bool reset_on_deactivate = true) {
if (!window) {
return;
}
if (ImGui::IsItemActivated()) {
SDL_GetGlobalMouseState(&start_mouse_x, &start_mouse_y);
SDL_GetWindowPosition(window, &start_win_x, &start_win_y);
dragging = false;
}
if (ImGui::IsItemActive()) {
if (!dragging &&
ImGui::IsMouseDragging(ImGuiMouseButton_Left, kDragThresholdPx)) {
dragging = true;
}
if (dragging) {
float mouse_x = 0.0f;
float mouse_y = 0.0f;
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
const int dx = (int)(mouse_x - start_mouse_x);
const int dy = (int)(mouse_y - start_mouse_y);
SDL_SetWindowPosition(window, start_win_x + dx, start_win_y + dy);
}
}
if (reset_on_deactivate && ImGui::IsItemDeactivated()) {
dragging = false;
}
}
} // namespace
namespace {} // namespace
int Render::ServerWindow() {
ImGui::SetNextWindowSize(ImVec2(server_window_width_, server_window_height_),
@@ -57,44 +18,6 @@ int Render::ServerWindow() {
ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoScrollWithMouse);
// Collapsed mode: no buttons; drag to move; click to restore.
if (server_window_collapsed_) {
ImGui::SetCursorPos(ImVec2(0.0f, 0.0f));
ImGui::InvisibleButton("##server_collapsed_area",
ImVec2(server_window_width_, server_window_height_));
HandleWindowDragForLastItem(server_window_,
server_window_collapsed_dragging_,
server_window_collapsed_drag_start_mouse_x_,
server_window_collapsed_drag_start_mouse_y_,
server_window_collapsed_drag_start_win_x_,
server_window_collapsed_drag_start_win_y_,
/*reset_on_deactivate=*/false);
const bool request_restore =
ImGui::IsItemDeactivated() && !server_window_collapsed_dragging_;
if (ImGui::IsItemDeactivated()) {
server_window_collapsed_dragging_ = false;
}
if (request_restore && server_window_) {
int w = 0;
int x = 0;
int y = 0;
int h = 0;
SDL_GetWindowSize(server_window_, &w, &h);
SDL_GetWindowPosition(server_window_, &x, &y);
const int normal_h = server_window_normal_height_;
SDL_SetWindowSize(server_window_, w, normal_h);
SDL_SetWindowPosition(server_window_, x, y);
server_window_collapsed_ = false;
}
ImGui::End();
return 0;
}
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
@@ -105,97 +28,132 @@ int Render::ServerWindow() {
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
float server_title_bar_button_width = server_window_title_bar_height_;
float server_title_bar_button_height = server_window_title_bar_height_;
// Drag area: the title bar excluding the right-side buttons.
// Collapse/expand toggle button (FontAwesome icon).
{
const float drag_w =
server_window_width_ - server_title_bar_button_width * 2;
const float drag_h = server_title_bar_button_height;
ImGui::SetCursorPos(ImVec2(0.0f, 0.0f));
ImGui::InvisibleButton("##server_title_drag_area", ImVec2(drag_w, drag_h));
HandleWindowDragForLastItem(
server_window_, server_window_dragging_,
server_window_drag_start_mouse_x_, server_window_drag_start_mouse_y_,
server_window_drag_start_win_x_, server_window_drag_start_win_y_);
}
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
float minimize_button_pos_x =
server_window_width_ - server_title_bar_button_width * 2;
ImGui::SetCursorPos(ImVec2(minimize_button_pos_x, 0.0f));
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::SetWindowFontScale(0.5f);
const char* icon =
server_window_collapsed_ ? ICON_FA_ANGLE_DOWN : ICON_FA_ANGLE_UP;
std::string toggle_label = std::string(icon) + "##server_toggle";
if (ImGui::Button(toggle_label.c_str(),
ImVec2(server_title_bar_button_width,
server_title_bar_button_height))) {
if (server_window_) {
int w = 0;
int h = 0;
int x = 0;
int y = 0;
SDL_GetWindowSize(server_window_, &w, &h);
SDL_GetWindowPosition(server_window_, &x, &y);
float minimize_pos_x =
minimize_button_pos_x + server_title_bar_button_width * 0.33f;
float minimize_pos_y = server_title_bar_button_height * 0.5f;
std::string server_minimize_button = "##minimize"; // ICON_FA_MINUS;
if (ImGui::Button(server_minimize_button.c_str(),
ImVec2(server_title_bar_button_width,
server_title_bar_button_height))) {
if (server_window_) {
int w = 0;
int h = 0;
int x = 0;
int y = 0;
SDL_GetWindowSize(server_window_, &w, &h);
SDL_GetWindowPosition(server_window_, &x, &y);
const int collapsed_h = (int)server_window_title_bar_height_;
// Collapse upward: keep top edge stable.
SDL_SetWindowSize(server_window_, w, collapsed_h);
SDL_SetWindowPosition(server_window_, x, y);
server_window_collapsed_ = true;
if (server_window_collapsed_) {
const int normal_h = server_window_normal_height_;
SDL_SetWindowSize(server_window_, w, normal_h);
SDL_SetWindowPosition(server_window_, x, y);
server_window_collapsed_ = false;
} else {
const int collapsed_h = (int)server_window_title_bar_height_;
// Collapse upward: keep top edge stable.
SDL_SetWindowSize(server_window_, w, collapsed_h);
SDL_SetWindowPosition(server_window_, x, y);
server_window_collapsed_ = true;
}
}
}
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(3);
}
draw_list->AddLine(
ImVec2(minimize_pos_x, minimize_pos_y),
ImVec2(minimize_pos_x + server_title_bar_button_width * 0.33f,
minimize_pos_y),
IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(3);
float xmark_button_pos_x =
server_window_width_ - server_title_bar_button_width;
ImGui::SetCursorPos(ImVec2(xmark_button_pos_x, 0.0f));
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0, 0, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0, 0, 0.5f));
float xmark_pos_x = xmark_button_pos_x + server_title_bar_button_width * 0.5f;
float xmark_pos_y = server_title_bar_button_height * 0.5f;
float xmark_size = server_title_bar_button_width * 0.33f;
std::string server_close_button = "##xmark"; // ICON_FA_XMARK;
if (ImGui::Button(server_close_button.c_str(),
ImVec2(server_title_bar_button_width,
server_title_bar_button_height))) {
LOG_ERROR("Close button clicked");
LeaveConnection(peer_, self_hosted_id_);
}
draw_list->AddLine(ImVec2(xmark_pos_x - xmark_size / 2 - 0.25f,
xmark_pos_y - xmark_size / 2 + 0.75f),
ImVec2(xmark_pos_x + xmark_size / 2 - 1.5f,
xmark_pos_y + xmark_size / 2 - 0.5f),
IM_COL32(0, 0, 0, 255));
draw_list->AddLine(
ImVec2(xmark_pos_x + xmark_size / 2 - 1.75f,
xmark_pos_y - xmark_size / 2 + 0.75f),
ImVec2(xmark_pos_x - xmark_size / 2, xmark_pos_y + xmark_size / 2 - 1.0f),
IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(3);
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::PopStyleColor();
RemoteClientInfoWindow();
ImGui::End();
return 0;
}
int Render::RemoteClientInfoWindow() {
float remote_client_info_window_width = server_window_width_ * 0.75f;
float remote_client_info_window_height =
(server_window_height_ - server_window_title_bar_height_) * 0.3f;
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
ImGui::BeginChild(
"RemoteClientInfoWindow",
ImVec2(remote_client_info_window_width, remote_client_info_window_height),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::SetWindowFontScale(0.7f);
ImGui::Text("%s",
localization::controller[localization_language_index_].c_str());
ImGui::SameLine();
ImGui::Text("%s", remote_client_id_.c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::EndChild();
ImGui::SameLine();
float close_connection_button_width = server_window_width_ * 0.15f;
float close_connection_button_height = remote_client_info_window_height;
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0.5f, 0.5f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 5.0f);
ImGui::SetWindowFontScale(0.7f);
if (ImGui::Button(ICON_FA_XMARK, ImVec2(close_connection_button_width,
close_connection_button_height))) {
LeaveConnection(peer_, self_hosted_id_);
}
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(3);
ImGui::PopStyleVar();
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
ImGui::BeginChild(
"RemoteClientInfoFileTransferWindow",
ImVec2(remote_client_info_window_width, remote_client_info_window_height),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor();
ImGui::SetWindowFontScale(0.7f);
ImGui::AlignTextToFramePadding();
ImGui::Text(
"%s", localization::file_transfer[localization_language_index_].c_str());
ImGui::SameLine();
if (ImGui::Button(
localization::select_file[localization_language_index_].c_str())) {
std::string title = localization::select_file[localization_language_index_];
std::string path = OpenFileDialog(title);
LOG_INFO("Selected file path: {}", path.c_str());
}
ImGui::SetWindowFontScale(1.0f);
ImGui::EndChild();
return 0;
}
} // namespace crossdesk