Fügt Einstellungsfenster und Lua-Skriptausführung hinzu
Implementiert ein Einstellungsfenster zur Konfiguration von Lua-Skript-Timeouts und anderen Einstellungen. Ermöglicht die Ausführung von Lua-Skripten in einem separaten Thread mit Abbruchfunktion und Timeout-Mechanismus. Verbessert die Benutzererfahrung durch Hinzufügen der Möglichkeit, das Toolbox-Verzeichnis im Dateisystem zu öffnen. Behebt Fokusprobleme und verbessert die Fensterpositionierung und -größe.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
class toolboxTray : public tray {
|
||||
public:
|
||||
// Konstruktor mit optionalen Parametern für Icon und Tooltip
|
||||
toolboxTray(const char* icon = nullptr, const char* tooltip = nullptr) {
|
||||
explicit toolboxTray(const char* icon = nullptr, const char* tooltip = nullptr) : tray() {
|
||||
this->icon = icon;
|
||||
this->tooltip = const_cast<char*>(tooltip);
|
||||
this->menu = nullptr; // Initialisiere ohne Menü (kann später gesetzt werden)
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <saucer/embedded/all.hpp>
|
||||
#include <sol/sol.hpp>
|
||||
#include <saucer/webview.hpp>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include "optionWindow.h"
|
||||
#include "toolConfig.h"
|
||||
|
||||
class ToolboxWindow {
|
||||
public:
|
||||
@@ -21,6 +25,7 @@ public:
|
||||
void initialize();
|
||||
|
||||
void setupToolboxWindow();
|
||||
void toggleDevTools();
|
||||
|
||||
std::atomic_bool isIndex = true;
|
||||
|
||||
@@ -40,12 +45,13 @@ public:
|
||||
|
||||
std::vector<ToolboxItem> m_toolboxItems;
|
||||
|
||||
saucer::smartview<saucer::default_serializer> m_webview;
|
||||
saucer::smartview m_webview;
|
||||
|
||||
private:
|
||||
std::unique_ptr<hwnd_module> m_hwnd_module;
|
||||
HWND m_hwnd{};
|
||||
std::shared_ptr<saucer::application> m_app;
|
||||
std::unique_ptr<optionWindow> m_optionWindow;
|
||||
std::thread m_threadMonitor;
|
||||
std::atomic<bool> m_runningMonitor = true;
|
||||
|
||||
@@ -77,6 +83,7 @@ private:
|
||||
void debug_print();
|
||||
|
||||
void run_lua(int id);
|
||||
void cancel_lua(int id);
|
||||
|
||||
void monitor_focus();
|
||||
|
||||
@@ -85,10 +92,31 @@ private:
|
||||
void SetJsonItems();
|
||||
|
||||
void openEinst();
|
||||
void openEinst(int id);
|
||||
void centerWindow();
|
||||
void resizeWindow(int width, int height);
|
||||
void resizeWindow(double widthPercent, double heightPercent);
|
||||
|
||||
void openIndex();
|
||||
void getNewContent();
|
||||
|
||||
int getLuaTimeoutSeconds();
|
||||
void setLuaTimeoutSeconds(int seconds);
|
||||
std::string getActiveToolName();
|
||||
|
||||
struct LuaTask {
|
||||
std::shared_ptr<std::atomic_bool> cancel;
|
||||
};
|
||||
|
||||
std::mutex m_luaTasksMutex;
|
||||
std::unordered_map<int, LuaTask> m_luaTasks;
|
||||
|
||||
int m_activeToolId = -1;
|
||||
ToolConfigStore m_configStore;
|
||||
|
||||
std::filesystem::path getToolConfigPath(int id) const;
|
||||
void ensureConfigExists(int id) const;
|
||||
int getLuaTimeoutSecondsForId(int id) const;
|
||||
std::string getToolConfigIni() const;
|
||||
void setToolConfigIni(const std::string &content);
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Toolbox</title>
|
||||
<link rel="stylesheet" href="../highlight/styles/dark.css" media="all" title="dark">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
@@ -129,7 +128,7 @@
|
||||
flex: 1;
|
||||
background: #1e1e2e;
|
||||
padding: 15px;
|
||||
display: none; /* Standardmäßig ausgeblendet */
|
||||
display: flex; /* Standardmäßig sichtbar */
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -170,18 +169,32 @@
|
||||
<div class="editor" id="editor">
|
||||
<label for="code-editor"></label>
|
||||
<textarea id="code-editor" placeholder="Write Lua code here..."></textarea>
|
||||
<pre><code id="highlightedOutput" class="language-lua"></code></pre>
|
||||
<pre><code id="highlightedOutput" class="language-lua"></code></pre>
|
||||
</div>
|
||||
|
||||
<div class="general" id="general"></div>
|
||||
<div class="general" id="general">
|
||||
<div style="width: 80%; max-width: 520px;">
|
||||
<h3 style="margin: 0 0 10px 0;">Tool</h3>
|
||||
<div id="tool-name" style="margin-bottom: 20px; color: #ff79c6;">-</div>
|
||||
|
||||
<label for="lua-timeout">Lua Timeout (Sekunden)</label>
|
||||
<input id="lua-timeout" type="number" min="0" step="1" value="30"
|
||||
style="width: 100%; margin-top: 6px; padding: 8px; border-radius: 4px; border: 1px solid #32334a; background: #2b2c3b; color: #fff;">
|
||||
<div style="margin-top: 6px; font-size: 12px; color: #aaa;">
|
||||
0 = kein Timeout
|
||||
</div>
|
||||
|
||||
<button id="save-settings" class="back-button" style="margin-top: 16px;">Speichern</button>
|
||||
<div id="save-status" style="margin-top: 8px; font-size: 12px; color: #aaa;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="footer">
|
||||
<!--Schmidti.Digital © 2024-->
|
||||
</div>
|
||||
</div>
|
||||
<script src="../highlight/highlight.min.js"></script>
|
||||
<script src="../highlight/languages/lua.min.js"></script>
|
||||
<script>
|
||||
function goBack() {
|
||||
saucer.exposed.openIndex();
|
||||
@@ -206,13 +219,40 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const editor = document.getElementById('code-editor');
|
||||
const output = document.getElementById('highlightedOutput');
|
||||
showContent('general');
|
||||
|
||||
// Synchronisiere den Inhalt von textarea mit dem Codeblock
|
||||
editor.addEventListener('input', () => {
|
||||
output.innerHTML = ''; // Vorheriges Highlighting entfernen
|
||||
output.textContent = editor.value; // Aktuellen Text setzen
|
||||
hljs.highlightAll();
|
||||
if (window.hljs && typeof hljs.highlightAll === 'function') {
|
||||
hljs.highlightAll();
|
||||
}
|
||||
});
|
||||
|
||||
const toolName = document.getElementById('tool-name');
|
||||
const timeoutInput = document.getElementById('lua-timeout');
|
||||
const saveBtn = document.getElementById('save-settings');
|
||||
const saveStatus = document.getElementById('save-status');
|
||||
|
||||
saucer.exposed.getActiveToolName().then(name => {
|
||||
toolName.textContent = name || '-';
|
||||
});
|
||||
|
||||
saucer.exposed.getLuaTimeoutSeconds().then(value => {
|
||||
timeoutInput.value = value;
|
||||
});
|
||||
|
||||
|
||||
saveBtn.addEventListener('click', () => {
|
||||
const seconds = parseInt(timeoutInput.value, 10);
|
||||
saucer.exposed.setLuaTimeoutSeconds(Number.isFinite(seconds) ? seconds : 0);
|
||||
saveStatus.textContent = 'Gespeichert';
|
||||
setTimeout(() => {
|
||||
saveStatus.textContent = '';
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -2,29 +2,103 @@
|
||||
#include <iostream>
|
||||
#include <windows.h>
|
||||
#include <saucer/embedded/all.hpp>
|
||||
#include <saucer/navigation.hpp>
|
||||
#include <saucer/app.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
optionWindow::optionWindow(std::shared_ptr<saucer::application>& app)
|
||||
namespace {
|
||||
std::unordered_map<HWND, WNDPROC> g_option_prev_procs;
|
||||
|
||||
LRESULT CALLBACK option_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
if (msg == WM_KEYDOWN && wparam == VK_F12) {
|
||||
auto *self = reinterpret_cast<optionWindow *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
if (self) {
|
||||
self->toggleDevTools();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
const auto it = g_option_prev_procs.find(hwnd);
|
||||
if (it != g_option_prev_procs.end()) {
|
||||
return CallWindowProc(it->second, hwnd, msg, wparam, lparam);
|
||||
}
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void install_option_f12_toggle(HWND hwnd, optionWindow *self) {
|
||||
if (!hwnd || !self) {
|
||||
return;
|
||||
}
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
|
||||
auto prev = reinterpret_cast<WNDPROC>(
|
||||
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(option_wndproc))
|
||||
);
|
||||
if (prev) {
|
||||
g_option_prev_procs[hwnd] = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optionWindow::optionWindow(std::shared_ptr<saucer::application>& app,
|
||||
std::function<int()> getLuaTimeoutSeconds,
|
||||
std::function<void(int)> setLuaTimeoutSeconds,
|
||||
std::function<std::string()> getActiveToolName,
|
||||
std::function<std::string()> getToolConfigIni,
|
||||
std::function<void(const std::string &)> setToolConfigIni,
|
||||
std::function<void()> openIndex)
|
||||
: m_app(app)
|
||||
, m_webview([&]() -> saucer::smartview<> {
|
||||
, m_webview([&]() -> saucer::smartview {
|
||||
auto window_res = saucer::window::create(app.get());
|
||||
if (!window_res.has_value()) {
|
||||
throw std::runtime_error("optionWindow: failed to create saucer::window");
|
||||
}
|
||||
saucer::webview::options opts{window_res.value()};
|
||||
auto sv_res = saucer::smartview<>::create(opts);
|
||||
opts.browser_flags.insert("--disable-gpu");
|
||||
auto sv_res = saucer::smartview::create(opts);
|
||||
if (!sv_res.has_value()) {
|
||||
throw std::runtime_error("optionWindow: failed to create saucer::smartview");
|
||||
}
|
||||
return std::move(sv_res.value());
|
||||
}())
|
||||
, m_hwnd()
|
||||
, m_getLuaTimeoutSeconds(std::move(getLuaTimeoutSeconds))
|
||||
, m_setLuaTimeoutSeconds(std::move(setLuaTimeoutSeconds))
|
||||
, m_getActiveToolName(std::move(getActiveToolName))
|
||||
, m_getToolConfigIni(std::move(getToolConfigIni))
|
||||
, m_setToolConfigIni(std::move(setToolConfigIni))
|
||||
, m_openIndex(std::move(openIndex))
|
||||
{
|
||||
}
|
||||
|
||||
void optionWindow::initialize() {
|
||||
// Modul hinzufügen
|
||||
m_hwnd_module = std::make_unique<hwnd_module>(&m_webview);
|
||||
m_hwnd = m_hwnd_module->get_hwnd();
|
||||
install_option_f12_toggle(m_hwnd, this);
|
||||
configureWindow();
|
||||
exposeToJs();
|
||||
loadResources();
|
||||
#ifdef _DEBUG
|
||||
m_webview.set_dev_tools(false);
|
||||
#endif
|
||||
m_webview.on<saucer::webview::event::navigate>([](const saucer::navigation& nav) {
|
||||
const auto scheme = nav.url().scheme();
|
||||
const auto host = nav.url().host();
|
||||
if (scheme == "saucer" && host && *host == "embedded") {
|
||||
return saucer::policy::allow;
|
||||
}
|
||||
if (scheme == "about") {
|
||||
return saucer::policy::allow;
|
||||
}
|
||||
return saucer::policy::block;
|
||||
});
|
||||
|
||||
m_webview.parent().on<saucer::window::event::close>([this]() -> saucer::policy {
|
||||
if (m_openIndex) {
|
||||
m_openIndex();
|
||||
}
|
||||
m_webview.parent().hide();
|
||||
return saucer::policy::block;
|
||||
});
|
||||
}
|
||||
|
||||
void optionWindow::setHWND(HWND hwnd)
|
||||
@@ -40,10 +114,12 @@ void optionWindow::configureWindow() {
|
||||
int windowHeight = static_cast<int>(screenHeight * (700.0 / 1080.0));
|
||||
|
||||
m_webview.parent().set_size({windowWidth, windowHeight});
|
||||
m_webview.set_force_dark(true);
|
||||
const saucer::color bg{0x1e, 0x1e, 0x2e, 0xFF};
|
||||
m_webview.set_background(bg);
|
||||
m_webview.parent().set_background(bg);
|
||||
|
||||
int xPos = screenWidth - windowWidth;
|
||||
int yPos = screenHeight - 42 - windowHeight;
|
||||
int xPos = (screenWidth - windowWidth) / 2;
|
||||
int yPos = (screenHeight - windowHeight) / 2;
|
||||
|
||||
// HWND über das Modul abrufen
|
||||
if (HWND hwnd = m_hwnd) {
|
||||
@@ -59,13 +135,14 @@ void optionWindow::loadResources() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = resources.find("/html/index.html");
|
||||
auto it = resources.find("/html/einstellungen.html");
|
||||
if (it == resources.end()) {
|
||||
std::cerr << "Fehler: 'index.html' wurde nicht gefunden!" << std::endl;
|
||||
std::cerr << "Fehler: 'einstellungen.html' wurde nicht gefunden!" << std::endl;
|
||||
return;
|
||||
}
|
||||
m_webview.embed(resources);
|
||||
m_webview.serve("/html/index.html");
|
||||
// Explicit URL to avoid accidental fallback to main index
|
||||
m_webview.set_url("saucer://embedded/html/einstellungen.html");
|
||||
m_webview.set_context_menu(false);
|
||||
|
||||
if (!resources.contains("/ico/toolbox.png")) {
|
||||
@@ -88,4 +165,51 @@ void optionWindow::runLuaScript() {
|
||||
void optionWindow::show() {
|
||||
m_webview.parent().show();
|
||||
runLuaScript();
|
||||
configureWindow();
|
||||
}
|
||||
|
||||
void optionWindow::exposeToJs() {
|
||||
m_webview.expose("openIndex", [&]() {
|
||||
if (m_openIndex) {
|
||||
m_openIndex();
|
||||
}
|
||||
m_webview.parent().hide();
|
||||
});
|
||||
|
||||
m_webview.expose("getLuaTimeoutSeconds", [&]() -> int {
|
||||
if (m_getLuaTimeoutSeconds) {
|
||||
return m_getLuaTimeoutSeconds();
|
||||
}
|
||||
return 30;
|
||||
});
|
||||
|
||||
m_webview.expose("setLuaTimeoutSeconds", [&](int seconds) {
|
||||
if (m_setLuaTimeoutSeconds) {
|
||||
m_setLuaTimeoutSeconds(seconds);
|
||||
}
|
||||
});
|
||||
|
||||
m_webview.expose("getActiveToolName", [&]() -> std::string {
|
||||
if (m_getActiveToolName) {
|
||||
return m_getActiveToolName();
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
m_webview.expose("getToolConfigIni", [&]() -> std::string {
|
||||
if (m_getToolConfigIni) {
|
||||
return m_getToolConfigIni();
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
m_webview.expose("setToolConfigIni", [&](const std::string &content) {
|
||||
if (m_setToolConfigIni) {
|
||||
m_setToolConfigIni(content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void optionWindow::toggleDevTools() {
|
||||
m_webview.set_dev_tools(!m_webview.dev_tools());
|
||||
}
|
||||
|
||||
@@ -1,21 +1,73 @@
|
||||
#include "toolboxWindow.h"
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <cppcodec/base64_rfc4648.hpp>
|
||||
#include <saucer/embedded/all.hpp>
|
||||
#include <saucer/navigation.hpp>
|
||||
#include <saucer/app.hpp>
|
||||
#include <format>
|
||||
#include <chrono>
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
}
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace {
|
||||
std::unordered_map<HWND, WNDPROC> g_toolbox_prev_procs;
|
||||
|
||||
LRESULT CALLBACK toolbox_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
if (msg == WM_KEYDOWN && wparam == VK_F12) {
|
||||
auto *self = reinterpret_cast<ToolboxWindow *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
if (self) {
|
||||
self->toggleDevTools();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
const auto it = g_toolbox_prev_procs.find(hwnd);
|
||||
if (it != g_toolbox_prev_procs.end()) {
|
||||
return CallWindowProc(it->second, hwnd, msg, wparam, lparam);
|
||||
}
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void install_toolbox_f12_toggle(HWND hwnd, ToolboxWindow *self) {
|
||||
if (!hwnd || !self) {
|
||||
return;
|
||||
}
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
|
||||
auto prev = reinterpret_cast<WNDPROC>(
|
||||
SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(toolbox_wndproc))
|
||||
);
|
||||
if (prev) {
|
||||
g_toolbox_prev_procs[hwnd] = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolboxWindow::ToolboxWindow(std::shared_ptr<saucer::application>& app)
|
||||
: m_webview([&]() -> saucer::smartview<> {
|
||||
: m_webview([&]() -> saucer::smartview {
|
||||
auto window_res = saucer::window::create(app.get());
|
||||
if (!window_res.has_value()) {
|
||||
throw std::runtime_error("ToolboxWindow: failed to create saucer::window");
|
||||
}
|
||||
saucer::webview::options opts{window_res.value()};
|
||||
auto sv_res = saucer::smartview<>::create(opts);
|
||||
opts.browser_flags.insert("--disable-gpu");
|
||||
auto sv_res = saucer::smartview::create(opts);
|
||||
if (!sv_res.has_value()) {
|
||||
throw std::runtime_error("ToolboxWindow: failed to create saucer::smartview");
|
||||
}
|
||||
@@ -27,6 +79,7 @@ ToolboxWindow::ToolboxWindow(std::shared_ptr<saucer::application>& app)
|
||||
void ToolboxWindow::initialize() {
|
||||
m_hwnd_module = std::make_unique<hwnd_module>(&m_webview);
|
||||
m_hwnd = m_hwnd_module->get_hwnd();
|
||||
install_toolbox_f12_toggle(m_hwnd, this);
|
||||
ensureToolboxInUserPath();
|
||||
fillToolboxMenu();
|
||||
configureWindow();
|
||||
@@ -37,6 +90,17 @@ void ToolboxWindow::initialize() {
|
||||
void ToolboxWindow::setupToolboxWindow() {
|
||||
SetJsonItems();
|
||||
ExposeToJs();
|
||||
m_webview.on<saucer::webview::event::navigate>([](const saucer::navigation& nav) {
|
||||
const auto scheme = nav.url().scheme();
|
||||
const auto host = nav.url().host();
|
||||
if (scheme == "saucer" && host && *host == "embedded") {
|
||||
return saucer::policy::allow;
|
||||
}
|
||||
if (scheme == "about") {
|
||||
return saucer::policy::allow;
|
||||
}
|
||||
return saucer::policy::block;
|
||||
});
|
||||
m_webview.parent().set_always_on_top(true);
|
||||
m_webview.parent().set_decorations(saucer::window::decoration::none);
|
||||
|
||||
@@ -95,7 +159,9 @@ void ToolboxWindow::configureWindow() {
|
||||
const int windowHeight = 600;
|
||||
|
||||
m_webview.parent().set_size({windowWidth, windowHeight});
|
||||
m_webview.set_force_dark(true);
|
||||
const saucer::color bg{0x1e, 0x1e, 0x2e, 0xFF};
|
||||
m_webview.set_background(bg);
|
||||
m_webview.parent().set_background(bg);
|
||||
|
||||
// Arbeitsbereich mit DPI-Skalierung berücksichtigen
|
||||
RECT workArea;
|
||||
@@ -142,7 +208,7 @@ void ToolboxWindow::loadResources() {
|
||||
return;
|
||||
}
|
||||
m_webview.embed(resources);
|
||||
m_webview.serve("/html/index.html");
|
||||
m_webview.set_url("saucer://embedded/html/index.html");
|
||||
//m_webview.set_url("https://nindo.de");
|
||||
m_webview.set_context_menu(false);
|
||||
|
||||
@@ -200,6 +266,10 @@ void ToolboxWindow::ExposeToJs() {
|
||||
run_lua(id);
|
||||
});
|
||||
|
||||
m_webview.expose("cancel_lua", [&](int id) {
|
||||
cancel_lua(id);
|
||||
});
|
||||
|
||||
m_webview.expose("debug_print", [&]() {
|
||||
debug_print();
|
||||
});
|
||||
@@ -208,8 +278,8 @@ void ToolboxWindow::ExposeToJs() {
|
||||
open_file_system();
|
||||
});
|
||||
|
||||
m_webview.expose("openEinst", [&]() {
|
||||
openEinst();
|
||||
m_webview.expose("openEinst", [&](int id) {
|
||||
openEinst(id);
|
||||
});
|
||||
|
||||
m_webview.expose("openIndex", [&]() {
|
||||
@@ -220,6 +290,26 @@ void ToolboxWindow::ExposeToJs() {
|
||||
{
|
||||
getNewContent();
|
||||
});
|
||||
|
||||
m_webview.expose("getLuaTimeoutSeconds", [&]() -> int {
|
||||
return getLuaTimeoutSeconds();
|
||||
});
|
||||
|
||||
m_webview.expose("setLuaTimeoutSeconds", [&](int seconds) {
|
||||
setLuaTimeoutSeconds(seconds);
|
||||
});
|
||||
|
||||
m_webview.expose("getActiveToolName", [&]() -> std::string {
|
||||
return getActiveToolName();
|
||||
});
|
||||
|
||||
m_webview.expose("getToolConfigIni", [&]() -> std::string {
|
||||
return getToolConfigIni();
|
||||
});
|
||||
|
||||
m_webview.expose("setToolConfigIni", [&](const std::string &content) {
|
||||
setToolConfigIni(content);
|
||||
});
|
||||
}
|
||||
|
||||
void ToolboxWindow::SetJsonItems() {// Konvertierung des Vektors in JSON
|
||||
@@ -349,8 +439,20 @@ void ToolboxWindow::run_lua(int id) {
|
||||
console_opened = true;
|
||||
}*/
|
||||
|
||||
constexpr int kHookInstructionCount = 10000;
|
||||
const int timeoutSeconds = getLuaTimeoutSecondsForId(id);
|
||||
const auto deadline = (timeoutSeconds > 0)
|
||||
? (std::chrono::steady_clock::now() + std::chrono::seconds(timeoutSeconds))
|
||||
: (std::chrono::steady_clock::time_point::max)();
|
||||
|
||||
auto cancelFlag = std::make_shared<std::atomic_bool>(false);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_luaTasksMutex);
|
||||
m_luaTasks[id] = LuaTask{cancelFlag};
|
||||
}
|
||||
|
||||
// Lambda-Funktion, um das Lua-Skript auszuführen
|
||||
auto lua_task = [this, id]() {
|
||||
auto lua_task = [this, id, cancelFlag, deadline]() {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base,
|
||||
sol::lib::os,
|
||||
@@ -362,6 +464,37 @@ void ToolboxWindow::run_lua(int id) {
|
||||
sol::lib::utf8,
|
||||
sol::lib::io);
|
||||
|
||||
struct LuaHookContext {
|
||||
std::shared_ptr<std::atomic_bool> cancel;
|
||||
std::chrono::steady_clock::time_point deadline;
|
||||
};
|
||||
|
||||
LuaHookContext ctx{
|
||||
cancelFlag,
|
||||
deadline
|
||||
};
|
||||
|
||||
lua_State* L = lua.lua_state();
|
||||
*reinterpret_cast<LuaHookContext**>(lua_getextraspace(L)) = &ctx;
|
||||
lua_sethook(
|
||||
L,
|
||||
[](lua_State* hookState, lua_Debug*) {
|
||||
auto* hookCtx = *reinterpret_cast<LuaHookContext**>(lua_getextraspace(hookState));
|
||||
if (!hookCtx) {
|
||||
return;
|
||||
}
|
||||
if (hookCtx->cancel->load(std::memory_order_relaxed)) {
|
||||
luaL_error(hookState, "Lua script cancelled");
|
||||
}
|
||||
if (hookCtx->deadline != (std::chrono::steady_clock::time_point::max)() &&
|
||||
std::chrono::steady_clock::now() > hookCtx->deadline) {
|
||||
luaL_error(hookState, "Lua script cancelled or timed out");
|
||||
}
|
||||
},
|
||||
LUA_MASKCOUNT,
|
||||
kHookInstructionCount
|
||||
);
|
||||
|
||||
try {
|
||||
std::string scriptPath = m_toolboxItems[id].lua_script_path_string;
|
||||
std::cout << "Running Lua script: " << scriptPath << std::endl;
|
||||
@@ -380,6 +513,11 @@ void ToolboxWindow::run_lua(int id) {
|
||||
m_webview.saucer::webview::execute(std::format("enableButtonByToolId({})", id));
|
||||
m_webview.reload();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_luaTasksMutex);
|
||||
m_luaTasks.erase(id);
|
||||
}
|
||||
};
|
||||
|
||||
// Erstellen und starten des Threads
|
||||
@@ -391,6 +529,14 @@ void ToolboxWindow::run_lua(int id) {
|
||||
std::cout << "Lua-Skript wurde gestartet." << std::endl;
|
||||
}
|
||||
|
||||
void ToolboxWindow::cancel_lua(int id) {
|
||||
std::lock_guard<std::mutex> lock(m_luaTasksMutex);
|
||||
auto it = m_luaTasks.find(id);
|
||||
if (it != m_luaTasks.end() && it->second.cancel) {
|
||||
it->second.cancel->store(true, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
void ToolboxWindow::debug_print() {
|
||||
std::cout << "ToolboxWindow::debug_print()" << std::endl;
|
||||
}
|
||||
@@ -442,12 +588,29 @@ void ToolboxWindow::open_file_system() {
|
||||
|
||||
// Beispielhafte Nutzung:
|
||||
void ToolboxWindow::openEinst() {
|
||||
if (!serveHtmlFile("html/einstellungen.html", true)) {
|
||||
if (!m_optionWindow) {
|
||||
m_optionWindow = std::make_unique<optionWindow>(
|
||||
m_app,
|
||||
[this]() { return getLuaTimeoutSeconds(); },
|
||||
[this](int seconds) { setLuaTimeoutSeconds(seconds); },
|
||||
[this]() { return getActiveToolName(); },
|
||||
[this]() { return getToolConfigIni(); },
|
||||
[this](const std::string &content) { setToolConfigIni(content); },
|
||||
[this]() { openIndex(); }
|
||||
);
|
||||
m_optionWindow->initialize();
|
||||
}
|
||||
m_optionWindow->show();
|
||||
}
|
||||
|
||||
void ToolboxWindow::openEinst(int id) {
|
||||
if (id < 0 || id >= static_cast<int>(m_toolboxItems.size())) {
|
||||
std::cerr << "openEinst: invalid tool id " << id << std::endl;
|
||||
return;
|
||||
}
|
||||
isIndex = false;
|
||||
resizeWindow(60.0, 70.0);
|
||||
centerWindow();
|
||||
m_activeToolId = id;
|
||||
ensureConfigExists(id);
|
||||
openEinst();
|
||||
}
|
||||
|
||||
void ToolboxWindow::centerWindow() {
|
||||
@@ -494,6 +657,9 @@ void ToolboxWindow::resizeWindow(double widthPercent, double heightPercent)
|
||||
}
|
||||
|
||||
void ToolboxWindow::openIndex() {
|
||||
if (!m_bShow) {
|
||||
show();
|
||||
}
|
||||
if (!serveHtmlFile("html/index.html", false)) {
|
||||
return;
|
||||
}
|
||||
@@ -509,3 +675,77 @@ void ToolboxWindow::getNewContent()
|
||||
isIndex = true;
|
||||
}
|
||||
|
||||
void ToolboxWindow::toggleDevTools() {
|
||||
m_webview.set_dev_tools(!m_webview.dev_tools());
|
||||
}
|
||||
|
||||
std::filesystem::path ToolboxWindow::getToolConfigPath(int id) const {
|
||||
if (id < 0 || id >= static_cast<int>(m_toolboxItems.size())) {
|
||||
return {};
|
||||
}
|
||||
return std::filesystem::path(m_toolboxItems[id].path) / "config.ini";
|
||||
}
|
||||
|
||||
void ToolboxWindow::ensureConfigExists(int id) const {
|
||||
const auto configPath = getToolConfigPath(id);
|
||||
if (configPath.empty()) {
|
||||
return;
|
||||
}
|
||||
m_configStore.ensureExists(configPath);
|
||||
}
|
||||
|
||||
int ToolboxWindow::getLuaTimeoutSecondsForId(int id) const {
|
||||
const auto configPath = getToolConfigPath(id);
|
||||
if (configPath.empty()) {
|
||||
return 30;
|
||||
}
|
||||
return m_configStore.getInt(configPath, "lua_timeout_seconds", 30);
|
||||
}
|
||||
|
||||
int ToolboxWindow::getLuaTimeoutSeconds() {
|
||||
if (m_activeToolId < 0) {
|
||||
return 30;
|
||||
}
|
||||
return getLuaTimeoutSecondsForId(m_activeToolId);
|
||||
}
|
||||
|
||||
void ToolboxWindow::setLuaTimeoutSeconds(int seconds) {
|
||||
if (m_activeToolId < 0) {
|
||||
return;
|
||||
}
|
||||
const auto configPath = getToolConfigPath(m_activeToolId);
|
||||
if (configPath.empty()) {
|
||||
return;
|
||||
}
|
||||
m_configStore.setInt(configPath, "lua_timeout_seconds", seconds);
|
||||
}
|
||||
|
||||
std::string ToolboxWindow::getToolConfigIni() const {
|
||||
if (m_activeToolId < 0) {
|
||||
return {};
|
||||
}
|
||||
const auto configPath = getToolConfigPath(m_activeToolId);
|
||||
if (configPath.empty()) {
|
||||
return {};
|
||||
}
|
||||
return m_configStore.readAll(configPath);
|
||||
}
|
||||
|
||||
void ToolboxWindow::setToolConfigIni(const std::string &content) {
|
||||
if (m_activeToolId < 0) {
|
||||
return;
|
||||
}
|
||||
const auto configPath = getToolConfigPath(m_activeToolId);
|
||||
if (configPath.empty()) {
|
||||
return;
|
||||
}
|
||||
m_configStore.writeAll(configPath, content);
|
||||
}
|
||||
|
||||
std::string ToolboxWindow::getActiveToolName() {
|
||||
if (m_activeToolId < 0 || m_activeToolId >= static_cast<int>(m_toolboxItems.size())) {
|
||||
return {};
|
||||
}
|
||||
return m_toolboxItems[m_activeToolId].name;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user