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:
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
class toolboxTray : public tray {
|
class toolboxTray : public tray {
|
||||||
public:
|
public:
|
||||||
// Konstruktor mit optionalen Parametern für Icon und Tooltip
|
// 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->icon = icon;
|
||||||
this->tooltip = const_cast<char*>(tooltip);
|
this->tooltip = const_cast<char*>(tooltip);
|
||||||
this->menu = nullptr; // Initialisiere ohne Menü (kann später gesetzt werden)
|
this->menu = nullptr; // Initialisiere ohne Menü (kann später gesetzt werden)
|
||||||
|
|||||||
+29
-1
@@ -5,6 +5,10 @@
|
|||||||
#include <saucer/embedded/all.hpp>
|
#include <saucer/embedded/all.hpp>
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
#include <saucer/webview.hpp>
|
#include <saucer/webview.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <mutex>
|
||||||
|
#include "optionWindow.h"
|
||||||
|
#include "toolConfig.h"
|
||||||
|
|
||||||
class ToolboxWindow {
|
class ToolboxWindow {
|
||||||
public:
|
public:
|
||||||
@@ -21,6 +25,7 @@ public:
|
|||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
void setupToolboxWindow();
|
void setupToolboxWindow();
|
||||||
|
void toggleDevTools();
|
||||||
|
|
||||||
std::atomic_bool isIndex = true;
|
std::atomic_bool isIndex = true;
|
||||||
|
|
||||||
@@ -40,12 +45,13 @@ public:
|
|||||||
|
|
||||||
std::vector<ToolboxItem> m_toolboxItems;
|
std::vector<ToolboxItem> m_toolboxItems;
|
||||||
|
|
||||||
saucer::smartview<saucer::default_serializer> m_webview;
|
saucer::smartview m_webview;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<hwnd_module> m_hwnd_module;
|
std::unique_ptr<hwnd_module> m_hwnd_module;
|
||||||
HWND m_hwnd{};
|
HWND m_hwnd{};
|
||||||
std::shared_ptr<saucer::application> m_app;
|
std::shared_ptr<saucer::application> m_app;
|
||||||
|
std::unique_ptr<optionWindow> m_optionWindow;
|
||||||
std::thread m_threadMonitor;
|
std::thread m_threadMonitor;
|
||||||
std::atomic<bool> m_runningMonitor = true;
|
std::atomic<bool> m_runningMonitor = true;
|
||||||
|
|
||||||
@@ -77,6 +83,7 @@ private:
|
|||||||
void debug_print();
|
void debug_print();
|
||||||
|
|
||||||
void run_lua(int id);
|
void run_lua(int id);
|
||||||
|
void cancel_lua(int id);
|
||||||
|
|
||||||
void monitor_focus();
|
void monitor_focus();
|
||||||
|
|
||||||
@@ -85,10 +92,31 @@ private:
|
|||||||
void SetJsonItems();
|
void SetJsonItems();
|
||||||
|
|
||||||
void openEinst();
|
void openEinst();
|
||||||
|
void openEinst(int id);
|
||||||
void centerWindow();
|
void centerWindow();
|
||||||
void resizeWindow(int width, int height);
|
void resizeWindow(int width, int height);
|
||||||
void resizeWindow(double widthPercent, double heightPercent);
|
void resizeWindow(double widthPercent, double heightPercent);
|
||||||
|
|
||||||
void openIndex();
|
void openIndex();
|
||||||
void getNewContent();
|
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 charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Toolbox</title>
|
<title>Toolbox</title>
|
||||||
<link rel="stylesheet" href="../highlight/styles/dark.css" media="all" title="dark">
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
@@ -129,7 +128,7 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
background: #1e1e2e;
|
background: #1e1e2e;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
display: none; /* Standardmäßig ausgeblendet */
|
display: flex; /* Standardmäßig sichtbar */
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -170,18 +169,32 @@
|
|||||||
<div class="editor" id="editor">
|
<div class="editor" id="editor">
|
||||||
<label for="code-editor"></label>
|
<label for="code-editor"></label>
|
||||||
<textarea id="code-editor" placeholder="Write Lua code here..."></textarea>
|
<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>
|
||||||
|
|
||||||
<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 -->
|
<!-- Footer -->
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<!--Schmidti.Digital © 2024-->
|
<!--Schmidti.Digital © 2024-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="../highlight/highlight.min.js"></script>
|
|
||||||
<script src="../highlight/languages/lua.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
function goBack() {
|
function goBack() {
|
||||||
saucer.exposed.openIndex();
|
saucer.exposed.openIndex();
|
||||||
@@ -206,13 +219,40 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const editor = document.getElementById('code-editor');
|
const editor = document.getElementById('code-editor');
|
||||||
const output = document.getElementById('highlightedOutput');
|
const output = document.getElementById('highlightedOutput');
|
||||||
|
showContent('general');
|
||||||
|
|
||||||
// Synchronisiere den Inhalt von textarea mit dem Codeblock
|
// Synchronisiere den Inhalt von textarea mit dem Codeblock
|
||||||
editor.addEventListener('input', () => {
|
editor.addEventListener('input', () => {
|
||||||
output.innerHTML = ''; // Vorheriges Highlighting entfernen
|
output.innerHTML = ''; // Vorheriges Highlighting entfernen
|
||||||
output.textContent = editor.value; // Aktuellen Text setzen
|
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>
|
</script>
|
||||||
|
|||||||
+133
-9
@@ -2,29 +2,103 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <saucer/embedded/all.hpp>
|
#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_app(app)
|
||||||
, m_webview([&]() -> saucer::smartview<> {
|
, m_webview([&]() -> saucer::smartview {
|
||||||
auto window_res = saucer::window::create(app.get());
|
auto window_res = saucer::window::create(app.get());
|
||||||
if (!window_res.has_value()) {
|
if (!window_res.has_value()) {
|
||||||
throw std::runtime_error("optionWindow: failed to create saucer::window");
|
throw std::runtime_error("optionWindow: failed to create saucer::window");
|
||||||
}
|
}
|
||||||
saucer::webview::options opts{window_res.value()};
|
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()) {
|
if (!sv_res.has_value()) {
|
||||||
throw std::runtime_error("optionWindow: failed to create saucer::smartview");
|
throw std::runtime_error("optionWindow: failed to create saucer::smartview");
|
||||||
}
|
}
|
||||||
return std::move(sv_res.value());
|
return std::move(sv_res.value());
|
||||||
}())
|
}())
|
||||||
, m_hwnd()
|
, 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() {
|
void optionWindow::initialize() {
|
||||||
// Modul hinzufügen
|
// 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();
|
configureWindow();
|
||||||
|
exposeToJs();
|
||||||
loadResources();
|
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)
|
void optionWindow::setHWND(HWND hwnd)
|
||||||
@@ -40,10 +114,12 @@ void optionWindow::configureWindow() {
|
|||||||
int windowHeight = static_cast<int>(screenHeight * (700.0 / 1080.0));
|
int windowHeight = static_cast<int>(screenHeight * (700.0 / 1080.0));
|
||||||
|
|
||||||
m_webview.parent().set_size({windowWidth, windowHeight});
|
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 xPos = (screenWidth - windowWidth) / 2;
|
||||||
int yPos = screenHeight - 42 - windowHeight;
|
int yPos = (screenHeight - windowHeight) / 2;
|
||||||
|
|
||||||
// HWND über das Modul abrufen
|
// HWND über das Modul abrufen
|
||||||
if (HWND hwnd = m_hwnd) {
|
if (HWND hwnd = m_hwnd) {
|
||||||
@@ -59,13 +135,14 @@ void optionWindow::loadResources() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = resources.find("/html/index.html");
|
auto it = resources.find("/html/einstellungen.html");
|
||||||
if (it == resources.end()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
m_webview.embed(resources);
|
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);
|
m_webview.set_context_menu(false);
|
||||||
|
|
||||||
if (!resources.contains("/ico/toolbox.png")) {
|
if (!resources.contains("/ico/toolbox.png")) {
|
||||||
@@ -88,4 +165,51 @@ void optionWindow::runLuaScript() {
|
|||||||
void optionWindow::show() {
|
void optionWindow::show() {
|
||||||
m_webview.parent().show();
|
m_webview.parent().show();
|
||||||
runLuaScript();
|
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());
|
||||||
}
|
}
|
||||||
|
|||||||
+251
-11
@@ -1,21 +1,73 @@
|
|||||||
#include "toolboxWindow.h"
|
#include "toolboxWindow.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <cppcodec/base64_rfc4648.hpp>
|
#include <cppcodec/base64_rfc4648.hpp>
|
||||||
#include <saucer/embedded/all.hpp>
|
#include <saucer/embedded/all.hpp>
|
||||||
|
#include <saucer/navigation.hpp>
|
||||||
|
#include <saucer/app.hpp>
|
||||||
#include <format>
|
#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)
|
ToolboxWindow::ToolboxWindow(std::shared_ptr<saucer::application>& app)
|
||||||
: m_webview([&]() -> saucer::smartview<> {
|
: m_webview([&]() -> saucer::smartview {
|
||||||
auto window_res = saucer::window::create(app.get());
|
auto window_res = saucer::window::create(app.get());
|
||||||
if (!window_res.has_value()) {
|
if (!window_res.has_value()) {
|
||||||
throw std::runtime_error("ToolboxWindow: failed to create saucer::window");
|
throw std::runtime_error("ToolboxWindow: failed to create saucer::window");
|
||||||
}
|
}
|
||||||
saucer::webview::options opts{window_res.value()};
|
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()) {
|
if (!sv_res.has_value()) {
|
||||||
throw std::runtime_error("ToolboxWindow: failed to create saucer::smartview");
|
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() {
|
void ToolboxWindow::initialize() {
|
||||||
m_hwnd_module = std::make_unique<hwnd_module>(&m_webview);
|
m_hwnd_module = std::make_unique<hwnd_module>(&m_webview);
|
||||||
m_hwnd = m_hwnd_module->get_hwnd();
|
m_hwnd = m_hwnd_module->get_hwnd();
|
||||||
|
install_toolbox_f12_toggle(m_hwnd, this);
|
||||||
ensureToolboxInUserPath();
|
ensureToolboxInUserPath();
|
||||||
fillToolboxMenu();
|
fillToolboxMenu();
|
||||||
configureWindow();
|
configureWindow();
|
||||||
@@ -37,6 +90,17 @@ void ToolboxWindow::initialize() {
|
|||||||
void ToolboxWindow::setupToolboxWindow() {
|
void ToolboxWindow::setupToolboxWindow() {
|
||||||
SetJsonItems();
|
SetJsonItems();
|
||||||
ExposeToJs();
|
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_always_on_top(true);
|
||||||
m_webview.parent().set_decorations(saucer::window::decoration::none);
|
m_webview.parent().set_decorations(saucer::window::decoration::none);
|
||||||
|
|
||||||
@@ -95,7 +159,9 @@ void ToolboxWindow::configureWindow() {
|
|||||||
const int windowHeight = 600;
|
const int windowHeight = 600;
|
||||||
|
|
||||||
m_webview.parent().set_size({windowWidth, windowHeight});
|
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
|
// Arbeitsbereich mit DPI-Skalierung berücksichtigen
|
||||||
RECT workArea;
|
RECT workArea;
|
||||||
@@ -142,7 +208,7 @@ void ToolboxWindow::loadResources() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_webview.embed(resources);
|
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_url("https://nindo.de");
|
||||||
m_webview.set_context_menu(false);
|
m_webview.set_context_menu(false);
|
||||||
|
|
||||||
@@ -200,6 +266,10 @@ void ToolboxWindow::ExposeToJs() {
|
|||||||
run_lua(id);
|
run_lua(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_webview.expose("cancel_lua", [&](int id) {
|
||||||
|
cancel_lua(id);
|
||||||
|
});
|
||||||
|
|
||||||
m_webview.expose("debug_print", [&]() {
|
m_webview.expose("debug_print", [&]() {
|
||||||
debug_print();
|
debug_print();
|
||||||
});
|
});
|
||||||
@@ -208,8 +278,8 @@ void ToolboxWindow::ExposeToJs() {
|
|||||||
open_file_system();
|
open_file_system();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_webview.expose("openEinst", [&]() {
|
m_webview.expose("openEinst", [&](int id) {
|
||||||
openEinst();
|
openEinst(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_webview.expose("openIndex", [&]() {
|
m_webview.expose("openIndex", [&]() {
|
||||||
@@ -220,6 +290,26 @@ void ToolboxWindow::ExposeToJs() {
|
|||||||
{
|
{
|
||||||
getNewContent();
|
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
|
void ToolboxWindow::SetJsonItems() {// Konvertierung des Vektors in JSON
|
||||||
@@ -349,8 +439,20 @@ void ToolboxWindow::run_lua(int id) {
|
|||||||
console_opened = true;
|
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
|
// Lambda-Funktion, um das Lua-Skript auszuführen
|
||||||
auto lua_task = [this, id]() {
|
auto lua_task = [this, id, cancelFlag, deadline]() {
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
lua.open_libraries(sol::lib::base,
|
lua.open_libraries(sol::lib::base,
|
||||||
sol::lib::os,
|
sol::lib::os,
|
||||||
@@ -362,6 +464,37 @@ void ToolboxWindow::run_lua(int id) {
|
|||||||
sol::lib::utf8,
|
sol::lib::utf8,
|
||||||
sol::lib::io);
|
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 {
|
try {
|
||||||
std::string scriptPath = m_toolboxItems[id].lua_script_path_string;
|
std::string scriptPath = m_toolboxItems[id].lua_script_path_string;
|
||||||
std::cout << "Running Lua script: " << scriptPath << std::endl;
|
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.saucer::webview::execute(std::format("enableButtonByToolId({})", id));
|
||||||
m_webview.reload();
|
m_webview.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_luaTasksMutex);
|
||||||
|
m_luaTasks.erase(id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Erstellen und starten des Threads
|
// Erstellen und starten des Threads
|
||||||
@@ -391,6 +529,14 @@ void ToolboxWindow::run_lua(int id) {
|
|||||||
std::cout << "Lua-Skript wurde gestartet." << std::endl;
|
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() {
|
void ToolboxWindow::debug_print() {
|
||||||
std::cout << "ToolboxWindow::debug_print()" << std::endl;
|
std::cout << "ToolboxWindow::debug_print()" << std::endl;
|
||||||
}
|
}
|
||||||
@@ -442,12 +588,29 @@ void ToolboxWindow::open_file_system() {
|
|||||||
|
|
||||||
// Beispielhafte Nutzung:
|
// Beispielhafte Nutzung:
|
||||||
void ToolboxWindow::openEinst() {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
isIndex = false;
|
m_activeToolId = id;
|
||||||
resizeWindow(60.0, 70.0);
|
ensureConfigExists(id);
|
||||||
centerWindow();
|
openEinst();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolboxWindow::centerWindow() {
|
void ToolboxWindow::centerWindow() {
|
||||||
@@ -494,6 +657,9 @@ void ToolboxWindow::resizeWindow(double widthPercent, double heightPercent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ToolboxWindow::openIndex() {
|
void ToolboxWindow::openIndex() {
|
||||||
|
if (!m_bShow) {
|
||||||
|
show();
|
||||||
|
}
|
||||||
if (!serveHtmlFile("html/index.html", false)) {
|
if (!serveHtmlFile("html/index.html", false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -509,3 +675,77 @@ void ToolboxWindow::getNewContent()
|
|||||||
isIndex = true;
|
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