diff --git a/Marlin/src/HAL/HAL_STM32_F4_F7/watchdog.cpp b/Marlin/src/HAL/HAL_STM32_F4_F7/watchdog.cpp
index e51af618c..900d1ef6a 100644
--- a/Marlin/src/HAL/HAL_STM32_F4_F7/watchdog.cpp
+++ b/Marlin/src/HAL/HAL_STM32_F4_F7/watchdog.cpp
@@ -38,7 +38,7 @@
       //Error_Handler();
     }
     else {
-      #if PIN_EXISTS(LED) && !ENABLED(PINS_DEBUGGING)
+      #if PIN_EXISTS(LED) && DISABLED(PINS_DEBUGGING)
         TOGGLE(LED_PIN);  // heartbeat indicator
       #endif
     }
diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h
index 567b35c8b..72578faaa 100644
--- a/Marlin/src/core/types.h
+++ b/Marlin/src/core/types.h
@@ -26,6 +26,9 @@
 
 #include "millis_t.h"
 
+class __FlashStringHelper;
+typedef const __FlashStringHelper *progmem_str;
+
 //
 // Enumerated axis indices
 //
diff --git a/Marlin/src/inc/MarlinConfigPre.h b/Marlin/src/inc/MarlinConfigPre.h
index 19427c4c1..e11f171c6 100644
--- a/Marlin/src/inc/MarlinConfigPre.h
+++ b/Marlin/src/inc/MarlinConfigPre.h
@@ -36,7 +36,6 @@
 #include "../core/macros.h"
 #include "../../Configuration.h"
 
-
 #ifdef CUSTOM_VERSION_FILE
   #if defined(__has_include)
     #if __has_include(XSTR(../../CUSTOM_VERSION_FILE))
