️ Enhance and fix FTDI Eve Touch UI file select (#22651)

This commit is contained in:
Marcio T 2021-08-29 16:03:10 -06:00 committed by GitHub
parent f721c44c22
commit ab03c9a560
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 209 additions and 113 deletions

View file

@ -0,0 +1,52 @@
/**************
* arrows.cpp *
**************/
/****************************************************************************
* Written By Marcio Teixeira 2021 - SynDaver 3D *
* *
* 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. *
* *
* To view a copy of the GNU General Public License, go to the following *
* location: <https://www.gnu.org/licenses/>. *
****************************************************************************/
#include "ftdi_extended.h"
#if ENABLED(FTDI_EXTENDED)
#define COORD(X,Y) cx + s*(swapXY ? Y : (flipX ? -X : X)), cy + s*(swapXY ? (flipX ? -X : X) : Y)
namespace FTDI {
void drawArrow(int x, int y, int w, int h, Direction direction) {
const bool swapXY = direction == UP || direction == DOWN;
const bool flipX = direction == UP || direction == LEFT;
const int s = min(w,h);
const int cx = (x + w/2)*16;
const int cy = (y + h/2)*16;
CommandProcessor cmd;
cmd.cmd(SAVE_CONTEXT())
.cmd(LINE_WIDTH(s/2))
.cmd(BEGIN(LINES))
.cmd(VERTEX2F(COORD( 5, 0)))
.cmd(VERTEX2F(COORD( 2,-2)))
.cmd(VERTEX2F(COORD( 5, 0)))
.cmd(VERTEX2F(COORD( 2, 2)))
.cmd(VERTEX2F(COORD( 5, 0)))
.cmd(VERTEX2F(COORD(-5, 0)))
.cmd(RESTORE_CONTEXT());
}
} // namespace FTDI
#endif // FTDI_EXTENDED

View file

@ -0,0 +1,28 @@
/************
* arrows.h *
************/
/****************************************************************************
* Written By Marcio Teixeira 2021 - SynDaver 3D *
* *
* 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. *
* *
* To view a copy of the GNU General Public License, go to the following *
* location: <https://www.gnu.org/licenses/>. *
****************************************************************************/
#pragma once
namespace FTDI {
enum Direction {UP, DOWN, LEFT, RIGHT};
void drawArrow(int x, int y, int w, int h, Direction direction);
}

View file

@ -48,6 +48,7 @@
#include "sound_list.h"
#include "polygon.h"
#include "poly_ui.h"
#include "arrows.h"
#include "text_box.h"
#include "text_ellipsis.h"
#include "adjuster_widget.h"

View file

@ -54,23 +54,33 @@
#define EDGE_L 0
#define EDGE_R 0
// GRID_X and GRID_Y computes the positions of the divisions on
// _GRID_X and _GRID_Y computes the positions of the divisions on
// the layout grid.
#define GRID_X(x) ((x)*(FTDI::display_width-EDGE_R-EDGE_L)/GRID_COLS+EDGE_L)
#define GRID_Y(y) ((y)*(FTDI::display_height-EDGE_B-EDGE_T)/GRID_ROWS+EDGE_T)
#define _GRID_X(x) ((x)*(FTDI::display_width-EDGE_R-EDGE_L)/GRID_COLS+EDGE_L)
#define _GRID_Y(y) ((y)*(FTDI::display_height-EDGE_B-EDGE_T)/GRID_ROWS+EDGE_T)
// BOX_X, BOX_Y, BOX_W and BOX_X returns the top-left and width
// and height of position on the grid.
#define BOX_X(x) (_GRID_X((x)-1))
#define BOX_Y(y) (_GRID_Y((y)-1))
#define BOX_W(w) (_GRID_X(w) - _GRID_X(0))
#define BOX_H(h) (_GRID_Y(h) - _GRID_Y(0))
// BTN_X, BTN_Y, BTN_W and BTN_X returns the top-left and width
// and height of a button, taking into account the button margins.
#define BTN_X(x) (GRID_X((x)-1) + MARGIN_L)
#define BTN_Y(y) (GRID_Y((y)-1) + MARGIN_T)
#define BTN_W(w) (GRID_X(w) - GRID_X(0) - MARGIN_L - MARGIN_R)
#define BTN_H(h) (GRID_Y(h) - GRID_Y(0) - MARGIN_T - MARGIN_B)
#define BTN_X(x) (BOX_X(x) + MARGIN_L)
#define BTN_Y(y) (BOX_Y(y) + MARGIN_T)
#define BTN_W(w) (BOX_W(w) - MARGIN_L - MARGIN_R)
#define BTN_H(h) (BOX_H(h) - MARGIN_T - MARGIN_B)
// Abbreviations for common phrases, to allow a button to be
// defined in one line of source.
// Abbreviations for common phrases, to allow a box or button
// to be defined in one line of source.
#define BTN_POS(x,y) BTN_X(x), BTN_Y(y)
#define BTN_SIZE(w,h) BTN_W(w), BTN_H(h)
#define BOX_POS(x,y) BOX_X(x), BOX_Y(y)
#define BOX_SIZE(w,h) BOX_W(w), BOX_H(h)
// Draw a reference grid for ease of spacing out widgets.
#define DRAW_LAYOUT_GRID \
@ -78,13 +88,13 @@
cmd.cmd(LINE_WIDTH(4)); \
for (int i = 1; i <= GRID_COLS; i++) { \
cmd.cmd(BEGIN(LINES)); \
cmd.cmd(VERTEX2F(GRID_X(i) *16, 0 *16)); \
cmd.cmd(VERTEX2F(GRID_X(i) *16, FTDI::display_height *16)); \
cmd.cmd(VERTEX2F(_GRID_X(i) *16, 0 *16)); \
cmd.cmd(VERTEX2F(_GRID_X(i) *16, FTDI::display_height *16)); \
} \
for (int i = 1; i < GRID_ROWS; i++) { \
cmd.cmd(BEGIN(LINES)); \
cmd.cmd(VERTEX2F(0 *16, GRID_Y(i) *16)); \
cmd.cmd(VERTEX2F(FTDI::display_width *16, GRID_Y(i) *16)); \
cmd.cmd(VERTEX2F(0 *16, _GRID_Y(i) *16)); \
cmd.cmd(VERTEX2F(FTDI::display_width *16, _GRID_Y(i) *16)); \
} \
cmd.cmd(LINE_WIDTH(16)); \
}

