#pragma once #include "font.h" enum TB_MODES { TB_DISABLED = 0, TB_STATIC, TB_REPEAT, TB_LOOP, TB_LOOP_WITH_DELAY, TB_BOUNCE, }; class textbox { private: /* data */ uint8_t cord_x; uint8_t cord_y; uint8_t w; uint8_t mode; uint16_t speed; uint16_t delay; int16_t offset; bool direction; bool state; mData color; char text[64]; uint8_t textlen; uint16_t textwidth; uint8_t letter[8]; uint64_t langMask; bool native; void getLetter(uint8_t i, bool skipBitmap = 0); uint32_t timer0; public: textbox(void); void setup(char _text[], uint64_t _langMask, mData _color, uint8_t _mode, uint8_t _x, uint8_t _y, uint8_t _w, uint8_t _reciprocal_speed = 0, uint16_t _delay = 0); uint8_t render(void); void disable(void); void changeCords(uint8_t newx, uint8_t newy); void resetTimers(void); }; textbox::textbox(void) { cord_x = 0; cord_y = 0; w = 0; mode = 0; speed = 0; delay = 0; memset(text, '\0', 64 * sizeof(char)); langMask = 0; // If 96th symbol is font_null there is no native language except for English native = pgm_read_byte(font[96]) != 0; } void textbox::setup(char _text[], uint64_t _langMask, mData _color, uint8_t _mode, uint8_t _x, uint8_t _y, uint8_t _w, uint8_t _reciprocal_speed = 0, uint16_t _delay = 0) { // Copy string memset(text, '\0', 64 * sizeof(char)); strcpy(text, _text); // Calculating width textlen = strlen(text); langMask = _langMask; textwidth = 0; for (uint16_t i = 0; i < textlen; i++) { getLetter(i, true); textwidth += letter[0] + 1; } textwidth--; // Defining other vars color = _color; mode = _mode; cord_x = _x; cord_y = _y; w = _w; offset = 0; switch (mode) { case TB_LOOP: delay = 0; goto NO_DELAY; case TB_REPEAT: case TB_LOOP_WITH_DELAY: case TB_BOUNCE: delay = _delay; NO_DELAY: speed = _reciprocal_speed; break; case TB_DISABLED: case TB_STATIC: default: speed = 0; delay = 0; break; } // Reset timer and render timer0 = 0; render(); } uint8_t textbox::render(void) { uint8_t r = 1; // Return 1 if rendered, 2 if rendered with new cycle if (mode != TB_DISABLED) { // If static or kickstart if (timer0 == 0 || mode == TB_STATIC) { offset = 0 + (mode == TB_REPEAT) * w + 1 * (mode == TB_LOOP); direction = 0; timer0 = millis(); } else { if ((millis() - timer0) > (((mode != TB_LOOP) && !state) ? delay : speed)) { state = 1; timer0 = millis(); if (mode == TB_BOUNCE) { if ((!direction && offset == -textwidth + w) || (direction && offset == 0)) { r = direction + 1; direction = !direction; state = 0; } else offset += direction ? 1 : -1; } else { offset += -1; if (offset < ((int16_t)-textwidth - 2 * (mode == TB_LOOP || mode == TB_LOOP_WITH_DELAY) - w * (mode == TB_REPEAT))) { offset = 0 + (mode == TB_REPEAT) * w; state = 0; r = 2; } } } else // Draw if kickstart if(state != 0) return 0; } } // Do nothing if disabled else return 0; // Clear spot for (uint8_t i = cord_x; (i < cord_x + w) && (i < WIDTH); i++) for (uint8_t j = cord_y; (j < cord_y + 7) && (j < HEIGHT); j++) matrix.set(i, j, mBlack); // Init letter counter, start X and Y uint8_t index = 0; int16_t positionX = cord_x + offset; int16_t positionY = cord_y; // Draw while in bounds while ((positionX < cord_x + w) && (index < textlen)) { // Recieve letter getLetter(index); // Relative X and Y uint8_t x = 0; uint8_t y = letter[1]; // X bound uint8_t maxX = letter[0]; // Run thougth bytes for (uint8_t i = 0; (i < letter[2]) && (y < 7); i++) { // Run througth bits for (int8_t j = 7; (j >= 0) && (y < 7); j--) { // Set pixel bool state = bitRead(letter[i + 3], j); int16_t mx = x + positionX; int16_t my = HEIGHT - 1 - y - positionY; if (state && mx >= cord_x && mx < cord_x + w && my >= cord_y && my < cord_y + 7) matrix.set(mx, my, color); // Next pixel x++; if (x >= maxX) { x = 0; y++; } } } // Shift X and index positionX += maxX + 1; index++; // Make a loop if((mode == TB_LOOP || mode == TB_LOOP_WITH_DELAY) && index == textlen) { positionX++; index = 0; } } return r; } void textbox::disable(void) { setup("", 0, 0, TB_DISABLED, 0, 0, 0); } void textbox::getLetter(uint8_t i, bool skipBitmap = 0) { // Letter and it's position in ASCII table char c = text[i]; uint8_t ctoi = (uint8_t)c; // Language (0 - English, 1 - Native) bool lang = bitRead(langMask, i); // Clear place for letter in RAM memset(letter, 0, 8 * sizeof(uint8_t)); uint8_t index; // Translate ASCII index to local if (ctoi >= 32 && ctoi <= 126) index = ctoi - 31 + 95 * lang * native; else index = 0; // Read properties from semeric number uint8_t readed = pgm_read_byte(font[index]); letter[0] = readed / 49 + 1; // width letter[1] = readed % 7; // offset letter[2] = readed / 7 % 7; // bytes // Read bitmaps if (!skipBitmap) for (uint8_t i = 0; i < letter[2]; i++) letter[i + 3] = pgm_read_byte(font[index] + (i + 1) * sizeof(uint8_t)); } void textbox::changeCords(uint8_t newx, uint8_t newy) { cord_x = newx; cord_y = newy; } void textbox::resetTimers(void) { timer0 = 0; }