ESPboy_Sub1GHzInspector/ESPboyTerminalGUI.cpp
2020-10-28 09:10:56 +03:00

339 lines
11 KiB
C++

/*
ESPboyTerminalGUI class
for www.ESPboy.com project by RomanS
https://hackaday.io/project/164830-espboy-games-iot-stem-for-education-fun
v2.1
*/
#include "ESPboyTerminalGUI.h"
#define SOUNDPIN D3
const uint8_t ESPboyTerminalGUI::keybOnscr[2][3][21] PROGMEM = {
{"+1234567890abcdefghi", "jklmnopqrstuvwxyz -=", "?!@$%&*()_[]\":;.,^<E",},
{"+1234567890ABCDEFGHI", "JKLMNOPQRSTUVWXYZ -=", "?!@$%&*()_[]\":;.,^<E",}
};
ESPboyTerminalGUI::ESPboyTerminalGUI(TFT_eSPI *tftGUI, Adafruit_MCP23017 *mcpGUI) {
keybParam.renderLine = 0;
keybParam.displayMode = 0;
keybParam.shiftOn = 0;
keybParam.selX = 0;
keybParam.selY = 0;
keybParam.typing = "";
tft = tftGUI;
mcp = mcpGUI;
#ifdef U8g2
u8f = new U8g2_for_TFT_eSPI;
u8f->begin(*tft);
u8f->setFontMode(1); // use u8g2 none transparent mode
u8f->setBackgroundColor(TFT_BLACK);
u8f->setFontDirection(0); // left to right
u8f->setFont(u8g2_font_4x6_t_cyrillic);
#endif
consoleStringsVector.push_back(consoleStringS());
consoleStringsVector.back().consoleString = "";
consoleStringsVector.back().consoleStringColor = TFT_BLACK;
toggleDisplayMode(1);
}
uint8_t ESPboyTerminalGUI::keysAction() {
uint8_t longActPress = 0;
uint8_t keyState = getKeys();
if (keyState) {
#ifdef buttonclicks
tone(SOUNDPIN, 100, 10);
#endif
if (!keybParam.displayMode) {
if (keyState & GUI_PAD_LEFT && keyState & GUI_PAD_UP) { // shift
keybParam.shiftOn = !keybParam.shiftOn;
drawKeyboard(keybParam.selX, keybParam.selY, 0);
waitKeyUnpressed();
} else {
if ((keyState & GUI_PAD_RIGHT) && keybParam.selX < 20) keybParam.selX++;
if ((keyState & GUI_PAD_LEFT) && keybParam.selX > -1) keybParam.selX--;
if ((keyState & GUI_PAD_DOWN) && keybParam.selY < 3) keybParam.selY++;
if ((keyState & GUI_PAD_UP) && keybParam.selY > -1) keybParam.selY--;
if ((keyState & GUI_PAD_LEFT) && keybParam.selX == -1) keybParam.selX = 19;
if ((keyState & GUI_PAD_RIGHT) && keybParam.selX == 20) keybParam.selX = 0;
if ((keyState & GUI_PAD_UP) && keybParam.selY == -1) keybParam.selY = 2;
if ((keyState & GUI_PAD_DOWN) && keybParam.selY == 3) keybParam.selY = 0;
}
if ((keyState&GUI_PAD_ACT && keyState&GUI_PAD_ESC) || (keyState&GUI_PAD_RGT && keyState&GUI_PAD_LFT)) {
if (keybParam.renderLine > consoleStringsVector.size() - GUI_MAX_STRINGS_ONSCREEN_FULL)
keybParam.renderLine = consoleStringsVector.size() - GUI_MAX_STRINGS_ONSCREEN_FULL;
toggleDisplayMode(1);
waitKeyUnpressed();
} else if (keyState&GUI_PAD_RGT && keybParam.renderLine) {
keybParam.renderLine--;
drawConsole(0);
} else if (keyState&GUI_PAD_LFT && keybParam.renderLine < consoleStringsVector.size() - GUI_MAX_STRINGS_ONSCREEN_SMALL) {
keybParam.renderLine++;
drawConsole(0);
}
if ((((keyState & GUI_PAD_ACT) && (keybParam.selX == 19 && keybParam.selY == 2)) || (keyState & GUI_PAD_RGT && keyState & GUI_PAD_LFT))) { // enter
if (keybParam.typing.length() > 0) longActPress = 1;
} else if ((keyState & GUI_PAD_ACT) && (keybParam.selX == 18 && keybParam.selY == 2)) { // back space
if (keybParam.typing.length() > 0) keybParam.typing.remove(keybParam.typing.length() - 1);
} else if ((keyState & GUI_PAD_ACT) && (keybParam.selX == 17 && keybParam.selY == 1)) { // SPACE
if (keybParam.typing.length() < GUI_MAX_TYPING_CHARS) keybParam.typing += " ";
} else if ((keyState & GUI_PAD_ACT) && (keybParam.selX == 17 && keybParam.selY == 2)) {
keybParam.shiftOn = !keybParam.shiftOn;
drawKeyboard(keybParam.selX, keybParam.selY, 0);
waitKeyUnpressed();
} else if (keyState & GUI_PAD_ACT){
if (waitKeyUnpressed() > GUI_KEY_PRESSED_DELAY_TO_SEND)
longActPress = 1;
else if (keybParam.typing.length() < GUI_MAX_TYPING_CHARS)
keybParam.typing += (char)pgm_read_byte(&keybOnscr[keybParam.shiftOn][keybParam.selY][keybParam.selX]);
}
if (keyState & GUI_PAD_ESC) {
if (waitKeyUnpressed() > GUI_KEY_PRESSED_DELAY_TO_SEND)
keybParam.typing = "";
else if (keybParam.typing.length() > 0)
keybParam.typing.remove(keybParam.typing.length() - 1);
}
}
else {
if ((keyState & GUI_PAD_ACT && keyState & GUI_PAD_ESC) || (keyState & GUI_PAD_RGT && keyState & GUI_PAD_LFT)) {
toggleDisplayMode(0);
waitKeyUnpressed();
} else
if (((keyState & GUI_PAD_RGT || keyState & GUI_PAD_RIGHT || keyState & GUI_PAD_DOWN)) && keybParam.renderLine > 0) {
keybParam.renderLine--;
drawConsole(0);
} else
if (((keyState&GUI_PAD_LFT || keyState & GUI_PAD_LEFT || keyState&GUI_PAD_UP)) && keybParam.renderLine < consoleStringsVector.size() - GUI_MAX_STRINGS_ONSCREEN_FULL) {
keybParam.renderLine++;
drawConsole(0);
} else
if (keyState & GUI_PAD_ESC)
toggleDisplayMode(0);
}
if (!keybParam.displayMode) drawKeyboard(keybParam.selX, keybParam.selY, 1);
}
if (!keybParam.displayMode) drawBlinkingCursor();
return (longActPress);
}
void ESPboyTerminalGUI::toggleDisplayMode(uint8_t mode) {
keybParam.displayMode = mode;
tft->fillScreen(TFT_BLACK);
tft->drawRect(0, 0, 128, 128, TFT_NAVY);
if (!keybParam.displayMode) {
tft->drawRect(0, 128 - 3 * 8 - 5, 128, 3 * 8 + 5, TFT_NAVY);
tft->drawRect(0, 0, 128, 86, TFT_NAVY);
}
if (!keybParam.displayMode) {
drawKeyboard(keybParam.selX, keybParam.selY, 0);
}
drawConsole(0);
}
String ESPboyTerminalGUI::getUserInput() {
String userInput;
toggleDisplayMode(0);
while (1) {
while (!keysAction()) delay(GUI_KEYB_CALL_DELAY);
if (keybParam.typing != "") break;
}
toggleDisplayMode(1);
userInput = keybParam.typing;
keybParam.typing = "";
return (userInput);
}
void ESPboyTerminalGUI::doScroll(){
uint8_t keyState=0;
#ifdef buttonclicks
tone(SOUNDPIN, 100, 10);
#endif
toggleDisplayMode(1);
while (!(keyState & GUI_PAD_ESC)){
delay(1);
keyState = getKeys();
if(keyState){
if (keyState&GUI_PAD_RGT && keybParam.renderLine) {
keybParam.renderLine--;}
if (keyState&GUI_PAD_LFT && keybParam.renderLine < consoleStringsVector.size() - GUI_MAX_STRINGS_ONSCREEN_SMALL) {
keybParam.renderLine++;}
drawConsole(0);
#ifdef buttonclicks
tone(SOUNDPIN, 100, 10);
#endif
delay(GUI_KEYB_CALL_DELAY);
}
}
}
void ESPboyTerminalGUI::printConsole(String bfrstr, uint16_t color, uint8_t ln, uint8_t noAddLine) {
String toprint;
keybParam.renderLine = 0;
if(bfrstr == "") bfrstr = " ";
if (!ln)
if (bfrstr.length() > ((128-4)/GUI_FONT_WIDTH)) {
bfrstr = bfrstr.substring(0, ((128-4)/GUI_FONT_WIDTH));
toprint = bfrstr;
}
for (uint8_t i = 0; i <= ((bfrstr.length()-1) / ((128-4)/GUI_FONT_WIDTH)); i++) {
toprint = bfrstr.substring(i * (128-4)/GUI_FONT_WIDTH);
toprint = toprint.substring(0, (128-4)/GUI_FONT_WIDTH);
if (!noAddLine) consoleStringsVector.push_back(consoleStringS());
consoleStringsVector.back().consoleString = toprint;
consoleStringsVector.back().consoleStringColor = color;
}
drawConsole(noAddLine);
if (consoleStringsVector.size() > GUI_MAX_CONSOLE_STRINGS){
consoleStringsVector.erase(consoleStringsVector.begin());
consoleStringsVector.shrink_to_fit();
}
}
void ESPboyTerminalGUI::drawConsole(uint8_t onlyLastLine) {
uint16_t lines;
uint16_t offsetY;
uint16_t quantityLinesToDraw;
int16_t startVectorToDraw;
if (keybParam.displayMode) lines = GUI_MAX_STRINGS_ONSCREEN_FULL;
else lines = GUI_MAX_STRINGS_ONSCREEN_SMALL;
#ifndef U8g2
if (!onlyLastLine) tft->fillRect(1, 4, 126, lines * GUI_FONT_HEIGHT, TFT_BLACK);
else tft->fillRect(1, (lines-1) * GUI_FONT_HEIGHT+4, 126, GUI_FONT_HEIGHT, TFT_BLACK);
#else
if (!onlyLastLine) tft->fillRect(1, 1, 126, lines * GUI_FONT_HEIGHT, TFT_BLACK);
else tft->fillRect(1, (lines-1) * GUI_FONT_HEIGHT, 126, GUI_FONT_HEIGHT+1, TFT_BLACK);
#endif
#ifndef U8g2
offsetY = lines * GUI_FONT_HEIGHT - 4;
#else
offsetY = lines * GUI_FONT_HEIGHT;
#endif
if(consoleStringsVector.size() < lines ) quantityLinesToDraw = consoleStringsVector.size();
else quantityLinesToDraw = lines;
startVectorToDraw = consoleStringsVector.size()-1-keybParam.renderLine;
for (uint8_t i = 0; i< quantityLinesToDraw; i++) {
#ifndef U8g2
tft->setTextColor(consoleStringsVector[startVectorToDraw].consoleStringColor, TFT_BLACK);
tft->drawString(consoleStringsVector[startVectorToDraw].consoleString, 3, offsetY);
#else
u8f->setForegroundColor(consoleStringsVector[startVectorToDraw].consoleStringColor);
u8f->drawStr(2, offsetY, consoleStringsVector[startVectorToDraw].consoleString.c_str());
#endif
offsetY -= GUI_FONT_HEIGHT;
startVectorToDraw--;
if(startVectorToDraw<0) startVectorToDraw=0;
}
}
uint8_t ESPboyTerminalGUI::getKeys() { return (~mcp->readGPIOAB() & 255); }
uint32_t ESPboyTerminalGUI::waitKeyUnpressed() {
uint32_t timerStamp = millis();
while (getKeys() && (millis() - timerStamp) < GUI_KEY_UNPRESSED_TIMEOUT) delay(1);
return (millis() - timerStamp);
}
void ESPboyTerminalGUI::drawKeyboard(uint8_t slX, uint8_t slY, uint8_t onlySelected) {
static char chr[2]={0,0};
static uint8_t prevX = 0, prevY = 0;
if (!onlySelected) {
tft->fillRect(1, 128 - 24, 126, 23, TFT_BLACK);
tft->setTextColor(TFT_YELLOW, TFT_BLACK);
for (uint8_t j = 0; j < 3; j++)
for (uint8_t i = 0; i < 20; i++) {
chr[0] = pgm_read_byte(&keybOnscr[keybParam.shiftOn][j][i]);
tft->drawString(&chr[0], i * 6 + 4, 128 - 2 - 8 * (3 - j));
}
}
tft->setTextColor(TFT_YELLOW, TFT_BLACK);
chr[0] = pgm_read_byte(&keybOnscr[keybParam.shiftOn][prevY][prevX]);
tft->drawString(&chr[0], prevX * 6 + 4, 128 - 24 + prevY * 8 - 2);
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->drawString("^<E", 6 * 17 + 4, 128 - 24 + 2 * 8 - 2);
tft->setTextColor(TFT_YELLOW, TFT_RED);
chr[0] = pgm_read_byte(&keybOnscr[keybParam.shiftOn][slY][slX]);
tft->drawString(&chr[0], slX * 6 + 4, 128 - 24 + slY * 8 - 2);
prevX = slX;
prevY = slY;
drawTyping(0);
}
void ESPboyTerminalGUI::drawTyping(uint8_t changeCursor) {
static char cursorType[2] = {220, '_'};
static uint8_t cursorTypeFlag=0;
if(changeCursor) cursorTypeFlag=!cursorTypeFlag;
tft->fillRect(1, 128 - 5 * 8, 126, 10, TFT_BLACK);
if (keybParam.typing.length() < 20) {
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->drawString(keybParam.typing + cursorType[cursorTypeFlag], 4, 128 - 5 * 8 + 1);
} else {
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->drawString("<" + keybParam.typing.substring(keybParam.typing.length() - 18) +cursorType[cursorTypeFlag], 4, 128 - 5 * 8 + 1);
}
}
void ESPboyTerminalGUI::drawOwnTypingLine(String typingLine, uint16_t colorLine){
keybParam.typing = typingLine;
toggleDisplayMode(0);
keybParam.typing = typingLine;
tft->fillRect(1, 128 - 5 * 8, 126, 10, TFT_BLACK);
tft->setTextColor(colorLine, TFT_BLACK);
tft->drawString(keybParam.typing, 4, 128 - 5 * 8 + 1);
}
void ESPboyTerminalGUI::drawBlinkingCursor() {
static uint32_t cursorBlinkMillis = 0;
if (millis() > (cursorBlinkMillis + GUI_CURSOR_BLINKING_PERIOD)) {
cursorBlinkMillis = millis();
drawTyping(1);
}
}
void ESPboyTerminalGUI::SetKeybParamTyping(String str){
keybParam.typing = str;
}