diff --git a/index.h b/index.h index 961bcf8..f38e9fe 100644 --- a/index.h +++ b/index.h @@ -105,8 +105,8 @@ const char index_html[] PROGMEM = R"rawliteral( ×

Modify Text Node

- - Node ID: + + Node Global ID:
@@ -131,8 +131,8 @@ const char index_html[] PROGMEM = R"rawliteral( ×

Modify Multi-Color Text Node

- - Node ID: + + Node Global ID:
@@ -311,12 +311,12 @@ const char index_html[] PROGMEM = R"rawliteral( } function modifyText() { - const id = document.getElementById('modifyIdInput').value; + const global_id = document.getElementById('modifyGlobalIdInput').value; const color = document.getElementById('modifyColorPicker').value; const text = document.getElementById('modifyTextInput').value; const slowness = document.getElementById('modifySlownessInput').value; - if (!id) { + if (!global_id) { alert('Please enter a node ID.'); return; } @@ -325,7 +325,7 @@ const char index_html[] PROGMEM = R"rawliteral( 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; + let data = "global_id=" + global_id + "&color=" + encodeURIComponent(color) + "&text=" + encodeURIComponent(text) + "&slowness=" + slowness; xhr.onload = function() { if (xhr.status === 200) { fetchNodes(); @@ -349,12 +349,12 @@ const char index_html[] PROGMEM = R"rawliteral( nodeDiv.className = 'node-item'; if (node.type === 'text') { var color = '#' + ('000000' + node.color.toString(16)).slice(-6); - nodeDiv.innerHTML = 'ID: ' + node.id + ', Text: ' + node.text + ', Color: ' + color + '' + - ''; + nodeDiv.innerHTML = 'ID: ' + node.global_id + ', Text: ' + node.text + ', Color: ' + color + '' + + ''; } else if (node.type === 'multi-color') { var colorsStr = node.colors.map(c => '#' + ('000000' + ((c.r << 16) | (c.g << 8) | c.b).toString(16)).slice(-6)).join(','); - nodeDiv.innerHTML = 'ID: ' + node.id + ', Text: ' + node.text + ', Type: Multi-Color' + - ''; + nodeDiv.innerHTML = 'ID: ' + node.global_id + ', Text: ' + node.text + ', Type: Multi-Color' + + ''; } nodesList.appendChild(nodeDiv); } @@ -363,9 +363,9 @@ const char index_html[] PROGMEM = R"rawliteral( xhr.send(); } - function populateModifyForm(id, color, text, slowness) { - document.getElementById('modifyIdInput').value = id; - document.getElementById('modifyIdDisplay').innerText = id; + function populateModifyForm(global_id, color, text, slowness) { + document.getElementById('modifyGlobalIdInput').value = global_id; + document.getElementById('modifyGlobalIdDisplay').innerText = global_id; document.getElementById('modifyColorPicker').value = color; document.getElementById('modifyTextInput').value = text; document.getElementById('modifySlownessInput').value = slowness; @@ -376,9 +376,9 @@ const char index_html[] PROGMEM = R"rawliteral( document.getElementById('modify-modal').style.display = "none"; } - function populateMultiColorModifyForm(id, colors, text) { - document.getElementById('modifyMultiColorIdInput').value = id; - document.getElementById('modifyMultiColorIdDisplay').innerText = id; + function populateMultiColorModifyForm(global_id, colors, text) { + document.getElementById('modifyMultiColorGlobalIdInput').value = global_id; + document.getElementById('modifyMultiColorGlobalIdDisplay').innerText = global_id; document.getElementById('modifyMultiColorColorInput').value = colors; document.getElementById('modifyMultiColorTextInput').value = text; document.getElementById('modify-multicolor-modal').style.display = "block"; @@ -389,11 +389,11 @@ const char index_html[] PROGMEM = R"rawliteral( } function modifyMultiColorText() { - const id = document.getElementById('modifyMultiColorIdInput').value; + const global_id = document.getElementById('modifyMultiColorGlobalIdInput').value; const colors = document.getElementById('modifyMultiColorColorInput').value; const text = document.getElementById('modifyMultiColorTextInput').value; - if (!id) { + if (!global_id) { alert('Please enter a node ID.'); return; } @@ -402,7 +402,7 @@ const char index_html[] PROGMEM = R"rawliteral( xhr.open("POST", "/modify-multicolor-text", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - let data = "id=" + id + "&colors=" + encodeURIComponent(colors) + "&text=" + encodeURIComponent(text); + let data = "global_id=" + global_id + "&colors=" + encodeURIComponent(colors) + "&text=" + encodeURIComponent(text); xhr.onload = function() { if (xhr.status === 200) { fetchNodes(); diff --git a/ledy.ino b/ledy.ino index 7228979..7828a1c 100644 --- a/ledy.ino +++ b/ledy.ino @@ -18,15 +18,18 @@ Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); TextNode text_nodes[MAX_TEXT_NODES_COUNT]; MultiColorTextNode multi_color_text_node[MAX_TEXT_NODES_COUNT]; Cursor cursor; -unsigned char ever_created_text_nodes = 0; -unsigned char ever_created_multi_color_text_nodes = 0; +unsigned char global_node_id = 0; + +bool main_animation_started = false; +unsigned char bottom_text_state = 0; // 0 = "Technik informatyk", 1 = "technik programista" +unsigned char scroll_node_global_id = 0; // tracks current bottom-row node +bool scroll_node_active = false; Image saved_images[MAX_IMAGES_SAVED] = { {},{} }; - short getTextNodeY2(TextNode *node) { return node->pos_y + node->characterSize.height - 1; @@ -38,14 +41,14 @@ short getTextNodeX2(TextNode *node) return node->pos_x + (node->characterSize.width * node->character_count) + (node->character_count - 1) - 1; } -void addNewTextNode +TextNode* addNewTextNode ( char text[TEXT_MAX_LENGTH + 1], uint32_t color, bool handle_pos_via_cursor, short pos_x, short pos_y, unsigned char scroll_slowness, bool is_scrolling, bool is_small, short disappear_time, bool is_repeating ) { unsigned char text_length = strlen(text); - if (text_length == 0){return;} + if (text_length == 0){return nullptr;} for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++) { if (text_nodes[i].disappear_time == 0) @@ -71,23 +74,24 @@ 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++; + text_nodes[i].global_id = global_node_id; + global_node_id++; if (handle_pos_via_cursor) { cursor.x += (text_nodes[i].characterSize.width + 1) * text_length; } - break; + return &text_nodes[i]; } } + return nullptr; } -void modifyTextNodeById(unsigned char id, uint32_t new_color, char new_text[TEXT_MAX_LENGTH + 1], unsigned char new_slowness) +void modifyTextNodeByGlobalId(unsigned char global_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) + if (text_nodes[i].global_id == global_id && text_nodes[i].disappear_time != 0) { text_nodes[i].color = new_color; strncpy(text_nodes[i].content, new_text, TEXT_MAX_LENGTH); @@ -98,11 +102,11 @@ void modifyTextNodeById(unsigned char id, uint32_t new_color, char new_text[TEXT } } -void modifyMultiColorTextNodeById(unsigned char id, char new_text[TEXT_MAX_LENGTH + 1], RGBWithIndex new_colors[4], unsigned char new_color_count) +void modifyMultiColorTextNodeByGlobalId(unsigned char global_id, char new_text[TEXT_MAX_LENGTH + 1], RGBWithIndex new_colors[4], unsigned char new_color_count) { for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++) { - if (multi_color_text_node[i].id == id && multi_color_text_node[i].disappear_time != 0) + if (multi_color_text_node[i].global_id == global_id && multi_color_text_node[i].disappear_time != 0) { strncpy(multi_color_text_node[i].content, new_text, TEXT_MAX_LENGTH); multi_color_text_node[i].character_count = strlen(new_text); @@ -184,14 +188,14 @@ void scrollAllScrollableTexts(bool split_scroll_mode = false) } } -void addNewMultiColor +MultiColorTextNode* addNewMultiColor ( char text[TEXT_MAX_LENGTH + 1], RGBWithIndex colors[4], unsigned char color_count, bool handle_pos_via_cursor, short pos_x, short pos_y, unsigned char scroll_slowness, bool is_scrolling, bool is_small, short disappear_time, bool is_repeating ) { unsigned char text_length = strlen(text); - if (text_length == 0){return;} + if (text_length == 0){return nullptr;} for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++) { if (multi_color_text_node[i].disappear_time == 0) @@ -221,16 +225,17 @@ 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++; + multi_color_text_node[i].global_id = global_node_id; + global_node_id++; if (handle_pos_via_cursor) { cursor.x += (multi_color_text_node[i].characterSize.width + 1) * text_length; } - break; + return &multi_color_text_node[i]; } } + return nullptr; } short getMultiColorTextNodeX2(MultiColorTextNode *node) @@ -363,6 +368,27 @@ void handleMultiColorDisappearTimers() } } +bool isNodeExistingByGlobal(unsigned char global_id) +{ + for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++) + { + if (text_nodes[i].global_id == global_id && text_nodes[i].disappear_time != 0) + { + return true; + } + if (multi_color_text_node[i].global_id == global_id && multi_color_text_node[i].disappear_time != 0) + { + return true; + } + } + return false; +} + +void resetGlobalIdToAfterIntroValue() +{ + global_node_id = 2; +} + void setup() { Serial.begin(115200); @@ -371,21 +397,61 @@ void setup() pixels.begin(); pixels.clear(); - addNewTextNode("NET", 0xFF050505, false, 0, 0, 1, true, true, 100); - addNewTextNode("AWAIT", 0xFF050505, false, 0, 9, 1, true, true, 100); + addNewTextNode("NO", 0xFF050505, false, 0, 0, 1, true, true); + addNewTextNode("INTERNET", 0xFF050505, false, 0, 9, 1, true, true); + scrollAllScrollableTexts(true); pixels.show(); start_server(); } void loop() { + if (!main_animation_started) + { + if (!isNodeExistingByGlobal(0) && !isNodeExistingByGlobal(1)) + { + main_animation_started = true; + + // Top row: "Witamy w PTI" — slow scroll, repeating, white + blue PTI + addNewMultiColor("Witamy w PTI", + (RGBWithIndex[4]){ + {40, 40, 40, 0}, // white (dimmed) from char 0 + {0, 0, 50, 9} // blue (dimmed) from char 9 ("PTI") + }, 2, false, 0, 0, 3, true, true, -1, true); + } + } + + // Bottom row: alternating scrolling texts + if (main_animation_started && + (!scroll_node_active || !isNodeExistingByGlobal(scroll_node_global_id))) + { + TextNode* node = nullptr; + if (bottom_text_state == 0) + { + node = addNewTextNode("Technik informatyk", + pixels.Color(0, 0, 50), // blue (dimmed) + false, DISPLAY_MAX_X, 9, 1, true, true, -1, false); + } + else + { + node = addNewTextNode("technik programista", + pixels.Color(50, 40, 0), // gold (dimmed) + false, DISPLAY_MAX_X, 9, 1, true, true, -1, false); + } + if (node != nullptr) + { + scroll_node_global_id = node->global_id; + scroll_node_active = true; + bottom_text_state = (bottom_text_state + 1) % 2; + } + } + pixels.clear(); handle_server(); handleDisappearTimers(); handleMultiColorDisappearTimers(); - scrollAllScrollableTexts(); - scrollAllMultiColorTexts(); - + scrollAllScrollableTexts(true); + scrollAllMultiColorTexts(true); pixels.show(); } \ No newline at end of file diff --git a/prototypes.h b/prototypes.h index 9ca92a1..c82b37e 100644 --- a/prototypes.h +++ b/prototypes.h @@ -16,9 +16,9 @@ void drawImageFromMemoryByIndex(unsigned char image_index, short pos_x, short po void setPixel(short x, short y, uint32_t color); void start_server(); void handle_server(); -void addNewTextNode(char text[TEXT_MAX_LENGTH + 1], uint32_t color, bool handle_pos_via_cursor, short pos_x, short pos_y, unsigned char scroll_slowness, bool is_scrolling, bool is_small, short disappear_time, bool is_repeating = false); +TextNode* addNewTextNode(char text[TEXT_MAX_LENGTH + 1], uint32_t color, bool handle_pos_via_cursor, short pos_x, short pos_y, unsigned char scroll_slowness, bool is_scrolling, bool is_small, short disappear_time = -1, bool is_repeating = false); void scrollAllScrollableTexts(bool split_scroll_mode); -void addNewMultiColor(char text[TEXT_MAX_LENGTH + 1], RGBWithIndex colors[4], unsigned char color_count, bool handle_pos_via_cursor, short pos_x, short pos_y, unsigned char scroll_slowness, bool is_scrolling, bool is_small, short disappear_time, bool is_repeating = false); +MultiColorTextNode* addNewMultiColor(char text[TEXT_MAX_LENGTH + 1], RGBWithIndex colors[4], unsigned char color_count, bool handle_pos_via_cursor, short pos_x, short pos_y, unsigned char scroll_slowness, bool is_scrolling, bool is_small, short disappear_time = -1, bool is_repeating = false); void scrollAllMultiColorTexts(bool split_scroll_mode); void drawCharacter(const bool (*character)[5], unsigned char height, unsigned char width, uint32_t color, Cursor (*used_cursor)); void handleDisappearTimers(); @@ -26,8 +26,9 @@ 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); -void modifyMultiColorTextNodeById(unsigned char id, char new_text[TEXT_MAX_LENGTH + 1], RGBWithIndex new_colors[4], unsigned char new_color_count); +void modifyTextNodeByGlobalId(unsigned char global_id, uint32_t new_color, char new_text[TEXT_MAX_LENGTH + 1], unsigned char new_slowness); +void modifyMultiColorTextNodeByGlobalId(unsigned char global_id, char new_text[TEXT_MAX_LENGTH + 1], RGBWithIndex new_colors[4], unsigned char new_color_count); +bool isNodeExistingByGlobal(unsigned char global_id); diff --git a/server.ino b/server.ino index 126d39c..3688096 100644 --- a/server.ino +++ b/server.ino @@ -221,16 +221,16 @@ void handleMulticolorText() { void handleModifyText() { - if (server.hasArg("id") && server.hasArg("color")) + if (server.hasArg("global_id") && server.hasArg("color")) { - unsigned char id = server.arg("id").toInt(); + unsigned char global_id = server.arg("global_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); + modifyTextNodeByGlobalId(global_id, color, text, slowness); server.send(200, "text/plain", "OK"); } else @@ -241,9 +241,9 @@ void handleMulticolorText() { void handleModifyMultiColorText() { - if (server.hasArg("id") && server.hasArg("colors") && server.hasArg("text")) + if (server.hasArg("global_id") && server.hasArg("colors") && server.hasArg("text")) { - unsigned char id = server.arg("id").toInt(); + unsigned char global_id = server.arg("global_id").toInt(); String colors_str = server.arg("colors"); String text_str = server.arg("text"); char text[TEXT_MAX_LENGTH + 1]; @@ -285,7 +285,7 @@ void handleMulticolorText() { } } - modifyMultiColorTextNodeById(id, text, colors, color_count); + modifyMultiColorTextNodeByGlobalId(global_id, text, colors, color_count); server.send(200, "text/plain", "OK"); } else @@ -304,7 +304,8 @@ void handleMulticolorText() { if (text_nodes[i].disappear_time != 0) { JsonObject node = nodes.createNestedObject(); - node["id"] = text_nodes[i].id; node["text"] = text_nodes[i].content; + node["global_id"] = text_nodes[i].global_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; @@ -319,7 +320,8 @@ void handleMulticolorText() { 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; + node["global_id"] = multi_color_text_node[i].global_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++) { @@ -344,9 +346,11 @@ void handleMulticolorText() { void start_server() { WiFi.begin(ssid, password); - while (WiFi.status() != WL_CONNECTED) { - delay(1000); - Serial.println("Connecting to WiFi..."); + while (WiFi.status() != WL_CONNECTED) { + pixels.clear(); + scrollAllScrollableTexts(true); + pixels.show(); + delay(50); } Serial.println("Connected to WiFi"); Serial.println(WiFi.localIP()); diff --git a/structs.h b/structs.h index 8b3ec6b..597137f 100644 --- a/structs.h +++ b/structs.h @@ -20,7 +20,7 @@ struct Pixel struct TextNode { - unsigned char id; + unsigned char global_id; char content[TEXT_MAX_LENGTH]; uint32_t color; struct CharacterSize @@ -38,7 +38,7 @@ struct TextNode bool is_repeating; - 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) {} + TextNode() : global_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 @@ -63,7 +63,7 @@ struct RGBWithIndex struct MultiColorTextNode { - unsigned char id; + unsigned char global_id; char content[TEXT_MAX_LENGTH]; RGBWithIndex colors[4]; @@ -82,7 +82,7 @@ struct MultiColorTextNode bool is_scrolling; bool is_repeating; - 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) {} + MultiColorTextNode() : global_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 diff --git a/upload_page.h b/upload_page.h index 29cb2b0..754b0bb 100644 --- a/upload_page.h +++ b/upload_page.h @@ -1,4 +1,3 @@ - #ifndef UPLOAD_PAGE_H #define UPLOAD_PAGE_H