0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

71歳の... 「ESP32-S3」、「800*480TFTモジュール」で初のエディター作成

Posted at

 エディター作成に初挑戦です。元ネタはここ。
https://github.com/VolosR/KeyboardMF/blob/main/KeyboardMF/KeyboardMF.ino

前回紹介した開発ボード

上に作成しました。元ネタに手を加え、次のようにしました。

1.1024*600解像度を800*480に変更
2.UsbHost機能が使えないため「Tera Term」からのキー入力に
3.Dir(Ls)表示、エディタ画面が1画面固定だったのを、複数画面、スクロール可能に
4.キー機能の追加

これだけでも500行になってしまいました。さらに機能を加えたかったのですが、Qiitaでの投稿はかなり重くなるのでここまでかなと。ino本体が長いのでここまでとします。次がスケッチ本体です。前回の投稿にありますが「Matouch7.h」をスケッチと同じフォルダーに入れコンパイルしてください。詳しくはそちらを。ご利用は、計画的に。

070_KeyboardMF.ino
#include "Matouch7.h"
#include "SD.h"
#include <string>

#define SW 800
#define SH 480
#define TFT_BL 2
#define _LH 22
// microSD card standard connect
#define SPI_MOSI 11
#define SPI_MISO 13
#define SPI_SCK 12
#define SD_CS 10

LGFX lcd; // to use this including "Matouch7.h"
LGFX_Sprite spr0(&lcd);
LGFX_Sprite spr1(&lcd);
LGFX_Sprite spr2(&lcd);
LGFX_Sprite spr3(&lcd);
#define YELW TFT_YELLOW
#define NAVY 0x0008
#define fnLs 20      // display rows at dir files
#define maxLines 18  //20
String fileName = "*.txt, *.c, *.cpp";
String txt[100];
String spc[100];
uint8_t cuX[100];
uint8_t lineCount = 0;
bool mode = 0;  // 0 is edit fileName, 1 is edit content
bool openMenu = false;
unsigned short modeColor[2] = { TFT_PURPLE, TFT_SILVER };
bool _drawLine = true;  // displaying cursor in line or not
uint8_t line = 0;       // present edit-line
uint8_t lastline = 0;   // content lines
uint8_t lb = 0;         // scroll base line

#define maxFiles 128         // Define maximum number of files to store
String fileNames[maxFiles];  // Array to store file names
uint8_t filesCount = 0;
uint8_t chosenFile = 0;
uint8_t fListPage = 0;

void resetAll() {
  fileName = "*.*";
  dispCurFname(fileName);
  lcd.fillRect(2, 27, SW - 4, SH - 28, TFT_BLACK);
  clearTexts();
}

void clearTexts() {
  line = 0;
  lastline = 2;  // 2
  lb = 0;
  for (uint8_t i = 0; i < 100; i++) {
    txt[i] = "";
    spc[i] = '|';
    cuX[i] = 0;
  }
}

void listFilesInArray(const char* dirname) {
  File root = SD.open(dirname);
  filesCount = 0;
  if (!root || !root.isDirectory()) {
    Serial.println("Failed to open directory or not a directory");
    return;
  }

  File file = root.openNextFile();
  while (file) {  // Store the file name in the array
    if (filesCount < maxFiles) {
      String fn = file.name();
      fn.toLowerCase();
      if (file.isDirectory()) fn = fn + '/';
      fileNames[filesCount] = fn;
      filesCount++;  // Increment file counter
    }
    file = root.openNextFile();  // Move to the next file
  }
}

void setup(void) {
  clearTexts();
  Serial.begin(115200);
  Serial.println("Serial begin");

  analogWrite(2, 210);  // LCD on
  lcd.begin();
  lcd.setRotation(0);
  lcd.fillScreen(0x0010);
  lcd.fillRect(1, 26, SW - 2, SH - 26, 0x222222U);

  lcd.setFont(&fonts::FreeMonoBold9pt7b);   //AsciiFont8x16);
  spr1.setFont(&fonts::FreeMonoBold9pt7b);  //AsciiFont8x16);
  spr0.setFont(&fonts::FreeMonoBold9pt7b);  //AsciiFont8x16);

  lcd.setTextColor(YELW);
  lcd.drawString("FILE:", 8, 5);
  FKey("F1", " DIR", 305, 1);
  FKey("F2", " NEW", 405, 1);
  FKey("F3", "Fi/Ed", 505, 1);
  FKey("F4", "SAVE", 605, 1);
  FKey("F5", "HELP", 705, 1);

  spr0.setColorDepth(1);
  spr0.createSprite(228, 22);  // filename editbox
  spr1.setColorDepth(4);       // 16 colors pallet
  spr1.createSprite(SW - 4, _LH);
  spr1.setPaletteColor(2, TFT_LIGHTGRAY);  // focused line background
  spr1.setPaletteColor(3, TFT_MAGENTA);    // cursor color
  spr1.setPaletteColor(4, 0x00FF00U);      // text color is GREEN
  spr2.createSprite(SW - 4, _LH);
  spr3.createSprite(SW - 4, 2 * _LH);
  fileName = " *.txt ; *.c ; *.cpp";
  dispCurFname(fileName);

  if (!SD.begin(SD_CS, SPI, 48000000, "/sd")) {
    Serial.println("Card Mount Failed");
    return;
  }
  SD_Info();
}

void loop(void) {

  if (mode == 0) {
    lcd.drawRect(64, 0, 230, 24, modeColor[0]);
    lcd.drawRect(1, 26, SW - 2, SH - 26, modeColor[1]);
  } else {
    lcd.drawRect(64, 0, 230, 24, modeColor[1]);
    lcd.drawRect(1, 26, SW - 2, SH - 26, modeColor[0]);
  }

  while (Serial.available() == 0) { ; }

  uint8_t intC = Serial.read();
  String intS;
  if (intC < ' ' || intC > '~') {
    intS = (String)intC;
    while (Serial.available()) {
      uint8_t k = Serial.read();
      intS = intS + (String)k;
    }
    Serial.printf("%c ; %s\n\r", intC, intS);

    if (intS.equals("27") || intS.equals("277980")) {  // ESC or F1
      resetAll();
      openMenu = true;        // "Dir /"
      listFilesInArray("/");  // store to fileNames[]
      dispFiles(fListPage);
    }

    if (intS.equals("277981")) {  //F2 New file
      resetAll();
      openMenu = false;  // NEW
      mode = 0;          // edit file name
    }

    if (intS.equals("277982")) {  //F3 switch edit fileneme/content
      mode = !mode;               // toggle filename or content
      lcd.drawRect(64, 0, 230, 24, modeColor[mode]);
      lcd.drawRect(1, 26, SW - 2, SH - 26, modeColor[!mode]);
    }
    /*
    if (uint8_tS.equals("27914957126")) Serial.pruint8_tln("F8");
    if (uint8_tS.equals("27915048126")) Serial.pruint8_tln("F9");
    if (uint8_tS.equals("27915049126")) Serial.pruint8_tln("F10");
    if (uint8_tS.equals("27915051126")) Serial.pruint8_tln("F11");
    if (uint8_tS.equals("27915052126")) Serial.pruint8_tln("F12");
    */
  }

  if (openMenu) {                      // File-Choosing mode
    if (intS.equals("27914953126")) {  //F5 HELP
      lcd.drawRect(64, 0, 230, 24, modeColor[1]);
      lcd.fillRect(1, 26, SW - 2, SH - 26, 0x111111U);
      lcd.setTextColor(TFT_WHITE);
      lcd.drawString("UP  : DIR previous file", 100, 50);
      lcd.drawString("DOWN: DIR next file", 100, 80);
      lcd.drawString("F6  : DIR previous page", 100, 110);
      lcd.drawString("F7  : DIR next page", 100, 140);
      lcd.drawString("ESC : DIR", 100, 170);
    }

    if (intS.equals("27914955126")) {  // F6 previous file list
      if (fListPage > 0) {
        fListPage--;
        chosenFile = fListPage * fnLs;
        dispFiles(fListPage);
        lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
        dispCurFname(fileNames[chosenFile]);
      }
    }

    if (intS.equals("27914956126")) {  // F7 next file list
      if (filesCount > fnLs * (fListPage + 1)) {
        fListPage++;
        chosenFile = fListPage * fnLs;
        dispFiles(fListPage);
        lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
        dispCurFname(fileNames[chosenFile]);
      }
    }

    if (intC == 13) {  // RETURN to choose the file
      resetAll();
      lcd.fillRect(2, 27, SW - 4, SH - 28, TFT_BLACK);
      openMenu = false;
      fileName = fileNames[chosenFile];
      dispCurFname(fileName);
      openFile("/" + fileName);  //String ff = "/" + fileName;
      mode = 1;                  // editing content mode
      drawFep();
    }

    if (intS.equals("279166")) {  // DOWN at file choosing
      if (chosenFile < filesCount - 1) {
        lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, NAVY);
        chosenFile++;
        if ((chosenFile % fnLs) == 0) {
          fListPage++;
          dispFiles(fListPage);
        }
        lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
        dispCurFname(fileNames[chosenFile]);
      }
    }

    if (intS.equals("279165")) {  // UP at file choosing
      if (chosenFile > 0) {
        lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, NAVY);
        chosenFile--;
        if (fListPage > 0 && chosenFile % fnLs == fnLs - 1) {
          fListPage--;
          dispFiles(fListPage);
        }
        lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
        dispCurFname(fileNames[chosenFile]);
      }
    }

  } else {                               // (openmenu == false) content-editing mode
    if (mode == 0) {                     // at editing filename
      if ('!' <= intC && intC <= '~') {  // Ascii chara
        fileName = fileName + String((char)intC);
      }
      if (intC == 8) {  // BS
        fileName = fileName.substring(0, fileName.length() - 1);
      }
      if (intC == 127) {  // DEL
        fileName = "*.txt/*.c/*.cpp";
      }
      dispCurFname(fileName);

    } else {                                  //(mode == 1)         at Editing content textlines
      if (intS.equals("277983")) saveFile();  // F4 Save file

      if (intS.equals("279168")) {  // LEFT
        if (spc[line].length() > 1) {
          cuX[line]--;
          spc[line] = spc[line].substring(1, spc[line].length());
        } else {
          if ((line - lb) > 0) {
            _drawLine = 0;
            drawEditLine(line);
            line--;
            if (lb > 0) {
              lb--;
              for (uint8_t i = 0; i < maxLines; i++) {
                _drawLine = 0;
                drawEditLine(i + lb);
              }
            }
          }
        }
      }

      if (intS.equals("279167")) {  // RIGHT
        if (spc[line].length() <= txt[line].length()) {
          cuX[line]++;
          spc[line] = " " + spc[line];
        } else {  //if(spc[line].length() > txt[line].length())
          if (line < lastline) {
            _drawLine = 0;
            drawEditLine(line);
            line++;
            spc[line] = "|";
            cuX[line] = 0;
            if ((line - lb) >= maxLines) {
              lb++;
              for (uint8_t i = 0; i < maxLines; i++) {
                _drawLine = 0;
                drawEditLine(i + lb);
              }
            }
          }
        }
      }

      if (' ' <= intC && intC <= '~') {  // Ascii char
        txt[line] = txt[line].substring(0, cuX[line])
                    + (char)intC + txt[line].substring(cuX[line]);
        spc[line] = " " + spc[line];
        cuX[line]++;
      }

      if (intC == 9) {  // TAB
        txt[line] = txt[line].substring(0, cuX[line])
                    + "  " + txt[line].substring(cuX[line]);
        spc[line] = "  " + spc[line];
        cuX[line] += 2;
      }

      if (intC == 8) {  // BACKSPACE
        if (txt[line].length() == 0) {
          spr1.fillSprite(0);
          spr1.pushSprite(3, 32 + ((line - lb) * _LH));
          for (uint8_t i = line; i < lastline; i++) {
            spc[i] = spc[i + 1];
            txt[i] = txt[i + 1];
            cuX[i] = cuX[i + 1];
            _drawLine = 0;
            drawEditLine(i);
          }
          spr1.fillSprite(0);
          spr1.pushSprite(3, 32 + ((lastline - lb) * _LH));

          lastline--;
          if (line > 0) line--;
          _drawLine = 1;
          drawBlackEndline();
        } else {  // any word exists
          txt[line] = txt[line].substring(0, cuX[line] - 1)
                      + txt[line].substring(cuX[line]);
          spc[line] = spc[line].substring(0, cuX[line] - 1) + '|';
          cuX[line]--;
        }
      }

      if (intS.equals("279165")) {  // UP at Editing text
        if ((line - lb) > 0) {
          _drawLine = 0;
          drawEditLine(line);
          line--;
          if (lb > 0) {
            lb--;
            for (uint8_t i = 0; i < maxLines; i++) {
              _drawLine = 0;
              drawEditLine(i + lb);
            }
          }
        }
      }

      if (intS.equals("279166")) {  // DOWN at editing
        if (line < lastline) {
          _drawLine = 0;
          drawEditLine(line);
          line++;
          if ((line - lb) >= maxLines) {
            lb++;
            for (uint8_t i = 0; i < maxLines; i++) {
              _drawLine = 0;
              drawEditLine(i + lb);
            }
          }
        }
      }

      if (intC == 13) {                               // RETURN at editing text
        for (uint16_t i = lastline; i > line; i--) {  // insert a new line
          spc[i + 1] = spc[i];
          txt[i + 1] = txt[i];
          cuX[i + 1] = cuX[i];
          _drawLine = 0;
          drawEditLine(i + 1);
        }
        lastline++;

        spc[line + 1] = spc[line];
        txt[line + 1] = txt[line];
        cuX[line + 1] = cuX[line];
        _drawLine = 0;
        drawEditLine(line + 1);
        spc[line] = "|";
        txt[line] = "";
        cuX[line] = 0;

        if ((line - lb) >= maxLines) {
          lb++;
          for (uint8_t i = 0; i < maxLines; i++) {
            _drawLine = 0;
            drawEditLine(i + lb);
          }
        }
      }

      _drawLine = 1;
      drawEditLine(line);
      drawBlackEndline();
      drawFep();
    }
  }
}

void dispFiles(uint8_t page) {
  lcd.fillRect(1, 26, 380, SH - 26, NAVY);
  lcd.setTextColor(YELW);
  for (uint8_t i = 0; i < fnLs; i++) {
    if (i + page * fnLs < filesCount) {
      char s[16];
      sprintf(s, "%2d", i + page * fnLs);
      lcd.drawString((String)s + ":" + fileNames[i + page * fnLs],
                     30, 35 + i * _LH);
    }
  }
  lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
}

void drawEditLine(uint8_t ln) {
  if (_drawLine) spr1.fillSprite(1);  //フォーカス行の背景は少し明るく
  else spr1.fillSprite(0);
  spr1.setTextColor(2);
  if (ln < 0) exit;
  String n = (ln + 1 < 10) ? "0" : "";
  spr1.drawString(n + String(ln + 1) + ">", 0, 4);  // 行番号
  spr1.setTextColor(3);
  if (_drawLine) spr1.drawString(spc[ln], 36, 4);  // "|"を先に表示
  spr1.setTextColor(4);
  spr1.drawString(txt[ln], 36, 4);
  spr1.pushSprite(2, 32 + ((ln - lb) * _LH));
}

void drawBlackEndline() {
  spr2.fillSprite(0);
  spr2.pushSprite(2, 32 + (maxLines * _LH));
}

void drawFep() {
  spr3.fillSprite(0x3804);
  spr3.pushSprite(2, SH - 2 * _LH);
}

void dispCurFname(String fn) {
  spr0.fillSprite(0);
  spr0.setTextColor(1);
  spr0.drawString(fn, 2, 3);
  spr0.pushSprite(65, 1);
}

void FKey(String s1, String s2, uint16_t x, uint16_t y) {
  lcd.fillRect(x, y, 90, 22, TFT_SILVER);
  lcd.setTextColor(TFT_RED);
  lcd.drawString(s1, x + 3, y + 4);
  lcd.setTextColor(TFT_BLACK);
  lcd.drawString(s2, x + 30, y + 4);
}

void SD_Info() {
  uint8_t cardType = SD.cardType();  // カード情報
  String s = "Card Type: ";
  if (cardType == CARD_MMC) s += "MMC";
  else if (cardType == CARD_SD) s += "SDSC";
  else if (cardType == CARD_SDHC) s += "SDHC";
  else s += "UNKNOWN";
  Serial.println(s);
  uint64_t cardSize = SD.cardSize() / (1024 * 1024 * 1024);
  s = "Card Size: " + (String)(cardSize) + "GB";
  Serial.println(s);
}

void saveFile() {
  String ff = "/" + fileName;
  File file = SD.open(ff, FILE_WRITE);  // Open file.txt in write mode
  if (file) {
    for (uint8_t i = 0; i <= lastline; i++) file.println(txt[i]);  // Write
    file.close();
    Serial.println("File save successfully.");
  }
}

void openFile(String fn) {
  clearTexts();
  File fp = SD.open(fn, FILE_READ);
  if (fp) {
    Serial.println("Reading text file...");
    lastline = 0;
    while (fp.available()) {
      uint8_t c = fp.read();
      if (c == 10) lastline++;  // Increment the line count
      if (c == 9) txt[lastline] += '\t';
      if (c >= 32 && c <= 126) txt[lastline] += (char)c;
    }
    fp.close();                                // Close the file
    for (uint8_t l = 0; l <= lastline; l++) {  // make background spc
      uint8_t tlen = txt[l].length();
      spc[l] = '|';
      for (uint8_t j = 0; j < tlen; j++) spc[l] = " " + spc[l];
      cuX[l] = tlen;
    }
    for (uint8_t i = 0; i < maxLines; i++) {  // draw lines
      _drawLine = (i == 0) ? 1 : 0;
      drawEditLine(i);
      if (i == lastline) break;
    }
    line = 0;
    Serial.println("File read successfully.");
  } else {
    Serial.println("Failed to open file.txt");
  }
}

最後まで見ていただきありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?