/**
 * Marlin 3D Printer Firmware
 * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
 *
 * Based on Sprinter and grbl.
 * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */
#include "../../../../inc/MarlinConfigPre.h"

#if HAS_TFT_LVGL_UI

#if ENABLED(TFT_LVGL_UI_SPI)
  #include "SPI_TFT.h"
#endif

#include "tft_lvgl_configuration.h"

#include "pic_manager.h"

#include "draw_ui.h"
#include "mks_hardware_test.h"

#include <SPI.h>

#include "../../../../MarlinCore.h"
#include "../../../../sd/cardreader.h"
#include "../../../../module/motion.h"
#include "../../../../module/planner.h"

#if ENABLED(POWER_LOSS_RECOVERY)
  #include "../../../../feature/powerloss.h"
#endif

#if ENABLED(PARK_HEAD_ON_PAUSE)
  #include "../../../../feature/pause.h"
#endif

W25QXXFlash W25QXX;
CFG_ITMES gCfgItems;
UI_CFG uiCfg;
DISP_STATE_STACK disp_state_stack;
DISP_STATE disp_state = MAIN_UI;
DISP_STATE last_disp_state;
PRINT_TIME print_time;
value_state value;

uint32_t To_pre_view;
uint8_t gcode_preview_over;
uint8_t flash_preview_begin;
uint8_t default_preview_flg;
uint32_t size = 809;
uint16_t row;
uint8_t temperature_change_frequency;
uint8_t printing_rate_update_flag;

extern uint8_t once_flag;
extern uint8_t sel_id;
extern uint8_t public_buf[512];
extern uint8_t bmp_public_buf[17 * 1024];

extern void LCD_IO_WriteData(uint16_t RegValue);

lv_point_t line_points[4][2] = {
  {{PARA_UI_POS_X, PARA_UI_POS_Y + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y + PARA_UI_SIZE_Y}},
  {{PARA_UI_POS_X, PARA_UI_POS_Y*2 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*2 + PARA_UI_SIZE_Y}},
  {{PARA_UI_POS_X, PARA_UI_POS_Y*3 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*3 + PARA_UI_SIZE_Y}},
  {{PARA_UI_POS_X, PARA_UI_POS_Y*4 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*4 + PARA_UI_SIZE_Y}}
};
void gCfgItems_init() {
  gCfgItems.multiple_language = MULTI_LANGUAGE_ENABLE;
  #if 1 // LCD_LANGUAGE == en
    gCfgItems.language = LANG_ENGLISH;
  #elif LCD_LANGUAGE == zh_CN
    gCfgItems.language = LANG_SIMPLE_CHINESE;
  #elif LCD_LANGUAGE == zh_TW
    gCfgItems.language = LANG_COMPLEX_CHINESE;
  #elif LCD_LANGUAGE == jp_kana
    gCfgItems.language = LANG_JAPAN;
  #elif LCD_LANGUAGE == de
    gCfgItems.language = LANG_GERMAN;
  #elif LCD_LANGUAGE == fr
    gCfgItems.language = LANG_FRENCH;
  #elif LCD_LANGUAGE == ru
    gCfgItems.language = LANG_RUSSIAN;
  #elif LCD_LANGUAGE == ko_KR
    gCfgItems.language = LANG_KOREAN;
  #elif LCD_LANGUAGE == tr
    gCfgItems.language = LANG_TURKISH;
  #elif LCD_LANGUAGE == es
    gCfgItems.language = LANG_SPANISH;
  #elif LCD_LANGUAGE == el
    gCfgItems.language = LANG_GREEK;
  #elif LCD_LANGUAGE == it
    gCfgItems.language = LANG_ITALY;
  #elif LCD_LANGUAGE == pt
    gCfgItems.language = LANG_PORTUGUESE;
  #endif
  gCfgItems.leveling_mode    = 0;
  gCfgItems.from_flash_pic   = 0;
  gCfgItems.curFilesize      = 0;
  gCfgItems.finish_power_off = 0;
  gCfgItems.pause_reprint    = 0;
  gCfgItems.pausePosX        = -1;
  gCfgItems.pausePosY        = -1;
  gCfgItems.pausePosZ        = 5;
  W25QXX.SPI_FLASH_BufferRead((uint8_t *)&gCfgItems.spi_flash_flag, VAR_INF_ADDR, sizeof(gCfgItems.spi_flash_flag));
  if (gCfgItems.spi_flash_flag == GCFG_FLAG_VALUE) {
    W25QXX.SPI_FLASH_BufferRead((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
  }
  else {
    gCfgItems.spi_flash_flag = GCFG_FLAG_VALUE;
    W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR);
    W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
  }

  uiCfg.F[0] = 'N';
  uiCfg.F[1] = 'A';
  uiCfg.F[2] = 'N';
  uiCfg.F[3] = 'O';
  W25QXX.SPI_FLASH_BlockErase(REFLSHE_FLGA_ADD + 32 - 64*1024);
  W25QXX.SPI_FLASH_BufferWrite(uiCfg.F,REFLSHE_FLGA_ADD,4);
}

void gCfg_to_spiFlah() {
  W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR);
  W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
}

void ui_cfg_init() {
  uiCfg.curTempType         = 0;
  uiCfg.curSprayerChoose    = 0;
  uiCfg.stepHeat            = 10;
  uiCfg.leveling_first_time = 0;
  uiCfg.para_ui_page        = 0;
  uiCfg.extruStep           = 5;
  uiCfg.extruSpeed          = 10;
  uiCfg.move_dist           = 1;
  uiCfg.moveSpeed           = 3000;
  uiCfg.stepPrintSpeed      = 10;
}

void update_spi_flash() {
  W25QXX.init(SPI_QUARTER_SPEED);
  W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR);
  W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
}

lv_style_t tft_style_scr;
lv_style_t tft_style_label_pre;
lv_style_t tft_style_label_rel;
lv_style_t style_line;
lv_style_t style_para_value_pre;
lv_style_t style_para_value_rel;

