第一版
This commit is contained in:
151
lib/ktx2/ui.js
Normal file
151
lib/ktx2/ui.js
Normal file
@ -0,0 +1,151 @@
|
||||
import color from "picocolors";
|
||||
import { steps } from "./config.js";
|
||||
import { initKeypress, onKey } from "../keyboard.js";
|
||||
|
||||
// 存储结果和状态
|
||||
let results = [];
|
||||
let completed = new Set();
|
||||
let currentStep = 0;
|
||||
let currentOption = 0;
|
||||
|
||||
// 初始化结果
|
||||
export function initResults() {
|
||||
results = steps.map(s => s.type === "multiselect" ? [...s.default] : s.default);
|
||||
completed = new Set();
|
||||
currentStep = 0;
|
||||
currentOption = 0;
|
||||
}
|
||||
|
||||
// 渲染导航栏
|
||||
function renderNav() {
|
||||
const nav = steps.map((step, i) => {
|
||||
if (completed.has(i)) {
|
||||
return color.green(`☑ ${step.name}`);
|
||||
} else if (i === currentStep) {
|
||||
return color.bgCyan(color.black(` ${step.name} `));
|
||||
} else {
|
||||
return color.dim(`□ ${step.name}`);
|
||||
}
|
||||
});
|
||||
return `← ${nav.join(" ")} ${color.green("✓Submit")} →`;
|
||||
}
|
||||
|
||||
// 渲染选项列表
|
||||
function renderOptions() {
|
||||
const step = steps[currentStep];
|
||||
const lines = [];
|
||||
|
||||
lines.push(color.cyan(step.message));
|
||||
lines.push("");
|
||||
|
||||
step.options.forEach((opt, i) => {
|
||||
const isCurrent = i === currentOption;
|
||||
const isSelected = step.type === "multiselect"
|
||||
? results[currentStep].includes(opt.value)
|
||||
: results[currentStep] === opt.value;
|
||||
|
||||
let prefix;
|
||||
if (step.type === "multiselect") {
|
||||
prefix = isSelected ? color.green("◉ ") : "○ ";
|
||||
} else {
|
||||
prefix = isSelected ? color.green("● ") : "○ ";
|
||||
}
|
||||
|
||||
const cursor = isCurrent ? color.cyan("❯ ") : " ";
|
||||
const label = isCurrent ? color.cyan(opt.label) : opt.label;
|
||||
const check = isSelected ? color.green(" ✓") : "";
|
||||
|
||||
lines.push(`${cursor}${prefix}${label}${check}`);
|
||||
if (opt.hint) {
|
||||
lines.push(` ${color.dim(opt.hint)}`);
|
||||
}
|
||||
});
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
// 渲染整个界面
|
||||
function render() {
|
||||
console.clear();
|
||||
console.log(color.bgCyan(color.black(" KTX2 纹理压缩工具 ")));
|
||||
console.log("\n" + renderNav());
|
||||
console.log(color.dim("\n← → 切换步骤 | ↑ ↓ 选择 | Space 选中 | Tab 提交 | Esc 返回\n"));
|
||||
console.log(renderOptions());
|
||||
}
|
||||
|
||||
// 主交互循环
|
||||
export async function runInteractive() {
|
||||
initResults();
|
||||
initKeypress();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
render();
|
||||
|
||||
onKey((str, key) => {
|
||||
if (!key) return;
|
||||
|
||||
const step = steps[currentStep];
|
||||
const optCount = step.options.length;
|
||||
|
||||
if (key.name === "left") {
|
||||
if (currentStep > 0) {
|
||||
currentStep--;
|
||||
currentOption = 0;
|
||||
}
|
||||
render();
|
||||
} else if (key.name === "right") {
|
||||
if (currentStep < steps.length - 1) {
|
||||
currentStep++;
|
||||
currentOption = 0;
|
||||
}
|
||||
render();
|
||||
} else if (key.name === "up") {
|
||||
currentOption = (currentOption - 1 + optCount) % optCount;
|
||||
render();
|
||||
} else if (key.name === "down") {
|
||||
currentOption = (currentOption + 1) % optCount;
|
||||
render();
|
||||
} else if (key.name === "space") {
|
||||
const opt = step.options[currentOption];
|
||||
if (step.type === "multiselect") {
|
||||
const idx = results[currentStep].indexOf(opt.value);
|
||||
if (idx >= 0) {
|
||||
results[currentStep].splice(idx, 1);
|
||||
} else {
|
||||
results[currentStep].push(opt.value);
|
||||
}
|
||||
} else {
|
||||
results[currentStep] = opt.value;
|
||||
}
|
||||
completed.add(currentStep);
|
||||
render();
|
||||
} else if (key.name === "return") {
|
||||
if (step.type === "select") {
|
||||
results[currentStep] = step.options[currentOption].value;
|
||||
}
|
||||
completed.add(currentStep);
|
||||
if (currentStep < steps.length - 1) {
|
||||
currentStep++;
|
||||
currentOption = 0;
|
||||
}
|
||||
render();
|
||||
} else if (key.name === "tab") {
|
||||
resolve(results);
|
||||
} else if (key.name === "escape" || (key.ctrl && key.name === "c")) {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 显示配置摘要
|
||||
export function showSummary(config) {
|
||||
console.clear();
|
||||
console.log(color.bgCyan(color.black(" KTX2 纹理压缩工具 ")));
|
||||
console.log("\n" + color.green("配置完成!当前设置:"));
|
||||
console.log(` 文件格式: ${config.exts.join(", ")}`);
|
||||
console.log(` 压缩程度: ${config.quality}`);
|
||||
console.log(` 编码格式: ${config.encoding}`);
|
||||
console.log(` Mipmap: ${config.mipmap}`);
|
||||
console.log(` 输出选项: ${config.outputOpts.join(", ")}\n`);
|
||||
}
|
||||
Reference in New Issue
Block a user