From 79b38e0e14074b52e0aeb98b08a686a99a9b1aad Mon Sep 17 00:00:00 2001
From: Miguel Risco-Castillo <mriscoc@users.noreply.github.com>
Date: Fri, 11 Mar 2022 15:06:49 -0500
Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8=20Update=20Ender3=20V2/S1=20Pro=20?=
 =?UTF-8?q?UI=20(#23878)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Marlin/src/MarlinCore.cpp                     |    8 +-
 Marlin/src/feature/pause.cpp                  |    3 +-
 Marlin/src/gcode/bedlevel/mbl/G29.cpp         |    2 +
 Marlin/src/gcode/config/M302.cpp              |    5 +
 Marlin/src/gcode/sd/M524.cpp                  |   20 +-
 Marlin/src/gcode/stats/M75-M78.cpp            |    3 +-
 Marlin/src/inc/Conditionals_LCD.h             |    5 +-
 Marlin/src/lcd/e3v2/common/encoder.h          |   20 +
 Marlin/src/lcd/e3v2/creality/dwin.cpp         |   25 +-
 Marlin/src/lcd/e3v2/creality/dwin.h           |    1 +
 Marlin/src/lcd/e3v2/proui/dwin.cpp            | 1444 +++++++----------
 Marlin/src/lcd/e3v2/proui/dwin.h              |  100 +-
 Marlin/src/lcd/e3v2/proui/dwin_defines.h      |   43 +-
 Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp        |   56 +-
 Marlin/src/lcd/e3v2/proui/dwin_lcd.h          |   26 +-
 Marlin/src/lcd/e3v2/proui/dwin_popup.cpp      |   60 +-
 Marlin/src/lcd/e3v2/proui/dwin_popup.h        |   27 +-
 Marlin/src/lcd/e3v2/proui/dwinui.cpp          |  119 +-
 Marlin/src/lcd/e3v2/proui/dwinui.h            |  126 +-
 Marlin/src/lcd/e3v2/proui/endstop_diag.cpp    |   11 +-
 Marlin/src/lcd/e3v2/proui/endstop_diag.h      |    8 +-
 Marlin/src/lcd/e3v2/proui/lockscreen.cpp      |    4 +-
 Marlin/src/lcd/e3v2/proui/lockscreen.h        |    4 +-
 Marlin/src/lcd/e3v2/proui/menus.cpp           |  370 +++++
 Marlin/src/lcd/e3v2/proui/menus.h             |   94 ++
 Marlin/src/lcd/e3v2/proui/meshviewer.cpp      |   68 +-
 Marlin/src/lcd/e3v2/proui/meshviewer.h        |   17 +-
 Marlin/src/lcd/e3v2/proui/printstats.cpp      |   16 +-
 Marlin/src/lcd/e3v2/proui/printstats.h        |   12 +-
 Marlin/src/lcd/language/language_en.h         |    6 +-
 Marlin/src/lcd/marlinui.cpp                   |    7 +-
 Marlin/src/lcd/marlinui.h                     |   14 +-
 Marlin/src/module/settings.cpp                |    8 +-
 Marlin/src/module/stepper.cpp                 |    3 +
 Marlin/src/module/temperature.cpp             |    2 +-
 .../stm32f1/pins_BTT_SKR_MINI_E3_common.h     |    2 +-
 .../pins/stm32f1/pins_CREALITY_V24S1_301.h    |   26 +-
 Marlin/src/sd/cardreader.cpp                  |   11 +-
 Marlin/src/sd/cardreader.h                    |    7 +
 buildroot/tests/STM32F103RE_creality          |    5 +-
 40 files changed, 1577 insertions(+), 1211 deletions(-)
 create mode 100644 Marlin/src/lcd/e3v2/proui/menus.cpp
 create mode 100644 Marlin/src/lcd/e3v2/proui/menus.h

diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp
index cc928baff94..4117d3f382a 100644
--- a/Marlin/src/MarlinCore.cpp
+++ b/Marlin/src/MarlinCore.cpp
@@ -822,7 +822,7 @@ void idle(bool no_stepper_sleep/*=false*/) {
   TERN_(USE_BEEPER, buzzer.tick());
 
   // Handle UI input / draw events
-  TERN(HAS_DWIN_E3V2_BASIC, DWIN_Update(), ui.update());
+  TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update());
 
   // Run i2c Position Encoders
   #if ENABLED(I2C_POSITION_ENCODERS)
@@ -1571,11 +1571,7 @@ void setup() {
   #endif
 
   #if HAS_DWIN_E3V2_BASIC
-    SETUP_LOG("E3V2 Init");
-    Encoder_Configuration();
-    HMI_Init();
-    HMI_SetLanguageCache();
-    HMI_StartFrame(true);
+    SETUP_RUN(DWIN_InitScreen());
   #endif
 
   #if HAS_SERVICE_INTERVALS && !HAS_DWIN_E3V2_BASIC
diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp
index 79780021cfb..636ac32042b 100644
--- a/Marlin/src/feature/pause.cpp
+++ b/Marlin/src/feature/pause.cpp
@@ -407,6 +407,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool
   #endif
 
   TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_open(PROMPT_INFO, F("Pause"), FPSTR(DISMISS_STR)));
+  TERN_(DWIN_LCD_PROUI, DWIN_Print_Pause());
 
   // Indicate that the printer is paused
   ++did_pause_print;
@@ -709,7 +710,7 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_
 
   TERN_(HAS_FILAMENT_SENSOR, runout.reset());
 
-  TERN_(HAS_STATUS_MESSAGE, ui.reset_status());
+  TERN(DWIN_LCD_PROUI, DWIN_Print_Resume(), ui.reset_status());
   TERN_(HAS_MARLINUI_MENU, ui.return_to_status());
   TERN_(DWIN_LCD_PROUI, HMI_ReturnScreen());
 }
diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp
index 309d21fe53f..3767cef3cfb 100644
--- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp
+++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp
@@ -105,6 +105,7 @@ void GcodeSuite::G29() {
       if (!ui.wait_for_move) {
         queue.inject(parser.seen_test('N') ? F("G28" TERN(CAN_SET_LEVELING_AFTER_G28, "L0", "") "\nG29S2") : F("G29S2"));
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshLevelingStart());
+        TERN_(DWIN_LCD_PROUI, DWIN_MeshLevelingStart());
         return;
       }
       state = MeshNext;
@@ -127,6 +128,7 @@ void GcodeSuite::G29() {
         // Save Z for the previous mesh position
         mbl.set_zigzag_z(mbl_probe_index - 1, current_position.z);
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, current_position.z));
+        TERN_(DWIN_LCD_PROUI, DWIN_MeshUpdate(_MIN(mbl_probe_index, GRID_MAX_POINTS), int(GRID_MAX_POINTS), current_position.z));
         SET_SOFT_ENDSTOP_LOOSE(false);
       }
       // If there's another point to sample, move there with optional lift.
diff --git a/Marlin/src/gcode/config/M302.cpp b/Marlin/src/gcode/config/M302.cpp
index e271dcd469e..9f4d569d7b2 100644
--- a/Marlin/src/gcode/config/M302.cpp
+++ b/Marlin/src/gcode/config/M302.cpp
@@ -27,6 +27,10 @@
 #include "../gcode.h"
 #include "../../module/temperature.h"
 
+#if ENABLED(DWIN_LCD_PROUI)
+  #include "../../lcd/e3v2/proui/dwin_defines.h"
+#endif
+
 /**
  * M302: Allow cold extrudes, or set the minimum extrude temperature
  *
@@ -47,6 +51,7 @@ void GcodeSuite::M302() {
   if (seen_S) {
     thermalManager.extrude_min_temp = parser.value_celsius();
     thermalManager.allow_cold_extrude = (thermalManager.extrude_min_temp == 0);
+    TERN_(DWIN_LCD_PROUI, HMI_data.ExtMinT = thermalManager.extrude_min_temp);
   }
 
   if (parser.seen('P'))
diff --git a/Marlin/src/gcode/sd/M524.cpp b/Marlin/src/gcode/sd/M524.cpp
index e7159155655..001a1e18426 100644
--- a/Marlin/src/gcode/sd/M524.cpp
+++ b/Marlin/src/gcode/sd/M524.cpp
@@ -27,15 +27,27 @@
 #include "../gcode.h"
 #include "../../sd/cardreader.h"
 
+#if ENABLED(DWIN_LCD_PROUI)
+  #include "../../lcd/e3v2/proui/dwin.h"
+#endif
+
 /**
  * M524: Abort the current SD print job (started with M24)
  */
 void GcodeSuite::M524() {
 
-  if (IS_SD_PRINTING())
-    card.abortFilePrintSoon();
-  else if (card.isMounted())
-    card.closefile();
+  #if ENABLED(DWIN_LCD_PROUI)
+
+    HMI_flag.abort_flag = true;    // The LCD will handle it
+
+  #else
+
+    if (IS_SD_PRINTING())
+      card.abortFilePrintSoon();
+    else if (card.isMounted())
+      card.closefile();
+
+  #endif
 
 }
 
diff --git a/Marlin/src/gcode/stats/M75-M78.cpp b/Marlin/src/gcode/stats/M75-M78.cpp
index 01630adc507..0ed1e669301 100644
--- a/Marlin/src/gcode/stats/M75-M78.cpp
+++ b/Marlin/src/gcode/stats/M75-M78.cpp
@@ -39,8 +39,8 @@
 void GcodeSuite::M75() {
   startOrResumeJob();
   #if ENABLED(DWIN_LCD_PROUI)
-    DWIN_Print_Header(parser.string_arg && parser.string_arg[0] ? parser.string_arg : GET_TEXT(MSG_HOST_START_PRINT));
     DWIN_Print_Started(false);
+    if (!IS_SD_PRINTING()) DWIN_Print_Header(parser.string_arg && parser.string_arg[0] ? parser.string_arg : GET_TEXT(MSG_HOST_START_PRINT));
   #endif
 }
 