lv_style_t style_num_key_pre;
lv_style_t style_num_key_rel;

lv_style_t style_num_text;
void tft_style_init() {
  lv_style_copy(&tft_style_scr, &lv_style_scr);
  tft_style_scr.body.main_color   = LV_COLOR_BACKGROUND;
  tft_style_scr.body.grad_color   = LV_COLOR_BACKGROUND;
  tft_style_scr.text.color        = LV_COLOR_TEXT;
  tft_style_scr.text.sel_color    = LV_COLOR_TEXT;
  tft_style_scr.line.width        = 0;
  tft_style_scr.text.letter_space = 0;
  tft_style_scr.text.line_space   = 0;

  lv_style_copy(&tft_style_label_pre, &lv_style_scr);
  lv_style_copy(&tft_style_label_rel, &lv_style_scr);
  tft_style_label_pre.body.main_color = LV_COLOR_BACKGROUND;
  tft_style_label_pre.body.grad_color = LV_COLOR_BACKGROUND;
  tft_style_label_pre.text.color      = LV_COLOR_TEXT;
  tft_style_label_pre.text.sel_color  = LV_COLOR_TEXT;
  tft_style_label_rel.body.main_color = LV_COLOR_BACKGROUND;
  tft_style_label_rel.body.grad_color = LV_COLOR_BACKGROUND;
  tft_style_label_rel.text.color      = LV_COLOR_TEXT;
  tft_style_label_rel.text.sel_color  = LV_COLOR_TEXT;
  tft_style_label_pre.text.font       = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
  tft_style_label_rel.text.font       = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
  tft_style_label_pre.line.width        = 0;
  tft_style_label_rel.line.width        = 0;
  tft_style_label_pre.text.letter_space = 0;
  tft_style_label_rel.text.letter_space = 0;
  tft_style_label_pre.text.line_space   = -5;
  tft_style_label_rel.text.line_space   = -5;
  lv_style_copy(&style_para_value_pre, &lv_style_scr);
  lv_style_copy(&style_para_value_rel, &lv_style_scr);
  style_para_value_pre.body.main_color = LV_COLOR_BACKGROUND;
  style_para_value_pre.body.grad_color = LV_COLOR_BACKGROUND;
  style_para_value_pre.text.color      = LV_COLOR_BLACK;
  style_para_value_pre.text.sel_color  = LV_COLOR_BLACK;
  style_para_value_rel.body.main_color = LV_COLOR_BACKGROUND;
  style_para_value_rel.body.grad_color = LV_COLOR_BACKGROUND;
  style_para_value_rel.text.color      = LV_COLOR_BLACK;
  style_para_value_rel.text.sel_color  = LV_COLOR_BLACK;
  style_para_value_pre.text.font       = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
  style_para_value_rel.text.font       = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
  style_para_value_pre.line.width        = 0;
  style_para_value_rel.line.width        = 0;
  style_para_value_pre.text.letter_space = 0;
  style_para_value_rel.text.letter_space = 0;
  style_para_value_pre.text.line_space   = -5;
  style_para_value_rel.text.line_space   = -5;
  lv_style_copy(&style_num_key_pre, &lv_style_scr);
  lv_style_copy(&style_num_key_rel, &lv_style_scr);
  style_num_key_pre.body.main_color = LV_COLOR_KEY_BACKGROUND;
  style_num_key_pre.body.grad_color = LV_COLOR_KEY_BACKGROUND;
  style_num_key_pre.text.color      = LV_COLOR_TEXT;
  style_num_key_pre.text.sel_color  = LV_COLOR_TEXT;
  style_num_key_rel.body.main_color = LV_COLOR_KEY_BACKGROUND;
  style_num_key_rel.body.grad_color = LV_COLOR_KEY_BACKGROUND;
  style_num_key_rel.text.color      = LV_COLOR_TEXT;
  style_num_key_rel.text.sel_color  = LV_COLOR_TEXT;
  #if HAS_SPI_FLASH_FONT
    style_num_key_pre.text.font = &gb2312_puhui32;
    style_num_key_rel.text.font = &gb2312_puhui32;
  #else
    style_num_key_pre.text.font = LV_FONT_DEFAULT;
    style_num_key_rel.text.font = LV_FONT_DEFAULT;
  #endif

  style_num_key_pre.line.width        = 0;
  style_num_key_rel.line.width        = 0;
  style_num_key_pre.text.letter_space = 0;
  style_num_key_rel.text.letter_space = 0;
  style_num_key_pre.text.line_space   = -5;
  style_num_key_rel.text.line_space   = -5;
  lv_style_copy(&style_num_text, &lv_style_scr);

  style_num_text.body.main_color   = LV_COLOR_WHITE;
  style_num_text.body.grad_color   = LV_COLOR_WHITE;
  style_num_text.text.color        = LV_COLOR_BLACK;
  style_num_text.text.sel_color    = LV_COLOR_BLACK;
  style_num_text.text.font         = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
  style_num_text.line.width        = 0;
  style_num_text.text.letter_space = 0;
  style_num_text.text.line_space   = -5;

  lv_style_copy(&style_line, &lv_style_plain);
  style_line.line.color   = LV_COLOR_MAKE(0x49, 0x54, 0xff);
  style_line.line.width   = 1;
  style_line.line.rounded = 1;
}

#define MAX_TITLE_LEN 28

char public_buf_m[100] = {0};
char public_buf_l[30];

void titleText_cat(char *str, int strSize, char *addPart) {
  if (str == 0 || addPart == 0) return;
  if ((int)(strlen(str) + strlen(addPart)) >= strSize) return;
  strcat(str, addPart);
}