diff --git a/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp b/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
index 92ef0c83c..8103efe2c 100644
--- a/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
+++ b/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
@@ -991,7 +991,8 @@ void MarlinUI::draw_status_screen() {
 
   #endif // ADVANCED_PAUSE_FEATURE
 
-  void draw_menu_item_static(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const valstr/*=nullptr*/) {
+  // Draw a static item with no left-right margin required. Centered by default.
+  void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const valstr/*=nullptr*/) {
     int8_t n = LCD_WIDTH;
     lcd_moveto(0, row);
     if ((style & SS_CENTER) && !valstr) {
@@ -1003,7 +1004,8 @@ void MarlinUI::draw_status_screen() {
     for (; n > 0; --n) lcd_put_wchar(' ');
   }
 
-  void draw_menu_item(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) {
+  // Draw a generic menu item with pre_char (if selected) and post_char
+  void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char) {
     uint8_t n = LCD_WIDTH - 2;
     lcd_put_wchar(0, row, sel ? pre_char : ' ');
     n -= lcd_put_u8str_max_P(pstr, n);
@@ -1011,16 +1013,18 @@ void MarlinUI::draw_status_screen() {
     lcd_put_wchar(post_char);
   }
 
-  void _draw_menu_item_edit(const bool sel, const uint8_t row, PGM_P pstr, const char* const data, const bool pgm) {
-    uint8_t n = LCD_WIDTH - 2 - (pgm ? utf8_strlen_P(data) : utf8_strlen(data));
+  // Draw an edit menu item with label and value string
+  void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P pstr, const char* const data, const bool pgm) {
+    int8_t n = LCD_WIDTH - 2 - (pgm ? utf8_strlen_P(data) : utf8_strlen(data));
     lcd_put_wchar(0, row, sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
     n -= lcd_put_u8str_max_P(pstr, n);
     lcd_put_wchar(':');
-    for (; n; --n) lcd_put_wchar(' ');
+    for (; n > 0; --n) lcd_put_wchar(' ');
     if (pgm) lcd_put_u8str_P(data); else lcd_put_u8str(data);
   }
 
-  void draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
+  // Draw the edit screen for an editable menu item
+  void MenuEditItemBase::edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
     ui.encoder_direction_normal();
 
     lcd_put_u8str_P(0, 1, pstr);
@@ -1033,7 +1037,8 @@ void MarlinUI::draw_status_screen() {
     }
   }
 
-  void draw_select_screen(PGM_P const yes, PGM_P const no, const bool yesno, PGM_P const pref, const char * const string, PGM_P const suff) {
+  // The Select Screen presents a prompt and two "buttons"
+  void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const bool yesno, PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/) {
     ui.draw_select_screen_prompt(pref, string, suff);
     SETCURSOR(0, LCD_HEIGHT - 1);
     lcd_put_wchar(yesno ? ' ' : '['); lcd_put_u8str_P(no); lcd_put_wchar(yesno ? ' ' : ']');
@@ -1043,9 +1048,7 @@ void MarlinUI::draw_status_screen() {
 
   #if ENABLED(SDSUPPORT)
 
-    void draw_sd_menu_item(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) {
-      UNUSED(pstr);
-
+    void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
       lcd_put_wchar(0, row, sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
       constexpr uint8_t maxlen = LCD_WIDTH - 2;
       uint8_t n = maxlen - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), maxlen);
@@ -1053,7 +1056,7 @@ void MarlinUI::draw_status_screen() {
       lcd_put_wchar(isDir ? LCD_STR_FOLDER[0] : ' ');
     }
 
-  #endif // SDSUPPORT
+  #endif
 
   #if ENABLED(LCD_HAS_STATUS_INDICATORS)
 
diff --git a/Marlin/src/lcd/dogm/ultralcd_DOGM.cpp b/Marlin/src/lcd/dogm/ultralcd_DOGM.cpp
index fa9433829..375783af6 100644
--- a/Marlin/src/lcd/dogm/ultralcd_DOGM.cpp
+++ b/Marlin/src/lcd/dogm/ultralcd_DOGM.cpp
@@ -363,7 +363,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
   }
 
   // Draw a static line of text in the same idiom as a menu item
-  void draw_menu_item_static(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const valstr/*=nullptr*/) {
+  void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const valstr/*=nullptr*/) {
 
     if (mark_as_selected(row, style & SS_INVERT)) {
 
@@ -380,9 +380,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
   }
 
   // Draw a generic menu item
-  void draw_menu_item(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char) {
-    UNUSED(pre_char);
-
+  void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char, const char post_char) {
     if (mark_as_selected(row, sel)) {
       u8g_uint_t n = (LCD_WIDTH - 2) * (MENU_FONT_WIDTH);
       n -= lcd_put_u8str_max_P(pstr, n);
@@ -393,7 +391,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
   }
 
   // Draw a menu item with an editable value
-  void _draw_menu_item_edit(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
+  void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
     if (mark_as_selected(row, sel)) {
       const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen((char*)data));
       u8g_uint_t n = (LCD_WIDTH - 2 - vallen) * (MENU_FONT_WIDTH);
@@ -405,7 +403,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
     }
   }
 
-  void draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
+  void MenuEditItemBase::edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
     ui.encoder_direction_normal();
 
     const u8g_uint_t labellen = utf8_strlen_P(pstr), vallen = utf8_strlen(value);
@@ -466,7 +464,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
     if (inv) u8g.setColorIndex(1);
   }
 
-  void draw_select_screen(PGM_P const yes, PGM_P const no, const bool yesno, PGM_P const pref, const char * const string, PGM_P const suff) {
+  void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const bool yesno, PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/) {
     ui.draw_select_screen_prompt(pref, string, suff);
     draw_boxed_string(1, LCD_HEIGHT - 1, no, !yesno);
     draw_boxed_string(LCD_WIDTH - (utf8_strlen_P(yes) + 1), LCD_HEIGHT - 1, yes, yesno);
@@ -474,9 +472,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
 
   #if ENABLED(SDSUPPORT)
 
-    void draw_sd_menu_item(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) {
-      UNUSED(pstr);
-
+    void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
       if (mark_as_selected(row, sel)) {
         if (isDir) lcd_put_wchar(LCD_STR_FOLDER[0]);
         constexpr uint8_t maxlen = LCD_WIDTH - 1;
diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h
index ebb8186e7..41db956e0 100644
--- a/Marlin/src/lcd/language/language_cz.h
+++ b/Marlin/src/lcd/language/language_cz.h
@@ -137,9 +137,9 @@ namespace Language_cz {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplikace");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Zrcadlení");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Plná kontrola");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2. tryska X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2. tryska Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2. tryska Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2. tryska X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2. tryska Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2. tryska Z");
 
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("Provádím G29");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("UBL nástroje");
diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h
index 9fa894bb9..49553a4fc 100644
--- a/Marlin/src/lcd/language/language_de.h
+++ b/Marlin/src/lcd/language/language_de.h
@@ -137,9 +137,9 @@ namespace Language_de {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplizieren");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Spiegelkopie");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("vollstä. Kontrolle");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2. Düse X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2. Düse Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2. Düse Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2. Düse X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2. Düse Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2. Düse Z");
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("G29 ausführen");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("UBL-Werkzeuge");
   PROGMEM Language_Str MSG_UBL_LEVEL_BED                   = _UxGT("Unified Bed Leveling");
diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h
index 837290c38..e40f394fb 100644
--- a/Marlin/src/lcd/language/language_en.h
+++ b/Marlin/src/lcd/language/language_en.h
@@ -150,9 +150,9 @@ namespace Language_en {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplication");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Mirrored Copy");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Full Control");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2nd Nozzle X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2nd Nozzle Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2nd Nozzle Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2nd Nozzle X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2nd Nozzle Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2nd Nozzle Z");
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("Doing G29");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("UBL Tools");
   PROGMEM Language_Str MSG_UBL_LEVEL_BED                   = _UxGT("Unified Bed Leveling");
diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h
index 9c33add94..7327744e3 100644
--- a/Marlin/src/lcd/language/language_es.h
+++ b/Marlin/src/lcd/language/language_es.h
@@ -142,9 +142,9 @@ namespace Language_es {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplicar");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Copia Reflejada");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Control Total");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2ª Boquilla X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2ª Boquilla Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2ª Boquilla Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2ª Boquilla X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2ª Boquilla Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2ª Boquilla Z");
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("Hacer G29");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("Herramientas UBL");
   PROGMEM Language_Str MSG_UBL_LEVEL_BED                   = _UxGT("Nivel.Cama.Uni.(UBL)");
diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h
index 34fc7becd..3d43db069 100644
--- a/Marlin/src/lcd/language/language_fr.h
+++ b/Marlin/src/lcd/language/language_fr.h
@@ -138,9 +138,9 @@ namespace Language_fr {
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Copie miroir");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Contrôle complet");
   PROGMEM Language_Str MSG_OFFSETS_MENU                    = _UxGT("Offsets Outil");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("Buse 2 X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("Buse 2 Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("Buse 2 Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("Buse 2 X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("Buse 2 Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("Buse 2 Z");
   PROGMEM Language_Str MSG_G26_HEATING_BED                 = _UxGT("G26 Chauffe lit");
   PROGMEM Language_Str MSG_G26_HEATING_NOZZLE              = _UxGT("G26 Chauffe buse");
   PROGMEM Language_Str MSG_G26_MANUAL_PRIME                = _UxGT("Amorce manuelle...");
diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h
index ff3c5f4ea..5d94ab85a 100644
--- a/Marlin/src/lcd/language/language_it.h
+++ b/Marlin/src/lcd/language/language_it.h
@@ -143,9 +143,9 @@ namespace Language_it {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplicazione");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Copia speculare");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Pieno controllo");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2° ugello X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2° ugello Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2° ugello Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2° ugello X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2° ugello Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2° ugello Z");
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("G29 in corso");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("Strumenti UBL");
   PROGMEM Language_Str MSG_UBL_LEVEL_BED                   = _UxGT("Unified Bed Leveling");
diff --git a/Marlin/src/lcd/language/language_pl.h b/Marlin/src/lcd/language/language_pl.h
index ab5461536..cd25c2761 100644
--- a/Marlin/src/lcd/language/language_pl.h
+++ b/Marlin/src/lcd/language/language_pl.h
@@ -142,9 +142,9 @@ namespace Language_pl {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplikowanie");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Kopia lustrzana");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Pełne sterowanie");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2ga dysza X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2ga dysza Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2ga dysza Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2ga dysza X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2ga dysza Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2ga dysza Z");
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("Wykonywanie G29");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("Narzędzia UBL");
   PROGMEM Language_Str MSG_UBL_LEVEL_BED                   = _UxGT("Unified Bed Leveling");
diff --git a/Marlin/src/lcd/language/language_pt_br.h b/Marlin/src/lcd/language/language_pt_br.h
index 548ba4cd9..ba82a3627 100644
--- a/Marlin/src/lcd/language/language_pt_br.h
+++ b/Marlin/src/lcd/language/language_pt_br.h
@@ -119,9 +119,9 @@ namespace Language_pt_br {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplicação");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Cópia espelhada");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Controle Total");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2o bico X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2o bico Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2o bico Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2o bico X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2o bico Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2o bico Z");
 
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("Executando G29");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("Ferramentas UBL");
diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h
index f19b33dd0..ecb932f85 100644
--- a/Marlin/src/lcd/language/language_ru.h
+++ b/Marlin/src/lcd/language/language_ru.h
@@ -117,9 +117,9 @@ namespace Language_ru {
   // TODO: IDEX Menu
   PROGMEM Language_Str MSG_OFFSETS_MENU                    = _UxGT("Размещение сопел");
 
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2-е сопло X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2-е сопло Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2-е сопло Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2-е сопло X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2-е сопло Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2-е сопло Z");
 
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("Выполняем G29");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("Утилиты UBL");
diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h
index 176834a81..60cec3d3f 100644
--- a/Marlin/src/lcd/language/language_sk.h
+++ b/Marlin/src/lcd/language/language_sk.h
@@ -145,9 +145,9 @@ namespace Language_sk {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Duplikácia");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Zrkadlená kópia");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Plná kontrola");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2. tryska X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2. tryska Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2. tryska Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2. tryska X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2. tryska Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2. tryska Z");
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("Vykonávam G29");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("Nástroje UBL");
   PROGMEM Language_Str MSG_UBL_LEVEL_BED                   = _UxGT("UBL rovnanie");
diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h
index 26ec1e35f..4216d030e 100644
--- a/Marlin/src/lcd/language/language_tr.h
+++ b/Marlin/src/lcd/language/language_tr.h
@@ -123,9 +123,9 @@ namespace Language_tr {
   PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE             = _UxGT("Kopyala");
   PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY         = _UxGT("Yansıtılmış kopya");
   PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL             = _UxGT("Tam Kontrol");
-  PROGMEM Language_Str MSG_X_OFFSET                        = _UxGT("2. nozul X");
-  PROGMEM Language_Str MSG_Y_OFFSET                        = _UxGT("2. nozul Y");
-  PROGMEM Language_Str MSG_Z_OFFSET                        = _UxGT("2. nozul Z");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_X                 = _UxGT("2. nozul X");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Y                 = _UxGT("2. nozul Y");
+  PROGMEM Language_Str MSG_HOTEND_OFFSET_Z                 = _UxGT("2. nozul Z");
   PROGMEM Language_Str MSG_UBL_DOING_G29                   = _UxGT("G29 Çalışıyor");
   PROGMEM Language_Str MSG_UBL_TOOLS                       = _UxGT("UBL Araçları");
   PROGMEM Language_Str MSG_UBL_LEVEL_BED                   = _UxGT("UBL Yatak Hizalama");
diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp
index 60461528d..a41de3643 100644
--- a/Marlin/src/lcd/menu/menu.cpp
+++ b/Marlin/src/lcd/menu/menu.cpp
@@ -141,7 +141,7 @@ void MenuItem_gcode::action(PGM_P const, PGM_P const pgcode) { queue.inject_P(pg
  *
  * ...which calls:
  *       MenuItem_int3::action(plabel, &feedrate_percentage, 10, 999)
- *       draw_menu_item_int3(encoderLine == _thisItemNr, _lcdLineNr, plabel, &feedrate_percentage, 10, 999)
+ *       MenuItem_int3::draw(encoderLine == _thisItemNr, _lcdLineNr, plabel, &feedrate_percentage, 10, 999)
  */
 void MenuEditItemBase::edit(strfunc_t strfunc, loadfunc_t loadfunc) {
   #if ENABLED(TOUCH_BUTTONS)
@@ -150,7 +150,7 @@ void MenuEditItemBase::edit(strfunc_t strfunc, loadfunc_t loadfunc) {
   if (int32_t(ui.encoderPosition) < 0) ui.encoderPosition = 0;
   if (int32_t(ui.encoderPosition) > maxEditValue) ui.encoderPosition = maxEditValue;
   if (ui.should_draw())
-    draw_edit_screen(editLabel, strfunc(ui.encoderPosition + minEditValue));
+    edit_screen(editLabel, strfunc(ui.encoderPosition + minEditValue));
   if (ui.lcd_clicked || (liveEdit && ui.should_draw())) {
     if (editValue != nullptr) loadfunc(editValue, ui.encoderPosition + minEditValue);
     if (callbackFunc && (liveEdit || ui.lcd_clicked)) (*callbackFunc)();
@@ -187,6 +187,7 @@ DEFINE_MENU_EDIT_ITEM(float43);     // 1.234
 DEFINE_MENU_EDIT_ITEM(float5);      // 12345      right-justified
 DEFINE_MENU_EDIT_ITEM(float5_25);   // 12345      right-justified (25 increment)
 DEFINE_MENU_EDIT_ITEM(float51);     // 1234.5     right-justified
+DEFINE_MENU_EDIT_ITEM(float41sign); // +123.4
 DEFINE_MENU_EDIT_ITEM(float51sign); // +1234.5
 DEFINE_MENU_EDIT_ITEM(float52sign); // +123.45
 DEFINE_MENU_EDIT_ITEM(long5);       // 12345      right-justified
@@ -309,7 +310,7 @@ void MarlinUI::goto_screen(screenFunc_t screen, const uint16_t encoder/*=0*/, co
 static PGM_P sync_message;
 
 void MarlinUI::_synchronize() {
-  if (should_draw()) draw_menu_item_static(LCD_HEIGHT >= 4 ? 1 : 0, sync_message);
+  if (should_draw()) MenuItem_static::draw(LCD_HEIGHT >= 4, sync_message);
   if (no_reentry) return;
   // Make this the current handler till all moves are done
   no_reentry = true;
@@ -417,10 +418,10 @@ void scroll_screen(const uint8_t limit, const bool is_menu) {
     if (ui.should_draw()) {
       #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
         if (!do_probe)
-          draw_edit_screen(GET_TEXT(MSG_Z_OFFSET), ftostr43sign(hotend_offset[active_extruder].z));
+          MenuEditItemBase::edit_screen(GET_TEXT(MSG_HOTEND_OFFSET_Z), ftostr43sign(hotend_offset[active_extruder].z));
         else
       #endif
-          draw_edit_screen(GET_TEXT(MSG_ZPROBE_ZOFFSET), ftostr43sign(probe_offset.z));
+          MenuEditItemBase::edit_screen(GET_TEXT(MSG_ZPROBE_ZOFFSET), ftostr43sign(probe_offset.z));
 
       #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY)
         if (do_probe) _lcd_zoffset_overlay_gfx(probe_offset.z);
@@ -465,7 +466,7 @@ void scroll_screen(const uint8_t limit, const bool is_menu) {
 
 void _lcd_draw_homing() {
   constexpr uint8_t line = (LCD_HEIGHT - 1) / 2;
-  if (ui.should_draw()) draw_menu_item_static(line, GET_TEXT(MSG_LEVEL_BED_HOMING));
+  if (ui.should_draw()) MenuItem_static::draw(line, GET_TEXT(MSG_LEVEL_BED_HOMING));
   ui.refresh(LCDVIEW_CALL_NO_REDRAW);
 }
 
@@ -486,7 +487,8 @@ bool MarlinUI::update_selection() {
   }
   return selection;
 }
-void do_select_screen(PGM_P const yes, PGM_P const no, selectFunc_t yesFunc, selectFunc_t noFunc, PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/) {
+
+void MenuItem_confirm::select_screen(PGM_P const yes, PGM_P const no, selectFunc_t yesFunc, selectFunc_t noFunc, PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/) {
   const bool ui_selection = ui.update_selection(), got_click = ui.use_click();
   if (got_click || ui.should_draw()) {
     draw_select_screen(yes, no, ui_selection, pref, string, suff);
diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h
index 268ca05d3..aa8e699e7 100644
--- a/Marlin/src/lcd/menu/menu.h
+++ b/Marlin/src/lcd/menu/menu.h
@@ -37,118 +37,79 @@ extern bool screen_changed;
 void scroll_screen(const uint8_t limit, const bool is_menu);
 bool printer_busy();
 
-////////////////////////////////////////////
-////////// Menu Item Numeric Types /////////
-////////////////////////////////////////////
-
-#define DECLARE_MENU_EDIT_TYPE(TYPE, NAME, STRFUNC, SCALE) \
-  struct MenuEditItemInfo_##NAME { \
-    typedef TYPE type_t; \
-    static constexpr float scale = SCALE; \
-    static inline const char* strfunc(const float value) { return STRFUNC((TYPE) value); } \
-  };
-
-DECLARE_MENU_EDIT_TYPE(uint8_t,  percent,     ui8tostr4pct, 100.0/255);   // 100%       right-justified
-DECLARE_MENU_EDIT_TYPE(int16_t,  int3,        i16tostr3,       1     );   // 123, -12   right-justified
-DECLARE_MENU_EDIT_TYPE(int16_t,  int4,        i16tostr4sign,   1     );   // 1234, -123 right-justified
-DECLARE_MENU_EDIT_TYPE(int8_t,   int8,        i8tostr3,        1     );   // 123, -12   right-justified
-DECLARE_MENU_EDIT_TYPE(uint8_t,  uint8,       ui8tostr3,       1     );   // 123        right-justified
-DECLARE_MENU_EDIT_TYPE(uint16_t, uint16_3,    ui16tostr3,      1     );   // 123        right-justified
-DECLARE_MENU_EDIT_TYPE(uint16_t, uint16_4,    ui16tostr4,      0.1   );   // 1234       right-justified
-DECLARE_MENU_EDIT_TYPE(uint16_t, uint16_5,    ui16tostr5,      0.01  );   // 12345      right-justified
-DECLARE_MENU_EDIT_TYPE(float,    float3,      ftostr3,         1     );   // 123        right-justified
-DECLARE_MENU_EDIT_TYPE(float,    float52,     ftostr42_52,   100     );   // _2.34, 12.34, -2.34 or 123.45, -23.45
-DECLARE_MENU_EDIT_TYPE(float,    float43,     ftostr43sign, 1000     );   // 1.234
-DECLARE_MENU_EDIT_TYPE(float,    float5,      ftostr5rj,       1     );   // 12345      right-justified
-DECLARE_MENU_EDIT_TYPE(float,    float5_25,   ftostr5rj,       0.04f );   // 12345      right-justified (25 increment)
-DECLARE_MENU_EDIT_TYPE(float,    float51,     ftostr51rj,     10     );   // 1234.5     right-justified
-DECLARE_MENU_EDIT_TYPE(float,    float51sign, ftostr51sign,   10     );   // +1234.5
-DECLARE_MENU_EDIT_TYPE(float,    float52sign, ftostr52sign,  100     );   // +123.45
-DECLARE_MENU_EDIT_TYPE(uint32_t, long5,       ftostr5rj,       0.01f );   // 12345      right-justified
-DECLARE_MENU_EDIT_TYPE(uint32_t, long5_25,    ftostr5rj,       0.04f );   // 12345      right-justified (25 increment)
-
-////////////////////////////////////////////
-///////// Menu Item Draw Functions /////////
-////////////////////////////////////////////
-
 typedef void (*selectFunc_t)();
-void draw_select_screen(PGM_P const yes, PGM_P const no, const bool yesno, PGM_P const pref, const char * const string, PGM_P const suff);
-void do_select_screen(PGM_P const yes, PGM_P const no, selectFunc_t yesFunc, selectFunc_t noFunc, PGM_P const pref, const char * const string=nullptr, PGM_P const suff=nullptr);
-inline void do_select_screen_yn(selectFunc_t yesFunc, selectFunc_t noFunc, PGM_P const pref, const char * const string=nullptr, PGM_P const suff=nullptr) {
-  do_select_screen(GET_TEXT(MSG_YES), GET_TEXT(MSG_NO), yesFunc, noFunc, pref, string, suff);
-}
 
 #define SS_LEFT    0x00
 #define SS_CENTER  0x01
 #define SS_INVERT  0x02
 #define SS_DEFAULT SS_CENTER
 
-void draw_edit_screen(PGM_P const pstr, const char* const value=nullptr);
-void draw_menu_item(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char);
-void draw_menu_item_static(const uint8_t row, PGM_P const pstr, const uint8_t style=SS_DEFAULT, const char * const valstr=nullptr);
-void _draw_menu_item_edit(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm);
-FORCE_INLINE void draw_menu_item_back(const bool sel, const uint8_t row, PGM_P const pstr) { draw_menu_item(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]); }
-FORCE_INLINE void draw_menu_item_edit(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data) { _draw_menu_item_edit(sel, row, pstr, data, false); }
-FORCE_INLINE void draw_menu_item_edit_P(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data) { _draw_menu_item_edit(sel, row, pstr, data, true); }
-#define draw_menu_item_submenu(sel, row, pstr, data)  draw_menu_item(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0])
-#define draw_menu_item_gcode(sel, row, pstr, gcode)   draw_menu_item(sel, row, pstr, '>', ' ')
-#define draw_menu_item_function(sel, row, pstr, data) draw_menu_item(sel, row, pstr, '>', ' ')
-#define DRAW_MENU_ITEM_SETTING_EDIT_GENERIC(VAL)      draw_menu_item_edit(sel, row, pstr, VAL)
-#define DRAW_BOOL_SETTING(sel, row, pstr, data)       draw_menu_item_edit_P(sel, row, pstr, (*(data))?GET_TEXT(MSG_LCD_ON):GET_TEXT(MSG_LCD_OFF))
-
-#if ENABLED(SDSUPPORT)
-  class CardReader;
-  void draw_sd_menu_item(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir);
-  FORCE_INLINE void draw_menu_item_sdfile(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard) { draw_sd_menu_item(sel, row, pstr, theCard, false); }
-  FORCE_INLINE void draw_menu_item_sdfolder(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard) { draw_sd_menu_item(sel, row, pstr, theCard, true); }
-#endif
-
 #if HAS_GRAPHICAL_LCD && EITHER(BABYSTEP_ZPROBE_GFX_OVERLAY, MESH_EDIT_GFX_OVERLAY)
   void _lcd_zoffset_overlay_gfx(const float zvalue);
 #endif
 
 ////////////////////////////////////////////
-/////// Edit Setting Draw Functions ////////
+///////////// Base Menu Items //////////////
 ////////////////////////////////////////////
 
-#define _DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(TYPE, NAME, STRFUNC) \
-  FORCE_INLINE void draw_menu_item_##NAME (const bool sel, const uint8_t row, PGM_P const pstr, TYPE * const data, ...) { \
-    DRAW_MENU_ITEM_SETTING_EDIT_GENERIC(STRFUNC(*(data))); \
-  } \
-  FORCE_INLINE void draw_menu_item_accessor_##NAME (const bool sel, const uint8_t row, PGM_P const pstr, PGM_P const, TYPE (*pget)(), void (*)(TYPE), ...) { \
-    DRAW_MENU_ITEM_SETTING_EDIT_GENERIC(STRFUNC(pget())); \
-  } \
-  typedef void NAME##_void
-#define DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(NAME) _DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(MenuEditItemInfo_##NAME::type_t, NAME, MenuEditItemInfo_##NAME::strfunc)
-
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(percent);          // 100%       right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(int3);             // 123, -12   right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(int4);             // 1234, -123 right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(int8);             // 123, -12   right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(uint8);            // 123        right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(uint16_3);         // 123        right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(uint16_4);         // 1234       right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(uint16_5);         // 12345      right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float3);           // 123        right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float52);          // _2.34, 12.34, -2.34 or 123.45, -23.45
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float43);          // 1.234
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float5);           // 12345      right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float5_25);        // 12345      right-justified (25 increment)
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float51);          // _1234.5    right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float51sign);      // +1234.5
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(float52sign);      // +123.45
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(long5);            // 12345      right-justified
-DEFINE_DRAW_MENU_ITEM_SETTING_EDIT(long5_25);         // 12345      right-justified (25 increment)
-
-#define draw_menu_item_bool(sel, row, pstr, data, ...)           DRAW_BOOL_SETTING(sel, row, pstr, data)
-#define draw_menu_item_accessor_bool(sel, row, pstr, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data)
+class MenuItem_static {
+  public:
+    static void draw(const uint8_t row, PGM_P const pstr, const uint8_t style=SS_DEFAULT, const char * const valstr=nullptr);
+};
 
-////////////////////////////////////////////
-/////////////// Menu Actions ///////////////
-////////////////////////////////////////////
+class MenuItemBase {
+  public:
+    // Draw an item either selected (pre_char) or not (space) with post_char
+    static void _draw(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char);
+
+    // Draw an item either selected ('>') or not (space) with post_char
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, const char post_char) {
+      _draw(sel, row, pstr, '>', post_char);
+    }
+};
 
-class MenuItem_back {
+// CONFIRM_ITEM(PLABEL,Y,N,FY,FN,V...), YESNO_ITEM(PLABEL,FY,FN,V...)
+class MenuItem_confirm : MenuItemBase {
   public:
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, ...) {
+      _draw(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0]);
+    }
+    // Implemented for HD44780 and DOGM
+    // Draw the prompt, buttons, and state
+    static void draw_select_screen(
+      PGM_P const yes,            // Right option label
+      PGM_P const no,             // Left option label
+      const bool yesno,           // Is "yes" selected?
+      PGM_P const pref,           // Prompt prefix
+      const char * const string,  // Prompt runtime string
+      PGM_P const suff            // Prompt suffix
+    );
+    static void select_screen(
+      PGM_P const yes, PGM_P const no,
+      selectFunc_t yesFunc, selectFunc_t noFunc,
+      PGM_P const pref, const char * const string=nullptr, PGM_P const suff=nullptr
+    );
+    static inline void select_screen(
+      PGM_P const yes, PGM_P const no,
+      selectFunc_t yesFunc, selectFunc_t noFunc,
+      PGM_P const pref, const progmem_str string, PGM_P const suff=nullptr
+    ) {
+      char str[strlen_P((PGM_P)string) + 1];
+      strcpy_P(str, (PGM_P)string);
+      select_screen(yes, no, yesFunc, noFunc, pref, str, suff);
+    }
+    // Shortcut for prompt with "NO"/ "YES" labels
+    FORCE_INLINE static void confirm_screen(selectFunc_t yesFunc, selectFunc_t noFunc, PGM_P const pref, const char * const string=nullptr, PGM_P const suff=nullptr) {
+      select_screen(GET_TEXT(MSG_YES), GET_TEXT(MSG_NO), yesFunc, noFunc, pref, string, suff);
+    }
+};
+
+// BACK_ITEM(PLABEL)
+class MenuItem_back : public MenuItemBase {
+  public:
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr) {
+      _draw(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]);
+    }
     static inline void action(PGM_P const=nullptr) {
       ui.goto_previous_screen(
         #if ENABLED(TURBO_BACK_MENU_ITEM)
@@ -158,30 +119,46 @@ class MenuItem_back {
     }
 };
 
-class MenuItem_submenu {
+// SUBMENU(PLABEL, screen_handler)
+class MenuItem_submenu : public MenuItemBase {
   public:
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, ...) {
+      _draw(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0]);
+    }
     static inline void action(PGM_P const, const screenFunc_t func) { ui.save_previous_screen(); ui.goto_screen(func); }
 };
 
-class MenuItem_gcode {
+// GCODE_ITEM(PLABEL, gcode)
+class MenuItem_gcode : public MenuItemBase {
   public:
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, ...) {
+      _draw(sel, row, pstr, '>', ' ');
+    }
     static void action(PGM_P const, const char * const pgcode);
 };
 
-class MenuItem_function {
+// ACTION_ITEM(PLABEL, function)
+class MenuItem_function : public MenuItemBase {
   public:
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, ...) {
+      _draw(sel, row, pstr, '>', ' ');
+    }
     static inline void action(PGM_P const, const menuAction_t func) { (*func)(); };
 };
 
+#if ENABLED(SDSUPPORT)
+  class CardReader;
+  class MenuItem_sdbase {
+    public:
+      static void draw(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir);
+  };
+#endif
+
 ////////////////////////////////////////////
-/////////// Menu Editing Actions ///////////
+///////////// Edit Menu Items //////////////
 ////////////////////////////////////////////
 
-//
 // The Menu Edit shadow value
-// Only one edit value is needed at a time
-//
-
 typedef union {
   bool     state;
   float    decimal;
@@ -192,11 +169,10 @@ typedef union {
   uint16_t uint16;
   uint32_t uint32;
 } chimera_t;
-
 extern chimera_t editable;
 
 // Edit items use long integer encoder units
-class MenuEditItemBase {
+class MenuEditItemBase : public MenuItemBase {
   private:
     static PGM_P editLabel;
     static void *editValue;
@@ -208,6 +184,17 @@ class MenuEditItemBase {
     typedef void (*loadfunc_t)(void *, const int32_t);
     static void init(PGM_P const el, void * const ev, const int32_t minv, const int32_t maxv, const uint16_t ep, const screenFunc_t cs, const screenFunc_t cb, const bool le);
     static void edit(strfunc_t, loadfunc_t);
+  public:
+    // Implemented for HD44780 and DOGM
+    // Draw the current item at specified row with edit data
+    static void draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm);
+
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data) { draw(sel, row, pstr, data, false); }
+    FORCE_INLINE static void draw_P(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data) { draw(sel, row, pstr, data, true); }
+
+    // Implemented for HD44780 and DOGM
+    // This low-level method is good to draw from anywhere
+    static void edit_screen(PGM_P const pstr, const char* const value=nullptr);
 };
 
 template<typename NAME>
@@ -219,6 +206,12 @@ class TMenuEditItem : MenuEditItemBase {
     static void load(void *ptr, const int32_t value)  { *((type_t*)ptr) = unscale(value);     }
     static const char* to_string(const int32_t value) { return NAME::strfunc(unscale(value)); }
   public:
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, type_t * const data, ...) {
+      MenuEditItemBase::draw(sel, row, pstr, NAME::strfunc(*(data)));
+    }
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, type_t (*pget)(), ...) {
+      MenuEditItemBase::draw(sel, row, pstr, NAME::strfunc(pget()));
+    }
     static void action(
       PGM_P const pstr,                     // Edit label
       type_t * const ptr,                   // Value pointer
@@ -235,30 +228,53 @@ class TMenuEditItem : MenuEditItemBase {
     static void edit() { MenuEditItemBase::edit(to_string, load); }
 };
 
-#define DECLARE_MENU_EDIT_ITEM(NAME) typedef TMenuEditItem<MenuEditItemInfo_##NAME> MenuItem_##NAME;
-
-DECLARE_MENU_EDIT_ITEM(percent);
-DECLARE_MENU_EDIT_ITEM(int3);
-DECLARE_MENU_EDIT_ITEM(int4);
-DECLARE_MENU_EDIT_ITEM(int8);
-DECLARE_MENU_EDIT_ITEM(uint8);
-DECLARE_MENU_EDIT_ITEM(uint16_3);
-DECLARE_MENU_EDIT_ITEM(uint16_4);
-DECLARE_MENU_EDIT_ITEM(uint16_5);
-DECLARE_MENU_EDIT_ITEM(float3);
-DECLARE_MENU_EDIT_ITEM(float52);
-DECLARE_MENU_EDIT_ITEM(float43);
-DECLARE_MENU_EDIT_ITEM(float5);
-DECLARE_MENU_EDIT_ITEM(float5_25);
-DECLARE_MENU_EDIT_ITEM(float51);
-DECLARE_MENU_EDIT_ITEM(float51sign);
-DECLARE_MENU_EDIT_ITEM(float52sign);
-DECLARE_MENU_EDIT_ITEM(long5);
-DECLARE_MENU_EDIT_ITEM(long5_25);
-
-class MenuItem_bool {
+// Provide a set of Edit Item Types which encompass a primitive
+// type, a string function, and a scale factor for edit and display.
+// These items call the Edit Item draw method passing the prepared string.
+#define DEFINE_MENU_EDIT_ITEM_TYPE(TYPE, NAME, STRFUNC, SCALE) \
+  struct MenuEditItemInfo_##NAME { \
+    typedef TYPE type_t; \
+    static constexpr float scale = SCALE; \
+    static inline const char* strfunc(const float value) { return STRFUNC((TYPE)value); } \
+  }; \
+  typedef TMenuEditItem<MenuEditItemInfo_##NAME> MenuItem_##NAME
+
+//                         TYPE      NAME         STRFUNC       SCALE
+DEFINE_MENU_EDIT_ITEM_TYPE(uint8_t,  percent,     ui8tostr4pct, 100.0/255);   // 100%       right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(int16_t,  int3,        i16tostr3,       1     );   // 123, -12   right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(int16_t,  int4,        i16tostr4sign,   1     );   // 1234, -123 right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(int8_t,   int8,        i8tostr3,        1     );   // 123, -12   right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(uint8_t,  uint8,       ui8tostr3,       1     );   // 123        right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(uint16_t, uint16_3,    ui16tostr3,      1     );   // 123        right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(uint16_t, uint16_4,    ui16tostr4,      0.1   );   // 1234       right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(uint16_t, uint16_5,    ui16tostr5,      0.01  );   // 12345      right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float3,      ftostr3,         1     );   // 123        right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float52,     ftostr42_52,   100     );   // _2.34, 12.34, -2.34 or 123.45, -23.45
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float43,     ftostr43sign, 1000     );   // 1.234
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float5,      ftostr5rj,       1     );   // 12345      right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float5_25,   ftostr5rj,       0.04f );   // 12345      right-justified (25 increment)
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float51,     ftostr51rj,     10     );   // 1234.5     right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float41sign, ftostr41sign,   10     );   // +123.4
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float51sign, ftostr51sign,   10     );   // +1234.5
+DEFINE_MENU_EDIT_ITEM_TYPE(float,    float52sign, ftostr52sign,  100     );   // +123.45
+DEFINE_MENU_EDIT_ITEM_TYPE(uint32_t, long5,       ftostr5rj,       0.01f );   // 12345      right-justified
+DEFINE_MENU_EDIT_ITEM_TYPE(uint32_t, long5_25,    ftostr5rj,       0.04f );   // 12345      right-justified (25 increment)
+
+class MenuItem_bool : public MenuEditItemBase {
   public:
-    static void action(PGM_P const pstr, bool* ptr, const screenFunc_t callbackFunc=nullptr);
+    //#define DRAW_BOOL_SETTING(sel, row, pstr, data)  draw_menu_item_edit_P(sel, row, pstr, (*(data))?GET_TEXT(MSG_LCD_ON):GET_TEXT(MSG_LCD_OFF))
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, const bool onoff) {
+      MenuEditItemBase::draw(sel, row, pstr, onoff ? GET_TEXT(MSG_LCD_ON) : GET_TEXT(MSG_LCD_OFF), true);
+    }
+    //#define draw_menu_item_bool(sel, row, pstr, data, ...)           DRAW_BOOL_SETTING(sel, row, pstr, data)
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, bool * const data, ...) {
+      draw(sel, row, pstr, *data);
+    }
+    //#define draw_menu_item_accessor_bool(sel, row, pstr, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data)
+    FORCE_INLINE static void draw(const bool sel, const uint8_t row, PGM_P const pstr, PGM_P const, bool (*pget)(), ...) {
+      draw(sel, row, pstr, pget());
+    }
+    static void action(PGM_P const pstr, bool * const ptr, const screenFunc_t callbackFunc=nullptr);
 };
 
 ////////////////////////////////////////////
@@ -313,39 +329,39 @@ class MenuItem_bool {
 /**
  * MENU_ITEM generates draw & handler code for a menu item, potentially calling:
  *
- *   draw_menu_item_<type>(sel, row, label, arg3...)
+ *   MenuItem_<type>::draw(sel, row, label, arg3...)
  *   MenuItem_<type>::action(arg3...)
  *
  * Examples:
  *   BACK_ITEM(MSG_WATCH)
  *   MENU_ITEM(back, MSG_WATCH)
- *     draw_menu_item_back(sel, row, GET_TEXT(MSG_WATCH))
+ *     MenuItem_back::draw(sel, row, GET_TEXT(MSG_WATCH))
  *     MenuItem_back::action()
  *
  *   ACTION_ITEM(MSG_PAUSE_PRINT, lcd_sdcard_pause)
  *   MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause)
- *     draw_menu_item_function(sel, row, GET_TEXT(MSG_PAUSE_PRINT), lcd_sdcard_pause)
- *     MenuItem_function::action(lcd_sdcard_pause)
+ *     MenuItem_function::draw(sel, row, GET_TEXT(MSG_PAUSE_PRINT), lcd_sdcard_pause)
+ *     MenuItem_function::action(GET_TEXT(MSG_PAUSE_PRINT), lcd_sdcard_pause)
  *
  *   EDIT_ITEM(int3, MSG_SPEED, &feedrate_percentage, 10, 999)
- *     draw_menu_item_int3(sel, row, GET_TEXT(MSG_SPEED), &feedrate_percentage, 10, 999)
+ *     MenuItem_int3::draw(sel, row, GET_TEXT(MSG_SPEED), &feedrate_percentage, 10, 999)
  *     MenuItem_int3::action(GET_TEXT(MSG_SPEED), &feedrate_percentage, 10, 999)
  *
  */
-#define _MENU_ITEM_P(TYPE, USE_MULTIPLIER, PLABEL, V...) do {  \
-    _skipStatic = false;                                          \
-    if (_menuLineNr == _thisItemNr) {                             \
-      PGM_P const plabel = PLABEL;                                \
-      if (encoderLine == _thisItemNr && ui.use_click()) {         \
-        _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER);              \
-        MenuItem_##TYPE ::action(plabel, ##V);                    \
-        if (screen_changed) return;                               \
-      }                                                           \
-      if (ui.should_draw())                                       \
-        draw_menu_item_ ## TYPE                                   \
-          (encoderLine == _thisItemNr, _lcdLineNr, plabel, ##V);  \
-    }                                                             \
-  ++_thisItemNr;                                                  \
+#define _MENU_ITEM_P(TYPE, USE_MULTIPLIER, PLABEL, V...) do {   \
+  _skipStatic = false;                                          \
+  if (_menuLineNr == _thisItemNr) {                             \
+    PGM_P const plabel = PLABEL;                                \
+    if (encoderLine == _thisItemNr && ui.use_click()) {         \
+      _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER);              \
+      MenuItem_##TYPE::action(plabel, ##V);                     \
+      if (screen_changed) return;                               \
+    }                                                           \
+    if (ui.should_draw())                                       \
+      MenuItem_##TYPE::draw                                     \
+        (encoderLine == _thisItemNr, _lcdLineNr, plabel, ##V);  \
+  }                                                             \
+  ++_thisItemNr;                                                \
 }while(0)
 
 // Used to print static text with no visible cursor.
@@ -357,7 +373,7 @@ class MenuItem_bool {
       ++encoderLine;                                      \
     }                                                     \
     if (ui.should_draw())                                 \
-      draw_menu_item_static(_lcdLineNr, PLABEL, ##V);     \
+      MenuItem_static::draw(_lcdLineNr, PLABEL, ##V);     \
   }                                                       \
   ++_thisItemNr;                                          \
 } while(0)
@@ -385,6 +401,24 @@ class MenuItem_bool {
 #define BACK_ITEM(LABEL)                         MENU_ITEM(back, LABEL)
 #define SKIP_ITEM() (_thisItemNr++)
 
+#define _CONFIRM_ITEM_P(PLABEL, V...) do {                      \
+  _skipStatic = false;                                          \
+  if (_menuLineNr == _thisItemNr) {                             \
+    if (encoderLine == _thisItemNr && ui.use_click()) {         \
+      ui.goto_screen([]{MenuItem_confirm::select_screen(V);});  \
+      return;                                                   \
+    }                                                           \
+    if (ui.should_draw()) MenuItem_confirm::draw                \
+      (encoderLine == _thisItemNr, _lcdLineNr, PLABEL, ##V);    \
+  }                                                             \
+  ++_thisItemNr;                                                \
+}while(0)
+
+#define CONFIRM_ITEM_P(PLABEL,A,B,V...) _CONFIRM_ITEM_P(PLABEL, GET_TEXT(A), GET_TEXT(B), ##V)
+#define CONFIRM_ITEM(LABEL, V...)        CONFIRM_ITEM_P(GET_TEXT(LABEL), ##V)
+#define YESNO_ITEM_P(PLABEL, V...)      _CONFIRM_ITEM_P(PLABEL, ##V)
+#define YESNO_ITEM(LABEL, V...)         _CONFIRM_ITEM_P(GET_TEXT(LABEL), ##V)
+
 ////////////////////////////////////////////
 /////////////// Menu Screens ///////////////
 ////////////////////////////////////////////
diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp
index d4e59730d..0a69870fb 100644
--- a/Marlin/src/lcd/menu/menu_advanced.cpp
+++ b/Marlin/src/lcd/menu/menu_advanced.cpp
@@ -48,6 +48,10 @@
   float lcd_runout_distance_mm;
 #endif
 
+#if ENABLED(EEPROM_SETTINGS) && DISABLED(SLIM_LCD_MENUS)
+  #include "../../module/configuration_store.h"
+#endif
+
 void menu_tmc();
 void menu_backlash();
 void menu_cancelobject();
@@ -595,27 +599,6 @@ void menu_cancelobject();
     END_MENU();
   }
 
-  #if ENABLED(EEPROM_SETTINGS)
-
-    #include "../../module/configuration_store.h"
-
-    static void lcd_init_eeprom_confirm() {
-      do_select_screen(
-        GET_TEXT(MSG_BUTTON_INIT), GET_TEXT(MSG_BUTTON_CANCEL),
-        []{
-          const bool inited = settings.init_eeprom();
-          #if HAS_BUZZER
-            ui.completion_feedback(inited);
-          #endif
-          UNUSED(inited);
-        },
-        ui.goto_previous_screen,
-        GET_TEXT(MSG_INIT_EEPROM), nullptr, PSTR("?")
-      );
-    }
-
-  #endif
-
 #endif // !SLIM_LCD_MENUS
 
 void menu_advanced_settings() {
@@ -718,7 +701,18 @@ void menu_advanced_settings() {
   #endif
 
   #if ENABLED(EEPROM_SETTINGS) && DISABLED(SLIM_LCD_MENUS)
-    SUBMENU(MSG_INIT_EEPROM, lcd_init_eeprom_confirm);
+    CONFIRM_ITEM(MSG_INIT_EEPROM,
+      MSG_BUTTON_INIT, MSG_BUTTON_CANCEL,
+      []{
+        const bool inited = settings.init_eeprom();
+        #if HAS_BUZZER
+          ui.completion_feedback(inited);
+        #endif
+        UNUSED(inited);
+      },
+      ui.goto_previous_screen,
+      GET_TEXT(MSG_INIT_EEPROM), (PGM_P)nullptr, PSTR("?")
+    );
   #endif
 
   END_MENU();
diff --git a/Marlin/src/lcd/menu/menu_bed_corners.cpp b/Marlin/src/lcd/menu/menu_bed_corners.cpp
index b2eae427a..f3c3a1d90 100644
--- a/Marlin/src/lcd/menu/menu_bed_corners.cpp
+++ b/Marlin/src/lcd/menu/menu_bed_corners.cpp
@@ -84,31 +84,27 @@ static inline void _lcd_goto_next_corner() {
   ) bed_corner = 0;
 }
 
-static inline void menu_level_bed_corners() {
-  do_select_screen(
-    GET_TEXT(MSG_BUTTON_NEXT), GET_TEXT(MSG_BUTTON_DONE),
-    _lcd_goto_next_corner,
-    []{
-      #if HAS_LEVELING
-        set_bed_leveling_enabled(leveling_was_active);
-      #endif
-      ui.goto_previous_screen_no_defer();
-    },
-    GET_TEXT(
-      #if ENABLED(LEVEL_CENTER_TOO)
-        MSG_LEVEL_BED_NEXT_POINT
-      #else
-        MSG_NEXT_CORNER
-      #endif
-    ), nullptr, PSTR("?")
-  );
-}
-
 static inline void _lcd_level_bed_corners_homing() {
   _lcd_draw_homing();
   if (all_axes_homed()) {
     bed_corner = 0;
-    ui.goto_screen(menu_level_bed_corners);
+    MenuItem_confirm::select_screen(
+      GET_TEXT(MSG_BUTTON_NEXT), GET_TEXT(MSG_BUTTON_DONE),
+      _lcd_goto_next_corner,
+      []{
+        #if HAS_LEVELING
+          set_bed_leveling_enabled(leveling_was_active);
+        #endif
+        ui.goto_previous_screen_no_defer();
+      },
+      GET_TEXT(
+        #if ENABLED(LEVEL_CENTER_TOO)
+          MSG_LEVEL_BED_NEXT_POINT
+        #else
+          MSG_NEXT_CORNER
+        #endif
+      ), (PGM_P)nullptr, PSTR("?")
+    );
     ui.set_selection(true);
     _lcd_goto_next_corner();
   }
diff --git a/Marlin/src/lcd/menu/menu_bed_leveling.cpp b/Marlin/src/lcd/menu/menu_bed_leveling.cpp
index f53c10f33..892bb0d1d 100644
--- a/Marlin/src/lcd/menu/menu_bed_leveling.cpp
+++ b/Marlin/src/lcd/menu/menu_bed_leveling.cpp
@@ -81,7 +81,7 @@
         ui.completion_feedback();
       #endif
     }
-    if (ui.should_draw()) draw_menu_item_static(LCD_HEIGHT >= 4 ? 1 : 0, GET_TEXT(MSG_LEVEL_BED_DONE));
+    if (ui.should_draw()) MenuItem_static::draw(LCD_HEIGHT >= 4, GET_TEXT(MSG_LEVEL_BED_DONE));
     ui.refresh(LCDVIEW_CALL_REDRAW_NEXT);
   }
 
@@ -132,7 +132,7 @@
     //
     if (ui.should_draw()) {
       const float v = current_position.z;
-      draw_edit_screen(GET_TEXT(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001f : 0.0001f), '+'));
+      MenuEditItemBase::edit_screen(GET_TEXT(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001f : 0.0001f), '+'));
     }
   }
 
