mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-03-28 12:27:21 +08:00
[feat] add support for server window resizing and dragging
This commit is contained in:
@@ -825,7 +825,7 @@ int Render::CreateMainWindow() {
|
|||||||
// for window region action
|
// for window region action
|
||||||
SDL_SetWindowHitTest(main_window_, HitTestCallback, this);
|
SDL_SetWindowHitTest(main_window_, HitTestCallback, this);
|
||||||
|
|
||||||
SetupFontAndStyle(true);
|
SetupFontAndStyle(&main_windows_system_chinese_font_);
|
||||||
|
|
||||||
ImGuiStyle& style = ImGui::GetStyle();
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
style.ScaleAllSizes(dpi_scale_);
|
style.ScaleAllSizes(dpi_scale_);
|
||||||
@@ -894,7 +894,7 @@ int Render::CreateStreamWindow() {
|
|||||||
// for window region action
|
// for window region action
|
||||||
SDL_SetWindowHitTest(stream_window_, HitTestCallback, this);
|
SDL_SetWindowHitTest(stream_window_, HitTestCallback, this);
|
||||||
|
|
||||||
SetupFontAndStyle(false);
|
SetupFontAndStyle(&stream_windows_system_chinese_font_);
|
||||||
|
|
||||||
ImGuiStyle& style = ImGui::GetStyle();
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
style.ScaleAllSizes(dpi_scale_);
|
style.ScaleAllSizes(dpi_scale_);
|
||||||
@@ -977,7 +977,13 @@ int Render::CreateServerWindow() {
|
|||||||
|
|
||||||
// for window region action
|
// for window region action
|
||||||
SDL_SetWindowHitTest(server_window_, HitTestCallback, this);
|
SDL_SetWindowHitTest(server_window_, HitTestCallback, this);
|
||||||
SetupFontAndStyle(false);
|
|
||||||
|
SetupFontAndStyle(&server_windows_system_chinese_font_);
|
||||||
|
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
style.ScaleAllSizes(dpi_scale_);
|
||||||
|
style.FontScaleDpi = dpi_scale_;
|
||||||
|
|
||||||
ImGui_ImplSDL3_InitForSDLRenderer(server_window_, server_renderer_);
|
ImGui_ImplSDL3_InitForSDLRenderer(server_window_, server_renderer_);
|
||||||
ImGui_ImplSDLRenderer3_Init(server_renderer_);
|
ImGui_ImplSDLRenderer3_Init(server_renderer_);
|
||||||
|
|
||||||
@@ -1007,7 +1013,7 @@ int Render::DestroyServerWindow() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Render::SetupFontAndStyle(bool main_window) {
|
int Render::SetupFontAndStyle(ImFont** system_chinese_font_out) {
|
||||||
float font_size = 32.0f;
|
float font_size = 32.0f;
|
||||||
|
|
||||||
// Setup Dear ImGui style
|
// Setup Dear ImGui style
|
||||||
@@ -1029,10 +1035,8 @@ int Render::SetupFontAndStyle(bool main_window) {
|
|||||||
// Load system Chinese font as fallback
|
// Load system Chinese font as fallback
|
||||||
config.MergeMode = false;
|
config.MergeMode = false;
|
||||||
config.FontDataOwnedByAtlas = false;
|
config.FontDataOwnedByAtlas = false;
|
||||||
if (main_window) {
|
if (system_chinese_font_out) {
|
||||||
main_windows_system_chinese_font_ = nullptr;
|
*system_chinese_font_out = nullptr;
|
||||||
} else {
|
|
||||||
stream_windows_system_chinese_font_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@@ -1059,61 +1063,36 @@ int Render::SetupFontAndStyle(bool main_window) {
|
|||||||
std::ifstream font_file(font_paths[i], std::ios::binary);
|
std::ifstream font_file(font_paths[i], std::ios::binary);
|
||||||
if (font_file.good()) {
|
if (font_file.good()) {
|
||||||
font_file.close();
|
font_file.close();
|
||||||
if (main_window) {
|
if (!system_chinese_font_out) {
|
||||||
main_windows_system_chinese_font_ =
|
break;
|
||||||
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
|
}
|
||||||
io.Fonts->GetGlyphRangesChineseFull());
|
|
||||||
if (main_windows_system_chinese_font_ != nullptr) {
|
*system_chinese_font_out =
|
||||||
// Merge FontAwesome icons into the Chinese font
|
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
|
||||||
config.MergeMode = true;
|
io.Fonts->GetGlyphRangesChineseFull());
|
||||||
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
if (*system_chinese_font_out != nullptr) {
|
||||||
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
// Merge FontAwesome icons into the Chinese font
|
||||||
font_size, &config, icon_ranges);
|
config.MergeMode = true;
|
||||||
config.MergeMode = false;
|
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
||||||
LOG_INFO("Loaded system Chinese font with icons: {}", font_paths[i]);
|
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
||||||
break;
|
font_size, &config, icon_ranges);
|
||||||
}
|
config.MergeMode = false;
|
||||||
} else {
|
LOG_INFO("Loaded system Chinese font with icons: {}", font_paths[i]);
|
||||||
stream_windows_system_chinese_font_ =
|
break;
|
||||||
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
|
|
||||||
io.Fonts->GetGlyphRangesChineseFull());
|
|
||||||
if (stream_windows_system_chinese_font_ != nullptr) {
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no system font found, use default font
|
// If no system font found, use default font
|
||||||
if (main_window) {
|
if (system_chinese_font_out && *system_chinese_font_out == nullptr) {
|
||||||
if (main_windows_system_chinese_font_ == nullptr) {
|
*system_chinese_font_out = io.Fonts->AddFontDefault(&config);
|
||||||
main_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config);
|
// Merge FontAwesome icons into the default font
|
||||||
// Merge FontAwesome icons into the default font
|
config.MergeMode = true;
|
||||||
config.MergeMode = true;
|
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
||||||
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
||||||
io.Fonts->AddFontFromMemoryTTF(fa_solid_900_ttf, fa_solid_900_ttf_len,
|
font_size, &config, icon_ranges);
|
||||||
font_size, &config, icon_ranges);
|
config.MergeMode = false;
|
||||||
config.MergeMode = false;
|
LOG_WARN("System Chinese font not found, using default font with icons");
|
||||||
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);
|
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::StyleColorsLight();
|
ImGui::StyleColorsLight();
|
||||||
@@ -1258,7 +1237,8 @@ int Render::DrawServerWindow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (server_window_) {
|
if (server_window_) {
|
||||||
int w = 0, h = 0;
|
int w = 0;
|
||||||
|
int h = 0;
|
||||||
SDL_GetWindowSize(server_window_, &w, &h);
|
SDL_GetWindowSize(server_window_, &w, &h);
|
||||||
if (w > 0 && h > 0) {
|
if (w > 0 && h > 0) {
|
||||||
server_window_width_ = (float)w;
|
server_window_width_ = (float)w;
|
||||||
@@ -1272,12 +1252,7 @@ int Render::DrawServerWindow() {
|
|||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
ServerWindow();
|
ServerWindow();
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
// Transparent clear for compact (shaped) mode; opaque clear for normal mode.
|
SDL_SetRenderDrawColor(server_renderer_, 255, 255, 255, 255);
|
||||||
if (server_window_compact_) {
|
|
||||||
SDL_SetRenderDrawColor(server_renderer_, 0, 0, 0, 0);
|
|
||||||
} else {
|
|
||||||
SDL_SetRenderDrawColor(server_renderer_, 255, 255, 255, 255);
|
|
||||||
}
|
|
||||||
SDL_RenderClear(server_renderer_);
|
SDL_RenderClear(server_renderer_);
|
||||||
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), server_renderer_);
|
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), server_renderer_);
|
||||||
SDL_RenderPresent(server_renderer_);
|
SDL_RenderPresent(server_renderer_);
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ class Render {
|
|||||||
int DestroyStreamWindow();
|
int DestroyStreamWindow();
|
||||||
int CreateServerWindow();
|
int CreateServerWindow();
|
||||||
int DestroyServerWindow();
|
int DestroyServerWindow();
|
||||||
int SetupFontAndStyle(bool main_window);
|
int SetupFontAndStyle(ImFont** system_chinese_font_out);
|
||||||
int DestroyMainWindowContext();
|
int DestroyMainWindowContext();
|
||||||
int DestroyStreamWindowContext();
|
int DestroyStreamWindowContext();
|
||||||
int DestroyServerWindowContext();
|
int DestroyServerWindowContext();
|
||||||
@@ -395,6 +395,7 @@ class Render {
|
|||||||
ImGuiContext* main_ctx_ = nullptr;
|
ImGuiContext* main_ctx_ = nullptr;
|
||||||
ImFont* main_windows_system_chinese_font_ = nullptr;
|
ImFont* main_windows_system_chinese_font_ = nullptr;
|
||||||
ImFont* stream_windows_system_chinese_font_ = nullptr;
|
ImFont* stream_windows_system_chinese_font_ = nullptr;
|
||||||
|
ImFont* server_windows_system_chinese_font_ = nullptr;
|
||||||
bool exit_ = false;
|
bool exit_ = false;
|
||||||
const int sdl_refresh_ms_ = 16; // ~60 FPS
|
const int sdl_refresh_ms_ = 16; // ~60 FPS
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
@@ -507,20 +508,27 @@ class Render {
|
|||||||
int server_window_height_default_ = 450;
|
int server_window_height_default_ = 450;
|
||||||
float server_window_width_ = 300;
|
float server_window_width_ = 300;
|
||||||
float server_window_height_ = 450;
|
float server_window_height_ = 450;
|
||||||
float server_window_title_bar_height_ = 30.0f;
|
float server_window_title_bar_height_ = 50.0f;
|
||||||
SDL_PixelFormat server_pixformat_ = SDL_PIXELFORMAT_NV12;
|
SDL_PixelFormat server_pixformat_ = SDL_PIXELFORMAT_NV12;
|
||||||
int server_window_width_real_ = 400;
|
int server_window_normal_width_ = 300;
|
||||||
int server_window_height_real_ = 450;
|
int server_window_normal_height_ = 450;
|
||||||
float server_window_dpi_scaling_w_ = 1.0f;
|
float server_window_dpi_scaling_w_ = 1.0f;
|
||||||
float server_window_dpi_scaling_h_ = 1.0f;
|
float server_window_dpi_scaling_h_ = 1.0f;
|
||||||
|
|
||||||
// server window compact mode (50x50) toggle
|
// server window collapsed mode
|
||||||
bool server_window_compact_ = false;
|
bool server_window_collapsed_ = false;
|
||||||
int server_window_width_before_compact_ = 0;
|
bool server_window_collapsed_dragging_ = false;
|
||||||
int server_window_height_before_compact_ = 0;
|
float server_window_collapsed_drag_start_mouse_x_ = 0.0f;
|
||||||
int server_window_x_before_compact_ = 0;
|
float server_window_collapsed_drag_start_mouse_y_ = 0.0f;
|
||||||
int server_window_y_before_compact_ = 0;
|
int server_window_collapsed_drag_start_win_x_ = 0;
|
||||||
bool server_window_bounds_saved_ = false;
|
int server_window_collapsed_drag_start_win_y_ = 0;
|
||||||
|
|
||||||
|
// server window drag normal mode
|
||||||
|
bool server_window_dragging_ = false;
|
||||||
|
float server_window_drag_start_mouse_x_ = 0.0f;
|
||||||
|
float server_window_drag_start_mouse_y_ = 0.0f;
|
||||||
|
int server_window_drag_start_win_x_ = 0;
|
||||||
|
int server_window_drag_start_win_y_ = 0;
|
||||||
|
|
||||||
bool label_inited_ = false;
|
bool label_inited_ = false;
|
||||||
bool connect_button_pressed_ = false;
|
bool connect_button_pressed_ = false;
|
||||||
|
|||||||
@@ -568,6 +568,7 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
|
|||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ConnectionStatus::Connected: {
|
case ConnectionStatus::Connected: {
|
||||||
|
render->need_to_send_host_info_ = true;
|
||||||
if (!render->need_to_create_stream_window_ &&
|
if (!render->need_to_create_stream_window_ &&
|
||||||
!render->client_properties_.empty()) {
|
!render->client_properties_.empty()) {
|
||||||
render->need_to_create_stream_window_ = true;
|
render->need_to_create_stream_window_ = true;
|
||||||
@@ -623,6 +624,7 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
|
|||||||
switch (status) {
|
switch (status) {
|
||||||
case ConnectionStatus::Connected: {
|
case ConnectionStatus::Connected: {
|
||||||
render->need_to_create_server_window_ = true;
|
render->need_to_create_server_window_ = true;
|
||||||
|
render->need_to_send_host_info_ = true;
|
||||||
render->is_server_mode_ = true;
|
render->is_server_mode_ = true;
|
||||||
render->start_screen_capturer_ = true;
|
render->start_screen_capturer_ = true;
|
||||||
render->start_speaker_capturer_ = true;
|
render->start_speaker_capturer_ = true;
|
||||||
|
|||||||
@@ -1,110 +1,95 @@
|
|||||||
#include <cmath>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
|
|
||||||
static void SetServerWindowCircleShape(SDL_Window* window, int diameter) {
|
namespace {
|
||||||
if (!window || diameter <= 0) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int pitch = diameter * 4;
|
if (ImGui::IsItemActivated()) {
|
||||||
std::vector<unsigned char> pixels((size_t)diameter * (size_t)diameter * 4, 0);
|
SDL_GetGlobalMouseState(&start_mouse_x, &start_mouse_y);
|
||||||
|
SDL_GetWindowPosition(window, &start_win_x, &start_win_y);
|
||||||
|
dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Sub-pixel centered circle helps symmetry on even diameters.
|
if (ImGui::IsItemActive()) {
|
||||||
const float r = (float)diameter * 0.5f;
|
if (!dragging &&
|
||||||
const float cx = r - 0.5f;
|
ImGui::IsMouseDragging(ImGuiMouseButton_Left, kDragThresholdPx)) {
|
||||||
const float cy = r - 0.5f;
|
dragging = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (int y = 0; y < diameter; ++y) {
|
if (dragging) {
|
||||||
for (int x = 0; x < diameter; ++x) {
|
float mouse_x = 0.0f;
|
||||||
const float dx = (float)x - cx;
|
float mouse_y = 0.0f;
|
||||||
const float dy = (float)y - cy;
|
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
|
||||||
const float dist = std::sqrt(dx * dx + dy * dy);
|
const int dx = (int)(mouse_x - start_mouse_x);
|
||||||
|
const int dy = (int)(mouse_y - start_mouse_y);
|
||||||
// 1px soft edge to reduce jaggies on small circles.
|
SDL_SetWindowPosition(window, start_win_x + dx, start_win_y + dy);
|
||||||
float a = r + 0.5f - dist;
|
|
||||||
if (a < 0.0f) a = 0.0f;
|
|
||||||
if (a > 1.0f) a = 1.0f;
|
|
||||||
const unsigned char alpha = (unsigned char)(a * 255.0f);
|
|
||||||
const size_t idx = ((size_t)y * (size_t)diameter + (size_t)x) * 4;
|
|
||||||
pixels[idx + 0] = 255; // R
|
|
||||||
pixels[idx + 1] = 255; // G
|
|
||||||
pixels[idx + 2] = 255; // B
|
|
||||||
pixels[idx + 3] = alpha; // A
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface* shape = SDL_CreateSurfaceFrom(
|
if (reset_on_deactivate && ImGui::IsItemDeactivated()) {
|
||||||
diameter, diameter, SDL_PIXELFORMAT_RGBA32, pixels.data(), pitch);
|
dragging = false;
|
||||||
if (!shape) {
|
|
||||||
LOG_ERROR("SDL_CreateSurfaceFrom failed: {}", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SDL_SetWindowShape(window, shape)) {
|
|
||||||
LOG_ERROR("SDL_SetWindowShape failed: {}", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_DestroySurface(shape);
|
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int Render::ServerWindow() {
|
int Render::ServerWindow() {
|
||||||
ImGui::SetNextWindowSize(ImVec2(server_window_width_, server_window_height_),
|
ImGui::SetNextWindowSize(ImVec2(server_window_width_, server_window_height_),
|
||||||
ImGuiCond_Always);
|
ImGuiCond_Always);
|
||||||
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
||||||
|
|
||||||
if (server_window_compact_) {
|
|
||||||
ImGui::SetNextWindowBgAlpha(0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Begin("##server_window", nullptr,
|
ImGui::Begin("##server_window", nullptr,
|
||||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
|
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
|
||||||
ImGuiWindowFlags_NoScrollbar |
|
ImGuiWindowFlags_NoScrollbar |
|
||||||
ImGuiWindowFlags_NoScrollWithMouse);
|
ImGuiWindowFlags_NoScrollWithMouse);
|
||||||
|
|
||||||
// Compact mode: show a 50x50 clickable square that restores the window.
|
// Collapsed mode: no buttons; drag to move; click to restore.
|
||||||
if (server_window_compact_) {
|
if (server_window_collapsed_) {
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
|
||||||
ImGui::SetCursorPos(ImVec2(0.0f, 0.0f));
|
ImGui::SetCursorPos(ImVec2(0.0f, 0.0f));
|
||||||
if (ImGui::InvisibleButton(
|
ImGui::InvisibleButton("##server_collapsed_area",
|
||||||
"##server_compact_restore",
|
ImVec2(server_window_width_, server_window_height_));
|
||||||
ImVec2(server_window_width_, server_window_height_))) {
|
|
||||||
if (server_window_) {
|
|
||||||
SDL_SetWindowShape(server_window_, nullptr);
|
|
||||||
}
|
|
||||||
if (server_window_ && server_window_bounds_saved_ &&
|
|
||||||
server_window_width_before_compact_ > 0 &&
|
|
||||||
server_window_height_before_compact_ > 0) {
|
|
||||||
SDL_SetWindowSize(server_window_, server_window_width_before_compact_,
|
|
||||||
server_window_height_before_compact_);
|
|
||||||
SDL_SetWindowPosition(server_window_, server_window_x_before_compact_,
|
|
||||||
server_window_y_before_compact_);
|
|
||||||
|
|
||||||
server_window_width_ = (float)server_window_width_before_compact_;
|
HandleWindowDragForLastItem(server_window_,
|
||||||
server_window_height_ = (float)server_window_height_before_compact_;
|
server_window_collapsed_dragging_,
|
||||||
}
|
server_window_collapsed_drag_start_mouse_x_,
|
||||||
server_window_compact_ = false;
|
server_window_collapsed_drag_start_mouse_y_,
|
||||||
server_window_bounds_saved_ = false;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a visible circular affordance.
|
if (request_restore && server_window_) {
|
||||||
const float w = server_window_width_;
|
int w = 0;
|
||||||
const float h = server_window_height_;
|
int x = 0;
|
||||||
const float radius = (w < h ? w : h) * 0.5f - 1.0f;
|
int y = 0;
|
||||||
const ImVec2 center(w * 0.5f, h * 0.5f);
|
int h = 0;
|
||||||
draw_list->AddCircleFilled(center, radius, IM_COL32(255, 255, 255, 220),
|
SDL_GetWindowSize(server_window_, &w, &h);
|
||||||
32);
|
SDL_GetWindowPosition(server_window_, &x, &y);
|
||||||
draw_list->AddCircle(center, radius, IM_COL32(0, 0, 0, 255), 32, 2.0f);
|
|
||||||
// A simple "restore" hint.
|
const int normal_h = server_window_normal_height_;
|
||||||
draw_list->AddRect(
|
SDL_SetWindowSize(server_window_, w, normal_h);
|
||||||
ImVec2(center.x - radius * 0.35f, center.y - radius * 0.35f),
|
SDL_SetWindowPosition(server_window_, x, y);
|
||||||
ImVec2(center.x + radius * 0.35f, center.y + radius * 0.35f),
|
server_window_collapsed_ = false;
|
||||||
IM_COL32(0, 0, 0, 255), 2.0f, 0, 2.0f);
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -122,12 +107,23 @@ int Render::ServerWindow() {
|
|||||||
|
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
|
||||||
|
|
||||||
float server_title_bar_button_width = server_window_title_bar_height_;
|
float server_title_bar_button_width = server_window_title_bar_height_;
|
||||||
float server_title_bar_button_height = 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.
|
||||||
|
{
|
||||||
|
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_);
|
||||||
|
}
|
||||||
|
|
||||||
float minimize_button_pos_x =
|
float minimize_button_pos_x =
|
||||||
server_window_width_ - server_title_bar_button_width * 2;
|
server_window_width_ - server_title_bar_button_width * 2;
|
||||||
ImGui::SetCursorPos(ImVec2(minimize_button_pos_x, 0.0f));
|
ImGui::SetCursorPos(ImVec2(minimize_button_pos_x, 0.0f));
|
||||||
@@ -143,36 +139,18 @@ int Render::ServerWindow() {
|
|||||||
ImVec2(server_title_bar_button_width,
|
ImVec2(server_title_bar_button_width,
|
||||||
server_title_bar_button_height))) {
|
server_title_bar_button_height))) {
|
||||||
if (server_window_) {
|
if (server_window_) {
|
||||||
int w = 0, h = 0;
|
int w = 0;
|
||||||
int x = 0, y = 0;
|
int h = 0;
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
SDL_GetWindowSize(server_window_, &w, &h);
|
SDL_GetWindowSize(server_window_, &w, &h);
|
||||||
SDL_GetWindowPosition(server_window_, &x, &y);
|
SDL_GetWindowPosition(server_window_, &x, &y);
|
||||||
server_window_width_before_compact_ = w;
|
|
||||||
server_window_height_before_compact_ = h;
|
|
||||||
server_window_x_before_compact_ = x;
|
|
||||||
server_window_y_before_compact_ = y;
|
|
||||||
server_window_bounds_saved_ = true;
|
|
||||||
|
|
||||||
constexpr int kCompactSize = 50;
|
const int collapsed_h = (int)server_window_title_bar_height_;
|
||||||
SDL_SetWindowSize(server_window_, kCompactSize, kCompactSize);
|
// Collapse upward: keep top edge stable.
|
||||||
|
SDL_SetWindowSize(server_window_, w, collapsed_h);
|
||||||
// Move to bottom-right of the current display's usable bounds.
|
SDL_SetWindowPosition(server_window_, x, y);
|
||||||
SDL_Rect display_bounds;
|
server_window_collapsed_ = true;
|
||||||
if (SDL_GetDisplayUsableBounds(SDL_GetDisplayForWindow(server_window_),
|
|
||||||
&display_bounds)) {
|
|
||||||
int compact_x = display_bounds.x + display_bounds.w - kCompactSize;
|
|
||||||
int compact_y = display_bounds.y + display_bounds.h - kCompactSize;
|
|
||||||
SDL_SetWindowPosition(server_window_, compact_x, compact_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use pixel size to match transparency buffer on HiDPI.
|
|
||||||
int w_px = kCompactSize;
|
|
||||||
int h_px = kCompactSize;
|
|
||||||
SDL_GetWindowSizeInPixels(server_window_, &w_px, &h_px);
|
|
||||||
const int diameter = (w_px < h_px ? w_px : h_px);
|
|
||||||
SetServerWindowCircleShape(server_window_, diameter);
|
|
||||||
|
|
||||||
server_window_compact_ = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
draw_list->AddLine(
|
draw_list->AddLine(
|
||||||
@@ -212,8 +190,6 @@ int Render::ServerWindow() {
|
|||||||
IM_COL32(0, 0, 0, 255));
|
IM_COL32(0, 0, 0, 255));
|
||||||
|
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(3);
|
||||||
ImGui::PopStyleVar();
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|||||||
Reference in New Issue
Block a user