SDL 3 + curl thread download manager

This commit is contained in:
Anthony 2024-04-01 15:29:00 +02:00
parent 001034db61
commit 42c3d9d215
11 changed files with 313 additions and 145 deletions

View file

@ -12,9 +12,16 @@ LibraryManager::LibraryManager() {}
void LibraryManager::Initialize(const std::string &library_path) void LibraryManager::Initialize(const std::string &library_path)
{ {
m_library_path = library_path; m_library_path = library_path;
CheckDirectories();
Scan(); Scan();
} }
void LibraryManager::CheckDirectories()
{
std::filesystem::path dlDir = std::filesystem::path(m_library_path) / "store";
std::filesystem::create_directories(dlDir);
}
void LibraryManager::Scan() void LibraryManager::Scan()
{ {
std::filesystem::path directoryPath(m_library_path); std::filesystem::path directoryPath(m_library_path);

View file

@ -24,12 +24,17 @@ public:
void Scan(); void Scan();
std::shared_ptr<StoryProject> NewProject(); std::shared_ptr<StoryProject> NewProject();
void CheckDirectories();
std::shared_ptr<StoryProject> GetStory(const std::string &uuid); std::shared_ptr<StoryProject> GetStory(const std::string &uuid);
void SetStoreUrl(const std::string &store_url) { m_storeUrl = store_url; }
std::string GetStoreUrl() const { return m_storeUrl; }
private: private:
std::string m_library_path; std::string m_library_path;
std::vector<std::shared_ptr<StoryProject>> m_projectsList; std::vector<std::shared_ptr<StoryProject>> m_projectsList;
std::string m_storeUrl;
}; };
#endif // LIBRARYMANAGER_H #endif // LIBRARYMANAGER_H

View file

@ -60,24 +60,36 @@ add_compile_definitions(IMGUI_INCLUDE="imgui.h")
add_subdirectory(libs/ImGuiFileDialog) add_subdirectory(libs/ImGuiFileDialog)
# ========================================================================================================================= # =========================================================================================================================
# SDL # SDL2
# ========================================================================================================================= # =========================================================================================================================
Set(FETCHCONTENT_QUIET FALSE)
# FetchContent_Declare(
# sdl2
# GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
# GIT_TAG origin/SDL2
# GIT_SHALLOW TRUE
# GIT_PROGRESS TRUE
# )
# set(BUILD_SHARED_LIBS TRUE)
# set(SDL_STATIC TRUE)
# FetchContent_MakeAvailable(sdl2)
# =========================================================================================================================
# SDL3
# =========================================================================================================================
FetchContent_Declare( FetchContent_Declare(
sdl2 sdl3
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
GIT_TAG origin/SDL2 GIT_TAG prerelease-3.1.0
GIT_SHALLOW TRUE GIT_SHALLOW TRUE
GIT_PROGRESS TRUE GIT_PROGRESS TRUE
) )
set(BUILD_SHARED_LIBS TRUE) set(BUILD_SHARED_LIBS TRUE)
set(SDL_STATIC TRUE) set(SDL_STATIC TRUE)
FetchContent_MakeAvailable(sdl2) FetchContent_MakeAvailable(sdl3)
include_directories(${sdl3_SOURCE_DIR}/include)
# add_subdirectory(libs/SDL)
# include_directories(libs/SDL/include)
# ========================================================================================================================= # =========================================================================================================================
# SDL3-Image # SDL3-Image
@ -155,8 +167,8 @@ set(SRCS
libs/imgui-node-editor/crude_json.cpp libs/imgui-node-editor/crude_json.cpp
libs/ImGuiFileDialog/ImGuiFileDialog.cpp libs/ImGuiFileDialog/ImGuiFileDialog.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_sdl2.cpp ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer2.cpp ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
${imgui_SOURCE_DIR}/imgui.cpp ${imgui_SOURCE_DIR}/imgui.cpp
${imgui_SOURCE_DIR}/imgui_widgets.cpp ${imgui_SOURCE_DIR}/imgui_widgets.cpp
@ -243,16 +255,17 @@ target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC cimg_display=0)
target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC "$<$<CONFIG:DEBUG>:DEBUG>") target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC "$<$<CONFIG:DEBUG>:DEBUG>")
target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl2_BINARY_DIR} ${curl_BINARY_DIR}) target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl3_BINARY_DIR} ${curl_BINARY_DIR})
message(${sdl2_BINARY_DIR})
set(SDL2_BIN_DIR ${sdl2_BINARY_DIR})
set(SDL2_BIN_DIR ${sdl3_BINARY_DIR})
if(UNIX) if(UNIX)
target_link_libraries(${STORY_EDITOR_PROJECT} target_link_libraries(${STORY_EDITOR_PROJECT}
pthread pthread
OpenGL::GL OpenGL::GL
dl dl
SDL2 SDL3
libcurl_static libcurl_static
OpenSSL::SSL OpenSSL::Crypto OpenSSL::SSL OpenSSL::Crypto
) )