@@ -143,7 +143,7 @@
     if (ui.should_draw()) {
       char msg[10];
       sprintf_P(msg, PSTR("%i / %u"), int(manual_probe_index + 1), total_probe_points);
-      draw_edit_screen(GET_TEXT(MSG_LEVEL_BED_NEXT_POINT), msg);
+      MenuEditItemBase::edit_screen(GET_TEXT(MSG_LEVEL_BED_NEXT_POINT), msg);
     }
     ui.refresh(LCDVIEW_CALL_NO_REDRAW);
     if (!ui.wait_for_bl_move) ui.goto_screen(_lcd_level_bed_get_z);
@@ -169,7 +169,7 @@
   //         Move to the first probe position
   //
   void _lcd_level_bed_homing_done() {
-    if (ui.should_draw()) draw_edit_screen(GET_TEXT(MSG_LEVEL_BED_WAITING));
+    if (ui.should_draw()) MenuItem_static::draw(1, GET_TEXT(MSG_LEVEL_BED_WAITING));
     if (ui.use_click()) {
       manual_probe_index = 0;
       _lcd_level_goto_next_point();
diff --git a/Marlin/src/lcd/menu/menu_cancelobject.cpp b/Marlin/src/lcd/menu/menu_cancelobject.cpp
index ccb0e2948..69399e0d3 100644
--- a/Marlin/src/lcd/menu/menu_cancelobject.cpp
+++ b/Marlin/src/lcd/menu/menu_cancelobject.cpp
@@ -41,7 +41,7 @@ static void lcd_cancel_object_confirm() {
     char('0' + (v % 10)),
     '\0'
   };
-  do_select_screen_yn(
+  MenuItem_confirm::confirm_screen(
     []{
       cancelable.cancel_object(editable.int8 - 1);
       #if HAS_BUZZER
diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp
index 8ed707421..892f9c61d 100644
--- a/Marlin/src/lcd/menu/menu_configuration.cpp
+++ b/Marlin/src/lcd/menu/menu_configuration.cpp
@@ -68,7 +68,7 @@ void menu_advanced_settings();
     bar_percent += (int8_t)ui.encoderPosition;
     LIMIT(bar_percent, 0, 100);
     ui.encoderPosition = 0;
-    draw_menu_item_static(0, GET_TEXT(MSG_PROGRESS_BAR_TEST), SS_CENTER|SS_INVERT);
+    MenuItem_static::draw(0, GET_TEXT(MSG_PROGRESS_BAR_TEST), SS_CENTER|SS_INVERT);
     lcd_put_int((LCD_WIDTH) / 2 - 2, LCD_HEIGHT - 2, bar_percent); lcd_put_wchar('%');
     lcd_moveto(0, LCD_HEIGHT - 1); ui.draw_progress_bar(bar_percent);
   }
@@ -138,12 +138,12 @@ void menu_advanced_settings();
     START_MENU();
     BACK_ITEM(MSG_CONFIGURATION);
     #if ENABLED(DUAL_X_CARRIAGE)
-      EDIT_ITEM_FAST(float51, MSG_X_OFFSET, &hotend_offset[1].x, float(X2_HOME_POS - 25), float(X2_HOME_POS + 25), _recalc_offsets);
+      EDIT_ITEM_FAST(float51, MSG_HOTEND_OFFSET_X, &hotend_offset[1].x, float(X2_HOME_POS - 25), float(X2_HOME_POS + 25), _recalc_offsets);
     #else
-      EDIT_ITEM_FAST(float52sign, MSG_X_OFFSET, &hotend_offset[1].x, -99.0, 99.0, _recalc_offsets);
+      EDIT_ITEM_FAST(float41sign, MSG_HOTEND_OFFSET_X, &hotend_offset[1].x, -99.0, 99.0, _recalc_offsets);
     #endif
-    EDIT_ITEM_FAST(float52sign, MSG_Y_OFFSET, &hotend_offset[1].y, -99.0, 99.0, _recalc_offsets);
-    EDIT_ITEM_FAST(float52sign, MSG_Z_OFFSET, &hotend_offset[1].z, Z_PROBE_LOW_POINT, 10.0, _recalc_offsets);
+    EDIT_ITEM_FAST(float41sign, MSG_HOTEND_OFFSET_Y, &hotend_offset[1].y, -99.0, 99.0, _recalc_offsets);
+    EDIT_ITEM_FAST(float41sign, MSG_HOTEND_OFFSET_Z, &hotend_offset[1].z, Z_PROBE_LOW_POINT, 10.0, _recalc_offsets);
     #if ENABLED(EEPROM_SETTINGS)
       ACTION_ITEM(MSG_STORE_EEPROM, lcd_store_settings);
     #endif
@@ -202,19 +202,11 @@ void menu_advanced_settings();
     ACTION_ITEM(MSG_BLTOUCH_STOW, bltouch._stow);
     ACTION_ITEM(MSG_BLTOUCH_SW_MODE, bltouch._set_SW_mode);
     #if ENABLED(BLTOUCH_LCD_VOLTAGE_MENU)
-      SUBMENU(MSG_BLTOUCH_5V_MODE, []{
-        do_select_screen(GET_TEXT(MSG_BLTOUCH_5V_MODE), GET_TEXT(MSG_BUTTON_CANCEL), bltouch._set_5V_mode, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
-      });
-      SUBMENU(MSG_BLTOUCH_OD_MODE, []{
-        do_select_screen(GET_TEXT(MSG_BLTOUCH_OD_MODE), GET_TEXT(MSG_BUTTON_CANCEL), bltouch._set_OD_mode, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
-      });
+      CONFIRM_ITEM(MSG_BLTOUCH_5V_MODE, MSG_BLTOUCH_5V_MODE, MSG_BUTTON_CANCEL, bltouch._set_5V_mode, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
+      CONFIRM_ITEM(MSG_BLTOUCH_OD_MODE, MSG_BLTOUCH_OD_MODE, MSG_BUTTON_CANCEL, bltouch._set_OD_mode, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
       ACTION_ITEM(MSG_BLTOUCH_MODE_STORE, bltouch._mode_store);
-      SUBMENU(MSG_BLTOUCH_MODE_STORE_5V, []{
-        do_select_screen(GET_TEXT(MSG_BLTOUCH_MODE_STORE_5V), GET_TEXT(MSG_BUTTON_CANCEL), bltouch.mode_conv_5V, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
-      });
-      SUBMENU(MSG_BLTOUCH_MODE_STORE_OD, []{
-        do_select_screen(GET_TEXT(MSG_BLTOUCH_MODE_STORE_OD), GET_TEXT(MSG_BUTTON_CANCEL), bltouch.mode_conv_OD, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
-      });
+      CONFIRM_ITEM(MSG_BLTOUCH_MODE_STORE_5V, MSG_BLTOUCH_MODE_STORE_5V, MSG_BUTTON_CANCEL, bltouch.mode_conv_5V, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
+      CONFIRM_ITEM(MSG_BLTOUCH_MODE_STORE_OD, MSG_BLTOUCH_MODE_STORE_OD, MSG_BUTTON_CANCEL, bltouch.mode_conv_OD, ui.goto_previous_screen, GET_TEXT(MSG_BLTOUCH_MODE_CHANGE));
       ACTION_ITEM(MSG_BLTOUCH_MODE_ECHO, bltouch_report);
     #endif
     END_MENU();
diff --git a/Marlin/src/lcd/menu/menu_filament.cpp b/Marlin/src/lcd/menu/menu_filament.cpp
index df0311a99..d41ed18c1 100644
--- a/Marlin/src/lcd/menu/menu_filament.cpp
+++ b/Marlin/src/lcd/menu/menu_filament.cpp
@@ -281,7 +281,7 @@ static PGM_P pause_header() {
 #define HOTEND_STATUS_ITEM() do { \
   if (_menuLineNr == _thisItemNr) { \
     if (ui.should_draw()) { \
-      draw_menu_item_static(_lcdLineNr, GET_TEXT(MSG_FILAMENT_CHANGE_NOZZLE), SS_INVERT); \
+      MenuItem_static::draw(_lcdLineNr, GET_TEXT(MSG_FILAMENT_CHANGE_NOZZLE), SS_INVERT); \
       ui.draw_hotend_status(_lcdLineNr, hotend_status_extruder); \
     } \
     if (_skipStatic && encoderLine <= _thisItemNr) { \
diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp
index d68995b19..e2dcf6637 100644
--- a/Marlin/src/lcd/menu/menu_main.cpp
+++ b/Marlin/src/lcd/menu/menu_main.cpp
@@ -44,7 +44,11 @@
 
 #if MACHINE_CAN_STOP
   void menu_abort_confirm() {
-    do_select_screen(GET_TEXT(MSG_BUTTON_STOP), GET_TEXT(MSG_BACK), ui.abort_print, ui.goto_previous_screen, GET_TEXT(MSG_STOP_PRINT), nullptr, PSTR("?"));
+    MenuItem_confirm::select_screen(
+      GET_TEXT(MSG_BUTTON_STOP), GET_TEXT(MSG_BACK),
+      ui.abort_print, ui.goto_previous_screen,
+      GET_TEXT(MSG_STOP_PRINT), (PGM_P)nullptr, PSTR("?")
+    );
   }
 #endif // MACHINE_CAN_STOP
 
@@ -83,18 +87,6 @@ void menu_configuration();
   void menu_mixer();
 #endif
 
-#if HAS_SERVICE_INTERVALS
-  #if SERVICE_INTERVAL_1 > 0
-    void menu_service1();
-  #endif
-  #if SERVICE_INTERVAL_2 > 0
-    void menu_service2();
-  #endif
-  #if SERVICE_INTERVAL_3 > 0
-    void menu_service3();
-  #endif
-#endif
-
 extern const char M21_STR[];
 
 void menu_main() {
@@ -239,14 +231,34 @@ void menu_main() {
   #endif // HAS_ENCODER_WHEEL && SDSUPPORT
 
   #if HAS_SERVICE_INTERVALS
+    static auto _service_reset = [](const int index) {
+      print_job_timer.resetServiceInterval(index);
+      #if HAS_BUZZER
+        ui.completion_feedback();
+      #endif
+      ui.reset_status();
+      ui.return_to_status();
+    };
     #if SERVICE_INTERVAL_1 > 0
-      SUBMENU_P(PSTR(SERVICE_NAME_1), menu_service1);
+      CONFIRM_ITEM_P(PSTR(SERVICE_NAME_1),
+        MSG_BUTTON_RESET, MSG_BUTTON_CANCEL,
+        []{ _service_reset(1); }, ui.goto_previous_screen,
+        GET_TEXT(MSG_SERVICE_RESET), F(SERVICE_NAME_1), PSTR("?")
+      );
     #endif
     #if SERVICE_INTERVAL_2 > 0
-      SUBMENU_P(PSTR(SERVICE_NAME_2), menu_service2);
+      CONFIRM_ITEM_P(PSTR(SERVICE_NAME_2),
+        MSG_BUTTON_RESET, MSG_BUTTON_CANCEL,
+        []{ _service_reset(2); }, ui.goto_previous_screen,
+        GET_TEXT(MSG_SERVICE_RESET), F(SERVICE_NAME_2), PSTR("?")
+      );
     #endif
     #if SERVICE_INTERVAL_3 > 0
-      SUBMENU_P(PSTR(SERVICE_NAME_3), menu_service3);
+      CONFIRM_ITEM_P(PSTR(SERVICE_NAME_3),
+        MSG_BUTTON_RESET, MSG_BUTTON_CANCEL,
+        []{ _service_reset(3); }, ui.goto_previous_screen,
+        GET_TEXT(MSG_SERVICE_RESET), F(SERVICE_NAME_3), PSTR("?")
+      );
     #endif
   #endif
 
diff --git a/Marlin/src/lcd/menu/menu_media.cpp b/Marlin/src/lcd/menu/menu_media.cpp
index 34218ce2a..76cee902e 100644
--- a/Marlin/src/lcd/menu/menu_media.cpp
+++ b/Marlin/src/lcd/menu/menu_media.cpp
@@ -79,7 +79,7 @@ inline void sdcard_start_selected_file() {
     char buffer[strlen(longest) + 2];
     buffer[0] = ' ';
     strcpy(buffer + 1, longest);
-    do_select_screen(
+    MenuItem_confirm::select_screen(
       GET_TEXT(MSG_BUTTON_PRINT), GET_TEXT(MSG_BUTTON_CANCEL),
       sdcard_start_selected_file, ui.goto_previous_screen,
       GET_TEXT(MSG_START_PRINT), buffer, PSTR("?")
@@ -88,8 +88,11 @@ inline void sdcard_start_selected_file() {
 
 #endif
 
-class MenuItem_sdfile {
+class MenuItem_sdfile : public MenuItem_sdbase {
   public:
+    static inline void draw(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard) {
+      MenuItem_sdbase::draw(sel, row, pstr, theCard, false);
+    }
     static void action(PGM_P const pstr, CardReader &) {
       #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
         // Save menu state for the selected file
@@ -106,8 +109,11 @@ class MenuItem_sdfile {
     }
 };
 
-class MenuItem_sdfolder {
+class MenuItem_sdfolder : public MenuItem_sdbase {
   public:
+    static inline void draw(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard) {
+      MenuItem_sdbase::draw(sel, row, pstr, theCard, true);
+    }
     static void action(PGM_P const, CardReader &theCard) {
       card.cd(theCard.filename);
       encoderTopLine = 0;
diff --git a/Marlin/src/lcd/menu/menu_mixer.cpp b/Marlin/src/lcd/menu/menu_mixer.cpp
index c8484edc9..13cb31a5c 100644
--- a/Marlin/src/lcd/menu/menu_mixer.cpp
+++ b/Marlin/src/lcd/menu/menu_mixer.cpp
@@ -245,22 +245,6 @@ void lcd_mixer_mix_edit() {
   }
 #endif
 
-//
-// Reset All V-Tools
-//
-void menu_mixer_vtools_reset_confirm() {
-  do_select_screen(
-    GET_TEXT(MSG_BUTTON_RESET), GET_TEXT(MSG_BUTTON_CANCEL),
-    []{
-      mixer.reset_vtools();
-      LCD_MESSAGEPGM(MSG_VTOOLS_RESET);
-      ui.return_to_status();
-    },
-    ui.goto_previous_screen,
-    GET_TEXT(MSG_RESET_VTOOLS), nullptr, PSTR("?")
-  );
-}
-
 void menu_mixer() {
   START_MENU();
   BACK_ITEM(MSG_MAIN);
@@ -287,7 +271,19 @@ void menu_mixer() {
     SUBMENU(MSG_MIX, _lcd_goto_mix_edit);
   #endif
 
-  SUBMENU(MSG_RESET_VTOOLS, menu_mixer_vtools_reset_confirm);
+  //
+  // Reset All V-Tools
+  //
+  CONFIRM_ITEM(MSG_RESET_VTOOLS,
+    MSG_BUTTON_RESET, MSG_BUTTON_CANCEL,
+    []{
+      mixer.reset_vtools();
+      LCD_MESSAGEPGM(MSG_VTOOLS_RESET);
+      ui.return_to_status();
+    },
+    ui.goto_previous_screen,
+    GET_TEXT(MSG_RESET_VTOOLS), (PGM_P)nullptr, PSTR("?")
+  );
 
   #if ENABLED(GRADIENT_MIX)
   {
diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp
index 87b5a680d..cc15c19ec 100644
--- a/Marlin/src/lcd/menu/menu_motion.cpp
+++ b/Marlin/src/lcd/menu/menu_motion.cpp
@@ -147,7 +147,7 @@ static void _lcd_move_xyz(PGM_P name, AxisEnum axis) {
         + manual_move_offset
       #endif
     , axis);
-    draw_edit_screen(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos));
+    MenuEditItemBase::edit_screen(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos));
   }
 }
 void lcd_move_x() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_X), X_AXIS); }
@@ -200,7 +200,7 @@ void lcd_move_z() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_Z), Z_AXIS); }
         }
       #endif // E_MANUAL > 1
 
-      draw_edit_screen(pos_label, ftostr41sign(current_position.e
+      MenuEditItemBase::edit_screen(pos_label, ftostr41sign(current_position.e
         #if IS_KINEMATIC
           + manual_move_offset
         #endif
diff --git a/Marlin/src/lcd/menu/menu_service.cpp b/Marlin/src/lcd/menu/menu_service.cpp
deleted file mode 100644
index 0d305d028..000000000
--- a/Marlin/src/lcd/menu/menu_service.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Marlin 3D Printer Firmware
- * Copyright (c) 2019 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-//
-// Service Menus
-//
-
-#include "../../inc/MarlinConfigPre.h"
-
-#if HAS_LCD_MENU && HAS_SERVICE_INTERVALS
-
-#include "menu.h"
-#include "../../module/printcounter.h"
-
-inline void _service_reset(const int index) {
-  print_job_timer.resetServiceInterval(index);
-  #if HAS_BUZZER
-    ui.completion_feedback();
-  #endif
-  ui.reset_status();
-  ui.return_to_status();
-}
-
-#if SERVICE_INTERVAL_1 > 0
-  void menu_service1() {
-    char sram[30];
-    strncpy_P(sram, PSTR(SERVICE_NAME_1), 29);
-    do_select_screen(
-      GET_TEXT(MSG_BUTTON_RESET), GET_TEXT(MSG_BUTTON_CANCEL),
-      []{ _service_reset(1); },
-      ui.goto_previous_screen,
-      GET_TEXT(MSG_SERVICE_RESET), sram, PSTR("?")
-    );
-  }
-#endif
-
-#if SERVICE_INTERVAL_2 > 0
-  void menu_service2() {
-    char sram[30];
-    strncpy_P(sram, PSTR(SERVICE_NAME_2), 29);
-    do_select_screen(
-      GET_TEXT(MSG_BUTTON_RESET), GET_TEXT(MSG_BUTTON_CANCEL),
-      []{ _service_reset(2); },
-      ui.goto_previous_screen,
-      GET_TEXT(MSG_SERVICE_RESET), sram, PSTR("?")
-    );
-  }
-#endif
-
-#if SERVICE_INTERVAL_3 > 0
-  void menu_service3() {
-    char sram[30];
-    strncpy_P(sram, PSTR(SERVICE_NAME_3), 29);
-    do_select_screen(
-      GET_TEXT(MSG_BUTTON_RESET), GET_TEXT(MSG_BUTTON_CANCEL),
-      []{ _service_reset(3); },
-      ui.goto_previous_screen,
-      GET_TEXT(MSG_SERVICE_RESET), sram, PSTR("?")
-    );
-  }
-#endif
-
-#endif // HAS_LCD_MENU && HAS_SERVICE_INTERVALS
diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp
index 59e7794d8..8a40d8823 100644
--- a/Marlin/src/lcd/menu/menu_tune.cpp
+++ b/Marlin/src/lcd/menu/menu_tune.cpp
@@ -65,7 +65,7 @@
     }
     if (ui.should_draw()) {
       const float spm = planner.steps_to_mm[axis];
-      draw_edit_screen(msg, ftostr54sign(spm * babystep.accum));
+      MenuEditItemBase::edit_screen(msg, ftostr54sign(spm * babystep.accum));
       #if ENABLED(BABYSTEP_DISPLAY_TOTAL)
         const bool in_view = (true
           #if HAS_GRAPHICAL_LCD
diff --git a/Marlin/src/lcd/menu/menu_ubl.cpp b/Marlin/src/lcd/menu/menu_ubl.cpp
index a24683f99..948dae76a 100644
--- a/Marlin/src/lcd/menu/menu_ubl.cpp
+++ b/Marlin/src/lcd/menu/menu_ubl.cpp
@@ -65,7 +65,7 @@ static void _lcd_mesh_fine_tune(PGM_P msg) {
   }
 
   if (ui.should_draw()) {
-    draw_edit_screen(msg, ftostr43sign(mesh_edit_value));
+    MenuEditItemBase::edit_screen(msg, ftostr43sign(mesh_edit_value));
     #if ENABLED(MESH_EDIT_GFX_OVERLAY)
       _lcd_zoffset_overlay_gfx(mesh_edit_value);
     #endif
diff --git a/buildroot/share/tests/megaatmega2560-tests b/buildroot/share/tests/megaatmega2560-tests
index 14ac826cd..a08f8a231 100755
--- a/buildroot/share/tests/megaatmega2560-tests
+++ b/buildroot/share/tests/megaatmega2560-tests
@@ -32,6 +32,7 @@ opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER LCD_PROGRESS_BAR LCD_PROGRESS_BAR_TE
            BLINKM PCA9632 RGB_LED RGB_LED_R_PIN RGB_LED_G_PIN RGB_LED_B_PIN LED_CONTROL_MENU \
            NEOPIXEL_LED CASE_LIGHT_ENABLE CASE_LIGHT_USE_NEOPIXEL CASE_LIGHT_MENU \
            PID_PARAMS_PER_HOTEND PID_AUTOTUNE_MENU PID_EDIT_MENU LCD_SHOW_E_TOTAL \
+           PRINTCOUNTER SERVICE_NAME_1 SERVICE_INTERVAL_1 LEVEL_BED_CORNERS \
            NOZZLE_PARK_FEATURE FILAMENT_RUNOUT_SENSOR FILAMENT_RUNOUT_DISTANCE_MM \
            ADVANCED_PAUSE_FEATURE FILAMENT_LOAD_UNLOAD_GCODES FILAMENT_UNLOAD_ALL_EXTRUDERS \
            AUTO_BED_LEVELING_BILINEAR Z_MIN_PROBE_REPEATABILITY_TEST DISTINCT_E_FACTORS \