Files
Toolbox/src/toolboxWindow.cpp
Yadciel f49d8874c1 Add Cython setup and enhance installer functionality
Introduced a Cython-based setup to compile Python files for performance improvements. Updated installer scripts with customtkinter modifications for better UI, added support for additional content loading, and enhanced project structure. Adjusted build commands, streamlined file paths, and integrated new UI elements in the HTML resources.
2024-12-22 20:24:23 +01:00

387 lines
12 KiB
C++

#include "toolboxWindow.h"
#include "optionWindow.h"
#include <iostream>
#include <windows.h>
#include <nlohmann/json.hpp>
#include <cppcodec/base64_rfc4648.hpp>
ToolboxWindow::ToolboxWindow(std::shared_ptr<saucer::application>& 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<int>(screenWidth * (500.0 / 1920.0));
const int windowHeight = static_cast<int>(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<hwnd_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<unsigned char> fileData(fileSize);
if (!file.read(reinterpret_cast<char*>(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<char>(descFile)),
std::istreambuf_iterator<char>());
}
// 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;
}