char *getDispText(int index) {

  ZERO(public_buf_l);

  switch (disp_state_stack._disp_state[index]) {
    case PRINT_READY_UI:
      strcpy(public_buf_l, main_menu.title);
      break;
    case PRINT_FILE_UI:
      strcpy(public_buf_l, file_menu.title);
      break;
    case PRINTING_UI:
      if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI
        #ifndef TFT35
          || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI
          || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI
        #endif
      )    strcpy(public_buf_l, common_menu.print_special_title);
      else strcpy(public_buf_l, printing_menu.title);
      break;
    case MOVE_MOTOR_UI:
      strcpy(public_buf_l, move_menu.title);
      break;
    case OPERATE_UI:
      if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI
        #ifndef TFT35
          || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI
          || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI
        #endif
      )    strcpy(public_buf_l, common_menu.operate_special_title);
      else strcpy(public_buf_l, operation_menu.title);
      break;

    case PAUSE_UI:
      if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI
        || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI
        || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI
      )    strcpy(public_buf_l, common_menu.pause_special_title);
      else strcpy(public_buf_l, pause_menu.title);
      break;

    case EXTRUSION_UI:
      strcpy(public_buf_l, extrude_menu.title);
      break;
    case CHANGE_SPEED_UI:
      strcpy(public_buf_l, speed_menu.title);
      break;
    case FAN_UI:
      strcpy(public_buf_l, fan_menu.title);
      break;
    case PRE_HEAT_UI:
      if ((disp_state_stack._disp_state[disp_state_stack._disp_index - 1] == OPERATE_UI))
           strcpy(public_buf_l, preheat_menu.adjust_title);
      else strcpy(public_buf_l, preheat_menu.title);
      break;
    case SET_UI:
      strcpy(public_buf_l, set_menu.title);
      break;
    case ZERO_UI:
      strcpy(public_buf_l, home_menu.title);
      break;
    case SPRAYER_UI: break;
    case MACHINE_UI: break;
    case LANGUAGE_UI:
      strcpy(public_buf_l, language_menu.title);
      break;
    case ABOUT_UI:
      strcpy(public_buf_l, about_menu.title);
      break;
    case LOG_UI: break;
    case DISK_UI:
      strcpy(public_buf_l, filesys_menu.title);
      break;
    case DIALOG_UI:
      strcpy(public_buf_l, common_menu.dialog_confirm_title);
      break;
    case WIFI_UI:
      strcpy(public_buf_l, wifi_menu.title);
      break;
    case MORE_UI:
    case PRINT_MORE_UI:
      strcpy(public_buf_l, more_menu.title);
      break;
    case FILAMENTCHANGE_UI:
      strcpy(public_buf_l, filament_menu.title);
      break;
    case LEVELING_UI:
    case MESHLEVELING_UI:
      strcpy(public_buf_l, leveling_menu.title);
      break;
    case BIND_UI:
      strcpy(public_buf_l, cloud_menu.title);
      break;
    case ZOFFSET_UI:
      strcpy(public_buf_l, zoffset_menu.title);
      break;
    case TOOL_UI:
      strcpy(public_buf_l, tool_menu.title);
      break;
    case WIFI_LIST_UI:
      //strcpy(public_buf_l, list_menu.title);
      break;
    case MACHINE_PARA_UI:
      strcpy(public_buf_l, MachinePara_menu.title);
      break;
    case BABY_STEP_UI:
      strcpy(public_buf_l, operation_menu.babystep);
      break;
    case EEPROM_SETTINGS_UI:
      strcpy(public_buf_l, eeprom_menu.title);
      break;
    default: break;
  }

  return public_buf_l;
}

char *creat_title_text() {
  int index     = 0;
  char *tmpText = 0;
  char tmpCurFileStr[20];

  ZERO(tmpCurFileStr);

  #if _LFN_UNICODE
    //cutFileName((TCHAR *)curFileName, 16, 16, (TCHAR *)tmpCurFileStr);
  #else
    cutFileName(list_file.long_name[sel_id], 16, 16, tmpCurFileStr);
  #endif

  ZERO(public_buf_m);

  while (index <= disp_state_stack._disp_index) {
    tmpText = getDispText(index);
    if ((*tmpText == 0) || (tmpText == 0)) {
      index++;
      continue;
    }

    titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText);
    if (index < disp_state_stack._disp_index) titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)">");

    index++;
  }

  if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI
    /*|| disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI
    || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI*/
  ) {
    titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)":");
    titleText_cat(public_buf_m, sizeof(public_buf_m), tmpCurFileStr);
  }

  if (strlen(public_buf_m) > MAX_TITLE_LEN) {
    ZERO(public_buf_m);
    tmpText = getDispText(0);
    if (*tmpText != 0) {
      titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText);
      titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)">...>");
      tmpText = getDispText(disp_state_stack._disp_index);
      if (*tmpText != 0) titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText);
    }
  }

  return public_buf_m;
}

