tarinai/js/ui_tools.js
2026-06-26 12:46:32 +09:00

125 lines
4.9 KiB
JavaScript

"use strict";
const SCALABLE_TOOLS = new Set(scalableToolIds());
const EMOJI_ICON_TOOLS = new Set(["poke", "pinch", "water_hose"]);
const SIZE_ORDER = typeof TOOL_SIZE_ORDER !== "undefined" ? TOOL_SIZE_ORDER : ["small", "medium", "large"];
const SIZE_LABELS = typeof TOOL_SIZE_LABELS !== "undefined" ? TOOL_SIZE_LABELS : { small: "\u5c0f", medium: "\u4e2d", large: "\u5927" };
function renderToolPalette() {
if (!ui?.toolPalette || typeof toolCategories !== "function") return;
ui.toolPalette.innerHTML = "";
const frag = document.createDocumentFragment();
for (const category of toolCategories()) {
const section = document.createElement("section");
section.className = `tool-category ${category.themeClass || ""}`.trim();
section.dataset.toolCategory = category.id;
const toggle = document.createElement("button");
toggle.className = "tool-category-toggle";
toggle.type = "button";
toggle.setAttribute("aria-expanded", "true");
toggle.textContent = category.label || category.id;
const body = document.createElement("div");
body.className = "tool-grid tool-category-body";
for (const toolId of category.toolIds || []) {
const def = toolDefinition(toolId);
if (!def || def.simulationOnly || toolId === "observe") continue;
const btn = document.createElement("button");
btn.className = "tool";
if (EMOJI_ICON_TOOLS.has(toolId)) btn.classList.add("tool-emoji-icon");
btn.dataset.tool = toolId;
btn.dataset.toolCategory = category.id || "";
const label = document.createElement("span");
label.className = "tool-label";
label.textContent = def.label || toolId;
btn.setAttribute("aria-label", label.textContent);
btn.removeAttribute("title");
btn.appendChild(label);
attachToolSpritePreview(btn, def, toolId);
if (toolId === world?.tool) btn.classList.add("selected");
body.appendChild(btn);
}
section.append(toggle, body);
frag.appendChild(section);
}
ui.toolPalette.appendChild(frag);
}
function drawToolPreviewCanvas(canvas, itemType, { watermark = false } = {}) {
if (!canvas || !itemType) return false;
const ctx = canvas.getContext("2d");
if (!ctx) return false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (typeof window.drawToolItemPreview === "function") {
return window.drawToolItemPreview(ctx, itemType, { width: canvas.width, height: canvas.height, compact: true, watermark }) !== false;
}
if (typeof window.isConsumableSpriteType === "function" && window.isConsumableSpriteType(itemType) && typeof window.drawConsumableFieldSprite === "function") {
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
const baseScale = itemType === "protein" || itemType === "niteropu" ? 0.9 : 1.0;
ctx.scale(baseScale, baseScale);
window.drawConsumableFieldSprite(ctx, itemType, 17.5, 112.4, { compact: true });
ctx.restore();
return true;
}
return false;
}
function createToolPreviewCanvas(className, size = 96) {
const canvas = document.createElement("canvas");
canvas.className = className;
canvas.width = size;
canvas.height = size;
canvas.setAttribute("aria-hidden", "true");
return canvas;
}
function attachToolSpritePreview(btn, def, toolId) {
const itemType = def?.itemType || toolId;
if (!btn || !itemType || !def?.placeable) return;
if (toolId === "ball" || itemType === "ball") return;
if (typeof window.drawToolItemPreview !== "function" && typeof window.drawConsumableFieldSprite !== "function") return;
const iconCanvas = createToolPreviewCanvas("tool-sprite-preview", 160);
const iconDrawn = drawToolPreviewCanvas(iconCanvas, itemType);
if (!iconDrawn) return;
btn.classList.add("tool-has-canvas-icon");
btn.prepend(iconCanvas);
}
function toolSizeFor(tool) {
if (!SCALABLE_TOOLS.has(tool)) return "";
return typeof normalizedToolSizeFor === "function" ? normalizedToolSizeFor(world, tool) : ((world.toolSizes && world.toolSizes[tool]) || world.toolSize || "medium");
}
function cycleToolSize(tool) {
if (!SCALABLE_TOOLS.has(tool)) return false;
const result = window.TarinaiCommands?.dispatch?.(world, { type: "tool.size.cycle", toolId: tool, order: SIZE_ORDER });
if (!result?.ok) return false;
syncToolSizeBadges();
showToast(`\u30b5\u30a4\u30ba: ${SIZE_LABELS[result.size] || result.size}`);
return true;
}
function syncToolSizeBadges() {
for (const btn of uiCache.toolButtons || []) {
const tool = btn.dataset.tool || "";
const old = btn.querySelector(".tool-size-badge");
if (!SCALABLE_TOOLS.has(tool)) {
btn.removeAttribute("data-size");
if (old) old.remove();
continue;
}
const size = toolSizeFor(tool);
btn.dataset.size = size;
let badge = old;
if (!badge) {
badge = document.createElement("b");
badge.className = "tool-size-badge";
btn.appendChild(badge);
}
badge.textContent = SIZE_LABELS[size] || size;
}
}