From 51d81c67805c7a6470d6a87484ce062a7652a6bb Mon Sep 17 00:00:00 2001 From: gitProtogen Date: Fri, 6 Feb 2026 11:10:18 +0100 Subject: [PATCH] editing normal nodetText --- index.h | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++ ledy.ino | 17 ++++++ prototypes.h | 2 + server.ino | 84 ++++++++++++++++++++++++---- structs.h | 6 +- 5 files changed, 249 insertions(+), 12 deletions(-) diff --git a/index.h b/index.h index 41c9d60..ed1bc56 100644 --- a/index.h +++ b/index.h @@ -40,6 +40,48 @@ const char index_html[] PROGMEM = R"rawliteral( padding: 10px; white-space: pre-wrap; } + #nodes-container { + margin-top: 20px; + border: 1px solid #ccc; + padding: 10px; + margin-bottom: 10px; + } + .node-item { + border-bottom: 1px solid #eee; + padding: 5px; + margin-bottom: 5px; + } + .modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ + } + .modal-content { + background-color: #fefefe; + margin: 15% auto; /* 15% from the top and centered */ + padding: 20px; + border: 1px solid #888; + width: 80%; /* Could be more or less, depending on screen size */ + } + .close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; + } + .close:hover, + .close:focus { + color: black; + text-decoration: none; + cursor: pointer; + } @@ -53,6 +95,37 @@ const char index_html[] PROGMEM = R"rawliteral(
+
+

Current Text Nodes

+
+
+ + +

Add Text Node (Full Control)

void addNewTextNode(char text[TEXT_MAX_LENGTH + 1], uint32_t color, bool handle_pos_via_cursor = true, short pos_x = 0, short pos_y = 0, unsigned char scroll_slowness = 1, bool is_scrolling = true, bool is_small = true, short disappear_time = -1)
@@ -172,6 +245,11 @@ const char index_html[] PROGMEM = R"rawliteral( } if(fontSize) data += "&fontSize=" + fontSize; + xhr.onload = function() { + if (xhr.status === 200) { + fetchNodes(); + } + }; xhr.send(data); } @@ -202,8 +280,82 @@ const char index_html[] PROGMEM = R"rawliteral( if(y) data += "&y=" + y; if(fontSize) data += "&fontSize=" + fontSize; + xhr.onload = function() { + if (xhr.status === 200) { + fetchNodes(); + } + }; xhr.send(data); } + + function modifyText() { + const id = document.getElementById('modifyIdInput').value; + const color = document.getElementById('modifyColorPicker').value; + const text = document.getElementById('modifyTextInput').value; + const slowness = document.getElementById('modifySlownessInput').value; + + if (!id) { + alert('Please enter a node ID.'); + return; + } + + var xhr = new XMLHttpRequest(); + xhr.open("POST", "/modify-text", true); + xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + + let data = "id=" + id + "&color=" + encodeURIComponent(color) + "&text=" + encodeURIComponent(text) + "&slowness=" + slowness; + xhr.onload = function() { + if (xhr.status === 200) { + fetchNodes(); + closeModal(); + } + }; + xhr.send(data); + } + + function fetchNodes() { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/nodes", true); + xhr.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var nodes = JSON.parse(this.responseText); + var nodesList = document.getElementById('nodes-list'); + nodesList.innerHTML = ''; + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var color = '#' + ('000000' + node.color.toString(16)).slice(-6); + var nodeDiv = document.createElement('div'); + nodeDiv.className = 'node-item'; + nodeDiv.innerHTML = 'ID: ' + node.id + ', Text: ' + node.text + ', Color: ' + color + '' + + ''; + nodesList.appendChild(nodeDiv); + } + } + }; + xhr.send(); + } + + function populateModifyForm(id, color, text, slowness) { + document.getElementById('modifyIdInput').value = id; + document.getElementById('modifyIdDisplay').innerText = id; + document.getElementById('modifyColorPicker').value = color; + document.getElementById('modifyTextInput').value = text; + document.getElementById('modifySlownessInput').value = slowness; + document.getElementById('modify-modal').style.display = "block"; + } + + function closeModal() { + document.getElementById('modify-modal').style.display = "none"; + } + + window.onclick = function(event) { + if (event.target == document.getElementById('modify-modal')) { + closeModal(); + } + } + + setInterval(fetchNodes, 5000); + window.onload = fetchNodes; diff --git a/ledy.ino b/ledy.ino index ccd0425..7fbbc54 100644 --- a/ledy.ino +++ b/ledy.ino @@ -71,6 +71,7 @@ void addNewTextNode text_nodes[i].is_scrolling = is_scrolling; text_nodes[i].is_repeating = is_repeating; text_nodes[i].disappear_time = disappear_time; + text_nodes[i].id = ever_created_text_nodes; ever_created_text_nodes++; if (handle_pos_via_cursor) @@ -82,6 +83,21 @@ void addNewTextNode } } +void modifyTextNodeById(unsigned char id, uint32_t new_color, char new_text[TEXT_MAX_LENGTH + 1], unsigned char new_slowness) +{ + for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++) + { + if (text_nodes[i].id == id && text_nodes[i].disappear_time != 0) + { + text_nodes[i].color = new_color; + strncpy(text_nodes[i].content, new_text, TEXT_MAX_LENGTH); + text_nodes[i].character_count = strlen(new_text); + text_nodes[i].scroll_slowness = new_slowness; + break; + } + } +} + void scrollAllScrollableTexts(bool split_scroll_mode = false) { for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++) @@ -187,6 +203,7 @@ void addNewMultiColor multi_color_text_node[i].is_scrolling = is_scrolling; multi_color_text_node[i].is_repeating = is_repeating; multi_color_text_node[i].disappear_time = disappear_time; + multi_color_text_node[i].id = ever_created_multi_color_text_nodes; ever_created_multi_color_text_nodes++; if (handle_pos_via_cursor) diff --git a/prototypes.h b/prototypes.h index f7f674f..d5d3974 100644 --- a/prototypes.h +++ b/prototypes.h @@ -26,6 +26,8 @@ void handleMultiColorDisappearTimers(); short getTextNodeY2(TextNode *node); short getTextNodeX2(TextNode *node); short getMultiColorTextNodeX2(MultiColorTextNode *node); +void modifyTextNodeById(unsigned char id, uint32_t new_color, char new_text[TEXT_MAX_LENGTH + 1], unsigned char new_slowness); + #endif // PROTOTYPES_H \ No newline at end of file diff --git a/server.ino b/server.ino index 1d7837a..52cd456 100644 --- a/server.ino +++ b/server.ino @@ -214,18 +214,80 @@ void handleMulticolorText() { addNewMultiColor(text, colors, color_count, false, x, y, slowness, true, is_small, disappear_time, is_repeating); server.send(200, "text/plain", "OK"); - } else { - server.send(400, "text/plain", "Invalid arguments for /multicolor-text"); + } else { + server.send(400, "text/plain", "Invalid arguments for /multicolor-text"); + } } -} - - - -void start_server() -{ - WiFi.begin(ssid, password); - while (WiFi.status() != WL_CONNECTED) + + void handleModifyText() { + if (server.hasArg("id") && server.hasArg("color")) + { + unsigned char id = server.arg("id").toInt(); + String colorStr = server.arg("color"); + uint32_t color = strtol(colorStr.substring(1).c_str(), NULL, 16); + String text_str = server.arg("text"); + char text[TEXT_MAX_LENGTH + 1]; + text_str.toCharArray(text, TEXT_MAX_LENGTH + 1); + unsigned char slowness = server.arg("slowness").toInt(); + modifyTextNodeById(id, color, text, slowness); + server.send(200, "text/plain", "OK"); + } + else + { + server.send(400, "text/plain", "Invalid arguments for /modify-text"); + } + } void handleGetNodes() + { + StaticJsonDocument<2048> jsonDoc; + JsonArray nodes = jsonDoc.to(); + + for (int i = 0; i < MAX_TEXT_NODES_COUNT; i++) + { + if (text_nodes[i].disappear_time != 0) + { + JsonObject node = nodes.createNestedObject(); + node["id"] = text_nodes[i].id; node["text"] = text_nodes[i].content; + node["color"] = text_nodes[i].color; + node["x"] = text_nodes[i].pos_x; + node["y"] = text_nodes[i].pos_y; + node["slowness"] = text_nodes[i].scroll_slowness; + node["is_repeating"] = text_nodes[i].is_repeating; + node["type"] = "text"; + node["slowness"] = text_nodes[i].scroll_slowness; + } + } + for (int i = 0; i < MAX_TEXT_NODES_COUNT; i++) + { + if (multi_color_text_node[i].disappear_time != 0) + { + JsonObject node = nodes.createNestedObject(); + node["id"] = multi_color_text_node[i].id; node["text"] = multi_color_text_node[i].content; + JsonArray colors = node.createNestedArray("colors"); + for(int j = 0; j < multi_color_text_node[i].color_count; j++) + { + JsonObject color = colors.createNestedObject(); + color["r"] = multi_color_text_node[i].colors[j].r; + color["g"] = multi_color_text_node[i].colors[j].g; + color["b"] = multi_color_text_node[i].colors[j].b; + } + node["x"] = multi_color_text_node[i].pos_x; + node["y"] = multi_color_text_node[i].pos_y; + node["slowness"] = multi_color_text_node[i].scroll_slowness; + node["is_repeating"] = multi_color_text_node[i].is_repeating; + node["type"] = "multi-color"; + node["slowness"] = multi_color_text_node[i].scroll_slowness; + } + } + String jsonString; + serializeJson(jsonDoc, jsonString); + server.send(200, "application/json", jsonString); + } + + void start_server() + { + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } @@ -233,7 +295,9 @@ void start_server() Serial.println(WiFi.localIP()); server.on("/", handleRoot); + server.on("/nodes", HTTP_GET, handleGetNodes); server.on("/text", HTTP_POST, handleText); + server.on("/modify-text", HTTP_POST, handleModifyText); server.on("/multicolor-text", HTTP_POST, handleMulticolorText); server.on("/brightness", HTTP_POST, handleBrightness); server.on("/upload-page", HTTP_GET, handleUploadPage); diff --git a/structs.h b/structs.h index fd2ab16..8b3ec6b 100644 --- a/structs.h +++ b/structs.h @@ -20,6 +20,7 @@ struct Pixel struct TextNode { + unsigned char id; char content[TEXT_MAX_LENGTH]; uint32_t color; struct CharacterSize @@ -37,7 +38,7 @@ struct TextNode bool is_repeating; - TextNode() : color(0), pos_x(0), pos_y(0), character_count(0), scroll_slowness(0), scroll_progress(0), characterSize({7,5}), disappear_time(0), is_scrolling(true), is_repeating(false) {} + TextNode() : id(0), color(0), pos_x(0), pos_y(0), character_count(0), scroll_slowness(0), scroll_progress(0), characterSize({7,5}), disappear_time(0), is_scrolling(true), is_repeating(false) {} }; struct RGB @@ -62,6 +63,7 @@ struct RGBWithIndex struct MultiColorTextNode { + unsigned char id; char content[TEXT_MAX_LENGTH]; RGBWithIndex colors[4]; @@ -80,7 +82,7 @@ struct MultiColorTextNode bool is_scrolling; bool is_repeating; - MultiColorTextNode() : pos_x(0), pos_y(0), character_count(0), scroll_slowness(0), scroll_progress(0), characterSize({7,5}), disappear_time(0), is_scrolling(true), color_count(0), is_repeating(false) {} + MultiColorTextNode() : id(0), pos_x(0), pos_y(0), character_count(0), scroll_slowness(0), scroll_progress(0), characterSize({7,5}), disappear_time(0), is_scrolling(true), color_count(0), is_repeating(false) {} }; struct Image