#include "toolboxWindow.h" #include "optionWindow.h" #include #include #include #include ToolboxWindow::ToolboxWindow(std::shared_ptr& app) : m_webview({.application = app}), m_app(app) {} void ToolboxWindow::initialize() { ensureToolboxInUserPath(); fillToolboxMenu(); configureWindow(); loadResources(); setupToolboxWindow(); } void ToolboxWindow::setupToolboxWindow() { SetJsonItems(); ExposeToJs(); m_webview.set_always_on_top(true); m_webview.set_decorations(false); #ifdef _DEBUG m_webview.set_dev_tools(true); #endif startThreadMonitor(); } void ToolboxWindow::startThreadMonitor() { m_threadMonitor = std::thread([&]() { monitor_focus(); }); m_threadMonitor.detach(); } bool ToolboxWindow::serveHtmlFile(const std::string& htmlPath, bool setDecorations) { auto resources = saucer::embedded::all(); if (!resources.contains(htmlPath)) { std::cerr << "Fehler: '" << htmlPath << "' wurde nicht gefunden!" << std::endl; return false; } m_webview.serve(htmlPath); m_webview.set_decorations(setDecorations); return true; } void ToolboxWindow::configureWindow() { const int screenWidth = GetSystemMetrics(SM_CXSCREEN); const int screenHeight = GetSystemMetrics(SM_CYSCREEN); const int windowWidth = static_cast(screenWidth * (500.0 / 1920.0)); const int windowHeight = static_cast(screenHeight * (700.0 / 1080.0)); m_webview.set_size(windowWidth, windowHeight); m_webview.set_force_dark_mode(true); const int xPos = screenWidth - windowWidth; const int yPos = screenHeight - 42 - windowHeight; if (const HWND hwnd = m_webview.module().get_hwnd()) { SetWindowPos(hwnd, nullptr, xPos, yPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } } void ToolboxWindow::loadResources() { auto resources = saucer::embedded::all(); if (!resources.contains("html/card.html")) { std::cerr << "Fehler: 'card.html' wurde nicht gefunden!" << std::endl; return; } if (const auto it = resources.find("html/index.html"); it == resources.end()) { std::cerr << "Fehler: 'index.html' wurde nicht gefunden!" << std::endl; return; } m_webview.embed(resources); m_webview.serve("html/index.html"); m_webview.set_context_menu(false); if (!resources.contains("ico/toolbox.png")) { std::cerr << "Fehler: 'toolbox.png' wurde nicht gefunden!" << std::endl; return; } const saucer::icon window_icon = saucer::icon::from(resources.find("ico/toolbox.png")->second.content).value(); m_webview.set_icon(window_icon); m_webview.set_title("Toolbox"); m_webview.register_scheme("Toolbox"); } void ToolboxWindow::runLuaScript() { sol::state lua; lua.open_libraries(sol::lib::base); lua.script("print('Hallo von Lua!')"); } void ToolboxWindow::show() { m_webview.show(); m_bShow = true; } void ToolboxWindow::hide() { m_webview.hide(); m_bShow = false; } void ToolboxWindow::ExposeToJs() { // Funktion, die JSON-Code an das JavaScript exponiert m_webview.expose("getToolboxItems", [&]() -> std::string { return jsonString; }, saucer::launch::async); m_webview.expose("run_lua", [&](int id) { run_lua(id); }, saucer::launch::async); m_webview.expose("debug_print", [&]() { debug_print(); }, saucer::launch::async); m_webview.expose("open_file_system", [&]() { open_file_system(); },saucer::launch::async); m_webview.expose("openEinst", [&]() { openEinst(); },saucer::launch::async); m_webview.expose("openIndex", [&]() { openIndex(); },saucer::launch::async); m_webview.expose("getNewContent", [&]() { getNewContent(); },saucer::launch::async); } void ToolboxWindow::SetJsonItems() {// Konvertierung des Vektors in JSON nlohmann::json jsonArray = nlohmann::json::array(); for (const auto& item : m_toolboxItems) { nlohmann::json jsonItem = { {"id", item.id}, {"name", item.name}, {"path", item.path}, {"icon", item.icon}, {"description", item.description}, {"category", item.category}, {"version", item.version}, {"author", item.author}, {"url", item.url}, {"license", item.license} }; jsonArray.push_back(jsonItem); } jsonString = ""; // Konvertiere den JSON-Array in einen String jsonString = jsonArray.dump(); } bool ToolboxWindow::ensureToolboxInUserPath() { // Bestimme das Benutzerverzeichnis abhängig vom Betriebssystem std::filesystem::path userPath; #ifdef _WIN32 userPath = std::getenv("USERPROFILE"); // Windows #else userPath = std::getenv("HOME"); // Unix/Linux/MacOS #endif // Setze den Pfad zum .Toolbox-Verzeichnis // Überprüfe, ob der Pfad existiert if (const std::filesystem::path toolboxPath = userPath / ".Toolbox"; !std::filesystem::exists(toolboxPath)) { try { // Versuche, das Verzeichnis zu erstellen if (std::filesystem::create_directory(toolboxPath)) { std::cout << ".Toolbox Verzeichnis wurde erstellt." << std::endl; return true; } else { std::cerr << "Fehler beim Erstellen des .Toolbox Verzeichnisses." << std::endl; return false; } } catch (const std::filesystem::filesystem_error& e) { std::cerr << "Filesystem-Fehler: " << e.what() << std::endl; return false; } } std::cout << "Das Verzeichnis .Toolbox existiert bereits." << std::endl; return true; } void encodeImageToBase64(const std::filesystem::path& imagePath, ToolboxWindow::ToolboxItem& item) { std::ifstream file(imagePath, std::ios::binary | std::ios::ate); if (!file) { std::cerr << "Fehler beim Öffnen des PNG-Bildes: " << imagePath << std::endl; return; } const std::streamsize fileSize = file.tellg(); file.seekg(0, std::ios::beg); std::vector fileData(fileSize); if (!file.read(reinterpret_cast(fileData.data()), fileSize)) { std::cerr << "Fehler beim Lesen des PNG-Bildes: " << imagePath << std::endl; return; } // Kodieren der Binärdaten mit cppcodec zu Base64 const std::string base64Encoded = cppcodec::base64_rfc4648::encode(fileData); item.icon = "data:image/png;base64," + base64Encoded; } void ToolboxWindow::fillToolboxMenu() { m_toolboxItems.clear(); std::filesystem::path toolboxDir = userPath / ".Toolbox"; if (!std::filesystem::exists(toolboxDir) || !std::filesystem::is_directory(toolboxDir)) { std::cerr << "Fehler: Das Verzeichnis .Toolbox existiert nicht." << std::endl; return; } int id = 0; for (const auto& entry : std::filesystem::directory_iterator(toolboxDir)) { if (!entry.is_directory()) continue; ToolboxItem item; item.id = std::to_string(id++); item.name = entry.path().filename().string(); item.path = entry.path().string(); // Encode Image encodeImageToBase64(entry.path() / "icon.png", item); // Lese Beschreibung von description.txt std::filesystem::path descriptionFile = entry.path() / "description.txt"; if (std::filesystem::exists(descriptionFile)) { std::ifstream descFile(descriptionFile); item.description.assign((std::istreambuf_iterator(descFile)), std::istreambuf_iterator()); } // Lese Beschreibung von description.txt std::filesystem::path luaScript = entry.path() / "start.lua"; if (std::filesystem::exists(luaScript)) { item.lua_script_path_string = luaScript.string(); } m_toolboxItems.push_back(item); } } void ToolboxWindow::run_lua(int id) { /*// Öffnet ein CMD-Fenster, falls noch keins offen ist static bool console_opened = false; if (!console_opened) { AllocConsole(); freopen("CONOUT$", "w", stdout); // stdout auf die Konsole umleiten freopen("CONOUT$", "w", stderr); // stderr auf die Konsole umleiten console_opened = true; }*/ // Lambda-Funktion, um das Lua-Skript auszuführen auto lua_task = [this, id]() { sol::state lua; lua.open_libraries(sol::lib::base, sol::lib::os, sol::lib::string, sol::lib::coroutine, sol::lib::package, sol::lib::table, sol::lib::math, sol::lib::utf8, sol::lib::io); try { std::string scriptPath = m_toolboxItems[id].lua_script_path_string; std::cout << "Running Lua script: " << scriptPath << std::endl; // Lua-Skript ausführen lua.script_file(scriptPath); // Nach erfolgreichem Ausführen UI aktualisieren m_webview.execute("enableButtonByToolId({})", saucer::make_args(id)); m_webview.reload(); } catch (const sol::error& e) { // Lua-Fehler in der Konsole ausgeben std::cerr << "Lua error: " << e.what() << std::endl; // Nach Fehler UI aktualisieren m_webview.execute("enableButtonByToolId({})", saucer::make_args(id)); m_webview.reload(); } }; // Erstellen und starten des Threads std::thread lua_thread(lua_task); // Thread lösen, um die Anwendung nicht zu blockieren lua_thread.detach(); std::cout << "Lua-Skript wurde gestartet." << std::endl; } void ToolboxWindow::debug_print() { std::cout << "ToolboxWindow::debug_print()" << std::endl; } ToolboxWindow::~ToolboxWindow() { m_runningMonitor = false; } void ToolboxWindow::monitor_focus() { while (m_runningMonitor) { if (m_bShow && !m_webview.focused() && isIndex) { this->hide(); } // Schlafpause hinzufügen, um die CPU-Last zu reduzieren std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } void ToolboxWindow::open_file_system() { if (const std::filesystem::path toolboxDir = userPath / ".Toolbox"; std::filesystem::exists(toolboxDir) && std::filesystem::is_directory(toolboxDir)) { std::string path = toolboxDir.string(); std::string command; #ifdef _WIN32 command = "explorer \"" + path + "\""; #elif __APPLE__ command = "open \"" + path + "\""; #elif __linux__ command = "xdg-open \"" + path + "\""; #else std::cerr << "Fehler: Plattform nicht unterstützt." << std::endl; return; #endif if (const int result = std::system(command.c_str()); result != 0) { std::cerr << "Fehler beim Öffnen des Verzeichnisses: " << result << std::endl; } } else { std::cerr << "Fehler: Das Verzeichnis .Toolbox existiert nicht." << std::endl; } fillToolboxMenu(); SetJsonItems(); m_webview.execute("reloadContent({})",saucer::make_args()); } // Beispielhafte Nutzung: void ToolboxWindow::openEinst() { if (!serveHtmlFile("html/einstellungen.html", true)) { return; } isIndex = false; } void ToolboxWindow::openIndex() { if (!serveHtmlFile("html/index.html", false)) { return; } getNewContent(); } void ToolboxWindow::getNewContent() { configureWindow(); fillToolboxMenu(); SetJsonItems(); m_webview.execute("reloadContent({})", saucer::make_args()); isIndex = true; }