@@ -50,6 +50,7 @@ void GcodeSuite::M75() {
 void GcodeSuite::M76() {
   print_job_timer.pause();
   TERN_(HOST_PAUSE_M76, hostui.pause());
+  TERN_(DWIN_LCD_PROUI, DWIN_Print_Pause());
 }
 
 /**
diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h
index 9d9fddc8c1b..33d9e462209 100644
--- a/Marlin/src/inc/Conditionals_LCD.h
+++ b/Marlin/src/inc/Conditionals_LCD.h
@@ -479,6 +479,9 @@
 #if EITHER(HAS_DWIN_E3V2_BASIC, DWIN_CREALITY_LCD_JYERSUI)
   #define HAS_DWIN_E3V2 1
 #endif
+#if ENABLED(DWIN_LCD_PROUI)
+  #define DO_LIST_BIN_FILES 1
+#endif
 
 // E3V2 extras
 #if HAS_DWIN_E3V2 || IS_DWIN_MARLINUI
@@ -513,7 +516,7 @@
   #endif
 #endif
 
-#if ANY(HAS_WIRED_LCD, EXTENSIBLE_UI, DWIN_CREALITY_LCD_JYERSUI)
+#if ANY(HAS_WIRED_LCD, EXTENSIBLE_UI, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI)
   #define HAS_DISPLAY 1
 #endif
 
diff --git a/Marlin/src/lcd/e3v2/common/encoder.h b/Marlin/src/lcd/e3v2/common/encoder.h
index e5d9645ed43..3ab8c3bf422 100644
--- a/Marlin/src/lcd/e3v2/common/encoder.h
+++ b/Marlin/src/lcd/e3v2/common/encoder.h
@@ -45,12 +45,32 @@ typedef enum {
   ENCODER_DIFF_ENTER = 3   // click
 } EncoderState;
 
+#define ENCODER_WAIT_MS 20
+
 // Encoder initialization
 void Encoder_Configuration();
 
 // Analyze encoder value and return state
 EncoderState Encoder_ReceiveAnalyze();
 
+inline EncoderState get_encoder_state() {
+  static millis_t Encoder_ms = 0;
+  const millis_t ms = millis();
+  if (PENDING(ms, Encoder_ms)) return ENCODER_DIFF_NO;
+  const EncoderState state = Encoder_ReceiveAnalyze();
+  if (state != ENCODER_DIFF_NO) Encoder_ms = ms + ENCODER_WAIT_MS;
+  return state;
+}
+
+template<typename T>
+inline bool Apply_Encoder(const EncoderState &encoder_diffState, T &valref) {
+  if (encoder_diffState == ENCODER_DIFF_CW)
+    valref += EncoderRate.encoderMoveValue;
+  else if (encoder_diffState == ENCODER_DIFF_CCW)
+    valref -= EncoderRate.encoderMoveValue;
+  return encoder_diffState == ENCODER_DIFF_ENTER;
+}
+
 /*********************** Encoder LED ***********************/
 
 #if PIN_EXISTS(LCD_LED)
diff --git a/Marlin/src/lcd/e3v2/creality/dwin.cpp b/Marlin/src/lcd/e3v2/creality/dwin.cpp
index f20260e43d5..7dc06d00f2a 100644
--- a/Marlin/src/lcd/e3v2/creality/dwin.cpp
+++ b/Marlin/src/lcd/e3v2/creality/dwin.cpp
@@ -471,15 +471,6 @@ void Draw_Back_First(const bool is_sel=true) {
   if (is_sel) Draw_Menu_Cursor(0);
 }
 
-template <typename T>
-inline bool Apply_Encoder(const EncoderState &encoder_diffState, T &valref) {
-  if (encoder_diffState == ENCODER_DIFF_CW)
-    valref += EncoderRate.encoderMoveValue;
-  else if (encoder_diffState == ENCODER_DIFF_CCW)
-    valref -= EncoderRate.encoderMoveValue;
-  return encoder_diffState == ENCODER_DIFF_ENTER;
-}
-
 //
 // Draw Menus
 //
@@ -1296,15 +1287,6 @@ void Goto_MainMenu() {
   TERN(HAS_ONESTEP_LEVELING, ICON_Leveling, ICON_StartInfo)();
 }
 
-inline EncoderState get_encoder_state() {
-  static millis_t Encoder_ms = 0;
-  const millis_t ms = millis();
-  if (PENDING(ms, Encoder_ms)) return ENCODER_DIFF_NO;
-  const EncoderState state = Encoder_ReceiveAnalyze();
-  if (state != ENCODER_DIFF_NO) Encoder_ms = ms + ENCODER_WAIT_MS;
-  return state;
-}
-
 void HMI_Plan_Move(const feedRate_t fr_mm_s) {
   if (!planner.is_full()) {
     planner.synchronize();
@@ -4086,6 +4068,13 @@ void HMI_Init() {
   HMI_SetLanguage();
 }
 
+void DWIN_InitScreen() {
+  Encoder_Configuration();
+  HMI_Init();
+  HMI_SetLanguageCache();
+  HMI_StartFrame(true);
+}
+
 void DWIN_Update() {
   EachMomentUpdate();   // Status update
   HMI_SDCardUpdate();   // SD card update
diff --git a/Marlin/src/lcd/e3v2/creality/dwin.h b/Marlin/src/lcd/e3v2/creality/dwin.h
index 3122a6fcbae..3ccb70e52f7 100644
--- a/Marlin/src/lcd/e3v2/creality/dwin.h
+++ b/Marlin/src/lcd/e3v2/creality/dwin.h
@@ -236,6 +236,7 @@ void HMI_MaxJerk();         // Maximum jerk speed submenu
 void HMI_Step();            // Transmission ratio
 
 void HMI_Init();
+void DWIN_InitScreen();
 void DWIN_Update();
 void EachMomentUpdate();
 void DWIN_HandleScreen();
diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp
index 9e08854aedd..0a392cd5636 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin.cpp
+++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp
@@ -21,19 +21,18 @@
  */
 
 /**
- * Enhanced DWIN implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.11.2
- * date: 2022/01/19
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.15.2
+ * Date: 2022/03/01
  */
 
-#include "../../../inc/MarlinConfigPre.h"
+#include "../../../inc/MarlinConfig.h"
 
 #if ENABLED(DWIN_LCD_PROUI)
 
 #include "dwin.h"
+#include "menus.h"
 #include "dwin_popup.h"
 
 #include "../../fontutils.h"
@@ -65,6 +64,10 @@
   #include "../../../feature/host_actions.h"
 #endif
 
+#if ANY(AUTO_BED_LEVELING_BILINEAR, AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) && DISABLED(PROBE_MANUALLY)
+  #define HAS_ONESTEP_LEVELING 1
+#endif
+
 #if HAS_MESH || HAS_ONESTEP_LEVELING
   #include "../../../feature/bedlevel/bedlevel.h"
 #endif
@@ -77,8 +80,14 @@
   #include "../../../feature/bltouch.h"
 #endif
 
-#if EITHER(BABYSTEP_ZPROBE_OFFSET, JUST_BABYSTEP)
-  #include "../../../feature/babystep.h"
+#if ANY(BABYSTEPPING, HAS_BED_PROBE, HAS_WORKSPACE_OFFSET)
+  #define HAS_ZOFFSET_ITEM 1
+  #if !HAS_BED_PROBE && ENABLED(BABYSTEPPING)
+    #define JUST_BABYSTEP 1
+  #endif
+  #if EITHER(BABYSTEP_ZPROBE_OFFSET, JUST_BABYSTEP)
+    #include "../../../feature/babystep.h"
+  #endif
 #endif
 
 #if ENABLED(POWER_LOSS_RECOVERY)
@@ -171,7 +180,7 @@ enum SelectItem : uint8_t {
   PAGE_PRINT = 0,
   PAGE_PREPARE,
   PAGE_CONTROL,
-  PAGE_INFO_LEV_ADV,
+  PAGE_ADVANCE,
   PAGE_COUNT,
 
   PRINT_SETUP = 0,
@@ -192,14 +201,13 @@ typedef struct {
 select_t select_page{0}, select_file{0}, select_print{0};
 uint8_t index_file     = MROWS;
 
-bool dwin_abort_flag = false; // Flag to reset feedrate, return to Home
 bool hash_changed = true; // Flag to know if message status was changed
 
-constexpr float default_max_feedrate[]        = DEFAULT_MAX_FEEDRATE;
-constexpr float default_max_acceleration[]    = DEFAULT_MAX_ACCELERATION;
+constexpr float max_feedrate_edit_values[]        = DEFAULT_MAX_FEEDRATE;
+constexpr float max_acceleration_edit_values[]    = DEFAULT_MAX_ACCELERATION;
 
 #if HAS_CLASSIC_JERK
-  constexpr float default_max_jerk[]          = { DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK, DEFAULT_EJERK };
+  constexpr float max_jerk_edit_values[]          = { DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK, DEFAULT_EJERK };
 #endif
 
 static uint8_t _percent_done = 0;
@@ -208,18 +216,6 @@ static uint32_t _remain_time = 0;
 // Additional Aux Host Support
 static bool sdprint = false;
 
-#if ENABLED(PAUSE_HEAT)
-  #if HAS_HOTEND
-    celsius_t resume_hotend_temp = 0;
-  #endif
-  #if HAS_HEATED_BED
-    celsius_t resume_bed_temp = 0;
-  #endif
-  #if HAS_FAN
-    uint16_t resume_fan = 0;
-  #endif
-#endif
-
 #if HAS_ZOFFSET_ITEM
   float dwin_zoffset = 0, last_zoffset = 0;
 #endif
@@ -348,31 +344,13 @@ void ICON_Control() {
   ICON_Button(select_page.now == PAGE_CONTROL, ICON_Control_0, ico, txt, GET_TEXT_F(MSG_CONTROL));
 }
 
-//
-// Main Menu: "Info"
-//
-void ICON_StartInfo() {
-  constexpr frame_rect_t ico = { 145, 226, 110, 100 };
-  constexpr text_info_t txt = { 91, { 405, TERN(USE_STOCK_DWIN_SET, 446, 447) }, 27, 15 };
-  ICON_Button(select_page.now == PAGE_INFO_LEV_ADV, ICON_Info_0, ico, txt, GET_TEXT_F(MSG_BUTTON_INFO));
-}
-
-//
-// Main Menu: "Level"
-//
-void ICON_Leveling() {
-  constexpr frame_rect_t ico = { 145, 226, 110, 100 };
-  constexpr text_info_t txt = { 211, { 405, TERN(USE_STOCK_DWIN_SET, 446, 447) }, 27, 15 };
-  ICON_Button(select_page.now == PAGE_INFO_LEV_ADV, ICON_Leveling_0, ico, txt, GET_TEXT_F(MSG_BUTTON_LEVEL));
-}
-
 //
 // Main Menu: "Advanced Settings"
 //
 void ICON_AdvSettings() {
   constexpr frame_rect_t ico = { 145, 226, 110, 100 };
   constexpr text_info_t txt = { 91, { 405, TERN(USE_STOCK_DWIN_SET, 446, 447) }, 27, 15 };
-  ICON_Button(select_page.now == PAGE_INFO_LEV_ADV, ICON_Info_0, ico, txt, GET_TEXT_F(MSG_BUTTON_ADVANCED));
+  ICON_Button(select_page.now == PAGE_ADVANCE, ICON_Info_0, ico, txt, GET_TEXT_F(MSG_BUTTON_ADVANCED));
 }
 
 //
@@ -415,14 +393,6 @@ void ICON_Stop() {
 // Drawing routines
 //-----------------------------------------------------------------------------
 
-void Draw_Menu_Cursor(const int8_t line) {
-  DWIN_Draw_Rectangle(1, HMI_data.Cursor_color, 0, MBASE(line) - 18, 14, MBASE(line + 1) - 20);
-}
-
-void Erase_Menu_Cursor(const int8_t line) {
-  DWIN_Draw_Rectangle(1, HMI_data.Background_Color, 0, MBASE(line) - 18, 14, MBASE(line + 1) - 20);
-}
-
 void Move_Highlight(const int8_t from, const int8_t newline) {
   Erase_Menu_Cursor(newline - from);
   Draw_Menu_Cursor(newline);
@@ -430,7 +400,7 @@ void Move_Highlight(const int8_t from, const int8_t newline) {
 
 void Add_Menu_Line() {
   Move_Highlight(1, MROWS);
-  DWIN_Draw_Line(HMI_data.SplitLine_Color, 16, MBASE(MROWS + 1) - 20, 256, MBASE(MROWS + 1) - 19);
+  DWIN_Draw_HLine(HMI_data.SplitLine_Color, 16, MYPOS(MROWS + 1), 240);
 }
 
 void Scroll_Menu(const uint8_t dir) {
@@ -449,21 +419,6 @@ void Erase_Menu_Text(const uint8_t line) {
   DWIN_Draw_Rectangle(1, HMI_data.Background_Color, LBLX, MBASE(line) - 14, 271, MBASE(line) + 28);
 }
 
-void Draw_Menu_Line(const uint8_t line, const uint8_t icon=0, const char * const label=nullptr, bool more=false) {
-  if (icon)  DWINUI::Draw_Icon(icon, ICOX, MBASE(line) - 3);
-  if (label) DWINUI::Draw_String(LBLX, MBASE(line) - 1, (char*)label);
-  if (more)  DWINUI::Draw_Icon(ICON_More, VALX + 16, MBASE(line) - 3);
-  DWIN_Draw_HLine(HMI_data.SplitLine_Color, 16, MYPOS(line + 1), 240);
-}
-
-void Draw_Chkb_Line(const uint8_t line, const bool checked) {
-  DWINUI::Draw_Checkbox(HMI_data.Text_Color, HMI_data.Background_Color, VALX + 16, MBASE(line) - 1, checked);
-}
-
-void Draw_Menu_IntValue(uint16_t bcolor, const uint8_t line, uint8_t iNum, const uint16_t value=0) {
-  DWINUI::Draw_Int(HMI_data.Text_Color, bcolor, iNum , VALX, MBASE(line) - 1, value);
-}
-
 // Draw "Back" line at the top
 void Draw_Back_First(const bool is_sel=true) {
   Draw_Menu_Line(0, ICON_Back);
@@ -474,24 +429,6 @@ void Draw_Back_First(const bool is_sel=true) {
   if (is_sel) Draw_Menu_Cursor(0);
 }
 
-inline EncoderState get_encoder_state() {
-  static millis_t Encoder_ms = 0;
-  const millis_t ms = millis();
-  if (PENDING(ms, Encoder_ms)) return ENCODER_DIFF_NO;
-  const EncoderState state = Encoder_ReceiveAnalyze();
-  if (state != ENCODER_DIFF_NO) Encoder_ms = ms + ENCODER_WAIT_MS;
-  return state;
-}
-
-template<typename T>
-inline bool Apply_Encoder(const EncoderState &encoder_diffState, T &valref) {
-  if (encoder_diffState == ENCODER_DIFF_CW)
-    valref += EncoderRate.encoderMoveValue;
-  else if (encoder_diffState == ENCODER_DIFF_CCW)
-    valref -= EncoderRate.encoderMoveValue;
-  return encoder_diffState == ENCODER_DIFF_ENTER;
-}
-
 //PopUps
 void Popup_window_PauseOrStop() {
   if (HMI_IsChinese()) {
@@ -530,9 +467,10 @@ void Popup_window_PauseOrStop() {
 
 #if HAS_HOTEND || HAS_HEATED_BED
   void DWIN_Popup_Temperature(const bool toohigh) {
-    DWINUI::ClearMenuArea();
-    Draw_Popup_Bkgd();
+    HMI_SaveProcessID(WaitResponse);
     if (HMI_IsChinese()) {
+      DWINUI::ClearMenuArea();
+      Draw_Popup_Bkgd();
       if (toohigh) {
         DWINUI::Draw_Icon(ICON_TempTooHigh, 102, 165);
         DWIN_Frame_AreaCopy(1, 103, 371, 237, 386, 52, 285);
@@ -545,23 +483,14 @@ void Popup_window_PauseOrStop() {
         DWIN_Frame_AreaCopy(1, 189, 389, 271, 402, 95, 310);
       }
     }
-    else {
-      DWIN_Draw_Popup(toohigh ? ICON_TempTooHigh : ICON_TempTooLow, F("Nozzle or Bed temperature"), toohigh ? F("is too high") : F("is too low"));
-    }
+    else DWIN_Show_Popup(toohigh ? ICON_TempTooHigh : ICON_TempTooLow, F("Nozzle or Bed temperature"), toohigh ? F("is too high") : F("is too low"), BTN_Continue);
   }
 #endif
 
 // Draw status line
-void DWIN_DrawStatusLine(const uint16_t color, const uint16_t bgcolor, const char *text, const bool center = true) {
-  DWIN_Draw_Rectangle(1, bgcolor, 0, STATUS_Y, DWIN_WIDTH, STATUS_Y + 20);
-  if (text) {
-    if (center) DWINUI::Draw_CenteredString(color, STATUS_Y + 2, text);
-    else        DWINUI::Draw_String(color, 0, STATUS_Y + 2, text);
-  }
-  DWIN_UpdateLCD();
-}
-void DWIN_DrawStatusLine(const char *text, const bool center = true) {
-  DWIN_DrawStatusLine(HMI_data.StatusTxt_Color, HMI_data.StatusBg_Color, text, center);
+void DWIN_DrawStatusLine(const char *text) {
+  DWIN_Draw_Rectangle(1, HMI_data.StatusBg_Color, 0, STATUS_Y, DWIN_WIDTH, STATUS_Y + 20);
+  if (text) DWINUI::Draw_CenteredString(HMI_data.StatusTxt_Color, STATUS_Y + 2, text);
 }
 
 // Clear & reset status line
@@ -582,17 +511,15 @@ void DWIN_CheckStatusMessage() {
 };
 
 void DWIN_DrawStatusMessage() {
-  const uint8_t max_status_chars = DWIN_WIDTH / DWINUI::fontWidth();
-
   #if ENABLED(STATUS_MESSAGE_SCROLLING)
 
     // Get the UTF8 character count of the string
     uint8_t slen = utf8_strlen(ui.status_message);
 
     // If the string fits the status line do not scroll it
-    if (slen <= max_status_chars) {
+    if (slen <= LCD_WIDTH) {
        if (hash_changed) {
-         DWIN_DrawStatusLine(HMI_data.StatusTxt_Color, HMI_data.StatusBg_Color, ui.status_message);
+         DWIN_DrawStatusLine(ui.status_message);
          hash_changed = false;
        }
     }
@@ -605,16 +532,16 @@ void DWIN_DrawStatusMessage() {
       const char *stat = MarlinUI::status_and_len(rlen);
       DWIN_Draw_Rectangle(1, HMI_data.StatusBg_Color, 0, STATUS_Y, DWIN_WIDTH, STATUS_Y + 20);
       DWINUI::MoveTo(0, STATUS_Y + 2);
-      DWINUI::Draw_String(stat, max_status_chars);
+      DWINUI::Draw_String(HMI_data.StatusTxt_Color, stat, LCD_WIDTH);
 
       // If the string doesn't completely fill the line...
-      if (rlen < max_status_chars) {
-        DWINUI::Draw_Char('.');                   // Always at 1+ spaces left, draw a dot
-        uint8_t chars = max_status_chars - rlen;  // Amount of space left in characters
+      if (rlen < LCD_WIDTH) {
+        DWINUI::Draw_Char(HMI_data.StatusTxt_Color, '.');  // Always at 1+ spaces left, draw a dot
+        uint8_t chars = LCD_WIDTH - rlen;                  // Amount of space left in characters
         if (--chars) {                            // Draw a second dot if there's space
-          DWINUI::Draw_Char('.');
+          DWINUI::Draw_Char(HMI_data.StatusTxt_Color, '.');
           if (--chars)
-            DWINUI::Draw_String(ui.status_message, chars); // Print a second copy of the message
+            DWINUI::Draw_String(HMI_data.StatusTxt_Color, ui.status_message, chars); // Print a second copy of the message
         }
       }
       MarlinUI::advance_status_scroll();
@@ -623,8 +550,8 @@ void DWIN_DrawStatusMessage() {
   #else
 
     if (hash_changed) {
-      ui.status_message[max_status_chars] = 0;
-      DWIN_DrawStatusLine(HMI_data.StatusTxt_Color, HMI_data.StatusBg_Color, ui.status_message);
+      ui.status_message[LCD_WIDTH] = 0;
+      DWIN_DrawStatusLine(ui.status_message);
       hash_changed = false;
     }
 
@@ -643,7 +570,7 @@ void Draw_Print_Labels() {
 }
 
 void Draw_Print_ProgressBar() {
-  DWINUI::Draw_IconWB(ICON_Bar, 15, 93);
+  DWIN_ICON_Show(true, false, false, ICON, ICON_Bar, 15, 93);
   DWIN_Draw_Rectangle(1, HMI_data.Barfill_Color, 16 + _percent_done * 240 / 100, 93, 256, 113);
   DWINUI::Draw_Int(HMI_data.PercentTxt_Color, HMI_data.Background_Color, 3, 117, 133, _percent_done);
   DWINUI::Draw_String(HMI_data.PercentTxt_Color, 142, 133, F("%"));
@@ -663,10 +590,21 @@ void Draw_Print_ProgressRemain() {
 }
 
 void ICON_ResumeOrPause() {
-  if (printingIsPaused() || HMI_flag.pause_flag || HMI_flag.pause_action)
-    ICON_Resume();
-  else
-    ICON_Pause();
+  if (checkkey == PrintProcess) printingIsPaused() ? ICON_Resume() : ICON_Pause();
+}
+
+// Update filename on print
+void DWIN_Print_Header(const char *text = nullptr) {
+  static char headertxt[31] = "";  // Print header text
+  if (text) {
+    const int8_t size = _MIN(30U, strlen_P(text));
+    LOOP_L_N(i, size) headertxt[i] = text[i];
+    headertxt[size] = '\0';
+  }
+  if (checkkey == PrintProcess || checkkey == PrintDone) {
+    DWIN_Draw_Rectangle(1, HMI_data.Background_Color, 0, 60, DWIN_WIDTH, 60+16);
+    DWINUI::Draw_CenteredString(60, headertxt);
+  }
 }
 
 void Draw_PrintProcess() {
@@ -685,17 +623,16 @@ void Draw_PrintProcess() {
   ICON_Tune();
   ICON_ResumeOrPause();
   ICON_Stop();
-  DWIN_UpdateLCD();
 }
 
 void Goto_PrintProcess() {
-  if (checkkey == PrintProcess) {
+  if (checkkey == PrintProcess)
     ICON_ResumeOrPause();
-    DWIN_UpdateLCD();
-    return;
+  else {
+    checkkey = PrintProcess;
+    Draw_PrintProcess();
   }
-  checkkey = PrintProcess;
-  Draw_PrintProcess();
+  DWIN_UpdateLCD();
 }
 
 void Draw_PrintDone() {
@@ -713,8 +650,16 @@ void Draw_PrintDone() {
   Draw_Print_ProgressElapsed();
   Draw_Print_ProgressRemain();
   // show print done confirm
-  DWINUI::Draw_IconWB(HMI_IsChinese() ? ICON_Confirm_C : ICON_Confirm_E, 86, 273);
-  DWIN_UpdateLCD();
+  DWINUI::Draw_Button(BTN_Confirm, 86, 273);
+}
+
+void Goto_PrintDone() {
+  wait_for_user = true;
+  if (checkkey != PrintDone) {
+    checkkey = PrintDone;
+    Draw_PrintDone();
+    DWIN_UpdateLCD();
+  }
 }
 
 void Draw_Main_Menu() {
@@ -724,18 +669,18 @@ void Draw_Main_Menu() {
   else
     Title.ShowCaption(MACHINE_NAME);
   DWINUI::Draw_Icon(ICON_LOGO, 71, 52);  // CREALITY logo
+  DWIN_ResetStatusLine();
   ICON_Print();
   ICON_Prepare();
   ICON_Control();
   ICON_AdvSettings();
-  DWIN_UpdateLCD();
 }
 
 void Goto_Main_Menu() {
   if (checkkey == MainMenu) return;
   checkkey = MainMenu;
-  ui.reset_status(true);
   Draw_Main_Menu();
+  DWIN_UpdateLCD();
 }
 
 // Draw X, Y, Z and blink if in an un-homed or un-trusted state
@@ -751,9 +696,9 @@ void _update_axis_value(const AxisEnum axis, const uint16_t x, const uint16_t y,
 
   if (force || changed || draw_qmark || draw_empty) {
     if (blink && draw_qmark)
-      DWINUI::Draw_String(HMI_data.Coordinate_Color, HMI_data.Background_Color, x, y, F(" - ? -"));
+      DWINUI::Draw_String(HMI_data.Coordinate_Color, HMI_data.Background_Color, x, y, F("  - ? -"));
     else if (blink && draw_empty)
-      DWINUI::Draw_String(HMI_data.Coordinate_Color, HMI_data.Background_Color, x, y, F("     "));
+      DWINUI::Draw_String(HMI_data.Coordinate_Color, HMI_data.Background_Color, x, y, F("       "));
     else
       DWINUI::Draw_Signed_Float(HMI_data.Coordinate_Color, HMI_data.Background_Color, 3, 2, x, y, p);
   }
@@ -766,9 +711,9 @@ void _draw_xyz_position(const bool force) {
   if (force || blink != _blink) {
     _blink = blink;
     //SERIAL_ECHOPGM(" (blink)");
-    _update_axis_value(X_AXIS,  35, 459, blink, true);
-    _update_axis_value(Y_AXIS, 120, 459, blink, true);
-    _update_axis_value(Z_AXIS, 205, 459, blink, true);
+    _update_axis_value(X_AXIS,  27, 459, blink, true);
+    _update_axis_value(Y_AXIS, 112, 459, blink, true);
+    _update_axis_value(Z_AXIS, 197, 459, blink, true);
   }
   //SERIAL_EOL();
 }
@@ -852,7 +797,7 @@ void update_variable() {
   static float _offset = 0;
   if (BABY_Z_VAR != _offset) {
     _offset = BABY_Z_VAR;
-    DWINUI::Draw_Signed_Float(DWIN_FONT_STAT, HMI_data.Indicator_Color,  HMI_data.Background_Color, 2, 2, 210, 417, _offset);
+    DWINUI::Draw_Signed_Float(DWIN_FONT_STAT, HMI_data.Indicator_Color,  HMI_data.Background_Color, 2, 2, 204, 417, _offset);
   }
 
   #if HAS_MESH
@@ -908,15 +853,6 @@ void make_name_without_ext(char *dst, char *src, size_t maxlen=MENU_CHAR_LIMIT)
 
 void HMI_SDCardInit() { card.cdroot(); }
 
-// Initialize or re-initialize the LCD
-void MarlinUI::init_lcd() { DWIN_Startup(); }
-
-void MarlinUI::refresh() { /* Nothing to see here */ }
-
-#if HAS_LCD_BRIGHTNESS
-  void MarlinUI::_set_brightness() { DWIN_LCD_Brightness(backlight ? brightness : 0); }
-#endif
-
 #if ENABLED(SCROLL_LONG_FILENAMES)
 
   char shift_name[LONG_FILENAME_LENGTH + 1];
@@ -966,7 +902,8 @@ void Draw_SDItem(const uint16_t item, int16_t row=-1) {
   // Draw the file/folder with name aligned left
   char str[strlen(name) + 1];
   make_name_without_ext(str, name);
-  Draw_Menu_Line(row, card.flag.filenameIsDir ? ICON_Folder : ICON_File, str);
+  const uint8_t icon = card.flag.filenameIsDir ? ICON_Folder : card.fileIsBinary() ? ICON_Binary : ICON_File;
+  Draw_Menu_Line(row, icon, str);
 }
 
 #if ENABLED(SCROLL_LONG_FILENAMES)
@@ -1045,11 +982,8 @@ void HMI_SDCardUpdate() {
         Redraw_SD_List();
       }
       else if (sdprint && card.isPrinting() && printingIsActive()) {
-        // TODO: Move card removed abort handling
-        //       to CardReader::manage_media.
-        card.abortFilePrintSoon();
         wait_for_heatup = wait_for_user = false;
-        dwin_abort_flag = true; // Reset feedrate, return to Home
+        HMI_flag.abort_flag = true; // Abort print
       }
     }
     DWIN_UpdateLCD();
@@ -1057,10 +991,10 @@ void HMI_SDCardUpdate() {
 }
 
 //
-// The status area is always on-screen, except during
-// full-screen modal dialogs. (TODO: Keep alive during dialogs)
+// The Dashboard is always on-screen, except during
+// full-screen modal dialogs.
 //
-void Draw_Status_Area(const bool with_update) {
+void DWIN_Draw_Dashboard() {
 
   DWIN_Draw_Rectangle(1, HMI_data.Background_Color, 0, STATUS_Y + 21, DWIN_WIDTH, DWIN_HEIGHT - 1);
 
@@ -1095,7 +1029,7 @@ void Draw_Status_Area(const bool with_update) {
     DWINUI::Draw_Icon(planner.leveling_active ? ICON_SetZOffset : ICON_Zoffset, 187, 416);
   #endif
 
-  DWINUI::Draw_Signed_Float(DWIN_FONT_STAT, HMI_data.Indicator_Color,  HMI_data.Background_Color, 2, 2, 210, 417, BABY_Z_VAR);
+  DWINUI::Draw_Signed_Float(DWIN_FONT_STAT, HMI_data.Indicator_Color,  HMI_data.Background_Color, 2, 2, 204, 417, BABY_Z_VAR);
 
   DWIN_Draw_Rectangle(1, HMI_data.SplitLine_Color, 0, 449, DWIN_WIDTH, 451);
 
@@ -1104,16 +1038,6 @@ void Draw_Status_Area(const bool with_update) {
   DWINUI::Draw_Icon(ICON_MaxSpeedZ, 180, 456);
   _draw_xyz_position(true);
 
-  if (with_update) {
-    DWIN_UpdateLCD();
-    delay(5);
-  }
-}
-
-void HMI_StartFrame(const bool with_update) {
-  Goto_Main_Menu();
-  DWIN_DrawStatusLine(nullptr);
-  Draw_Status_Area(with_update);
 }
 
 void Draw_Info_Menu() {
@@ -1143,8 +1067,6 @@ void Draw_Info_Menu() {
     DWINUI::Draw_Icon(ICON_PrintSize + i, ICOX, 99 + i * 73);
     DWIN_Draw_HLine(HMI_data.SplitLine_Color, 16, MBASE(2) + i * 73, 240);
   }
-
-  DWIN_UpdateLCD();
 }
 
 void Draw_Print_File_Menu() {
@@ -1166,7 +1088,7 @@ void HMI_MainMenu() {
         case PAGE_PRINT: ICON_Print(); break;
         case PAGE_PREPARE: ICON_Print(); ICON_Prepare(); break;
         case PAGE_CONTROL: ICON_Prepare(); ICON_Control(); break;
-        case PAGE_INFO_LEV_ADV: ICON_Control(); ICON_AdvSettings(); break;
+        case PAGE_ADVANCE: ICON_Control(); ICON_AdvSettings(); break;
       }
     }
   }
@@ -1176,7 +1098,7 @@ void HMI_MainMenu() {
         case PAGE_PRINT: ICON_Print(); ICON_Prepare(); break;
         case PAGE_PREPARE: ICON_Prepare(); ICON_Control(); break;
         case PAGE_CONTROL: ICON_Control(); ICON_AdvSettings(); break;
-        case PAGE_INFO_LEV_ADV: ICON_AdvSettings(); break;
+        case PAGE_ADVANCE: ICON_AdvSettings(); break;
       }
     }
   }
@@ -1185,14 +1107,12 @@ void HMI_MainMenu() {
       case PAGE_PRINT:
         checkkey = SelectFile;
         card.mount();
+        delay(300);
         Draw_Print_File_Menu();
         break;
-
       case PAGE_PREPARE: Draw_Prepare_Menu(); break;
-
       case PAGE_CONTROL: Draw_Control_Menu(); break;
-
-      case PAGE_INFO_LEV_ADV: Draw_AdvancedSettings_Menu(); break;
+      case PAGE_ADVANCE: Draw_AdvancedSettings_Menu(); break;
     }
   }
   DWIN_UpdateLCD();
@@ -1277,7 +1197,7 @@ void HMI_SelectFile() {
   else if (encoder_diffState == ENCODER_DIFF_ENTER) {
     if (select_file.now == 0) { // Back
       select_page.set(PAGE_PRINT);
-      Goto_Main_Menu();
+      return Goto_Main_Menu();
     }
     else if (hasUpDir && select_file.now == 1) { // CD-Up
       SDCard_Up();
@@ -1301,16 +1221,10 @@ void HMI_SelectFile() {
       HMI_flag.heat_flag = true;
       HMI_flag.print_finish = false;
 
-      card.openAndPrintFile(card.filename);
-
-      #if HAS_FAN
-        // All fans on for Ender 3 v2 ?
-        // The slicer should manage this for us.
-        //for (uint8_t i = 0; i < FAN_COUNT; i++)
-        //  thermalManager.fan_speed[i] = 255;
-      #endif
-
-      DWIN_Print_Started(true);
+      if (card.fileIsBinary())
+        return DWIN_Popup_Confirm(ICON_Error, F("Please check filenames"), F("Only G-code can be printed"));
+      else
+        return Goto_ConfirmToPrint();
     }
   }
 
@@ -1318,6 +1232,16 @@ void HMI_SelectFile() {
   DWIN_UpdateLCD();
 }
 
+// Pause or Stop popup
+void onClick_PauseOrStop() {
+  switch (select_print.now) {
+    case PRINT_PAUSE_RESUME: if (HMI_flag.select_flag) HMI_flag.pause_flag = true; break; // confirm pause
+    case PRINT_STOP: if (HMI_flag.select_flag) HMI_flag.abort_flag = true; break; // stop confirmed then abort print
+    default: break;
+  }
+  return Goto_PrintProcess();
+}
+
 // Printing
 void HMI_Printing() {
   EncoderState encoder_diffState = get_encoder_state();
@@ -1345,93 +1269,20 @@ void HMI_Printing() {
     switch (select_print.now) {
       case PRINT_SETUP: Draw_Tune_Menu(); break;
       case PRINT_PAUSE_RESUME:
-        if (HMI_flag.pause_flag) {
-          ICON_Pause();
-          #if DISABLED(ADVANCED_PAUSE_FEATURE)
-            char cmd[40];
-            cmd[0] = '\0';
-            #if BOTH(HAS_HEATED_BED, PAUSE_HEAT)
-              if (resume_bed_temp) sprintf_P(cmd, PSTR("M190 S%i\n"), resume_bed_temp);
-            #endif
-            #if BOTH(HAS_HOTEND, PAUSE_HEAT)
-              if (resume_hotend_temp) sprintf_P(&cmd[strlen(cmd)], PSTR("M109 S%i\n"), resume_hotend_temp);
-            #endif
-            #if HAS_FAN
-              if (resume_fan) thermalManager.fan_speed[0] = resume_fan;
-            #endif
-            strcat_P(cmd, M24_STR);
-            queue.inject(cmd);
-          #endif
+        if (printingIsPaused()) {  // if printer is already in pause
+          ui.resume_print();
+          break;
         }
-        else {
-          HMI_flag.select_flag = true;
-          checkkey = PauseOrStop;
-          Popup_window_PauseOrStop();
-        }
-        break;
-
+        else
+          return Goto_Popup(Popup_window_PauseOrStop, onClick_PauseOrStop);
       case PRINT_STOP:
-        HMI_flag.select_flag = true;
-        checkkey = PauseOrStop;
-        Popup_window_PauseOrStop();
-        break;
-
+        return Goto_Popup(Popup_window_PauseOrStop, onClick_PauseOrStop);
       default: break;
     }
   }
   DWIN_UpdateLCD();
 }
 
-// Print done
-void HMI_PrintDone() {
-  EncoderState encoder_diffState = get_encoder_state();
-  if (encoder_diffState == ENCODER_DIFF_NO) return;
-  if (encoder_diffState == ENCODER_DIFF_ENTER) {
-    dwin_abort_flag = true; // Reset feedrate, return to Home
-    Goto_Main_Menu(); // Return to Main menu after print done
-  }
-}
-
-// Pause or Stop popup
-void HMI_PauseOrStop() {
-  EncoderState encoder_diffState = get_encoder_state();
-  if (encoder_diffState == ENCODER_DIFF_NO) return;
-
-  if (encoder_diffState == ENCODER_DIFF_CW)
-    Draw_Select_Highlight(false);
-  else if (encoder_diffState == ENCODER_DIFF_CCW)
-    Draw_Select_Highlight(true);
-  else if (encoder_diffState == ENCODER_DIFF_ENTER) {
-    if (select_print.now == PRINT_PAUSE_RESUME) {
-      if (HMI_flag.select_flag) {
-        HMI_flag.pause_action = true;
-        ICON_Resume();
-        queue.inject(F("M25"));
-      }
-      else {
-        // cancel pause
-      }
-      Goto_PrintProcess();
-    }
-    else if (select_print.now == PRINT_STOP) {
-      if (HMI_flag.select_flag) {
-        checkkey = MainMenu;
-        if (HMI_flag.home_flag) planner.synchronize(); // Wait for planner moves to finish!
-        wait_for_heatup = wait_for_user = false;       // Stop waiting for heating/user
-        card.abortFilePrintSoon();                     // Let the main loop handle SD abort
-        dwin_abort_flag = true;                        // Reset feedrate, return to Home
-        #ifdef ACTION_ON_CANCEL
-          hostui.cancel();
-        #endif
-        DWIN_Draw_Popup(ICON_BLTouch, GET_TEXT_F(MSG_STOPPING), GET_TEXT_F(MSG_PLEASE_WAIT));
-      }
-      else
-        Goto_PrintProcess(); // cancel stop
-    }
-  }
-  DWIN_UpdateLCD();
-}
-
 #include "../../../libs/buzzer.h"
 
 void HMI_AudioFeedback(const bool success/*=true*/) {
@@ -1452,24 +1303,11 @@ void Draw_Main_Area() {
     case SelectFile:             Draw_Print_File_Menu(); break;
     case PrintProcess:           Draw_PrintProcess(); break;
     case PrintDone:              Draw_PrintDone(); break;
-    case Info:                   Draw_Info_Menu(); break;
     #if HAS_ESDIAG
       case ESDiagProcess:        Draw_EndStopDiag(); break;
     #endif
-    #if ENABLED(PRINTCOUNTER)
-      case PrintStatsProcess:    Draw_PrintStats(); break;
-    #endif
-    case PauseOrStop:            Popup_window_PauseOrStop(); break;
-    #if ENABLED(POWER_LOSS_RECOVERY)
-      case PwrlossRec:           Popup_PowerLossRecovery(); break;
-    #endif
-    #if ENABLED(ADVANCED_PAUSE_FEATURE)
-      case FilamentPurge:        Draw_Popup_FilamentPurge(); break;
-    #endif
+    case Popup:                  popupDraw(); break;
     case Locked:                 lockScreen.draw(); break;
-    #if HAS_GCODE_PREVIEW
-      case ConfirmToPrint:       Draw_PreviewFromSD(); break;
-    #endif
     case Menu:
     case SetInt:
     case SetPInt:
@@ -1484,19 +1322,32 @@ void HMI_ReturnScreen() {
   checkkey = last_checkkey;
   wait_for_user = false;
   Draw_Main_Area();
-  return;
 }
 
-void HMI_Popup() {
-  EncoderState encoder_diffState = get_encoder_state();
-  if (encoder_diffState == ENCODER_DIFF_NO) return;
-  if (encoder_diffState == ENCODER_DIFF_ENTER) {
-    HMI_ReturnScreen();
+void HMI_WaitForUser() {
+  get_encoder_state();
+  if (!wait_for_user) {
+    switch (checkkey) {
+      case PrintDone:
+        select_page.reset();
+        Goto_Main_Menu();
+        break;
+      #if HAS_ONESTEP_LEVELING
+      case Leveling:
+        //TERN_(ProUI, ProEx.StopLeveling());
+        HMI_ReturnScreen();
+        break;
+      #endif
+      default:
+        HMI_ReturnScreen();
+        break;
+    }
   }
 }
 
 void HMI_Init() {
-  HMI_SDCardInit();
+  DWINUI::Draw_Box(1, Color_Black, {5, 220, DWIN_WIDTH-5, DWINUI::fontHeight()});
+  DWINUI::Draw_CenteredString(Color_White, 220, F("Professional Firmware "));
   for (uint16_t t = 0; t <= 100; t += 2) {
     DWINUI::Draw_Icon(ICON_Bar, 15, 260);
     DWIN_Draw_Rectangle(1, HMI_data.Background_Color, 15 + t * 242 / 100, 260, 257, 280);
@@ -1506,12 +1357,6 @@ void HMI_Init() {
   HMI_SetLanguage();
 }
 
-void DWIN_Update() {
-  EachMomentUpdate();   // Status update
-  HMI_SDCardUpdate();   // SD card update
-  DWIN_HandleScreen();  // Rotary encoder update
-}
-
 void EachMomentUpdate() {
   static millis_t next_var_update_ms = 0, next_rts_update_ms = 0, next_status_update_ms = 0;
 
@@ -1538,52 +1383,45 @@ void EachMomentUpdate() {
   if (PENDING(ms, next_rts_update_ms)) return;
   next_rts_update_ms = ms + DWIN_SCROLL_UPDATE_INTERVAL;
 
-  if (checkkey == PrintProcess) {
-    // if print done
-    if (HMI_flag.print_finish) {
-      HMI_flag.print_finish = false;
-      TERN_(POWER_LOSS_RECOVERY, recovery.cancel());
-      planner.finish_and_disable();
-      checkkey = PrintDone;
-      Draw_PrintDone();
-    }
-    else if (HMI_flag.pause_flag != printingIsPaused()) {
-      // print status update
-      HMI_flag.pause_flag = printingIsPaused();
-      ICON_ResumeOrPause();
-    }
-  }
-
-  // pause after homing
-  if (HMI_flag.pause_action && printingIsPaused() && !planner.has_blocks_queued()) {
-    HMI_flag.pause_action = false;
-    #if ENABLED(PAUSE_HEAT)
-      TERN_(HAS_HOTEND, resume_hotend_temp = sdprint ? thermalManager.degTargetHotend(0) : thermalManager.wholeDegHotend(0));
-      TERN_(HAS_HEATED_BED, resume_bed_temp = sdprint ? thermalManager.degTargetBed() : thermalManager.wholeDegBed());
-      TERN_(HAS_FAN, resume_fan = thermalManager.fan_speed[0]);
-    #endif
-    IF_DISABLED(ADVANCED_PAUSE_FEATURE, thermalManager.disable_all_heaters());
-    IF_DISABLED(PARK_HEAD_ON_PAUSE, queue.inject(F("G1 F1200 X0 Y0")));
-  }
-
   if (checkkey == PrintProcess) { // print process
 
+    // Print pause
+    if (HMI_flag.pause_flag && !HMI_flag.home_flag) {
+      HMI_flag.pause_flag = false;
+      if (!HMI_flag.pause_action) {
+        HMI_flag.pause_action = true;
+        return ui.pause_print();
+      }
+    }
+
+    // if print done
+    if (HMI_flag.print_finish && !HMI_flag.home_flag) {
+      HMI_flag.print_finish = false;
+      return DWIN_Print_Finished();
+    }
+
+    // if print was aborted
+    if (HMI_flag.abort_flag && !HMI_flag.home_flag) { // Print Stop
+      HMI_flag.abort_flag = false;
+      if (!HMI_flag.abort_action) {
+        HMI_flag.abort_action = true;
+        ui.abort_print();
+        return Goto_PrintDone();
+      }
+    }
+
     duration_t elapsed = print_job_timer.duration(); // print timer
 
     if (sdprint && card.isPrinting()) {
       uint8_t percentDone = card.percentDone();
-      static uint8_t last_percentValue = 101;
-      if (last_percentValue != percentDone) { // print percent
-        last_percentValue = percentDone;
-        if (percentDone) {
+      if (_percent_done != percentDone) { // print percent
           _percent_done = percentDone;
           Draw_Print_ProgressBar();
         }
-      }
 
       // Estimate remaining time every 20 seconds
       static millis_t next_remain_time_update = 0;
-      if (_percent_done > 1 && ELAPSED(ms, next_remain_time_update) && !HMI_flag.heat_flag) {
+      if (_percent_done > 1 && ELAPSED(ms, next_remain_time_update) && !HMI_flag.heat_flag && !HMI_flag.remain_flag) {
         _remain_time = (elapsed.value - dwin_heat_time) / (_percent_done * 0.01f) - (elapsed.value - dwin_heat_time);
         next_remain_time_update += DWIN_REMAIN_TIME_UPDATE_INTERVAL;
         Draw_Print_ProgressRemain();
@@ -1599,12 +1437,6 @@ void EachMomentUpdate() {
     }
 
   }
-  else if (dwin_abort_flag && !HMI_flag.home_flag) { // Print Stop
-    dwin_abort_flag = false;
-    dwin_zoffset = BABY_Z_VAR;
-    select_page.set(PAGE_PRINT);
-    Goto_Main_Menu();
-  }
 
   #if ENABLED(POWER_LOSS_RECOVERY)
     else if (DWIN_lcd_sd_status && recovery.dwin_flag) { // resume print before power off
@@ -1629,8 +1461,8 @@ void EachMomentUpdate() {
       DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 70, GET_TEXT_F(MSG_OUTAGE_RECOVERY));
       DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 147, F("It looks like the last"));
       DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 167, F("file was interrupted."));
-      DWINUI::Draw_IconWB(ICON_Cancel_E,    26, 280);
-      DWINUI::Draw_IconWB(ICON_Continue_E, 146, 280);
+      DWINUI::Draw_Button(BTN_Cancel,    26, 280);
+      DWINUI::Draw_Button(BTN_Continue, 146, 280);
     }
     SdFile *dir = nullptr;
     const char * const filename = card.diveToFile(true, dir, recovery.info.sd_filename);
@@ -1640,35 +1472,26 @@ void EachMomentUpdate() {
     DWIN_UpdateLCD();
   }
 
+  void onClick_PowerLossRecovery() {
+    if (HMI_flag.select_flag) {
+      queue.inject(F("M1000C"));
+      select_page.reset();
+      return Goto_Main_Menu();
+    }
+    else {
+      select_print.set(PRINT_SETUP);
+      queue.inject(F("M1000"));
+      sdprint = true;
+      return Goto_PrintProcess();
+    }
+  }
+
   void Goto_PowerLossRecovery() {
     recovery.dwin_flag = false;
     LCD_MESSAGE_F(GET_TEXT_F(MSG_CONTINUE_PRINT_JOB));
-    HMI_flag.select_flag = false;
-    Popup_PowerLossRecovery();
-    last_checkkey = MainMenu;
-    checkkey = PwrlossRec;
+    Goto_Popup(Popup_PowerLossRecovery, onClick_PowerLossRecovery);
   }
 
-  void HMI_PowerlossRecovery() {
-    EncoderState encoder_diffState = get_encoder_state();
-    if (encoder_diffState == ENCODER_DIFF_NO) return;
-    if (encoder_diffState == ENCODER_DIFF_ENTER) {
-      if (HMI_flag.select_flag) {
-        queue.inject(F("M1000C"));
-        select_page.reset();
-        Goto_Main_Menu();
-      }
-      else {
-        select_print.set(PRINT_SETUP);
-        queue.inject(F("M1000"));
-        sdprint = true;
-        Goto_PrintProcess();
-      }
-    }
-    else
-      Draw_Select_Highlight(encoder_diffState != ENCODER_DIFF_CW);
-    DWIN_UpdateLCD();
-  }
 #endif // POWER_LOSS_RECOVERY
 
 
@@ -1682,49 +1505,39 @@ void DWIN_HandleScreen() {
     case SetFloat:        HMI_SetFloat(); break;
     case SetPFloat:       HMI_SetPFloat(); break;
     case SelectFile:      HMI_SelectFile(); break;
-    case Homing:          break;
-    case Leveling:        break;
     case PrintProcess:    HMI_Printing(); break;
-    case PrintDone:       HMI_PrintDone(); break;
-    case PauseOrStop:     HMI_PauseOrStop(); break;
-    case Info:            HMI_Popup(); break;
-    case WaitResponse:    HMI_Popup(); break;
-    #if ENABLED(ADVANCED_PAUSE_FEATURE)
-      case FilamentPurge: HMI_FilamentPurge(); break;
-    #endif
-    case NothingToDo:     break;
+    case Popup:           HMI_Popup(); break;
+    case Leveling:        //TERN_(ProUI, HMI_WaitForUser());
+                          break;
     case Locked:          HMI_LockScreen(); break;
-    #if ENABLED(POWER_LOSS_RECOVERY)
-      case PwrlossRec:    HMI_PowerlossRecovery(); break;
-    #endif
-    #if HAS_GCODE_PREVIEW
-      case ConfirmToPrint: HMI_ConfirmToPrint(); break;
-    #endif
-    #if HAS_ESDIAG
-      case ESDiagProcess: HMI_Popup(); break;
-    #endif
-    #if ENABLED(PRINTCOUNTER)
-      case PrintStatsProcess: HMI_Popup(); break;
-    #endif
+    case PrintDone:
+    TERN_(HAS_ESDIAG, case ESDiagProcess:)
+    case WaitResponse:    HMI_WaitForUser(); break;
+    case Homing:
+    case PidProcess:
+    case NothingToDo:     break;
     default: break;
   }
 }
 
 bool IDisPopUp() {    // If ID is popup...
-  return  (checkkey == NothingToDo) ||
-          (checkkey == WaitResponse) ||
-          (checkkey == Info) ||
-          (checkkey == Homing) ||
-          (checkkey == Leveling) ||
-          TERN_(HAS_ESDIAG, (checkkey == ESDiagProcess) ||)
-          TERN_(PRINTCOUNTER, (checkkey == PrintStatsProcess) ||)
-          (checkkey == PauseOrStop) ||
-          (checkkey == FilamentPurge);
+  return  (checkkey == NothingToDo)
+       || (checkkey == WaitResponse)
+       || (checkkey == Homing)
+       || (checkkey == Leveling)
+       || (checkkey == PidProcess)
+       || TERN0(HAS_ESDIAG, (checkkey == ESDiagProcess))
+       || (checkkey == Popup);
 }
 
 void HMI_SaveProcessID(const uint8_t id) {
   if (checkkey != id) {
     if (!IDisPopUp()) last_checkkey = checkkey; // if previous is not a popup
+    if ((id == Popup)
+         || TERN0(HAS_ESDIAG, (id == ESDiagProcess))
+         || (id == PrintDone)
+         || (id == Leveling)
+         || (id == WaitResponse)) wait_for_user = true;
     checkkey = id;
   }
 }
@@ -1732,37 +1545,35 @@ void HMI_SaveProcessID(const uint8_t id) {
 void DWIN_StartHoming() {
   HMI_flag.home_flag = true;
   HMI_SaveProcessID(Homing);
-  Title.ShowCaption(GET_TEXT_F(MSG_LEVEL_BED_HOMING));
-  DWIN_Draw_Popup(ICON_BLTouch, GET_TEXT_F(MSG_LEVEL_BED_HOMING), GET_TEXT_F(MSG_PLEASE_WAIT));
+  Title.ShowCaption(GET_TEXT_F(MSG_HOMING));
+  DWIN_Show_Popup(ICON_BLTouch, GET_TEXT_F(MSG_HOMING), GET_TEXT_F(MSG_PLEASE_WAIT));
 }
 
 void DWIN_CompletedHoming() {
   HMI_flag.home_flag = false;
   dwin_zoffset = TERN0(HAS_BED_PROBE, probe.offset.z);
-  if (dwin_abort_flag) {
-    planner.finish_and_disable();
-  }
-  HMI_ReturnScreen();
+  if (HMI_flag.abort_action) DWIN_Print_Aborted(); else HMI_ReturnScreen();
 }
 
 void DWIN_MeshLevelingStart() {
   #if HAS_ONESTEP_LEVELING
     HMI_SaveProcessID(Leveling);
     Title.ShowCaption(GET_TEXT_F(MSG_BED_LEVELING));
-    DWIN_Show_Popup(ICON_AutoLeveling, GET_TEXT_F(MSG_BED_LEVELING), GET_TEXT_F(MSG_PLEASE_WAIT), ICON_Cancel_E);
+    DWIN_Show_Popup(ICON_AutoLeveling, GET_TEXT_F(MSG_BED_LEVELING), GET_TEXT_F(MSG_PLEASE_WAIT));
   #elif ENABLED(MESH_BED_LEVELING)
     Draw_ManualMesh_Menu();
   #endif
 }
 
-void DWIN_CompletedLeveling() { TERN_(HAS_MESH, DWIN_MeshViewer()); }
+void DWIN_CompletedLeveling() {
+  TERN_(HAS_ONESTEP_LEVELING, if (planner.leveling_active) Goto_MeshViewer());
+}
 
 #if HAS_MESH
-  void DWIN_MeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {
+  void DWIN_MeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) {
     char msg[33] = "";
     char str_1[6] = "";
-    sprintf_P(msg, PSTR(S_FMT " %i/%i Z=%s"), GET_TEXT(MSG_PROBING_POINT), xpos, ypos,
-      dtostrf(zval, 1, 2, str_1));
+    sprintf_P(msg, PSTR(S_FMT " %i/%i Z=%s"), GET_TEXT(MSG_PROBING_POINT), xpos, ypos, dtostrf(zval, 1, 2, str_1));
     ui.set_status(msg);
   }
 #endif
@@ -1800,67 +1611,63 @@ void DWIN_PidTuning(pidresult_t result) {
   }
 }
 
-// Update filename on print
-void DWIN_Print_Header(const char *text = nullptr) {
-  static char headertxt[31] = "";  // Print header text
-
-  if (text) {
-    const int8_t size = _MIN((unsigned) 30, strlen_P(text));
-    LOOP_L_N(i, size) headertxt[i] = text[i];
-    headertxt[size] = '\0';
-  }
-  if (checkkey == PrintProcess || checkkey == PrintDone) {
-    DWIN_Draw_Rectangle(1, HMI_data.Background_Color, 0, 60, DWIN_WIDTH, 60+16);
-    DWINUI::Draw_CenteredString(60, headertxt);
-  }
-}
-
-void Draw_Title(TitleClass* title) {
-  DWIN_Draw_Rectangle(1, HMI_data.TitleBg_color, 0, 0, DWIN_WIDTH - 1, TITLE_HEIGHT - 1);
-  if (title->frameid)
-    DWIN_Frame_AreaCopy(title->frameid, title->frame.left, title->frame.top, title->frame.right, title->frame.bottom, 14, (TITLE_HEIGHT - (title->frame.bottom - title->frame.top)) / 2 - 1);
-  else
-    DWIN_Draw_String(false, DWIN_FONT_HEAD, HMI_data.TitleTxt_color, HMI_data.TitleBg_color, 14, (TITLE_HEIGHT - DWINUI::fontHeight(DWIN_FONT_HEAD)) / 2 - 1, title->caption);
-}
-
-void Draw_Menu(MenuClass* menu) {
-  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color);
-  DWIN_Draw_Rectangle(1, DWINUI::backcolor, 0, TITLE_HEIGHT, DWIN_WIDTH - 1, STATUS_Y - 1);
-  DWIN_ResetStatusLine();
-}
-
-// Startup routines
-void DWIN_Startup() {
-  DWINUI::init();
-  DWINUI::onCursorDraw = Draw_Menu_Cursor;
-  DWINUI::onCursorErase = Erase_Menu_Cursor;
-  DWINUI::onTitleDraw = Draw_Title;
-  DWINUI::onMenuDraw = Draw_Menu;
-  DWIN_JPG_ShowAndCache(3);
-  HMI_SetLanguage();
-}
-
 // Started a Print Job
 void DWIN_Print_Started(const bool sd) {
-  sdprint = card.isPrinting() || sd;
+  sdprint = IS_SD_PRINTING() || sd;
   _percent_done = 0;
   _remain_time = 0;
+  HMI_flag.remain_flag = false;
+  HMI_flag.pause_flag = false;
+  HMI_flag.pause_action = false;
+  HMI_flag.abort_flag = false;
+  HMI_flag.abort_action = false;
   HMI_flag.print_finish = false;
   Goto_PrintProcess();
 }
 
+// Pause a print job
+void DWIN_Print_Pause() {
+  ICON_ResumeOrPause();
+}
+
+// Resume print job
+void DWIN_Print_Resume() {
+  HMI_flag.pause_action = false;
+  ICON_ResumeOrPause();
+  if (printJobOngoing()) {
+    LCD_MESSAGE(MSG_RESUME_PRINT);
+    Goto_PrintProcess();
+  }
+}
+
 // Ended print job
 void DWIN_Print_Finished() {
-  if (checkkey == PrintProcess || printingIsActive()) {
+  if (HMI_flag.abort_flag || checkkey == PrintDone) return;
+  TERN_(POWER_LOSS_RECOVERY, if (card.isPrinting()) recovery.cancel());
+  HMI_flag.pause_flag = false;
+  wait_for_heatup = false;
+  planner.finish_and_disable();
     thermalManager.cooldown();
-    HMI_flag.print_finish = true;
-  }
+  Goto_PrintDone();
+}
+
+// Print was aborted
+void DWIN_Print_Aborted() {
+  TERN_(DEBUG_DWIN, SERIAL_ECHOLNPGM("DWIN_Print_Aborted"));
+  HMI_flag.abort_action = false;
+  wait_for_heatup = false;
+  planner.finish_and_disable();
+  thermalManager.cooldown();
+  Goto_PrintDone();
 }
 
 // Progress Bar update
 void DWIN_Progress_Update() {
   if (parser.seenval('P')) _percent_done = parser.byteval('P');
-  if (parser.seenval('R')) _remain_time = parser.ulongval('R') * 60;
+  if (parser.seenval('R')) {
+    _remain_time = parser.ulongval('R') * 60;
+    HMI_flag.remain_flag = true;
+  }
   if (checkkey == PrintProcess) {
     Draw_Print_ProgressBar();
     Draw_Print_ProgressRemain();
@@ -1896,11 +1703,18 @@ void DWIN_SetColorDefaults() {
 
 void DWIN_SetDataDefaults() {
   DWIN_SetColorDefaults();
-  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color);
-  TERN_(HAS_HOTEND,             HMI_data.HotendPidT = PREHEAT_1_TEMP_HOTEND);
-  TERN_(HAS_HEATED_BED,         HMI_data.BedPidT    = PREHEAT_1_TEMP_BED);
-  TERN_(HAS_HOTEND,             HMI_data.PidCycles  = 5);
-  TERN_(PREVENT_COLD_EXTRUSION, HMI_data.ExtMinT    = EXTRUDE_MINTEMP);
+  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color, HMI_data.StatusBg_Color);
+  TERN_(HAS_HOTEND,     HMI_data.HotendPidT = PREHEAT_1_TEMP_HOTEND);
+  TERN_(HAS_HEATED_BED, HMI_data.BedPidT    = PREHEAT_1_TEMP_BED);
+  TERN_(HAS_HOTEND,     HMI_data.PidCycles  = 5);
+  #if ENABLED(PREVENT_COLD_EXTRUSION)
+    HMI_data.ExtMinT = EXTRUDE_MINTEMP;
+    ApplyExtMinT();
+  #endif
+  #if BOTH(HAS_HEATED_BED, PREHEAT_BEFORE_LEVELING)
+    HMI_data.BedLevT = PREHEAT_1_TEMP_BED;
+  #endif
+  TERN_(BAUD_RATE_GCODE, SetBaud250K());
 }
 
 void DWIN_StoreSettings(char *buff) {
@@ -1912,9 +1726,10 @@ void DWIN_LoadSettings(const char *buff) {
   memcpy((void *)&HMI_data, buff, _MIN(sizeof(HMI_data), eeprom_data_size));
   dwin_zoffset = TERN0(HAS_BED_PROBE, probe.offset.z);
   if (HMI_data.Text_Color == HMI_data.Background_Color) DWIN_SetColorDefaults();
-  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color);
+  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color, HMI_data.StatusBg_Color);
   TERN_(PREVENT_COLD_EXTRUSION, ApplyExtMinT());
   feedrate_percentage = 100;
+  TERN_(BAUD_RATE_GCODE, HMI_SetBaudRate());
   #if BOTH(CASE_LIGHT_MENU, CASELIGHT_USES_BRIGHTNESS)
     // Apply Case light brightness
     caselight.brightness = HMI_data.CaseLight_Brightness;
@@ -1926,6 +1741,37 @@ void DWIN_LoadSettings(const char *buff) {
   #endif
 }
 
+// Initialize or re-initialize the LCD
+void MarlinUI::init_lcd() {
+  TERN_(DEBUG_DWIN, SERIAL_ECHOLNPGM("DWIN_Startup"));
+  DWINUI::init();
+  DWIN_JPG_CacheTo1(Language_English);
+  Encoder_Configuration();
+}
+
+void DWIN_InitScreen() {
+  HMI_Init();   // draws boot screen
+  DWINUI::onCursorDraw = Draw_Menu_Cursor;
+  DWINUI::onCursorErase = Erase_Menu_Cursor;
+  DWINUI::onTitleDraw = Draw_Title;
+  DWINUI::onMenuDraw = Draw_Menu;
+  DWIN_DrawStatusLine(nullptr);
+  DWIN_Draw_Dashboard();
+  Goto_Main_Menu();
+}
+
+void MarlinUI::update() {
+  EachMomentUpdate();   // Status update
+  HMI_SDCardUpdate();   // SD card update
+  DWIN_HandleScreen();  // Rotary encoder update
+}
+
+void MarlinUI::refresh() { /* Nothing to see here */ }
+
+#if HAS_LCD_BRIGHTNESS
+  void MarlinUI::_set_brightness() { DWIN_LCD_Brightness(backlight ? brightness : 0); }
+#endif
+
 void MarlinUI::kill_screen(FSTR_P const lcd_error, FSTR_P const lcd_component) {
   DWIN_Draw_Popup(ICON_BLTouch, F("Printer killed:"), lcd_error);
   DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 270, F("Turn off the printer"));
@@ -1938,65 +1784,55 @@ void DWIN_RebootScreen() {
   DWINUI::Draw_CenteredString(Color_White, 220, GET_TEXT_F(MSG_PLEASE_WAIT_REBOOT));
   DWIN_UpdateLCD();
   delay(500);
-  DWIN_JPG_ShowAndCache(3);
 }
 
 void DWIN_Redraw_screen() {
   Draw_Main_Area();
-  Draw_Status_Area(false);
+  hash_changed = true;
+  DWIN_DrawStatusMessage();
+  DWIN_Draw_Dashboard();
 }
 
 #if ENABLED(ADVANCED_PAUSE_FEATURE)
-
-  void DWIN_Popup_Pause(FSTR_P const fmsg, uint8_t button = 0) {
+  void DWIN_Popup_Pause(FSTR_P const fmsg, uint8_t button /*= 0*/) {
     HMI_SaveProcessID(button ? WaitResponse : NothingToDo);
-    DWIN_Draw_Popup(ICON_BLTouch, GET_TEXT_F(MSG_ADVANCED_PAUSE), fmsg, button);
-    ui.reset_status(true);
+    DWIN_Show_Popup(ICON_BLTouch, GET_TEXT_F(MSG_ADVANCED_PAUSE), fmsg, button);
   }
 
   void MarlinUI::pause_show_message(const PauseMessage message, const PauseMode mode/*=PAUSE_MODE_SAME*/, const uint8_t extruder/*=active_extruder*/) {
+    //if (mode == PAUSE_MODE_SAME) return;
+    pause_mode = mode;
     switch (message) {
-      case PAUSE_MESSAGE_PARKING:  DWIN_Popup_Pause(GET_TEXT_F(MSG_PAUSE_PRINT_PARKING));    break;
-      case PAUSE_MESSAGE_CHANGING: DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_INIT));   break;
-      case PAUSE_MESSAGE_UNLOAD:   DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_UNLOAD)); break;
-      case PAUSE_MESSAGE_WAITING:  DWIN_Popup_Pause(GET_TEXT_F(MSG_ADVANCED_PAUSE_WAITING), ICON_Continue_E); break;
+      case PAUSE_MESSAGE_PARKING:  DWIN_Popup_Pause(GET_TEXT_F(MSG_PAUSE_PRINT_PARKING));    break;                                     // M125
+      case PAUSE_MESSAGE_CHANGING: DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_INIT));   break;                                     // pause_print (M125, M600)
+      case PAUSE_MESSAGE_WAITING:  DWIN_Popup_Pause(GET_TEXT_F(MSG_ADVANCED_PAUSE_WAITING), BTN_Continue); break;
       case PAUSE_MESSAGE_INSERT:   DWIN_Popup_Continue(ICON_BLTouch, GET_TEXT_F(MSG_ADVANCED_PAUSE), GET_TEXT_F(MSG_FILAMENT_CHANGE_INSERT)); break;
       case PAUSE_MESSAGE_LOAD:     DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_LOAD));   break;
-      case PAUSE_MESSAGE_PURGE:    DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE));  break;
-      case PAUSE_MESSAGE_OPTION:   DWIN_Popup_FilamentPurge(); break;
+      case PAUSE_MESSAGE_UNLOAD:   DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_UNLOAD)); break;                                     // Unload of pause and Unload of M702
+      case PAUSE_MESSAGE_PURGE:
+        #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
+          DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_CONT_PURGE));
+        #else
+          DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE));
+        #endif
+        break;
+      case PAUSE_MESSAGE_OPTION:   Goto_FilamentPurge(); break;
       case PAUSE_MESSAGE_RESUME:   DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_RESUME)); break;
-      case PAUSE_MESSAGE_HEAT:     DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_HEAT), ICON_Continue_E);   break;
+      case PAUSE_MESSAGE_HEAT:     DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_HEAT), BTN_Continue);   break;
       case PAUSE_MESSAGE_HEATING:  LCD_MESSAGE(MSG_FILAMENT_CHANGE_HEATING); break;
-      case PAUSE_MESSAGE_STATUS:   HMI_ReturnScreen(); break;
+      case PAUSE_MESSAGE_STATUS:   HMI_ReturnScreen(); break;                                                                         // Exit from Pause, Load and Unload
       default: break;
     }
   }
 
   void Draw_Popup_FilamentPurge() {
     DWIN_Draw_Popup(ICON_BLTouch, GET_TEXT_F(MSG_ADVANCED_PAUSE), F("Purge or Continue?"));
-    DWINUI::Draw_IconWB(ICON_Confirm_E, 26, 280);
-    DWINUI::Draw_IconWB(ICON_Continue_E, 146, 280);
+    DWINUI::Draw_Button(BTN_Confirm, 26, 280);
+    DWINUI::Draw_Button(BTN_Continue, 146, 280);
     Draw_Select_Highlight(true);
-    DWIN_UpdateLCD();
   }
 
-  // Handle responses such as:
-  //  - Purge More, Continue
-  //  - General "Continue" response
-  void DWIN_Popup_FilamentPurge() {
-    HMI_SaveProcessID(FilamentPurge);
-    pause_menu_response = PAUSE_RESPONSE_WAIT_FOR;
-    Draw_Popup_FilamentPurge();
-  }
-
-  void HMI_FilamentPurge() {
-    EncoderState encoder_diffState = get_encoder_state();
-    if (encoder_diffState == ENCODER_DIFF_NO) return;
-    if (encoder_diffState == ENCODER_DIFF_CW)
-      Draw_Select_Highlight(false);
-    else if (encoder_diffState == ENCODER_DIFF_CCW)
-      Draw_Select_Highlight(true);
-    else if (encoder_diffState == ENCODER_DIFF_ENTER) {
+  void onClick_FilamentPurge() {
       if (HMI_flag.select_flag)
         pause_menu_response = PAUSE_RESPONSE_EXTRUDE_MORE;  // "Purge More" button
       else {
@@ -2004,7 +1840,10 @@ void DWIN_Redraw_screen() {
         pause_menu_response = PAUSE_RESPONSE_RESUME_PRINT;  // "Continue" button
       }
     }
-    DWIN_UpdateLCD();
+
+  void Goto_FilamentPurge() {
+    pause_menu_response = PAUSE_RESPONSE_WAIT_FOR;
+    Goto_Popup(Draw_Popup_FilamentPurge, onClick_FilamentPurge);
   }
 
 #endif // ADVANCED_PAUSE_FEATURE
@@ -2042,39 +1881,10 @@ void HMI_LockScreen() {
   if (lockScreen.isUnlocked()) DWIN_UnLockScreen();
 }
 
-#if HAS_GCODE_PREVIEW
-
-  void HMI_ConfirmToPrint() {
-    EncoderState encoder_diffState = get_encoder_state();
-    if (encoder_diffState == ENCODER_DIFF_NO) return;
-    if (encoder_diffState == ENCODER_DIFF_CW)
-      Draw_Select_Highlight(false);
-    else if (encoder_diffState == ENCODER_DIFF_CCW)
-      Draw_Select_Highlight(true);
-    else if (encoder_diffState == ENCODER_DIFF_ENTER) {
-      if (HMI_flag.select_flag) {     // Confirm
-        card.openAndPrintFile(card.filename);
-        DWIN_Print_Started(true);
-      }
-      else {                          // Cancel
-        DWIN_ResetStatusLine();
-        checkkey = SelectFile;
-        Draw_Print_File_Menu();
-      }
-    }
-    DWIN_UpdateLCD();
-  }
-
-#endif
 
 void Goto_ConfirmToPrint() {
-  #if HAS_GCODE_PREVIEW
-    HMI_SaveProcessID(ConfirmToPrint);
-    Draw_PreviewFromSD();
-  #else
-    card.openAndPrintFile(card.filename);
-    DWIN_Print_Started(true);
-  #endif
+  card.openAndPrintFile(card.filename);
+  DWIN_Print_Started(true);
 }
 
 #if HAS_ESDIAG
@@ -2084,103 +1894,11 @@ void Goto_ConfirmToPrint() {
   }
 #endif
 
-#if ENABLED(PRINTCOUNTER)
-  void Draw_PrintStats() {
-    HMI_SaveProcessID(PrintStatsProcess);
-    PrintStats.Draw();
-  }
-#endif
-
 //=============================================================================
 // NEW MENU SUBSYSTEM
 //=============================================================================
 
-// On click functions
-
-// Generic onclick event without draw anything
-//  process: process id HMI destiny
-//  lo: low limit
-//  hi: high limit
-//  dp: decimal places, 0 for integers
-//  val: value / scaled value
-//  LiveUpdate: live update function when the encoder changes
-//  Apply: update function when the encoder is pressed
-void SetOnClick(uint8_t process, const int32_t lo, const int32_t hi, uint8_t dp, const int32_t val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr) {
-  checkkey = process;
-  HMI_value.MinValue = lo;
-  HMI_value.MaxValue = hi;
-  HMI_value.dp = dp;
-  HMI_value.Apply = Apply;
-  HMI_value.LiveUpdate = LiveUpdate;
-  HMI_value.Value = val;
-  EncoderRate.enabled = true;
-}
-
-// Generic onclick event for integer values
-//  process: process id HMI destiny
-//  lo: scaled low limit
-//  hi: scaled high limit
-//  val: value
-//  LiveUpdate: live update function when the encoder changes
-//  Apply: update function when the encoder is pressed
-void SetValueOnClick(uint8_t process, const int32_t lo, const int32_t hi, const int32_t val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr) {
-  SetOnClick(process, lo, hi, 0, val, Apply, LiveUpdate);
-  Draw_Menu_IntValue(HMI_data.Selected_Color, CurrentMenu->line(), 4, HMI_value.Value);
-}
-
-// Generic onclick event for float values
-//  process: process id HMI destiny
-//  lo: scaled low limit
-//  hi: scaled high limit
-//  val: value
-//  LiveUpdate: live update function when the encoder changes
-//  Apply: update function when the encoder is pressed
-void SetValueOnClick(uint8_t process, const float lo, const float hi, uint8_t dp, const float val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr) {
-  const int32_t value =  round(val * POW(10, dp));
-  SetOnClick(process, lo * POW(10, dp), hi * POW(10, dp), dp, value, Apply, LiveUpdate);
-  DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Selected_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(CurrentMenu->line()), val);
-}
-
-// Generic onclick event for integer values
-//  lo: scaled low limit
-//  hi: scaled high limit
-//  val: value
-//  LiveUpdate: live update function when the encoder changes
-//  Apply: update function when the encoder is pressed
-inline void SetIntOnClick(const int32_t lo, const int32_t hi, const int32_t val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr) {
-  SetValueOnClick(SetInt, lo, hi, val, Apply, LiveUpdate);
-}
-
-// Generic onclick event for set pointer to 16 bit uinteger values
-//  lo: low limit
-//  hi: high limit
-//  LiveUpdate: live update function when the encoder changes
-//  Apply: update function when the encoder is pressed
-void SetPIntOnClick(const int32_t lo, const int32_t hi, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr) {
-  HMI_value.P_Int = (int16_t*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
-  const int32_t value = *HMI_value.P_Int;
-  SetValueOnClick(SetPInt, lo, hi, value, Apply, LiveUpdate);
-}
-
-// Generic onclick event for float values
-//  process: process id HMI destiny
-//  lo: low limit
-//  hi: high limit
-//  dp: decimal places
-//  val: value
-inline void SetFloatOnClick(const float lo, const float hi, uint8_t dp, const float val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr) {
-  SetValueOnClick(SetFloat, lo, hi, dp, val, Apply, LiveUpdate);
-}
-
-// Generic onclick event for set pointer to float values
-//  lo: low limit
-//  hi: high limit
-//  LiveUpdate: live update function when the encoder changes
-//  Apply: update function when the encoder is pressed
-void SetPFloatOnClick(const float lo, const float hi, uint8_t dp, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr) {
-  HMI_value.P_Float = (float*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
-  SetValueOnClick(SetPFloat, lo, hi, dp, *HMI_value.P_Float, Apply, LiveUpdate);
-}
+// Tool functions
 
 #if ENABLED(EEPROM_SETTINGS)
   void WriteEeprom() {
@@ -2203,7 +1921,6 @@ void SetPFloatOnClick(const float lo, const float hi, uint8_t dp, void (*Apply)(
 
 // Reset Printer
 void RebootPrinter() {
-  dwin_abort_flag = true;
   wait_for_heatup = wait_for_user = false;    // Stop waiting for heating/user
   thermalManager.disable_all_heaters();
   planner.finish_and_disable();
@@ -2212,8 +1929,8 @@ void RebootPrinter() {
 }
 
 void Goto_Info_Menu(){
-  HMI_SaveProcessID(Info);
   Draw_Info_Menu();
+  HMI_SaveProcessID(WaitResponse);
 }
 
 void Goto_Move_Menu() {
@@ -2226,14 +1943,11 @@ void Goto_Move_Menu() {
 
 void DisableMotors() { queue.inject(F("M84")); }
 
-void AutoLev() { queue.inject(F("G28Z\nG29")); }  // Force to get the current Z home position
+void AutoLev() { queue.inject(F("G28XYO\nG28Z\nG29")); }  // Force to get the current Z home position
 
 void AutoHome() { queue.inject_P(G28_STR); }
-
 void HomeX() { queue.inject(F("G28X")); }
-
 void HomeY() { queue.inject(F("G28Y")); }
-
 void HomeZ() { queue.inject(F("G28Z")); }
 
 void SetHome() {
@@ -2247,7 +1961,7 @@ void SetHome() {
   void ApplyZOffset() { TERN_(EEPROM_SETTINGS, settings.save()); }
   void LiveZOffset() {
     last_zoffset = dwin_zoffset;
-    dwin_zoffset = HMI_value.Value / 100.0f;
+    dwin_zoffset = MenuData.Value / 100.0f;
     #if EITHER(BABYSTEP_ZPROBE_OFFSET, JUST_BABYSTEP)
       if (BABYSTEP_ALLOWED()) babystep.add_mm(Z_AXIS, dwin_zoffset - last_zoffset);
     #endif
@@ -2257,6 +1971,24 @@ void SetHome() {
       SetPFloatOnClick(Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX, 2, ApplyZOffset, LiveZOffset);
     }
   #endif
+
+  void SetMoveZto0() {
+    char cmd[48] = "";
+    char str_1[5] = "", str_2[5] = "";
+    sprintf_P(cmd, PSTR("G28XYO\nG28Z\nG0X%sY%sF5000\nM420S0\nG0Z0F300"),
+      #if ENABLED(MESH_BED_LEVELING)
+        dtostrf(0, 1, 1, str_1),
+        dtostrf(0, 1, 1, str_2)
+      #else
+        dtostrf(X_CENTER, 1, 1, str_1),
+        dtostrf(Y_CENTER, 1, 1, str_2)
+      #endif
+    );
+    gcode.process_subcommands_now(cmd);
+    planner.synchronize();
+    LCD_MESSAGE_F("Now adjust Z Offset");
+    HMI_AudioFeedback(true);
+  }
 #endif
 
 #if HAS_PREHEAT
@@ -2274,14 +2006,14 @@ void SetLanguage() {
 }
 
 void LiveMove() {
-  *HMI_value.P_Float = HMI_value.Value / MINUNITMULT;
+  *MenuData.P_Float = MenuData.Value / MINUNITMULT;
   if (!planner.is_full()) {
     planner.synchronize();
     planner.buffer_line(current_position, homing_feedrate(HMI_value.axis));
   }
 }
 void ApplyMoveE() {
-  last_E = HMI_value.Value / MINUNITMULT;
+  last_E = MenuData.Value / MINUNITMULT;
   if (!planner.is_full()) {
     planner.synchronize();
     planner.buffer_line(current_position, MMM_TO_MMS(FEEDRATE_E));
@@ -2294,33 +2026,13 @@ void SetMoveZ() { HMI_value.axis = Z_AXIS; SetPFloatOnClick(Z_MIN_POS, Z_MAX_POS
 #if HAS_HOTEND
   void SetMoveE() {
     #if ENABLED(PREVENT_COLD_EXTRUSION)
-      if (thermalManager.tooColdToExtrude(0)) {
-        Popup_Window_ETempTooLow();
-        return;
-      }
+      if (thermalManager.tooColdToExtrude(0))
+        return DWIN_Popup_Confirm(ICON_TempTooLow, GET_TEXT_F(MSG_HOTEND_TOO_COLD), GET_TEXT_F(MSG_PLEASE_PREHEAT));
     #endif
     SetPFloatOnClick(last_E - (EXTRUDE_MAXLENGTH), last_E + (EXTRUDE_MAXLENGTH), UNITFDIGITS, ApplyMoveE);
   }
 #endif
 
-void SetMoveZto0() {
-  char cmd[48] = "";
-  char str_1[5] = "", str_2[5] = "";
-  sprintf_P(cmd, PSTR("G28Z\nG0X%sY%sF5000\nM420S0\nG0Z0F300"),
-    #if ENABLED(MESH_BED_LEVELING)
-      dtostrf(0, 1, 1, str_1),
-      dtostrf(0, 1, 1, str_2)
-    #else
-      dtostrf(X_CENTER, 1, 1, str_1),
-      dtostrf(Y_CENTER, 1, 1, str_2)
-    #endif
-  );
-  gcode.process_subcommands_now(cmd);
-  planner.synchronize();
-  LCD_MESSAGE_F("Now adjust Z Offset");
-  HMI_AudioFeedback(true);
-}
-
 void SetPID(celsius_t t, heater_id_t h) {
   char cmd[48] = "";
   char str_1[5] = "", str_2[5] = "";
@@ -2347,10 +2059,24 @@ void SetPID(celsius_t t, heater_id_t h) {
   }
 #endif
 
+#if ENABLED(BAUD_RATE_GCODE)
+  void HMI_SetBaudRate() {
+    if (HMI_data.Baud115K) SetBaud115K(); else SetBaud250K();
+  }
+  void SetBaudRate() {
+    HMI_SetBaudRate();
+    Draw_Chkb_Line(CurrentMenu->line(), HMI_data.Baud115K);
+    DWIN_UpdateLCD();
+  }
+  void SetBaud115K() { queue.inject(F("M575 P0 B115200")); HMI_data.Baud115K = true; }
+  void SetBaud250K() { queue.inject(F("M575 P0 B250000")); HMI_data.Baud115K = false; }
+#endif
+
 #if HAS_LCD_BRIGHTNESS
-  void ApplyBrightness() { ui.set_brightness(HMI_value.Value); }
-  void LiveBrightness() { DWIN_LCD_Brightness(HMI_value.Value); }
+  void ApplyBrightness() { ui.set_brightness(MenuData.Value); }
+  void LiveBrightness() { DWIN_LCD_Brightness(MenuData.Value); }
   void SetBrightness() { SetIntOnClick(LCD_BRIGHTNESS_MIN, LCD_BRIGHTNESS_MAX, ui.brightness, ApplyBrightness, LiveBrightness); }
+  void TurnOffBacklight() { HMI_SaveProcessID(WaitResponse); ui.set_brightness(0); DWIN_Redraw_screen(); }
 #endif
 
 #if ENABLED(CASE_LIGHT_MENU)
@@ -2361,7 +2087,7 @@ void SetPID(celsius_t t, heater_id_t h) {
     DWIN_UpdateLCD();
   }
   #if ENABLED(CASELIGHT_USES_BRIGHTNESS)
-    void LiveCaseLightBrightness() { HMI_data.CaseLight_Brightness = caselight.brightness = HMI_value.Value; caselight.update_brightness(); }
+    void LiveCaseLightBrightness() { HMI_data.CaseLight_Brightness = caselight.brightness = MenuData.Value; caselight.update_brightness(); }
     void SetCaseLightBrightness() { SetIntOnClick(0, 255, caselight.brightness, nullptr, LiveCaseLightBrightness); }
   #endif
 #endif
@@ -2375,14 +2101,14 @@ void SetPID(celsius_t t, heater_id_t h) {
     }
   #endif
   #if ENABLED(HAS_COLOR_LEDS)
-    void LiveLedColorR() { leds.color.r = HMI_value.Value; HMI_data.Led_Color = leds.color; leds.update(); }
+    void LiveLedColorR() { leds.color.r = MenuData.Value; HMI_data.Led_Color = leds.color; leds.update(); }
     void SetLedColorR() { SetIntOnClick(0, 255, leds.color.r, nullptr, LiveLedColorR); }
-    void LiveLedColorG() { leds.color.g = HMI_value.Value; HMI_data.Led_Color = leds.color; leds.update(); }
+    void LiveLedColorG() { leds.color.g = MenuData.Value; HMI_data.Led_Color = leds.color; leds.update(); }
     void SetLedColorG() { SetIntOnClick(0, 255, leds.color.g, nullptr, LiveLedColorG); }
-    void LiveLedColorB() { leds.color.b = HMI_value.Value; HMI_data.Led_Color = leds.color; leds.update(); }
+    void LiveLedColorB() { leds.color.b = MenuData.Value; HMI_data.Led_Color = leds.color; leds.update(); }
     void SetLedColorB() { SetIntOnClick(0, 255, leds.color.b, nullptr, LiveLedColorB); }
     #if HAS_WHITE_LED
-      void LiveLedColorW() { leds.color.w = HMI_value.Value; HMI_data.Led_Color = leds.color; leds.update(); }
+      void LiveLedColorW() { leds.color.w = MenuData.Value; HMI_data.Led_Color = leds.color; leds.update(); }
       void SetLedColorW() { SetIntOnClick(0, 255, leds.color.w, nullptr, LiveLedColorW); }
     #endif
   #endif
@@ -2397,7 +2123,7 @@ void SetPID(celsius_t t, heater_id_t h) {
 #endif
 
 #if HAS_HOME_OFFSET
-  void ApplyHomeOffset() { set_home_offset(HMI_value.axis, HMI_value.Value / MINUNITMULT); }
+  void ApplyHomeOffset() { set_home_offset(HMI_value.axis, MenuData.Value / MINUNITMULT); }
   void SetHomeOffsetX() { HMI_value.axis = X_AXIS; SetPFloatOnClick(-50, 50, UNITFDIGITS, ApplyHomeOffset); }
   void SetHomeOffsetY() { HMI_value.axis = Y_AXIS; SetPFloatOnClick(-50, 50, UNITFDIGITS, ApplyHomeOffset); }
   void SetHomeOffsetZ() { HMI_value.axis = Z_AXIS; SetPFloatOnClick( -2,  2, UNITFDIGITS, ApplyHomeOffset); }
@@ -2421,12 +2147,11 @@ void SetPID(celsius_t t, heater_id_t h) {
       DWIN_UpdateLCD();
     }
   #endif
-#endif
 
-#if ENABLED(NOZZLE_PARK_FEATURE)
-  void SetParkPosX()   { SetPIntOnClick(0, X_MAX_POS); }
-  void SetParkPosY()   { SetPIntOnClick(0, Y_MAX_POS); }
-  void SetParkZRaise() { SetPIntOnClick(0, 50); }
+  #if BOTH(HAS_HEATED_BED, PREHEAT_BEFORE_LEVELING)
+    void SetBedLevT() { SetPIntOnClick(BED_MINTEMP, BED_MAX_TARGET); }
+  #endif
+
 #endif
 
 #if HAS_FILAMENT_SENSOR
@@ -2437,7 +2162,7 @@ void SetPID(celsius_t t, heater_id_t h) {
     DWIN_UpdateLCD();
   }
   #if HAS_FILAMENT_RUNOUT_DISTANCE
-    void ApplyRunoutDistance() { runout.set_runout_distance(HMI_value.Value / MINUNITMULT); }
+    void ApplyRunoutDistance() { runout.set_runout_distance(MenuData.Value / MINUNITMULT); }
     void SetRunoutDistance() { SetFloatOnClick(0, 999, UNITFDIGITS, runout.runout_distance(), ApplyRunoutDistance); }
   #endif
 #endif
@@ -2454,20 +2179,20 @@ void SetPID(celsius_t t, heater_id_t h) {
 
 void RestoreDefaultsColors() {
   DWIN_SetColorDefaults();
-  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color);
+  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color, HMI_data.StatusBg_Color);
   DWIN_Redraw_screen();
 }
 
 void SelColor() {
-  HMI_value.P_Int = (int16_t*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
-  HMI_value.Color[0] = GetRColor(*HMI_value.P_Int);  // Red
-  HMI_value.Color[1] = GetGColor(*HMI_value.P_Int);  // Green
-  HMI_value.Color[2] = GetBColor(*HMI_value.P_Int);  // Blue
+  MenuData.P_Int = (int16_t*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
+  HMI_value.Color[0] = GetRColor(*MenuData.P_Int);  // Red
+  HMI_value.Color[1] = GetGColor(*MenuData.P_Int);  // Green
+  HMI_value.Color[2] = GetBColor(*MenuData.P_Int);  // Blue
   Draw_GetColor_Menu();
 }
 
 void LiveRGBColor() {
-    HMI_value.Color[CurrentMenu->line() - 2] = HMI_value.Value;
+    HMI_value.Color[CurrentMenu->line() - 2] = MenuData.Value;
     uint16_t color = RGB(HMI_value.Color[0], HMI_value.Color[1], HMI_value.Color[2]);
     DWIN_Draw_Rectangle(1, color, 20, 315, DWIN_WIDTH - 20, 335);
 }
@@ -2477,27 +2202,28 @@ void SetRGBColor() {
 }
 
 void DWIN_ApplyColor() {
-  *HMI_value.P_Int = RGB(HMI_value.Color[0], HMI_value.Color[1], HMI_value.Color[2]);
-  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color);
-  Draw_Status_Area(false);
+  *MenuData.P_Int = RGB(HMI_value.Color[0], HMI_value.Color[1], HMI_value.Color[2]);
+  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color, HMI_data.StatusBg_Color);
   Draw_SelectColors_Menu();
+  hash_changed = true;
   LCD_MESSAGE_F(GET_TEXT_F(MSG_COLORS_APPLIED));
+  DWIN_Draw_Dashboard();
 }
 
 void SetSpeed() { SetPIntOnClick(MIN_PRINT_SPEED, MAX_PRINT_SPEED); }
 
 #if HAS_HOTEND
-  void ApplyHotendTemp() { thermalManager.setTargetHotend(HMI_value.Value, 0); }
+  void ApplyHotendTemp() { thermalManager.setTargetHotend(MenuData.Value, 0); }
   void SetHotendTemp() { SetIntOnClick(MIN_ETEMP, MAX_ETEMP, thermalManager.degTargetHotend(0), ApplyHotendTemp); }
 #endif
 
 #if HAS_HEATED_BED
-  void ApplyBedTemp() { thermalManager.setTargetBed(HMI_value.Value); }
+  void ApplyBedTemp() { thermalManager.setTargetBed(MenuData.Value); }
   void SetBedTemp() { SetIntOnClick(BED_MINTEMP, BED_MAX_TARGET, thermalManager.degTargetBed(), ApplyBedTemp); }
 #endif
 
 #if HAS_FAN
-  void ApplyFanSpeed() { thermalManager.set_fan_speed(0, HMI_value.Value); }
+  void ApplyFanSpeed() { thermalManager.set_fan_speed(0, MenuData.Value); }
   void SetFanSpeed() { SetIntOnClick(0, 255, thermalManager.fan_speed[0], ApplyFanSpeed); }
 #endif
 
@@ -2531,17 +2257,15 @@ void ApplyFlow() { planner.refresh_e_factor(0); }
 void SetFlow() { SetPIntOnClick(MIN_PRINT_FLOW, MAX_PRINT_FLOW, ApplyFlow); }
 
 // Bed Tramming
-void Tram(uint8_t point) {
+TERN(HAS_ONESTEP_LEVELING, float, void) Tram(uint8_t point) {
   char cmd[100] = "";
   #if HAS_ONESTEP_LEVELING
     static bool inLev = false;
-    if (inLev) return;
+    float xpos = 0, ypos = 0, zval = 0, margin = 0;
     char str_1[6] = "", str_2[6] = "", str_3[6] = "";
-    #define fmt "X:%s, Y:%s, Z:%s"
-    float xpos = 0, ypos = 0, zval = 0;
-    float margin = PROBING_MARGIN;
+    if (inLev) return NAN;
+    margin = HMI_data.FullManualTramming ? 30 : PROBING_MARGIN;
   #else
-    #define fmt "M420S0\nG28O\nG90\nG0Z5F300\nG0X%iY%iF5000\nG0Z0F300"
     int16_t xpos = 0, ypos = 0;
     int16_t margin = 30;
   #endif
@@ -2569,24 +2293,45 @@ void Tram(uint8_t point) {
       break;
   }
 
+  planner.synchronize();
+
   #if HAS_ONESTEP_LEVELING
-    planner.synchronize();
-    probe.stow();
-    gcode.process_subcommands_now(F("M420S0\nG28O"));
-    planner.synchronize();
-    inLev = true;
-    zval = probe.probe_at_point(xpos, ypos, PROBE_PT_STOW);
-    sprintf_P(cmd, PSTR(fmt),
-      dtostrf(xpos, 1, 1, str_1),
-      dtostrf(ypos, 1, 1, str_2),
-      dtostrf(zval, 1, 2, str_3)
-    );
-    ui.set_status(cmd);
-    inLev = false;
+
+    if (HMI_data.FullManualTramming) {
+      planner.synchronize();
+      sprintf_P(cmd, PSTR("M420S0\nG28O\nG90\nG0Z5F300\nG0X%sY%sF5000\nG0Z0F300"),
+        dtostrf(xpos, 1, 1, str_1),
+        dtostrf(ypos, 1, 1, str_2)
+      );
+      queue.inject(cmd);
+    }
+    else {
+      LIMIT(xpos, X_MIN_POS, (X_MAX_POS + probe.offset.x));
+      LIMIT(ypos, Y_MIN_POS, (Y_MAX_POS + probe.offset.y));
+      probe.stow();
+      gcode.process_subcommands_now(F("M420S0\nG28O"));
+      planner.synchronize();
+      inLev = true;
+      zval = probe.probe_at_point(xpos, ypos, PROBE_PT_STOW);
+      if (isnan(zval))
+        ui.set_status(F("Position Not Reachable, check offsets"));
+      else {
+        sprintf_P(cmd, PSTR("X:%s, Y:%s, Z:%s"),
+          dtostrf(xpos, 1, 1, str_1),
+          dtostrf(ypos, 1, 1, str_2),
+          dtostrf(zval, 1, 2, str_3)
+        );
+        ui.set_status(cmd);
+      }
+      inLev = false;
+    }
+    return zval;
+
   #else
-    planner.synchronize();
-    sprintf_P(cmd, PSTR(fmt), xpos, ypos);
+
+    sprintf_P(cmd, PSTR("M420S0\nG28O\nG90\nG0Z5F300\nG0X%iY%iF5000\nG0Z0F300"), xpos, ypos);
     queue.inject(cmd);
+
   #endif
 }
 
@@ -2596,11 +2341,72 @@ void TramBR() { Tram(2); }
 void TramBL() { Tram(3); }
 void TramC () { Tram(4); }
 
+#if HAS_ONESTEP_LEVELING
+
+  void Trammingwizard() {
+    bed_mesh_t zval = {0};
+    if (HMI_data.FullManualTramming) {
+      ui.set_status(F("Disable manual tramming"));
+      return;
+    }
+    zval[0][0] = Tram(0);
+    checkkey = NothingToDo;
+    MeshViewer.DrawMesh(zval, 2, 2);
+    zval[1][0] = Tram(1);
+    MeshViewer.DrawMesh(zval, 2, 2);
+    zval[1][1] = Tram(2);
+    MeshViewer.DrawMesh(zval, 2, 2);
+    zval[0][1] = Tram(3);
+    MeshViewer.DrawMesh(zval, 2, 2);
+    char str_1[6] = "", str_2[6] = "";
+    ui.status_printf(0, F("Limits minZ: %s, maxZ: %s"),
+      dtostrf(MeshViewer.min, 1, 2, str_1),
+      dtostrf(MeshViewer.max, 1, 2, str_2)
+    );
+    if (ABS(MeshViewer.max - MeshViewer.min) < 0.05) {
+      DWINUI::Draw_CenteredString(140,F("Corners leveled"));
+      DWINUI::Draw_CenteredString(160,F("Tolerance achieved!"));
+    }
+    else {
+      uint8_t p = 0;
+      float d, max = 0;
+      FSTR_P plabel;
+      LOOP_L_N(x,2) LOOP_L_N(y,2) {
+        d = ABS(zval[x][y] - MeshViewer.avg);
+        if (max < d) {
+          max = d;
+          p = x + 2 * y;
+        }
+      }
+      switch (p) {
+        case 0b00 : plabel = GET_TEXT_F(MSG_LEVBED_FL); break;
+        case 0b01 : plabel = GET_TEXT_F(MSG_LEVBED_FR); break;
+        case 0b10 : plabel = GET_TEXT_F(MSG_LEVBED_BL); break;
+        case 0b11 : plabel = GET_TEXT_F(MSG_LEVBED_BR); break;
+        default   : plabel = F(""); break;
+      }
+      DWINUI::Draw_CenteredString(130, F("Corners not leveled"));
+      DWINUI::Draw_CenteredString(150, F("Knob adjustment required"));
+      DWINUI::Draw_CenteredString(Color_Green, 170, plabel);
+    }
+    DWINUI::Draw_Button(BTN_Continue, 86, 305);
+    checkkey = Menu;
+    HMI_SaveProcessID(WaitResponse);
+  }
+
+  void SetManualTramming() {
+    HMI_data.FullManualTramming = !HMI_data.FullManualTramming;
+    Draw_Chkb_Line(CurrentMenu->line(), HMI_data.FullManualTramming);
+    DWIN_UpdateLCD();
+  }
+
+#endif // HAS_ONESTEP_LEVELING
+
 #if ENABLED(MESH_BED_LEVELING)
 
   void ManualMeshStart(){
     LCD_MESSAGE(MSG_UBL_BUILD_MESH_MENU);
-    gcode.process_subcommands_now(F("G28Z\nM211S0\nG29S1"));
+    gcode.process_subcommands_now(F("G28XYO\nG28Z\nM211S0\nG29S1"));
     planner.synchronize();
     #ifdef MANUAL_PROBE_START_Z
       const uint8_t line = CurrentMenu->line(MMeshMoveZItem->pos);
@@ -2609,7 +2415,7 @@ void TramC () { Tram(4); }
   }
 
   void LiveMeshMoveZ() {
-    *HMI_value.P_Float = HMI_value.Value / POW(10, 2);
+    *MenuData.P_Float = MenuData.Value / POW(10, 2);
     if (!planner.is_full()) {
       planner.synchronize();
       planner.buffer_line(current_position, homing_feedrate(Z_AXIS));
@@ -2642,29 +2448,29 @@ void TramC () { Tram(4); }
   #endif
 #endif
 
-void ApplyMaxSpeed() { planner.set_max_feedrate(HMI_value.axis, HMI_value.Value / MINUNITMULT); }
-void SetMaxSpeedX() { HMI_value.axis = X_AXIS, SetFloatOnClick(MIN_MAXFEEDSPEED, default_max_feedrate[X_AXIS] * 2, UNITFDIGITS, planner.settings.max_feedrate_mm_s[X_AXIS], ApplyMaxSpeed); }
-void SetMaxSpeedY() { HMI_value.axis = Y_AXIS, SetFloatOnClick(MIN_MAXFEEDSPEED, default_max_feedrate[Y_AXIS] * 2, UNITFDIGITS, planner.settings.max_feedrate_mm_s[Y_AXIS], ApplyMaxSpeed); }
-void SetMaxSpeedZ() { HMI_value.axis = Z_AXIS, SetFloatOnClick(MIN_MAXFEEDSPEED, default_max_feedrate[Z_AXIS] * 2, UNITFDIGITS, planner.settings.max_feedrate_mm_s[Z_AXIS], ApplyMaxSpeed); }
+void ApplyMaxSpeed() { planner.set_max_feedrate(HMI_value.axis, MenuData.Value / MINUNITMULT); }
+void SetMaxSpeedX() { HMI_value.axis = X_AXIS, SetFloatOnClick(MIN_MAXFEEDSPEED, max_feedrate_edit_values[X_AXIS], UNITFDIGITS, planner.settings.max_feedrate_mm_s[X_AXIS], ApplyMaxSpeed); }
+void SetMaxSpeedY() { HMI_value.axis = Y_AXIS, SetFloatOnClick(MIN_MAXFEEDSPEED, max_feedrate_edit_values[Y_AXIS], UNITFDIGITS, planner.settings.max_feedrate_mm_s[Y_AXIS], ApplyMaxSpeed); }
+void SetMaxSpeedZ() { HMI_value.axis = Z_AXIS, SetFloatOnClick(MIN_MAXFEEDSPEED, max_feedrate_edit_values[Z_AXIS], UNITFDIGITS, planner.settings.max_feedrate_mm_s[Z_AXIS], ApplyMaxSpeed); }
 #if HAS_HOTEND
-  void SetMaxSpeedE() { HMI_value.axis = E_AXIS; SetFloatOnClick(MIN_MAXFEEDSPEED, default_max_feedrate[E_AXIS] * 2, UNITFDIGITS, planner.settings.max_feedrate_mm_s[E_AXIS], ApplyMaxSpeed); }
+  void SetMaxSpeedE() { HMI_value.axis = E_AXIS; SetFloatOnClick(MIN_MAXFEEDSPEED, max_feedrate_edit_values[E_AXIS], UNITFDIGITS, planner.settings.max_feedrate_mm_s[E_AXIS], ApplyMaxSpeed); }
 #endif
 
-void ApplyMaxAccel() { planner.set_max_acceleration(HMI_value.axis, HMI_value.Value); }
-void SetMaxAccelX() { HMI_value.axis = X_AXIS, SetIntOnClick(MIN_MAXACCELERATION, default_max_acceleration[X_AXIS] * 2, planner.settings.max_acceleration_mm_per_s2[X_AXIS], ApplyMaxAccel); }
-void SetMaxAccelY() { HMI_value.axis = Y_AXIS, SetIntOnClick(MIN_MAXACCELERATION, default_max_acceleration[Y_AXIS] * 2, planner.settings.max_acceleration_mm_per_s2[Y_AXIS], ApplyMaxAccel); }
-void SetMaxAccelZ() { HMI_value.axis = Z_AXIS, SetIntOnClick(MIN_MAXACCELERATION, default_max_acceleration[Z_AXIS] * 2, planner.settings.max_acceleration_mm_per_s2[Z_AXIS], ApplyMaxAccel); }
+void ApplyMaxAccel() { planner.set_max_acceleration(HMI_value.axis, MenuData.Value); }
+void SetMaxAccelX() { HMI_value.axis = X_AXIS, SetIntOnClick(MIN_MAXACCELERATION, max_acceleration_edit_values[X_AXIS], planner.settings.max_acceleration_mm_per_s2[X_AXIS], ApplyMaxAccel); }
+void SetMaxAccelY() { HMI_value.axis = Y_AXIS, SetIntOnClick(MIN_MAXACCELERATION, max_acceleration_edit_values[Y_AXIS], planner.settings.max_acceleration_mm_per_s2[Y_AXIS], ApplyMaxAccel); }
+void SetMaxAccelZ() { HMI_value.axis = Z_AXIS, SetIntOnClick(MIN_MAXACCELERATION, max_acceleration_edit_values[Z_AXIS], planner.settings.max_acceleration_mm_per_s2[Z_AXIS], ApplyMaxAccel); }
 #if HAS_HOTEND
-  void SetMaxAccelE() { HMI_value.axis = E_AXIS; SetIntOnClick(MIN_MAXACCELERATION, default_max_acceleration[E_AXIS] * 2, planner.settings.max_acceleration_mm_per_s2[E_AXIS], ApplyMaxAccel); }
+  void SetMaxAccelE() { HMI_value.axis = E_AXIS; SetIntOnClick(MIN_MAXACCELERATION, max_acceleration_edit_values[E_AXIS], planner.settings.max_acceleration_mm_per_s2[E_AXIS], ApplyMaxAccel); }
 #endif
 
 #if HAS_CLASSIC_JERK
-  void ApplyMaxJerk() { planner.set_max_jerk(HMI_value.axis, HMI_value.Value / MINUNITMULT); }
-  void SetMaxJerkX() { HMI_value.axis = X_AXIS, SetFloatOnClick(MIN_MAXJERK, default_max_jerk[X_AXIS] * 2, UNITFDIGITS, planner.max_jerk[X_AXIS], ApplyMaxJerk); }
-  void SetMaxJerkY() { HMI_value.axis = Y_AXIS, SetFloatOnClick(MIN_MAXJERK, default_max_jerk[Y_AXIS] * 2, UNITFDIGITS, planner.max_jerk[Y_AXIS], ApplyMaxJerk); }
-  void SetMaxJerkZ() { HMI_value.axis = Z_AXIS, SetFloatOnClick(MIN_MAXJERK, default_max_jerk[Z_AXIS] * 2, UNITFDIGITS, planner.max_jerk[Z_AXIS], ApplyMaxJerk); }
+  void ApplyMaxJerk() { planner.set_max_jerk(HMI_value.axis, MenuData.Value / MINUNITMULT); }
+  void SetMaxJerkX() { HMI_value.axis = X_AXIS, SetFloatOnClick(MIN_MAXJERK, max_jerk_edit_values[X_AXIS], UNITFDIGITS, planner.max_jerk[X_AXIS], ApplyMaxJerk); }
+  void SetMaxJerkY() { HMI_value.axis = Y_AXIS, SetFloatOnClick(MIN_MAXJERK, max_jerk_edit_values[Y_AXIS], UNITFDIGITS, planner.max_jerk[Y_AXIS], ApplyMaxJerk); }
+  void SetMaxJerkZ() { HMI_value.axis = Z_AXIS, SetFloatOnClick(MIN_MAXJERK, max_jerk_edit_values[Z_AXIS], UNITFDIGITS, planner.max_jerk[Z_AXIS], ApplyMaxJerk); }
   #if HAS_HOTEND
-    void SetMaxJerkE() { HMI_value.axis = E_AXIS; SetFloatOnClick(MIN_MAXJERK, default_max_jerk[E_AXIS] * 2, UNITFDIGITS, planner.max_jerk[E_AXIS], ApplyMaxJerk); }
+    void SetMaxJerkE() { HMI_value.axis = E_AXIS; SetFloatOnClick(MIN_MAXJERK, max_jerk_edit_values[E_AXIS], UNITFDIGITS, planner.max_jerk[E_AXIS], ApplyMaxJerk); }
   #endif
 #endif
 
@@ -2683,21 +2489,21 @@ void SetStepsZ() { HMI_value.axis = Z_AXIS, SetPFloatOnClick( MIN_STEP, MAX_STEP
   void SetPidCycles() { SetPIntOnClick(3, 50); }
   void SetKp() { SetPFloatOnClick(0, 1000, 2); }
   void ApplyPIDi() {
-    *HMI_value.P_Float = scalePID_i(HMI_value.Value / POW(10, 2));
+    *MenuData.P_Float = scalePID_i(MenuData.Value / POW(10, 2));
     thermalManager.updatePID();
   }
   void ApplyPIDd() {
-    *HMI_value.P_Float = scalePID_d(HMI_value.Value / POW(10, 2));
+    *MenuData.P_Float = scalePID_d(MenuData.Value / POW(10, 2));
     thermalManager.updatePID();
   }
   void SetKi() {
-    HMI_value.P_Float = (float*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
-    const float value = unscalePID_i(*HMI_value.P_Float);
+    MenuData.P_Float = (float*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
+    const float value = unscalePID_i(*MenuData.P_Float);
     SetFloatOnClick(0, 1000, 2, value, ApplyPIDi);
   }
   void SetKd() {
-    HMI_value.P_Float = (float*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
-    const float value = unscalePID_d(*HMI_value.P_Float);
+    MenuData.P_Float = (float*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
+    const float value = unscalePID_d(*MenuData.P_Float);
     SetFloatOnClick(0, 1000, 2, value, ApplyPIDd);
   }
 #endif
@@ -2709,62 +2515,7 @@ void SetStepsZ() { HMI_value.axis = Z_AXIS, SetPFloatOnClick( MIN_STEP, MAX_STEP
   void SetRecoverSpeed() { SetPFloatOnClick( 1, 90, UNITFDIGITS); };
 #endif
 
-// Menuitem Drawing functions =================================================
-
-void onDrawMenuItem(MenuItemClass* menuitem, int8_t line) {
-  if (menuitem->icon) DWINUI::Draw_Icon(menuitem->icon, ICOX, MBASE(line) - 3);
-  if (menuitem->frameid)
-    DWIN_Frame_AreaCopy(menuitem->frameid, menuitem->frame.left, menuitem->frame.top, menuitem->frame.right, menuitem->frame.bottom, LBLX, MBASE(line));
-  else if (menuitem->caption)
-    DWINUI::Draw_String(LBLX, MBASE(line) - 1, menuitem->caption);
-  DWIN_Draw_HLine(HMI_data.SplitLine_Color, 16, MYPOS(line + 1), 240);
-}
-
-void onDrawSubMenu(MenuItemClass* menuitem, int8_t line) {
-  onDrawMenuItem(menuitem, line);
-  DWINUI::Draw_Icon(ICON_More, VALX + 16, MBASE(line) - 3);
-}
-
-void onDrawIntMenu(MenuItemClass* menuitem, int8_t line, uint16_t value) {
-  onDrawMenuItem(menuitem, line);
-  Draw_Menu_IntValue(HMI_data.Background_Color, line, 4, value);
-}
-
-void onDrawPIntMenu(MenuItemClass* menuitem, int8_t line) {
-  const uint16_t value = *(uint16_t*)static_cast<MenuItemPtrClass*>(menuitem)->value;
-  onDrawIntMenu(menuitem, line, value);
-}
-
-void onDrawPInt8Menu(MenuItemClass* menuitem, int8_t line) {
-  const uint8_t value = *(uint8_t*)static_cast<MenuItemPtrClass*>(menuitem)->value;
-  onDrawIntMenu(menuitem, line, value);
-}
-
-void onDrawPInt32Menu(MenuItemClass* menuitem, int8_t line) {
-  const uint32_t value = *(uint32_t*)static_cast<MenuItemPtrClass*>(menuitem)->value;
-  onDrawIntMenu(menuitem, line, value);
-}
-
-void onDrawFloatMenu(MenuItemClass* menuitem, int8_t line, uint8_t dp, const float value) {
-  onDrawMenuItem(menuitem, line);
-  DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Background_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(line), value);
-}
-
-void onDrawPFloatMenu(MenuItemClass* menuitem, int8_t line) {
-  const float value = *(float*)static_cast<MenuItemPtrClass*>(menuitem)->value;
-  const int8_t dp = UNITFDIGITS;
-  onDrawFloatMenu(menuitem, line, dp, value);
-}
-
-void onDrawPFloat2Menu(MenuItemClass* menuitem, int8_t line) {
-  const float value = *(float*)static_cast<MenuItemPtrClass*>(menuitem)->value;
-  onDrawFloatMenu(menuitem, line, 2, value);
-}
-
-void onDrawChkbMenu(MenuItemClass* menuitem, int8_t line, bool checked) {
-  onDrawMenuItem(menuitem, line);
-  Draw_Chkb_Line(line, checked);
-}
+// Special Menuitem Drawing functions =================================================
 
 void onDrawBack(MenuItemClass* menuitem, int8_t line) {
   if (HMI_IsChinese()) menuitem->SetFrame(1, 129, 72, 156, 84);
@@ -2882,6 +2633,10 @@ void onDrawLanguage(MenuItemClass* menuitem, int8_t line) {
   void onDrawPwrLossR(MenuItemClass* menuitem, int8_t line) { onDrawChkbMenu(menuitem, line, recovery.enabled); }
 #endif
 
+#if ENABLED(BAUD_RATE_GCODE)
+  void onDrawBaudrate(MenuItemClass* menuitem, int8_t line) { onDrawChkbMenu(menuitem, line, HMI_data.Baud115K); }
+#endif
+
 #if ENABLED(CASE_LIGHT_MENU)
   void onDrawCaseLight(MenuItemClass* menuitem, int8_t line) { onDrawChkbMenu(menuitem, line, caselight.on); }
 #endif
@@ -3172,137 +2927,9 @@ void onDrawStepsZ(MenuItemClass* menuitem, int8_t line) {
   }
 #endif
 
-// HMI Control functions ======================================================
-
-// Generic menu control using the encoder
-void HMI_Menu() {
-  EncoderState encoder_diffState = get_encoder_state();
-  if (encoder_diffState == ENCODER_DIFF_NO) return;
-  if (CurrentMenu) {
-    if (encoder_diffState == ENCODER_DIFF_ENTER)
-      CurrentMenu->onClick();
-    else
-      CurrentMenu->onScroll(encoder_diffState == ENCODER_DIFF_CW);
-  }
-}
-
-// Get an integer value using the encoder without draw anything
-//  lo: low limit
-//  hi: high limit
-// Return value:
-//  0 : no change
-//  1 : live change
-//  2 : apply change
-int8_t HMI_GetIntNoDraw(const int32_t lo, const int32_t hi) {
-  EncoderState encoder_diffState = Encoder_ReceiveAnalyze();
-  if (encoder_diffState != ENCODER_DIFF_NO) {
-    if (Apply_Encoder(encoder_diffState, HMI_value.Value)) {
-      EncoderRate.enabled = false;
-      checkkey = Menu;
-      return 2;
-    }
-    LIMIT(HMI_value.Value, lo, hi);
-    return 1;
-  }
-  return 0;
-}
-
-// Get an integer value using the encoder
-//  lo: low limit
-//  hi: high limit
-// Return value:
-//  0 : no change
-//  1 : live change
-//  2 : apply change
-int8_t HMI_GetInt(const int32_t lo, const int32_t hi) {
-  EncoderState encoder_diffState = Encoder_ReceiveAnalyze();
-  if (encoder_diffState != ENCODER_DIFF_NO) {
-    if (Apply_Encoder(encoder_diffState, HMI_value.Value)) {
-      EncoderRate.enabled = false;
-      DWINUI::Draw_Int(HMI_data.Text_Color, HMI_data.Background_Color, 4 , VALX, MBASE(CurrentMenu->line()) - 1, HMI_value.Value);
-      checkkey = Menu;
-      return 2;
-    }
-    LIMIT(HMI_value.Value, lo, hi);
-    DWINUI::Draw_Int(HMI_data.Text_Color, HMI_data.Selected_Color, 4 , VALX, MBASE(CurrentMenu->line()) - 1, HMI_value.Value);
-    return 1;
-  }
-  return 0;
-}
-
-// Set an integer using the encoder
-void HMI_SetInt() {
-  int8_t val = HMI_GetInt(HMI_value.MinValue, HMI_value.MaxValue);
-  switch (val) {
-    case 0: return; break;
-    case 1: if (HMI_value.LiveUpdate) HMI_value.LiveUpdate(); break;
-    case 2: if (HMI_value.Apply) HMI_value.Apply(); break;
-  }
-}
-
-// Set an integer without drawing
-void HMI_SetIntNoDraw() {
-  int8_t val = HMI_GetIntNoDraw(HMI_value.MinValue, HMI_value.MaxValue);
-  switch (val) {
-    case 0: return; break;
-    case 1: if (HMI_value.LiveUpdate) HMI_value.LiveUpdate(); break;
-    case 2: if (HMI_value.Apply) HMI_value.Apply(); break;
-  }
-}
-
-// Set an integer pointer variable using the encoder
-void HMI_SetPInt() {
-  int8_t val = HMI_GetInt(HMI_value.MinValue, HMI_value.MaxValue);
-  switch (val) {
-    case 0: return;
-    case 1: if (HMI_value.LiveUpdate) HMI_value.LiveUpdate(); break;
-    case 2: *HMI_value.P_Int = HMI_value.Value; if (HMI_value.Apply) HMI_value.Apply(); break;
-  }
-}
-
-// Get a scaled float value using the encoder
-//  dp: decimal places
-//  lo: scaled low limit
-//  hi: scaled high limit
-// Return value:
-//  0 : no change
-//  1 : live change
-//  2 : apply change
-int8_t HMI_GetFloat(uint8_t dp, int32_t lo, int32_t hi) {
-  EncoderState encoder_diffState = Encoder_ReceiveAnalyze();
-  if (encoder_diffState != ENCODER_DIFF_NO) {
-    if (Apply_Encoder(encoder_diffState, HMI_value.Value)) {
-      EncoderRate.enabled = false;
-      DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Background_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(CurrentMenu->line()), HMI_value.Value / POW(10, dp));
-      checkkey = Menu;
-      return 2;
-    }
-    LIMIT(HMI_value.Value, lo, hi);
-    DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Selected_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(CurrentMenu->line()), HMI_value.Value / POW(10, dp));
-    return 1;
-  }
-  return 0;
-}
-
-// Set a scaled float using the encoder
-void HMI_SetFloat() {
-  const int8_t val = HMI_GetFloat(HMI_value.dp, HMI_value.MinValue, HMI_value.MaxValue);
-  switch (val) {
-    case 0: return;
-    case 1: if (HMI_value.LiveUpdate) HMI_value.LiveUpdate(); break;
-    case 2: if (HMI_value.Apply) HMI_value.Apply(); break;
-  }
-}
-
-// Set a scaled float pointer variable using the encoder
-void HMI_SetPFloat() {
-  const int8_t val = HMI_GetFloat(HMI_value.dp, HMI_value.MinValue, HMI_value.MaxValue);
-  switch (val) {
-    case 0: return;
-    case 1: if (HMI_value.LiveUpdate) HMI_value.LiveUpdate(); break;
-    case 2: *HMI_value.P_Float = HMI_value.Value / POW(10, HMI_value.dp); if (HMI_value.Apply) HMI_value.Apply(); break;
-  }
-}
+#if HAS_ONESTEP_LEVELING
+  void onDrawManualTramming(MenuItemClass* menuitem, int8_t line) { onDrawChkbMenu(menuitem, line, HMI_data.FullManualTramming); }
+#endif
 
 // Menu Creation and Drawing functions ======================================================
 
@@ -3359,6 +2986,7 @@ void Draw_Prepare_Menu() {
     MENU_ITEM(ICON_Cool, GET_TEXT_F(MSG_COOLDOWN), onDrawCooldown, DoCoolDown);
     MENU_ITEM(ICON_Language, PSTR(GET_TEXT_F(MSG_UI_LANGUAGE)), onDrawLanguage, SetLanguage);
   }
+  ui.reset_status(true);
   CurrentMenu->draw();
 }
 
@@ -3369,13 +2997,17 @@ void Draw_Tramming_Menu() {
   if (CurrentMenu != TrammingMenu) {
     CurrentMenu = TrammingMenu;
     SetMenuTitle({0}, GET_TEXT_F(MSG_BED_TRAMMING)); // TODO: Chinese, English "Bed Tramming" JPG
-    DWINUI::MenuItemsPrepare(6);
+    DWINUI::MenuItemsPrepare(8);
     MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Prepare_Menu);
     MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_LEVBED_FL), onDrawMenuItem, TramFL);
     MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_LEVBED_FR), onDrawMenuItem, TramFR);
     MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_LEVBED_BR), onDrawMenuItem, TramBR);
     MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_LEVBED_BL), onDrawMenuItem, TramBL);
     MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_LEVBED_C ), onDrawMenuItem, TramC );
+    #if HAS_ONESTEP_LEVELING
+      MENU_ITEM(ICON_ProbeSet, F("Bed tramming wizard"), onDrawMenuItem, Trammingwizard);
+      MENU_ITEM(ICON_ProbeSet, GET_TEXT_F(MSG_BED_TRAMMING_MANUAL), onDrawManualTramming, SetManualTramming);
+    #endif
   }
   CurrentMenu->draw();
 }
@@ -3386,7 +3018,7 @@ void Draw_Control_Menu() {
   if (CurrentMenu != ControlMenu) {
     CurrentMenu = ControlMenu;
     SetMenuTitle({103, 1, 28, 14}, GET_TEXT_F(MSG_CONTROL));
-    DWINUI::MenuItemsPrepare(8);
+    DWINUI::MenuItemsPrepare(10);
     MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Goto_Main_Menu);
     #if ENABLED(CASE_LIGHT_MENU)
       #if ENABLED(CASELIGHT_USES_BRIGHTNESS)
@@ -3408,6 +3040,7 @@ void Draw_Control_Menu() {
     MENU_ITEM(ICON_Reboot, GET_TEXT_F(MSG_RESET_PRINTER), onDrawMenuItem, RebootPrinter);
     MENU_ITEM(ICON_Info, GET_TEXT_F(MSG_INFO_SCREEN), onDrawInfoSubMenu, Goto_Info_Menu);
   }
+  ui.reset_status(true);
   CurrentMenu->draw();
 }
 
@@ -3417,8 +3050,11 @@ void Draw_AdvancedSettings_Menu() {
   if (CurrentMenu != AdvancedSettings) {
     CurrentMenu = AdvancedSettings;
     SetMenuTitle({0}, GET_TEXT_F(MSG_ADVANCED_SETTINGS)); // TODO: Chinese, English "Advanced Settings" JPG
-    DWINUI::MenuItemsPrepare(15);
+    DWINUI::MenuItemsPrepare(17);
     MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Goto_Main_Menu);
+    #if ENABLED(EEPROM_SETTINGS)
+      MENU_ITEM(ICON_WriteEEPROM, GET_TEXT_F(MSG_STORE_EEPROM), onDrawMenuItem, WriteEeprom);
+    #endif
     #if HAS_HOME_OFFSET
       MENU_ITEM(ICON_HomeOffset, GET_TEXT_F(MSG_SET_HOME_OFFSETS), onDrawSubMenu, Draw_HomeOffset_Menu);
     #endif
@@ -3437,6 +3073,9 @@ void Draw_AdvancedSettings_Menu() {
     #if ENABLED(POWER_LOSS_RECOVERY)
       MENU_ITEM(ICON_Pwrlossr, GET_TEXT_F(MSG_OUTAGE_RECOVERY), onDrawPwrLossR, SetPwrLossr);
     #endif
+    #if ENABLED(BAUD_RATE_GCODE)
+      MENU_ITEM(ICON_SetBaudRate, F("115K baud"), onDrawBaudrate, SetBaudRate);
+    #endif
     #if HAS_LCD_BRIGHTNESS
       EDIT_ITEM(ICON_Brightness, GET_TEXT_F(MSG_BRIGHTNESS), onDrawPInt8Menu, SetBrightness, &ui.brightness);
     #endif
@@ -3451,11 +3090,12 @@ void Draw_AdvancedSettings_Menu() {
       MENU_ITEM(ICON_ESDiag, F("End-stops diag."), onDrawSubMenu, Draw_EndStopDiag);
     #endif
     #if ENABLED(PRINTCOUNTER)
-      MENU_ITEM(ICON_PrintStats, GET_TEXT_F(MSG_INFO_STATS_MENU), onDrawSubMenu, Draw_PrintStats);
+      MENU_ITEM(ICON_PrintStats, GET_TEXT_F(MSG_INFO_STATS_MENU), onDrawSubMenu, Goto_PrintStats);
       MENU_ITEM(ICON_PrintStatsReset, GET_TEXT_F(MSG_INFO_PRINT_COUNT_RESET), onDrawSubMenu, PrintStats.Reset);
     #endif
     MENU_ITEM(ICON_Lock, GET_TEXT_F(MSG_LOCKSCREEN), onDrawMenuItem, DWIN_LockScreen);
   }
+  ui.reset_status(true);
   CurrentMenu->draw();
 }
 
@@ -3502,11 +3142,14 @@ void Draw_Move_Menu() {
     if (CurrentMenu != ProbeSetMenu) {
       CurrentMenu = ProbeSetMenu;
       SetMenuTitle({0}, GET_TEXT_F(MSG_ZPROBE_SETTINGS)); // TODO: Chinese, English "Probe Settings" JPG
-      DWINUI::MenuItemsPrepare(8);
+      DWINUI::MenuItemsPrepare(9);
       MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_AdvancedSettings_Menu);
       EDIT_ITEM(ICON_ProbeOffsetX, GET_TEXT_F(MSG_ZPROBE_XOFFSET), onDrawPFloatMenu, SetProbeOffsetX, &probe.offset.x);
       EDIT_ITEM(ICON_ProbeOffsetY, GET_TEXT_F(MSG_ZPROBE_YOFFSET), onDrawPFloatMenu, SetProbeOffsetY, &probe.offset.y);
       EDIT_ITEM(ICON_ProbeOffsetZ, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), onDrawPFloat2Menu, SetProbeOffsetZ, &probe.offset.z);
+      #if BOTH(HAS_HEATED_BED, PREHEAT_BEFORE_LEVELING)
+        EDIT_ITEM(ICON_Temperature, GET_TEXT_F(MSG_UBL_SET_TEMP_BED), onDrawPIntMenu, SetBedLevT, &HMI_data.BedLevT);
+      #endif
       #ifdef BLTOUCH_HS_MODE
         MENU_ITEM(ICON_HSMode, F("Enable HS mode"), onDrawHSMode, SetHSMode);
       #endif
@@ -3596,7 +3239,7 @@ void Draw_GetColor_Menu() {
     MENU_ITEM(2, GET_TEXT_F(MSG_COLORS_BLUE), onDrawGetColorItem, SetRGBColor);
   }
   CurrentMenu->draw();
-  DWIN_Draw_Rectangle(1, *HMI_value.P_Int, 20, 315, DWIN_WIDTH - 20, 335);
+  DWIN_Draw_Rectangle(1, *MenuData.P_Int, 20, 315, DWIN_WIDTH - 20, 335);
 }
 
 #if BOTH(CASE_LIGHT_MENU, CASELIGHT_USES_BRIGHTNESS)
@@ -3646,7 +3289,7 @@ void Draw_Tune_Menu() {
   if (CurrentMenu != TuneMenu) {
     CurrentMenu = TuneMenu;
     SetMenuTitle({73, 2, 28, 12}, GET_TEXT_F(MSG_TUNE)); // TODO: Chinese, English "Tune" JPG
-    DWINUI::MenuItemsPrepare(14);
+    DWINUI::MenuItemsPrepare(16);
     MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Goto_PrintProcess);
     #if ENABLED(CASE_LIGHT_MENU)
       MENU_ITEM(ICON_CaseLight, GET_TEXT_F(MSG_CASE_LIGHT), onDrawCaseLight, SetCaseLight);
@@ -3679,6 +3322,7 @@ void Draw_Tune_Menu() {
     MENU_ITEM(ICON_Lock, GET_TEXT_F(MSG_LOCKSCREEN), onDrawMenuItem, DWIN_LockScreen);
     #if HAS_LCD_BRIGHTNESS
       EDIT_ITEM(ICON_Brightness, GET_TEXT_F(MSG_BRIGHTNESS), onDrawPInt8Menu, SetBrightness, &ui.brightness);
+      MENU_ITEM(ICON_Brightness, GET_TEXT_F(MSG_BRIGHTNESS_OFF), onDrawMenuItem, TurnOffBacklight);
     #endif
   }
   CurrentMenu->draw();
diff --git a/Marlin/src/lcd/e3v2/proui/dwin.h b/Marlin/src/lcd/e3v2/proui/dwin.h
index 04ac1590ebf..9f49fa1825b 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin.h
+++ b/Marlin/src/lcd/e3v2/proui/dwin.h
@@ -22,32 +22,18 @@
 #pragma once
 
 /**
- * Enhanced DWIN implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.9.2
- * date: 2021/11/21
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.15.2
+ * Date: 2022/03/01
  */
 
-#include "../../../inc/MarlinConfigPre.h"
+#include "dwin_defines.h"
 #include "dwinui.h"
 #include "../common/encoder.h"
 #include "../../../libs/BL24CXX.h"
 
-#if ANY(AUTO_BED_LEVELING_BILINEAR, AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) && DISABLED(PROBE_MANUALLY)
-  #define HAS_ONESTEP_LEVELING 1
-#endif
-
-#if !HAS_BED_PROBE && ENABLED(BABYSTEPPING)
-  #define JUST_BABYSTEP 1
-#endif
-
-#if ANY(BABYSTEPPING, HAS_BED_PROBE, HAS_WORKSPACE_OFFSET)
-  #define HAS_ZOFFSET_ITEM 1
-#endif
-
-#include "dwin_defines.h"
+#include "../../../inc/MarlinConfig.h"
 
 enum processID : uint8_t {
   // Process ID
@@ -60,23 +46,16 @@ enum processID : uint8_t {
   SetPFloat,
   SelectFile,
   PrintProcess,
-  PrintDone,
-  PwrlossRec,
-  Reboot,
-  Info,
-  ConfirmToPrint,
-
-  // Popup Windows
-  Homing,
+  Popup,
   Leveling,
-  PidProcess,
-  ESDiagProcess,
-  PrintStatsProcess,
-  PauseOrStop,
-  FilamentPurge,
-  WaitResponse,
   Locked,
-  NothingToDo,
+  Reboot,
+  PrintDone,
+  ESDiagProcess,
+  WaitResponse,
+  Homing,
+  PidProcess,
+  NothingToDo
 };
 
 enum pidresult_t : uint8_t {
@@ -93,24 +72,18 @@ enum pidresult_t : uint8_t {
 
 typedef struct {
   int8_t Color[3];                    // Color components
-  uint16_t pidgrphpoints  = 0;
   pidresult_t pidresult   = PID_DONE;
   int8_t Preheat          = 0;        // Material Select 0: PLA, 1: ABS, 2: Custom
   AxisEnum axis           = X_AXIS;   // Axis Select
-  int32_t MaxValue        = 0;        // Auxiliar max integer/scaled float value
-  int32_t MinValue        = 0;        // Auxiliar min integer/scaled float value
-  int8_t dp               = 0;        // Auxiliar decimal places
-  int32_t Value           = 0;        // Auxiliar integer / scaled float value
-  int16_t *P_Int          = nullptr;  // Auxiliar pointer to 16 bit integer variable
-  float *P_Float          = nullptr;  // Auxiliar pointer to float variable
-  void (*Apply)()         = nullptr;  // Auxiliar apply function
-  void (*LiveUpdate)()    = nullptr;  // Auxiliar live update function
 } HMI_value_t;
 
 typedef struct {
   uint8_t language;
+  bool remain_flag:1;   // remain was override by M73
   bool pause_flag:1;    // printing is paused
   bool pause_action:1;  // flag a pause action
+  bool abort_flag:1;    // printing is aborting
+  bool abort_action:1;  // flag a aborting action
   bool print_finish:1;  // print was finished
   bool select_flag:1;   // Popup button selected
   bool home_flag:1;     // homing in course
@@ -126,9 +99,6 @@ extern millis_t dwin_heat_time;
 #if HAS_HOTEND || HAS_HEATED_BED
   void DWIN_Popup_Temperature(const bool toohigh);
 #endif
-#if HAS_HOTEND
-  void Popup_Window_ETempTooLow();
-#endif
 #if ENABLED(POWER_LOSS_RECOVERY)
   void Popup_PowerLossRecovery();
 #endif
@@ -143,50 +113,64 @@ void Goto_Main_Menu();
 void Goto_Info_Menu();
 void Goto_PowerLossRecovery();
 void Goto_ConfirmToPrint();
-void Draw_Status_Area(const bool with_update); // Status Area
+void DWIN_Draw_Dashboard(const bool with_update); // Status Area
 void Draw_Main_Area();      // Redraw main area;
 void DWIN_Redraw_screen();  // Redraw all screen elements
-void HMI_StartFrame(const bool with_update);   // Prepare the menu view
 void HMI_MainMenu();        // Main process screen
 void HMI_SelectFile();      // File page
 void HMI_Printing();        // Print page
 void HMI_ReturnScreen();    // Return to previous screen before popups
 void ApplyExtMinT();
 void HMI_SetLanguageCache(); // Set the languaje image cache
+void RebootPrinter();
+#if ENABLED(BAUD_RATE_GCODE)
+  void HMI_SetBaudRate();
+  void SetBaud115K();
+  void SetBaud250K();
+#endif
+#if ENABLED(EEPROM_SETTINGS)
+  void WriteEeprom();
+  void ReadEeprom();
+  void ResetEeprom();
+#endif
 
-void HMI_Init();
-void HMI_Popup();
+void HMI_WaitForUser();
 void HMI_SaveProcessID(const uint8_t id);
 void HMI_AudioFeedback(const bool success=true);
 void EachMomentUpdate();
 void update_variable();
+void DWIN_InitScreen();
 void DWIN_HandleScreen();
-void DWIN_Update();
 void DWIN_CheckStatusMessage();
 void DWIN_StartHoming();
 void DWIN_CompletedHoming();
 #if HAS_MESH
-  void DWIN_MeshUpdate(const int8_t xpos, const int8_t ypos, const float zval);
+  void DWIN_MeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval);
 #endif
 void DWIN_MeshLevelingStart();
 void DWIN_CompletedLeveling();
 void DWIN_PidTuning(pidresult_t result);
-void DWIN_Print_Started(const bool sd = false);
+void DWIN_Print_Started(const bool sd=false);
+void DWIN_Print_Pause();
+void DWIN_Print_Resume();
 void DWIN_Print_Finished();
+void DWIN_Print_Aborted();
 #if HAS_FILAMENT_SENSOR
   void DWIN_FilamentRunout(const uint8_t extruder);
 #endif
 void DWIN_Progress_Update();
 void DWIN_Print_Header(const char *text);
 void DWIN_SetColorDefaults();
+void DWIN_ApplyColor();
 void DWIN_StoreSettings(char *buff);
 void DWIN_LoadSettings(const char *buff);
 void DWIN_SetDataDefaults();
 void DWIN_RebootScreen();
 
 #if ENABLED(ADVANCED_PAUSE_FEATURE)
+  void DWIN_Popup_Pause(FSTR_P const fmsg, uint8_t button=0);
   void Draw_Popup_FilamentPurge();
-  void DWIN_Popup_FilamentPurge();
+  void Goto_FilamentPurge();
   void HMI_FilamentPurge();
 #endif
 
@@ -207,14 +191,6 @@ void HMI_LockScreen();
   void Draw_PrintStats();
 #endif
 
-// HMI user control functions
-void HMI_Menu();
-void HMI_SetInt();
-void HMI_SetPInt();
-void HMI_SetIntNoDraw();
-void HMI_SetFloat();
-void HMI_SetPFloat();
-
 // Menu drawing functions
 void Draw_Control_Menu();
 void Draw_AdvancedSettings_Menu();
diff --git a/Marlin/src/lcd/e3v2/proui/dwin_defines.h b/Marlin/src/lcd/e3v2/proui/dwin_defines.h
index 3dc2408f4a0..5065bb94d75 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin_defines.h
+++ b/Marlin/src/lcd/e3v2/proui/dwin_defines.h
@@ -22,18 +22,37 @@
 #pragma once
 
 /**
- * DWIN general defines and data structs
+ * DWIN general defines and data structs for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.9.2
- * Date: 2021/11/21
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.11.2
+ * Date: 2022/02/28
  */
 
-//#define NEED_HEX_PRINT 1
 //#define DEBUG_DWIN 1
+//#define NEED_HEX_PRINT 1
+
+#include "../../../inc/MarlinConfigPre.h"
+#include <stddef.h>
+
+#if DISABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU)
+  #error "INDIVIDUAL_AXIS_HOMING_SUBMENU is required with ProUI."
+#endif
+#if DISABLED(LCD_SET_PROGRESS_MANUALLY)
+  #error "LCD_SET_PROGRESS_MANUALLY is required with ProUI."
+#endif
+#if DISABLED(STATUS_MESSAGE_SCROLLING)
+  #error "STATUS_MESSAGE_SCROLLING is required with ProUI."
+#endif
+#if DISABLED(BAUD_RATE_GCODE)
+  #error "BAUD_RATE_GCODE is required with ProUI."
+#endif
+#if DISABLED(SOUND_MENU_ITEM)
+  #error "SOUND_MENU_ITEM is required with ProUI."
+#endif
+#if DISABLED(PRINTCOUNTER)
+  #error "PRINTCOUNTER is required with ProUI."
+#endif
 
-#include "../../../core/types.h"
 #include "../common/dwin_color.h"
 #if ENABLED(LED_CONTROL_MENU)
   #include "../../../feature/leds/leds.h"
@@ -57,8 +76,8 @@
 #define Def_Barfill_Color     BarFill_Color
 #define Def_Indicator_Color   Color_White
 #define Def_Coordinate_Color  Color_White
+#define Def_Button_Color      RGB( 0, 23, 16)
 
-//#define HAS_GCODE_PREVIEW 1
 #define HAS_ESDIAG 1
 
 #if ENABLED(LED_CONTROL_MENU, HAS_COLOR_LEDS)
@@ -101,6 +120,9 @@ typedef struct {
   #if ENABLED(PREVENT_COLD_EXTRUSION)
     int16_t ExtMinT = EXTRUDE_MINTEMP;
   #endif
+  int16_t BedLevT = PREHEAT_1_TEMP_BED;
+  TERN_(BAUD_RATE_GCODE, bool Baud115K = false);
+  bool FullManualTramming = false;
   // Led
   #if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
     LEDColor Led_Color = Def_Leds_Color;
@@ -113,3 +135,8 @@ typedef struct {
 
 static constexpr size_t eeprom_data_size = 64;
 extern HMI_data_t HMI_data;
+
+#if PREHEAT_1_TEMP_BED
+  #undef LEVELING_BED_TEMP
+  #define LEVELING_BED_TEMP HMI_data.BedLevT
+#endif
diff --git a/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp b/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp
index b8bff351595..3da3fc80862 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp
+++ b/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp
@@ -21,12 +21,10 @@
  */
 
 /**
- * DWIN UI Enhanced implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.8.1
- * Date: 2021/11/09
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.9.1
+ * Date: 2022/02/08
  */
 
 #include "../../../inc/MarlinConfigPre.h"
@@ -37,6 +35,54 @@
 
 #include "dwin_lcd.h"
 
+/*---------------------------------------- Numeric related functions ----------------------------------------*/
+
+// Draw a numeric value
+//  bShow: true=display background color; false=don't display background color
+//  zeroFill: true=zero fill; false=no zero fill
+//  signedMode: 1=signed; 0=unsigned
+//  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  iNum: Number of digits
+//  fNum: Number of decimal digits
+//  x/y: Upper-left coordinate
+//  value: Integer value
+void DWIN_Draw_Value(uint8_t bShow, bool signedMode, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                          uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, int32_t value) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x14);
+  // Bit 7: bshow
+  // Bit 6: 1 = signed; 0 = unsigned number;
+  // Bit 5: zeroFill
+  // Bit 4: zeroMode
+  // Bit 3-0: size
+  DWIN_Byte(i, (bShow * 0x80) | (signedMode * 0x40) | (zeroFill * 0x20) | (zeroMode * 0x10) | size);
+  DWIN_Word(i, color);
+  DWIN_Word(i, bColor);
+  DWIN_Byte(i, signedMode && (value >= 0) ? iNum + 1 : iNum);
+  DWIN_Byte(i, fNum);
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  // Write a big-endian 64 bit integer
+  const size_t p = i + 1;
+  for (size_t count = 8; count--;) { // 7..0
+    ++i;
+    DWIN_SendBuf[p + count] = value;
+    value >>= 8;
+  }
+  DWIN_Send(i);
+}
+
+// Draw a numeric value
+//  value: positive unscaled float value
+void DWIN_Draw_Value(uint8_t bShow, bool signedMode, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                          uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
+  const int32_t val = round(value * POW(10, fNum));
+  DWIN_Draw_Value(bShow, signedMode, zeroFill, zeroMode, size, color, bColor, iNum, fNum, x, y, val);
+}
+
 /*---------------------------------------- Picture related functions ----------------------------------------*/
 
 // Display QR code
diff --git a/Marlin/src/lcd/e3v2/proui/dwin_lcd.h b/Marlin/src/lcd/e3v2/proui/dwin_lcd.h
index 623a94f09e1..cdffb96f2f3 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin_lcd.h
+++ b/Marlin/src/lcd/e3v2/proui/dwin_lcd.h
@@ -22,16 +22,32 @@
 #pragma once
 
 /**
- * DWIN UI Enhanced implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.8.1
- * Date: 2021/11/09
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.9.1
+ * Date: 2022/02/08
  */
 
 #include "../common/dwin_api.h"
 
+// Draw a numeric value
+//  bShow: true=display background color; false=don't display background color
+//  zeroFill: true=zero fill; false=no zero fill
+//  signedMode: 1=signed; 0=unsigned
+//  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  iNum: Number of digits
+//  fNum: Number of decimal digits
+//  x/y: Upper-left coordinate
+//  value: Integer value
+void DWIN_Draw_Value(uint8_t bShow, bool signedMode, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                          uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, int32_t value);
+//  value: positive unscaled float value
+void DWIN_Draw_Value(uint8_t bShow, bool signedMode, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                          uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value);
+
 // Display QR code
 //  The size of the QR code is (46*QR_Pixel)*(46*QR_Pixel) dot matrix
 //  QR_Pixel: The pixel size occupied by each point of the QR code: 0x01-0x0F (1-16)
diff --git a/Marlin/src/lcd/e3v2/proui/dwin_popup.cpp b/Marlin/src/lcd/e3v2/proui/dwin_popup.cpp
index 33f216fde6e..59b6c0d328a 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin_popup.cpp
+++ b/Marlin/src/lcd/e3v2/proui/dwin_popup.cpp
@@ -21,12 +21,10 @@
  */
 
 /**
- * DWIN UI Enhanced implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.10.1
- * Date: 2022/01/21
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.11.1
+ * Date: 2022/02/28
  */
 
 #include "../../../inc/MarlinConfigPre.h"
@@ -34,30 +32,64 @@
 #if ENABLED(DWIN_LCD_PROUI)
 
 #include "dwin.h"
+#include "dwinui.h"
 #include "dwin_popup.h"
 
-void Draw_Select_Highlight(const bool sel) {
+#include "../../../MarlinCore.h" // for wait_for_user
+
+popupDrawFunc_t popupDraw = nullptr;
+popupClickFunc_t popupClick = nullptr;
+popupChangeFunc_t popupChange = nullptr;
+
+uint16_t HighlightYPos = 280;
+
+void Draw_Select_Highlight(const bool sel, const uint16_t ypos) {
+  HighlightYPos = ypos;
   HMI_flag.select_flag = sel;
   const uint16_t c1 = sel ? HMI_data.Highlight_Color : HMI_data.PopupBg_color,
                  c2 = sel ? HMI_data.PopupBg_color : HMI_data.Highlight_Color;
-  DWIN_Draw_Rectangle(0, c1, 25, 279, 126, 318);
-  DWIN_Draw_Rectangle(0, c1, 24, 278, 127, 319);
-  DWIN_Draw_Rectangle(0, c2, 145, 279, 246, 318);
-  DWIN_Draw_Rectangle(0, c2, 144, 278, 247, 319);
+  DWIN_Draw_Rectangle(0, c1, 25, ypos - 1, 126, ypos + 38);
+  DWIN_Draw_Rectangle(0, c1, 24, ypos - 2, 127, ypos + 39);
+  DWIN_Draw_Rectangle(0, c2, 145, ypos - 1, 246, ypos + 38);
+  DWIN_Draw_Rectangle(0, c2, 144, ypos - 2, 247, ypos + 39);
 }
 
 void DWIN_Popup_Continue(const uint8_t icon, FSTR_P const fmsg1, FSTR_P const fmsg2) {
   HMI_SaveProcessID(WaitResponse);
-  DWIN_Draw_Popup(icon, fmsg1, fmsg2, ICON_Continue_E);  // Button Continue
+  DWIN_Draw_Popup(icon, fmsg1, fmsg2, BTN_Continue);  // Button Continue
   DWIN_UpdateLCD();
 }
 
 void DWIN_Popup_ConfirmCancel(const uint8_t icon, FSTR_P const fmsg2) {
   DWIN_Draw_Popup(ICON_BLTouch, F("Please confirm"), fmsg2);
-  DWINUI::Draw_IconWB(ICON_Confirm_E, 26, 280);
-  DWINUI::Draw_IconWB(ICON_Cancel_E, 146, 280);
-  Draw_Select_Highlight(true);
+  DWINUI::Draw_Button(BTN_Confirm, 26, 280);
+  DWINUI::Draw_Button(BTN_Cancel, 146, 280);
+  Draw_Select_Highlight(HMI_flag.select_flag);
   DWIN_UpdateLCD();
 }
 
+void Goto_Popup(const popupDrawFunc_t fnDraw, const popupClickFunc_t fnClick/*=nullptr*/, const popupChangeFunc_t fnChange/*=nullptr*/) {
+  popupDraw = fnDraw;
+  popupClick = fnClick;
+  popupChange = fnChange;
+  HMI_SaveProcessID(Popup);
+  HMI_flag.select_flag = false;
+  popupDraw();
+}
+
+void HMI_Popup() {
+  if (!wait_for_user) {
+    if (popupClick) popupClick();
+    return;
+  }
+  else {
+    EncoderState encoder_diffState = get_encoder_state();
+    if (encoder_diffState == ENCODER_DIFF_CW || encoder_diffState == ENCODER_DIFF_CCW) {
+      const bool change = encoder_diffState != ENCODER_DIFF_CW;
+      if (popupChange) popupChange(change); else Draw_Select_Highlight(change, HighlightYPos);
+      DWIN_UpdateLCD();
+    }
+  }
+}
+
 #endif // DWIN_LCD_PROUI
diff --git a/Marlin/src/lcd/e3v2/proui/dwin_popup.h b/Marlin/src/lcd/e3v2/proui/dwin_popup.h
index 2e952cc1b99..0d864994754 100644
--- a/Marlin/src/lcd/e3v2/proui/dwin_popup.h
+++ b/Marlin/src/lcd/e3v2/proui/dwin_popup.h
@@ -22,20 +22,26 @@
 #pragma once
 
 /**
- * DWIN UI Enhanced implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.10.1
- * Date: 2022/01/21
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.11.1
+ * Date: 2022/02/28
  */
 
 #include "dwinui.h"
 #include "dwin.h"
 
-// Popup windows
+typedef void (*popupDrawFunc_t)();
+typedef void (*popupClickFunc_t)();
+typedef void (*popupChangeFunc_t)(const bool state);
+extern popupDrawFunc_t popupDraw;
 
-void Draw_Select_Highlight(const bool sel);
+void Draw_Select_Highlight(const bool sel, const uint16_t ypos);
+inline void Draw_Select_Highlight(const bool sel) { Draw_Select_Highlight(sel, 280); };
+void DWIN_Popup_Continue(const uint8_t icon, FSTR_P const fmsg1, FSTR_P const fmsg2);
+void DWIN_Popup_ConfirmCancel(const uint8_t icon, FSTR_P const fmsg2);
+void Goto_Popup(const popupDrawFunc_t fnDraw, const popupClickFunc_t fnClick=nullptr, const popupChangeFunc_t fnChange=nullptr);
+void HMI_Popup();
 
 inline void Draw_Popup_Bkgd() {
   DWIN_Draw_Rectangle(1, HMI_data.PopupBg_color, 14, 60, 258, 330);
@@ -49,7 +55,7 @@ void DWIN_Draw_Popup(const uint8_t icon, T amsg1=nullptr, U amsg2=nullptr, uint8
   if (icon) DWINUI::Draw_Icon(icon, 101, 105);
   if (amsg1) DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 210, amsg1);
   if (amsg2) DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 240, amsg2);
-  if (button) DWINUI::Draw_IconWB(button, 86, 280);
+  if (button) DWINUI::Draw_Button(button, 86, 280);
 }
 
 template<typename T, typename U>
@@ -61,10 +67,7 @@ void DWIN_Show_Popup(const uint8_t icon, T amsg1=nullptr, U amsg2=nullptr, uint8
 template<typename T, typename U>
 void DWIN_Popup_Confirm(const uint8_t icon, T amsg1, U amsg2) {
   HMI_SaveProcessID(WaitResponse);
-  DWIN_Draw_Popup(icon, amsg1, amsg2, ICON_Confirm_E);  // Button Confirm
+  DWIN_Draw_Popup(icon, amsg1, amsg2, BTN_Confirm);  // Button Confirm
   DWIN_UpdateLCD();
 }
 
-void DWIN_Popup_Continue(const uint8_t icon, FSTR_P const fmsg1, FSTR_P const fmsg2);
-
-void DWIN_Popup_ConfirmCancel(const uint8_t icon, FSTR_P const fmsg2);
diff --git a/Marlin/src/lcd/e3v2/proui/dwinui.cpp b/Marlin/src/lcd/e3v2/proui/dwinui.cpp
index 1dbd5313906..ddc494fc849 100644
--- a/Marlin/src/lcd/e3v2/proui/dwinui.cpp
+++ b/Marlin/src/lcd/e3v2/proui/dwinui.cpp
@@ -21,12 +21,10 @@
  */
 
 /**
- * DWIN UI Enhanced implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.8.2
- * Date: 2021/11/09
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.15.1
+ * Date: 2022/02/25
  */
 
 #include "../../../inc/MarlinConfigPre.h"
@@ -51,7 +49,9 @@ xy_int_t DWINUI::cursor = { 0 };
 uint16_t DWINUI::pencolor = Color_White;
 uint16_t DWINUI::textcolor = Def_Text_Color;
 uint16_t DWINUI::backcolor = Def_Background_Color;
+uint16_t DWINUI::buttoncolor = Def_Button_Color;
 uint8_t  DWINUI::font = font8x16;
+FSTR_P const DWINUI::Author = F(STRING_CONFIG_H_AUTHOR);
 
 void (*DWINUI::onCursorErase)(const int8_t line)=nullptr;
 void (*DWINUI::onCursorDraw)(const int8_t line)=nullptr;
@@ -59,18 +59,16 @@ void (*DWINUI::onTitleDraw)(TitleClass* title)=nullptr;
 void (*DWINUI::onMenuDraw)(MenuClass* menu)=nullptr;
 
 void DWINUI::init() {
-  DEBUG_ECHOPGM("\r\nDWIN handshake ");
-  delay(750);   // Delay here or init later in the boot process
-  const bool success = DWIN_Handshake();
-  if (success) DEBUG_ECHOLNPGM("ok."); else DEBUG_ECHOLNPGM("error.");
+  TERN_(DEBUG_DWIN, SERIAL_ECHOPGM("\r\nDWIN handshake "));
+  delay(750);   // Delay for wait to wakeup screen
+  const bool hs = DWIN_Handshake();
+  TERN(DEBUG_DWIN, SERIAL_ECHOLNF(hs ? F("ok.") : F("error.")), UNUSED(hs));
   DWIN_Frame_SetDir(1);
-  TERN(SHOW_BOOTSCREEN,,DWIN_Frame_Clear(Color_Bg_Black));
-  DWIN_UpdateLCD();
-  cursor.x = 0;
-  cursor.y = 0;
+  cursor.reset();
   pencolor = Color_White;
   textcolor = Def_Text_Color;
   backcolor = Def_Background_Color;
+  buttoncolor = Def_Button_Color;
   font = font8x16;
 }
 
@@ -124,9 +122,10 @@ uint16_t DWINUI::RowToY(uint8_t row) {
 }
 
 // Set text/number color
-void DWINUI::SetColors(uint16_t fgcolor, uint16_t bgcolor) {
+void DWINUI::SetColors(uint16_t fgcolor, uint16_t bgcolor, uint16_t alcolor) {
   textcolor = fgcolor;
   backcolor = bgcolor;
+  buttoncolor = alcolor;
 }
 void DWINUI::SetTextColor(uint16_t fgcolor) {
   textcolor = fgcolor;
@@ -159,16 +158,22 @@ void DWINUI::MoveBy(xy_int_t point) {
   cursor += point;
 }
 
-// Draw a Centered string using DWIN_WIDTH
-void DWINUI::Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t y, const char * const string) {
-  const int8_t x = _MAX(0U, DWIN_WIDTH - strlen_P(string) * fontWidth(size)) / 2 - 1;
+// Draw a Centered string using arbitrary x1 and x2 margins
+void DWINUI::Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x1, uint16_t x2, uint16_t y, const char * const string) {
+  const uint16_t x = _MAX(0U, x2 + x1 - strlen_P(string) * fontWidth(size)) / 2 - 1;
   DWIN_Draw_String(bShow, size, color, bColor, x, y, string);
 }
 
+// // Draw a Centered string using DWIN_WIDTH
+// void DWINUI::Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t y, const char * const string) {
+//   const int8_t x = _MAX(0U, DWIN_WIDTH - strlen_P(string) * fontWidth(size)) / 2 - 1;
+//   DWIN_Draw_String(bShow, size, color, bColor, x, y, string);
+// }
+
 // Draw a char at cursor position
-void DWINUI::Draw_Char(const char c) {
+void DWINUI::Draw_Char(uint16_t color, const char c) {
   const char string[2] = { c, 0};
-  DWIN_Draw_String(false, font, textcolor, backcolor, cursor.x, cursor.y, string, 1);
+  DWIN_Draw_String(false, font, color, backcolor, cursor.x, cursor.y, string, 1);
   MoveBy(fontWidth(font), 0);
 }
 
@@ -185,21 +190,26 @@ void DWINUI::Draw_String(uint16_t color, const char * const string, uint16_t rli
   MoveBy(strlen(string) * fontWidth(font), 0);
 }
 
-// Draw a signed floating point number
-//  bShow: true=display background color; false=don't display background color
-//  zeroFill: true=zero fill; false=no zero fill
-//  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
-//  size: Font size
-//  bColor: Background color
-//  iNum: Number of whole digits
-//  fNum: Number of decimal digits
-//  x/y: Upper-left point
-//  value: Float value
-void DWINUI::Draw_Signed_Float(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-  DWIN_Draw_FloatValue(bShow, zeroFill, zeroMode, size, color, bColor, iNum, fNum, x, y, value < 0 ? -value : value);
-  DWIN_Draw_String(bShow, size, color, bColor, x - 6, y, value < 0 ? F("-") : F(" "));
+// ------------------------- Buttons ------------------------------//
+
+void DWINUI::Draw_Button(uint16_t color, uint16_t bcolor, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const char * const caption) {
+  DWIN_Draw_Rectangle(1, bcolor, x1, y1, x2, y2);
+  Draw_CenteredString(0, font, color, bcolor, x1, x2, (y2 + y1 - fontHeight())/2, caption);
 }
 
+void DWINUI::Draw_Button(uint8_t id, uint16_t x, uint16_t y) {
+  switch (id) {
+    case BTN_Cancel  : Draw_Button(GET_TEXT_F(MSG_BUTTON_CANCEL), x, y); break;
+    case BTN_Confirm : Draw_Button(GET_TEXT_F(MSG_BUTTON_CONFIRM), x, y); break;
+    case BTN_Continue: Draw_Button(GET_TEXT_F(MSG_BUTTON_CONTINUE), x, y); break;
+    case BTN_Print   : Draw_Button(GET_TEXT_F(MSG_BUTTON_PRINT), x, y); break;
+    case BTN_Save    : Draw_Button(GET_TEXT_F(MSG_BUTTON_SAVE), x, y); break;
+    default: break;
+  }
+}
+
+// -------------------------- Extra -------------------------------//
+
 // Draw a circle
 //  color: circle color
 //  x: the abscissa of the center of the circle
@@ -247,13 +257,12 @@ void DWINUI::Draw_FillCircle(uint16_t bcolor, uint16_t x,uint16_t y,uint8_t r) {
 //  color1 : Start color
 //  color2 : End color
 uint16_t DWINUI::ColorInt(int16_t val, int16_t minv, int16_t maxv, uint16_t color1, uint16_t color2) {
-  uint8_t B,G,R;
-  float n;
-  n = (float)(val-minv)/(maxv-minv);
-  R = (1-n)*GetRColor(color1) + n*GetRColor(color2);
-  G = (1-n)*GetGColor(color1) + n*GetGColor(color2);
-  B = (1-n)*GetBColor(color1) + n*GetBColor(color2);
-  return RGB(R,G,B);
+  uint8_t B, G, R;
+  const float n = (float)(val - minv) / (maxv - minv);
+  R = (1 - n) * GetRColor(color1) + n * GetRColor(color2);
+  G = (1 - n) * GetGColor(color1) + n * GetGColor(color2);
+  B = (1 - n) * GetBColor(color1) + n * GetBColor(color2);
+  return RGB(R, G, B);
 }
 
 // Color Interpolator through Red->Yellow->Green->Blue
@@ -261,33 +270,27 @@ uint16_t DWINUI::ColorInt(int16_t val, int16_t minv, int16_t maxv, uint16_t colo
 //  minv : Minimum value
 //  maxv : Maximum value
 uint16_t DWINUI::RainbowInt(int16_t val, int16_t minv, int16_t maxv) {
-  uint8_t B,G,R;
-  const uint8_t maxB = 28;
-  const uint8_t maxR = 28;
-  const uint8_t maxG = 38;
+  uint8_t B, G, R;
+  const uint8_t maxB = 28, maxR = 28, maxG = 38;
   const int16_t limv = _MAX(abs(minv), abs(maxv));
-  float n;
-  if (minv>=0) {
-    n = (float)(val-minv)/(maxv-minv);
-  } else {
-    n = (float)val/limv;
-  }
-  n = _MIN(1, n);
-  n = _MAX(-1, n);
+  float n = minv >= 0 ? (float)(val - minv) / (maxv - minv) : (float)val / limv;
+  LIMIT(n, -1, 1);
   if (n < 0) {
     R = 0;
-    G = (1+n)*maxG;
-    B = (-n)*maxB;
-  } else if (n < 0.5) {
-    R = maxR*n*2;
+    G = (1 + n) * maxG;
+    B = (-n) * maxB;
+  }
+  else if (n < 0.5) {
+    R = maxR * n * 2;
     G = maxG;
     B = 0;
-  } else {
+  }
+  else {
     R = maxR;
-    G = maxG*(1-n);
+    G = maxG * (1 - n);
     B = 0;
   }
-  return RGB(R,G,B);
+  return RGB(R, G, B);
 }
 
 // Draw a checkbox
diff --git a/Marlin/src/lcd/e3v2/proui/dwinui.h b/Marlin/src/lcd/e3v2/proui/dwinui.h
index 595c534356d..1504dcd3059 100644
--- a/Marlin/src/lcd/e3v2/proui/dwinui.h
+++ b/Marlin/src/lcd/e3v2/proui/dwinui.h
@@ -22,12 +22,10 @@
 #pragma once
 
 /**
- * DWIN UI Enhanced implementation
+ * DWIN Enhanced implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.11.1
- * Date: 2022/01/19
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 3.15.1
+ * Date: 2022/02/25
  */
 
 #include "dwin_lcd.h"
@@ -107,6 +105,13 @@
 #define ICON_CaseLight            ICON_Motion
 #define ICON_LedControl           ICON_Motion
 
+// Buttons
+#define BTN_Continue          85
+#define BTN_Cancel            87
+#define BTN_Confirm           89
+#define BTN_Print             90
+#define BTN_Save              91
+
 // Extended and default UI Colors
 #define Color_Black           0
 #define Color_Green           RGB(0,63,0)
@@ -119,7 +124,11 @@
 #define DWIN_FONT_HEAD font10x20
 #define DWIN_FONT_ALERT font10x20
 #define STATUS_Y 354
-#define LCD_WIDTH (DWIN_WIDTH / 8)
+#define LCD_WIDTH (DWIN_WIDTH / 8)  // only if the default font is font8x16
+
+// Minimum unit (0.1) : multiple (10)
+#define UNITFDIGITS 1
+#define MINUNITMULT POW(10, UNITFDIGITS)
 
 constexpr uint16_t TITLE_HEIGHT = 30,                          // Title bar height
                    MLINE = 53,                                 // Menu line height
@@ -212,7 +221,9 @@ namespace DWINUI {
   extern uint16_t pencolor;
   extern uint16_t textcolor;
   extern uint16_t backcolor;
+  extern uint16_t buttoncolor;
   extern uint8_t  font;
+  extern FSTR_P const Author;
 
   extern void (*onCursorErase)(const int8_t line);
   extern void (*onCursorDraw)(const int8_t line);
@@ -240,7 +251,7 @@ namespace DWINUI {
   uint16_t RowToY(uint8_t row);
 
   // Set text/number color
-  void SetColors(uint16_t fgcolor, uint16_t bgcolor);
+  void SetColors(uint16_t fgcolor, uint16_t bgcolor, uint16_t alcolor);
   void SetTextColor(uint16_t fgcolor);
   void SetBackgroundColor(uint16_t bgcolor);
 
@@ -268,6 +279,17 @@ namespace DWINUI {
     DWIN_Draw_Line(pencolor, cursor.x, cursor.y, x, y);
   }
 
+  // Extend a frame box
+  //  v: value to extend
+  inline frame_rect_t ExtendFrame(frame_rect_t frame, uint8_t v) {
+    frame_rect_t t;
+    t.x = frame.x - v;
+    t.y = frame.y - v;
+    t.w = frame.w + 2 * v;
+    t.h = frame.h + 2 * v;
+    return t;
+  }
+
   // Draw an Icon with transparent background from the library ICON
   //  icon: Icon ID
   //  x/y: Upper-left point
@@ -293,26 +315,56 @@ namespace DWINUI {
   //  x/y: Upper-left coordinate
   //  value: Integer value
   inline void Draw_Int(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) {
-    DWIN_Draw_IntValue(bShow, zeroFill, zeroMode, size, color, bColor, iNum, x, y, value);
+    DWIN_Draw_Value(bShow, 0, zeroFill, zeroMode, size, color, bColor, iNum, 0, x, y, value);
   }
   inline void Draw_Int(uint8_t iNum, long value) {
-    DWIN_Draw_IntValue(false, true, 0, font, textcolor, backcolor, iNum, cursor.x, cursor.y, value);
+    DWIN_Draw_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, 0, cursor.x, cursor.y, value);
     MoveBy(iNum * fontWidth(font), 0);
   }
   inline void Draw_Int(uint8_t iNum, uint16_t x, uint16_t y, long value) {
-    DWIN_Draw_IntValue(false, true, 0, font, textcolor, backcolor, iNum, x, y, value);
+    DWIN_Draw_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, 0, x, y, value);
   }
   inline void Draw_Int(uint16_t color, uint8_t iNum, uint16_t x, uint16_t y, long value) {
-    DWIN_Draw_IntValue(false, true, 0, font, color, backcolor, iNum, x, y, value);
+    DWIN_Draw_Value(false, 0, true, 0, font, color, backcolor, iNum, 0, x, y, value);
   }
   inline void Draw_Int(uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) {
-    DWIN_Draw_IntValue(true, true, 0, font, color, bColor, iNum, x, y, value);
+    DWIN_Draw_Value(true, 0, true, 0, font, color, bColor, iNum, 0, x, y, value);
   }
   inline void Draw_Int(uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) {
-    DWIN_Draw_IntValue(true, true, 0, size, color, bColor, iNum, x, y, value);
+    DWIN_Draw_Value(true, 0, true, 0, size, color, bColor, iNum, 0, x, y, value);
   }
 
-  // Draw a floating point number
+  // Draw a signed integer
+  //  bShow: true=display background color; false=don't display background color
+  //  zeroFill: true=zero fill; false=no zero fill
+  //  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
+  //  size: Font size
+  //  color: Character color
+  //  bColor: Background color
+  //  iNum: Number of digits
+  //  x/y: Upper-left coordinate
+  //  value: Integer value
+  inline void Draw_Signed_Int(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) {
+    DWIN_Draw_Value(bShow, 1, zeroFill, zeroMode, size, color, bColor, iNum, 0, x, y, value);
+  }
+  inline void Draw_Signed_Int(uint8_t iNum, long value) {
+    DWIN_Draw_Value(false, 1, true, 0, font, textcolor, backcolor, iNum, 0, cursor.x, cursor.y, value);
+    MoveBy(iNum * fontWidth(font), 0);
+  }
+  inline void Draw_Signed_Int(uint8_t iNum, uint16_t x, uint16_t y, long value) {
+    DWIN_Draw_Value(false, 1, true, 0, font, textcolor, backcolor, iNum, 0, x, y, value);
+  }
+  inline void Draw_Signed_Int(uint16_t color, uint8_t iNum, uint16_t x, uint16_t y, long value) {
+    DWIN_Draw_Value(false, 1, true, 0, font, color, backcolor, iNum, 0, x, y, value);
+  }
+  inline void Draw_Signed_Int(uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) {
+    DWIN_Draw_Value(true, 1, true, 0, font, color, bColor, iNum, 0, x, y, value);
+  }
+  inline void Draw_Signed_Int(uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) {
+    DWIN_Draw_Value(true, 1, true, 0, size, color, bColor, iNum, 0, x, y, value);
+  }
+
+  // Draw a positive floating point number
   //  bShow: true=display background color; false=don't display background color
   //  zeroFill: true=zero fill; false=no zero fill
   //  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
@@ -324,23 +376,23 @@ namespace DWINUI {
   //  x/y: Upper-left point
   //  value: Float value
   inline void Draw_Float(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    DWIN_Draw_FloatValue(bShow, zeroFill, zeroMode, size, color, bColor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(bShow, 0, zeroFill, zeroMode, size, color, bColor, iNum, fNum, x, y, value);
   }
   inline void Draw_Float(uint8_t iNum, uint8_t fNum, float value) {
-    DWIN_Draw_FloatValue(false, true, 0, font, textcolor, backcolor, iNum, fNum,  cursor.x, cursor.y, value);
+    DWIN_Draw_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, fNum, cursor.x, cursor.y, value);
     MoveBy((iNum + fNum + 1) * fontWidth(font), 0);
   }
   inline void Draw_Float(uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    DWIN_Draw_FloatValue(false, true, 0, font, textcolor, backcolor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, fNum, x, y, value);
   }
   inline void Draw_Float(uint16_t color, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    DWIN_Draw_FloatValue(false, true, 0, font, color, backcolor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(false, 0, true, 0, font, color, backcolor, iNum, fNum, x, y, value);
   }
   inline void Draw_Float(uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    DWIN_Draw_FloatValue(true, true, 0, font, color, bColor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(true, 0, true, 0, font, color, bColor, iNum, fNum, x, y, value);
   }
   inline void Draw_Float(uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    DWIN_Draw_FloatValue(true, true, 0, size, color, bColor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(true, 0, true, 0, size, color, bColor, iNum, fNum, x, y, value);
   }
 
   // Draw a signed floating point number
@@ -348,31 +400,35 @@ namespace DWINUI {
   //  zeroFill: true=zero fill; false=no zero fill
   //  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
   //  size: Font size
+  //  color: Character color
   //  bColor: Background color
   //  iNum: Number of whole digits
   //  fNum: Number of decimal digits
   //  x/y: Upper-left point
   //  value: Float value
-  void Draw_Signed_Float(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value);
+  inline void Draw_Signed_Float(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
+    DWIN_Draw_Value(bShow, 1, zeroFill, zeroMode, size, color, bColor, iNum, fNum, x, y, value);
+  }
   inline void Draw_Signed_Float(uint8_t iNum, uint8_t fNum, float value) {
-    Draw_Signed_Float(false, true, 0, font, textcolor, backcolor, iNum, fNum, cursor.x, cursor.y, value);
+    DWIN_Draw_Value(false, 1, true, 0, font, textcolor, backcolor, iNum, fNum, cursor.x, cursor.y, value);
     MoveBy((iNum + fNum + 1) * fontWidth(font), 0);
   }
   inline void Draw_Signed_Float(uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    Draw_Signed_Float(false, true, 0, font, textcolor, backcolor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(false, 1, true, 0, font, textcolor, backcolor, iNum, fNum, x, y, value);
   }
   inline void Draw_Signed_Float(uint8_t size, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    Draw_Signed_Float(false, true, 0, size, textcolor, backcolor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(false, 1, true, 0, size, textcolor, backcolor, iNum, fNum, x, y, value);
   }
   inline void Draw_Signed_Float(uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    Draw_Signed_Float(true, true, 0, font, color, bColor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(true, 1, true, 0, font, color, bColor, iNum, fNum, x, y, value);
   }
   inline void Draw_Signed_Float(uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) {
-    Draw_Signed_Float(true, true, 0, size, color, bColor, iNum, fNum, x, y, value);
+    DWIN_Draw_Value(true, 1, true, 0, size, color, bColor, iNum, fNum, x, y, value);
   }
 
   // Draw a char at cursor position
-  void Draw_Char(const char c);
+  void Draw_Char(uint16_t color, const char c);
+  inline void Draw_Char(const char c) { Draw_Char(textcolor, c); }
 
   // Draw a string at cursor position
   //  color: Character color
@@ -425,7 +481,10 @@ namespace DWINUI {
   //  bColor: Background color
   //  y: Upper coordinate of the string
   //  *string: The string
-  void Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t y, const char * const string);
+  void Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x1, uint16_t x2, uint16_t y, const char * const string);
+  inline void Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t y, const char * const string) {
+    Draw_CenteredString(bShow, size, color, bColor, 0, DWIN_WIDTH, y, string);
+  }
   inline void Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t y, FSTR_P string) {
     Draw_CenteredString(bShow, size, color, bColor, y, FTOP(string));
   }
@@ -487,6 +546,17 @@ namespace DWINUI {
   //  color2 : End color
   uint16_t ColorInt(int16_t val, int16_t minv, int16_t maxv, uint16_t color1, uint16_t color2);
 
+  // ------------------------- Buttons ------------------------------//
+
+  void Draw_Button(uint16_t color, uint16_t bcolor, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const char * const caption);
+  inline void Draw_Button(uint16_t color, uint16_t bcolor, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, FSTR_P caption) {
+    Draw_Button(color, bcolor, x1, y1, x2, y2, FTOP(caption));
+  }
+  inline void Draw_Button(FSTR_P caption, uint16_t x, uint16_t y) {
+    Draw_Button(textcolor, buttoncolor, x, y, x + 99, y + 37, caption);
+  }
+  void Draw_Button(uint8_t id, uint16_t x, uint16_t y);
+
   // -------------------------- Extra -------------------------------//
 
   // Draw a circle filled with color
diff --git a/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp b/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp
index f04c079017b..74eb94e751a 100644
--- a/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp
+++ b/Marlin/src/lcd/e3v2/proui/endstop_diag.cpp
@@ -21,15 +21,12 @@
  */
 
 /**
- * DWIN End Stops diagnostic page
+ * DWIN End Stops diagnostic page for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 1.0.2
- * Date: 2021/11/06
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 1.2.2
+ * Date: 2022/02/24
  */
 
-#include "../../../inc/MarlinConfigPre.h"
 #include "dwin_defines.h"
 
 #if BOTH(DWIN_LCD_PROUI, HAS_ESDIAG)
@@ -72,7 +69,7 @@ void ESDiagClass::Draw() {
   Title.ShowCaption(F("End-stops Diagnostic"));
   DWINUI::ClearMenuArea();
   Draw_Popup_Bkgd();
-  DWINUI::Draw_Icon(ICON_Continue_E, 86, 250);
+  DWINUI::Draw_Button(BTN_Continue, 86, 250);
   DWINUI::cursor.y = 80;
   #define ES_LABEL(S) draw_es_label(F(STR_##S))
   #if HAS_X_MIN
diff --git a/Marlin/src/lcd/e3v2/proui/endstop_diag.h b/Marlin/src/lcd/e3v2/proui/endstop_diag.h
index 4694ddb1417..316a1e1ed3d 100644
--- a/Marlin/src/lcd/e3v2/proui/endstop_diag.h
+++ b/Marlin/src/lcd/e3v2/proui/endstop_diag.h
@@ -22,12 +22,10 @@
 #pragma once
 
 /**
- * DWIN End Stops diagnostic page
+ * DWIN End Stops diagnostic page for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 1.0
- * Date: 2021/11/06
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 1.2.3
+ * Date: 2022/02/24
  */
 
 class ESDiagClass {
diff --git a/Marlin/src/lcd/e3v2/proui/lockscreen.cpp b/Marlin/src/lcd/e3v2/proui/lockscreen.cpp
index 2ccdcc12073..2895c01544b 100644
--- a/Marlin/src/lcd/e3v2/proui/lockscreen.cpp
+++ b/Marlin/src/lcd/e3v2/proui/lockscreen.cpp
@@ -21,12 +21,10 @@
  */
 
 /**
- * Lock screen implementation for DWIN UI Enhanced implementation
+ * Lock screen implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
  * Version: 2.1
  * Date: 2021/11/09
- *
- * Based on the original code provided by Creality under GPL
  */
 
 #include "../../../inc/MarlinConfigPre.h"
diff --git a/Marlin/src/lcd/e3v2/proui/lockscreen.h b/Marlin/src/lcd/e3v2/proui/lockscreen.h
index bf2fdb3f4b0..ec967fe2db7 100644
--- a/Marlin/src/lcd/e3v2/proui/lockscreen.h
+++ b/Marlin/src/lcd/e3v2/proui/lockscreen.h
@@ -22,12 +22,10 @@
 #pragma once
 
 /**
- * Lock screen implementation for DWIN UI Enhanced implementation
+ * Lock screen implementation for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
  * Version: 2.1
  * Date: 2021/11/09
- *
- * Based on the original code provided by Creality under GPL
  */
 
 #include "../common/encoder.h"
diff --git a/Marlin/src/lcd/e3v2/proui/menus.cpp b/Marlin/src/lcd/e3v2/proui/menus.cpp
new file mode 100644
index 00000000000..6dfcb8595c8
--- /dev/null
+++ b/Marlin/src/lcd/e3v2/proui/menus.cpp
@@ -0,0 +1,370 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Menu functions for ProUI
+ * Author: Miguel A. Risco-Castillo
+ * Version: 1.2.1
+ * Date: 2022/02/25
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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 Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DWIN_LCD_PROUI)
+
+#include "../common/encoder.h"
+#include "dwin_lcd.h"
+#include "dwinui.h"
+#include "dwin.h"
+#include "menus.h"
+
+MenuData_t MenuData;
+
+// Menuitem Drawing functions =================================================
+
+void Draw_Title(TitleClass* title) {
+  DWIN_Draw_Rectangle(1, HMI_data.TitleBg_color, 0, 0, DWIN_WIDTH - 1, TITLE_HEIGHT - 1);
+  if (title->frameid)
+    DWIN_Frame_AreaCopy(title->frameid, title->frame.left, title->frame.top, title->frame.right, title->frame.bottom, 14, (TITLE_HEIGHT - (title->frame.bottom - title->frame.top)) / 2 - 1);
+  else
+    DWIN_Draw_String(false, DWIN_FONT_HEAD, HMI_data.TitleTxt_color, HMI_data.TitleBg_color, 14, (TITLE_HEIGHT - DWINUI::fontHeight(DWIN_FONT_HEAD)) / 2 - 1, title->caption);
+}
+
+void Draw_Menu(MenuClass* menu) {
+  DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color, HMI_data.StatusBg_Color);
+  DWIN_Draw_Rectangle(1, DWINUI::backcolor, 0, TITLE_HEIGHT, DWIN_WIDTH - 1, STATUS_Y - 1);
+}
+
+void Draw_Menu_Cursor(const int8_t line) {
+  DWIN_Draw_Rectangle(1, HMI_data.Cursor_color, 0, MBASE(line) - 18, 14, MBASE(line + 1) - 20);
+}
+
+void Erase_Menu_Cursor(const int8_t line) {
+  DWIN_Draw_Rectangle(1, HMI_data.Background_Color, 0, MBASE(line) - 18, 14, MBASE(line + 1) - 20);
+}
+
+void Draw_Menu_Line(const uint8_t line, const uint8_t icon /*=0*/, const char * const label /*=nullptr*/, bool more /*=false*/) {
+  if (icon)  DWINUI::Draw_Icon(icon, ICOX, MBASE(line) - 3);
+  if (label) DWINUI::Draw_String(LBLX, MBASE(line) - 1, (char*)label);
+  if (more)  DWINUI::Draw_Icon(ICON_More, VALX + 16, MBASE(line) - 3);
+  DWIN_Draw_HLine(HMI_data.SplitLine_Color, 16, MYPOS(line + 1), 240);
+}
+
+void Draw_Chkb_Line(const uint8_t line, const bool checked) {
+  DWINUI::Draw_Checkbox(HMI_data.Text_Color, HMI_data.Background_Color, VALX + 16, MBASE(line) - 1, checked);
+}
+
+void Draw_Menu_IntValue(uint16_t bcolor, const uint8_t line, uint8_t iNum, const int32_t value /*=0*/) {
+  DWINUI::Draw_Signed_Int(HMI_data.Text_Color, bcolor, iNum , VALX, MBASE(line) - 1, value);
+}
+
+void onDrawMenuItem(MenuItemClass* menuitem, int8_t line) {
+  if (menuitem->icon) DWINUI::Draw_Icon(menuitem->icon, ICOX, MBASE(line) - 3);
+  if (menuitem->frameid)
+    DWIN_Frame_AreaCopy(menuitem->frameid, menuitem->frame.left, menuitem->frame.top, menuitem->frame.right, menuitem->frame.bottom, LBLX, MBASE(line));
+  else if (menuitem->caption)
+    DWINUI::Draw_String(LBLX, MBASE(line) - 1, menuitem->caption);
+  DWIN_Draw_HLine(HMI_data.SplitLine_Color, 16, MYPOS(line + 1), 240);
+}
+
+void onDrawSubMenu(MenuItemClass* menuitem, int8_t line) {
+  onDrawMenuItem(menuitem, line);
+  DWINUI::Draw_Icon(ICON_More, VALX + 16, MBASE(line) - 3);
+}
+
+void onDrawIntMenu(MenuItemClass* menuitem, int8_t line, int32_t value) {
+  onDrawMenuItem(menuitem, line);
+  Draw_Menu_IntValue(HMI_data.Background_Color, line, 4, value);
+}
+
+void onDrawPIntMenu(MenuItemClass* menuitem, int8_t line) {
+  const int16_t value = *(int16_t*)static_cast<MenuItemPtrClass*>(menuitem)->value;
+  onDrawIntMenu(menuitem, line, value);
+}
+
+void onDrawPInt8Menu(MenuItemClass* menuitem, int8_t line) {
+  const uint8_t value = *(uint8_t*)static_cast<MenuItemPtrClass*>(menuitem)->value;
+  onDrawIntMenu(menuitem, line, value);
+}
+
+void onDrawPInt32Menu(MenuItemClass* menuitem, int8_t line) {
+  const uint32_t value = *(uint32_t*)static_cast<MenuItemPtrClass*>(menuitem)->value;
+  onDrawIntMenu(menuitem, line, value);
+}
+
+void onDrawFloatMenu(MenuItemClass* menuitem, int8_t line, uint8_t dp, const float value) {
+  onDrawMenuItem(menuitem, line);
+  DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Background_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(line), value);
+}
+
+void onDrawPFloatMenu(MenuItemClass* menuitem, int8_t line) {
+  const float value = *(float*)static_cast<MenuItemPtrClass*>(menuitem)->value;
+  const int8_t dp = UNITFDIGITS;
+  onDrawFloatMenu(menuitem, line, dp, value);
+}
+
+void onDrawPFloat2Menu(MenuItemClass* menuitem, int8_t line) {
+  const float value = *(float*)static_cast<MenuItemPtrClass*>(menuitem)->value;
+  onDrawFloatMenu(menuitem, line, 2, value);
+}
+
+void onDrawChkbMenu(MenuItemClass* menuitem, int8_t line, bool checked) {
+  onDrawMenuItem(menuitem, line);
+  Draw_Chkb_Line(line, checked);
+}
+
+//-----------------------------------------------------------------------------
+// On click functions
+//-----------------------------------------------------------------------------
+
+// Generic onclick event without draw
+//  process: process id HMI destiny
+//  lo: low limit
+//  hi: high limit
+//  dp: decimal places, 0 for integers
+//  val: value / scaled value
+//  LiveUpdate: live update function when the encoder changes
+//  Apply: update function when the encoder is pressed
+void SetOnClick(uint8_t process, const int32_t lo, const int32_t hi, uint8_t dp, const int32_t val, void (*Apply)() /*= nullptr*/, void (*LiveUpdate)() /*= nullptr*/) {
+  checkkey = process;
+  MenuData.MinValue = lo;
+  MenuData.MaxValue = hi;
+  MenuData.dp = dp;
+  MenuData.Apply = Apply;
+  MenuData.LiveUpdate = LiveUpdate;
+  MenuData.Value = val;
+  EncoderRate.enabled = true;
+}
+
+// Generic onclick event for integer values
+//  process: process id HMI destiny
+//  lo: scaled low limit
+//  hi: scaled high limit
+//  val: value
+//  LiveUpdate: live update function when the encoder changes
+//  Apply: update function when the encoder is pressed
+void SetValueOnClick(uint8_t process, const int32_t lo, const int32_t hi, const int32_t val, void (*Apply)() /*= nullptr*/, void (*LiveUpdate)() /*= nullptr*/) {
+  SetOnClick(process, lo, hi, 0, val, Apply, LiveUpdate);
+  Draw_Menu_IntValue(HMI_data.Selected_Color, CurrentMenu->line(), 4, MenuData.Value);
+}
+
+// Generic onclick event for float values
+//  process: process id HMI destiny
+//  lo: scaled low limit
+//  hi: scaled high limit
+//  val: value
+//  LiveUpdate: live update function when the encoder changes
+//  Apply: update function when the encoder is pressed
+void SetValueOnClick(uint8_t process, const float lo, const float hi, uint8_t dp, const float val, void (*Apply)() /*= nullptr*/, void (*LiveUpdate)() /*= nullptr*/) {
+  const int32_t value =  round(val * POW(10, dp));
+  SetOnClick(process, lo * POW(10, dp), hi * POW(10, dp), dp, value, Apply, LiveUpdate);
+  DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Selected_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(CurrentMenu->line()), val);
+}
+
+// Generic onclick event for integer values
+//  lo: scaled low limit
+//  hi: scaled high limit
+//  val: value
+//  LiveUpdate: live update function when the encoder changes
+//  Apply: update function when the encoder is pressed
+void SetIntOnClick(const int32_t lo, const int32_t hi, const int32_t val, void (*Apply)() /*= nullptr*/, void (*LiveUpdate)() /*= nullptr*/) {
+  SetValueOnClick(SetInt, lo, hi, val, Apply, LiveUpdate);
+}
+
+// Generic onclick event for set pointer to 16 bit uinteger values
+//  lo: low limit
+//  hi: high limit
+//  LiveUpdate: live update function when the encoder changes
+//  Apply: update function when the encoder is pressed
+void SetPIntOnClick(const int32_t lo, const int32_t hi, void (*Apply)() /*= nullptr*/, void (*LiveUpdate)() /*= nullptr*/) {
+  MenuData.P_Int = (int16_t*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
+  const int32_t value = *MenuData.P_Int;
+  SetValueOnClick(SetPInt, lo, hi, value, Apply, LiveUpdate);
+}
+
+// Generic onclick event for float values
+//  process: process id HMI destiny
+//  lo: low limit
+//  hi: high limit
+//  dp: decimal places
+//  val: value
+void SetFloatOnClick(const float lo, const float hi, uint8_t dp, const float val, void (*Apply)() /*= nullptr*/, void (*LiveUpdate)() /*= nullptr*/) {
+  SetValueOnClick(SetFloat, lo, hi, dp, val, Apply, LiveUpdate);
+}
+
+// Generic onclick event for set pointer to float values
+//  lo: low limit
+//  hi: high limit
+//  LiveUpdate: live update function when the encoder changes
+//  Apply: update function when the encoder is pressed
+void SetPFloatOnClick(const float lo, const float hi, uint8_t dp, void (*Apply)() /*= nullptr*/, void (*LiveUpdate)() /*= nullptr*/) {
+  MenuData.P_Float = (float*)static_cast<MenuItemPtrClass*>(CurrentMenu->SelectedItem())->value;
+  SetValueOnClick(SetPFloat, lo, hi, dp, *MenuData.P_Float, Apply, LiveUpdate);
+}
+
+// HMI Control functions ======================================================
+
+// Generic menu control using the encoder
+void HMI_Menu() {
+  EncoderState encoder_diffState = get_encoder_state();
+  if (encoder_diffState == ENCODER_DIFF_NO) return;
+  if (CurrentMenu) {
+    if (encoder_diffState == ENCODER_DIFF_ENTER)
+      CurrentMenu->onClick();
+    else
+      CurrentMenu->onScroll(encoder_diffState == ENCODER_DIFF_CW);
+  }
+}
+
+// Get an integer value using the encoder without draw anything
+//  lo: low limit
+//  hi: high limit
+// Return value:
+//  0 : no change
+//  1 : live change
+//  2 : apply change
+int8_t HMI_GetIntNoDraw(const int32_t lo, const int32_t hi) {
+  EncoderState encoder_diffState = Encoder_ReceiveAnalyze();
+  if (encoder_diffState != ENCODER_DIFF_NO) {
+    if (Apply_Encoder(encoder_diffState, MenuData.Value)) {
+      EncoderRate.enabled = false;
+      checkkey = Menu;
+      return 2;
+    }
+    LIMIT(MenuData.Value, lo, hi);
+    return 1;
+  }
+  return 0;
+}
+
+// Get an integer value using the encoder
+//  lo: low limit
+//  hi: high limit
+// Return value:
+//  0 : no change
+//  1 : live change
+//  2 : apply change
+int8_t HMI_GetInt(const int32_t lo, const int32_t hi) {
+  EncoderState encoder_diffState = Encoder_ReceiveAnalyze();
+  if (encoder_diffState != ENCODER_DIFF_NO) {
+    if (Apply_Encoder(encoder_diffState, MenuData.Value)) {
+      EncoderRate.enabled = false;
+      DWINUI::Draw_Signed_Int(HMI_data.Text_Color, HMI_data.Background_Color, 4 , VALX, MBASE(CurrentMenu->line()) - 1, MenuData.Value);
+      checkkey = Menu;
+      return 2;
+    }
+    LIMIT(MenuData.Value, lo, hi);
+    DWINUI::Draw_Signed_Int(HMI_data.Text_Color, HMI_data.Selected_Color, 4 , VALX, MBASE(CurrentMenu->line()) - 1, MenuData.Value);
+    return 1;
+  }
+  return 0;
+}
+
+// Set an integer using the encoder
+void HMI_SetInt() {
+  int8_t val = HMI_GetInt(MenuData.MinValue, MenuData.MaxValue);
+  switch (val) {
+    case 0: return; break;
+    case 1: if (MenuData.LiveUpdate) MenuData.LiveUpdate(); break;
+    case 2: if (MenuData.Apply) MenuData.Apply(); break;
+  }
+}
+
+// Set an integer without drawing
+void HMI_SetIntNoDraw() {
+  int8_t val = HMI_GetIntNoDraw(MenuData.MinValue, MenuData.MaxValue);
+  switch (val) {
+    case 0: return; break;
+    case 1: if (MenuData.LiveUpdate) MenuData.LiveUpdate(); break;
+    case 2: if (MenuData.Apply) MenuData.Apply(); break;
+  }
+}
+
+// Set an integer pointer variable using the encoder
+void HMI_SetPInt() {
+  int8_t val = HMI_GetInt(MenuData.MinValue, MenuData.MaxValue);
+  switch (val) {
+    case 0: return;
+    case 1: if (MenuData.LiveUpdate) MenuData.LiveUpdate(); break;
+    case 2: *MenuData.P_Int = MenuData.Value; if (MenuData.Apply) MenuData.Apply(); break;
+  }
+}
+
+// Get a scaled float value using the encoder
+//  dp: decimal places
+//  lo: scaled low limit
+//  hi: scaled high limit
+// Return value:
+//  0 : no change
+//  1 : live change
+//  2 : apply change
+int8_t HMI_GetFloat(uint8_t dp, int32_t lo, int32_t hi) {
+  EncoderState encoder_diffState = Encoder_ReceiveAnalyze();
+  if (encoder_diffState != ENCODER_DIFF_NO) {
+    if (Apply_Encoder(encoder_diffState, MenuData.Value)) {
+      EncoderRate.enabled = false;
+      DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Background_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(CurrentMenu->line()), MenuData.Value / POW(10, dp));
+      checkkey = Menu;
+      return 2;
+    }
+    LIMIT(MenuData.Value, lo, hi);
+    DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Selected_Color, 3, dp, VALX - dp * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(CurrentMenu->line()), MenuData.Value / POW(10, dp));
+    return 1;
+  }
+  return 0;
+}
+
+// Set a scaled float using the encoder
+void HMI_SetFloat() {
+  const int8_t val = HMI_GetFloat(MenuData.dp, MenuData.MinValue, MenuData.MaxValue);
+  switch (val) {
+    case 0: return;
+    case 1: if (MenuData.LiveUpdate) MenuData.LiveUpdate(); break;
+    case 2: if (MenuData.Apply) MenuData.Apply(); break;
+  }
+}
+
+// Set a scaled float pointer variable using the encoder
+void HMI_SetPFloat() {
+  const int8_t val = HMI_GetFloat(MenuData.dp, MenuData.MinValue, MenuData.MaxValue);
+  switch (val) {
+    case 0: return;
+    case 1: if (MenuData.LiveUpdate) MenuData.LiveUpdate(); break;
+    case 2: *MenuData.P_Float = MenuData.Value / POW(10, MenuData.dp); if (MenuData.Apply) MenuData.Apply(); break;
+  }
+}
+
+#endif // DWIN_LCD_PROUI
diff --git a/Marlin/src/lcd/e3v2/proui/menus.h b/Marlin/src/lcd/e3v2/proui/menus.h
new file mode 100644
index 00000000000..0147c1616b3
--- /dev/null
+++ b/Marlin/src/lcd/e3v2/proui/menus.h
@@ -0,0 +1,94 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Menu functions for ProUI
+ * Author: Miguel A. Risco-Castillo
+ * Version: 1.2.1
+ * Date: 2022/02/25
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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 Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "dwinui.h"
+
+typedef struct {
+  int32_t MaxValue     = 0;        // Auxiliar max integer/scaled float value
+  int32_t MinValue     = 0;        // Auxiliar min integer/scaled float value
+  int8_t dp            = 0;        // Auxiliar decimal places
+  int32_t Value        = 0;        // Auxiliar integer / scaled float value
+  int16_t *P_Int       = nullptr;  // Auxiliar pointer to 16 bit integer variable
+  float *P_Float       = nullptr;  // Auxiliar pointer to float variable
+  void (*Apply)()      = nullptr;  // Auxiliar apply function
+  void (*LiveUpdate)() = nullptr;  // Auxiliar live update function
+} MenuData_t;
+
+extern MenuData_t MenuData;
+
+// Menuitem Drawing functions =================================================
+void Draw_Title(TitleClass* title);
+void Draw_Menu(MenuClass* menu);
+void Draw_Menu_Cursor(const int8_t line);
+void Erase_Menu_Cursor(const int8_t line);
+void Draw_Menu_Line(const uint8_t line, const uint8_t icon=0, const char * const label=nullptr, bool more=false);
+void Draw_Chkb_Line(const uint8_t line, const bool checked);
+void Draw_Menu_IntValue(uint16_t bcolor, const uint8_t line, uint8_t iNum, const int32_t value=0);
+void onDrawMenuItem(MenuItemClass* menuitem, int8_t line);
+void onDrawSubMenu(MenuItemClass* menuitem, int8_t line);
+void onDrawIntMenu(MenuItemClass* menuitem, int8_t line, int32_t value);
+void onDrawPIntMenu(MenuItemClass* menuitem, int8_t line);
+void onDrawPInt8Menu(MenuItemClass* menuitem, int8_t line);
+void onDrawPInt32Menu(MenuItemClass* menuitem, int8_t line);
+void onDrawFloatMenu(MenuItemClass* menuitem, int8_t line, uint8_t dp, const float value);
+void onDrawPFloatMenu(MenuItemClass* menuitem, int8_t line);
+void onDrawPFloat2Menu(MenuItemClass* menuitem, int8_t line);
+void onDrawChkbMenu(MenuItemClass* menuitem, int8_t line, bool checked);
+
+// On click functions =========================================================
+void SetOnClick(uint8_t process, const int32_t lo, const int32_t hi, uint8_t dp, const int32_t val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr);
+void SetValueOnClick(uint8_t process, const int32_t lo, const int32_t hi, const int32_t val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr);
+void SetValueOnClick(uint8_t process, const float lo, const float hi, uint8_t dp, const float val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr);
+void SetIntOnClick(const int32_t lo, const int32_t hi, const int32_t val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr);
+void SetPIntOnClick(const int32_t lo, const int32_t hi, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr);
+void SetFloatOnClick(const float lo, const float hi, uint8_t dp, const float val, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr);
+void SetPFloatOnClick(const float lo, const float hi, uint8_t dp, void (*Apply)() = nullptr, void (*LiveUpdate)() = nullptr);
+
+// HMI user control functions =================================================
+void HMI_Menu();
+void HMI_SetInt();
+void HMI_SetPInt();
+void HMI_SetIntNoDraw();
+void HMI_SetFloat();
+void HMI_SetPFloat();
diff --git a/Marlin/src/lcd/e3v2/proui/meshviewer.cpp b/Marlin/src/lcd/e3v2/proui/meshviewer.cpp
index 275a29cd385..0b22ae98d5e 100644
--- a/Marlin/src/lcd/e3v2/proui/meshviewer.cpp
+++ b/Marlin/src/lcd/e3v2/proui/meshviewer.cpp
@@ -21,12 +21,10 @@
  */
 
 /**
- * DWIN Mesh Viewer
+ * Mesh Viewer for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.9.1
- * Date: 2021/11/09
- *
- * Based on the original code provided by Creality under GPL
+ * version: 3.12.1
+ * Date: 2022/02/24
  */
 
 #include "../../../inc/MarlinConfigPre.h"
@@ -40,49 +38,53 @@
 #include "dwin_lcd.h"
 #include "dwinui.h"
 #include "dwin.h"
+#include "dwin_popup.h"
 #include "../../../feature/bedlevel/bedlevel.h"
 
 MeshViewerClass MeshViewer;
 
-void MeshViewerClass::Draw() {
+void MeshViewerClass::DrawMesh(bed_mesh_t zval, const uint8_t sizex, const uint8_t sizey) {
   const int8_t mx = 25, my = 25;  // Margins
-  const int16_t stx = (DWIN_WIDTH - 2 * mx) / (GRID_MAX_POINTS_X - 1),  // Steps
-                sty = (DWIN_WIDTH - 2 * my) / (GRID_MAX_POINTS_Y - 1);
+  const int16_t stx = (DWIN_WIDTH - 2 * mx) / (sizex - 1),  // Steps
+                sty = (DWIN_WIDTH - 2 * my) / (sizey - 1);
   const int8_t rmax = _MIN(mx - 2, stx / 2);
   const int8_t rmin = 7;
-  int16_t zmesh[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y], maxz =-32000, minz = 32000;
+  int16_t zmesh[sizex][sizey];
   #define px(xp) (mx + (xp) * stx)
   #define py(yp) (30 + DWIN_WIDTH - my - (yp) * sty)
   #define rm(z) ((z - minz) * (rmax - rmin) / _MAX(1, (maxz - minz)) + rmin)
-  #define DrawMeshValue(xp, yp, zv) DWINUI::Draw_Signed_Float(font6x12, 1, 2, px(xp) - 12, py(yp) - 6, zv)
+  #define DrawMeshValue(xp, yp, zv) DWINUI::Draw_Signed_Float(font6x12, 1, 2, px(xp) - 18, py(yp) - 6, zv)
   #define DrawMeshHLine(yp) DWIN_Draw_HLine(HMI_data.SplitLine_Color, px(0), py(yp), DWIN_WIDTH - 2 * mx)
-  #define DrawMeshVLine(xp) DWIN_Draw_VLine(HMI_data.SplitLine_Color, px(xp), py(GRID_MAX_POINTS_Y - 1), DWIN_WIDTH - 2 * my)
-  GRID_LOOP(x, y) {
-    const float v = isnan(Z_VALUES(x,y)) ? 0 : round(Z_VALUES(x,y) * 100);
+  #define DrawMeshVLine(xp) DWIN_Draw_VLine(HMI_data.SplitLine_Color, px(xp), py(sizey - 1), DWIN_WIDTH - 2 * my)
+  int16_t maxz =-32000; int16_t minz = 32000; avg = 0;
+  LOOP_L_N(y, sizey) LOOP_L_N(x, sizex) {
+    const float v = isnan(zval[x][y]) ? 0 : round(zval[x][y] * 100);
     zmesh[x][y] = v;
+    avg += v;
     NOLESS(maxz, v);
     NOMORE(minz, v);
   }
-  Title.ShowCaption(F("Mesh Viewer"));
+  max = (float)maxz / 100;
+  min = (float)minz / 100;
+  avg = avg / (100 * sizex * sizey);
   DWINUI::ClearMenuArea();
-  DWINUI::Draw_Icon(ICON_Continue_E, 86, 305);
-  DWIN_Draw_Rectangle(0, HMI_data.SplitLine_Color, px(0), py(0), px(GRID_MAX_POINTS_X - 1), py(GRID_MAX_POINTS_Y - 1));
-  LOOP_S_L_N(x, 1, GRID_MAX_POINTS_X - 1) DrawMeshVLine(x);
-  LOOP_S_L_N(y, 1, GRID_MAX_POINTS_Y - 1) DrawMeshHLine(y);
-  LOOP_L_N(y, GRID_MAX_POINTS_Y) {
+  DWIN_Draw_Rectangle(0, HMI_data.SplitLine_Color, px(0), py(0), px(sizex - 1), py(sizey - 1));
+  LOOP_S_L_N(x, 1, sizex - 1) DrawMeshVLine(x);
+  LOOP_S_L_N(y, 1, sizey - 1) DrawMeshHLine(y);
+  LOOP_L_N(y, sizey) {
     watchdog_refresh();
-    LOOP_L_N(x, GRID_MAX_POINTS_X) {
+    LOOP_L_N(x, sizex) {
       uint16_t color = DWINUI::RainbowInt(zmesh[x][y], _MIN(-5, minz), _MAX(5, maxz));
       uint8_t radius = rm(zmesh[x][y]);
       DWINUI::Draw_FillCircle(color, px(x), py(y), radius);
-      if (GRID_MAX_POINTS_X < 9)
-        DWINUI::Draw_Signed_Float(font6x12, 1, 2, px(x) - 12, py(y) - 6, Z_VALUES(x,y));
+      if (sizex < 9)
+        DWINUI::Draw_Signed_Float(font6x12, 1, 2, px(x) - 18, py(y) - 6, zval[x][y]);
       else {
         char str_1[9];
         str_1[0] = 0;
         switch (zmesh[x][y]) {
           case -999 ... -100:
-            DWINUI::Draw_Signed_Float(font6x12, 1, 1, px(x) - 12, py(y) - 6, Z_VALUES(x,y));
+            DWINUI::Draw_Signed_Float(font6x12, 1, 1, px(x) - 18, py(y) - 6, zval[x][y]);
             break;
           case -99 ... -1:
             sprintf_P(str_1, PSTR("-.%02i"), -zmesh[x][y]);
@@ -94,7 +96,7 @@ void MeshViewerClass::Draw() {
             sprintf_P(str_1, PSTR(".%02i"), zmesh[x][y]);
             break;
           case 100 ... 999:
-            DWINUI::Draw_Signed_Float(font6x12, 1, 1, px(x) - 12, py(y) - 6, Z_VALUES(x,y));
+            DWINUI::Draw_Signed_Float(font6x12, 1, 1, px(x) - 18, py(y) - 6, zval[x][y]);
             break;
         }
         if (str_1[0])
@@ -102,11 +104,25 @@ void MeshViewerClass::Draw() {
       }
     }
   }
+}
+
+void MeshViewerClass::Draw(bool withsave /*= false*/) {
+  Title.ShowCaption(F("Mesh Viewer"));
+  DrawMesh(Z_VALUES_ARR, GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y);
+  if (withsave) {
+    DWINUI::Draw_Button(BTN_Save, 26, 305);
+    DWINUI::Draw_Button(BTN_Continue, 146, 305);
+    Draw_Select_Highlight(HMI_flag.select_flag, 305);
+  } else DWINUI::Draw_Button(BTN_Continue, 86, 305);
   char str_1[6], str_2[6] = "";
   ui.status_printf(0, F("Mesh minZ: %s, maxZ: %s"),
-    dtostrf((float)minz / 100, 1, 2, str_1),
-    dtostrf((float)maxz / 100, 1, 2, str_2)
+    dtostrf(min, 1, 2, str_1),
+    dtostrf(max, 1, 2, str_2)
   );
 }
 
+void Draw_MeshViewer() { MeshViewer.Draw(true); }
+void onClick_MeshViewer() { if (HMI_flag.select_flag) WriteEeprom(); HMI_ReturnScreen(); }
+void Goto_MeshViewer() { if (leveling_is_valid()) Goto_Popup(Draw_MeshViewer, onClick_MeshViewer);  else HMI_ReturnScreen(); }
+
 #endif // DWIN_LCD_PROUI && HAS_MESH
diff --git a/Marlin/src/lcd/e3v2/proui/meshviewer.h b/Marlin/src/lcd/e3v2/proui/meshviewer.h
index acd5f0d5c46..f914bab4ae2 100644
--- a/Marlin/src/lcd/e3v2/proui/meshviewer.h
+++ b/Marlin/src/lcd/e3v2/proui/meshviewer.h
@@ -21,18 +21,23 @@
  */
 #pragma once
 
+#include "../../../core/types.h"
+#include "../../../feature/bedlevel/bedlevel.h"
+
 /**
- * DWIN Mesh Viewer
+ * Mesh Viewer for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 3.9.1
- * Date: 2021/11/09
- *
- * Based on the original code provided by Creality under GPL
+ * version: 3.12.1
+ * Date: 2022/02/24
  */
 
 class MeshViewerClass {
 public:
-  void Draw();
+  float avg, max, min;
+  void Draw(bool withsave = false);
+  void DrawMesh(bed_mesh_t zval, const uint8_t sizex, const uint8_t sizey);
 };
 
 extern MeshViewerClass MeshViewer;
+
+void Goto_MeshViewer();
diff --git a/Marlin/src/lcd/e3v2/proui/printstats.cpp b/Marlin/src/lcd/e3v2/proui/printstats.cpp
index 54c87f4be10..d4ca4ca2255 100644
--- a/Marlin/src/lcd/e3v2/proui/printstats.cpp
+++ b/Marlin/src/lcd/e3v2/proui/printstats.cpp
@@ -21,12 +21,10 @@
  */
 
 /**
- * DWIN Print Stats page
+ * Print Stats page for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 1.1
- * Date: 2022/01/09
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 1.3.0
+ * Date: 2022/02/24
  */
 
 #include "../../../inc/MarlinConfigPre.h"
@@ -36,6 +34,7 @@
 #include "printstats.h"
 
 #include "../../../core/types.h"
+#include "../../../MarlinCore.h"
 #include "../../marlinui.h"
 #include "../../../module/printcounter.h"
 #include "dwin_lcd.h"
@@ -53,7 +52,7 @@ void PrintStatsClass::Draw() {
   Title.ShowCaption(GET_TEXT_F(MSG_INFO_STATS_MENU));
   DWINUI::ClearMenuArea();
   Draw_Popup_Bkgd();
-  DWINUI::Draw_Icon(ICON_Continue_E, 86, 250);
+  DWINUI::Draw_Button(BTN_Continue, 86, 250);
   printStatistics ps = print_job_timer.getStats();
 
   sprintf_P(buf, PSTR(S_FMT ": %i"), GET_TEXT(MSG_INFO_PRINT_COUNT), ps.totalPrints);
@@ -75,4 +74,9 @@ void PrintStatsClass::Reset() {
   HMI_AudioFeedback();
 }
 
+void Goto_PrintStats() {
+  PrintStats.Draw();
+  HMI_SaveProcessID(WaitResponse);
+}
+
 #endif // DWIN_LCD_PROUI && PRINTCOUNTER
diff --git a/Marlin/src/lcd/e3v2/proui/printstats.h b/Marlin/src/lcd/e3v2/proui/printstats.h
index f17e4dc9dd6..705c923da41 100644
--- a/Marlin/src/lcd/e3v2/proui/printstats.h
+++ b/Marlin/src/lcd/e3v2/proui/printstats.h
@@ -22,18 +22,18 @@
 #pragma once
 
 /**
- * DWIN Print Stats page
+ * Print Stats page for PRO UI
  * Author: Miguel A. Risco-Castillo (MRISCOC)
- * Version: 1.1
- * Date: 2022/01/09
- *
- * Based on the original code provided by Creality under GPL
+ * Version: 1.3.0
+ * Date: 2022/02/24
  */
 
 class PrintStatsClass {
 public:
-  void Draw();
+  static void Draw();
   static void Reset();
 };
 
 extern PrintStatsClass PrintStats;
+
+void Goto_PrintStats();
diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h
index 9925f225e38..7fe5c222715 100644
--- a/Marlin/src/lcd/language/language_en.h
+++ b/Marlin/src/lcd/language/language_en.h
@@ -151,6 +151,7 @@ namespace Language_en {
   LSTR MSG_BED_LEVELING                   = _UxGT("Bed Leveling");
   LSTR MSG_LEVEL_BED                      = _UxGT("Level Bed");
   LSTR MSG_BED_TRAMMING                   = _UxGT("Bed Tramming");
+  LSTR MSG_BED_TRAMMING_MANUAL            = _UxGT("Manual Tramming");
   LSTR MSG_BED_TRAMMING_RAISE             = _UxGT("Adjust bed until the probe triggers.");
   LSTR MSG_BED_TRAMMING_IN_RANGE          = _UxGT("Corners within tolerance. Bed trammed.");
   LSTR MSG_BED_TRAMMING_GOOD_POINTS       = _UxGT("Good Points: ");
@@ -402,7 +403,7 @@ namespace Language_en {
   LSTR MSG_ADVANCE_K_E                    = _UxGT("Advance K *");
   LSTR MSG_CONTRAST                       = _UxGT("LCD Contrast");
   LSTR MSG_BRIGHTNESS                     = _UxGT("LCD Brightness");
-  LSTR MSG_LCD_BKL_TIMEOUT                = _UxGT("LCD Sleep (s)");
+  LSTR MSG_BRIGHTNESS_OFF                 = _UxGT("Turn Off LCD");
   LSTR MSG_STORE_EEPROM                   = _UxGT("Store Settings");
   LSTR MSG_LOAD_EEPROM                    = _UxGT("Load Settings");
   LSTR MSG_RESTORE_DEFAULTS               = _UxGT("Restore Defaults");
@@ -429,6 +430,8 @@ namespace Language_en {
   LSTR MSG_BUTTON_RESET                   = _UxGT("Reset");
   LSTR MSG_BUTTON_IGNORE                  = _UxGT("Ignore");
   LSTR MSG_BUTTON_CANCEL                  = _UxGT("Cancel");
+  LSTR MSG_BUTTON_CONFIRM                 = _UxGT("Confirm");
+  LSTR MSG_BUTTON_CONTINUE                = _UxGT("Continue");
   LSTR MSG_BUTTON_DONE                    = _UxGT("Done");
   LSTR MSG_BUTTON_BACK                    = _UxGT("Back");
   LSTR MSG_BUTTON_PROCEED                 = _UxGT("Proceed");
@@ -438,6 +441,7 @@ namespace Language_en {
   LSTR MSG_BUTTON_PAUSE                   = _UxGT("Pause");
   LSTR MSG_BUTTON_RESUME                  = _UxGT("Resume");
   LSTR MSG_BUTTON_ADVANCED                = _UxGT("Advanced");
+  LSTR MSG_BUTTON_SAVE                    = _UxGT("Save");
   LSTR MSG_PAUSING                        = _UxGT("Pausing...");
   LSTR MSG_PAUSE_PRINT                    = _UxGT("Pause Print");
   LSTR MSG_ADVANCED_PAUSE                 = _UxGT("Advanced Pause");
diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp
index 810d0db5278..f0677afd2d1 100644
--- a/Marlin/src/lcd/marlinui.cpp
+++ b/Marlin/src/lcd/marlinui.cpp
@@ -48,7 +48,6 @@ MarlinUI ui;
 #if ENABLED(DWIN_CREALITY_LCD)
   #include "e3v2/creality/dwin.h"
 #elif ENABLED(DWIN_LCD_PROUI)
-  #include "fontutils.h"
   #include "e3v2/proui/dwin.h"
 #elif ENABLED(DWIN_CREALITY_LCD_JYERSUI)
   #include "e3v2/jyersui/dwin.h"
@@ -1441,8 +1440,10 @@ void MarlinUI::init() {
       else if (print_job_timer.needsService(3)) msg = FPSTR(service3);
     #endif
 
-    else if (!no_welcome)
-      msg = GET_TEXT_F(WELCOME_MSG);
+    else if (!no_welcome) msg = GET_TEXT_F(WELCOME_MSG);
+
+    else if (ENABLED(DWIN_LCD_PROUI))
+        msg = F("");
     else
       return;
 
diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h
index 36cbb14c5cc..83eb332105d 100644
--- a/Marlin/src/lcd/marlinui.h
+++ b/Marlin/src/lcd/marlinui.h
@@ -367,15 +367,6 @@ public:
   static void set_status(FSTR_P const fstr, const int8_t level=0);
   static void status_printf(const uint8_t level, FSTR_P const fmt, ...);
 
-  #if EITHER(HAS_DISPLAY, DWIN_LCD_PROUI)
-    static void kill_screen(FSTR_P const lcd_error, FSTR_P const lcd_component);
-    #if DISABLED(LIGHTWEIGHT_UI)
-      static void draw_status_message(const bool blink);
-    #endif
-  #else
-    static void kill_screen(FSTR_P const, FSTR_P const) {}
-  #endif
-
   #if HAS_DISPLAY
 
     static void update();
@@ -489,11 +480,16 @@ public:
     #endif
 
     static void draw_kill_screen();
+    static void kill_screen(FSTR_P const lcd_error, FSTR_P const lcd_component);
+    #if DISABLED(LIGHTWEIGHT_UI)
+      static void draw_status_message(const bool blink);
+    #endif
 
   #else // No LCD
 
     static void update() {}
     static void return_to_status() {}
+    static void kill_screen(FSTR_P const, FSTR_P const) {}
 
   #endif
 
diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp
index e0b2eccbbd3..2b2e3355652 100644
--- a/Marlin/src/module/settings.cpp
+++ b/Marlin/src/module/settings.cpp
@@ -1467,16 +1467,18 @@ void MarlinSettings::postprocess() {
     //
     #if ENABLED(DWIN_LCD_PROUI)
     {
+      _FIELD_TEST(dwin_data);
       char dwin_data[eeprom_data_size] = { 0 };
       DWIN_StoreSettings(dwin_data);
-      _FIELD_TEST(dwin_data);
       EEPROM_WRITE(dwin_data);
     }
-    #elif ENABLED(DWIN_CREALITY_LCD_JYERSUI)
+    #endif
+
+    #if ENABLED(DWIN_CREALITY_LCD_JYERSUI)
     {
+      _FIELD_TEST(dwin_settings);
       char dwin_settings[CrealityDWIN.eeprom_data_size] = { 0 };
       CrealityDWIN.Save_Settings(dwin_settings);
-      _FIELD_TEST(dwin_settings);
       EEPROM_WRITE(dwin_settings);
     }
     #endif
diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp
index a96ed3a6512..f83104fe9c4 100644
--- a/Marlin/src/module/stepper.cpp
+++ b/Marlin/src/module/stepper.cpp
@@ -497,6 +497,9 @@ void Stepper::enable_axis(const AxisEnum axis) {
 
 bool Stepper::disable_axis(const AxisEnum axis) {
   mark_axis_disabled(axis);
+
+  TERN_(DWIN_LCD_PROUI, set_axis_untrusted(axis)); // MRISCOC workaround: https://github.com/MarlinFirmware/Marlin/issues/23095
+
   // If all the axes that share the enabled bit are disabled
   const bool can_disable = can_axis_disable(axis);
   if (can_disable) {
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index 4adf9689198..653b3179b0c 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -821,7 +821,7 @@ volatile bool Temperature::raw_temps_ready = false;
       hal.idletask();
 
       // Run UI update
-      TERN(HAS_DWIN_E3V2_BASIC, DWIN_Update(), ui.update());
+      TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update());
     }
     wait_for_heatup = false;
 
diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h
index 92d65babfa7..5b48d7cadbc 100644
--- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h
+++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h
@@ -235,7 +235,7 @@
       #define TFTGLCD_CS                    PA9
 
     #endif
-  
+
   #elif ENABLED(FYSETC_MINI_12864_2_1)
 
     #error "CAUTION! FYSETC_MINI_12864_2_1 / MKS_MINI_12864_V3 / BTT_MINI_12864_V1 requires wiring modifications. See 'pins_BTT_SKR_MINI_E3_common.h' for details. Comment out this line to continue."
diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h
index 8616a8fb340..fb7198e57c2 100644
--- a/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h
+++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V24S1_301.h
@@ -28,7 +28,11 @@
 #include "env_validate.h"
 
 #if HAS_MULTI_HOTEND || E_STEPPERS > 1
-  #error "Creality V4 only supports one hotend / E-stepper. Comment out this line to continue."
+  #error "Creality V24S1 only supports one hotend / E-stepper. Comment out this line to continue."
+#endif
+
+#if BOTH(BLTOUCH, Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
+  #error "Disable Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN when using BLTOUCH with Creality V24S1-301."
 #endif
 
 #define BOARD_INFO_NAME      "Creality V24S1-301"
@@ -44,7 +48,7 @@
 //
 // Limit Switches
 //
-#define Z_STOP_PIN                          PC14
+#define Z_STOP_PIN                          PA15
 
 #ifndef Z_MIN_PROBE_PIN
   #define Z_MIN_PROBE_PIN                   PC14  // BLTouch IN
@@ -63,4 +67,22 @@
 #define HEATER_BED_PIN                      PA7   // HOT BED
 #define FAN1_PIN                            PC0   // extruder fan
 
+//
+// SD Card
+//
+#define ONBOARD_SPI_DEVICE                  1
+#define ONBOARD_SD_CS_PIN                   PA4  // SDSS
+
+//
+// M3/M4/M5 - Spindle/Laser Control
+//
+#if HAS_CUTTER
+  //#define HEATER_0_PIN                    -1
+  //#define HEATER_BED_PIN                  -1
+  #define FAN_PIN                           -1
+  #define SPINDLE_LASER_ENA_PIN             PA0  // FET 1
+  #define SPINDLE_LASER_PWM_PIN             PA0  // Bed FET
+  #define SPINDLE_DIR_PIN                   PA0  // FET 4
+#endif
+
 #include "pins_CREALITY_V4.h"
diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp
index 41ec44d4b7b..724de8f82a2 100644
--- a/Marlin/src/sd/cardreader.cpp
+++ b/Marlin/src/sd/cardreader.cpp
@@ -195,7 +195,7 @@ char *createFilename(char * const buffer, const dir_t &p) {
 }
 
 //
-// Return 'true' if the item is something Marlin can read
+// Return 'true' if the item is a folder, G-code file or Binary file
 //
 bool CardReader::is_visible_entity(const dir_t &p OPTARG(CUSTOM_FIRMWARE_UPLOAD, bool onlyBin/*=false*/)) {
   //uint8_t pn0 = p.name[0];
@@ -212,14 +212,15 @@ bool CardReader::is_visible_entity(const dir_t &p OPTARG(CUSTOM_FIRMWARE_UPLOAD,
   ) return false;
 
   flag.filenameIsDir = DIR_IS_SUBDIR(&p);               // We know it's a File or Folder
+  setBinFlag(p.name[8] == 'B' &&                        // List .bin files (a firmware file for flashing)
+             p.name[9] == 'I' &&
+             p.name[10]== 'N');
 
   return (
     flag.filenameIsDir                                  // All Directories are ok
+    || fileIsBinary()                                   // BIN files are accepted
     || (!onlyBin && p.name[8] == 'G'
                  && p.name[9] != '~')                   // Non-backup *.G* files are accepted
-    || ( onlyBin && p.name[8]  == 'B'
-                 && p.name[9]  == 'I'
-                 && p.name[10] == 'N')                  // BIN files are accepted
   );
 }
 
@@ -867,6 +868,7 @@ void CardReader::selectFileByIndex(const uint16_t nr) {
       strcpy(filename, sortshort[nr]);
       strcpy(longFilename, sortnames[nr]);
       flag.filenameIsDir = IS_DIR(nr);
+      setBinFlag(strcmp_P(strrchr(filename, '.'), PSTR(".BIN")) == 0);
       return;
     }
   #endif
@@ -884,6 +886,7 @@ void CardReader::selectFileByName(const char * const match) {
         strcpy(filename, sortshort[nr]);
         strcpy(longFilename, sortnames[nr]);
         flag.filenameIsDir = IS_DIR(nr);
+        setBinFlag(strcmp_P(strrchr(filename, '.'), PSTR(".BIN")) == 0);
         return;
       }
   #endif
diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h
index 2b3dcd00fbf..483ab813958 100644
--- a/Marlin/src/sd/cardreader.h
+++ b/Marlin/src/sd/cardreader.h
@@ -80,6 +80,9 @@ typedef struct {
        filenameIsDir:1,
        workDirIsRoot:1,
        abort_sd_printing:1
+       #if DO_LIST_BIN_FILES
+         , filenameIsBin:1
+       #endif
        #if ENABLED(BINARY_FILE_TRANSFER)
          , binary_mode:1
        #endif
@@ -218,6 +221,10 @@ public:
     static void removeJobRecoveryFile();
   #endif
 
+  // Binary flag for the current file
+  static bool fileIsBinary() { return TERN0(DO_LIST_BIN_FILES, flag.filenameIsBin); }
+  static void setBinFlag(const bool bin) { TERN(DO_LIST_BIN_FILES, flag.filenameIsBin = bin, UNUSED(bin)); }
+
   // Current Working Dir - Set by cd, cdup, cdroot, and diveToFile(true, ...)
   static char* getWorkDirName()  { workDir.getDosName(filename); return filename; }
   static SdFile& getWorkDir()    { return workDir.isOpen() ? workDir : root; }
diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality
index 6a15ec12217..6440c567922 100755
--- a/buildroot/tests/STM32F103RE_creality
+++ b/buildroot/tests/STM32F103RE_creality
@@ -15,8 +15,9 @@ exec_test $1 $2 "Ender 3 v2 with CrealityUI" "$3"
 
 use_example_configs "Creality/Ender-3 V2/CrealityV422/CrealityUI"
 opt_disable DWIN_CREALITY_LCD
-opt_enable DWIN_LCD_PROUI BLTOUCH AUTO_BED_LEVELING_UBL Z_SAFE_HOMING INDIVIDUAL_AXIS_HOMING_SUBMENU LCD_SET_PROGRESS_MANUALLY STATUS_MESSAGE_SCROLLING BAUD_RATE_GCODE
-exec_test $1 $2 "Ender 3 v2 with Pro UI" "$3"
+opt_enable BLTOUCH AUTO_BED_LEVELING_UBL Z_SAFE_HOMING INDIVIDUAL_AXIS_HOMING_SUBMENU LCD_SET_PROGRESS_MANUALLY STATUS_MESSAGE_SCROLLING BAUD_RATE_GCODE \
+           DWIN_LCD_PROUI SOUND_MENU_ITEM PRINTCOUNTER
+exec_test $1 $2 "Ender 3 v2 with ProUI" "$3"
 
 use_example_configs "Creality/Ender-3 V2/CrealityV422/CrealityUI"
 opt_disable DWIN_CREALITY_LCD