sounds
This commit is contained in:
parent
c6ba3e38a2
commit
37087d08a7
189 changed files with 12864 additions and 9589 deletions
216
js/ui_layout_dialogs.js
Normal file
216
js/ui_layout_dialogs.js
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
"use strict";
|
||||
|
||||
function resizeCanvas() {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const perf = world?.performanceLevel ? world.performanceLevel() : 0;
|
||||
const maxDpr = perf >= 2 ? 1 : (perf === 1 ? 1.5 : 2);
|
||||
const dpr = Math.max(1, Math.min(window.devicePixelRatio || 1, maxDpr));
|
||||
const nextW = Math.max(1, Math.floor(rect.width * dpr));
|
||||
const nextH = Math.max(1, Math.floor(rect.height * dpr));
|
||||
if (canvas.width === nextW && canvas.height === nextH && uiCache.canvasDpr === dpr) return;
|
||||
uiCache.canvasDpr = dpr;
|
||||
canvas.width = nextW;
|
||||
canvas.height = nextH;
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
ctx.fillStyle = "#cfe3d3";
|
||||
ctx.fillRect(0, 0, Math.max(1, rect.width), Math.max(1, rect.height));
|
||||
world.setViewportSize(Math.max(1, rect.width), Math.max(1, rect.height));
|
||||
uiCache.lastChartDraw = "";
|
||||
if (typeof render === "function") render();
|
||||
}
|
||||
|
||||
function applyFieldLayout(fieldType = world.fieldType || "garden") {
|
||||
const field = FIELD_TYPES?.[fieldType] || FIELD_TYPES.garden;
|
||||
const root = document.documentElement;
|
||||
root.style.setProperty("--field-height", field.height);
|
||||
root.style.setProperty("--field-min-height", field.minHeight || field.height);
|
||||
root.style.setProperty("--field-mobile-height", field.mobileHeight || field.height);
|
||||
root.style.setProperty("--field-mobile-min-height", field.mobileMinHeight || field.mobileHeight || "460px");
|
||||
world.fieldType = field.id;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
world.setViewportSize(rect.width, rect.height);
|
||||
resizeCanvas();
|
||||
}
|
||||
|
||||
function openFieldDialog() {
|
||||
ui.fieldDialog?.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function closeFieldDialog() {
|
||||
ui.fieldDialog?.classList.add("hidden");
|
||||
}
|
||||
|
||||
function hydrateLazyImages(root) {
|
||||
const scope = root || document;
|
||||
for (const img of scope.querySelectorAll("img[data-src]")) {
|
||||
if (!img.getAttribute("src")) img.setAttribute("src", img.dataset.src || "");
|
||||
}
|
||||
}
|
||||
|
||||
function applyToolTips() {
|
||||
const tips = window.TEXT_CATALOG?.toolTips || {};
|
||||
if (!ui.toolPalette) return;
|
||||
let pop = document.getElementById("toolTipPopover");
|
||||
if (!pop) {
|
||||
pop = document.createElement("div");
|
||||
pop.id = "toolTipPopover";
|
||||
pop.className = "tool-tip-popover hidden";
|
||||
document.body.appendChild(pop);
|
||||
}
|
||||
const showTip = (btn) => {
|
||||
const baseTip = btn?.dataset?.tip || "";
|
||||
if (!baseTip) return;
|
||||
let tip = baseTip;
|
||||
if (btn?.dataset?.tool === "nest_box") {
|
||||
const count = world?.nestBoxToolTipCount?.();
|
||||
if (count) tip = `${baseTip}
|
||||
(${count.current}/${count.max})\u5339`;
|
||||
}
|
||||
pop.textContent = tip;
|
||||
pop.classList.remove("hidden");
|
||||
const rect = btn.getBoundingClientRect();
|
||||
const popW = pop.offsetWidth || 220;
|
||||
const popH = pop.offsetHeight || 36;
|
||||
const left = rect.left - popW - 12;
|
||||
pop.style.left = `${clamp(left, 8, Math.max(8, window.innerWidth - popW - 8))}px`;
|
||||
pop.style.top = `${clamp(rect.top + rect.height / 2 - popH / 2, 8, Math.max(8, window.innerHeight - popH - 8))}px`;
|
||||
};
|
||||
const hideTip = () => pop.classList.add("hidden");
|
||||
for (const btn of ui.toolPalette.querySelectorAll(".tool[data-tool]")) {
|
||||
const tip = tips[btn.dataset.tool];
|
||||
if (!tip) continue;
|
||||
btn.dataset.tip = tip;
|
||||
if (btn.dataset.tipBound === "1") continue;
|
||||
btn.dataset.tipBound = "1";
|
||||
btn.addEventListener("mouseenter", () => showTip(btn));
|
||||
btn.addEventListener("focus", () => showTip(btn));
|
||||
btn.addEventListener("mouseleave", hideTip);
|
||||
btn.addEventListener("blur", hideTip);
|
||||
}
|
||||
}
|
||||
|
||||
function renderEcologyCards() {
|
||||
if (!ui.ecologyGrid || ui.ecologyGrid.dataset.ready === "1") return;
|
||||
const cards = window.TEXT_CATALOG?.ecologyCards || [];
|
||||
ui.ecologyGrid.innerHTML = cards.map(card => `
|
||||
<section class="ecology-card">
|
||||
<img data-src="${escapeHtml(card.image || "assets/sprites/tarinai_01_smile.webp")}" loading="lazy" decoding="async" alt="">
|
||||
<div><strong>${escapeHtml(card.title || "")}</strong><p>${escapeHtml(card.text || "")}</p></div>
|
||||
</section>`).join("");
|
||||
ui.ecologyGrid.dataset.ready = "1";
|
||||
}
|
||||
|
||||
function openEcologyDialog() {
|
||||
renderEcologyCards();
|
||||
hydrateLazyImages(ui.ecologyDialog);
|
||||
ui.ecologyDialog?.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function closeEcologyDialog() {
|
||||
ui.ecologyDialog?.classList.add("hidden");
|
||||
}
|
||||
|
||||
function openArchiveResetDialog() {
|
||||
ui.archiveResetDialog?.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function closeArchiveResetDialog() {
|
||||
ui.archiveResetDialog?.classList.add("hidden");
|
||||
}
|
||||
|
||||
function resetWithField(fieldType) {
|
||||
const field = FIELD_TYPES?.[fieldType] || FIELD_TYPES.garden;
|
||||
closeFieldDialog();
|
||||
applyFieldLayout(field.id);
|
||||
world.reset(null, field.id);
|
||||
uiCache.archiveVersion = "";
|
||||
renderLog(world.logs);
|
||||
renderArchive();
|
||||
renderStats();
|
||||
render();
|
||||
}
|
||||
|
||||
function screenToWorld(e) {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const touch = e.touches ? e.touches[0] : e;
|
||||
const sx = touch.clientX - rect.left;
|
||||
const sy = touch.clientY - rect.top;
|
||||
return world.screenToWorld ? world.screenToWorld(sx, sy) : { x: sx, y: sy };
|
||||
}
|
||||
|
||||
function resizeFieldFromWheel(e) {
|
||||
if (!world.setFieldZoom) return;
|
||||
e.preventDefault();
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const sx = e.clientX - rect.left;
|
||||
const sy = e.clientY - rect.top;
|
||||
const focus = world.screenToWorld ? world.screenToWorld(sx, sy) : { x: sx, y: sy };
|
||||
const factor = e.deltaY > 0 ? 1 / 1.08 : 1.08;
|
||||
if (!world.setFieldZoom((world.fieldZoom || 1) * factor)) return;
|
||||
const off = world.fieldScreenOffset ? world.fieldScreenOffset() : { x: 0, y: 0 };
|
||||
const scale = world.viewScale ? world.viewScale() : 1;
|
||||
world.cameraX = focus.x - (sx - off.x) / scale;
|
||||
world.cameraY = focus.y - (sy - off.y) / scale;
|
||||
world.clampCamera?.();
|
||||
render();
|
||||
}
|
||||
|
||||
function selectTool(tool) {
|
||||
world.tool = tool;
|
||||
for (const btn of uiCache.toolButtons) {
|
||||
btn.classList.toggle("selected", btn.dataset.tool === tool);
|
||||
}
|
||||
syncToolSizeBadges();
|
||||
canvas.style.cursor = tool === "observe" ? "default" : (tool === "pinch" ? "grab" : (tool === "poke" || tool === "delete" ? "pointer" : "crosshair"));
|
||||
}
|
||||
|
||||
function showToast(text) {
|
||||
ui.toast.textContent = text;
|
||||
ui.toast.classList.remove("hidden");
|
||||
clearTimeout(showToast._timer);
|
||||
showToast._timer = setTimeout(() => ui.toast.classList.add("hidden"), 1400);
|
||||
}
|
||||
|
||||
function openCreditsDialog() {
|
||||
ui.creditsDialog?.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function closeCreditsDialog() {
|
||||
ui.creditsDialog?.classList.add("hidden");
|
||||
}
|
||||
|
||||
function syncTopButtons() {
|
||||
ui.pauseBtn.textContent = world.paused ? "\u518d\u958b" : "\u4e00\u6642\u505c\u6b62";
|
||||
ui.speedBtn.textContent = `\u901f\u5ea6 x${world.speed}`;
|
||||
syncAudioControls();
|
||||
syncArchiveUpdateButton();
|
||||
}
|
||||
|
||||
function archiveAutoUpdateEnabled() {
|
||||
return Boolean(uiCache.archiveUpdateEnabled);
|
||||
}
|
||||
|
||||
function syncArchiveUpdateButton() {
|
||||
const btn = ui.archiveUpdateToggleBtn;
|
||||
if (!btn) return;
|
||||
const on = archiveAutoUpdateEnabled();
|
||||
btn.textContent = on ? "\u66f4\u65b0 ON" : "\u66f4\u65b0 OFF";
|
||||
btn.classList.toggle("active", on);
|
||||
btn.setAttribute("aria-pressed", on ? "true" : "false");
|
||||
}
|
||||
|
||||
function setArchiveUpdateEnabled(on) {
|
||||
uiCache.archiveUpdateEnabled = Boolean(on);
|
||||
syncArchiveUpdateButton();
|
||||
if (uiCache.archiveUpdateEnabled) {
|
||||
uiCache.archiveVersion = "";
|
||||
uiCache.archiveFamilyVersion = null;
|
||||
world.familyTreeDirty = true;
|
||||
scheduleArchiveWindowRender?.();
|
||||
showToast("\u5bb6\u7cfb\u56f3\u306e\u66f4\u65b0\u3092ON\u306b\u3057\u307e\u3057\u305f\u3002");
|
||||
} else {
|
||||
if (uiCache.archiveRenderTimer) { clearTimeout(uiCache.archiveRenderTimer); uiCache.archiveRenderTimer = 0; }
|
||||
uiCache.archiveScheduled = false;
|
||||
showToast("\u5bb6\u7cfb\u56f3\u306e\u66f4\u65b0\u3092OFF\u306b\u3057\u307e\u3057\u305f\u3002");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue