mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-24 11:22:07 +00:00
feat: Python Plugins
This commit is contained in:
8
resources/web/dialog/PluginWebDialog/blank.html
Normal file
8
resources/web/dialog/PluginWebDialog/blank.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Bootstrap page for PluginWebDialog. The real plugin HTML is loaded via
|
||||
wxWebView::SetPage once this page finishes loading; this file only exists
|
||||
to bring the webview up. -->
|
||||
<html>
|
||||
<head><meta charset="utf-8"><title></title></head>
|
||||
<body style="margin:0;background:transparent;"></body>
|
||||
</html>
|
||||
141
resources/web/dialog/PluginsDialog/index.html
Normal file
141
resources/web/dialog/PluginsDialog/index.html
Normal file
@@ -0,0 +1,141 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Plugins</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../include/global.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
<script type="text/javascript" src="../js/common.js"></script>
|
||||
<script src="./index.js"></script>
|
||||
</head>
|
||||
<body onLoad="OnInit()">
|
||||
<div class="app">
|
||||
<div class="toolbar">
|
||||
<button id="refresh_btn" class="ButtonStyleRegular ButtonTypeChoice">
|
||||
Refresh
|
||||
</button>
|
||||
<div id="exploreDropdown" class="explore-dropdown">
|
||||
<button id="explore_menu_btn" class="ButtonStyleConfirm ButtonTypeChoice explore-menu-btn" type="button"
|
||||
aria-haspopup="true" aria-expanded="false" aria-controls="exploreMenu" title="More plugin install options">
|
||||
<span class="explore-menu-icon" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button id="explore_btn" class="ButtonStyleConfirm ButtonTypeChoice explore-main-btn" type="button">
|
||||
Browse plugins
|
||||
</button>
|
||||
<div id="exploreMenu" class="explore-menu" role="menu" hidden>
|
||||
<button type="button" class="explore-menu-item" role="menuitem" data-install-action="explore">Browse plugins</button>
|
||||
<button type="button" class="explore-menu-item" role="menuitem" data-install-action="install-local">Install local plugin</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="content">
|
||||
<section class="pane plugin-list-pane">
|
||||
<div class="hdr plugin-cols">
|
||||
<span>Activate</span>
|
||||
<span>Name</span>
|
||||
<span>Plugin Version</span>
|
||||
<span>Status</span>
|
||||
</div>
|
||||
<div id="pluginList" class="body thin-scroll"></div>
|
||||
</section>
|
||||
|
||||
<section class="pane details-pane">
|
||||
<div class="detail-tabs" role="tablist" aria-label="Plugin details">
|
||||
<button id="pluginInfoTab" class="detail-tab active" type="button" role="tab"
|
||||
aria-selected="true" aria-controls="pluginInfoPanel" data-tab="plugin-info">Plugin Info</button>
|
||||
<button id="descriptionTab" class="detail-tab" type="button" role="tab" tabindex="-1"
|
||||
aria-selected="false" aria-controls="descriptionPanel" data-tab="description">Description</button>
|
||||
<button id="changelogTab" class="detail-tab" type="button" role="tab" tabindex="-1"
|
||||
aria-selected="false" aria-controls="changelogPanel" data-tab="changelog">Changelog</button>
|
||||
<button id="diagnosticsTab" class="detail-tab" type="button" role="tab" tabindex="-1"
|
||||
aria-selected="false" aria-controls="diagnosticsPanel" data-tab="diagnostics">Diagnostics</button>
|
||||
</div>
|
||||
|
||||
<div class="detail-tab-panels">
|
||||
<section id="pluginInfoPanel" class="detail-tab-panel" role="tabpanel"
|
||||
aria-labelledby="pluginInfoTab" data-panel="plugin-info">
|
||||
<div class="plugin-info-layout">
|
||||
<div class="plugin-thumbnail">
|
||||
<img id="detailThumbnail" alt="" hidden />
|
||||
</div>
|
||||
<div class="detail-fields">
|
||||
<div class="detail-field-row">
|
||||
<div class="detail-label">Source</div>
|
||||
<div id="detailSource" class="detail-value">-</div>
|
||||
</div>
|
||||
<div class="detail-field-row">
|
||||
<div class="detail-label">Types</div>
|
||||
<div id="detailTypes" class="detail-value">-</div>
|
||||
</div>
|
||||
<div class="detail-field-row">
|
||||
<div class="detail-label">Author</div>
|
||||
<div id="detailAuthor" class="detail-value">-</div>
|
||||
</div>
|
||||
<div class="detail-field-row">
|
||||
<div class="detail-label">Installed Version</div>
|
||||
<div class="detail-value">
|
||||
<span id="detailInstalledVersion">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-row">
|
||||
<div class="detail-label">Latest Version</div>
|
||||
<div class="detail-value detail-version-row">
|
||||
<span id="detailLatestVersion">-</span>
|
||||
<span id="detailUpdateBadge" class="version-update-badge" hidden
|
||||
aria-label="Update available" title="Update available"></span>
|
||||
<button id="detailUpdateBtn" type="button" class="plugin-update-btn" hidden
|
||||
title="Update to the latest version">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="descriptionPanel" class="detail-tab-panel thin-scroll" role="tabpanel" tabindex="0"
|
||||
aria-labelledby="descriptionTab" data-panel="description" hidden>
|
||||
<h2 class="detail-section-title">Description</h2>
|
||||
<div id="detailDescription" class="detail-description">No description available</div>
|
||||
</section>
|
||||
|
||||
<section id="changelogPanel" class="detail-tab-panel thin-scroll" role="tabpanel" tabindex="0"
|
||||
aria-labelledby="changelogTab" data-panel="changelog" hidden>
|
||||
<table id="changelogTable" class="detail-table changelog-table" aria-label="Plugin changelog">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Version</th>
|
||||
<th scope="col">Date</th>
|
||||
<th scope="col">Changes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="changelogBody"></tbody>
|
||||
</table>
|
||||
<div id="changelogEmpty" class="detail-empty" hidden>No changelog available</div>
|
||||
</section>
|
||||
|
||||
<section id="diagnosticsPanel" class="detail-tab-panel thin-scroll" role="tabpanel" tabindex="0"
|
||||
aria-labelledby="diagnosticsTab" data-panel="diagnostics" hidden>
|
||||
<div id="detailStatusBody" class="detail-status-body">No issues detected</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="AcceptArea">
|
||||
<button id="open_terminal" class="ButtonStyleRegular ButtonTypeChoice left-btn">
|
||||
Open Terminal
|
||||
</button>
|
||||
<div id="close_btn" class="ButtonStyleRegular ButtonTypeChoice">Close</div>
|
||||
</div>
|
||||
|
||||
<div id="ctxMenu" class="ctx" hidden></div>
|
||||
</body>
|
||||
</html>
|
||||
1030
resources/web/dialog/PluginsDialog/index.js
Normal file
1030
resources/web/dialog/PluginsDialog/index.js
Normal file
File diff suppressed because it is too large
Load Diff
1089
resources/web/dialog/PluginsDialog/styles.css
Normal file
1089
resources/web/dialog/PluginsDialog/styles.css
Normal file
File diff suppressed because it is too large
Load Diff
29
resources/web/dialog/TerminalDialog/index.html
Normal file
29
resources/web/dialog/TerminalDialog/index.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Terminal</title>
|
||||
<link rel="stylesheet" href="../../include/xterm/xterm.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../include/global.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/common.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
|
||||
<script type="text/javascript" src="../js/json2.js"></script>
|
||||
<script type="text/javascript" src="../../data/text.js"></script>
|
||||
<script type="text/javascript" src="../js/globalapi.js"></script>
|
||||
<script type="text/javascript" src="../../include/xterm/xterm.js"></script>
|
||||
<script type="text/javascript" src="../../include/xterm/xterm-addon-fit.js"></script>
|
||||
<script src="./index.js"></script>
|
||||
</head>
|
||||
<body onLoad="OnInit()">
|
||||
<div class="app">
|
||||
<div id="terminal-container"></div>
|
||||
<div class="input-row">
|
||||
<input type="text" id="cmd-input" placeholder="python ... or uv ..." />
|
||||
<button id="run-btn">Run</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
125
resources/web/dialog/TerminalDialog/index.js
Normal file
125
resources/web/dialog/TerminalDialog/index.js
Normal file
@@ -0,0 +1,125 @@
|
||||
let term = null;
|
||||
let fitAddon = null;
|
||||
|
||||
function OnInit() {
|
||||
if (typeof TranslatePage === "function")
|
||||
TranslatePage();
|
||||
|
||||
term = new Terminal({
|
||||
cursorBlink: true,
|
||||
fontSize: 13,
|
||||
fontFamily: '"Cascadia Code", "Fira Code", "JetBrains Mono", monospace',
|
||||
theme: {
|
||||
background: "#1e1e1e",
|
||||
foreground: "#d4d4d4",
|
||||
cursor: "#ffffff",
|
||||
black: "#000000",
|
||||
red: "#cd3131",
|
||||
green: "#0dbc79",
|
||||
yellow: "#e5e510",
|
||||
blue: "#2472c8",
|
||||
magenta: "#bc3fbc",
|
||||
cyan: "#11a8cd",
|
||||
white: "#e5e5e5",
|
||||
brightBlack: "#666666",
|
||||
brightRed: "#f14c4c",
|
||||
brightGreen: "#23d18b",
|
||||
brightYellow: "#f5f543",
|
||||
brightBlue: "#3b8eea",
|
||||
brightMagenta: "#d670d6",
|
||||
brightCyan: "#29b8db",
|
||||
brightWhite: "#ffffff"
|
||||
},
|
||||
allowProposedApi: true
|
||||
});
|
||||
|
||||
fitAddon = new (FitAddon.FitAddon || FitAddon)();
|
||||
term.loadAddon(fitAddon);
|
||||
|
||||
term.open(document.getElementById("terminal-container"));
|
||||
fitAddon.fit();
|
||||
|
||||
// Focus the terminal so it captures keyboard input
|
||||
term.focus();
|
||||
|
||||
// Re-focus terminal when user clicks on it
|
||||
term.element.addEventListener("click", () => term.focus());
|
||||
|
||||
window.addEventListener("resize", () => fitAddon.fit());
|
||||
|
||||
// Send keystrokes to C++
|
||||
term.onData((data) => {
|
||||
SendWXMessage(JSON.stringify({
|
||||
command: "write_stdin",
|
||||
data: data
|
||||
}));
|
||||
});
|
||||
|
||||
document.getElementById("run-btn").addEventListener("click", onRun);
|
||||
document.getElementById("cmd-input").addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter")
|
||||
onRun();
|
||||
});
|
||||
|
||||
term.writeln("Plugin terminal ready.");
|
||||
}
|
||||
|
||||
function onRun() {
|
||||
const input = document.getElementById("cmd-input");
|
||||
const cmd = input.value.trim();
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
input.value = "";
|
||||
|
||||
term.writeln("$ " + cmd);
|
||||
|
||||
setRunning(true);
|
||||
|
||||
SendWXMessage(JSON.stringify({
|
||||
command: "run_command",
|
||||
cmd: cmd
|
||||
}));
|
||||
}
|
||||
|
||||
function setRunning(running) {
|
||||
document.getElementById("run-btn").disabled = running;
|
||||
document.getElementById("cmd-input").disabled = running;
|
||||
}
|
||||
|
||||
function HandleStudio(value) {
|
||||
const payload = (typeof value === "string") ? SafeJsonParse(value) : value;
|
||||
if (!payload || typeof payload !== "object")
|
||||
return;
|
||||
|
||||
switch (payload.command) {
|
||||
case "output":
|
||||
if (payload.lines && Array.isArray(payload.lines)) {
|
||||
payload.lines.forEach((line) => {
|
||||
if (line.is_stderr)
|
||||
term.writeln("\x1b[91m" + line.text + "\x1b[0m");
|
||||
else
|
||||
term.writeln(line.text);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "process_done":
|
||||
setRunning(false);
|
||||
term.writeln("\x1b[90mProcess exited with code: " + payload.exit_code + "\x1b[0m");
|
||||
break;
|
||||
|
||||
case "process_error":
|
||||
setRunning(false);
|
||||
term.writeln("\x1b[91m" + payload.message + "\x1b[0m");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function SafeJsonParse(value) {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
74
resources/web/dialog/TerminalDialog/styles.css
Normal file
74
resources/web/dialog/TerminalDialog/styles.css
Normal file
@@ -0,0 +1,74 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#terminal-container {
|
||||
flex: 1;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#terminal-container,
|
||||
#terminal-container .xterm,
|
||||
#terminal-container .xterm * {
|
||||
font-family: "Cascadia Code", "Fira Code", "JetBrains Mono", monospace;
|
||||
letter-spacing: 0;
|
||||
word-spacing: 0;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#cmd-input {
|
||||
flex: 1;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
background: #2d2d2d;
|
||||
color: #d4d4d4;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#cmd-input:focus {
|
||||
border-color: #666;
|
||||
}
|
||||
|
||||
#run-btn {
|
||||
padding: 6px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #0e639c;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#run-btn:hover {
|
||||
background: #1177bb;
|
||||
}
|
||||
|
||||
#run-btn:disabled {
|
||||
background: #555;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@@ -7,10 +7,28 @@
|
||||
--col-sep: #3a424d;
|
||||
|
||||
--text: #e6ebf0;
|
||||
--muted: #b9c0c8;
|
||||
--row-hover: #2b3340;
|
||||
--row-selected: #244945;
|
||||
--row-selected-outline: #00bfa5;
|
||||
|
||||
--plugin-status-danger: #ff7b72;
|
||||
--plugin-status-ok: #37c871;
|
||||
--plugin-status-warn: #f0b45a;
|
||||
--plugin-status-inactive: #b9c0c8;
|
||||
--plugin-status-danger-bg: rgba(255, 123, 114, 0.16);
|
||||
--plugin-status-ok-bg: rgba(55, 200, 113, 0.16);
|
||||
--plugin-status-warn-bg: rgba(240, 180, 90, 0.18);
|
||||
--plugin-status-inactive-bg: #36363b;
|
||||
--plugin-status-inactive-text: #c7ccd2;
|
||||
--plugin-source-mine-bg: rgba(0, 150, 136, 0.18);
|
||||
--plugin-source-mine-text: #8de5d6;
|
||||
--plugin-source-neutral-bg: #36363b;
|
||||
--plugin-source-neutral-text: #c7ccd2;
|
||||
--plugin-source-subscribed-bg: rgba(88, 166, 255, 0.18);
|
||||
--plugin-source-subscribed-text: #8fc0f0;
|
||||
--plugin-link-text: #62d8ca;
|
||||
|
||||
--footer-bg: #20262d;
|
||||
--btn-bg: #2a313a;
|
||||
--btn-border: #4b5664;
|
||||
@@ -96,5 +114,3 @@ input[type=checkbox]:checked{
|
||||
{
|
||||
color: #BEBEC0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user