vibecoded page and function change in ino

This commit is contained in:
2026-01-28 21:26:26 +01:00
parent a57485360a
commit 62be6be733
2 changed files with 495 additions and 128 deletions
+2 -6
View File
@@ -71,7 +71,7 @@ void drawTextNodes(bool reset_cursor = true)
} }
} }
void scrollAllScrollableTexts() void scrollAllScrollableTexts(split_scroll_mode = false)
{ {
for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++) for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++)
{ {
@@ -81,10 +81,8 @@ void scrollAllScrollableTexts()
short y1 = text_nodes[i].pos_y; short y1 = text_nodes[i].pos_y;
short x2 = text_nodes[i].pos_x + text_nodes[i].characterSize.width * text_nodes[i].character_count + text_nodes[i].character_count - 1; short x2 = text_nodes[i].pos_x + text_nodes[i].characterSize.width * text_nodes[i].character_count + text_nodes[i].character_count - 1;
short y2 = text_nodes[i].pos_y + text_nodes[i].characterSize.height - 1; short y2 = text_nodes[i].pos_y + text_nodes[i].characterSize.height - 1;
// If the text is scrolling on the upper part of the screen, scroll it to the left. if (split_scroll_mode || text_nodes[i].pos_y < 7)
if (text_nodes[i].pos_y < 7)
{ {
// If the text is completely out of the screen, mark it as deleted.
if (x2 < 0) if (x2 < 0)
{ {
text_nodes[i].is_deleted = true; text_nodes[i].is_deleted = true;
@@ -93,10 +91,8 @@ void scrollAllScrollableTexts()
shiftGivenRectangleLeft(x1, y1, x2, y2, text_nodes[i].scroll_slowness); shiftGivenRectangleLeft(x1, y1, x2, y2, text_nodes[i].scroll_slowness);
text_nodes[i].pos_x -= text_nodes[i].scroll_slowness; text_nodes[i].pos_x -= text_nodes[i].scroll_slowness;
} }
// If the text is scrolling on the lower part of the screen, scroll it to the right.
else else
{ {
// If the text is completely out of the screen, mark it as deleted.
if (x1 > PANEL_MAX_X) if (x1 > PANEL_MAX_X)
{ {
text_nodes[i].is_deleted = true; text_nodes[i].is_deleted = true;
+472 -101
View File
@@ -5,31 +5,124 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<style> <style>
body { body {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
padding: 20px; padding: 20px;
max-width: 800px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
background-color: #0d1117;
color: #c9d1d9;
} }
h1 { h1 {
text-align: center; text-align: center;
color: #333; color: #c9d1d9;
} }
.grid-container { .size-controls {
display: inline-grid; display: flex;
grid-template-columns: repeat(5, 25px); justify-content: center;
gap: 5px; gap: 20px;
margin: 20px 0;
padding: 15px;
background-color: #161b22;
border-radius: 8px;
border: 1px solid #30363d;
}
.size-input-group {
display: flex;
flex-direction: column;
align-items: center;
}
.size-input-group label {
font-weight: bold;
margin-bottom: 5px;
color: #c9d1d9;
}
.size-input-group input[type="number"] {
width: 80px;
padding: 8px;
font-size: 16px;
border: 1px solid #30363d;
border-radius: 6px;
text-align: center;
background-color: #0d1117;
color: #c9d1d9;
}
.size-input-group input[type="number"]:focus {
outline: none;
border-color: #58a6ff;
}
.color-controls {
display: flex;
justify-content: center;
gap: 20px;
margin: 20px 0;
padding: 15px;
background-color: #161b22;
border-radius: 8px;
border: 1px solid #30363d;
align-items: center;
}
.color-picker-group {
display: flex;
gap: 10px;
align-items: center;
}
.color-picker-group label {
font-weight: bold;
color: #c9d1d9;
}
.color-picker-wrapper {
display: flex;
align-items: center;
gap: 10px;
padding: 5px 10px;
background-color: #0d1117;
border: 1px solid #30363d;
border-radius: 6px;
}
input[type="color"] {
width: 50px;
height: 35px;
border: none;
border-radius: 4px;
cursor: pointer;
background: transparent;
}
.color-value {
font-family: 'Courier New', monospace;
font-size: 14px;
color: #c9d1d9;
min-width: 70px;
}
.canvas-container {
margin: 20px 0; margin: 20px 0;
padding: 10px; padding: 10px;
background-color: #f5f5f5; background-color: #161b22;
border-radius: 8px; border-radius: 8px;
border: 1px solid #30363d;
display: inline-block;
} }
.checkbox-cell { #gridCanvas {
width: 25px; cursor: crosshair;
height: 25px; display: block;
cursor: pointer; background-color: #000000;
} }
.controls { .controls {
@@ -41,138 +134,416 @@
padding: 10px 20px; padding: 10px 20px;
font-size: 16px; font-size: 16px;
cursor: pointer; cursor: pointer;
background-color: #0969da; background-color: transparent;
color: white; color: #c9d1d9;
border: none; border: 1px solid #c9d1d9;
border-radius: 6px; border-radius: 6px;
margin: 0 5px; margin: 0 5px;
transition: all 0.2s;
} }
button:hover { button:hover {
background-color: #0860ca; background-color: rgba(201, 209, 217, 0.1);
border-color: #ffffff;
color: #ffffff;
} }
.json-output { .export-section {
margin-top: 20px; margin: 20px 0;
padding: 15px; padding: 20px;
background-color: #f6f8fa; background-color: #161b22;
border: 1px solid #d0d7de; border-radius: 8px;
border: 1px solid #30363d;
text-align: center;
}
.export-section h3 {
margin-top: 0;
color: #c9d1d9;
}
.export-options {
display: flex;
justify-content: center;
gap: 15px;
margin: 15px 0;
flex-wrap: wrap;
}
.radio-group {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 15px;
background-color: #0d1117;
border: 1px solid #30363d;
border-radius: 6px; border-radius: 6px;
font-family: 'Courier New', monospace; cursor: pointer;
font-size: 12px; transition: all 0.2s;
white-space: pre-wrap; user-select: none;
word-wrap: break-word;
max-height: 400px;
overflow-y: auto;
} }
.hidden { .radio-group:hover {
display: none; border-color: #58a6ff;
background-color: rgba(88, 166, 255, 0.1);
} }
.copy-button { .radio-group input[type="radio"] {
background-color: #2da44e; cursor: pointer;
width: 18px;
height: 18px;
pointer-events: none;
}
.radio-group label {
cursor: pointer;
color: #c9d1d9;
margin: 0;
pointer-events: none;
}
.radio-group.selected {
border-color: #58a6ff;
background-color: rgba(88, 166, 255, 0.15);
}
.format-description {
font-size: 13px;
color: #8b949e;
margin-top: 10px; margin-top: 10px;
} }
.copy-button:hover { .generate-button {
background-color: #2c974b; margin-top: 15px;
position: relative;
} }
.copied-message { .copied-message {
color: #2da44e; color: #3fb950;
margin-left: 10px; margin-left: 10px;
font-weight: bold; font-weight: bold;
display: inline-block;
opacity: 0;
transition: opacity 0.3s;
}
.copied-message.show {
opacity: 1;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="grid-container" id="checkboxGrid"></div> <h1>Grid Color Generator</h1>
<div class="controls"> <div class="size-controls">
<button onclick="generateJSON()">Generate JSON</button> <div class="size-input-group">
<button onclick="clearGrid()">Clear All</button> <label for="rowsInput">Rows:</label>
<button onclick="checkAll()">Check All</button> <input type="number" id="rowsInput" min="1" max="50" value="16">
</div> </div>
<div class="size-input-group">
<div id="jsonOutputContainer" class="hidden"> <label for="colsInput">Columns:</label>
<h3>JSON Output:</h3> <input type="number" id="colsInput" min="1" max="50" value="43">
<div class="json-output" id="jsonOutput"></div>
<button class="copy-button" onclick="copyToClipboard()">Copy to Clipboard</button>
<span id="copiedMessage" class="copied-message hidden">✓ Copied!</span>
</div> </div>
</div>
<script> <div class="color-controls">
// Initialize the 7x5 grid (7 rows, 5 columns) <div class="color-picker-group">
function initializeGrid() { <label for="colorPicker">Draw Color:</label>
const grid = document.getElementById('checkboxGrid'); <div class="color-picker-wrapper">
grid.innerHTML = ''; <input type="color" id="colorPicker" value="#ffffff">
<span class="color-value" id="colorValue">#ffffff</span>
</div>
</div>
</div>
for (let i = 0; i < 7; i++) { <div class="canvas-container">
for (let j = 0; j < 5; j++) { <canvas id="gridCanvas"></canvas>
const checkbox = document.createElement('input'); </div>
checkbox.type = 'checkbox';
checkbox.className = 'checkbox-cell'; <div class="controls">
checkbox.dataset.row = i; <button onclick="clearGrid()">Clear All</button>
checkbox.dataset.col = j; <button onclick="fillAll()">Fill All</button>
grid.appendChild(checkbox); </div>
}
<div class="export-section">
<h3>Export Format</h3>
<div class="export-options">
<div class="radio-group selected" onclick="selectFormat('boolean')">
<input type="radio" id="formatBoolean" name="exportFormat" value="boolean" checked>
<label for="formatBoolean">Boolean (true/false)</label>
</div>
<div class="radio-group" onclick="selectFormat('color')">
<input type="radio" id="formatColor" name="exportFormat" value="color">
<label for="formatColor">Color (hex codes)</label>
</div>
</div>
<div class="format-description">
<strong>Boolean:</strong> Exports filled cells as true, empty as false<br>
<strong>Color:</strong> Exports actual hex color values, empty cells as null
</div>
<div class="generate-button">
<button onclick="generateAndCopy()">Generate & Copy to Clipboard</button>
<span id="copiedMessage" class="copied-message">✓ Copied!</span>
</div>
</div>
<script>
const canvas = document.getElementById('gridCanvas');
const ctx = canvas.getContext('2d');
let currentRows = 16;
let currentCols = 43;
let cellSize = 25;
let gridState = []; // Stores color values or null
let isDrawing = false;
let drawMode = null; // 'fill' or 'erase'
let currentColor = '#ffffff';
// Colors
const colors = {
background: '#000000',
border: '#30363d',
borderHover: '#58a6ff'
};
// Select format radio button
function selectFormat(format) {
// Update radio buttons
const booleanRadio = document.getElementById('formatBoolean');
const colorRadio = document.getElementById('formatColor');
if (format === 'boolean') {
booleanRadio.checked = true;
colorRadio.checked = false;
} else {
booleanRadio.checked = false;
colorRadio.checked = true;
}
// Update visual selection
const radioGroups = document.querySelectorAll('.radio-group');
radioGroups.forEach(group => group.classList.remove('selected'));
event.currentTarget.classList.add('selected');
}
// Initialize grid state
function initializeGrid() {
gridState = [];
for (let i = 0; i < currentRows; i++) {
gridState[i] = [];
for (let j = 0; j < currentCols; j++) {
gridState[i][j] = null;
} }
} }
// Generate JSON from checkbox states // Resize canvas
function generateJSON() { canvas.width = currentCols * cellSize;
const checkboxes = document.querySelectorAll('.checkbox-cell'); canvas.height = currentRows * cellSize;
const grid = [];
// Create 2D array (7 rows x 5 columns) drawGrid();
for (let i = 0; i < 7; i++) { }
grid[i] = [];
for (let j = 0; j < 5; j++) { // Draw the grid
const checkbox = document.querySelector(`[data-row="${i}"][data-col="${j}"]`); function drawGrid() {
grid[i][j] = checkbox.checked; // Clear canvas with black background
ctx.fillStyle = colors.background;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw cells
for (let i = 0; i < currentRows; i++) {
for (let j = 0; j < currentCols; j++) {
drawCell(i, j, gridState[i][j]);
}
}
}
// Draw individual cell
function drawCell(row, col, colorValue) {
const x = col * cellSize;
const y = row * cellSize;
// Draw cell background (black)
ctx.fillStyle = colors.background;
ctx.fillRect(x, y, cellSize, cellSize);
// Draw cell border
ctx.strokeStyle = colors.border;
ctx.lineWidth = 1;
ctx.strokeRect(x + 0.5, y + 0.5, cellSize - 1, cellSize - 1);
// Draw filled state with color
if (colorValue !== null) {
ctx.fillStyle = colorValue;
const padding = 3;
ctx.fillRect(
x + padding,
y + padding,
cellSize - padding * 2,
cellSize - padding * 2
);
}
}
// Get cell coordinates from mouse position
function getCellFromMouse(e) {
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
const col = Math.floor(mouseX / cellSize);
const row = Math.floor(mouseY / cellSize);
if (row >= 0 && row < currentRows && col >= 0 && col < currentCols) {
return { row, col };
}
return null;
}
// Mouse down event
canvas.addEventListener('mousedown', function(e) {
e.preventDefault();
isDrawing = true;
const cell = getCellFromMouse(e);
if (cell) {
if (e.button === 0) { // Left click
drawMode = 'fill';
gridState[cell.row][cell.col] = currentColor;
} else if (e.button === 2) { // Right click
drawMode = 'erase';
gridState[cell.row][cell.col] = null;
}
drawCell(cell.row, cell.col, gridState[cell.row][cell.col]);
}
});
// Mouse move event
canvas.addEventListener('mousemove', function(e) {
if (!isDrawing) return;
const cell = getCellFromMouse(e);
if (cell) {
if (drawMode === 'fill') {
gridState[cell.row][cell.col] = currentColor;
} else if (drawMode === 'erase') {
gridState[cell.row][cell.col] = null;
}
drawCell(cell.row, cell.col, gridState[cell.row][cell.col]);
}
});
// Mouse up event
canvas.addEventListener('mouseup', function(e) {
isDrawing = false;
drawMode = null;
});
// Mouse leave event
canvas.addEventListener('mouseleave', function(e) {
isDrawing = false;
drawMode = null;
});
// Prevent context menu
canvas.addEventListener('contextmenu', function(e) {
e.preventDefault();
return false;
});
// Color picker change
document.getElementById('colorPicker').addEventListener('input', function(e) {
currentColor = e.target.value;
document.getElementById('colorValue').textContent = currentColor;
});
// Update grid size
function updateGridSize() {
const rowsInput = document.getElementById('rowsInput');
const colsInput = document.getElementById('colsInput');
currentRows = parseInt(rowsInput.value) || 1;
currentCols = parseInt(colsInput.value) || 1;
if (currentRows < 1) currentRows = 1;
if (currentCols < 1) currentCols = 1;
initializeGrid();
}
// Generate JSON and copy to clipboard
function generateAndCopy() {
const formatRadios = document.getElementsByName('exportFormat');
let selectedFormat = 'boolean';
for (const radio of formatRadios) {
if (radio.checked) {
selectedFormat = radio.value;
break;
}
}
let outputData = [];
if (selectedFormat === 'boolean') {
// Convert to boolean: filled = true, empty = false
for (let i = 0; i < currentRows; i++) {
outputData[i] = [];
for (let j = 0; j < currentCols; j++) {
outputData[i][j] = gridState[i][j] !== null;
} }
} }
} else {
// Display JSON // Keep color values: hex codes or null
const jsonOutput = document.getElementById('jsonOutput'); outputData = JSON.parse(JSON.stringify(gridState)); // Deep copy
const jsonOutputContainer = document.getElementById('jsonOutputContainer');
jsonOutput.textContent = JSON.stringify(grid, null, 2);
jsonOutputContainer.classList.remove('hidden');
// Hide copied message
document.getElementById('copiedMessage').classList.add('hidden');
} }
// Clear all checkboxes // Generate JSON string
function clearGrid() { const jsonText = JSON.stringify(outputData, null, 2);
const checkboxes = document.querySelectorAll('.checkbox-cell');
checkboxes.forEach(cb => cb.checked = false);
}
// Check all checkboxes // Copy to clipboard
function checkAll() { navigator.clipboard.writeText(jsonText).then(() => {
const checkboxes = document.querySelectorAll('.checkbox-cell'); const message = document.getElementById('copiedMessage');
checkboxes.forEach(cb => cb.checked = true); message.classList.add('show');
} setTimeout(() => {
message.classList.remove('show');
}, 2000);
}).catch(err => {
alert('Failed to copy to clipboard');
console.error('Copy failed:', err);
});
}
// Copy JSON to clipboard // Clear all cells
function copyToClipboard() { function clearGrid() {
const jsonText = document.getElementById('jsonOutput').textContent; for (let i = 0; i < currentRows; i++) {
navigator.clipboard.writeText(jsonText).then(() => { for (let j = 0; j < currentCols; j++) {
const message = document.getElementById('copiedMessage'); gridState[i][j] = null;
message.classList.remove('hidden'); }
setTimeout(() => {
message.classList.add('hidden');
}, 2000);
}).catch(err => {
alert('Failed to copy to clipboard');
console.error('Copy failed:', err);
});
} }
drawGrid();
}
// Fill all cells
function fillAll() {
for (let i = 0; i < currentRows; i++) {
for (let j = 0; j < currentCols; j++) {
gridState[i][j] = currentColor;
}
}
drawGrid();
}
// Add event listeners to inputs
document.addEventListener('DOMContentLoaded', function() {
const rowsInput = document.getElementById('rowsInput');
const colsInput = document.getElementById('colsInput');
rowsInput.addEventListener('input', updateGridSize);
colsInput.addEventListener('input', updateGridSize);
// Initialize grid on page load // Initialize grid on page load
initializeGrid(); initializeGrid();
</script> });
</script>
</body> </body>
</html> </html>