diff --git a/samples/dev/index.js b/samples/dev/index.js index 36e40bc..81ba3a9 100644 --- a/samples/dev/index.js +++ b/samples/dev/index.js @@ -20,6 +20,7 @@ const groups = { let stackCursor = null; let isMovingStackItem = false; let stackSnapshotBeforeMove = null; +let stackViewOffset = 0; function labelFor(command) { return ({ add: '+', sub: '−', mul: '×', div: '÷', pow: 'y^x', recip: '1/x', sqr: 'x²' }[command] || command); @@ -39,14 +40,14 @@ function getStackValue(index) { return calc.isValidIndex(index) ? calc.stack[index] : undefined; } -function getLineValue(line) { +function getDisplayValue(index) { if (calc.isEditing) { - if (line === 0) { + if (index === 0) { return calc.inputValue; } - return getStackValue(line - 1); + return getStackValue(index - 1); } - return getStackValue(line); + return getStackValue(index); } function hasStackSelection() { @@ -57,6 +58,7 @@ function clearStackSelection() { stackCursor = null; isMovingStackItem = false; stackSnapshotBeforeMove = null; + stackViewOffset = 0; } function ensureValidSelection() { @@ -140,16 +142,48 @@ function moveStackItem(direction) { 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() { const names = ['T', 'Z', 'Y', 'X']; const lines = []; const showStackIndexes = hasStackSelection() || isMovingStackItem; - for (let line = 3; line >= 0; line -= 1) { - const value = getLineValue(line); - const isSelected = stackCursor === line; + clampStackViewOffset(); + ensureSelectionVisible(); + + 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 label = showStackIndexes ? String(line) : names[3 - line]; + const label = showStackIndexes ? String(stackIndex) : names[3 - visualLine]; if (isSelected) { classes.push(isMovingStackItem ? 'moving' : 'selected');