#if HAS_GCODE_PREVIEW

  uint32_t gPicturePreviewStart = 0;

  void preview_gcode_prehandle(char *path) {
    #if ENABLED(SDSUPPORT)
      //uint8_t re;
      //uint32_t read;
      uint32_t pre_read_cnt = 0;
      uint32_t *p1;
      char *cur_name;

      gPicturePreviewStart = 0;
      cur_name             = strrchr(path, '/');
      card.openFileRead(cur_name);
      card.read(public_buf, 512);
      p1 = (uint32_t *)strstr((char *)public_buf, ";simage:");

      if (p1) {
        pre_read_cnt = (uint32_t)p1 - (uint32_t)((uint32_t *)(&public_buf[0]));

        To_pre_view              = pre_read_cnt;
        gcode_preview_over       = 1;
        gCfgItems.from_flash_pic = 1;
        update_spi_flash();
      }
      else {
        gcode_preview_over       = 0;
        default_preview_flg      = 1;
        gCfgItems.from_flash_pic = 0;
        update_spi_flash();
      }
      card.closefile();
    #endif
  }

  #if 1

    void gcode_preview(char *path, int xpos_pixel, int ypos_pixel) {
      #if ENABLED(SDSUPPORT)
        //uint8_t ress;
        //uint32_t write;
        volatile uint32_t i, j;
        volatile uint16_t *p_index;
        //int res;
        char *cur_name;

        cur_name = strrchr(path, '/');
        card.openFileRead(cur_name);

        if (gPicturePreviewStart <= 0) {
          while (1) {
            uint32_t br  = card.read(public_buf, 400);
            uint32_t* p1 = (uint32_t *)strstr((char *)public_buf, ";gimage:");
            if (p1) {
              gPicturePreviewStart += (uint32_t)p1 - (uint32_t)((uint32_t *)(&public_buf[0]));
              break;
            }
            else {
              gPicturePreviewStart += br;
            }
            if (br < 400) break;
          }
        }

        card.setIndex((gPicturePreviewStart + To_pre_view) + size * row + 8);
        #if ENABLED(TFT_LVGL_UI_SPI)
          SPI_TFT.SetWindows(xpos_pixel, ypos_pixel + row, 200, 1);
        #else
          ili9320_SetWindows(xpos_pixel, ypos_pixel + row, 200, 1);
          LCD_WriteRAM_Prepare();
        #endif

        j = i = 0;

        while (1) {
          card.read(public_buf, 400);
          for (i = 0; i < 400;) {
            bmp_public_buf[j] = ascii2dec_test((char*)&public_buf[i]) << 4 | ascii2dec_test((char*)&public_buf[i + 1]);
            i                += 2;
            j++;
          }
          if (j >= 400) break;
        }
        #if ENABLED(TFT_LVGL_UI_SPI)
          for (i = 0; i < 400; i += 2) {
            p_index  = (uint16_t *)(&bmp_public_buf[i]);
            if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full;
          }
          SPI_TFT.tftio.WriteSequence((uint16_t*)bmp_public_buf, 200);
        #else
          for (i = 0; i < 400;) {
            p_index = (uint16_t *)(&bmp_public_buf[i]);
            if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full; //gCfgItems.preview_bk_color;
            LCD_IO_WriteData(*p_index);
            i += 2;
          }
        #endif
        #if HAS_BAK_VIEW_IN_FLASH
          W25QXX.init(SPI_QUARTER_SPEED);
          if (row < 20) W25QXX.SPI_FLASH_SectorErase(BAK_VIEW_ADDR_TFT35 + row * 4096);
          W25QXX.SPI_FLASH_BufferWrite(bmp_public_buf, BAK_VIEW_ADDR_TFT35 + row * 400, 400);
        #endif
        row++;
        if (row >= 200) {
          size = 809;
          row  = 0;

          gcode_preview_over = 0;
          //flash_preview_begin = 1;

          card.closefile();

          /*
          if (gCurFileState.file_open_flag != 0xaa) {
            reset_file_info();
            res = f_open(file, curFileName, FA_OPEN_EXISTING | FA_READ);
            if (res == FR_OK) {
              f_lseek(file,PREVIEW_SIZE+To_pre_view);
              gCurFileState.file_open_flag = 0xaa;
              //bakup_file_path((uint8_t *)curFileName, strlen(curFileName));
              srcfp = file;
              mksReprint.mks_printer_state = MKS_WORKING;
              once_flag = 0;
            }
          }
          */
          char *cur_name;

          cur_name = strrchr(list_file.file_name[sel_id], '/');

          SdFile file;
          SdFile *curDir;
          card.endFilePrint();
          const char * const fname = card.diveToFile(true, curDir, cur_name);
          if (!fname) return;
          if (file.open(curDir, fname, O_READ)) {
            gCfgItems.curFilesize = file.fileSize();
            file.close();
            update_spi_flash();
          }

          card.openFileRead(cur_name);
          if (card.isFileOpen()) {
            feedrate_percentage = 100;
            //saved_feedrate_percentage = feedrate_percentage;
            planner.flow_percentage[0] = 100;
            planner.e_factor[0]        = planner.flow_percentage[0] * 0.01;
            if (EXTRUDERS == 2) {
              planner.flow_percentage[1] = 100;
              planner.e_factor[1]        = planner.flow_percentage[1] * 0.01;
            }
            card.startFileprint();
            TERN_(POWER_LOSS_RECOVERY, recovery.prepare());
            once_flag = 0;
          }
          return;
        }
        card.closefile();
      #endif // SDSUPPORT
    }

  #else // if 1

    void gcode_preview(char *path, int xpos_pixel, int ypos_pixel) {
      #if ENABLED(SDSUPPORT)
        //uint8_t ress;
        //uint32_t write;
        volatile uint32_t i, j;
        volatile uint16_t *p_index;
        //int res;
        char *cur_name;
        uint16_t Color;

        cur_name = strrchr(path, '/');
        card.openFileRead(cur_name);

        card.setIndex((PREVIEW_LITTLE_PIC_SIZE + To_pre_view) + size * row + 8);
        #if ENABLED(TFT_LVGL_UI_SPI)
          SPI_TFT.SetWindows(xpos_pixel, ypos_pixel + row, 200, 1);
        #else
          ili9320_SetWindows(xpos_pixel, ypos_pixel + row, 200, 1);
          LCD_WriteRAM_Prepare();
        #endif

        j = 0;
        i = 0;

        while (1) {
          card.read(public_buf, 400);
          for (i = 0; i < 400;) {
            bmp_public_buf[j] = ascii2dec_test((char*)&public_buf[i]) << 4 | ascii2dec_test((char*)&public_buf[i + 1]);
            i += 2;
            j++;
          }

          //if (i > 800) break;
          //#ifdef TFT70
          //  if (j > 400) {
          //    f_read(file, buff_pic, 1, &read);
          //    break;
          //  }
          //#elif defined(TFT35)
          if (j >= 400)
            //f_read(file, buff_pic, 1, &read);
            break;
          //#endif

        }
        #if ENABLED(TFT_LVGL_UI_SPI)
          for (i = 0; i < 400;) {
            p_index = (uint16_t *)(&bmp_public_buf[i]);

            Color    = (*p_index >> 8);
            *p_index = Color | ((*p_index & 0xff) << 8);
            i       += 2;
            if (*p_index == 0x0000) *p_index = 0xC318;
          }
          TFT_CS_L;
          TFT_DC_H;
          SPI.dmaSend(bmp_public_buf, 400, true);
          TFT_CS_H;

        #else
          for (i = 0; i < 400;) {
            p_index = (uint16_t *)(&bmp_public_buf[i]);
            if (*p_index == 0x0000) *p_index = 0x18C3;
            LCD_IO_WriteData(*p_index);
            i = i + 2;
          }
        #endif
        W25QXX.init(SPI_QUARTER_SPEED);
        if (row < 20)
          W25QXX.SPI_FLASH_SectorErase(BAK_VIEW_ADDR_TFT35 + row * 4096);
        W25QXX.SPI_FLASH_BufferWrite(bmp_public_buf, BAK_VIEW_ADDR_TFT35 + row * 400, 400);
        row++;
        if (row >= 200) {
          size = 809;
          row  = 0;

          gcode_preview_over = 0;
          //flash_preview_begin = 1;

          card.closefile();

          /*
          if (gCurFileState.file_open_flag != 0xaa) {
            reset_file_info();
            res = f_open(file, curFileName, FA_OPEN_EXISTING | FA_READ);
            if (res == FR_OK) {
              f_lseek(file,PREVIEW_SIZE+To_pre_view);
              gCurFileState.file_open_flag = 0xaa;
              //bakup_file_path((uint8_t *)curFileName, strlen(curFileName));
              srcfp = file;
              mksReprint.mks_printer_state = MKS_WORKING;
              once_flag = 0;
            }
          }
          */
          char *cur_name;

          cur_name = strrchr(list_file.file_name[sel_id], '/');

          SdFile file;
          SdFile *curDir;
          card.endFilePrint();
          const char * const fname = card.diveToFile(true, curDir, cur_name);
          if (!fname) return;
          if (file.open(curDir, fname, O_READ)) {
            gCfgItems.curFilesize = file.fileSize();
            file.close();
            update_spi_flash();
          }

          card.openFileRead(cur_name);
          if (card.isFileOpen()) {
            feedrate_percentage = 100;
            //saved_feedrate_percentage = feedrate_percentage;
            planner.flow_percentage[0] = 100;
            planner.e_factor[0]        = planner.flow_percentage[0] * 0.01;
            if (EXTRUDERS == 2) {
              planner.flow_percentage[1] = 100;
              planner.e_factor[1]        = planner.flow_percentage[1] * 0.01;
            }
            card.startFileprint();
            TERN_(POWER_LOSS_RECOVERY, recovery.prepare());
            once_flag = 0;
          }
          return;
        }
        card.closefile();
      #endif // SDSUPPORT
    }

  #endif // if 1

  void Draw_default_preview(int xpos_pixel, int ypos_pixel, uint8_t sel) {
    int index;
    int y_off = 0;

    for (index = 0; index < 10; index++) { // 200*200
      #if HAS_BAK_VIEW_IN_FLASH
        if (sel == 1) {
          flash_view_Read(bmp_public_buf, 8000); // 20k
        }
        else {
          default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 20k
        }
      #else
        default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 20k
      #endif

      #if ENABLED(TFT_LVGL_UI_SPI)
        SPI_TFT.SetWindows(xpos_pixel, y_off * 20 + ypos_pixel, 200, 20); // 200*200
        SPI_TFT.tftio.WriteSequence((uint16_t*)(bmp_public_buf), DEFAULT_VIEW_MAX_SIZE / 20);
      #else
        int x_off = 0;
        uint16_t temp_p;
        int i = 0;
        uint16_t *p_index;
        ili9320_SetWindows(xpos_pixel, y_off * 20 + ypos_pixel, 200, 20); // 200*200

        LCD_WriteRAM_Prepare();

        for (int _y = y_off * 20; _y < (y_off + 1) * 20; _y++) {
          for (x_off = 0; x_off < 200; x_off++) {
            if (sel == 1) {
              temp_p  = (uint16_t)(bmp_public_buf[i] | bmp_public_buf[i + 1] << 8);
              p_index = &temp_p;
            }
            else {
              p_index = (uint16_t *)(&bmp_public_buf[i]);
            }
            if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full; //gCfgItems.preview_bk_color;
            LCD_IO_WriteData(*p_index);
            i += 2;
          }
          if (i >= 8000) break;
        }
      #endif // TFT_LVGL_UI_SPI
      y_off++;
    }
    W25QXX.init(SPI_QUARTER_SPEED);
  }

  void disp_pre_gcode(int xpos_pixel, int ypos_pixel) {
    if (gcode_preview_over == 1) gcode_preview(list_file.file_name[sel_id], xpos_pixel, ypos_pixel);
    #if HAS_BAK_VIEW_IN_FLASH
      if (flash_preview_begin == 1) {
        flash_preview_begin = 0;
        Draw_default_preview(xpos_pixel, ypos_pixel, 1);
      }
    #endif
    #if HAS_GCODE_DEFAULT_VIEW_IN_FLASH
      if (default_preview_flg == 1) {
        Draw_default_preview(xpos_pixel, ypos_pixel, 0);
        default_preview_flg = 0;
      }
    #endif
  }
