diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index f811545ef66..6e0205bdfb3 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -297,16 +297,17 @@ public: } #endif + #if HAS_PRINT_PROGRESS_PERMYRIAD + typedef uint16_t progress_t; + #define PROGRESS_SCALE 100U + #define PROGRESS_MASK 0x7FFF + #else + typedef uint8_t progress_t; + #define PROGRESS_SCALE 1U + #define PROGRESS_MASK 0x7F + #endif + #if HAS_PRINT_PROGRESS - #if HAS_PRINT_PROGRESS_PERMYRIAD - typedef uint16_t progress_t; - #define PROGRESS_SCALE 100U - #define PROGRESS_MASK 0x7FFF - #else - typedef uint8_t progress_t; - #define PROGRESS_SCALE 1U - #define PROGRESS_MASK 0x7F - #endif #if ENABLED(SET_PROGRESS_PERCENT) static progress_t progress_override; static void set_progress(const progress_t p) { progress_override = _MIN(p, 100U * (PROGRESS_SCALE)); } diff --git a/Marlin/src/lcd/tft/bitmaps/time_elapsed.bmp b/Marlin/src/lcd/tft/bitmaps/time_elapsed.bmp new file mode 100644 index 00000000000..6bb4b1a4394 Binary files /dev/null and b/Marlin/src/lcd/tft/bitmaps/time_elapsed.bmp differ diff --git a/Marlin/src/lcd/tft/bitmaps/time_elapsed.svg b/Marlin/src/lcd/tft/bitmaps/time_elapsed.svg new file mode 100644 index 00000000000..da2d37b56b6 --- /dev/null +++ b/Marlin/src/lcd/tft/bitmaps/time_elapsed.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Marlin/src/lcd/tft/bitmaps/time_remaining.bmp b/Marlin/src/lcd/tft/bitmaps/time_remaining.bmp new file mode 100644 index 00000000000..36e40c9c573 Binary files /dev/null and b/Marlin/src/lcd/tft/bitmaps/time_remaining.bmp differ diff --git a/Marlin/src/lcd/tft/bitmaps/time_remaining.svg b/Marlin/src/lcd/tft/bitmaps/time_remaining.svg new file mode 100644 index 00000000000..ff4cdb8e24d --- /dev/null +++ b/Marlin/src/lcd/tft/bitmaps/time_remaining.svg @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Marlin/src/lcd/tft/images/time_elapsed_32x32x4.cpp b/Marlin/src/lcd/tft/images/time_elapsed_32x32x4.cpp new file mode 100644 index 00000000000..e6626f4c876 --- /dev/null +++ b/Marlin/src/lcd/tft/images/time_elapsed_32x32x4.cpp @@ -0,0 +1,57 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * 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 . + **/ + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_GRAPHICAL_TFT + +extern const uint8_t time_elapsed_32x32x4[512] = { + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xad, 0xca, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8a, 0xff, 0xff, 0xfe, 0xb8, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xce, 0xc8, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8a, 0xff, 0xfa, 0x6a, 0xff, 0xff, 0xff, 0xff, 0xff, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8a, 0xff, 0xfa, 0x58, 0x9d, 0xcd, 0xff, 0xff, 0xff, 0xf9, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xdf, 0xe6, 0x58, 0x85, 0x55, 0x69, 0xff, 0xff, 0xff, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xbb, 0x88, 0x66, 0x55, 0x68, 0x88, 0x88, 0x76, 0x6b, 0xff, 0xff, 0xf6, 0x88, 0x88, + 0x88, 0x8c, 0xff, 0xe6, 0x87, 0x67, 0x88, 0x88, 0x88, 0x88, 0x86, 0x9f, 0xff, 0xfd, 0x68, 0x88, + 0x88, 0x8e, 0xff, 0xf7, 0x68, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8b, 0xff, 0xff, 0x67, 0x88, + 0x88, 0x8b, 0xff, 0xd5, 0x68, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0xff, 0xb6, 0x88, + 0x88, 0x88, 0x89, 0x65, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaf, 0xff, 0xe5, 0x88, + 0x88, 0x88, 0x76, 0x56, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8f, 0xff, 0xf7, 0x78, + 0x88, 0x9c, 0x98, 0x88, 0x88, 0x88, 0x88, 0x9e, 0xdb, 0x98, 0x88, 0x88, 0x8d, 0xff, 0xf8, 0x68, + 0x89, 0xff, 0xf8, 0x88, 0x88, 0x88, 0x89, 0xff, 0xff, 0xff, 0xec, 0xa9, 0x8d, 0xff, 0xfa, 0x68, + 0x8b, 0xff, 0xfa, 0x68, 0x88, 0x88, 0x8c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xff, 0xfd, 0x58, + 0x89, 0xff, 0xf7, 0x58, 0x88, 0x88, 0x89, 0xff, 0xff, 0xff, 0xeb, 0x96, 0x59, 0xff, 0xf9, 0x58, + 0x88, 0x89, 0x75, 0x68, 0x88, 0x88, 0x88, 0x8d, 0xda, 0x86, 0x55, 0x55, 0x67, 0x9c, 0x95, 0x58, + 0x88, 0x86, 0x56, 0x88, 0x88, 0x88, 0x88, 0x86, 0x55, 0x56, 0x67, 0x88, 0x88, 0x75, 0x55, 0x78, + 0x88, 0x88, 0xbb, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8b, 0xa8, 0x88, 0x88, + 0x88, 0x8c, 0xff, 0xe6, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xef, 0xfb, 0x78, 0x88, + 0x88, 0x8e, 0xff, 0xf6, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0xfd, 0x58, 0x88, + 0x88, 0x8b, 0xff, 0xd5, 0x68, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xef, 0xfa, 0x57, 0x88, + 0x88, 0x88, 0x89, 0x65, 0x79, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x95, 0x58, 0x88, + 0x88, 0x88, 0x76, 0x58, 0xef, 0xe8, 0x88, 0x88, 0x88, 0x88, 0xef, 0xd8, 0x86, 0x55, 0x78, 0x88, + 0x88, 0x88, 0x88, 0x8b, 0xff, 0xf9, 0x68, 0x9b, 0x98, 0x8b, 0xff, 0xf9, 0x68, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8a, 0xff, 0xf8, 0x59, 0xff, 0xf8, 0x8b, 0xff, 0xf8, 0x58, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xad, 0xa5, 0x5b, 0xff, 0xf9, 0x68, 0xbe, 0xa5, 0x68, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x75, 0x55, 0x79, 0xff, 0xf7, 0x58, 0x75, 0x55, 0x78, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x78, 0x88, 0x8a, 0x75, 0x68, 0x88, 0x78, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x86, 0x56, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, +}; +#endif // HAS_GRAPHICAL_TFT diff --git a/Marlin/src/lcd/tft/images/time_remaining_32x32x4.cpp b/Marlin/src/lcd/tft/images/time_remaining_32x32x4.cpp new file mode 100644 index 00000000000..8c64403a2bb --- /dev/null +++ b/Marlin/src/lcd/tft/images/time_remaining_32x32x4.cpp @@ -0,0 +1,57 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * 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 . + **/ + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_GRAPHICAL_TFT + +extern const uint8_t time_remaining_32x32x4[512] = { + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x9a, 0xbd, 0xb8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x89, 0xce, 0xff, 0xff, 0xf9, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xef, 0xff, 0xff, 0xff, 0xfd, 0x58, 0xbe, 0xb8, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x5a, 0xff, 0xf9, 0x78, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x8a, 0xff, 0xff, 0xff, 0xfd, 0xcd, 0x95, 0x5b, 0xff, 0xfa, 0x58, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x9f, 0xff, 0xff, 0xf9, 0x65, 0x55, 0x55, 0x78, 0xef, 0xe6, 0x58, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xff, 0xff, 0xfb, 0x55, 0x56, 0x78, 0x88, 0x88, 0x67, 0x55, 0x6a, 0x98, 0x88, 0x88, + 0x88, 0x8e, 0xff, 0xff, 0x95, 0x56, 0x88, 0x88, 0x88, 0x88, 0x86, 0x66, 0xdf, 0xfa, 0x78, 0x88, + 0x88, 0x9f, 0xff, 0xfb, 0x55, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0xfe, 0x58, 0x88, + 0x88, 0xcf, 0xff, 0xf5, 0x57, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xef, 0xfc, 0x57, 0x88, + 0x88, 0xef, 0xff, 0x95, 0x68, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8b, 0xa6, 0x57, 0x88, + 0x89, 0xff, 0xff, 0x65, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x86, 0x55, 0x68, 0x88, + 0x8a, 0xff, 0xfd, 0x56, 0x88, 0x88, 0xac, 0xdd, 0x88, 0x88, 0x88, 0x88, 0x88, 0x9b, 0x98, 0x88, + 0x8c, 0xff, 0xfc, 0x58, 0xbd, 0xef, 0xff, 0xff, 0xf7, 0x88, 0x88, 0x88, 0x89, 0xff, 0xf8, 0x88, + 0x8d, 0xff, 0xfd, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x68, 0x88, 0x88, 0x8b, 0xff, 0xfa, 0x68, + 0x8a, 0xff, 0xf9, 0x57, 0x9c, 0xef, 0xff, 0xff, 0xf6, 0x58, 0x88, 0x88, 0x89, 0xff, 0xf8, 0x58, + 0x88, 0x9c, 0x85, 0x57, 0x65, 0x56, 0x8a, 0xdd, 0x75, 0x68, 0x88, 0x88, 0x88, 0x8a, 0x85, 0x68, + 0x88, 0x75, 0x55, 0x88, 0x88, 0x87, 0x66, 0x55, 0x56, 0x88, 0x88, 0x88, 0x88, 0x86, 0x56, 0x88, + 0x88, 0x88, 0xbb, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8b, 0xa8, 0x88, 0x88, + 0x88, 0x8c, 0xff, 0xe6, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xef, 0xfb, 0x78, 0x88, + 0x88, 0x8e, 0xff, 0xf6, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0xfd, 0x58, 0x88, + 0x88, 0x8b, 0xff, 0xd5, 0x68, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xef, 0xfa, 0x57, 0x88, + 0x88, 0x88, 0x89, 0x65, 0x79, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x95, 0x58, 0x88, + 0x88, 0x88, 0x76, 0x58, 0xef, 0xe8, 0x88, 0x88, 0x88, 0x88, 0xef, 0xd8, 0x86, 0x55, 0x78, 0x88, + 0x88, 0x88, 0x88, 0x8b, 0xff, 0xf9, 0x68, 0x9b, 0x98, 0x8b, 0xff, 0xf9, 0x68, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8a, 0xff, 0xf8, 0x59, 0xff, 0xf8, 0x8b, 0xff, 0xf8, 0x58, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xad, 0xa5, 0x5b, 0xff, 0xf9, 0x68, 0xbe, 0xa5, 0x68, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x75, 0x55, 0x79, 0xff, 0xf7, 0x58, 0x75, 0x55, 0x78, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x78, 0x88, 0x8a, 0x75, 0x68, 0x88, 0x78, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x86, 0x56, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, +}; +#endif // HAS_GRAPHICAL_TFT diff --git a/Marlin/src/lcd/tft/tft_image.cpp b/Marlin/src/lcd/tft/tft_image.cpp index 507b5f582c7..6309de032eb 100644 --- a/Marlin/src/lcd/tft/tft_image.cpp +++ b/Marlin/src/lcd/tft/tft_image.cpp @@ -72,6 +72,8 @@ const tImage Left_32x32x4 = { (void *)left_32x32x4, 32, 32, GREYSCALE4 const tImage Right_32x32x4 = { (void *)right_32x32x4, 32, 32, GREYSCALE4 }; const tImage Refresh_32x32x4 = { (void *)refresh_32x32x4, 32, 32, GREYSCALE4 }; const tImage Leveling_32x32x4 = { (void *)leveling_32x32x4, 32, 32, GREYSCALE4 }; +const tImage Time_Elapsed_32x32x4 = { (void *)time_elapsed_32x32x4, 32, 32, GREYSCALE4 }; +const tImage Time_Remaining_32x32x4 = { (void *)time_remaining_32x32x4, 32, 32, GREYSCALE4 }; const tImage Slider8x16x4 = { (void *)slider_8x16x4, 8, 16, GREYSCALE4 }; @@ -108,6 +110,8 @@ const tImage images[imgCount] = { Home_64x64x4, BtnRounded_64x52x4, BtnRounded_42x39x4, + Time_Elapsed_32x32x4, + Time_Remaining_32x32x4, }; #endif // HAS_GRAPHICAL_TFT diff --git a/Marlin/src/lcd/tft/tft_image.h b/Marlin/src/lcd/tft/tft_image.h index d202e3d0f61..7761a72dc34 100644 --- a/Marlin/src/lcd/tft/tft_image.h +++ b/Marlin/src/lcd/tft/tft_image.h @@ -61,6 +61,8 @@ extern const uint8_t left_32x32x4[]; extern const uint8_t right_32x32x4[]; extern const uint8_t refresh_32x32x4[]; extern const uint8_t leveling_32x32x4[]; +extern const uint8_t time_elapsed_32x32x4[]; +extern const uint8_t time_remaining_32x32x4[]; extern const uint8_t slider_8x16x4[]; @@ -97,6 +99,9 @@ enum MarlinImage : uint8_t { imgHome, imgBtn52Rounded, imgBtn39Rounded, + imgTimeElapsed, + imgTimeRemaining, + // Special values - must be at the end! imgCount, noImage = imgCount, imgPageUp = imgLeft, @@ -172,6 +177,8 @@ extern const tImage Left_32x32x4; extern const tImage Right_32x32x4; extern const tImage Refresh_32x32x4; extern const tImage Leveling_32x32x4; +extern const tImage Time_Elapsed_32x32x4; +extern const tImage Time_Remaining_32x32x4; extern const tImage Slider8x16x4; diff --git a/Marlin/src/lcd/tft/ui_1024x600.cpp b/Marlin/src/lcd/tft/ui_1024x600.cpp index b5d12cdab35..ddb606674cc 100644 --- a/Marlin/src/lcd/tft/ui_1024x600.cpp +++ b/Marlin/src/lcd/tft/ui_1024x600.cpp @@ -315,14 +315,14 @@ void MarlinUI::draw_status_screen() { y += 100; // Feed rate - tft.canvas(274, y, 128, 32); + tft.canvas(274, y, 200, 32); tft.set_background(COLOR_BACKGROUND); uint16_t color = feedrate_percentage == 100 ? COLOR_RATE_100 : COLOR_RATE_ALTERED; tft.add_image(0, 0, imgFeedRate, color); tft_string.set(i16tostr3rj(feedrate_percentage)); tft_string.add('%'); tft.add_text(36, 1, color, tft_string); - TERN_(TOUCH_SCREEN, touch.add_control(FEEDRATE, 274, y, 128, 32)); + TERN_(TOUCH_SCREEN, touch.add_control(FEEDRATE, 274, y, 200, 32)); // Flow rate #if HAS_EXTRUDERS @@ -333,7 +333,7 @@ void MarlinUI::draw_status_screen() { tft_string.set(i16tostr3rj(planner.flow_percentage[active_extruder])); tft_string.add('%'); tft.add_text(36, 1, color, tft_string); - TERN_(TOUCH_SCREEN, touch.add_control(FLOWRATE, 650, y, 128, 32, active_extruder)); + TERN_(TOUCH_SCREEN, touch.add_control(FLOWRATE, 650, y, 200, 32, active_extruder)); #endif #if ENABLED(TOUCH_SCREEN) @@ -348,32 +348,115 @@ void MarlinUI::draw_status_screen() { #endif y += 100; - // Print duration - char buffer[14]; - duration_t elapsed = print_job_timer.duration(); - elapsed.toDigital(buffer); + const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)(); + #if ENABLED(SHOW_ELAPSED_TIME) && DISABLED(SHOW_REMAINING_TIME) + // Print duration so far (time elapsed) - centered + char elapsed_str[22]; + duration_t elapsed = print_job_timer.duration(); + elapsed.toString(elapsed_str); - tft.canvas((TFT_WIDTH - 128) / 2, y, 128, 29); - tft.set_background(COLOR_BACKGROUND); - tft_string.set(buffer); - tft.add_text(tft_string.center(128), 0, COLOR_PRINT_TIME, tft_string); + // Same width constraints as feedrate/flowrate controls + constexpr uint16_t time_str_width = 476, image_width = 36; + + tft.canvas((TFT_WIDTH - time_str_width) / 2, y, time_str_width, 32); + tft.set_background(COLOR_BACKGROUND); + tft_string.set(elapsed_str); + uint16_t text_pos_x = tft_string.center(time_str_width - image_width); + tft.add_image(text_pos_x, 0, imgTimeElapsed, COLOR_PRINT_TIME); + tft.add_text(text_pos_x + image_width, 1, COLOR_PRINT_TIME, tft_string); + + #elif DISABLED(SHOW_ELAPSED_TIME) && ENABLED(SHOW_REMAINING_TIME) + // Print time remaining estimation - centered + char estimate_str[22]; + duration_t elapsed = print_job_timer.duration(); + + // Get the estimate, first from M73 + uint32_t estimate_remaining = (0 + #if ALL(SET_PROGRESS_MANUALLY, SET_REMAINING_TIME) + + get_remaining_time() + #endif + ); + // If no M73 estimate is available but we have progress data, calculate time remaining assuming time elapsed is linear with progress + if (!estimate_remaining && progress > 0) + estimate_remaining = elapsed.value * (100 * (PROGRESS_SCALE) - progress) / progress; + + // Generate estimate string + if (!estimate_remaining) + tft_string.set("-"); + else { + duration_t estimation = estimate_remaining; + estimation.toString(estimate_str); + tft_string.set(estimate_str); + } + + // Same width constraints as feedrate/flowrate controls + constexpr uint16_t time_str_width = 476, image_width = 36; + + tft.canvas((TFT_WIDTH - time_str_width) / 2, y, time_str_width, 32); + tft.set_background(COLOR_BACKGROUND); + color = printingIsActive() ? COLOR_PRINT_TIME : COLOR_INACTIVE; + uint16_t text_pos_x = tft_string.center(time_str_width - image_width); + tft.add_image(text_pos_x, 0, imgTimeRemaining, color); + tft.add_text(text_pos_x + image_width, 1, color, tft_string); + + #elif ALL(SHOW_REMAINING_TIME, SHOW_ELAPSED_TIME) + // Print duration so far (time elapsed) - aligned under feed rate + char elapsed_str[22]; + duration_t elapsed = print_job_timer.duration(); + elapsed.toString(elapsed_str); + + tft.canvas(274, y, 200, 32); + tft.set_background(COLOR_BACKGROUND); + tft.add_image(0, 0, imgTimeElapsed, COLOR_PRINT_TIME); + tft_string.set(elapsed_str); + tft.add_text(36, 1, COLOR_PRINT_TIME, tft_string); + + // Print time remaining estimation - aligned under flow rate + char estimate_str[22]; + + // Get the estimate, first from M73 + uint32_t estimate_remaining = (0 + #if ALL(SET_PROGRESS_MANUALLY, SET_REMAINING_TIME) + + get_remaining_time() + #endif + ); + // If no M73 estimate is available but we have progress data, calculate time remaining assuming time elapsed is linear with progress + if (!estimate_remaining && progress > 0) + estimate_remaining = elapsed.value * (100 * (PROGRESS_SCALE) - progress) / progress; + + // Generate estimate string + if (!estimate_remaining) + tft_string.set("-"); + else { + duration_t estimation = estimate_remaining; + estimation.toString(estimate_str); + tft_string.set(estimate_str); + } + + // Push out the estimate to the screen + tft.canvas(650, y, 200, 32); + tft.set_background(COLOR_BACKGROUND); + color = printingIsActive() ? COLOR_PRINT_TIME : COLOR_INACTIVE; + tft.add_image(0, 0, imgTimeRemaining, color); + tft.add_text(36, 1, color, tft_string); + #endif y += 50; // Progress bar - const uint8_t progress = ui.get_progress_percent(); tft.canvas(4, y, TFT_WIDTH - 8, 9); tft.set_background(COLOR_PROGRESS_BG); tft.add_rectangle(0, 0, TFT_WIDTH - 8, 9, COLOR_PROGRESS_FRAME); if (progress) - tft.add_bar(1, 1, ((TFT_WIDTH - 10) * progress) / 100, 7, COLOR_PROGRESS_BAR); + tft.add_bar(1, 1, ((TFT_WIDTH - 10) * progress / (PROGRESS_SCALE)) / 100, 7, COLOR_PROGRESS_BAR); y += 50; // Status message - tft.canvas(0, y, TFT_WIDTH, FONT_LINE_HEIGHT); + const uint16_t status_height = TFT_HEIGHT - y; + tft.canvas(0, y, TFT_WIDTH, status_height); tft.set_background(COLOR_BACKGROUND); tft_string.set(status_message); tft_string.trim(); - tft.add_text(tft_string.center(TFT_WIDTH), 0, COLOR_STATUS_MESSAGE, tft_string); + tft.add_text(tft_string.center(TFT_WIDTH), (status_height - FONT_LINE_HEIGHT) / 2, COLOR_STATUS_MESSAGE, tft_string); } // Low-level draw_edit_screen can be used to draw an edit screen from anyplace diff --git a/Marlin/src/lcd/tft/ui_320x240.cpp b/Marlin/src/lcd/tft/ui_320x240.cpp index c39d2265171..dcbfa935b47 100644 --- a/Marlin/src/lcd/tft/ui_320x240.cpp +++ b/Marlin/src/lcd/tft/ui_320x240.cpp @@ -228,7 +228,7 @@ void MarlinUI::draw_status_screen() { TERN_(TOUCH_SCREEN, touch.clear()); // Statuses of heaters and fans - const uint16_t y = TFT_STATUS_TOP_Y; + constexpr uint16_t y = TFT_STATUS_TOP_Y; for (uint16_t i = 0 ; i < ITEMS_COUNT; i++) { const uint16_t x = (TFT_WIDTH / ITEMS_COUNT - 64) / 2 + (TFT_WIDTH * i / ITEMS_COUNT); switch (i) { @@ -278,14 +278,9 @@ void MarlinUI::draw_status_screen() { tft.add_text(TERN(TFT_COLOR_UI_PORTRAIT, 32, 10), tft_string.vcenter(FONT_LINE_HEIGHT), COLOR_AXIS_HOMED, "X"); const bool nhx = axis_should_home(X_AXIS); tft_string.set(blink && nhx ? "?" : ftostr4sign(LOGICAL_X_POSITION(current_position.x))); - tft.add_text( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 32 - tft_string.width() / 2, FONT_LINE_HEIGHT + tft_string.vcenter(FONT_LINE_HEIGHT), - #else - 68 - tft_string.width(), tft_string.vcenter(FONT_LINE_HEIGHT), - #endif - nhx ? COLOR_AXIS_NOT_HOMED : COLOR_AXIS_HOMED, tft_string - ); + uint16_t pos_x = TERN(TFT_COLOR_UI_PORTRAIT, 32 - tft_string.width() / 2, 68 - tft_string.width()), + pos_y = SUM_TERN(TFT_COLOR_UI_PORTRAIT, tft_string.vcenter(FONT_LINE_HEIGHT), FONT_LINE_HEIGHT); + tft.add_text(pos_x, pos_y, nhx ? COLOR_AXIS_NOT_HOMED : COLOR_AXIS_HOMED, tft_string); #endif #if HAS_Y_AXIS @@ -318,31 +313,30 @@ void MarlinUI::draw_status_screen() { tft_string.set(ftostr52sp(z)); offset -= tft_string.width(); } - tft.add_text( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 192 - tft_string.width() / 2, FONT_LINE_HEIGHT + tft_string.vcenter(FONT_LINE_HEIGHT), - #else - 301 - tft_string.width() - offset, tft_string.vcenter(FONT_LINE_HEIGHT), - #endif - nhz ? COLOR_AXIS_NOT_HOMED : COLOR_AXIS_HOMED, tft_string); #endif - TERN_(TOUCH_SCREEN, touch.add_control(MOVE_AXIS, 0, 103, - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 232, FONT_LINE_HEIGHT * 2 - #else - 312, FONT_LINE_HEIGHT - #endif - )); + uint16_t pos_x = TERN(TFT_COLOR_UI_PORTRAIT, 192 - tft_string.width() / 2, 301 - tft_string.width() - offset), + pos_y = SUM_TERN(TFT_COLOR_UI_PORTRAIT, tft_string.vcenter(FONT_LINE_HEIGHT), FONT_LINE_HEIGHT); + tft.add_text(pos_x, pos_y, nhz ? COLOR_AXIS_NOT_HOMED : COLOR_AXIS_HOMED, tft_string); + + // 3rd horizontal group - controls and times (height = 64, top margin = 3) + // 3rd group, subgroup A - controls (on the sides) + #if ENABLED(TOUCH_SCREEN) + width = TERN(TFT_COLOR_UI_PORTRAIT, 232, 312); + height = TERN(TFT_COLOR_UI_PORTRAIT, FONT_LINE_HEIGHT * 2, FONT_LINE_HEIGHT); + touch.add_control(MOVE_AXIS, 0, 103, width, height); + add_control(256, 130, menu_main, imgSettings); + TERN_(SDSUPPORT, add_control(0, 130, menu_media, imgSD, !printingIsActive(), COLOR_CONTROL_ENABLED, card.isMounted() && printingIsActive() ? COLOR_BUSY : COLOR_CONTROL_DISABLED)); + #endif + + // 3rd group, subgroup B - speeds (center, top half) // Feed rate tft.canvas( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 30, 172, 80 - #else - 70, 136, 84 - #endif - , 32 + TERN(TFT_COLOR_UI_PORTRAIT, 30, 70), + TERN(TFT_COLOR_UI_PORTRAIT, 172, 132), + TERN(TFT_COLOR_UI_PORTRAIT, 80, 88), + MENU_ITEM_HEIGHT ); tft.set_background(COLOR_BACKGROUND); uint16_t color = feedrate_percentage == 100 ? COLOR_RATE_100 : COLOR_RATE_ALTERED; @@ -351,88 +345,134 @@ void MarlinUI::draw_status_screen() { tft_string.add('%'); tft.add_text(32, tft_string.vcenter(30), color, tft_string); TERN_(TOUCH_SCREEN, touch.add_control(FEEDRATE, - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 30, 172, 80 - #else - 70, 136, 84 - #endif - , 32 + TERN(TFT_COLOR_UI_PORTRAIT, 30, 70), + TERN(TFT_COLOR_UI_PORTRAIT, 172, 132), + 80, MENU_ITEM_HEIGHT )); // Flow rate - #if HAS_EXTRUDERS - tft.canvas( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 140, 172, 80 - #else - 170, 136, 84 - #endif - , 32 - ); - tft.set_background(COLOR_BACKGROUND); - color = planner.flow_percentage[0] == 100 ? COLOR_RATE_100 : COLOR_RATE_ALTERED; - tft.add_image(0, 0, imgFlowRate, color); - tft_string.set(i16tostr3rj(planner.flow_percentage[active_extruder])); - tft_string.add('%'); - tft.add_text(32, tft_string.vcenter(30), color, tft_string); - TERN_(TOUCH_SCREEN, touch.add_control(FLOWRATE, - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 140, 172, 80 - #else - 170, 136, 84 - #endif - , 32, active_extruder - )); - #endif // HAS_EXTRUDERS - - // Print duration - char buffer[14]; - duration_t elapsed = print_job_timer.duration(); - elapsed.toDigital(buffer); - tft.canvas( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 56, 256, 128 - #else - 96, 173, 128 - #endif - , FONT_LINE_HEIGHT + TERN(TFT_COLOR_UI_PORTRAIT, 140, 162), + TERN(TFT_COLOR_UI_PORTRAIT, 172, 132), + TERN(TFT_COLOR_UI_PORTRAIT, 80, 88), + MENU_ITEM_HEIGHT ); tft.set_background(COLOR_BACKGROUND); - tft_string.set(buffer); - tft.add_text(tft_string.center(128), tft_string.vcenter(FONT_LINE_HEIGHT), COLOR_PRINT_TIME, tft_string); + color = planner.flow_percentage[0] == 100 ? COLOR_RATE_100 : COLOR_RATE_ALTERED; + tft.add_image(0, 0, imgFlowRate, color); + tft_string.set(i16tostr3rj(planner.flow_percentage[active_extruder])); + tft_string.add('%'); + tft.add_text(32, tft_string.vcenter(30), color, tft_string); + #if ENABLED(TOUCH_SCREEN) + touch.add_control(FLOWRATE, + TERN(TFT_COLOR_UI_PORTRAIT, 140, 170), + TERN(TFT_COLOR_UI_PORTRAIT, 172, 132), + 80, MENU_ITEM_HEIGHT, active_extruder + ); + #endif - // Progress bar - const uint8_t progress = ui.get_progress_percent(); - tft.canvas( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 4, 278, 232 - #else - 4, 198, 312 - #endif - , 9 - ); + // 3rd group, subgroup C - times (center, bottom half) + const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)(); + const uint16_t time_str_width = 180, image_width = 34; + pos_x = (TFT_WIDTH - time_str_width) / 2; + pos_y = TERN(TFT_COLOR_UI_PORTRAIT, 256, 164); + #if ENABLED(SHOW_ELAPSED_TIME) && DISABLED(SHOW_REMAINING_TIME) + // Print duration so far (time elapsed) - centered + char elapsed_str[18]; + duration_t elapsed = print_job_timer.duration(); + elapsed.toCompactString(elapsed_str); + + tft.canvas(pos_x, pos_y, time_str_width, MENU_ITEM_HEIGHT); + tft.set_background(COLOR_BACKGROUND); + tft_string.set(elapsed_str); + uint16_t text_pos_x = tft_string.center(time_str_width - image_width); + tft.add_image(text_pos_x, 0, imgTimeElapsed, COLOR_PRINT_TIME); + tft.add_text(text_pos_x + image_width, tft_string.vcenter(FONT_LINE_HEIGHT), COLOR_PRINT_TIME, tft_string); + + #elif DISABLED(SHOW_ELAPSED_TIME) && ENABLED(SHOW_REMAINING_TIME) + // Print time remaining estimation - centered + char estimate_str[18]; + duration_t elapsed = print_job_timer.duration(); + + // Get the estimate, first from M73 + uint32_t estimate_remaining = (0 + #if ALL(SET_PROGRESS_MANUALLY, SET_REMAINING_TIME) + + get_remaining_time() + #endif + ); + // If no M73 estimate is available but we have progress data, calculate time remaining assuming time elapsed is linear with progress + if (!estimate_remaining && progress > 0) + estimate_remaining = elapsed.value * (100 * (PROGRESS_SCALE) - progress) / progress; + + // Generate estimate string + if (!estimate_remaining) + tft_string.set("-"); + else { + duration_t estimation = estimate_remaining; + estimation.toCompactString(estimate_str); + tft_string.set(estimate_str); + } + + tft.canvas(pos_x, pos_y, time_str_width, MENU_ITEM_HEIGHT); + tft.set_background(COLOR_BACKGROUND); + color = printingIsActive() ? COLOR_PRINT_TIME : COLOR_INACTIVE; + uint16_t text_pos_x = tft_string.center(time_str_width - image_width); + tft.add_image(text_pos_x, 0, imgTimeRemaining, color); + tft.add_text(text_pos_x + image_width, tft_string.vcenter(FONT_LINE_HEIGHT), color, tft_string); + + #elif ALL(SHOW_REMAINING_TIME, SHOW_ELAPSED_TIME) + // Print duration so far (time elapsed) - aligned under feed rate + char elapsed_str[18]; + duration_t elapsed = print_job_timer.duration(); + elapsed.toCompactString(elapsed_str); + + tft.canvas(pos_x, pos_y, time_str_width / 2 - 2, MENU_ITEM_HEIGHT); + tft.set_background(COLOR_BACKGROUND); + tft.add_image(0, 0, imgTimeElapsed, COLOR_PRINT_TIME); + tft_string.set(elapsed_str); + tft.add_text(32, tft_string.vcenter(FONT_LINE_HEIGHT), COLOR_PRINT_TIME, tft_string); + + // Print time remaining estimation - aligned under flow rate + char estimate_str[18]; + + // Get the estimate, first from M73 + uint32_t estimate_remaining = (0 + #if ALL(SET_PROGRESS_MANUALLY, SET_REMAINING_TIME) + + get_remaining_time() + #endif + ); + // If no M73 estimate is available but we have progress data, calculate time remaining assuming time elapsed is linear with progress + if (!estimate_remaining && progress > 0) + estimate_remaining = elapsed.value * (100 * (PROGRESS_SCALE) - progress) / progress; + + // Generate estimate string + if (!estimate_remaining) + tft_string.set("-"); + else { + duration_t estimation = estimate_remaining; + estimation.toCompactString(estimate_str); + tft_string.set(estimate_str); + } + + // Push out the estimate to the screen + tft.canvas(pos_x + time_str_width / 2 + 2, pos_y, time_str_width / 2 - 2, MENU_ITEM_HEIGHT); + tft.set_background(COLOR_BACKGROUND); + color = printingIsActive() ? COLOR_PRINT_TIME : COLOR_INACTIVE; + tft.add_image(0, 0, imgTimeRemaining, color); + tft.add_text(32, tft_string.vcenter(FONT_LINE_HEIGHT), color, tft_string); + #endif + + // Fourth horizontal group - progress bar (height = 9, top margin = 4) + pos_y = TERN(TFT_COLOR_UI_PORTRAIT, 278, 198); + tft.canvas(4, pos_y, TFT_WIDTH - 8, 9); tft.set_background(COLOR_PROGRESS_BG); - tft.add_rectangle(0, 0, - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 232, 9 - #else - 312, 9 - #endif - , COLOR_PROGRESS_FRAME - ); + tft.add_rectangle(0, 0, TFT_WIDTH - 8, 9, COLOR_PROGRESS_FRAME); if (progress) - tft.add_bar(1, 1, ((TFT_WIDTH - 10) * progress) / 100, 7, COLOR_PROGRESS_BAR); + tft.add_bar(1, 1, ((TFT_WIDTH - 10) * progress / (PROGRESS_SCALE)) / 100, 7, COLOR_PROGRESS_BAR); // Status message - tft.canvas( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 0, 296, 240 - #else - 0, 212, 320 - #endif - , FONT_LINE_HEIGHT - ); + pos_y += 9 + 7; + tft.canvas(0, pos_y, TFT_WIDTH, TFT_HEIGHT - pos_y); tft.set_background(COLOR_BACKGROUND); tft_string.set(status_message); tft_string.trim(); @@ -441,12 +481,9 @@ void MarlinUI::draw_status_screen() { #if ENABLED(TOUCH_SCREEN) { add_control( - #if ENABLED(TFT_COLOR_UI_PORTRAIT) - 176, 210 - #else - 256, 130 - #endif - , menu_main, imgSettings + TERN(TFT_COLOR_UI_PORTRAIT, 176, 256), + TERN(TFT_COLOR_UI_PORTRAIT, 210, 130), + menu_main, imgSettings ); #if HAS_MEDIA const bool cm = card.isMounted(), pa = printingIsActive(); @@ -552,8 +589,8 @@ void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, con tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string); } #if ENABLED(TOUCH_SCREEN) - if (no) add_control(TERN(TFT_COLOR_UI_PORTRAIT, 16, 48), TFT_HEIGHT - 64, CANCEL, imgCancel, true, yesno ? HALF(COLOR_CONTROL_CANCEL) : COLOR_CONTROL_CANCEL); - if (yes) add_control(TERN(TFT_COLOR_UI_PORTRAIT, 160, 208), TFT_HEIGHT - 64, CONFIRM, imgConfirm, true, yesno ? COLOR_CONTROL_CONFIRM : HALF(COLOR_CONTROL_CONFIRM)); + if (no) add_control(TERN(TFT_COLOR_UI_PORTRAIT, 32,48), TFT_HEIGHT - 64, CANCEL, imgCancel, true, yesno ? HALF(COLOR_CONTROL_CANCEL) : COLOR_CONTROL_CANCEL); + if (yes) add_control(TERN(TFT_COLOR_UI_PORTRAIT, 172, 208), TFT_HEIGHT - 64, CONFIRM, imgConfirm, true, yesno ? COLOR_CONTROL_CONFIRM : HALF(COLOR_CONTROL_CONFIRM)); #endif } diff --git a/Marlin/src/lcd/tft/ui_320x240.h b/Marlin/src/lcd/tft/ui_320x240.h index 555ca3616a0..1d3aa86f812 100644 --- a/Marlin/src/lcd/tft/ui_320x240.h +++ b/Marlin/src/lcd/tft/ui_320x240.h @@ -37,6 +37,7 @@ #define MENU_ITEM_HEIGHT 32 #define MENU_LINE_HEIGHT (MENU_ITEM_HEIGHT + 2) +#define FONT_LINE_HEIGHT 24 #if (TFT_FONT == NOTOSANS) || (TFT_FONT == HELVETICA) #define FONT_SIZE 14 diff --git a/Marlin/src/lcd/tft/ui_480x320.cpp b/Marlin/src/lcd/tft/ui_480x320.cpp index 14d7da7ee43..8e554cf413a 100644 --- a/Marlin/src/lcd/tft/ui_480x320.cpp +++ b/Marlin/src/lcd/tft/ui_480x320.cpp @@ -340,50 +340,116 @@ void MarlinUI::draw_status_screen() { TERN_(TOUCH_SCREEN, touch.add_control(FLOWRATE, x, y, component_width, 32, active_extruder)); #endif - #if TFT_COLOR_UI_PORTRAIT || DISABLED(TOUCH_SCREEN) - y += STATUS_MARGIN_SIZE + 32; + y += TERN(HAS_UI_480x272, 36, 44); + + const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)(); + #if ENABLED(SHOW_ELAPSED_TIME) && DISABLED(SHOW_REMAINING_TIME) + // Print duration so far (time elapsed) - centered + char elapsed_str[22]; + duration_t elapsed = print_job_timer.duration(); + elapsed.toString(elapsed_str); + + // Same width constraints as feedrate/flowrate controls + constexpr uint16_t time_str_width = 288, image_width = 36; + + tft.canvas((TFT_WIDTH - time_str_width) / 2, y, time_str_width, 32); + tft.set_background(COLOR_BACKGROUND); + tft_string.set(elapsed_str); + uint16_t text_pos_x = tft_string.center(time_str_width - image_width); + tft.add_image(text_pos_x, 0, imgTimeElapsed, COLOR_PRINT_TIME); + tft.add_text(text_pos_x + image_width, tft_string.vcenter(29), COLOR_PRINT_TIME, tft_string); + + #elif DISABLED(SHOW_ELAPSED_TIME) && ENABLED(SHOW_REMAINING_TIME) + // Print time remaining estimation - centered + char estimate_str[22]; + duration_t elapsed = print_job_timer.duration(); + + // Get the estimate, first from M73 + uint32_t estimate_remaining = (0 + #if ALL(SET_PROGRESS_MANUALLY, SET_REMAINING_TIME) + + get_remaining_time() + #endif + ); + // If no M73 estimate is available but we have progress data, calculate time remaining assuming time elapsed is linear with progress + if (!estimate_remaining && progress > 0) + estimate_remaining = elapsed.value * (100 * (PROGRESS_SCALE) - progress) / progress; + + // Generate estimate string + if (!estimate_remaining) + tft_string.set("-"); + else { + duration_t estimation = estimate_remaining; + estimation.toString(estimate_str); + tft_string.set(estimate_str); + } + + // Same width constraints as feedrate/flowrate controls + constexpr uint16_t time_str_width = 288, image_width = 36; + + tft.canvas((TFT_WIDTH - time_str_width) / 2, y, time_str_width, 32); + tft.set_background(COLOR_BACKGROUND); + color = printingIsActive() ? COLOR_PRINT_TIME : COLOR_INACTIVE; + uint16_t text_pos_x = tft_string.center(time_str_width - image_width); + tft.add_image(text_pos_x, 0, imgTimeRemaining, color); + tft.add_text(text_pos_x + image_width, tft_string.vcenter(29), color, tft_string); + + #elif ALL(SHOW_REMAINING_TIME, SHOW_ELAPSED_TIME) + // Print duration so far (time elapsed) - aligned under feed rate + char elapsed_str[18]; + duration_t elapsed = print_job_timer.duration(); + elapsed.toCompactString(elapsed_str); + + tft.canvas(96, y, 144, 32); + tft.set_background(COLOR_BACKGROUND); + tft.add_image(0, 0, imgTimeElapsed, COLOR_PRINT_TIME); + tft_string.set(elapsed_str); + tft.add_text(36, tft_string.vcenter(29), COLOR_PRINT_TIME, tft_string); + + // Print time remaining estimation - aligned under flow rate + char estimate_str[18]; + + // Get the estimate, first from M73 + uint32_t estimate_remaining = (0 + #if ALL(SET_PROGRESS_MANUALLY, SET_REMAINING_TIME) + + get_remaining_time() + #endif + ); + // If no M73 estimate is available but we have progress data, calculate time remaining assuming time elapsed is linear with progress + if (!estimate_remaining && progress > 0) + estimate_remaining = elapsed.value * (100 * (PROGRESS_SCALE) - progress) / progress; + + // Generate estimate string + if (!estimate_remaining) + tft_string.set("-"); + else { + duration_t estimation = estimate_remaining; + estimation.toCompactString(estimate_str); + tft_string.set(estimate_str); + } + + // Push out the estimate to the screen + tft.canvas(256, y, 144, 32); + tft.set_background(COLOR_BACKGROUND); + color = printingIsActive() ? COLOR_PRINT_TIME : COLOR_INACTIVE; + tft.add_image(0, 0, imgTimeRemaining, color); + tft.add_text(36, tft_string.vcenter(29), color, tft_string); #endif - #if ENABLED(TOUCH_SCREEN) - // Settings button - add_control(SETTINGS_X, y, menu_main, imgSettings); - - // SD-card button / Cancel button - #if HAS_MEDIA - const bool cm = card.isMounted(), pa = printingIsActive(); - if (cm && pa) - add_control(SDCARD_X, y, STOP, imgCancel, true, COLOR_CONTROL_CANCEL); - else - add_control(SDCARD_X, y, menu_media, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, COLOR_CONTROL_DISABLED); // 64px icon size - #endif - - y += STATUS_MARGIN_SIZE + TERN(TFT_COLOR_UI_PORTRAIT, 64, 44); - #endif - - // Print duration - char buffer[14]; - duration_t elapsed = print_job_timer.duration(); - elapsed.toDigital(buffer); - - tft.canvas((TFT_WIDTH - 128) / 2, y, 128, 29); - tft.set_background(COLOR_BACKGROUND); - tft_string.set(buffer); - tft.add_text(tft_string.center(128), tft_string.vcenter(29), COLOR_PRINT_TIME, tft_string); - - y += STATUS_MARGIN_SIZE + 29; + y += TERN(HAS_UI_480x272, 36, 44); // Progress bar - const uint8_t progress = ui.get_progress_percent(); + // TODO: print percentage text for SHOW_PROGRESS_PERCENT tft.canvas(4, y, TFT_WIDTH - 8, 9); tft.set_background(COLOR_PROGRESS_BG); tft.add_rectangle(0, 0, TFT_WIDTH - 8, 9, COLOR_PROGRESS_FRAME); if (progress) - tft.add_bar(1, 1, ((TFT_WIDTH - 10) * progress) / 100, 7, COLOR_PROGRESS_BAR); - - y += STATUS_MARGIN_SIZE + 7; + tft.add_bar(1, 1, ((TFT_WIDTH - 10) * progress / (PROGRESS_SCALE)) / 100, 7, COLOR_PROGRESS_BAR); + y += 12; // Status message - tft.canvas(0, y, TFT_WIDTH, FONT_LINE_HEIGHT); + // Canvas height should be 40px on 480x320 and 28 on 480x272 + const uint16_t status_height = TFT_HEIGHT - y; + tft.canvas(0, y, TFT_WIDTH, status_height); tft.set_background(COLOR_BACKGROUND); tft_string.set(status_message); tft_string.trim(); @@ -878,9 +944,8 @@ static void drawBtn(const int x, const int y, const char *label, intptr_t data, tft_string.trim(); tft.add_text(tft_string.center(width), height / 2 - tft_string.font_height() / 2, bgColor, tft_string); } - else { + else tft.add_image(0, 0, img, bgColor, COLOR_BACKGROUND, COLOR_DARKGREY); - } TERN_(TOUCH_SCREEN, if (enabled) touch.add_control(BUTTON, x, y, width, height, data)); } diff --git a/Marlin/src/libs/duration_t.h b/Marlin/src/libs/duration_t.h index e45ce01496c..d648924dc95 100644 --- a/Marlin/src/libs/duration_t.h +++ b/Marlin/src/libs/duration_t.h @@ -117,6 +117,7 @@ struct duration_t { * * @param buffer The array pointed to must be able to accommodate 22 bytes * (21 for the string, 1 more for the terminating nul) + * @param dense Whether to skip spaces in the resulting string * * Output examples: * 123456789012345678901 (strlen) @@ -141,11 +142,43 @@ struct duration_t { return buffer; } + /** + * @brief Format the duration as a compact string + * @details String will be formatted using a "full" representation of duration + * + * @param buffer The array pointed to must be able to accommodate 18 bytes + * (17 for the string, 1 more for the terminating nul) + * @param dense Whether to skip spaces in the resulting string + * + * Output examples: + * 12345678901234567 (strlen) + * 135y364d23h59m59s + * 364d23h59m59s + * 23h59m59s + * 59m59s + * 59s + */ + char* toCompactString(char * const buffer) const { + const uint16_t y = this->year(), + d = this->day() % 365, + h = this->hour() % 24, + m = this->minute() % 60, + s = this->second() % 60; + + if (y) sprintf_P(buffer, PSTR("%iy%id%ih%im%is"), y, d, h, m, s); + else if (d) sprintf_P(buffer, PSTR("%id%ih%im%is"), d, h, m, s); + else if (h) sprintf_P(buffer, PSTR("%ih%im%is"), h, m, s); + else if (m) sprintf_P(buffer, PSTR("%im%is"), m, s); + else sprintf_P(buffer, PSTR("%is"), s); + return buffer; + } + /** * @brief Format the duration as a string * @details String will be formatted using a "digital" representation of duration * * @param buffer The array pointed to must be able to accommodate 10 bytes + * @return length of the formatted string (without terminating nul) * * Output examples: * 123456789 (strlen)