From c02c245e0f2f89efaaec49db823750c2f47450f9 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 25 Apr 2020 21:37:22 -0700 Subject: [PATCH] ui: Refactor --- ui/Makefile.objs | 1 - ui/xemu-hud.cc | 287 +++++++++++++++++++-------------------- ui/xemu-monitor.c | 4 +- ui/xemu-os-utils-linux.c | 6 +- ui/xemu.c | 5 +- 5 files changed, 148 insertions(+), 155 deletions(-) diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 550c9bcdf2..6db83f7206 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -26,7 +26,6 @@ endif # Override with xemu UI sdl.mo-objs := \ imgui/imgui.o \ - imgui/imgui_demo.o \ imgui/imgui_draw.o \ imgui/imgui_widgets.o \ imgui/examples/imgui_impl_opengl3.o \ diff --git a/ui/xemu-hud.cc b/ui/xemu-hud.cc index 22b92e7481..8575419a11 100644 --- a/ui/xemu-hud.cc +++ b/ui/xemu-hud.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include "xemu-hud.h" #include "xemu-input.h" @@ -55,22 +56,21 @@ extern "C" { #undef atomic_fetch_sub } -#include - -using namespace std; - ImFont *g_fixed_width_font; float g_main_menu_height; float g_ui_scale = 1.0; bool g_trigger_style_update = true; -struct NotificationManager { - std::deque notification_queue; +class NotificationManager +{ +private: const int kNotificationDuration = 4000; + std::deque notification_queue; bool active; uint32_t notification_end_ts; const char *msg; +public: NotificationManager() { active = false; @@ -112,6 +112,7 @@ struct NotificationManager { } } +private: void DrawNotification(float t, const char *msg) { const float DISTANCE = 10.0f; @@ -181,10 +182,12 @@ static void HelpMarker(const char* desc) } } -struct MonitorWindow +class MonitorWindow { +public: bool is_open; +private: char InputBuf[256]; ImVector Items; ImVector Commands; @@ -194,6 +197,7 @@ struct MonitorWindow bool AutoScroll; bool ScrollToBottom; +public: MonitorWindow() { is_open = false; @@ -208,7 +212,6 @@ struct MonitorWindow // Portable helpers static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } - static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); } static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; } @@ -262,6 +265,7 @@ struct MonitorWindow ImGui::End(); } +private: void ExecCommand(const char* command_line) { xemu_run_monitor_command(command_line); @@ -322,8 +326,9 @@ struct MonitorWindow } }; -struct InputWindow +class InputWindow { +public: bool is_open; InputWindow() @@ -369,8 +374,8 @@ struct InputWindow // circular numbers above them. These buttons can be activated to // configure the associated port, like a tabbed interface. // - ImVec4 color_active = ImVec4(0.5058, 0.8627, 0.5411, 0.1294); - ImVec4 color_inactive = ImVec4(0, 0, 0, 0); + ImVec4 color_active(0.50, 0.86, 0.54, 0.12); + ImVec4 color_inactive(0, 0, 0, 0); // Begin a 4-column layout to render the ports ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,12)); @@ -529,10 +534,12 @@ struct InputWindow #define MAX_STRING_LEN 2048 // FIXME: Completely arbitrary and only used here // to give a buffer to ImGui for each field -struct SettingsWindow +class SettingsWindow { +public: bool is_open; +private: bool dirty; bool pending_restart; @@ -544,9 +551,13 @@ struct SettingsWindow int memory_idx; bool short_animation; +public: SettingsWindow() { is_open = false; + dirty = false; + pending_restart = false; + flash_path[0] = '\0'; bootrom_path[0] = '\0'; hdd_path[0] = '\0'; @@ -554,15 +565,13 @@ struct SettingsWindow eeprom_path[0] = '\0'; memory_idx = 0; short_animation = false; - pending_restart = false; - dirty = false; } ~SettingsWindow() { } - void Load(void) + void Load() { const char *tmp; int tmp_int; @@ -570,27 +579,27 @@ struct SettingsWindow xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_FLASH_PATH, &tmp); len = strlen(tmp); - assert(len < (MAX_STRING_LEN-1)); + assert(len < MAX_STRING_LEN); strncpy(flash_path, tmp, sizeof(flash_path)); xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_BOOTROM_PATH, &tmp); len = strlen(tmp); - assert(len < (MAX_STRING_LEN-1)); + assert(len < MAX_STRING_LEN); strncpy(bootrom_path, tmp, sizeof(bootrom_path)); xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_HDD_PATH, &tmp); len = strlen(tmp); - assert(len < (MAX_STRING_LEN-1)); + assert(len < MAX_STRING_LEN); strncpy(hdd_path, tmp, sizeof(hdd_path)); xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_DVD_PATH, &tmp); len = strlen(tmp); - assert(len < (MAX_STRING_LEN-1)); + assert(len < MAX_STRING_LEN); strncpy(dvd_path, tmp, sizeof(dvd_path)); xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_EEPROM_PATH, &tmp); len = strlen(tmp); - assert(len < (MAX_STRING_LEN-1)); + assert(len < MAX_STRING_LEN); strncpy(eeprom_path, tmp, sizeof(eeprom_path)); xemu_settings_get_int(XEMU_SETTINGS_SYSTEM_MEMORY, &tmp_int); @@ -602,7 +611,7 @@ struct SettingsWindow dirty = false; } - void Save(void) + void Save() { xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_FLASH_PATH, flash_path); xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_BOOTROM_PATH, bootrom_path); @@ -659,31 +668,31 @@ struct SettingsWindow ImGui::NextColumn(); float picker_width = ImGui::GetColumnWidth()-120*g_ui_scale; ImGui::SetNextItemWidth(picker_width); - FilePicker("###Flash", flash_path, MAX_STRING_LEN, rom_file_filters); + FilePicker("###Flash", flash_path, sizeof(flash_path), rom_file_filters); ImGui::NextColumn(); ImGui::Text("BootROM File"); ImGui::NextColumn(); ImGui::SetNextItemWidth(picker_width); - FilePicker("###BootROM", bootrom_path, MAX_STRING_LEN, rom_file_filters); + FilePicker("###BootROM", bootrom_path, sizeof(bootrom_path), rom_file_filters); ImGui::NextColumn(); ImGui::Text("Hard Disk Image File"); ImGui::NextColumn(); ImGui::SetNextItemWidth(picker_width); - FilePicker("###HDD", hdd_path, MAX_STRING_LEN, qcow_file_filters); + FilePicker("###HDD", hdd_path, sizeof(hdd_path), qcow_file_filters); ImGui::NextColumn(); ImGui::Text("DVD Image File"); ImGui::NextColumn(); ImGui::SetNextItemWidth(picker_width); - FilePicker("###DVD", dvd_path, MAX_STRING_LEN, iso_file_filters); + FilePicker("###DVD", dvd_path, sizeof(dvd_path), iso_file_filters); ImGui::NextColumn(); ImGui::Text("EEPROM File"); ImGui::NextColumn(); ImGui::SetNextItemWidth(picker_width); - FilePicker("###EEPROM", eeprom_path, MAX_STRING_LEN, rom_file_filters); + FilePicker("###EEPROM", eeprom_path, sizeof(eeprom_path), rom_file_filters); ImGui::NextColumn(); ImGui::Text("System Memory"); @@ -726,11 +735,15 @@ struct SettingsWindow } }; -struct AboutWindow +class AboutWindow { +public: bool is_open; + +private: char build_info_text[256]; +public: AboutWindow() { snprintf(build_info_text, sizeof(build_info_text), @@ -786,109 +799,27 @@ struct AboutWindow ImGui::SetCursorPosX(10*g_ui_scale); ImGui::Dummy(ImVec2(0,20*g_ui_scale)); - + const char *msg = "Visit https://xemu.app for more information"; - float button_width = ImGui::GetStyle().FramePadding.x*2 + ImGui::CalcTextSize(msg).x; - ImGui::SetCursorPosX((ImGui::GetWindowWidth()-button_width)/2); - // ImGui::Text("%s", msg); - - if (ImGui::Button(msg, ImVec2(button_width, 0))) { + ImGui::SetCursorPosX((ImGui::GetWindowWidth()-ImGui::CalcTextSize(msg).x)/2); + ImGui::Text("%s", msg); + if (ImGui::IsItemClicked()) { xemu_open_web_browser("https://xemu.app"); } ImGui::Dummy(ImVec2(0,40*g_ui_scale)); ImGui::PushFont(g_fixed_width_font); - ImGui::InputTextMultiline("##build_info", build_info_text, IM_ARRAYSIZE(build_info_text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 6), ImGuiInputTextFlags_ReadOnly); + ImGui::InputTextMultiline("##build_info", build_info_text, sizeof(build_info_text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 6), ImGuiInputTextFlags_ReadOnly); ImGui::PopFont(); - if (ImGui::BeginPopupContextItem("##build_info_context", 1)) - { - if (ImGui::MenuItem("Copy to Clipboard")) { - SDL_SetClipboardText(build_info_text); - } - ImGui::EndPopup(); - } - + ImGui::End(); } }; -struct FirstBootWindow -{ - bool is_open; - - FirstBootWindow() - { - is_open = false; - } - - ~FirstBootWindow() - { - } - - void Draw() - { - if (!is_open) return; - - ImVec2 size(400*g_ui_scale, 300*g_ui_scale); - ImGuiIO& io = ImGui::GetIO(); - - ImVec2 window_pos = ImVec2((io.DisplaySize.x - size.x)/2, (io.DisplaySize.y - size.y)/2); - ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always); - - ImGui::SetNextWindowSize(size, ImGuiCond_Appearing); - if (!ImGui::Begin("First Boot", &is_open, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration)) { - ImGui::End(); - return; - } - - static uint32_t time_start = 0; - if (ImGui::IsWindowAppearing()) { - time_start = SDL_GetTicks(); - } - uint32_t now = SDL_GetTicks() - time_start; - - ImGui::SetCursorPosY(ImGui::GetCursorPosY()-50*g_ui_scale); - ImGui::SetCursorPosX((ImGui::GetWindowWidth()-256*g_ui_scale)/2); - - ImTextureID id = (ImTextureID)(intptr_t)render_to_fbo(logo_fbo); - float t_w = 256.0; - float t_h = 256.0; - float x_off = 0; - ImGui::Image(id, - ImVec2((t_w-x_off)*g_ui_scale, t_h*g_ui_scale), - ImVec2(x_off/t_w, t_h/t_h), - ImVec2(t_w/t_w, 0)); - render_logo(now, 0x42e335ff, 0x42e335ff, 0x00000000); - render_to_default_fb(); - - ImGui::SetCursorPosX(10*g_ui_scale); - ImGui::SetCursorPosY(ImGui::GetCursorPosY()-75*g_ui_scale); - - const char *msg = "To get started, please configure machine settings."; - ImGui::SetCursorPosX((ImGui::GetWindowWidth()-ImGui::CalcTextSize(msg).x)/2); - ImGui::Text("%s", msg); - - ImGui::Dummy(ImVec2(0,20*g_ui_scale)); - ImGui::SetCursorPosX((ImGui::GetWindowWidth()-120*g_ui_scale)/2); - if (ImGui::Button("Settings", ImVec2(120*g_ui_scale, 0))) { - // settings_window.is_open = true; // FIXME - } - ImGui::Dummy(ImVec2(0,20*g_ui_scale)); - - ImGui::SetCursorPosX(10*g_ui_scale); - - msg = "Visit https://xemu.app for more information"; - ImGui::SetCursorPosY(ImGui::GetWindowHeight()-ImGui::CalcTextSize(msg).y-10*g_ui_scale); - ImGui::SetCursorPosX((ImGui::GetWindowWidth()-ImGui::CalcTextSize(msg).x)/2); - ImGui::Text("%s", msg); - - ImGui::End(); - } -}; - -struct NetworkWindow +class NetworkWindow { +public: bool is_open; char remote_addr[64]; char local_addr[64]; @@ -922,8 +853,6 @@ struct NetworkWindow strncpy(local_addr, tmp, sizeof(local_addr)-1); } - bool is_enabled = xemu_net_is_enabled(); - ImGui::TextWrapped( "xemu socket networking works by sending and receiving packets over " "UDP which encapsulate the network traffic that the machine would " @@ -938,6 +867,7 @@ struct NetworkWindow ImGui::SetColumnWidth(0, ImGui::GetWindowWidth()*0.33); ImGuiInputTextFlags flg = 0; + bool is_enabled = xemu_net_is_enabled(); if (is_enabled) { flg |= ImGuiInputTextFlags_ReadOnly; } @@ -987,27 +917,6 @@ struct NetworkWindow } }; - -#ifdef WIN32 -// https://stackoverflow.com/a/2513561 -#include -unsigned long long getTotalSystemMemory() -{ - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx(&status); - return status.ullTotalPhys / (1024 * 1024); -} -#else -#include -unsigned long long getTotalSystemMemory() -{ - long pages = sysconf(_SC_PHYS_PAGES); - long page_size = sysconf(_SC_PAGE_SIZE); - return pages * page_size / (1024 * 1024); -} -#endif - #ifdef CONFIG_CPUID_H #include #endif @@ -1028,8 +937,9 @@ const char *get_cpu_info(void) return cpu_info; } -struct CompatibilityReporter +class CompatibilityReporter { +public: bool is_open; CompatibilityReporter() @@ -1089,7 +999,6 @@ struct CompatibilityReporter "OS: %s\n" "CPU: %s\n" "GPU: %s\n" - "Memory: %lld M\n" "XBE: %s", xemu_version, xemu_branch, @@ -1097,7 +1006,6 @@ struct CompatibilityReporter xemu_get_os_info(), get_cpu_info(), gpu_info, - getTotalSystemMemory(), xbe_info ); @@ -1152,7 +1060,7 @@ struct CompatibilityReporter ImGui::Text("Additional Information"); ImGui::PushFont(g_fixed_width_font); - ImGui::InputTextMultiline("##build_info", report_info, IM_ARRAYSIZE(report_info), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 7), ImGuiInputTextFlags_ReadOnly); + ImGui::InputTextMultiline("##build_info", report_info, sizeof(report_info), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 7), ImGuiInputTextFlags_ReadOnly); ImGui::PopFont(); ImGui::Columns(1); @@ -1171,13 +1079,96 @@ struct CompatibilityReporter static MonitorWindow monitor_window; static InputWindow input_window; static NetworkWindow network_window; -static FirstBootWindow first_boot_window; static AboutWindow about_window; static SettingsWindow settings_window; static CompatibilityReporter compatibility_reporter_window; static NotificationManager notification_manager; static std::deque g_errors; + + +class FirstBootWindow +{ +public: + bool is_open; + + FirstBootWindow() + { + is_open = false; + } + + ~FirstBootWindow() + { + } + + void Draw() + { + if (!is_open) return; + + ImVec2 size(400*g_ui_scale, 300*g_ui_scale); + ImGuiIO& io = ImGui::GetIO(); + + ImVec2 window_pos = ImVec2((io.DisplaySize.x - size.x)/2, (io.DisplaySize.y - size.y)/2); + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always); + + ImGui::SetNextWindowSize(size, ImGuiCond_Appearing); + if (!ImGui::Begin("First Boot", &is_open, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration)) { + ImGui::End(); + return; + } + + static uint32_t time_start = 0; + if (ImGui::IsWindowAppearing()) { + time_start = SDL_GetTicks(); + } + uint32_t now = SDL_GetTicks() - time_start; + + ImGui::SetCursorPosY(ImGui::GetCursorPosY()-50*g_ui_scale); + ImGui::SetCursorPosX((ImGui::GetWindowWidth()-256*g_ui_scale)/2); + + ImTextureID id = (ImTextureID)(intptr_t)render_to_fbo(logo_fbo); + float t_w = 256.0; + float t_h = 256.0; + float x_off = 0; + ImGui::Image(id, + ImVec2((t_w-x_off)*g_ui_scale, t_h*g_ui_scale), + ImVec2(x_off/t_w, t_h/t_h), + ImVec2(t_w/t_w, 0)); + if (ImGui::IsItemClicked()) { + time_start = SDL_GetTicks(); + } + render_logo(now, 0x42e335ff, 0x42e335ff, 0x00000000); + render_to_default_fb(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY()-100*g_ui_scale); + ImGui::SetCursorPosX((ImGui::GetWindowWidth()-ImGui::CalcTextSize(xemu_version).x)/2); + ImGui::Text("%s", xemu_version); + + ImGui::SetCursorPosX(10*g_ui_scale); + ImGui::Dummy(ImVec2(0,20*g_ui_scale)); + + const char *msg = "To get started, please configure machine settings."; + ImGui::SetCursorPosX((ImGui::GetWindowWidth()-ImGui::CalcTextSize(msg).x)/2); + ImGui::Text("%s", msg); + + ImGui::Dummy(ImVec2(0,20*g_ui_scale)); + ImGui::SetCursorPosX((ImGui::GetWindowWidth()-120*g_ui_scale)/2); + if (ImGui::Button("Settings", ImVec2(120*g_ui_scale, 0))) { + settings_window.is_open = true; // FIXME + } + ImGui::Dummy(ImVec2(0,20*g_ui_scale)); + + msg = "Visit https://xemu.app for more information"; + ImGui::SetCursorPosX((ImGui::GetWindowWidth()-ImGui::CalcTextSize(msg).x)/2); + ImGui::Text("%s", msg); + if (ImGui::IsItemClicked()) { + xemu_open_web_browser("https://xemu.app"); + } + + ImGui::End(); + } +}; + static void ShowMainMenu() { bool running = runstate_is_running(); @@ -1293,7 +1284,7 @@ static void InitializeStyle() ImVec4* colors = ImGui::GetStyle().Colors; colors[ImGuiCol_Text] = ImVec4(0.86f, 0.93f, 0.89f, 0.78f); colors[ImGuiCol_TextDisabled] = ImVec4(0.86f, 0.93f, 0.89f, 0.28f); - colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 250.0/255.0); + colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.98f); colors[ImGuiCol_ChildBg] = ImVec4(0.16f, 0.16f, 0.16f, 0.58f); colors[ImGuiCol_PopupBg] = ImVec4(0.16f, 0.16f, 0.16f, 0.90f); colors[ImGuiCol_Border] = ImVec4(0.11f, 0.11f, 0.11f, 0.60f); @@ -1342,6 +1333,7 @@ static void InitializeStyle() } /* External interface, called from ui/xemu.c which handles SDL main loop */ +static FirstBootWindow first_boot_window; static SDL_Window *g_sdl_window; void xemu_hud_init(SDL_Window* window, void* sdl_gl_context) @@ -1360,8 +1352,7 @@ void xemu_hud_init(SDL_Window* window, void* sdl_gl_context) // Setup Platform/Renderer bindings ImGui_ImplSDL2_InitForOpenGL(window, sdl_gl_context); - const char *glsl_version = "#version 150"; - ImGui_ImplOpenGL3_Init(glsl_version); + ImGui_ImplOpenGL3_Init("#version 150"); first_boot_window.is_open = xemu_settings_did_fail_to_load(); diff --git a/ui/xemu-monitor.c b/ui/xemu-monitor.c index d6e99cc83c..2ee6d27306 100644 --- a/ui/xemu-monitor.c +++ b/ui/xemu-monitor.c @@ -102,9 +102,9 @@ void xemu_run_monitor_command(const char *cmd) int len = strlen(cmd)+1; /* FIXME: qemu_chr_be_write needs to be fixed to declare inbuf as const. It - * does not modify the data. Accept the warning for now as a reminder. + * does not modify the data. Cast for now. */ - qemu_chr_be_write(mon_chr, cmd, len); + qemu_chr_be_write(mon_chr, (unsigned char*)cmd, len); } static const TypeInfo char_xemu_type_info = { diff --git a/ui/xemu-os-utils-linux.c b/ui/xemu-os-utils-linux.c index 80d5539996..50e5479d79 100644 --- a/ui/xemu-os-utils-linux.c +++ b/ui/xemu-os-utils-linux.c @@ -69,6 +69,10 @@ const char *xemu_get_os_info(void) void xemu_open_web_browser(const char *url) { char *cmd = g_strdup_printf("xdg-open %s", url); - system(cmd); + int status = system(cmd); + if (status < 0) { + fprintf(stderr, "Failed to run: %s\n", cmd); + } + free(cmd); } diff --git a/ui/xemu.c b/ui/xemu.c index 1cfaad5a19..314f052170 100644 --- a/ui/xemu.c +++ b/ui/xemu.c @@ -1420,9 +1420,8 @@ static void post_swap(void) } } -// #undef main - -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ QemuThread thread; DPRINTF("Entered main()\n");