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)