#endif // HAS_GCODE_PREVIEW

void print_time_run() {
  static uint8_t lastSec = 0;

  if (print_time.seconds >= 60) {
    print_time.seconds = 0;
    print_time.minutes++;
    if (print_time.minutes >= 60) {
      print_time.minutes = 0;
      print_time.hours++;
    }
  }
  if (disp_state == PRINTING_UI) {
    if (lastSec != print_time.seconds) disp_print_time();
    lastSec = print_time.seconds;
  }
}

void GUI_RefreshPage() {
  if ((systick_uptime_millis % 1000) == 0) temperature_change_frequency = 1;
  if ((systick_uptime_millis % 3000) == 0) printing_rate_update_flag = 1;

  switch (disp_state) {
    case MAIN_UI:
      //lv_draw_ready_print();
      break;
    case EXTRUSION_UI:
      if (temperature_change_frequency == 1) {
        temperature_change_frequency = 0;
        disp_hotend_temp();
      }
      break;
    case PRE_HEAT_UI:
      if (temperature_change_frequency == 1) {
        temperature_change_frequency = 0;
        disp_desire_temp();
      }
      break;
    case PRINT_READY_UI:
      /*
      if (gCfgItems.display_style == 2) {
        if (temperature_change_frequency) {
          temperature_change_frequency = 0;
          disp_restro_state();
        }
      }
      */
      break;

    case PRINT_FILE_UI: break;

    case PRINTING_UI:
      if (temperature_change_frequency) {
        temperature_change_frequency = 0;
        disp_ext_temp();
        disp_bed_temp();
        disp_fan_speed();
        disp_print_time();
        disp_fan_Zpos();
      }
      if (printing_rate_update_flag || marlin_state == MF_SD_COMPLETE) {
        printing_rate_update_flag = 0;
        if (gcode_preview_over == 0) setProBarRate();
      }
      break;

    case OPERATE_UI:
      /*
      if (temperature_change_frequency == 1) {
        temperature_change_frequency = 0;
        disp_temp_operate();
      }

      setProBarRateOpera();
      */
      break;

    case PAUSE_UI:
      /*
      if (temperature_change_frequency == 1) {
        temperature_change_frequency = 0;
        disp_temp_pause();
      }
      */
      break;

    case FAN_UI:
      if (temperature_change_frequency == 1) {
        temperature_change_frequency = 0;
        disp_fan_value();
      }
      break;

    case MOVE_MOTOR_UI:
      /*
      if (mksReprint.mks_printer_state == MKS_IDLE) {
        if ((z_high_count==1)&&(temper_error_flg != 1)) {
          z_high_count = 0;
          {
            memset((char *)gCfgItems.move_z_coordinate, ' ', sizeof(gCfgItems.move_z_coordinate));
            GUI_DispStringAt((const char *)gCfgItems.move_z_coordinate, 380, TITLE_YPOS);
            sprintf_P((char *)gCfgItems.move_z_coordinate, PSTR("Z: %.3f"), current_position[Z_AXIS]);
            GUI_DispStringAt((const char *)gCfgItems.move_z_coordinate, 380, TITLE_YPOS);
          }
        }
      }
      */
      break;

    case WIFI_UI:
      /*
      if (wifi_refresh_flg == 1) {
        disp_wifi_state();
        wifi_refresh_flg = 0;
      }
      */
      break;
    case BIND_UI:
      /*refresh_bind_ui();*/
      break;

    case FILAMENTCHANGE_UI:
      /*
      if (temperature_change_frequency) {
        temperature_change_frequency = 0;
        disp_filament_sprayer_temp();
      }
      */
      break;
    case DIALOG_UI:
      /*filament_dialog_handle();
      wifi_scan_handle();*/
      break;
    case MESHLEVELING_UI:
      /*disp_zpos();*/
      break;
    case HARDWARE_TEST_UI:
      break;
    case WIFI_LIST_UI:
      /*
      if (wifi_refresh_flg == 1) {
        disp_wifi_list();
        wifi_refresh_flg = 0;
      }
      */
      break;
    case KEY_BOARD_UI:
      /*update_password_disp();
      update_join_state_disp();*/
      break;
    case TIPS_UI:
      /*
      switch (tips_type) {
        case TIPS_TYPE_JOINING:
          if (wifi_link_state == WIFI_CONNECTED && strcmp((const char *)wifi_list.wifiConnectedName, (const char *)wifi_list.wifiName[wifi_list.nameIndex]) == 0) {
            tips_disp.timer = TIPS_TIMER_STOP;
            tips_disp.timer_count = 0;
            Clear_Tips();
            tips_type = TIPS_TYPE_WIFI_CONECTED;
            draw_Tips();
          }
          if (tips_disp.timer_count >= 30) {
            tips_disp.timer = TIPS_TIMER_STOP;
            tips_disp.timer_count = 0;
            Clear_Tips();
            tips_type = TIPS_TYPE_TAILED_JOIN;
            draw_Tips();
          }
          break;
        case TIPS_TYPE_TAILED_JOIN:
          if (tips_disp.timer_count >= 3) {
            tips_disp.timer = TIPS_TIMER_STOP;
            tips_disp.timer_count = 0;
            last_disp_state = TIPS_UI;
            Clear_Tips();
            draw_Wifi_list();
          }
          break;
        case TIPS_TYPE_WIFI_CONECTED:
          if (tips_disp.timer_count >= 3) {
            tips_disp.timer = TIPS_TIMER_STOP;
            tips_disp.timer_count = 0;

            last_disp_state = TIPS_UI;
            Clear_Tips();
            draw_Wifi();
          }
          break;
        default: break;
      }
      */
      break;
    case BABY_STEP_UI:
      /*
      if (temperature_change_frequency == 1) {
        temperature_change_frequency = 0;
        disp_z_offset_value();
      }
      */
      break;
    default: break;
  }

  print_time_run();
}

