mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2025-04-23 16:01:42 +00:00
🧑💻 Encapsulate ProUI G-code preview
This commit is contained in:
parent
e1121a4cd0
commit
4613f85bb7
3 changed files with 121 additions and 131 deletions
Marlin/src/lcd/e3v2/proui
|
@ -288,7 +288,7 @@ MenuItem *editZValueItem = nullptr;
|
||||||
|
|
||||||
bool isPrinting() { return printingIsActive() || printingIsPaused(); }
|
bool isPrinting() { return printingIsActive() || printingIsPaused(); }
|
||||||
bool sdPrinting() { return isPrinting() && IS_SD_FILE_OPEN(); }
|
bool sdPrinting() { return isPrinting() && IS_SD_FILE_OPEN(); }
|
||||||
bool Host_Printing() { return isPrinting() && !IS_SD_FILE_OPEN(); }
|
bool hostPrinting() { return isPrinting() && !IS_SD_FILE_OPEN(); }
|
||||||
|
|
||||||
#define DWIN_LANGUAGE_EEPROM_ADDRESS 0x01 // Between 0x01 and 0x63 (EEPROM_OFFSET-1)
|
#define DWIN_LANGUAGE_EEPROM_ADDRESS 0x01 // Between 0x01 and 0x63 (EEPROM_OFFSET-1)
|
||||||
// BL24CXX::check() uses 0x00
|
// BL24CXX::check() uses 0x00
|
||||||
|
@ -634,9 +634,9 @@ void drawPrintDone() {
|
||||||
DWINUI::clearMainArea();
|
DWINUI::clearMainArea();
|
||||||
dwinPrintHeader(nullptr);
|
dwinPrintHeader(nullptr);
|
||||||
#if HAS_GCODE_PREVIEW
|
#if HAS_GCODE_PREVIEW
|
||||||
const bool haspreview = Preview_Valid();
|
const bool haspreview = preview.valid();
|
||||||
if (haspreview) {
|
if (haspreview) {
|
||||||
Preview_Show();
|
preview.show();
|
||||||
DWINUI::drawButton(BTN_Continue, 86, 295);
|
DWINUI::drawButton(BTN_Continue, 86, 295);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -1675,7 +1675,7 @@ void dwinLevelingDone() {
|
||||||
|
|
||||||
// Started a Print Job
|
// Started a Print Job
|
||||||
void dwinPrintStarted() {
|
void dwinPrintStarted() {
|
||||||
TERN_(HAS_GCODE_PREVIEW, if (Host_Printing()) Preview_Invalidate());
|
TERN_(HAS_GCODE_PREVIEW, if (hostPrinting()) preview.invalidate());
|
||||||
TERN_(SET_PROGRESS_PERCENT, ui.progress_reset());
|
TERN_(SET_PROGRESS_PERCENT, ui.progress_reset());
|
||||||
TERN_(SET_REMAINING_TIME, ui.reset_remaining_time());
|
TERN_(SET_REMAINING_TIME, ui.reset_remaining_time());
|
||||||
hmiFlag.pause_flag = false;
|
hmiFlag.pause_flag = false;
|
||||||
|
@ -1960,7 +1960,7 @@ void dwinRedrawScreen() {
|
||||||
|
|
||||||
void gotoConfirmToPrint() {
|
void gotoConfirmToPrint() {
|
||||||
#if HAS_GCODE_PREVIEW
|
#if HAS_GCODE_PREVIEW
|
||||||
if (hmiData.enablePreview) return gotoPopup(Preview_DrawFromSD, onClickConfirmToPrint);
|
if (hmiData.enablePreview) return gotoPopup(preview.drawFromSD, onClickConfirmToPrint);
|
||||||
#endif
|
#endif
|
||||||
card.openAndPrintFile(card.filename); // Direct print SD file
|
card.openAndPrintFile(card.filename); // Direct print SD file
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
#if ALL(DWIN_LCD_PROUI, HAS_GCODE_PREVIEW)
|
#if ALL(DWIN_LCD_PROUI, HAS_GCODE_PREVIEW)
|
||||||
|
|
||||||
|
#include "gcode_preview.h"
|
||||||
|
|
||||||
#include "../../../core/types.h"
|
#include "../../../core/types.h"
|
||||||
#include "../../marlinui.h"
|
#include "../../marlinui.h"
|
||||||
#include "../../../sd/cardreader.h"
|
#include "../../../sd/cardreader.h"
|
||||||
|
@ -38,78 +40,66 @@
|
||||||
#include "dwin.h"
|
#include "dwin.h"
|
||||||
#include "dwin_popup.h"
|
#include "dwin_popup.h"
|
||||||
#include "base64.hpp"
|
#include "base64.hpp"
|
||||||
#include "gcode_preview.h"
|
|
||||||
|
|
||||||
#define THUMBWIDTH 230
|
#define THUMBWIDTH 230
|
||||||
#define THUMBHEIGHT 180
|
#define THUMBHEIGHT 180
|
||||||
|
|
||||||
|
Preview preview;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[13] = ""; // 8.3 + null
|
char name[13] = ""; // 8.3 + null
|
||||||
uint32_t thumbstart = 0;
|
uint32_t thumbstart = 0;
|
||||||
int thumbsize = 0;
|
int thumbsize = 0;
|
||||||
int thumbheight = 0;
|
int thumbheight = 0, thumbwidth = 0;
|
||||||
int thumbwidth = 0;
|
|
||||||
uint8_t *thumbdata = nullptr;
|
|
||||||
float time = 0;
|
float time = 0;
|
||||||
float filament = 0;
|
float filament = 0;
|
||||||
float layer = 0;
|
float layer = 0;
|
||||||
float width = 0;
|
float width = 0, height = 0, length = 0;
|
||||||
float height = 0;
|
|
||||||
float length = 0;
|
|
||||||
void setname(const char * const fn);
|
|
||||||
void clear();
|
|
||||||
} fileprop_t;
|
|
||||||
fileprop_t fileprop;
|
|
||||||
|
|
||||||
void fileprop_t::setname(const char * const fn) {
|
void setname(const char * const fn) {
|
||||||
const uint8_t len = _MIN(sizeof(name) - 1, strlen(fn));
|
const uint8_t len = _MIN(sizeof(name) - 1, strlen(fn));
|
||||||
memcpy(&name[0], fn, len);
|
memcpy(name, fn, len);
|
||||||
name[len] = '\0';
|
name[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileprop_t::clear() {
|
void clear() {
|
||||||
fileprop.name[0] = '\0';
|
fileprop.name[0] = '\0';
|
||||||
fileprop.thumbstart = 0;
|
fileprop.thumbstart = 0;
|
||||||
fileprop.thumbsize = 0;
|
fileprop.thumbsize = 0;
|
||||||
fileprop.thumbheight = 0;
|
fileprop.thumbheight = fileprop.thumbwidth = 0;
|
||||||
fileprop.thumbwidth = 0;
|
|
||||||
fileprop.thumbdata = nullptr;
|
|
||||||
fileprop.time = 0;
|
fileprop.time = 0;
|
||||||
fileprop.filament = 0;
|
fileprop.filament = 0;
|
||||||
fileprop.layer = 0;
|
fileprop.layer = 0;
|
||||||
fileprop.height = 0;
|
fileprop.height = fileprop.width = fileprop.length = 0;
|
||||||
fileprop.width = 0;
|
|
||||||
fileprop.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get_Value(char *buf, const char * const key, float &value) {
|
} fileprop_t;
|
||||||
|
|
||||||
|
fileprop_t fileprop;
|
||||||
|
|
||||||
|
void getValue(const char * const buf, PGM_P const key, float &value) {
|
||||||
|
if (value != 0.0f) return;
|
||||||
|
|
||||||
|
char *posptr = strstr_P(buf, key);
|
||||||
|
if (posptr == nullptr) return;
|
||||||
|
|
||||||
char num[10] = "";
|
char num[10] = "";
|
||||||
char * posptr = 0;
|
for (uint8_t i = 0; i < sizeof(num);) {
|
||||||
uint8_t i = 0;
|
const char c = *posptr;
|
||||||
if (!!value) return;
|
if (ISEOL(c) || c == '\0') {
|
||||||
posptr = strstr(buf, key);
|
|
||||||
if (posptr != nullptr) {
|
|
||||||
while (i < sizeof(num)) {
|
|
||||||
char c = posptr[0];
|
|
||||||
if (!ISEOL(c) && (c != 0)) {
|
|
||||||
if ((c > 47 && c < 58) || (c == '.')) num[i++] = c;
|
|
||||||
posptr++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
num[i] = '\0';
|
num[i] = '\0';
|
||||||
value = atof(num);
|
value = atof(num);
|
||||||
return;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (WITHIN(c, '0', '9') || c == '.') num[i++] = c;
|
||||||
|
posptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Has_Preview() {
|
bool Preview::hasPreview() {
|
||||||
const char * tbstart = "; thumbnail begin " STRINGIFY(THUMBWIDTH) "x" STRINGIFY(THUMBHEIGHT);
|
const char * const tbstart = PSTR("; thumbnail begin " STRINGIFY(THUMBWIDTH) "x" STRINGIFY(THUMBHEIGHT));
|
||||||
char * posptr = 0;
|
char *posptr = nullptr;
|
||||||
uint8_t nbyte = 1;
|
|
||||||
uint32_t indx = 0;
|
uint32_t indx = 0;
|
||||||
char buf[256];
|
|
||||||
float tmp = 0;
|
float tmp = 0;
|
||||||
|
|
||||||
fileprop.clear();
|
fileprop.clear();
|
||||||
|
@ -117,30 +107,32 @@ bool Has_Preview() {
|
||||||
|
|
||||||
card.openFileRead(fileprop.name);
|
card.openFileRead(fileprop.name);
|
||||||
|
|
||||||
while ((nbyte > 0) && (indx < 4 * sizeof(buf)) && !fileprop.thumbstart) {
|
char buf[256];
|
||||||
|
uint8_t nbyte = 1;
|
||||||
|
while (!fileprop.thumbstart && nbyte > 0 && indx < 4 * sizeof(buf)) {
|
||||||
nbyte = card.read(buf, sizeof(buf) - 1);
|
nbyte = card.read(buf, sizeof(buf) - 1);
|
||||||
if (nbyte > 0) {
|
if (nbyte > 0) {
|
||||||
buf[nbyte] = '\0';
|
buf[nbyte] = '\0';
|
||||||
Get_Value(buf, ";TIME:", fileprop.time);
|
getValue(buf, PSTR(";TIME:"), fileprop.time);
|
||||||
Get_Value(buf, ";Filament used:", fileprop.filament);
|
getValue(buf, PSTR(";Filament used:"), fileprop.filament);
|
||||||
Get_Value(buf, ";Layer height:", fileprop.layer);
|
getValue(buf, PSTR(";Layer height:"), fileprop.layer);
|
||||||
Get_Value(buf, ";MINX:", tmp);
|
getValue(buf, PSTR(";MINX:"), tmp);
|
||||||
Get_Value(buf, ";MAXX:", fileprop.width);
|
getValue(buf, PSTR(";MAXX:"), fileprop.width);
|
||||||
fileprop.width -= tmp;
|
fileprop.width -= tmp;
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
Get_Value(buf, ";MINY:", tmp);
|
getValue(buf, PSTR(";MINY:"), tmp);
|
||||||
Get_Value(buf, ";MAXY:", fileprop.length);
|
getValue(buf, PSTR(";MAXY:"), fileprop.length);
|
||||||
fileprop.length -= tmp;
|
fileprop.length -= tmp;
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
Get_Value(buf, ";MINZ:", tmp);
|
getValue(buf, PSTR(";MINZ:"), tmp);
|
||||||
Get_Value(buf, ";MAXZ:", fileprop.height);
|
getValue(buf, PSTR(";MAXZ:"), fileprop.height);
|
||||||
fileprop.height -= tmp;
|
fileprop.height -= tmp;
|
||||||
posptr = strstr(buf, tbstart);
|
posptr = strstr_P(buf, tbstart);
|
||||||
if (posptr != nullptr) {
|
if (posptr != nullptr) {
|
||||||
fileprop.thumbstart = indx + (posptr - &buf[0]);
|
fileprop.thumbstart = indx + (posptr - &buf[0]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
indx += _MAX(10, nbyte - (signed)strlen(tbstart));
|
indx += _MAX(10, nbyte - (signed)strlen_P(tbstart));
|
||||||
card.setIndex(indx);
|
card.setIndex(indx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,98 +141,89 @@ bool Has_Preview() {
|
||||||
if (!fileprop.thumbstart) {
|
if (!fileprop.thumbstart) {
|
||||||
card.closefile();
|
card.closefile();
|
||||||
LCD_MESSAGE_F("Thumbnail not found");
|
LCD_MESSAGE_F("Thumbnail not found");
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the size of the thumbnail
|
// Get the size of the thumbnail
|
||||||
card.setIndex(fileprop.thumbstart + strlen(tbstart));
|
card.setIndex(fileprop.thumbstart + strlen_P(tbstart));
|
||||||
for (uint8_t i = 0; i < 16; i++) {
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
char c = card.get();
|
const char c = card.get();
|
||||||
if (!ISEOL(c)) {
|
if (ISEOL(c)) { buf[i] = '\0'; break; }
|
||||||
buf[i] = c;
|
buf[i] = c;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
buf[i] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fileprop.thumbsize = atoi(buf);
|
fileprop.thumbsize = atoi(buf);
|
||||||
|
|
||||||
// Exit if there isn't a thumbnail
|
// Exit if there isn't a thumbnail
|
||||||
if (!fileprop.thumbsize) {
|
if (!fileprop.thumbsize) {
|
||||||
card.closefile();
|
card.closefile();
|
||||||
LCD_MESSAGE_F("Invalid Thumbnail Size");
|
LCD_MESSAGE_F("Invalid Thumbnail Size");
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t readed = 0;
|
|
||||||
uint8_t buf64[fileprop.thumbsize];
|
uint8_t buf64[fileprop.thumbsize];
|
||||||
|
uint16_t nread = 0;
|
||||||
fileprop.thumbdata = new uint8_t[3 + 3 * (fileprop.thumbsize / 4)]; // Reserve space for the JPEG thumbnail
|
while (nread < fileprop.thumbsize) {
|
||||||
|
const uint8_t c = card.get();
|
||||||
while (readed < fileprop.thumbsize) {
|
if (!ISEOL(c) && c != ';' && c != ' ')
|
||||||
uint8_t c = card.get();
|
buf64[nread++] = c;
|
||||||
if (!ISEOL(c) && (c != ';') && (c != ' ')) {
|
|
||||||
buf64[readed] = c;
|
|
||||||
readed++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
card.closefile();
|
card.closefile();
|
||||||
buf64[readed] = 0;
|
buf64[nread] = '\0';
|
||||||
|
|
||||||
|
uint8_t thumbdata[3 + 3 * (fileprop.thumbsize / 4)]; // Reserve space for the JPEG thumbnail
|
||||||
|
fileprop.thumbsize = decode_base64(buf64, thumbdata);
|
||||||
|
DWINUI::writeToSRAM(0x00, fileprop.thumbsize, thumbdata);
|
||||||
|
|
||||||
fileprop.thumbwidth = THUMBWIDTH;
|
fileprop.thumbwidth = THUMBWIDTH;
|
||||||
fileprop.thumbheight = THUMBHEIGHT;
|
fileprop.thumbheight = THUMBHEIGHT;
|
||||||
fileprop.thumbsize = decode_base64(buf64, fileprop.thumbdata); card.closefile();
|
|
||||||
DWINUI::WriteToSRAM(0x00, fileprop.thumbsize, fileprop.thumbdata);
|
|
||||||
delete[] fileprop.thumbdata;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preview_DrawFromSD() {
|
void Preview::drawFromSD() {
|
||||||
if (Has_Preview()) {
|
if (!hasPreview()) {
|
||||||
|
hmiFlag.select_flag = 1;
|
||||||
|
wait_for_user = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MString<45> buf;
|
MString<45> buf;
|
||||||
char str_1[6] = "", str_2[6] = "", str_3[6] = "";
|
|
||||||
dwinDrawRectangle(1, hmiData.colorBackground, 0, 0, DWIN_WIDTH, STATUS_Y - 1);
|
dwinDrawRectangle(1, hmiData.colorBackground, 0, 0, DWIN_WIDTH, STATUS_Y - 1);
|
||||||
if (fileprop.time) {
|
if (fileprop.time) {
|
||||||
buf.setf(F("Estimated time: %i:%02i"), (uint16_t)fileprop.time / 3600, ((uint16_t)fileprop.time % 3600) / 60);
|
buf.setf(F("Estimated time: %i:%02i"), (uint16_t)fileprop.time / 3600, ((uint16_t)fileprop.time % 3600) / 60);
|
||||||
DWINUI::drawString(20, 10, &buf);
|
DWINUI::drawString(20, 10, &buf);
|
||||||
}
|
}
|
||||||
if (fileprop.filament) {
|
if (fileprop.filament) {
|
||||||
buf.setf(F("Filament used: %s m"), dtostrf(fileprop.filament, 1, 2, str_1));
|
buf.set(F("Filament used: "), p_float_t(fileprop.filament, 2), F(" m"));
|
||||||
DWINUI::drawString(20, 30, &buf);
|
DWINUI::drawString(20, 30, &buf);
|
||||||
}
|
}
|
||||||
if (fileprop.layer) {
|
if (fileprop.layer) {
|
||||||
buf.setf(F("Layer height: %s mm"), dtostrf(fileprop.layer, 1, 2, str_1));
|
buf.set(F("Layer height: "), p_float_t(fileprop.layer, 2), F(" mm"));
|
||||||
DWINUI::drawString(20, 50, &buf);
|
DWINUI::drawString(20, 50, &buf);
|
||||||
}
|
}
|
||||||
if (fileprop.width) {
|
if (fileprop.width) {
|
||||||
buf.setf(F("Volume: %sx%sx%s mm"), dtostrf(fileprop.width, 1, 1, str_1), dtostrf(fileprop.length, 1, 1, str_2), dtostrf(fileprop.height, 1, 1, str_3));
|
buf.set(F("Volume: "), p_float_t(fileprop.width, 1), 'x', p_float_t(fileprop.length, 1), 'x', p_float_t(fileprop.height, 1), F(" mm"));
|
||||||
DWINUI::drawString(20, 70, &buf);
|
DWINUI::drawString(20, 70, &buf);
|
||||||
}
|
}
|
||||||
DWINUI::drawButton(BTN_Print, 26, 290);
|
DWINUI::drawButton(BTN_Print, 26, 290);
|
||||||
DWINUI::drawButton(BTN_Cancel, 146, 290);
|
DWINUI::drawButton(BTN_Cancel, 146, 290);
|
||||||
Preview_Show();
|
show();
|
||||||
drawSelectHighlight(true, 290);
|
drawSelectHighlight(true, 290);
|
||||||
dwinUpdateLCD();
|
dwinUpdateLCD();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
hmiFlag.select_flag = 1;
|
|
||||||
wait_for_user = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Preview_Invalidate() {
|
void Preview::invalidate() {
|
||||||
fileprop.thumbsize = 0;
|
fileprop.thumbsize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Preview_Valid() {
|
bool Preview::valid() {
|
||||||
return !!fileprop.thumbsize;
|
return !!fileprop.thumbsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preview_Show() {
|
void Preview::show() {
|
||||||
const uint8_t xpos = (DWIN_WIDTH - fileprop.thumbwidth) / 2;
|
const uint8_t xpos = ((DWIN_WIDTH) - fileprop.thumbwidth) / 2,
|
||||||
const uint8_t ypos = (205 - fileprop.thumbheight) / 2 + 87;
|
ypos = (205 - fileprop.thumbheight) / 2 + 87;
|
||||||
dwinIconShow(xpos, ypos, 0x00);
|
dwinIconShow(xpos, ypos, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // HAS_GCODE_PREVIEW && DWIN_LCD_PROUI
|
#endif // DWIN_LCD_PROUI && HAS_GCODE_PREVIEW
|
||||||
|
|
|
@ -28,7 +28,14 @@
|
||||||
* Date: 2022/09/03
|
* Date: 2022/09/03
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Preview_DrawFromSD();
|
class Preview {
|
||||||
void Preview_Invalidate();
|
public:
|
||||||
bool Preview_Valid();
|
static void drawFromSD();
|
||||||
void Preview_Show();
|
static void invalidate();
|
||||||
|
static bool valid();
|
||||||
|
static void show();
|
||||||
|
private:
|
||||||
|
static bool hasPreview();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Preview preview;
|
||||||
|
|
Loading…
Add table
Reference in a new issue