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(
×
@@ -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