View file

@ -11,23 +11,34 @@ your use of the corresponding standard functions.
#include <iostream> #include <iostream>
#include <filesystem> #include <filesystem>
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlrenderer2.h" #include "imgui_internal.h"
#include <stdio.h> // SDL2 ---------------------------------
#include <SDL2/SDL.h> // #include "imgui_impl_sdl2.h"
// #include "imgui_impl_sdlrenderer2.h"
// #include <SDL2/SDL.h>
// #if defined(IMGUI_IMPL_OPENGL_ES2)
// #include <SDL2/SDL_opengles2.h>
// #else
// #include <SDL2/SDL_opengl.h>
//#endif
// SDL3 ---------------------------------
#include "imgui_impl_sdl3.h"
#include "imgui_impl_sdlrenderer3.h"
#include <SDL3/SDL.h>
#if defined(IMGUI_IMPL_OPENGL_ES2) #if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL2/SDL_opengles2.h> #include <SDL3/SDL_opengles2.h>
#else #else
#include <SDL2/SDL_opengl.h> #include <SDL3/SDL_opengl.h>
#endif #endif
#include "IconsMaterialDesignIcons.h" #include "IconsMaterialDesignIcons.h"
#include "IconsFontAwesome5_c.h" #include "IconsFontAwesome5_c.h"
#include "qoi.h" #include "qoi.h"
#include "platform_folders.h"
static void glfw_error_callback(int error, const char* description) static void glfw_error_callback(int error, const char* description)
{ {
fprintf(stderr, "GLFW Error %d: %s\n", error, description); fprintf(stderr, "GLFW Error %d: %s\n", error, description);
@ -50,8 +61,6 @@ static std::string GetFileExtension(const std::string &fileName)
// Simple helper function to load an image into a OpenGL texture with common settings // Simple helper function to load an image into a OpenGL texture with common settings
bool LoadTextureFromFile(const char* filename, Gui::Image &img) bool LoadTextureFromFile(const char* filename, Gui::Image &img)
{ {
std::string ext = GetFileExtension(filename); std::string ext = GetFileExtension(filename);
SDL_Surface* surface = nullptr; SDL_Surface* surface = nullptr;
@ -64,8 +73,12 @@ bool LoadTextureFromFile(const char* filename, Gui::Image &img)
img.w = desc.width; img.w = desc.width;
img.h = desc.height; img.h = desc.height;
surface = SDL_CreateRGBSurfaceFrom((void*)pixels, img.w, img.h, channels * 8, channels * img.w, // SDL3
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); surface = SDL_CreateSurfaceFrom((void*)pixels, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888);
// SDL2
// surface = SDL_CreateRGBSurfaceFrom((void*)pixels, img.w, img.h, channels * 8, channels * img.w,
// 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
if (pixels != NULL) if (pixels != NULL)
{ {
@ -84,12 +97,12 @@ bool LoadTextureFromFile(const char* filename, Gui::Image &img)
} }
// SDL3 //SDL3
// SDL_Surface* surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888); surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA32);
// SDL2 // SDL2
surface = SDL_CreateRGBSurfaceFrom((void*)data, img.w, img.h, channels * 8, channels * img.w, // surface = SDL_CreateRGBSurfaceFrom((void*)data, img.w, img.h, channels * 8, channels * img.w,
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); // 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
stbi_image_free(data); stbi_image_free(data);
} }
@ -105,8 +118,8 @@ bool LoadTextureFromFile(const char* filename, Gui::Image &img)
fprintf(stderr, "Failed to create SDL texture: %s\n", SDL_GetError()); fprintf(stderr, "Failed to create SDL texture: %s\n", SDL_GetError());
} }
// SDL_DestroySurface(surface); // SDL3 SDL_DestroySurface(surface); // SDL3
SDL_FreeSurface(surface); // SDL2 // SDL_FreeSurface(surface); // SDL2
return true; return true;
@ -129,8 +142,11 @@ Gui::Gui()
bool Gui::Initialize() bool Gui::Initialize()
{ {
// Setup SDL // Setup SDL2
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) // if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
// Setup SDL3
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0)
{ {
printf("Error: SDL_Init(): %s\n", SDL_GetError()); printf("Error: SDL_Init(): %s\n", SDL_GetError());
return -1; return -1;
@ -143,17 +159,17 @@ bool Gui::Initialize()
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN);
// SDL3 // SDL3
//window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags); window = SDL_CreateWindow("Story Editor", 1280, 720, window_flags);
// SDL2 // SDL2
window = SDL_CreateWindow("Story Editor", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); // window = SDL_CreateWindow("Story Editor", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
if (window == nullptr) if (window == nullptr)
{ {
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
return -1; return -1;
} }
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); renderer = SDL_CreateRenderer(window, nullptr, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
if (renderer == nullptr) if (renderer == nullptr)
{ {
SDL_Log("Error: SDL_CreateRenderer(): %s\n", SDL_GetError()); SDL_Log("Error: SDL_CreateRenderer(): %s\n", SDL_GetError());
@ -170,6 +186,7 @@ bool Gui::Initialize()
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
io.Fonts->AddFontFromFileTTF( std::string(m_executablePath + "/fonts/roboto.ttf").c_str(), 20); io.Fonts->AddFontFromFileTTF( std::string(m_executablePath + "/fonts/roboto.ttf").c_str(), 20);
@ -201,13 +218,12 @@ bool Gui::Initialize()
// Setup Platform/Renderer backends // Setup Platform/Renderer backends
// SDL3 // SDL3
// ImGui_ImplSDL3_InitForSDLRenderer(window, renderer); ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
// ImGui_ImplSDLRenderer3_Init(renderer); ImGui_ImplSDLRenderer3_Init(renderer);
// SDL2 // SDL2
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer); // ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
ImGui_ImplSDLRenderer2_Init(renderer); // ImGui_ImplSDLRenderer2_Init(renderer);
// Load Fonts // Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
@ -237,20 +253,19 @@ bool Gui::PollEvent()
while (SDL_PollEvent(&event)) while (SDL_PollEvent(&event))
{ {
// SDL3 // SDL3
/*
ImGui_ImplSDL3_ProcessEvent(&event); ImGui_ImplSDL3_ProcessEvent(&event);
if (event.type == SDL_EVENT_QUIT) if (event.type == SDL_EVENT_QUIT)
done = true; done = true;
if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window))
done = true; done = true;
*/
// SLD2 // SLD2
ImGui_ImplSDL2_ProcessEvent(&event); // ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT) // if (event.type == SDL_QUIT)
done = true; // done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) // if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
done = true; // done = true;
} }
return done; return done;
@ -262,12 +277,12 @@ void Gui::StartFrame()
// Start the Dear ImGui frame // Start the Dear ImGui frame
// SDL3 // SDL3
// ImGui_ImplSDLRenderer3_NewFrame(); ImGui_ImplSDLRenderer3_NewFrame();
// ImGui_ImplSDL3_NewFrame(); ImGui_ImplSDL3_NewFrame();
// SDL2 // SDL2
ImGui_ImplSDLRenderer2_NewFrame(); // ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame(); // ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
} }
@ -284,8 +299,8 @@ void Gui::EndFrame()
ImGui::Render(); ImGui::Render();
//ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData()); // SDL3 ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData()); // SDL3
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); // SDL2 // ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); // SDL2
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }
@ -295,12 +310,12 @@ void Gui::Destroy()
// Cleanup // Cleanup
// SDL3 // SDL3
// ImGui_ImplSDLRenderer3_Shutdown(); ImGui_ImplSDLRenderer3_Shutdown();
// ImGui_ImplSDL3_Shutdown(); ImGui_ImplSDL3_Shutdown();
// SDL2 // SDL2
ImGui_ImplSDLRenderer2_Shutdown(); // ImGui_ImplSDLRenderer2_Shutdown();
ImGui_ImplSDL2_Shutdown(); // ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
@ -495,7 +510,7 @@ void Gui::ApplyTheme()
#include "imgui_internal.h"
namespace ImGui { namespace ImGui {
void LoadingIndicatorCircle(const char* label, const float indicator_radius, void LoadingIndicatorCircle(const char* label, const float indicator_radius,
const ImVec4& main_color, const ImVec4& backdrop_color, const ImVec4& main_color, const ImVec4& backdrop_color,

View file

@ -53,10 +53,10 @@ private:
std::string m_executablePath; std::string m_executablePath;
}; };
namespace ImGui { // namespace ImGui {
void LoadingIndicatorCircle(const char* label, const float indicator_radius, // void LoadingIndicatorCircle(const char* label, const float indicator_radius,
const ImVec4& main_color, const ImVec4& backdrop_color, // const ImVec4& main_color, const ImVec4& backdrop_color,
const int circle_count, const float speed); // const int circle_count, const float speed);
} // }
#endif // GUI_H #endif // GUI_H

View file

@ -5,10 +5,26 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <list> #include <list>
#include <functional>
#include "resource.h" #include "resource.h"
#include "connection.h" #include "connection.h"
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
static Ret callback(Args... args) {
return func(args...);
}
static std::function<Ret(Params...)> func;
};
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
class IStoryManager class IStoryManager
{ {
public: public:
@ -36,8 +52,6 @@ public:
virtual void Pause() = 0; virtual void Pause() = 0;
virtual void Next() = 0; virtual void Next() = 0;
virtual void Previous() = 0; virtual void Previous() = 0;
}; };
#endif // I_STORY_MANAGER_H #endif // I_STORY_MANAGER_H

View file

@ -3,61 +3,44 @@
#include "ImGuiFileDialog.h" #include "ImGuiFileDialog.h"
#include <filesystem> #include <filesystem>
#include "IconsMaterialDesignIcons.h" #include "IconsMaterialDesignIcons.h"
#include "i_story_manager.h"
#include <functional>
#define CPPHTTPLIB_OPENSSL_SUPPORT typedef int (*xfer_callback_t)(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
#include "httplib.h" curl_off_t ultotal, curl_off_t ulnow);
#define CA_CERT_FILE "./ca-bundle.crt"
#include <curl/curl.h>
int xfer_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, void download_file(CURL *curl,
curl_off_t ultotal, curl_off_t ulnow) const std::string &url,
const std::string &output_file,
std::function<void(bool)> finished_callback)
{ {
return 0;
}
void download_file(const std::string &output_file = "pi.txt")
{
CURL *curl_download;
FILE *fp; FILE *fp;
CURLcode res; CURLcode res;
std::string url = "http://www.gecif.net/articles/mathematiques/pi/pi_1_million.txt";
curl_download = curl_easy_init(); if (curl)
if (curl_download)
{ {
//SetConsoleTextAttribute(hConsole, 11); //SetConsoleTextAttribute(hConsole, 11);
fp = fopen(output_file.c_str(),"wb"); fp = fopen(output_file.c_str(),"wb");
curl_easy_setopt(curl_download, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl_download, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl_download, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl_download, CURLOPT_NOPROGRESS, 0);
//progress_bar : the fonction for the progress bar
curl_easy_setopt(curl_download, CURLOPT_XFERINFOFUNCTION, xfer_callback);
std::cout<<" Start download"<<std::endl<<std::endl; std::cout<<" Start download"<<std::endl<<std::endl;
res = curl_easy_perform(curl_download); res = curl_easy_perform(curl);
fclose(fp); fclose(fp);
if(res == CURLE_OK) if(res == CURLE_OK)
{ {
std::cout<< std::endl<< std::endl<<" The file was download with succes"<< std::endl; std::cout<< std::endl<< std::endl<<" The file was download with succes"<< std::endl;
} }
else else
{ {
std::cout<< std::endl << std::endl<<" Error"<< std::endl; std::cout<< std::endl << std::endl<<" Error"<< std::endl;
} }
curl_easy_cleanup(curl_download);
finished_callback(res == CURLE_OK);
} }
} }
@ -66,36 +49,78 @@ LibraryWindow::LibraryWindow(IStoryManager &project, LibraryManager &library)
, m_storyManager(project) , m_storyManager(project)
, m_libraryManager(library) , m_libraryManager(library)
{ {
m_downloadThread = std::thread( std::bind(&LibraryWindow::DownloadThread, this) );
download_file(); m_store_url[0] = 0;
}
httplib::SSLClient cli("gist.githubusercontent.com", 443); LibraryWindow::~LibraryWindow()
cli.set_ca_cert_path(CA_CERT_FILE); {
cli.enable_server_certificate_verification(false); // Cancel any pending download
if (auto res = cli.Get("/UnofficialStories/32702fb104aebfe650d4ef8d440092c1/raw/luniicreations.json")) { if (m_curl)
std::cout << res->status << std::endl; {
std::cout << res->get_header_value("Content-Type") << std::endl; m_downloadMutex.lock();
m_storeRawJson = res->body; m_cancel = true;
ParseStoreData(); m_downloadMutex.unlock();
//std::cout << res->body << std::endl;
} else {
std::cout << "error code: " << res.error() << std::endl;
auto result = cli.get_openssl_verify_result();
if (result) {
std::cout << "verify error: " << X509_verify_cert_error_string(result) <<std:: endl;
}
} }
// Quit download thread
m_downloadQueue.push({"quit", ""});
if (m_downloadThread.joinable())
{
m_downloadThread.join();
}
curl_global_cleanup();
} }
void LibraryWindow::ParseStoreData() void LibraryWindow::DownloadThread()
{
for (;;)
{
auto cmd = m_downloadQueue.front();
m_downloadQueue.pop();
if (cmd.order == "quit")
{
curl_easy_cleanup(m_curl);
return;
}
else if (cmd.order == "dl")
{
download_file(m_curl, cmd.url, cmd.filename, cmd.finished_callback);
}
}
}
int LibraryWindow::TransferCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
{
std::cout << "DL total: " << dltotal << ", now: " << dlnow << std::endl;
m_downloadMutex.lock();
bool cancel = m_cancel;
m_downloadMutex.unlock();
if (cancel)
{
return 1; // Annuler la requête curl
}
m_transferProgress.push(TransferProgress(dltotal, dlnow));
return 0;
}
void LibraryWindow::ParseStoreData(bool success)
{ {
try { try {
std::ifstream f(m_storeIndexFilename);
nlohmann::json j = nlohmann::json::parse(m_storeRawJson); nlohmann::json j = nlohmann::json::parse(f);
m_store.clear(); m_store.clear();
for (const auto &obj : j) for (const auto &obj : j)
@ -116,11 +141,28 @@ void LibraryWindow::ParseStoreData()
void LibraryWindow::Initialize() void LibraryWindow::Initialize()
{ {
// Try to download the store index file
m_curl = curl_easy_init();
if (m_curl)
{
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 0);
//progress_bar : the fonction for the progress bar
Callback<int(void *, curl_off_t, curl_off_t, curl_off_t, curl_off_t)>::func = std::bind(
&LibraryWindow::TransferCallback,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
std::placeholders::_5);
curl_easy_setopt(m_curl, CURLOPT_XFERINFOFUNCTION, static_cast<xfer_callback_t>(Callback<int(void *, curl_off_t, curl_off_t, curl_off_t, curl_off_t)>::callback));
}
} }
static bool canValidateDialog = false; static bool canValidateDialog = false;
inline void InfosPane(const char *vFilter, IGFDUserDatas vUserDatas, bool *vCantContinue) // if vCantContinue is false, the user cant validate the dialog inline void InfosPane(const char *vFilter, IGFDUserDatas vUserDatas, bool *vCantContinue) // if vCantContinue is false, the user cant validate the dialog
{ {
@ -131,6 +173,14 @@ inline void InfosPane(const char *vFilter, IGFDUserDatas vUserDatas, bool *vCant
*vCantContinue = canValidateDialog; *vCantContinue = canValidateDialog;
} }
std::string LibraryWindow::ToLocalStoreFile(const std::string &url)
{
auto filename = StoryProject::GetFileName(m_store_url);
filename = m_libraryManager.LibraryPath() + "/store/" + filename;
std::cout << "Store file: " << filename << std::endl;
return filename;
}
void LibraryWindow::Draw() void LibraryWindow::Draw()
{ {
@ -178,8 +228,6 @@ void LibraryWindow::Draw()
// ============================================================================ // ============================================================================
if (ImGui::BeginTabItem("Local library ##LocalTabBar", nullptr, ImGuiTabItemFlags_None)) if (ImGui::BeginTabItem("Local library ##LocalTabBar", nullptr, ImGuiTabItemFlags_None))
{ {
if (ImGui::Button("Scan library")) if (ImGui::Button("Scan library"))
{ {
m_libraryManager.Scan(); m_libraryManager.Scan();
@ -228,10 +276,45 @@ void LibraryWindow::Draw()
} }
// ============================================================================ // ============================================================================
// LOCAL TABLE // STORE STORY LIST
// ============================================================================ // ============================================================================
if (ImGui::BeginTabItem("Remote Store##StoreTabBar", nullptr, ImGuiTabItemFlags_None)) if (ImGui::BeginTabItem("Remote Store##StoreTabBar", nullptr, ImGuiTabItemFlags_None))
{ {
ImGui::InputTextWithHint("##store_url", "Store URL", m_store_url, IM_ARRAYSIZE(m_store_url));
ImGui::SameLine();
if (ImGui::Button("Load"))
{
m_storeIndexFilename = ToLocalStoreFile(m_store_url);
m_downloadQueue.push({
"dl",
m_store_url,
m_storeIndexFilename,
std::bind(&LibraryWindow::ParseStoreData, this, std::placeholders::_1)
});
}
static TransferProgress progressItem;
static std::string currentDownload;
static float progress = 0.0f;
if (m_transferProgress.try_pop(progressItem))
{
if (progressItem.total > 0)
{
// currentDownload = ""
progress += (progressItem.current / progressItem.total);
}
else
{
progress = 0.0;
}
}
// Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
// or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
// ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
// ImGui::Text("Current download: ");
if (ImGui::BeginTable("store_table", 3, tableFlags)) if (ImGui::BeginTable("store_table", 3, tableFlags))
{ {
ImGui::TableSetupColumn("Title", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("Title", ImGuiTableColumnFlags_WidthFixed);

View file

@ -1,14 +1,41 @@
#pragma once #pragma once
#include <thread>
#include "window_base.h" #include "window_base.h"
#include "library_manager.h" #include "library_manager.h"
#include "i_story_manager.h" #include "i_story_manager.h"
#include "thread_safe_queue.h"
#include <curl/curl.h>
struct StoryInf { struct StoryInf {
int age; int age;
std::string title; std::string title;
}; };
struct DownloadCommand {
std::string order;
std::string url;
std::string filename;
std::function<void(bool)> finished_callback;
};
struct TransferProgress {
long total;
long current;
TransferProgress() {
total = 0;
current = 0;
}
TransferProgress(int t, int c) {
total = t;
current = c;
}
};
class LibraryWindow : public WindowBase class LibraryWindow : public WindowBase
{ {
public: public:
@ -17,13 +44,27 @@ public:
void Initialize(); void Initialize();
virtual void Draw() override; virtual void Draw() override;
~LibraryWindow();
private: private:
IStoryManager &m_storyManager; IStoryManager &m_storyManager;
LibraryManager &m_libraryManager; LibraryManager &m_libraryManager;
CURL *m_curl;
char m_store_url[1024];
std::thread m_downloadThread;
ThreadSafeQueue<DownloadCommand> m_downloadQueue;
ThreadSafeQueue<TransferProgress> m_transferProgress;
std::mutex m_downloadMutex;
bool m_cancel{false};
std::vector<StoryInf> m_store; std::vector<StoryInf> m_store;
std::string m_storeIndexFilename;
std::string m_storeRawJson; std::string m_storeRawJson;
void ParseStoreData(); void ParseStoreData(bool success);
void DownloadThread();
int TransferCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
std::string ToLocalStoreFile(const std::string &url);
}; };

View file

@ -1,6 +1,6 @@
#include "main_window.h" #include "main_window.h"
#include <filesystem> #include <filesystem>
#include <SDL.h> #include <SDL3/SDL.h>
#include "platform_folders.h" #include "platform_folders.h"
#include "media_converter.h" #include "media_converter.h"
@ -372,6 +372,8 @@ void MainWindow::DrawMainMenuBar()
void MainWindow::Initialize() void MainWindow::Initialize()
{ {
LoadParams();
// GUI Init // GUI Init
m_gui.Initialize(); m_gui.Initialize();
// gui.ApplyTheme(); // gui.ApplyTheme();
@ -380,8 +382,9 @@ void MainWindow::Initialize()
m_emulatorWindow.Initialize(); m_emulatorWindow.Initialize();
m_nodeEditorWindow.Initialize(); m_nodeEditorWindow.Initialize();
m_PropertiesWindow.Initialize(); m_PropertiesWindow.Initialize();
m_libraryWindow.Initialize();
LoadParams();
} }
@ -979,6 +982,9 @@ void MainWindow::LoadParams()
m_libraryManager.Initialize(library_path); m_libraryManager.Initialize(library_path);
} }
nlohmann::json store_url = j["store_url"];
m_libraryManager.SetStoreUrl(store_url);
} }
catch(std::exception &e) catch(std::exception &e)
{ {

View file

@ -63,24 +63,6 @@ struct DebugContext
}; };
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
static Ret callback(Args... args) {
return func(args...);
}
static std::function<Ret(Params...)> func;
};
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
class MainWindow : public IStoryManager, public IAudioEvent class MainWindow : public IStoryManager, public IAudioEvent
{ {
public: public:

View file

@ -1,4 +1,6 @@
#include "node_editor_window.h" #include "node_editor_window.h"
#include "imgui.h" #include "imgui.h"
#include "imgui_internal.h" #include "imgui_internal.h"
#include <iostream> #include <iostream>