diff --git a/include/ftpServer.h b/include/ftpServer.h index 13a6899..13f5c68 100644 --- a/include/ftpServer.h +++ b/include/ftpServer.h @@ -28,6 +28,7 @@ #include #include #include +#include #include class FtpServer; @@ -46,6 +47,9 @@ public: /// \param port_ Port to listen on static UniqueFtpServer create (std::uint16_t port_); + /// \brief Get free space + static std::string getFreeSpace (); + /// \brief Update free space static void updateFreeSpace (); diff --git a/source/3ds/platform.cpp b/source/3ds/platform.cpp index 90ad19a..d64306e 100644 --- a/source/3ds/platform.cpp +++ b/source/3ds/platform.cpp @@ -21,6 +21,7 @@ #include "platform.h" #include "fs.h" +#include "ftpServer.h" #include "log.h" #include "imgui_citro3d.h" @@ -250,7 +251,7 @@ void drawStatus () // calculate battery icon position auto const p1 = ImVec2 (screenWidth - batteryWidth, 0.0f); - auto const p2 = ImVec2 (screenWidth, batteryHeight); + auto const p2 = ImVec2 (p1.x + batteryWidth, p1.y + batteryHeight); // calculate battery icon uv coords auto const uv1 = ImVec2 (battery->left, battery->top); @@ -269,8 +270,8 @@ void drawStatus () auto const wifiHeight = wifi->height; // calculate wifi icon position - auto const p3 = ImVec2 (p1.x - wifiWidth - 2.0f, 0.0f); - auto const p4 = ImVec2 (p1.x - 2.0f, wifiHeight); + auto const p3 = ImVec2 (p1.x - wifiWidth - style.FramePadding.x, 0.0f); + auto const p4 = ImVec2 (p3.x + wifiWidth, p3.y + wifiHeight); // calculate wifi icon uv coords auto const uv3 = ImVec2 (wifi->left, wifi->top); @@ -279,36 +280,22 @@ void drawStatus () // draw wifi icon ImGui::GetForegroundDrawList ()->AddImage ( &s_gfxTexture, p3, p4, uv3, uv4, ImGui::GetColorU32 (ImGuiCol_Text)); -#endif // draw current timestamp char timeBuffer[16]; auto const now = std::time (nullptr); std::strftime (timeBuffer, sizeof (timeBuffer), "%H:%M:%S", std::localtime (&now)); -#ifdef CLASSIC - static std::string statusString; + // draw free space + char buffer[64]; + auto const freeSpace = FtpServer::getFreeSpace (); - std::string newStatusString (256, '\0'); - newStatusString.resize (std::sprintf (&newStatusString[0], - "\x1b[0;0H\x1b[32;1m%s \x1b[36;1m%s%s \x1b[37;1m%s\x1b[K", - STATUS_STRING, - s_addr ? inet_ntoa (in_addr{s_addr}) : "Waiting", - s_addr ? ":5000" : "", - timeBuffer)); + std::snprintf ( + buffer, sizeof (buffer), "%s %s", timeBuffer, freeSpace.empty () ? "" : freeSpace.c_str ()); - if (newStatusString != statusString) - { - statusString = std::move (newStatusString); - - consoleSelect (&g_statusConsole); - std::fputs (statusString.c_str (), stdout); - std::fflush (stdout); - } -#else - ImGui::GetForegroundDrawList ()->AddText (ImVec2 (p3.x - 65.0f, style.FramePadding.y), - ImGui::GetColorU32 (ImGuiCol_Text), - timeBuffer); + auto const size = ImGui::CalcTextSize (buffer); + auto const p5 = ImVec2 (p3.x - size.x - style.FramePadding.x, style.FramePadding.y); + ImGui::GetForegroundDrawList ()->AddText (p5, ImGui::GetColorU32 (ImGuiCol_Text), buffer); #endif } } @@ -428,7 +415,6 @@ void platform::render () drawStatus (); #ifdef CLASSIC - drawLog (); gfxFlushBuffers (); gspWaitForVBlank (); gfxSwapBuffers (); diff --git a/source/ftpServer.cpp b/source/ftpServer.cpp index b88963f..24afa72 100644 --- a/source/ftpServer.cpp +++ b/source/ftpServer.cpp @@ -32,6 +32,7 @@ #endif #include +#include #include #include @@ -90,6 +91,32 @@ void FtpServer::draw () #endif #ifdef CLASSIC + { + char port[7]; +#ifndef NDS + auto lock = std::scoped_lock (m_lock); +#endif + if (m_socket) + std::sprintf (port, ":%u", m_socket->sockName ().port ()); + + consoleSelect (&g_statusConsole); + std::printf ("\x1b[0;0H\x1b[32;1m%s \x1b[36;1m%s%s", + STATUS_STRING, + m_socket ? m_socket->sockName ().name () : "Waiting on WiFi", + m_socket ? port : ""); + +#ifndef NDS + char timeBuffer[16]; + auto const now = std::time (nullptr); + std::strftime (timeBuffer, sizeof (timeBuffer), "%H:%M:%S", std::localtime (&now)); + + std::printf (" \x1b[37;1m%s", timeBuffer); +#endif + + std::fputs ("\x1b[K", stdout); + std::fflush (stdout); + } + { #ifndef NDS auto const lock = std::scoped_lock (s_lock); @@ -115,9 +142,11 @@ void FtpServer::draw () session->draw (); if (&session != &m_sessions.back ()) std::fputc ('\n', stdout); - std::fflush (stdout); } + std::fflush (stdout); } + + drawLog (); #else auto const &io = ImGui::GetIO (); auto const width = io.DisplaySize.x; @@ -130,38 +159,29 @@ void FtpServer::draw () #else ImGui::SetNextWindowSize (ImVec2 (width, height)); #endif - ImGui::Begin (STATUS_STRING, - nullptr, - ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); - { - auto const lock = std::scoped_lock (s_lock); - if (!s_freeSpace.empty ()) + char title[64]; + { - ImGui::SameLine (); - ImGui::TextUnformatted (s_freeSpace.c_str ()); + auto const serverLock = std::scoped_lock (m_lock); + std::snprintf (title, + sizeof (title), + STATUS_STRING " %s###ftpd", + m_socket ? m_name.c_str () : "Waiting for WiFi..."); } + + ImGui::Begin (title, + nullptr, + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); } - { - ImGui::SameLine (); - auto const lock = std::scoped_lock (m_lock); - if (m_socket) - ImGui::TextUnformatted (m_name.c_str ()); - else - ImGui::TextUnformatted ("Waiting for network..."); - } - - ImGui::Separator (); - -#ifdef _3DS - // Fill rest of top screen window - ImGui::BeginChild ("Logs", ImVec2 (0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); -#else +#ifndef _3DS ImGui::BeginChild ("Logs", ImVec2 (0, 200), false, ImGuiWindowFlags_HorizontalScrollbar); #endif drawLog (); +#ifndef _3DS ImGui::EndChild (); +#endif #ifdef _3DS ImGui::End (); @@ -192,19 +212,31 @@ UniqueFtpServer FtpServer::create (std::uint16_t const port_) return UniqueFtpServer (new FtpServer (port_)); } +std::string FtpServer::getFreeSpace () +{ +#ifndef NDS + auto const lock = std::scoped_lock (s_lock); +#endif + return s_freeSpace; +} + void FtpServer::updateFreeSpace () { -#if defined(_3DS) || defined(__SWITCH__) struct statvfs st; +#if defined(NDS) || defined(_3DS) || defined(__SWITCH__) if (::statvfs ("sdmc:/", &st) != 0) +#else + if (::statvfs ("/", &st) != 0) +#endif return; auto freeSpace = fs::printSize (static_cast (st.f_bsize) * st.f_bfree); +#ifndef NDS auto const lock = std::scoped_lock (s_lock); +#endif if (freeSpace != s_freeSpace) s_freeSpace = std::move (freeSpace); -#endif } std::time_t FtpServer::startTime () diff --git a/source/linux/platform.cpp b/source/linux/platform.cpp index 7d5e314..546b016 100644 --- a/source/linux/platform.cpp +++ b/source/linux/platform.cpp @@ -20,6 +20,8 @@ #include "platform.h" +#include "ftpServer.h" + #include "imgui.h" #include @@ -188,6 +190,19 @@ bool platform::loop () void platform::render () { + auto const freeSpace = FtpServer::getFreeSpace (); + if (!freeSpace.empty ()) + { + auto const &io = ImGui::GetIO (); + auto const &style = ImGui::GetStyle (); + + auto const size = ImGui::CalcTextSize (freeSpace.c_str ()); + auto const x = io.DisplaySize.x - size.x - style.FramePadding.x; + ImGui::GetForegroundDrawList ()->AddText (ImVec2 (x, style.FramePadding.y), + ImGui::GetColorU32 (ImGuiCol_Text), + freeSpace.c_str ()); + } + ImGui::Render (); glClearColor (0.45f, 0.55f, 0.60f, 1.00f); diff --git a/source/log.cpp b/source/log.cpp index 7d4474b..1e486b6 100644 --- a/source/log.cpp +++ b/source/log.cpp @@ -209,7 +209,6 @@ void addLog (LogLevel const level_, char const *const fmt_, va_list ap_) static char buffer[1024]; std::vsnprintf (buffer, sizeof (buffer), fmt_, ap_); - buffer[sizeof (buffer) - 1] = '\0'; #ifndef NDS auto const lock = std::scoped_lock (s_lock); diff --git a/source/nds/platform.cpp b/source/nds/platform.cpp index 1b48bf6..8a72283 100644 --- a/source/nds/platform.cpp +++ b/source/nds/platform.cpp @@ -108,13 +108,6 @@ bool platform::loop () void platform::render () { swiWaitForVBlank (); - consoleSelect (&g_statusConsole); - std::printf ("\n%s %s%s", - STATUS_STRING, - s_addr.s_addr ? inet_ntoa (s_addr) : "Waiting on WiFi", - s_addr.s_addr ? ":5000" : ""); - std::fflush (stdout); - drawLog (); } void platform::exit () diff --git a/source/switch/platform.cpp b/source/switch/platform.cpp index d740ed6..5b54c21 100644 --- a/source/switch/platform.cpp +++ b/source/switch/platform.cpp @@ -21,6 +21,7 @@ #include "platform.h" #include "fs.h" +#include "ftpServer.h" #include "log.h" #include "imgui_deko3d.h" @@ -396,139 +397,109 @@ void deko3dExit () } #endif -/// \brief Draw time status -void drawTimeStatus () -{ -#ifndef CLASSIC - auto const &io = ImGui::GetIO (); - auto const &style = ImGui::GetStyle (); -#endif - - // draw current timestamp - char timeBuffer[64]; - auto const now = std::time (nullptr); - std::strftime (timeBuffer, sizeof (timeBuffer), "%H:%M:%S", std::localtime (&now)); - -#ifdef CLASSIC - static std::string statusString; - - std::string newStatusString (256, '\0'); - newStatusString.resize (std::sprintf (&newStatusString[0], - "\x1b[0;0H\x1b[32;1m%s \x1b[36;1m%s%s \x1b[37;1m%s\x1b[K", - STATUS_STRING, - s_addr ? inet_ntoa (in_addr{s_addr}) : "Waiting", - s_addr ? ":5000" : "", - timeBuffer)); - - if (newStatusString != statusString) - { - statusString = std::move (newStatusString); - - consoleSelect (&g_statusConsole); - std::fputs (statusString.c_str (), stdout); - std::fflush (stdout); - } -#else - ImGui::GetForegroundDrawList ()->AddText ( - ImVec2 (io.DisplaySize.x - 240.0f, style.FramePadding.y), - ImGui::GetColorU32 (ImGuiCol_Text), - timeBuffer); -#endif -} - -/// \brief Draw network status -void drawNetworkStatus () -{ -#ifndef CLASSIC - TextureIndex netIcon = AIRPLANE_ICON; - - NifmInternetConnectionType type; - std::uint32_t wifiStrength; - NifmInternetConnectionStatus status; - if (R_SUCCEEDED (nifmGetInternetConnectionStatus (&type, &wifiStrength, &status))) - { - if (type == NifmInternetConnectionType_Ethernet) - { - if (status == NifmInternetConnectionStatus_Connected) - netIcon = ETH_ICON; - else - netIcon = ETH_NONE_ICON; - } - else - { - if (wifiStrength >= 3) - netIcon = WIFI3_ICON; - else if (wifiStrength == 2) - netIcon = WIFI3_ICON; - else if (wifiStrength == 1) - netIcon = WIFI3_ICON; - else if (wifiStrength == 0) - netIcon = WIFI_NONE_ICON; - } - } - - auto const &io = ImGui::GetIO (); - auto const &style = ImGui::GetStyle (); - - auto const x1 = io.DisplaySize.x - ICON_WIDTH - 100.0f; - auto const x2 = x1 + ICON_WIDTH; - auto const y1 = style.FramePadding.y; - auto const y2 = y1 + ICON_HEIGHT; - - ImGui::GetForegroundDrawList ()->AddImage ( - imgui::deko3d::makeTextureID (dkMakeTextureHandle (netIcon, 1)), - ImVec2 (x1, y1), - ImVec2 (x2, y2), - ImVec2 (0, 0), - ImVec2 (1, 1), - ImGui::GetColorU32 (ImGuiCol_Text)); -#endif -} - -/// \brief Draw power status -void drawPowerStatus () -{ -#ifndef CLASSIC - std::uint32_t batteryCharge = 0; - psmGetBatteryChargePercentage (&batteryCharge); - - ChargerType charger = ChargerType_None; - psmGetChargerType (&charger); - - TextureIndex powerIcon = BATTERY_ICON; - if (charger != ChargerType_None) - powerIcon = CHARGING_ICON; - - auto const &io = ImGui::GetIO (); - auto const &style = ImGui::GetStyle (); - - auto const x1 = io.DisplaySize.x - ICON_WIDTH - style.FramePadding.x; - auto const x2 = x1 + ICON_WIDTH; - auto const y1 = style.FramePadding.y; - auto const y2 = y1 + ICON_HEIGHT; - - ImGui::GetForegroundDrawList ()->AddImage ( - imgui::deko3d::makeTextureID (dkMakeTextureHandle (powerIcon, 1)), - ImVec2 (x1, y1), - ImVec2 (x2, y2), - ImVec2 (0, 0), - ImVec2 (1, 1), - ImGui::GetColorU32 (ImGuiCol_Text)); - - char buffer[16]; - std::sprintf (buffer, "%3u%%", batteryCharge); - - ImGui::GetForegroundDrawList ()->AddText ( - ImVec2 (x1 - 70.0f, y1), ImGui::GetColorU32 (ImGuiCol_Text), buffer); -#endif -} - /// \brief Draw status void drawStatus () { - drawTimeStatus (); - drawNetworkStatus (); - drawPowerStatus (); +#ifndef CLASSIC + auto const &io = ImGui::GetIO (); + auto const &style = ImGui::GetStyle (); + + auto pos = ImVec2 (io.DisplaySize.x, style.FramePadding.y); + + { + std::uint32_t batteryCharge = 0; + psmGetBatteryChargePercentage (&batteryCharge); + + ChargerType charger = ChargerType_None; + psmGetChargerType (&charger); + + TextureIndex powerIcon = BATTERY_ICON; + if (charger != ChargerType_None) + powerIcon = CHARGING_ICON; + + // draw battery/charging icon + pos.x -= ICON_WIDTH + style.FramePadding.x; + ImGui::GetForegroundDrawList ()->AddImage ( + imgui::deko3d::makeTextureID (dkMakeTextureHandle (powerIcon, 1)), + pos, + ImVec2 (pos.x + ICON_WIDTH, pos.y + ICON_HEIGHT), + ImVec2 (0, 0), + ImVec2 (1, 1), + ImGui::GetColorU32 (ImGuiCol_Text)); + + char buffer[16]; + std::sprintf (buffer, "%u%%", batteryCharge); + + // draw battery percentage + auto const fullWidth = ImGui::CalcTextSize ("100%").x; + auto const partWidth = ImGui::CalcTextSize (buffer).x; + auto const diffWidth = fullWidth - partWidth; + + // janky right-align + pos.x -= partWidth + style.FramePadding.x; + ImGui::GetForegroundDrawList ()->AddText (pos, ImGui::GetColorU32 (ImGuiCol_Text), buffer); + pos.x -= diffWidth; + } + + { + TextureIndex netIcon = AIRPLANE_ICON; + + NifmInternetConnectionType type; + std::uint32_t wifiStrength; + NifmInternetConnectionStatus status; + if (R_SUCCEEDED (nifmGetInternetConnectionStatus (&type, &wifiStrength, &status))) + { + if (type == NifmInternetConnectionType_Ethernet) + { + if (status == NifmInternetConnectionStatus_Connected) + netIcon = ETH_ICON; + else + netIcon = ETH_NONE_ICON; + } + else + { + if (wifiStrength >= 3) + netIcon = WIFI3_ICON; + else if (wifiStrength == 2) + netIcon = WIFI3_ICON; + else if (wifiStrength == 1) + netIcon = WIFI3_ICON; + else if (wifiStrength == 0) + netIcon = WIFI_NONE_ICON; + } + } + + // draw network icon + pos.x -= ICON_WIDTH + style.FramePadding.x; + ImGui::GetForegroundDrawList ()->AddImage ( + imgui::deko3d::makeTextureID (dkMakeTextureHandle (netIcon, 1)), + pos, + ImVec2 (pos.x + ICON_WIDTH, pos.y + ICON_HEIGHT), + ImVec2 (0, 0), + ImVec2 (1, 1), + ImGui::GetColorU32 (ImGuiCol_Text)); + } + + { + // draw free space + auto const freeSpace = FtpServer::getFreeSpace (); + pos.x -= ImGui::CalcTextSize (freeSpace.c_str ()).x + style.FramePadding.x; + ImGui::GetForegroundDrawList ()->AddText ( + pos, ImGui::GetColorU32 (ImGuiCol_Text), freeSpace.c_str ()); + } + + { + // get current timestamp + char timeBuffer[16]; + auto const now = std::time (nullptr); + std::strftime (timeBuffer, sizeof (timeBuffer), "%H:%M:%S", std::localtime (&now)); + + // draw time (centered) + pos.x = (io.DisplaySize.x - ImGui::CalcTextSize (timeBuffer).x) / 2.0f; + ImGui::GetForegroundDrawList ()->AddText ( + pos, ImGui::GetColorU32 (ImGuiCol_Text), timeBuffer); + } +#endif } } @@ -621,7 +592,6 @@ bool platform::loop () void platform::render () { #ifdef CLASSIC - drawLog (); consoleUpdate (&g_statusConsole); consoleUpdate (&g_logConsole); consoleUpdate (&g_sessionConsole);