void clear_cur_ui() {
  last_disp_state = disp_state_stack._disp_state[disp_state_stack._disp_index];

  switch (disp_state_stack._disp_state[disp_state_stack._disp_index]) {
    case PRINT_READY_UI:
      //Get_Temperature_Flg = 0;
      lv_clear_ready_print();
      break;
    case PRINT_FILE_UI:
      lv_clear_print_file();
      break;
    case PRINTING_UI:
      lv_clear_printing();
      break;
    case MOVE_MOTOR_UI:
      lv_clear_move_motor();
      break;
    case OPERATE_UI:
      lv_clear_operation();
      break;
    case PAUSE_UI:
      //Clear_pause();
      break;
    case EXTRUSION_UI:
      lv_clear_extrusion();
      break;
    case PRE_HEAT_UI:
      lv_clear_preHeat();
      break;
    case CHANGE_SPEED_UI:
      lv_clear_change_speed();
      break;
    case FAN_UI:
      lv_clear_fan();
      break;
    case SET_UI:
      lv_clear_set();
      break;
    case ZERO_UI:
      lv_clear_home();
      break;
    case SPRAYER_UI:
      //Clear_Sprayer();
      break;
    case MACHINE_UI:
      //Clear_Machine();
      break;
    case LANGUAGE_UI:
      lv_clear_language();
      break;
    case ABOUT_UI:
      lv_clear_about();
      break;
    case LOG_UI:
      //Clear_Connect();
      break;
    case DISK_UI:
      //Clear_Disk();
      break;
    case WIFI_UI:
      //Clear_Wifi();
      break;
    case MORE_UI:
      //Clear_more();
      break;
    case FILETRANSFER_UI:
      //Clear_fileTransfer();
      break;
    case DIALOG_UI:
      lv_clear_dialog();
      break;
    case FILETRANSFERSTATE_UI:
      //Clear_WifiFileTransferdialog();
      break;
    case PRINT_MORE_UI:
      //Clear_Printmore();
      break;
    case LEVELING_UI:
      lv_clear_manualLevel();
      break;
    case BIND_UI:
      //Clear_Bind();
      break;
    case ZOFFSET_UI:
      //Clear_Zoffset();
      break;
    case TOOL_UI:
      lv_clear_tool();
      break;
    case MESHLEVELING_UI:
      //Clear_MeshLeveling();
      break;
    case HARDWARE_TEST_UI:
      //Clear_Hardwaretest();
      break;
    case WIFI_LIST_UI:
      //Clear_Wifi_list();
      break;
    case KEY_BOARD_UI:
      //Clear_Keyboard();
      break;
    case TIPS_UI:
      //Clear_Tips();
      break;
    case MACHINE_PARA_UI:
      lv_clear_machine_para();
      break;
    case MACHINE_SETTINGS_UI:
      lv_clear_machine_settings();
      break;
    case TEMPERATURE_SETTINGS_UI:
      //Clear_TemperatureSettings();
      break;
    case MOTOR_SETTINGS_UI:
      lv_clear_motor_settings();
      break;
    case MACHINETYPE_UI:
      //Clear_MachineType();
      break;
    case STROKE_UI:
      //Clear_Stroke();
      break;
    case HOME_DIR_UI:
      //Clear_HomeDir();
      break;
    case ENDSTOP_TYPE_UI:
      //Clear_EndstopType();
      break;
    case FILAMENT_SETTINGS_UI:
      //Clear_FilamentSettings();
      break;
    case LEVELING_SETTIGNS_UI:
      //Clear_LevelingSettings();
      break;
    case LEVELING_PARA_UI:
      //Clear_LevelingPara();
      break;
    case DELTA_LEVELING_PARA_UI:
      //Clear_DeltaLevelPara();
      break;
    case XYZ_LEVELING_PARA_UI:
      //Clear_XYZLevelPara();
      break;
    case MAXFEEDRATE_UI:
      lv_clear_max_feedrate_settings();
      break;
    case STEPS_UI:
      lv_clear_step_settings();
      break;
    case ACCELERATION_UI:
      lv_clear_acceleration_settings();
      break;
    case JERK_UI:
      #if HAS_CLASSIC_JERK
        lv_clear_jerk_settings();
      #endif
      break;
    case MOTORDIR_UI:
      //Clear_MotorDir();
      break;
    case HOMESPEED_UI:
      //Clear_HomeSpeed();
      break;
    case NOZZLE_CONFIG_UI:
      //Clear_NozzleConfig();
      break;
    case HOTBED_CONFIG_UI:
      //Clear_HotbedConfig();
      break;
    case ADVANCED_UI:
      lv_clear_advance_settings();
      break;
    case DOUBLE_Z_UI:
      //Clear_DoubleZ();
      break;
    case ENABLE_INVERT_UI:
      //Clear_EnableInvert();
      break;
    case NUMBER_KEY_UI:
      lv_clear_number_key();
      break;
    case BABY_STEP_UI:
      //Clear_babyStep();
      break;
    case PAUSE_POS_UI:
      lv_clear_pause_position();
      break;
      #if HAS_TRINAMIC_CONFIG
        case TMC_CURRENT_UI:
          lv_clear_tmc_current_settings();
          break;
      #endif
    case EEPROM_SETTINGS_UI:
      lv_clear_eeprom_settings();
      break;
      #if HAS_STEALTHCHOP
        case TMC_MODE_UI:
          lv_clear_tmc_step_mode_settings();
          break;
      #endif
    default:
      break;
  }
  //GUI_Clear();
}

