133 lines
5.2 KiB
HTML
133 lines
5.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="vi">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>VST GUI</title>
|
|
<style>
|
|
:root { color-scheme: dark; }
|
|
* { box-sizing: border-box; }
|
|
body { margin: 0; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; background: #16161a; color: #e4e4e7; }
|
|
header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; background: #1e1e24; border-bottom: 1px solid #2d2d35; position: sticky; top: 0; z-index: 10; }
|
|
header h1 { font-size: 13px; margin: 0; font-weight: 600; color: #7dd3fc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
header .meta { font-size: 10px; color: #71717a; margin-top: 2px; }
|
|
#params { padding: 10px 12px; }
|
|
.param { display: grid; grid-template-columns: minmax(0,1fr) 60px; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid #26262d; }
|
|
.param .title { font-size: 11px; color: #d4d4d8; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.param .val { font-size: 10px; font-family: ui-monospace, monospace; color: #7dd3fc; text-align: right; }
|
|
input[type=range] { width: 100%; accent-color: #0ea5e9; }
|
|
#status { padding: 8px 12px; font-size: 11px; color: #a1a1aa; }
|
|
#status.err { color: #f87171; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<div>
|
|
<h1 id="title">VST GUI</h1>
|
|
<div class="meta" id="meta"></div>
|
|
</div>
|
|
<button id="closeBtn" style="background:#3f3f46;border:1px solid #52525b;color:#f4f4f5;font-size:11px;padding:4px 10px;border-radius:4px;cursor:pointer;">Đóng</button>
|
|
</header>
|
|
<div id="params"></div>
|
|
<div id="status">Đang tải tham số…</div>
|
|
|
|
<script>
|
|
(function () {
|
|
const qs = new URLSearchParams(window.location.search);
|
|
const trackId = qs.get('track') || '';
|
|
const pluginId = qs.get('plugin') || '';
|
|
const el = (id) => document.getElementById(id);
|
|
|
|
el('title').textContent = 'VST GUI - ' + pluginId;
|
|
el('meta').textContent = 'track=' + trackId;
|
|
|
|
const invoke = (cmd, args) => {
|
|
if (window.__TAURI__ && window.__TAURI__.core) {
|
|
return window.__TAURI__.core.invoke(cmd, args);
|
|
}
|
|
return Promise.reject(new Error('Tauri core unavailable'));
|
|
};
|
|
|
|
let params = [];
|
|
|
|
function render() {
|
|
const box = el('params');
|
|
box.innerHTML = '';
|
|
if (!params.length) {
|
|
el('status').textContent = 'Plugin không có tham số (hoặc chưa nạp).';
|
|
return;
|
|
}
|
|
el('status').textContent = params.length + ' tham số — kéo slider để đổi giá trị.';
|
|
params.forEach((p) => {
|
|
const row = document.createElement('div');
|
|
row.className = 'param';
|
|
const title = document.createElement('div');
|
|
title.className = 'title';
|
|
title.textContent = p.title || ('Param ' + p.param_id);
|
|
title.title = title.textContent;
|
|
const val = document.createElement('div');
|
|
val.className = 'val';
|
|
const range = document.createElement('input');
|
|
range.type = 'range';
|
|
range.min = 0;
|
|
range.max = 1;
|
|
range.step = 0.001;
|
|
range.value = Math.min(1, Math.max(0, p.value || 0));
|
|
val.textContent = (p.value || 0).toFixed(3);
|
|
let dragging = false;
|
|
range.addEventListener('input', () => {
|
|
val.textContent = Number(range.value).toFixed(3);
|
|
});
|
|
range.addEventListener('change', () => {
|
|
invoke('set_vst_param', { trackId: trackId, pluginId: pluginId, paramId: p.param_id, value: Number(range.value) })
|
|
.catch((err) => { el('status').className = 'err'; el('status').textContent = 'set_vst_param lỗi: ' + (err && (err.message || err)); });
|
|
});
|
|
row.appendChild(title);
|
|
row.appendChild(val);
|
|
row.appendChild(range);
|
|
box.appendChild(row);
|
|
});
|
|
}
|
|
|
|
// Sync 2 chiều: native editor đổi param → Rust emit vst_param_changed → cập nhật slider.
|
|
function onParamChanged(e) {
|
|
const d = e.payload || {};
|
|
if (d.param_id === undefined) return;
|
|
const p = params.find((x) => x.param_id === d.param_id);
|
|
if (p) {
|
|
p.value = d.value;
|
|
const ranges = document.querySelectorAll('input[type=range]');
|
|
const idx = params.indexOf(p);
|
|
if (ranges[idx]) ranges[idx].value = Math.min(1, Math.max(0, d.value));
|
|
const vals = document.querySelectorAll('.val');
|
|
if (vals[idx]) vals[idx].textContent = Number(d.value).toFixed(3);
|
|
}
|
|
}
|
|
|
|
function init() {
|
|
invoke('get_vst_params', { trackId: trackId, pluginId: pluginId }).then((list) => {
|
|
params = list || [];
|
|
render();
|
|
}).catch((err) => {
|
|
el('status').className = 'err';
|
|
el('status').textContent = 'get_vst_params lỗi: ' + (err && (err.message || err)) + ' — plugin chưa mở được (kiểm tra log Rust / bridge DLL).';
|
|
});
|
|
}
|
|
|
|
el('closeBtn').addEventListener('click', () => {
|
|
invoke('close_vst_editor', { trackId: trackId, pluginId: pluginId }).catch(() => {});
|
|
window.close();
|
|
});
|
|
window.addEventListener('beforeunload', () => {
|
|
invoke('close_vst_editor', { trackId: trackId, pluginId: pluginId }).catch(() => {});
|
|
});
|
|
|
|
if (window.__TAURI__ && window.__TAURI__.event) {
|
|
window.__TAURI__.event.listen('vst_param_changed', onParamChanged).catch(() => {});
|
|
}
|
|
init();
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|