Compare commits

..

2 Commits

Author SHA1 Message Date
matmoul f30bdb9946 fix: restore edited x value on escape 2026-04-25 01:17:32 +02:00
matmoul 2857df2c6f feat: add scroll offset for stack view in dev sample 2026-04-25 01:14:15 +02:00
+52 -8
View File
@@ -20,6 +20,8 @@ const groups = {
let stackCursor = null; let stackCursor = null;
let isMovingStackItem = false; let isMovingStackItem = false;
let stackSnapshotBeforeMove = null; let stackSnapshotBeforeMove = null;
let stackViewOffset = 0;
let editRestoreValue = null;
function labelFor(command) { function labelFor(command) {
return ({ add: '+', sub: '', mul: '×', div: '÷', pow: 'y^x', recip: '1/x', sqr: 'x²' }[command] || command); return ({ add: '+', sub: '', mul: '×', div: '÷', pow: 'y^x', recip: '1/x', sqr: 'x²' }[command] || command);
@@ -39,14 +41,14 @@ function getStackValue(index) {
return calc.isValidIndex(index) ? calc.stack[index] : undefined; return calc.isValidIndex(index) ? calc.stack[index] : undefined;
} }
function getLineValue(line) { function getDisplayValue(index) {
if (calc.isEditing) { if (calc.isEditing) {
if (line === 0) { if (index === 0) {
return calc.inputValue; return calc.inputValue;
} }
return getStackValue(line - 1); return getStackValue(index - 1);
} }
return getStackValue(line); return getStackValue(index);
} }
function hasStackSelection() { function hasStackSelection() {
@@ -57,6 +59,7 @@ function clearStackSelection() {
stackCursor = null; stackCursor = null;
isMovingStackItem = false; isMovingStackItem = false;
stackSnapshotBeforeMove = null; stackSnapshotBeforeMove = null;
stackViewOffset = 0;
} }
function ensureValidSelection() { function ensureValidSelection() {
@@ -103,9 +106,11 @@ function reactivateEditOnX() {
calc.remove(0); calc.remove(0);
calc.inputValue = calc.formatNumber(value); calc.inputValue = calc.formatNumber(value);
calc.isEditing = true; calc.isEditing = true;
editRestoreValue = value;
} else { } else {
calc.inputValue = ''; calc.inputValue = '';
calc.isEditing = true; calc.isEditing = true;
editRestoreValue = null;
} }
syncInputFromState(); syncInputFromState();
} }
@@ -140,16 +145,48 @@ function moveStackItem(direction) {
stackCursor = targetIndex; stackCursor = targetIndex;
} }
function getVisibleStackIndex(visualLine) {
return stackViewOffset + visualLine;
}
function clampStackViewOffset() {
const maxOffset = Math.max(0, calc.stack.length - 4);
if (stackViewOffset < 0) {
stackViewOffset = 0;
} else if (stackViewOffset > maxOffset) {
stackViewOffset = maxOffset;
}
}
function ensureSelectionVisible() {
if (!hasStackSelection()) {
stackViewOffset = 0;
return;
}
if (stackCursor < stackViewOffset) {
stackViewOffset = stackCursor;
} else if (stackCursor > stackViewOffset + 3) {
stackViewOffset = stackCursor - 3;
}
clampStackViewOffset();
}
function render() { function render() {
const names = ['T', 'Z', 'Y', 'X']; const names = ['T', 'Z', 'Y', 'X'];
const lines = []; const lines = [];
const showStackIndexes = hasStackSelection() || isMovingStackItem; const showStackIndexes = hasStackSelection() || isMovingStackItem;
for (let line = 3; line >= 0; line -= 1) { clampStackViewOffset();
const value = getLineValue(line); ensureSelectionVisible();
const isSelected = stackCursor === line;
for (let visualLine = 3; visualLine >= 0; visualLine -= 1) {
const stackIndex = getVisibleStackIndex(visualLine);
const value = getDisplayValue(stackIndex);
const isSelected = stackCursor === stackIndex;
const classes = ['stack-line']; const classes = ['stack-line'];
const label = showStackIndexes ? String(line) : names[3 - line]; const label = showStackIndexes ? String(stackIndex) : names[3 - visualLine];
if (isSelected) { if (isSelected) {
classes.push(isMovingStackItem ? 'moving' : 'selected'); classes.push(isMovingStackItem ? 'moving' : 'selected');
@@ -183,6 +220,7 @@ function pushEditingValueIfNeeded() {
} }
calc.inputValue = ''; calc.inputValue = '';
calc.isEditing = false; calc.isEditing = false;
editRestoreValue = null;
syncInputFromState(); syncInputFromState();
} }
@@ -317,6 +355,7 @@ function editXWithKey(key) {
pushEditingValueIfNeeded(); pushEditingValueIfNeeded();
calc.isEditing = true; calc.isEditing = true;
calc.inputValue = ''; calc.inputValue = '';
editRestoreValue = null;
} }
if (key === 'Backspace') { if (key === 'Backspace') {
calc.inputValue = calc.inputValue.slice(0, -1); calc.inputValue = calc.inputValue.slice(0, -1);
@@ -325,6 +364,7 @@ function editXWithKey(key) {
} }
if (calc.inputValue === '') { if (calc.inputValue === '') {
calc.isEditing = false; calc.isEditing = false;
editRestoreValue = null;
} }
syncInputFromState(); syncInputFromState();
} }
@@ -343,6 +383,10 @@ function handleKeydown(event) {
if (action.type === 'escapeKey') { if (action.type === 'escapeKey') {
if (calc.isEditing) { if (calc.isEditing) {
event.preventDefault(); event.preventDefault();
if (editRestoreValue !== null) {
calc.push(editRestoreValue);
editRestoreValue = null;
}
calc.inputValue = ''; calc.inputValue = '';
calc.isEditing = false; calc.isEditing = false;
syncInputFromState(); syncInputFromState();