View file

@ -157,12 +157,6 @@ void BedMeshViewScreen::doProbe() {
injectCommands_P(PSTR(BED_LEVELING_COMMANDS));
}
void BedMeshViewScreen::doMeshValidation() {
mydata.count = 0;
GOTO_SCREEN(StatusScreen);
injectCommands_P(PSTR("G28\nM117 Heating...\nG26 R X0 Y0\nG27"));
}
void BedMeshViewScreen::show() {
injectCommands_P(PSTR("G29 L1"));
GOTO_SCREEN(BedMeshViewScreen);

View file

@ -43,6 +43,5 @@ class BedMeshViewScreen : public BedMeshBase, public CachedScreen<BED_MESH_VIEW_
static bool onTouchEnd(uint8_t tag);
static void doProbe();
static void doMeshValidation();
static void show();
};

View file

@ -26,6 +26,34 @@
#ifdef FTDI_FILES_SCREEN
#if ENABLED(TOUCH_UI_PORTRAIT)
#define GRID_COLS 6
#define GRID_ROWS 15
#define FILES_PER_PAGE 11
#define PREV_DIR LEFT
#define NEXT_DIR RIGHT
#define PREV_POS BTN_POS(1,1), BTN_SIZE(1,2)
#define HEAD_POS BTN_POS(2,1), BTN_SIZE(4,2)
#define NEXT_POS BTN_POS(6,1), BTN_SIZE(1,2)
#define LIST_POS BTN_POS(1,3), BTN_SIZE(6,FILES_PER_PAGE)
#define BTN1_POS BTN_POS(1,14), BTN_SIZE(3,2)
#define BTN2_POS BTN_POS(4,14), BTN_SIZE(3,2)
#else
#define GRID_COLS 12
#define GRID_ROWS 8
#define FILES_PER_PAGE 6
#define PREV_DIR UP
#define NEXT_DIR DOWN
#define PREV_POS BTN_POS(12,2), BTN_SIZE(1,3)
#define HEAD_POS BTN_POS( 1,1), BTN_SIZE(12,1)
#define NEXT_POS BTN_POS(12,5), BTN_SIZE(1,4)
#define LIST_POS BTN_POS( 1,2), BTN_SIZE(11,FILES_PER_PAGE)
#define BTN1_POS BTN_POS( 1,8), BTN_SIZE(6,1)
#define BTN2_POS BTN_POS( 7,8), BTN_SIZE(5,1)
#endif
using namespace FTDI;
using namespace ExtUI;
using namespace Theme;
@ -49,6 +77,7 @@ const char *FilesScreen::getSelectedFilename(bool longName) {
}
void FilesScreen::drawSelectedFile() {
if(mydata.selected_tag == 0xFF) return;
FileList files;
files.seek(getSelectedFileIndex(), true);
mydata.flags.is_dir = files.isDir();
@ -65,122 +94,108 @@ uint16_t FilesScreen::getSelectedFileIndex() {
}
uint16_t FilesScreen::getFileForTag(uint8_t tag) {
return mydata.cur_page * files_per_page + tag - 2;
return mydata.cur_page * FILES_PER_PAGE + tag - 2;
}
#if ENABLED(TOUCH_UI_PORTRAIT)
#define GRID_COLS 6
#define GRID_ROWS (files_per_page + header_h + footer_h)
#else
#define GRID_COLS 6
#define GRID_ROWS (files_per_page + header_h + footer_h)
#endif
void FilesScreen::drawFileButton(int x, int y, int w, int h, const char *filename, uint8_t tag, bool is_dir, bool is_highlighted) {
#define SUB_COLS 6
#define SUB_ROWS FILES_PER_PAGE
const int bx = SUB_X(1);
const int by = SUB_Y(getLineForTag(tag)+1);
const int bw = SUB_W(6);
const int bh = SUB_H(1);
void FilesScreen::drawFileButton(const char *filename, uint8_t tag, bool is_dir, bool is_highlighted) {
const uint8_t line = getLineForTag(tag)+1;
CommandProcessor cmd;
cmd.tag(tag);
cmd.cmd(COLOR_RGB(is_highlighted ? fg_action : bg_color));
cmd.font(font_medium)
.rectangle( 0, BTN_Y(header_h+line), display_width, BTN_H(1));
cmd.font(font_medium).rectangle(bx, by, bw, bh);
cmd.cmd(COLOR_RGB(is_highlighted ? normal_btn.rgb : bg_text_enabled));
constexpr uint16_t dim[2] = {BTN_SIZE(6,1)};
#define POS_AND_SHORTEN(SHORTEN) BTN_POS(1,header_h+line), dim[0] - (SHORTEN), dim[1]
#define POS_AND_SIZE POS_AND_SHORTEN(0)
#if ENABLED(SCROLL_LONG_FILENAMES)
if (is_highlighted) {
cmd.cmd(SAVE_CONTEXT());
cmd.cmd(SCISSOR_XY(x,y));
cmd.cmd(SCISSOR_SIZE(w,h));
cmd.cmd(MACRO(0));
cmd.text(POS_AND_SIZE, filename, OPT_CENTERY | OPT_NOFIT);
cmd.text(bx, by, bw, bh, filename, OPT_CENTERY | OPT_NOFIT);
} else
#endif
draw_text_with_ellipsis(cmd, POS_AND_SHORTEN(is_dir ? 20 : 0), filename, OPT_CENTERY, font_medium);
if (is_dir && !is_highlighted) {
cmd.text(POS_AND_SIZE, F("> "), OPT_CENTERY | OPT_RIGHTX);
}
draw_text_with_ellipsis(cmd, bx,by, bw - (is_dir ? 20 : 0), bh, filename, OPT_CENTERY, font_medium);
if (is_dir && !is_highlighted) cmd.text(bx, by, bw, bh, F("> "), OPT_CENTERY | OPT_RIGHTX);
#if ENABLED(SCROLL_LONG_FILENAMES)
if (is_highlighted) {
cmd.cmd(RESTORE_CONTEXT());
}
if (is_highlighted) cmd.cmd(RESTORE_CONTEXT());
#endif
}
void FilesScreen::drawFileList() {
FileList files;
mydata.num_page = max(1,ceil(float(files.count()) / files_per_page));
mydata.num_page = max(1,ceil(float(files.count()) / FILES_PER_PAGE));
mydata.cur_page = min(mydata.cur_page, mydata.num_page-1);
mydata.flags.is_root = files.isAtRootDir();
#undef MARGIN_T
#undef MARGIN_B
#define MARGIN_T 0
#define MARGIN_B 0
uint16_t fileIndex = mydata.cur_page * files_per_page;
for (uint8_t i = 0; i < files_per_page; i++, fileIndex++) {
if (files.seek(fileIndex)) {
uint16_t fileIndex = mydata.cur_page * FILES_PER_PAGE;
for (uint8_t i = 0; i < FILES_PER_PAGE; i++, fileIndex++) {
if (files.seek(fileIndex))
drawFileButton(files.filename(), getTagForLine(i), files.isDir(), false);
}
else {
else
break;
}
}
}
void FilesScreen::drawHeader() {
const bool prev_enabled = mydata.cur_page > 0;
const bool next_enabled = mydata.cur_page < (mydata.num_page - 1);
#undef MARGIN_T
#undef MARGIN_B
#define MARGIN_T 0
#define MARGIN_B 2
char str[16];
sprintf_P(str, PSTR("Page %d of %d"),
mydata.cur_page + 1, mydata.num_page);
sprintf_P(str, PSTR("Page %d of %d"), mydata.cur_page + 1, mydata.num_page);
CommandProcessor cmd;
cmd.colors(normal_btn)
.font(font_small)
.tag(0).button(BTN_POS(2,1), BTN_SIZE(4,header_h), str, OPT_CENTER | OPT_FLAT)
.font(font_medium)
.colors(action_btn)
.tag(241).enabled(prev_enabled).button(BTN_POS(1,1), BTN_SIZE(1,header_h), F("<"))
.tag(242).enabled(next_enabled).button(BTN_POS(6,1), BTN_SIZE(1,header_h), F(">"));
.tag(0).button(HEAD_POS, str, OPT_CENTER | OPT_FLAT);
}
void FilesScreen::drawArrows() {
const bool prev_enabled = mydata.cur_page > 0;
const bool next_enabled = mydata.cur_page < (mydata.num_page - 1);
CommandProcessor cmd;
cmd.colors(normal_btn);
cmd.tag(242).enabled(prev_enabled).button(PREV_POS, F("")); if (prev_enabled) drawArrow(PREV_POS, PREV_DIR);
cmd.tag(243).enabled(next_enabled).button(NEXT_POS, F("")); if (next_enabled) drawArrow(NEXT_POS, NEXT_DIR);
}
void FilesScreen::drawFooter() {
#undef MARGIN_T
#undef MARGIN_B
#if ENABLED(TOUCH_UI_PORTRAIT)
#define MARGIN_T 15
#define MARGIN_B 5
#else
#define MARGIN_T 5
#define MARGIN_B 5
#endif
const bool has_selection = mydata.selected_tag != 0xFF;
const uint8_t back_tag = mydata.flags.is_root ? 240 : 245;
const uint8_t y = GRID_ROWS - footer_h + 1;
const uint8_t h = footer_h;
const bool has_selection = mydata.selected_tag != 0xFF;
CommandProcessor cmd;
cmd.colors(normal_btn)
.font(font_medium)
.colors(has_selection ? normal_btn : action_btn)
.tag(back_tag).button(BTN_POS(4,y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BUTTON_DONE))
.enabled(has_selection)
.colors(has_selection ? normal_btn : action_btn);
if (mydata.flags.is_root)
cmd.tag(240).button(BTN2_POS, GET_TEXT_F(MSG_BUTTON_DONE));
else
cmd.tag(245).button(BTN2_POS, F("Up Dir"));
cmd.enabled(has_selection)
.colors(has_selection ? action_btn : normal_btn);
if (mydata.flags.is_dir)
cmd.tag(244).button(BTN_POS(1, y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BUTTON_OPEN));
cmd.tag(244).button(BTN1_POS, GET_TEXT_F(MSG_BUTTON_OPEN));
else
cmd.tag(243).button(BTN_POS(1, y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BUTTON_PRINT));
cmd.tag(241).button(BTN1_POS, GET_TEXT_F(MSG_BUTTON_PRINT));
}
void FilesScreen::drawFileButton(const char *filename, uint8_t tag, bool is_dir, bool is_highlighted) {
#undef MARGIN_L
#undef MARGIN_R
#define MARGIN_L 0
#define MARGIN_R 0
drawFileButton(LIST_POS, filename, tag, is_dir, is_highlighted);
}
void FilesScreen::onRedraw(draw_mode_t what) {
if (what & FOREGROUND) {
drawHeader();
drawArrows();
drawSelectedFile();
drawFooter();
}
@ -200,48 +215,50 @@ void FilesScreen::gotoPage(uint8_t page) {
bool FilesScreen::onTouchEnd(uint8_t tag) {
switch (tag) {
case 240: GOTO_PREVIOUS(); return true;
case 241:
case 240: // Done button
GOTO_PREVIOUS();
return true;
case 241: // Print highlighted file
ConfirmStartPrintDialogBox::show(getSelectedFileIndex());
return true;
case 242: // Previous page
if (mydata.cur_page > 0) {
gotoPage(mydata.cur_page-1);
}
break;
case 242:
case 243: // Next page
if (mydata.cur_page < (mydata.num_page-1)) {
gotoPage(mydata.cur_page+1);
}
break;
case 243:
ConfirmStartPrintDialogBox::show(getSelectedFileIndex());
return true;
case 244:
case 244: // Select directory
{
FileList files;
files.changeDir(getSelectedShortFilename());
gotoPage(0);
}
break;
case 245:
case 245: // Up directory
{
FileList files;
files.upDir();
gotoPage(0);
}
break;
default:
default: // File selected
if (tag < 240) {
mydata.selected_tag = tag;
#if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810)
mydata.scroll_pos = 0;
mydata.scroll_max = 0;
if (FTDI::ftdi_chip >= 810) {
const char *longFilename = getSelectedLongFilename();
if (longFilename[0]) {
CommandProcessor cmd;
uint16_t text_width = cmd.font(font_medium).text_width(longFilename);
mydata.scroll_pos = 0;
if (text_width > display_width)
mydata.scroll_max = text_width - display_width + MARGIN_L + MARGIN_R;
else
mydata.scroll_max = 0;
constexpr int dim[4] = {LIST_POS};
const uint16_t text_width = cmd.font(font_medium).text_width(longFilename);
if (text_width > dim[2])
mydata.scroll_max = text_width - dim[2] + MARGIN_L + MARGIN_R + 10;
}
}
#endif

View file

@ -41,16 +41,6 @@ struct FilesScreenData {
class FilesScreen : public BaseScreen, public CachedScreen<FILES_SCREEN_CACHE, FILE_SCREEN_DL_SIZE> {
private:
#if ENABLED(TOUCH_UI_PORTRAIT)
static constexpr uint8_t header_h = 2;
static constexpr uint8_t footer_h = 2;
static constexpr uint8_t files_per_page = 11;
#else
static constexpr uint8_t header_h = 1;
static constexpr uint8_t footer_h = 1;
static constexpr uint8_t files_per_page = 6;
#endif
static uint8_t getTagForLine(uint8_t line) {return line + 2;}
static uint8_t getLineForTag(uint8_t tag) {return tag - 2;}
static uint16_t getFileForTag(uint8_t tag);
@ -60,9 +50,11 @@ class FilesScreen : public BaseScreen, public CachedScreen<FILES_SCREEN_CACHE, F
inline static const char *getSelectedLongFilename() {return getSelectedFilename(true);}
static const char *getSelectedFilename(bool longName);
static void drawFileButton(int x, int y, int w, int h, const char *filename, uint8_t tag, bool is_dir, bool is_highlighted);
static void drawFileButton(const char *filename, uint8_t tag, bool is_dir, bool is_highlighted);
static void drawFileList();
static void drawHeader();
static void drawArrows();
static void drawFooter();
static void drawSelectedFile();

View file

@ -123,7 +123,10 @@ bool LevelingMenu::onTouchEnd(uint8_t tag) {
case 5: BedMeshEditScreen::show(); break;
#endif
#if ENABLED(G26_MESH_VALIDATION)
case 6: BedMeshViewScreen::doMeshValidation(); break;
case 6:
GOTO_SCREEN(StatusScreen);
injectCommands_P(PSTR("G28\nM117 Heating...\nG26 R X0 Y0\nG27"));
break;
#endif
#if ENABLED(BLTOUCH)
case 7: injectCommands_P(PSTR("M280 P0 S60")); break;