diff --git a/include/Helpers/StringHelpers.cpp b/include/Helpers/StringHelpers.cpp index 7ef6bb6..e15a5c7 100644 --- a/include/Helpers/StringHelpers.cpp +++ b/include/Helpers/StringHelpers.cpp @@ -1,4 +1,6 @@ #include "StringHelpers.hpp" +#include +#include #include #include #include @@ -114,3 +116,20 @@ std::string ensure_string_unique(const std::vector& stringList, std } return str; } + +std::chrono::system_clock::time_point sdl_time_to_chrono_time(const SDL_Time& t) { + time_t unixTime = SDL_NS_TO_SECONDS(t); + return std::chrono::system_clock::from_time_t(unixTime); +} + +std::string chrono_time_to_nice_date(const std::chrono::system_clock::time_point& t, SDL_DateFormat f) { + switch(f) { + case SDL_DATE_FORMAT_YYYYMMDD: + return std::format("{:%Y-%m-%d}", t); + case SDL_DATE_FORMAT_DDMMYYYY: + return std::format("{:%d %b, %Y}", t); + case SDL_DATE_FORMAT_MMDDYYYY: + return std::format("{:%b %d, %Y}", t); + } + return ""; +} diff --git a/include/Helpers/StringHelpers.hpp b/include/Helpers/StringHelpers.hpp index 709b33d..d2e0b66 100644 --- a/include/Helpers/StringHelpers.hpp +++ b/include/Helpers/StringHelpers.hpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include std::vector split_string_by_token(std::string str, std::string token); @@ -13,3 +15,5 @@ std::string read_file_to_string(const std::filesystem::path& filePath); bool is_valid_http_url(const std::string& str); std::string remove_carriage_returns_from_str(std::string s); std::string ensure_string_unique(const std::vector& stringList, std::string str); +std::chrono::system_clock::time_point sdl_time_to_chrono_time(const SDL_Time& t); +std::string chrono_time_to_nice_date(const std::chrono::system_clock::time_point& t, SDL_DateFormat f); diff --git a/src/GUIHolder.cpp b/src/GUIHolder.cpp index fd3f0ab..499cf54 100644 --- a/src/GUIHolder.cpp +++ b/src/GUIHolder.cpp @@ -102,9 +102,10 @@ float GUIHolder::final_gui_scale() { } void GUIHolder::calculate_final_gui_scale() { - Vector2f maxWindowSizeBeforeForcedFit = final_gui_scale_not_fit() * Vector2f{700.0f, 700.0f}; - Vector2f fitRatio = {main.window.size.x() / maxWindowSizeBeforeForcedFit.x(), main.window.size.y() / maxWindowSizeBeforeForcedFit.y()}; - finalCalculatedGuiScale = final_gui_scale_not_fit() * std::min(std::min(fitRatio.x(), fitRatio.y()), 1.0f); + finalCalculatedGuiScale = final_gui_scale_not_fit(); + //Vector2f maxWindowSizeBeforeForcedFit = final_gui_scale_not_fit() * Vector2f{700.0f, 700.0f}; + //Vector2f fitRatio = {main.window.size.x() / maxWindowSizeBeforeForcedFit.x(), main.window.size.y() / maxWindowSizeBeforeForcedFit.y()}; + //finalCalculatedGuiScale = final_gui_scale_not_fit() * std::min(std::min(fitRatio.x(), fitRatio.y()), 1.0f); } float GUIHolder::final_gui_scale_not_fit() { diff --git a/src/GUIStuff/Elements/ImageDisplay.cpp b/src/GUIStuff/Elements/ImageDisplay.cpp index 70c5119..1bcb8a2 100644 --- a/src/GUIStuff/Elements/ImageDisplay.cpp +++ b/src/GUIStuff/Elements/ImageDisplay.cpp @@ -1,16 +1,18 @@ #include "ImageDisplay.hpp" #include "../GUIManager.hpp" #include +#include namespace GUIStuff { ImageDisplay::ImageDisplay(GUIManager& gui): Element(gui) {} -void ImageDisplay::layout(const Clay_ElementId& id, const std::filesystem::path& imgPath) { - if(imgPath != oldImgPath) { +void ImageDisplay::layout(const Clay_ElementId& id, const Data& data) { + if(data != d) { + d = data; std::string imgData; try { - imgData = read_file_to_string(imgPath); + imgData = read_file_to_string(data.imgPath); auto codec = SkCodec::MakeFromData(SkData::MakeWithoutCopy(imgData.c_str(), imgData.size()), { SkJpegDecoder::Decoder() }); @@ -30,12 +32,23 @@ void ImageDisplay::layout(const Clay_ElementId& id, const std::filesystem::path& void ImageDisplay::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) { if(img) { - canvas->drawImageRect(img, boundingBox.value().get_sk_rect(), {SkFilterMode::kLinear, SkMipmapMode::kNone}); + SkPaint p; + p.setAntiAlias(skiaAA); + if(d.radius != 0.0f) { + canvas->save(); + SkRRect r = SkRRect::MakeRectXY(boundingBox.value().get_sk_rect(), d.radius, d.radius); + canvas->clipRRect(r, skiaAA); + canvas->drawImageRect(img, boundingBox.value().get_sk_rect(), {SkFilterMode::kLinear, SkMipmapMode::kNone}, &p); + canvas->restore(); + } + else + canvas->drawImageRect(img, boundingBox.value().get_sk_rect(), {SkFilterMode::kLinear, SkMipmapMode::kNone}, &p); } else { SkPaint p{io.theme->frontColor1}; p.setAntiAlias(skiaAA); - canvas->drawRect(boundingBox.value().get_sk_rect(), p); + SkRRect r = SkRRect::MakeRectXY(boundingBox.value().get_sk_rect(), d.radius, d.radius); + canvas->drawRRect(r, p); } } diff --git a/src/GUIStuff/Elements/ImageDisplay.hpp b/src/GUIStuff/Elements/ImageDisplay.hpp index 59e3f66..e66e150 100644 --- a/src/GUIStuff/Elements/ImageDisplay.hpp +++ b/src/GUIStuff/Elements/ImageDisplay.hpp @@ -7,11 +7,16 @@ namespace GUIStuff { class ImageDisplay : public Element { public: ImageDisplay(GUIManager& gui); - void layout(const Clay_ElementId& id, const std::filesystem::path& imgPath); + struct Data { + std::filesystem::path imgPath; + float radius = 0.0f; + bool operator==(const Data& d) const = default; + }; + void layout(const Clay_ElementId& id, const Data& data); virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override; private: - std::filesystem::path oldImgPath; + Data d; sk_sp img; }; diff --git a/src/GlobalConfig.cpp b/src/GlobalConfig.cpp index 874f7dc..05863fc 100644 --- a/src/GlobalConfig.cpp +++ b/src/GlobalConfig.cpp @@ -2,11 +2,13 @@ #include #include "ResourceDisplay/ImageResourceDisplay.hpp" #include "DrawingProgram/DrawingProgramCache.hpp" +#include #include GlobalConfig::GlobalConfig() { load_default_palette(); displayName = Random::get().alphanumeric_str(10); + SDL_GetDateTimeLocalePreferences(&dateFormat, &timeFormat); } nlohmann::json GlobalConfig::get_config_json(const InputManager& input) const { diff --git a/src/GlobalConfig.hpp b/src/GlobalConfig.hpp index 02d7e98..15a7991 100644 --- a/src/GlobalConfig.hpp +++ b/src/GlobalConfig.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include "InputManager.hpp" @@ -69,6 +70,9 @@ class GlobalConfig { bool disableGraphicsDriverWorkarounds = false; int vsyncValue = 1; + SDL_DateFormat dateFormat = SDL_DATE_FORMAT_DDMMYYYY; + SDL_TimeFormat timeFormat = SDL_TIME_FORMAT_12HR; + #ifndef __EMSCRIPTEN__ bool applyDisplayScale = true; #endif diff --git a/src/Screens/FileSelectScreen.cpp b/src/Screens/FileSelectScreen.cpp index df09f22..b411dac 100644 --- a/src/Screens/FileSelectScreen.cpp +++ b/src/Screens/FileSelectScreen.cpp @@ -6,6 +6,7 @@ #include "../GUIStuff/Elements/GridScrollArea.hpp" #include "../GUIStuff/Elements/ImageDisplay.hpp" #include "../World.hpp" +#include "Helpers/StringHelpers.hpp" FileSelectScreen::FileSelectScreen(MainProgram& m): Screen(m) {} @@ -17,7 +18,7 @@ void FileSelectScreen::gui_layout_run() { CLAY_AUTO_ID({ .layout = { .sizing = {.width = CLAY_SIZING_FIXED(gui.io.windowSize.x()), .height = CLAY_SIZING_FIXED(gui.io.windowSize.y())}, - .padding = CLAY_PADDING_ALL(15), + .padding = {.top = 15}, .childGap = 15, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP }, .layoutDirection = CLAY_TOP_TO_BOTTOM, @@ -28,14 +29,14 @@ void FileSelectScreen::gui_layout_run() { gui.element("File selector grid", GridScrollArea::Options{ .entryMaximumWidth = 200.0f, .childAlignmentX = CLAY_ALIGN_X_LEFT, - .entryHeight = 250.0f, + .entryHeight = 220.0f, .entryCount = fileList.size(), .elementContent = [&](size_t i) { CLAY_AUTO_ID({ .layout = { - .sizing = { .width = CLAY_SIZING_FIXED(150), .height = CLAY_SIZING_GROW(0)}, + .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, .padding = CLAY_PADDING_ALL(gui.io.theme->padding1), - .childGap = 2, + .childGap = 6, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .layoutDirection = CLAY_TOP_TO_BOTTOM } @@ -44,19 +45,23 @@ void FileSelectScreen::gui_layout_run() { .layout = { .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }}, .aspectRatio = { .aspectRatio = 1.0f } }) { - gui.element("ico", main.conf.configPath / "saveThumbnails" / (fileList[i] + ".jpg")); + gui.element("ico", ImageDisplay::Data{ + .imgPath = main.conf.configPath / "saveThumbnails" / (fileList[i].fileName + ".jpg"), + .radius = 20 + }); } - text_label(gui, fileList[i]); + text_label(gui, fileList[i].fileName); + text_label_light(gui, fileList[i].lastAccessDate); } } }); } } -const std::vector& FileSelectScreen::get_file_list() { +const std::vector& FileSelectScreen::get_file_list() { if(!fileListOptional.has_value()) { std::filesystem::path savePath = main.conf.configPath / "saves"; - fileListOptional = std::vector(); + fileListOptional = std::vector(); auto& fL = fileListOptional.value(); int globCount; char** filesInPath = SDL_GlobDirectory(savePath.string().c_str(), "*", 0, &globCount); @@ -64,8 +69,14 @@ const std::vector& FileSelectScreen::get_file_list() { for(int i = 0; i < globCount; i++) { std::filesystem::path p = filesInPath[i]; std::string fExt = p.extension().string(); - if(fExt == "." + World::FILE_EXTENSION) - fL.emplace_back(p.stem().string()); + if(fExt == "." + World::FILE_EXTENSION) { + SDL_PathInfo pathInfo; + SDL_DateTime pathDt; + SDL_GetPathInfo(savePath.string().c_str(), &pathInfo); + SDL_TimeToDateTime(pathInfo.access_time, &pathDt, true); + SDL_NS_TO_SECONDS(pathInfo.access_time); + fL.emplace_back(p.stem().string(), pathInfo.access_time, chrono_time_to_nice_date(sdl_time_to_chrono_time(pathInfo.access_time), main.conf.dateFormat)); + } } } } diff --git a/src/Screens/FileSelectScreen.hpp b/src/Screens/FileSelectScreen.hpp index 109203d..a2e757c 100644 --- a/src/Screens/FileSelectScreen.hpp +++ b/src/Screens/FileSelectScreen.hpp @@ -7,6 +7,11 @@ class FileSelectScreen : public Screen { virtual void gui_layout_run() override; virtual void draw(SkCanvas* canvas) override; private: - const std::vector& get_file_list(); - std::optional> fileListOptional; + struct FileInfo { + std::string fileName; + SDL_Time lastAccessTime; + std::string lastAccessDate; + }; + const std::vector& get_file_list(); + std::optional> fileListOptional; };