void draw_return_ui() {
  if (disp_state_stack._disp_index > 0) {
    disp_state_stack._disp_index--;

    switch (disp_state_stack._disp_state[disp_state_stack._disp_index]) {
      case PRINT_READY_UI:
        lv_draw_ready_print();
        break;
      case PRINT_FILE_UI:
        lv_draw_print_file();
        break;
      case PRINTING_UI:
        if (gCfgItems.from_flash_pic == 1) flash_preview_begin = 1;
        else default_preview_flg = 1;
        lv_draw_printing();
        break;
      case MOVE_MOTOR_UI:
        lv_draw_move_motor();
        break;
      case OPERATE_UI:
        lv_draw_operation();
        break;

        #if 1
          case PAUSE_UI:
            //draw_pause();
            break;
        #endif

      case EXTRUSION_UI:
        lv_draw_extrusion();
        break;
      case PRE_HEAT_UI:
        lv_draw_preHeat();
        break;
      case CHANGE_SPEED_UI:
        lv_draw_change_speed();
        break;
      case FAN_UI:
        lv_draw_fan();
        break;
      case SET_UI:
        lv_draw_set();
        break;
      case ZERO_UI:
        lv_draw_home();
        break;
      case SPRAYER_UI:
        //draw_Sprayer();
        break;
      case MACHINE_UI:
        //draw_Machine();
        break;
      case LANGUAGE_UI:
        lv_draw_language();
        break;
      case ABOUT_UI:
        lv_draw_about();
        break;

        #if tan_mask
          case LOG_UI:
            //draw_Connect();
            break;
        #endif

      case CALIBRATE_UI:
        //draw_calibrate();
        break;
      case DISK_UI:
        //draw_Disk();
        break;
      case WIFI_UI:
        //draw_Wifi();
        break;
      case MORE_UI:
        //draw_More();
        break;
      case PRINT_MORE_UI:
        //draw_printmore();
        break;
      case FILAMENTCHANGE_UI:
        //draw_FilamentChange();
        break;
      case LEVELING_UI:
        lv_draw_manualLevel();
        break;
      case BIND_UI:
        //draw_bind();
        break;

        #if tan_mask
          case ZOFFSET_UI:
            //draw_Zoffset();
            break;
        #endif

      case TOOL_UI:
        lv_draw_tool();
        break;
      case MESHLEVELING_UI:
        //draw_meshleveling();
        break;
      case HARDWARE_TEST_UI:
        //draw_Hardwaretest();
        break;
      case WIFI_LIST_UI:
        //draw_Wifi_list();
        break;
      case KEY_BOARD_UI:
        //draw_Keyboard();
        break;
      case TIPS_UI:
        //draw_Tips();
        break;
      case MACHINE_PARA_UI:
        lv_draw_machine_para();
        break;
      case MACHINE_SETTINGS_UI:
        lv_draw_machine_settings();
        break;
      case TEMPERATURE_SETTINGS_UI:
        //draw_TemperatureSettings();
        break;
      case MOTOR_SETTINGS_UI:
        lv_draw_motor_settings();
        break;
      case MACHINETYPE_UI:
        //draw_MachineType();
        break;
      case STROKE_UI:
        //draw_Stroke();
        break;
      case HOME_DIR_UI:
        //draw_HomeDir();
        break;
      case ENDSTOP_TYPE_UI:
        //draw_EndstopType();
        break;
      case FILAMENT_SETTINGS_UI:
        //draw_FilamentSettings();
        break;
      case LEVELING_SETTIGNS_UI:
        //draw_LevelingSettings();
        break;
      case LEVELING_PARA_UI:
        //draw_LevelingPara();
        break;
      case DELTA_LEVELING_PARA_UI:
        //draw_DeltaLevelPara();
        break;
      case XYZ_LEVELING_PARA_UI:
        //draw_XYZLevelPara();
        break;
      case MAXFEEDRATE_UI:
        lv_draw_max_feedrate_settings();
        break;
      case STEPS_UI:
        lv_draw_step_settings();
        break;
      case ACCELERATION_UI:
        lv_draw_acceleration_settings();
        break;
      case JERK_UI:
        #if HAS_CLASSIC_JERK
          lv_draw_jerk_settings();
        #endif
        break;
      case MOTORDIR_UI:
        //draw_MotorDir();
        break;
      case HOMESPEED_UI:
        //draw_HomeSpeed();
        break;
      case NOZZLE_CONFIG_UI:
        //draw_NozzleConfig();
        break;
      case HOTBED_CONFIG_UI:
        //draw_HotbedConfig();
        break;
      case ADVANCED_UI:
        lv_draw_advance_settings();
        break;
      case DOUBLE_Z_UI:
        //draw_DoubleZ();
        break;
      case ENABLE_INVERT_UI:
        //draw_EnableInvert();
        break;
      case NUMBER_KEY_UI:
        lv_draw_number_key();
        break;
      case DIALOG_UI:
        //draw_dialog(DialogType);
        break;
      case BABY_STEP_UI:
        //draw_babyStep();
        break;
      case PAUSE_POS_UI:
        lv_draw_pause_position();
        break;
        #if HAS_TRINAMIC_CONFIG
          case TMC_CURRENT_UI:
            lv_draw_tmc_current_settings();
            break;
        #endif
      case EEPROM_SETTINGS_UI:
        lv_draw_eeprom_settings();
        break;
        #if HAS_STEALTHCHOP
          case TMC_MODE_UI:
            lv_draw_tmc_step_mode_settings();
            break;
        #endif
      default: break;
    }
  }
}

#if ENABLED(SDSUPPORT)

  void sd_detection() {
    static bool last_sd_status;
    const bool sd_status = IS_SD_INSERTED();
    if (sd_status != last_sd_status) {
      last_sd_status = sd_status;
      if (sd_status) card.mount(); else card.release();
    }
  }

#endif

void lv_ex_line(lv_obj_t * line, lv_point_t *points) {
  /*Copy the previous line and apply the new style*/
  lv_line_set_points(line, points, 2);     /*Set the points*/
  lv_line_set_style(line, LV_LINE_STYLE_MAIN, &style_line);
  lv_obj_align(line, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);
}

extern volatile uint32_t systick_uptime_millis;

void print_time_count() {
  if ((systick_uptime_millis % 1000) == 0)
    if (print_time.start == 1) print_time.seconds++;
}

void LV_TASK_HANDLER() {
  //lv_tick_inc(1);
  lv_task_handler();
  if (mks_test_flag == 0x1e) mks_hardware_test();
  #if HAS_GCODE_PREVIEW
    disp_pre_gcode(2, 36);
  #endif
  GUI_RefreshPage();
  //sd_detection();
}

#endif // HAS_TFT_LVGL_UI
