diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 96580905f4..748d3d03cf 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -890,7 +890,7 @@ void kill(FSTR_P const lcd_error/*=nullptr*/, FSTR_P const lcd_component/*=nullp // Echo the LCD message to serial for extra context if (lcd_error) { SERIAL_ECHO_START(); SERIAL_ECHOLNF(lcd_error); } - #if EITHER(HAS_DISPLAY, DWIN_LCD_PROUI) + #if HAS_DISPLAY ui.kill_screen(lcd_error ?: GET_TEXT_F(MSG_KILLED), lcd_component ?: FPSTR(NUL_STR)); #else UNUSED(lcd_error); UNUSED(lcd_component); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 0ae3e301cc..278d982f70 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -763,6 +763,7 @@ void unified_bed_leveling::shift_mesh_height() { TERN_(HAS_MARLINUI_MENU, ui.capture()); TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); + TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained uint8_t count = GRID_MAX_POINTS; @@ -826,6 +827,7 @@ void unified_bed_leveling::shift_mesh_height() { ); TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); + TERN_(DWIN_LCD_PROUI, DWIN_LevelingDone()); } #endif // HAS_BED_PROBE diff --git a/Marlin/src/gcode/probe/G30.cpp b/Marlin/src/gcode/probe/G30.cpp index 474f1f252a..a16853bdf8 100644 --- a/Marlin/src/gcode/probe/G30.cpp +++ b/Marlin/src/gcode/probe/G30.cpp @@ -33,6 +33,10 @@ #include "../../feature/probe_temp_comp.h" #endif +#if ENABLED(DWIN_LCD_PROUI) + #include "../../lcd/marlinui.h" +#endif + /** * G30: Do a single Z probe at the current XY * @@ -48,20 +52,38 @@ void GcodeSuite::G30() { const xy_pos_t pos = { parser.linearval('X', current_position.x + probe.offset_xy.x), parser.linearval('Y', current_position.y + probe.offset_xy.y) }; - if (!probe.can_reach(pos)) return; + if (!probe.can_reach(pos)) { + #if ENABLED(DWIN_LCD_PROUI) + SERIAL_ECHOLNF(GET_EN_TEXT_F(MSG_ZPROBE_OUT)); + LCD_MESSAGE(MSG_ZPROBE_OUT); + #endif + return; + } // Disable leveling so the planner won't mess with us TERN_(HAS_LEVELING, set_bed_leveling_enabled(false)); remember_feedrate_scaling_off(); + TERN_(DWIN_LCD_PROUI, process_subcommands_now(F("G28O"))); + const ProbePtRaise raise_after = parser.boolval('E', true) ? PROBE_PT_STOW : PROBE_PT_NONE; TERN_(HAS_PTC, ptc.set_enabled(!parser.seen('C') || parser.value_bool())); const float measured_z = probe.probe_at_point(pos, raise_after, 1); TERN_(HAS_PTC, ptc.set_enabled(true)); - if (!isnan(measured_z)) + if (!isnan(measured_z)) { SERIAL_ECHOLNPGM("Bed X: ", pos.x, " Y: ", pos.y, " Z: ", measured_z); + #if ENABLED(DWIN_LCD_PROUI) + char msg[31], str_1[6], str_2[6], str_3[6]; + sprintf_P(msg, PSTR("X:%s, Y:%s, Z:%s"), + dtostrf(pos.x, 1, 1, str_1), + dtostrf(pos.y, 1, 1, str_2), + dtostrf(measured_z, 1, 2, str_3) + ); + ui.set_status(msg); + #endif + } restore_feedrate_and_scaling(); diff --git a/Marlin/src/gcode/stats/M31.cpp b/Marlin/src/gcode/stats/M31.cpp index 355701f6a4..1a1c13ba2f 100644 --- a/Marlin/src/gcode/stats/M31.cpp +++ b/Marlin/src/gcode/stats/M31.cpp @@ -33,7 +33,7 @@ void GcodeSuite::M31() { char buffer[22]; duration_t(print_job_timer.duration()).toString(buffer); - ui.set_status(buffer); + ui.set_status(buffer, ENABLED(DWIN_LCD_PROUI)); SERIAL_ECHO_MSG("Print time: ", buffer); } diff --git a/Marlin/src/lcd/e3v2/common/dwin_api.cpp b/Marlin/src/lcd/e3v2/common/dwin_api.cpp index 63a75b89c8..3f699465a9 100644 --- a/Marlin/src/lcd/e3v2/common/dwin_api.cpp +++ b/Marlin/src/lcd/e3v2/common/dwin_api.cpp @@ -234,7 +234,9 @@ void DWIN_Frame_AreaMove(uint8_t mode, uint8_t dir, uint16_t dis, // *string: The string // rlimit: To limit the drawn string length void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, const char * const string, uint16_t rlimit/*=0xFFFF*/) { - DWIN_Draw_Rectangle(1, bColor, x, y, x + (fontWidth(size) * strlen_P(string)), y + fontHeight(size)); + #if DISABLED(DWIN_LCD_PROUI) + DWIN_Draw_Rectangle(1, bColor, x, y, x + (fontWidth(size) * strlen_P(string)), y + fontHeight(size)); + #endif constexpr uint8_t widthAdjust = 0; size_t i = 0; DWIN_Byte(i, 0x11); diff --git a/Marlin/src/lcd/e3v2/proui/dwin.cpp b/Marlin/src/lcd/e3v2/proui/dwin.cpp index 68099f2076..cae29e5b28 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin.cpp @@ -23,8 +23,8 @@ /** * DWIN Enhanced implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 3.15.2 - * Date: 2022/03/01 + * Version: 3.17.2 + * Date: 2022/04/08 */ #include "../../../inc/MarlinConfig.h" @@ -64,7 +64,7 @@ #include "../../../feature/host_actions.h" #endif -#if ANY(AUTO_BED_LEVELING_BILINEAR, AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) && DISABLED(PROBE_MANUALLY) +#if DISABLED(PROBE_MANUALLY) && ANY(AUTO_BED_LEVELING_BILINEAR, AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) #define HAS_ONESTEP_LEVELING 1 #endif @@ -82,11 +82,11 @@ #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) + #if ENABLED(BABYSTEPPING) #include "../../../feature/babystep.h" + #if !HAS_BED_PROBE + #define JUST_BABYSTEP 1 + #endif #endif #endif @@ -94,10 +94,6 @@ #include "../../../feature/powerloss.h" #endif -#if HAS_GCODE_PREVIEW - #include "gcode_preview.h" -#endif - #if HAS_ESDIAG #include "endstop_diag.h" #endif @@ -106,6 +102,10 @@ #include "meshviewer.h" #endif +#if ENABLED(AUTO_BED_LEVELING_UBL) + #include "ubl_tools.h" +#endif + #if ENABLED(PRINTCOUNTER) #include "printstats.h" #endif @@ -143,29 +143,26 @@ // Load and Unload limits #define MAX_LOAD_UNLOAD 500 -// Feedspeed limit (max feedspeed = DEFAULT_MAX_FEEDRATE * 2) +// Feedspeed limit (max feedspeed = MAX_FEEDRATE_EDIT_VALUES) #define MIN_MAXFEEDSPEED 1 #define MIN_MAXACCELERATION 1 #define MIN_MAXJERK 0.1 #define MIN_STEP 1 #define MAX_STEP 999.9 -// Extruder's temperature limits -#define MIN_ETEMP HEATER_0_MINTEMP -#define MAX_ETEMP (HEATER_0_MAXTEMP - HOTEND_OVERSHOOT) +// Editable temperature limits +#define MIN_ETEMP 0 +#define MAX_ETEMP (HEATER_0_MAXTEMP - (HOTEND_OVERSHOOT)) +#define MIN_BEDTEMP 0 +#define MAX_BEDTEMP BED_MAX_TARGET #define FEEDRATE_E (60) -// Minimum unit (0.1) : multiple (10) -#define UNITFDIGITS 1 -#define MINUNITMULT POW(10, UNITFDIGITS) - -#define ENCODER_WAIT_MS 20 #define DWIN_VAR_UPDATE_INTERVAL 1024 #define DWIN_SCROLL_UPDATE_INTERVAL SEC_TO_MS(2) #define DWIN_REMAIN_TIME_UPDATE_INTERVAL SEC_TO_MS(20) -#define BABY_Z_VAR TERN(HAS_BED_PROBE, probe.offset.z, dwin_zoffset) +#define BABY_Z_VAR TERN(HAS_BED_PROBE, probe.offset.z, HMI_data.ManualZOffset) // Structs HMI_value_t HMI_value; @@ -203,11 +200,11 @@ uint8_t index_file = MROWS; bool hash_changed = true; // Flag to know if message status was changed -constexpr float max_feedrate_edit_values[] = DEFAULT_MAX_FEEDRATE; -constexpr float max_acceleration_edit_values[] = DEFAULT_MAX_ACCELERATION; +constexpr float max_feedrate_edit_values[] = MAX_FEEDRATE_EDIT_VALUES; +constexpr float max_acceleration_edit_values[] = MAX_ACCEL_EDIT_VALUES; #if HAS_CLASSIC_JERK - constexpr float max_jerk_edit_values[] = { DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK, DEFAULT_EJERK }; + constexpr float max_jerk_edit_values[] = MAX_JERK_EDIT_VALUES; #endif static uint8_t _percent_done = 0; @@ -216,10 +213,6 @@ static uint32_t _remain_time = 0; // Additional Aux Host Support static bool sdprint = false; -#if HAS_ZOFFSET_ITEM - float dwin_zoffset = 0, last_zoffset = 0; -#endif - #if HAS_HOTEND float last_E = 0; #endif @@ -267,12 +260,22 @@ MenuClass *BedPIDMenu = nullptr; #if ENABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU) MenuClass *HomingMenu = nullptr; #endif +#if ENABLED(FWRETRACT) + MenuClass *FWRetractMenu = nullptr; +#endif +#if HAS_MESH + MenuClass *MeshMenu = nullptr; + #if ENABLED(MESH_EDIT_MENU) + MenuClass *EditMeshMenu = nullptr; + #endif +#endif // Updatable menuitems pointers MenuItemClass *HotendTargetItem = nullptr; MenuItemClass *BedTargetItem = nullptr; MenuItemClass *FanSpeedItem = nullptr; MenuItemClass *MMeshMoveZItem = nullptr; +MenuItemClass *EditZValueItem = nullptr; #define DWIN_LANGUAGE_EEPROM_ADDRESS 0x01 // Between 0x01 and 0x63 (EEPROM_OFFSET-1) // BL24CXX::check() uses 0x00 @@ -493,6 +496,11 @@ void DWIN_DrawStatusLine(const char *text) { if (text) DWINUI::Draw_CenteredString(HMI_data.StatusTxt_Color, STATUS_Y + 2, text); } +void DWIN_DrawStatusLine(FSTR_P fstr) { + DWIN_Draw_Rectangle(1, HMI_data.StatusBg_Color, 0, STATUS_Y, DWIN_WIDTH, STATUS_Y + 20); + if (fstr) DWINUI::Draw_CenteredString(HMI_data.StatusTxt_Color, STATUS_Y + 2, fstr); +} + // Clear & reset status line void DWIN_ResetStatusLine() { ui.status_message[0] = 0; @@ -631,6 +639,7 @@ void Goto_PrintProcess() { else { checkkey = PrintProcess; Draw_PrintProcess(); + TERN_(DASH_REDRAW, DWIN_RedrawDash()); } DWIN_UpdateLCD(); } @@ -649,8 +658,7 @@ void Draw_PrintDone() { DWINUI::Draw_Icon(ICON_RemainTime, 150, 171); Draw_Print_ProgressElapsed(); Draw_Print_ProgressRemain(); - // show print done confirm - DWINUI::Draw_Button(BTN_Confirm, 86, 273); + DWINUI::Draw_Button(BTN_Continue, 86, 273); } void Goto_PrintDone() { @@ -746,16 +754,13 @@ void update_variable() { if (checkkey == Menu && (CurrentMenu == TuneMenu || CurrentMenu == TemperatureMenu)) { // Tune page temperature update #if HAS_HOTEND - if (_new_hotend_target) - HotendTargetItem->draw(CurrentMenu->line(HotendTargetItem->pos)); + if (_new_hotend_target) HotendTargetItem->redraw(); #endif #if HAS_HEATED_BED - if (_new_bed_target) - BedTargetItem->draw(CurrentMenu->line(BedTargetItem->pos)); + if (_new_bed_target) BedTargetItem->redraw(); #endif #if HAS_FAN - if (_new_fanspeed) - FanSpeedItem->draw(CurrentMenu->line(FanSpeedItem->pos)); + if (_new_fanspeed) FanSpeedItem->redraw(); #endif } @@ -1013,7 +1018,7 @@ void DWIN_Draw_Dashboard() { DWINUI::Draw_Icon(ICON_BedTemp, 10, 416); DWINUI::Draw_Int(DWIN_FONT_STAT, HMI_data.Indicator_Color, HMI_data.Background_Color, 3, 28, 417, thermalManager.wholeDegBed()); DWINUI::Draw_String(DWIN_FONT_STAT, HMI_data.Indicator_Color, HMI_data.Background_Color, 25 + 3 * STAT_CHR_W + 5, 417, F("/")); - DWINUI::Draw_Int(true, true, 0, DWIN_FONT_STAT, HMI_data.Indicator_Color, HMI_data.Background_Color, 3, 25 + 4 * STAT_CHR_W + 6, 417, thermalManager.degTargetBed()); + DWINUI::Draw_Int(DWIN_FONT_STAT, HMI_data.Indicator_Color, HMI_data.Background_Color, 3, 25 + 4 * STAT_CHR_W + 6, 417, thermalManager.degTargetBed()); #endif DWINUI::Draw_Icon(ICON_Speed, 113, 383); @@ -1025,7 +1030,7 @@ void DWIN_Draw_Dashboard() { DWINUI::Draw_Int(DWIN_FONT_STAT, HMI_data.Indicator_Color, HMI_data.Background_Color, 3, 195 + 2 * STAT_CHR_W, 384, thermalManager.fan_speed[0]); #endif - #if HAS_ZOFFSET_ITEM + #if BOTH(BABYSTEPPING, HAS_BED_PROBE) DWINUI::Draw_Icon(planner.leveling_active ? ICON_SetZOffset : ICON_Zoffset, 187, 416); #endif @@ -1075,6 +1080,7 @@ void Draw_Print_File_Menu() { else Title.ShowCaption(GET_TEXT_F(MSG_MEDIA_MENU)); Redraw_SD_List(); + TERN_(DASH_REDRAW, DWIN_RedrawDash()); } // Main Process @@ -1285,8 +1291,6 @@ void HMI_Printing() { #include "../../../libs/buzzer.h" -void HMI_AudioFeedback(const bool success/*=true*/) { DONE_BUZZ(success); } - void Draw_Main_Area() { switch (checkkey) { case MainMenu: Draw_Main_Menu(); break; @@ -1303,7 +1307,7 @@ void Draw_Main_Area() { case SetPInt: case SetIntNoDraw: case SetFloat: - case SetPFloat: CurrentMenu->draw(); break; + case SetPFloat: ReDrawMenu(); break; default: break; } } @@ -1322,15 +1326,8 @@ void HMI_WaitForUser() { 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; + TERN_(HAS_ONESTEP_LEVELING, case Leveling:) + default: HMI_ReturnScreen(); break; } } } @@ -1354,17 +1351,17 @@ void EachMomentUpdate() { if (ELAPSED(ms, next_var_update_ms)) { next_var_update_ms = ms + DWIN_VAR_UPDATE_INTERVAL; update_variable(); - switch (checkkey) { - #if HAS_ESDIAG - case ESDiagProcess: - ESDiag.Update(); - break; - #endif - default: - break; - } + #if HAS_ESDIAG + if (checkkey == ESDiagProcess) ESDiag.Update(); + #endif } + #if HAS_STATUS_MESSAGE_TIMEOUT + bool did_expire = ui.status_reset_callback && (*ui.status_reset_callback)(); + did_expire |= ui.status_message_expire_ms && ELAPSED(ms, ui.status_message_expire_ms); + if (did_expire) ui.reset_status(); + #endif + if (ELAPSED(ms, next_status_update_ms)) { next_status_update_ms = ms + 500; DWIN_DrawStatusMessage(); @@ -1402,7 +1399,7 @@ void EachMomentUpdate() { duration_t elapsed = print_job_timer.duration(); // print timer - if (sdprint && card.isPrinting()) { + if (sdprint && card.isPrinting() && !HMI_flag.percent_flag) { uint8_t percentDone = card.percentDone(); if (_percent_done != percentDone) { // print percent _percent_done = percentDone; @@ -1497,8 +1494,7 @@ void DWIN_HandleScreen() { case SelectFile: HMI_SelectFile(); break; case PrintProcess: HMI_Printing(); break; case Popup: HMI_Popup(); break; - case Leveling: //TERN_(ProUI, HMI_WaitForUser()); - break; + case Leveling: break; case Locked: HMI_LockScreen(); break; case PrintDone: TERN_(HAS_ESDIAG, case ESDiagProcess:) @@ -1541,7 +1537,10 @@ void DWIN_HomingStart() { void DWIN_HomingDone() { HMI_flag.home_flag = false; - dwin_zoffset = TERN0(HAS_BED_PROBE, probe.offset.z); + #if ENABLED(MESH_BED_LEVELING) && EITHER(BABYSTEP_ZPROBE_OFFSET, JUST_BABYSTEP) + planner.synchronize(); + babystep.add_mm(Z_AXIS, HMI_data.ManualZOffset); + #endif if (HMI_flag.abort_action) DWIN_Print_Aborted(); else HMI_ReturnScreen(); } @@ -1550,13 +1549,25 @@ void DWIN_LevelingStart() { 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)); + #if BOTH(AUTO_BED_LEVELING_UBL, PREHEAT_BEFORE_LEVELING) + #if HAS_HOTEND + if (thermalManager.degTargetHotend(0) < LEVELING_NOZZLE_TEMP) + thermalManager.setTargetHotend(LEVELING_NOZZLE_TEMP, 0); + #endif + #if HAS_HEATED_BED + if (thermalManager.degTargetBed() < HMI_data.BedLevT) + thermalManager.setTargetBed(HMI_data.BedLevT); + #endif + TERN_(HAS_HOTEND, thermalManager.wait_for_hotend(0)); + TERN_(HAS_HEATED_BED, thermalManager.wait_for_bed_heating()); + #endif #elif ENABLED(MESH_BED_LEVELING) Draw_ManualMesh_Menu(); #endif } void DWIN_LevelingDone() { - TERN_(HAS_ONESTEP_LEVELING, if (planner.leveling_active) Goto_MeshViewer()); + TERN_(HAS_MESH, Goto_MeshViewer()); } #if HAS_MESH @@ -1606,6 +1617,7 @@ void DWIN_Print_Started(const bool sd) { sdprint = IS_SD_PRINTING() || sd; _percent_done = 0; _remain_time = 0; + HMI_flag.percent_flag = false; HMI_flag.remain_flag = false; HMI_flag.pause_flag = false; HMI_flag.pause_action = false; @@ -1653,9 +1665,12 @@ void DWIN_Print_Aborted() { // Progress Bar update void DWIN_M73() { - if (parser.seenval('P')) _percent_done = parser.byteval('P'); + if (parser.seenval('P')) { + _percent_done = parser.value_byte(); + HMI_flag.percent_flag = true; + } if (parser.seenval('R')) { - _remain_time = parser.ulongval('R') * 60; + _remain_time = parser.value_ulong() * 60; HMI_flag.remain_flag = true; } if (checkkey == PrintProcess) { @@ -1705,16 +1720,18 @@ void DWIN_SetDataDefaults() { HMI_data.BedLevT = LEVELING_BED_TEMP; #endif TERN_(BAUD_RATE_GCODE, SetBaud250K()); + #if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS) + leds.set_default(); + ApplyLEDColor(); + #endif } void DWIN_CopySettingsTo(char * const buff) { - memcpy(buff, &HMI_data, _MIN(sizeof(HMI_data), eeprom_data_size)); + memcpy(buff, &HMI_data, eeprom_data_size); } void DWIN_CopySettingsFrom(const char * const buff) { - // (void *)-> Avoid Warning when save data different from uintX_t in HMI_data_t struct - memcpy((void *)&HMI_data, buff, _MIN(sizeof(HMI_data), eeprom_data_size)); - dwin_zoffset = TERN0(HAS_BED_PROBE, probe.offset.z); + memcpy(&HMI_data, buff, sizeof(HMI_data_t)); if (HMI_data.Text_Color == HMI_data.Background_Color) DWIN_SetColorDefaults(); DWINUI::SetColors(HMI_data.Text_Color, HMI_data.Background_Color, HMI_data.StatusBg_Color); TERN_(PREVENT_COLD_EXTRUSION, ApplyExtMinT()); @@ -1726,8 +1743,13 @@ void DWIN_CopySettingsFrom(const char * const buff) { caselight.update_brightness(); #endif #if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS) - // Apply Led Color - leds.set_color(HMI_data.Led_Color); + leds.set_color( + (HMI_data.LED_Color >> 16) & 0xFF, + (HMI_data.LED_Color >> 8) & 0xFF, + (HMI_data.LED_Color >> 0) & 0xFF + OPTARG(HAS_WHITE_LED, (HMI_data.LED_Color >> 24) & 0xFF) + ); + leds.update(); #endif } @@ -1742,11 +1764,17 @@ void MarlinUI::init_lcd() { void DWIN_InitScreen() { HMI_Init(); // draws boot screen - DWINUI::onCursorDraw = Draw_Menu_Cursor; - DWINUI::onCursorErase = Erase_Menu_Cursor; + onCursorDraw = Draw_Menu_Cursor; + onCursorErase = Erase_Menu_Cursor; DWINUI::onTitleDraw = Draw_Title; - DWINUI::onMenuDraw = Draw_Menu; - DWIN_DrawStatusLine(nullptr); + onMenuDraw = Draw_Menu; + checkkey = 255; + CurrentMenu = nullptr; + PreviousMenu = nullptr; + index_file = MROWS; + hash_changed = true; + last_E = 0; + DWIN_DrawStatusLine(FSTR_P(nullptr)); DWIN_Draw_Dashboard(); Goto_Main_Menu(); } @@ -1764,8 +1792,8 @@ void MarlinUI::refresh() { /* Nothing to see here */ } #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")); + DWIN_Draw_Popup(ICON_BLTouch, GET_TEXT_F(MSG_PRINTER_KILLED), lcd_error); + DWINUI::Draw_CenteredString(HMI_data.PopupTxt_Color, 270, GET_TEXT_F(MSG_TURN_OFF)); DWIN_UpdateLCD(); } @@ -1777,13 +1805,17 @@ void DWIN_RebootScreen() { safe_delay(500); } -void DWIN_RedrawScreen() { - Draw_Main_Area(); +void DWIN_RedrawDash() { hash_changed = true; DWIN_DrawStatusMessage(); DWIN_Draw_Dashboard(); } +void DWIN_RedrawScreen() { + Draw_Main_Area(); + DWIN_RedrawDash(); +} + #if ENABLED(ADVANCED_PAUSE_FEATURE) void DWIN_Popup_Pause(FSTR_P const fmsg, uint8_t button /*= 0*/) { HMI_SaveProcessID(button ? WaitResponse : NothingToDo); @@ -1810,15 +1842,15 @@ void DWIN_RedrawScreen() { 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), BTN_Continue); break; - case PAUSE_MESSAGE_HEATING: LCD_MESSAGE(MSG_FILAMENT_CHANGE_HEATING); break; + case PAUSE_MESSAGE_HEATING: DWIN_Popup_Pause(GET_TEXT_F(MSG_FILAMENT_CHANGE_HEATING)); 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_Button(BTN_Confirm, 26, 280); + DWIN_Draw_Popup(ICON_BLTouch, GET_TEXT_F(MSG_ADVANCED_PAUSE), GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE_CONTINUE)); + DWINUI::Draw_Button(BTN_Purge, 26, 280); DWINUI::Draw_Button(BTN_Continue, 146, 280); Draw_Select_Highlight(true); } @@ -1893,21 +1925,26 @@ void Goto_ConfirmToPrint() { #if ENABLED(EEPROM_SETTINGS) void WriteEeprom() { - const bool success = settings.save(); - HMI_AudioFeedback(success); + DWIN_DrawStatusLine(GET_TEXT_F(MSG_STORE_EEPROM)); + DWIN_UpdateLCD(); + DONE_BUZZ(settings.save()); } void ReadEeprom() { const bool success = settings.load(); DWIN_RedrawScreen(); - HMI_AudioFeedback(success); + DONE_BUZZ(success); } void ResetEeprom() { settings.reset(); DWIN_RedrawScreen(); - HMI_AudioFeedback(); + DONE_BUZZ(true); } + + #if HAS_MESH + void SaveMesh() { TERN(AUTO_BED_LEVELING_UBL, UBLSaveMesh(), WriteEeprom()); } + #endif #endif // Reset Printer @@ -1919,22 +1956,24 @@ void RebootPrinter() { hal.reboot(); } -void Goto_Info_Menu(){ +void Goto_Info_Menu() { Draw_Info_Menu(); + DWIN_UpdateLCD(); HMI_SaveProcessID(WaitResponse); } void Goto_Move_Menu() { #if HAS_HOTEND gcode.process_subcommands_now(F("G92E0")); // reset extruder position - planner.synchronize(); #endif Draw_Move_Menu(); } void DisableMotors() { queue.inject(F("M84")); } -void AutoLev() { queue.inject(F("G28XYO\nG28Z\nG29")); } // Force to get the current Z home position +void AutoLev() { // Always reacquire the Z "home" position + queue.inject(F(TERN(AUTO_BED_LEVELING_UBL, "G28Z\nG29P1", "G28XYO\nG28Z\nG29"))); +} void AutoHome() { queue.inject_P(G28_STR); } void HomeX() { queue.inject(F("G28X")); } @@ -1944,48 +1983,56 @@ void HomeZ() { queue.inject(F("G28Z")); } void SetHome() { // Apply workspace offset, making the current position 0,0,0 queue.inject(F("G92X0Y0Z0")); - HMI_AudioFeedback(); + DONE_BUZZ(true); } #if HAS_ZOFFSET_ITEM void ApplyZOffset() { TERN_(EEPROM_SETTINGS, settings.save()); } void LiveZOffset() { - last_zoffset = dwin_zoffset; - 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); + const_float_t step_zoffset = round((MenuData.Value / 100.0f) * planner.settings.axis_steps_per_mm[Z_AXIS]) - babystep.accum; + if (BABYSTEP_ALLOWED()) babystep.add_steps(Z_AXIS, step_zoffset); #endif } - #if EITHER(HAS_BED_PROBE, BABYSTEPPING) + + #if EITHER(BABYSTEP_ZPROBE_OFFSET, JUST_BABYSTEP) void SetZOffset() { + babystep.accum = round(planner.settings.axis_steps_per_mm[Z_AXIS] * BABY_Z_VAR); 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); + #if ENABLED(Z_SAFE_HOMING) + char cmd[54], str_1[5], str_2[5]; + sprintf_P(cmd, PSTR("G28XYO\nG28Z\nG0X%sY%sF5000\nM420S0\nG0Z0F300\nM400"), + dtostrf(Z_SAFE_HOMING_X_POINT, 1, 1, str_1), + dtostrf(Z_SAFE_HOMING_Y_POINT, 1, 1, str_2) + ); + gcode.process_subcommands_now(cmd); + #else + gcode.process_subcommands_now(F("G28O\nM420S0\nG0Z0F300\nM400")); + #endif + ui.reset_status(); + DONE_BUZZ(true); } -#endif + + void HomeZandDisable() { + SetMoveZto0(); + DisableMotors(); + } + +#endif // HAS_ZOFFSET_ITEM #if HAS_PREHEAT void DoPreheat0() { ui.preheat_all(0); } - void DoPreheat1() { ui.preheat_all(1); } - void DoPreheat2() { ui.preheat_all(2); } + #if PREHEAT_COUNT >= 2 + void DoPreheat1() { ui.preheat_all(1); } + #if PREHEAT_COUNT >= 3 + void DoPreheat2() { ui.preheat_all(2); } + #endif + #endif #endif void DoCoolDown() { thermalManager.cooldown(); } @@ -2010,9 +2057,9 @@ void ApplyMoveE() { planner.buffer_line(current_position, MMM_TO_MMS(FEEDRATE_E)); } } -void SetMoveX() { HMI_value.axis = X_AXIS; SetPFloatOnClick(X_MIN_POS, X_MAX_POS, UNITFDIGITS, planner.synchronize, LiveMove);} -void SetMoveY() { HMI_value.axis = Y_AXIS; SetPFloatOnClick(Y_MIN_POS, Y_MAX_POS, UNITFDIGITS, planner.synchronize, LiveMove);} -void SetMoveZ() { HMI_value.axis = Z_AXIS; SetPFloatOnClick(Z_MIN_POS, Z_MAX_POS, UNITFDIGITS, planner.synchronize, LiveMove);} +void SetMoveX() { HMI_value.axis = X_AXIS; SetPFloatOnClick(X_MIN_POS, X_MAX_POS, UNITFDIGITS, planner.synchronize, LiveMove); } +void SetMoveY() { HMI_value.axis = Y_AXIS; SetPFloatOnClick(Y_MIN_POS, Y_MAX_POS, UNITFDIGITS, planner.synchronize, LiveMove); } +void SetMoveZ() { HMI_value.axis = Z_AXIS; SetPFloatOnClick(Z_MIN_POS, Z_MAX_POS, UNITFDIGITS, planner.synchronize, LiveMove); } #if HAS_HOTEND void SetMoveE() { @@ -2025,14 +2072,13 @@ void SetMoveZ() { HMI_value.axis = Z_AXIS; SetPFloatOnClick(Z_MIN_POS, Z_MAX_POS #endif void SetPID(celsius_t t, heater_id_t h) { - char cmd[48] = ""; + char cmd[53] = ""; char str_1[5] = "", str_2[5] = ""; - sprintf_P(cmd, PSTR("G28OXY\nG0Z5F300\nG0X%sY%sF5000\nM84"), + sprintf_P(cmd, PSTR("G28OXY\nG0Z5F300\nG0X%sY%sF5000\nM84\nM400"), dtostrf(X_CENTER, 1, 1, str_1), dtostrf(Y_CENTER, 1, 1, str_2) ); gcode.process_subcommands_now(cmd); - planner.synchronize(); thermalManager.PID_autotune(t, h, HMI_data.PidCycles, true); } #if HAS_HOTEND @@ -2078,7 +2124,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 = MenuData.Value; caselight.update_brightness(); } + void LiveCaseLightBrightness() { caselight.brightness = MenuData.Value; caselight.update_brightness(); } void SetCaseLightBrightness() { SetIntOnClick(0, 255, caselight.brightness, nullptr, LiveCaseLightBrightness); } #endif #endif @@ -2092,15 +2138,17 @@ void SetPID(celsius_t t, heater_id_t h) { } #endif #if HAS_COLOR_LEDS - 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 = 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 = MenuData.Value; HMI_data.Led_Color = leds.color; leds.update(); } - void SetLedColorB() { SetIntOnClick(0, 255, leds.color.b, nullptr, LiveLedColorB); } + void ApplyLEDColor() { HMI_data.LED_Color = TERN0(HAS_WHITE_LED, (leds.color.w << 24)) | (leds.color.r << 16) | (leds.color.g << 8) | leds.color.b; } + void LiveLEDColor(uint8_t *color) { *color = MenuData.Value; leds.update(); } + void LiveLEDColorR() { LiveLEDColor(&leds.color.r); } + void LiveLEDColorG() { LiveLEDColor(&leds.color.g); } + void LiveLEDColorB() { LiveLEDColor(&leds.color.b); } + void SetLEDColorR() { SetIntOnClick(0, 255, leds.color.r, ApplyLEDColor, LiveLEDColorR); } + void SetLEDColorG() { SetIntOnClick(0, 255, leds.color.g, ApplyLEDColor, LiveLEDColorG); } + void SetLEDColorB() { SetIntOnClick(0, 255, leds.color.b, ApplyLEDColor, LiveLEDColorB); } #if HAS_WHITE_LED - 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); } + void LiveLEDColorW() { LiveLEDColor(&leds.color.w); } + void SetLEDColorW() { SetIntOnClick(0, 255, leds.color.w, ApplyLEDColor, LiveLEDColorW); } #endif #endif #endif @@ -2139,10 +2187,6 @@ void SetPID(celsius_t t, heater_id_t h) { } #endif - #if BOTH(HAS_HEATED_BED, PREHEAT_BEFORE_LEVELING) - void SetBedLevT() { SetPIntOnClick(BED_MINTEMP, BED_MAX_TARGET); } - #endif - #endif #if HAS_FILAMENT_SENSOR @@ -2197,7 +2241,7 @@ void DWIN_ApplyColor() { 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)); + LCD_MESSAGE(MSG_COLORS_APPLIED); DWIN_Draw_Dashboard(); } @@ -2210,7 +2254,7 @@ void SetSpeed() { SetPIntOnClick(MIN_PRINT_SPEED, MAX_PRINT_SPEED); } #if HAS_HEATED_BED void ApplyBedTemp() { thermalManager.setTargetBed(MenuData.Value); } - void SetBedTemp() { SetIntOnClick(BED_MINTEMP, BED_MAX_TARGET, thermalManager.degTargetBed(), ApplyBedTemp); } + void SetBedTemp() { SetIntOnClick(MIN_BEDTEMP, MAX_BEDTEMP, thermalManager.degTargetBed(), ApplyBedTemp); } #endif #if HAS_FAN @@ -2225,18 +2269,18 @@ void SetSpeed() { SetPIntOnClick(MIN_PRINT_SPEED, MAX_PRINT_SPEED); } queue.inject(F("M600 B2")); } - void ParkHead(){ + void ParkHead() { LCD_MESSAGE(MSG_FILAMENT_PARK_ENABLED); queue.inject(F("G28O\nG27")); } #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) - void UnloadFilament(){ + void UnloadFilament() { LCD_MESSAGE(MSG_FILAMENTUNLOAD); queue.inject(F("M702 Z20")); } - void LoadFilament(){ + void LoadFilament() { LCD_MESSAGE(MSG_FILAMENTLOAD); queue.inject(F("M701 Z20")); } @@ -2248,9 +2292,9 @@ void ApplyFlow() { planner.refresh_e_factor(0); } void SetFlow() { SetPIntOnClick(MIN_PRINT_FLOW, MAX_PRINT_FLOW, ApplyFlow); } // Bed Tramming -TERN(HAS_ONESTEP_LEVELING, float, void) Tram(uint8_t point) { +TERN(HAS_BED_PROBE, float, void) Tram(uint8_t point) { char cmd[100] = ""; - #if HAS_ONESTEP_LEVELING + #if HAS_BED_PROBE static bool inLev = false; float xpos = 0, ypos = 0, zval = 0, margin = 0; char str_1[6] = "", str_2[6] = "", str_3[6] = ""; @@ -2286,7 +2330,7 @@ TERN(HAS_ONESTEP_LEVELING, float, void) Tram(uint8_t point) { planner.synchronize(); - #if HAS_ONESTEP_LEVELING + #if HAS_BED_PROBE if (HMI_data.FullManualTramming) { planner.synchronize(); @@ -2297,15 +2341,14 @@ TERN(HAS_ONESTEP_LEVELING, float, void) Tram(uint8_t point) { 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)); + LIMIT(xpos, MESH_MIN_X, MESH_MAX_X); + LIMIT(ypos, MESH_MIN_Y, MESH_MAX_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)) - LCD_MESSAGE_F("Position Not Reachable, check offsets"); + LCD_MESSAGE(MSG_ZPROBE_OUT); else { sprintf_P(cmd, PSTR("X:%s, Y:%s, Z:%s"), dtostrf(xpos, 1, 1, str_1), @@ -2318,7 +2361,7 @@ TERN(HAS_ONESTEP_LEVELING, float, void) Tram(uint8_t point) { } return zval; - #else + #else // !HAS_BED_PROBE sprintf_P(cmd, PSTR("M420S0\nG28O\nG90\nG0Z5F300\nG0X%iY%iF5000\nG0Z0F300"), xpos, ypos); queue.inject(cmd); @@ -2332,7 +2375,7 @@ void TramBR() { Tram(2); } void TramBL() { Tram(3); } void TramC () { Tram(4); } -#if HAS_ONESTEP_LEVELING +#if HAS_BED_PROBE void Trammingwizard() { bed_mesh_t zval = {0}; @@ -2349,22 +2392,30 @@ void TramC () { Tram(4); } 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) - ); + + DWINUI::Draw_CenteredString(140, F("Calculating average")); + DWINUI::Draw_CenteredString(160, F("and relative heights")); + safe_delay(1000); + float avg = 0.0f; + LOOP_L_N(x, 2) LOOP_L_N(y, 2) avg += zval[x][y]; + avg /= 4.0f; + LOOP_L_N(x, 2) LOOP_L_N(y, 2) zval[x][y] -= avg; + MeshViewer.DrawMesh(zval, 2, 2); + ui.reset_status(); + 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; + float max = 0; FSTR_P plabel; - LOOP_L_N(x,2) LOOP_L_N(y,2) { - d = ABS(zval[x][y] - MeshViewer.avg); + bool s = true; + LOOP_L_N(x, 2) LOOP_L_N(y, 2) { + const float d = ABS(zval[x][y]); if (max < d) { + s = (zval[x][y] >= 0); max = d; p = x + 2 * y; } @@ -2376,9 +2427,10 @@ void TramC () { Tram(4); } 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_CenteredString(120, F("Corners not leveled")); + DWINUI::Draw_CenteredString(140, F("Knob adjustment required")); + DWINUI::Draw_CenteredString(Color_Green, 160, s ? F("Lower") : F("Raise")); + DWINUI::Draw_CenteredString(Color_Green, 180, plabel); } DWINUI::Draw_Button(BTN_Continue, 86, 305); checkkey = Menu; @@ -2391,14 +2443,13 @@ void TramC () { Tram(4); } DWIN_UpdateLCD(); } -#endif // HAS_ONESTEP_LEVELING +#endif // HAS_BED_PROBE #if ENABLED(MESH_BED_LEVELING) - void ManualMeshStart(){ + void ManualMeshStart() { LCD_MESSAGE(MSG_UBL_BUILD_MESH_MENU); gcode.process_subcommands_now(F("G28XYO\nG28Z\nM211S0\nG29S1")); - planner.synchronize(); #ifdef MANUAL_PROBE_START_Z const uint8_t line = CurrentMenu->line(MMeshMoveZItem->pos); DWINUI::Draw_Signed_Float(HMI_data.Text_Color, HMI_data.Background_Color, 3, 2, VALX - 2 * DWINUI::fontWidth(DWIN_FONT_MENU), MBASE(line), MANUAL_PROBE_START_Z); @@ -2412,15 +2463,14 @@ void TramC () { Tram(4); } planner.buffer_line(current_position, homing_feedrate(Z_AXIS)); } } - void SetMMeshMoveZ() { SetPFloatOnClick(-1, 1, 2, planner.synchronize, LiveMeshMoveZ);} + void SetMMeshMoveZ() { SetPFloatOnClick(-1, 1, 2, planner.synchronize, LiveMeshMoveZ); } - void ManualMeshContinue(){ + void ManualMeshContinue() { gcode.process_subcommands_now(F("G29S2")); - planner.synchronize(); - MMeshMoveZItem->draw(CurrentMenu->line(MMeshMoveZItem->pos)); + MMeshMoveZItem->redraw(); } - void ManualMeshSave(){ + void ManualMeshSave() { LCD_MESSAGE(MSG_UBL_STORAGE_MESH_MENU); queue.inject(F("M211S1\nM500")); } @@ -2432,7 +2482,7 @@ void TramC () { Tram(4); } void SetPreheatEndTemp() { SetPIntOnClick(MIN_ETEMP, MAX_ETEMP); } #endif #if HAS_HEATED_BED - void SetPreheatBedTemp() { SetPIntOnClick(BED_MINTEMP, BED_MAX_TARGET); } + void SetPreheatBedTemp() { SetPIntOnClick(MIN_BEDTEMP, MAX_BEDTEMP); } #endif #if HAS_FAN void SetPreheatFanSpeed() { SetPIntOnClick(0, 255); } @@ -2473,7 +2523,7 @@ void SetStepsZ() { HMI_value.axis = Z_AXIS, SetPFloatOnClick( MIN_STEP, MAX_STEP void SetHotendPidT() { SetPIntOnClick(MIN_ETEMP, MAX_ETEMP); } #endif #if HAS_HEATED_BED - void SetBedPidT() { SetPIntOnClick(BED_MINTEMP, BED_MAX_TARGET); } + void SetBedPidT() { SetPIntOnClick(MIN_BEDTEMP, MAX_BEDTEMP); } #endif #if HAS_HOTEND || HAS_HEATED_BED @@ -2500,10 +2550,12 @@ void SetStepsZ() { HMI_value.axis = Z_AXIS, SetPFloatOnClick( MIN_STEP, MAX_STEP #endif #if ENABLED(FWRETRACT) - void SetRetractLength() { SetPFloatOnClick( 0, 10, UNITFDIGITS); }; - void SetRetractSpeed() { SetPFloatOnClick( 1, 90, UNITFDIGITS); }; - void SetZRaise() { SetPFloatOnClick( 0, 2, 2); }; - void SetRecoverSpeed() { SetPFloatOnClick( 1, 90, UNITFDIGITS); }; + void Return_FWRetract_Menu() { (PreviousMenu == FilSetMenu) ? Draw_FilSet_Menu() : Draw_Tune_Menu(); } + void SetRetractLength() { SetPFloatOnClick( 0, 10, UNITFDIGITS); } + void SetRetractSpeed() { SetPFloatOnClick( 1, 90, UNITFDIGITS); } + void SetZRaise() { SetPFloatOnClick( 0, 2, 2); } + void SetRecoverSpeed() { SetPFloatOnClick( 1, 90, UNITFDIGITS); } + void SetAddRecover() { SetPFloatOnClick(-5, 5, UNITFDIGITS); } #endif // Special Menuitem Drawing functions ================================================= @@ -2583,7 +2635,7 @@ void onDrawAutoHome(MenuItemClass* menuitem, int8_t line) { } #if HAS_ZOFFSET_ITEM - #if EITHER(HAS_BED_PROBE, BABYSTEPPING) + #if EITHER(BABYSTEP_ZPROBE_OFFSET, JUST_BABYSTEP) void onDrawZOffset(MenuItemClass* menuitem, int8_t line) { if (HMI_IsChinese()) menuitem->SetFrame(1, 174, 164, 223, 177); onDrawPFloat2Menu(menuitem, line); @@ -2601,10 +2653,12 @@ void onDrawAutoHome(MenuItemClass* menuitem, int8_t line) { if (HMI_IsChinese()) menuitem->SetFrame(1, 100, 89, 151, 101); onDrawMenuItem(menuitem, line); } - void onDrawPreheat2(MenuItemClass* menuitem, int8_t line) { - if (HMI_IsChinese()) menuitem->SetFrame(1, 180, 89, 233, 100); - onDrawMenuItem(menuitem, line); - } + #if PREHEAT_COUNT > 1 + void onDrawPreheat2(MenuItemClass* menuitem, int8_t line) { + if (HMI_IsChinese()) menuitem->SetFrame(1, 180, 89, 233, 100); + onDrawMenuItem(menuitem, line); + } + #endif #endif #if HAS_PREHEAT @@ -2620,32 +2674,6 @@ void onDrawLanguage(MenuItemClass* menuitem, int8_t line) { DWINUI::Draw_String(VALX, MBASE(line), HMI_IsChinese() ? F("CN") : F("EN")); } -#if ENABLED(POWER_LOSS_RECOVERY) - 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 - -#if ENABLED(LED_CONTROL_MENU) - #if !BOTH(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) - void onDrawLedStatus(MenuItemClass* menuitem, int8_t line) { onDrawChkbMenu(menuitem, line, leds.lights_on); } - #endif -#endif - -#if ENABLED(SOUND_MENU_ITEM) - void onDrawEnableSound(MenuItemClass* menuitem, int8_t line) { onDrawChkbMenu(menuitem, line, ui.sound_on); } -#endif - -#ifdef BLTOUCH_HS_MODE - void onDrawHSMode(MenuItemClass* menuitem, int8_t line) { onDrawChkbMenu(menuitem, line, bltouch.high_speed_mode); } -#endif - void onDrawSelColorItem(MenuItemClass* menuitem, int8_t line) { const uint16_t color = *(uint16_t*)static_cast(menuitem)->value; DWIN_Draw_Rectangle(0, HMI_data.Highlight_Color, ICOX + 1, MBASE(line) - 1 + 1, ICOX + 18, MBASE(line) - 1 + 18); @@ -2737,10 +2765,12 @@ void onDrawSteps(MenuItemClass* menuitem, int8_t line) { if (HMI_IsChinese()) menuitem->SetFrame(1, 100, 89, 178, 101); onDrawSubMenu(menuitem,line); } - void onDrawABSPreheatSubMenu(MenuItemClass* menuitem, int8_t line) { - if (HMI_IsChinese()) menuitem->SetFrame(1, 180, 89, 260, 100); - onDrawSubMenu(menuitem,line); - } + #if PREHEAT_COUNT >= 2 + void onDrawABSPreheatSubMenu(MenuItemClass* menuitem, int8_t line) { + if (HMI_IsChinese()) menuitem->SetFrame(1, 180, 89, 260, 100); + onDrawSubMenu(menuitem,line); + } + #endif #endif // HAS_PREHEAT void onDrawSpeed(MenuItemClass* menuitem, int8_t line) { @@ -2937,70 +2967,67 @@ void Draw_Prepare_Menu() { if (CurrentMenu != PrepareMenu) { CurrentMenu = PrepareMenu; SetMenuTitle({133, 1, 28, 13}, GET_TEXT_F(MSG_PREPARE)); - DWINUI::MenuItemsPrepare(13); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Goto_Main_Menu); + MenuItemsPrepare(13); + BACK_ITEM(Goto_Main_Menu); #if ENABLED(ADVANCED_PAUSE_FEATURE) - MENU_ITEM(ICON_FilMan, GET_TEXT_F(MSG_FILAMENT_MAN), onDrawSubMenu, Draw_FilamentMan_Menu); + MENU_ITEM_F(ICON_FilMan, MSG_FILAMENT_MAN, onDrawSubMenu, Draw_FilamentMan_Menu); #endif - MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_MOVE_AXIS), onDrawMoveSubMenu, Goto_Move_Menu); - MENU_ITEM(ICON_Tram, GET_TEXT_F(MSG_BED_TRAMMING), onDrawSubMenu, Draw_Tramming_Menu); - MENU_ITEM(ICON_CloseMotor, GET_TEXT_F(MSG_DISABLE_STEPPERS), onDrawDisableMotors, DisableMotors); + MENU_ITEM_F(ICON_Axis, MSG_MOVE_AXIS, onDrawMoveSubMenu, Goto_Move_Menu); + MENU_ITEM_F(ICON_Tram, MSG_BED_TRAMMING, onDrawSubMenu, Draw_Tramming_Menu); + MENU_ITEM_F(ICON_CloseMotor, MSG_DISABLE_STEPPERS, onDrawDisableMotors, DisableMotors); #if ENABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU) - MENU_ITEM(ICON_Homing, GET_TEXT_F(MSG_HOMING), onDrawSubMenu, Draw_Homing_Menu); + MENU_ITEM_F(ICON_Homing, MSG_HOMING, onDrawSubMenu, Draw_Homing_Menu); #else - MENU_ITEM(ICON_Homing, GET_TEXT_F(MSG_AUTO_HOME), onDrawAutoHome, AutoHome); + MENU_ITEM_F(ICON_Homing, MSG_AUTO_HOME, onDrawAutoHome, AutoHome); #endif #if ENABLED(MESH_BED_LEVELING) - MENU_ITEM(ICON_ManualMesh, GET_TEXT_F(MSG_MANUAL_MESH), onDrawSubMenu, Draw_ManualMesh_Menu); + MENU_ITEM_F(ICON_ManualMesh, MSG_MANUAL_MESH, onDrawSubMenu, Draw_ManualMesh_Menu); #endif #if HAS_ONESTEP_LEVELING - MENU_ITEM(ICON_Level, GET_TEXT_F(MSG_AUTO_MESH), onDrawMenuItem, AutoLev); + MENU_ITEM_F(ICON_Level, MSG_AUTO_MESH, onDrawMenuItem, AutoLev); #endif #if HAS_ZOFFSET_ITEM - #if HAS_BED_PROBE - MENU_ITEM(ICON_SetZOffset, GET_TEXT_F(MSG_PROBE_WIZARD), onDrawSubMenu, Draw_ZOffsetWiz_Menu); - #elif ENABLED(BABYSTEPPING) - EDIT_ITEM(ICON_Zoffset, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), onDrawPFloat2Menu, SetZOffset, &BABY_Z_VAR); + #if ENABLED(BABYSTEP_ZPROBE_OFFSET) + MENU_ITEM_F(ICON_SetZOffset, MSG_PROBE_WIZARD, onDrawSubMenu, Draw_ZOffsetWiz_Menu); + #elif JUST_BABYSTEP + EDIT_ITEM_F(ICON_Zoffset, MSG_ZPROBE_ZOFFSET, onDrawPFloat2Menu, SetZOffset, &BABY_Z_VAR); #else - MENU_ITEM(ICON_SetHome, GET_TEXT_F(MSG_SET_HOME_OFFSETS), onDrawHomeOffset, SetHome); + MENU_ITEM_F(ICON_SetHome, MSG_SET_HOME_OFFSETS, onDrawHomeOffset, SetHome); #endif #endif #if HAS_PREHEAT - MENU_ITEM(ICON_PLAPreheat, GET_TEXT_F(MSG_PREHEAT_1), onDrawPreheat1, DoPreheat0); + MENU_ITEM_F(ICON_PLAPreheat, MSG_PREHEAT_1, onDrawPreheat1, DoPreheat0); #if PREHEAT_COUNT > 1 - MENU_ITEM(ICON_ABSPreheat, PSTR("Preheat " PREHEAT_2_LABEL), onDrawPreheat2, DoPreheat1); - #endif - #if PREHEAT_COUNT > 2 - MENU_ITEM(ICON_CustomPreheat, GET_TEXT_F(MSG_PREHEAT_CUSTOM), onDrawMenuItem, DoPreheat2); + MENU_ITEM(ICON_ABSPreheat, F("Preheat " PREHEAT_2_LABEL), onDrawPreheat2, DoPreheat1); + #if PREHEAT_COUNT > 2 + MENU_ITEM(ICON_CustomPreheat, F("Preheat " PREHEAT_3_LABEL), onDrawMenuItem, DoPreheat2); + #endif #endif #endif - MENU_ITEM(ICON_Cool, GET_TEXT_F(MSG_COOLDOWN), onDrawCooldown, DoCoolDown); - MENU_ITEM(ICON_Language, PSTR(GET_TEXT_F(MSG_UI_LANGUAGE)), onDrawLanguage, SetLanguage); + MENU_ITEM_F(ICON_Cool, MSG_COOLDOWN, onDrawCooldown, DoCoolDown); + MENU_ITEM_F(ICON_Language, MSG_UI_LANGUAGE, onDrawLanguage, SetLanguage); } ui.reset_status(true); CurrentMenu->draw(); } void Draw_Tramming_Menu() { - DWINUI::ClearMainArea(); checkkey = Menu; - if (!TrammingMenu) TrammingMenu = new MenuClass(); - if (CurrentMenu != TrammingMenu) { - CurrentMenu = TrammingMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_BED_TRAMMING)); // TODO: Chinese, English "Bed Tramming" JPG - 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); + if (SetMenu(TrammingMenu, GET_TEXT_F(MSG_BED_TRAMMING), 8)) { + BACK_ITEM(Draw_Prepare_Menu); + #if HAS_BED_PROBE + MENU_ITEM_F(ICON_ProbeSet, MSG_TRAMMING_WIZARD, onDrawMenuItem, Trammingwizard); + EDIT_ITEM_F(ICON_ProbeSet, MSG_BED_TRAMMING_MANUAL, onDrawChkbMenu, SetManualTramming, &HMI_data.FullManualTramming); + #else + MENU_ITEM(ICON_MoveZ0, F("Home Z and disable"), onDrawMenuItem, HomeZandDisable); #endif + MENU_ITEM_F(ICON_Axis, MSG_LEVBED_FL, onDrawMenuItem, TramFL); + MENU_ITEM_F(ICON_Axis, MSG_LEVBED_FR, onDrawMenuItem, TramFR); + MENU_ITEM_F(ICON_Axis, MSG_LEVBED_BR, onDrawMenuItem, TramBR); + MENU_ITEM_F(ICON_Axis, MSG_LEVBED_BL, onDrawMenuItem, TramBL); + MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_LEVBED_C ), onDrawMenuItem, TramC ); } - CurrentMenu->draw(); + UpdateMenu(TrammingMenu); } void Draw_Control_Menu() { @@ -3009,27 +3036,27 @@ void Draw_Control_Menu() { if (CurrentMenu != ControlMenu) { CurrentMenu = ControlMenu; SetMenuTitle({103, 1, 28, 14}, GET_TEXT_F(MSG_CONTROL)); - DWINUI::MenuItemsPrepare(10); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Goto_Main_Menu); + MenuItemsPrepare(10); + BACK_ITEM(Goto_Main_Menu); + MENU_ITEM_F(ICON_Temperature, MSG_TEMPERATURE, onDrawTempSubMenu, Draw_Temperature_Menu); + MENU_ITEM_F(ICON_Motion, MSG_MOTION, onDrawMotionSubMenu, Draw_Motion_Menu); + #if ENABLED(EEPROM_SETTINGS) + MENU_ITEM_F(ICON_WriteEEPROM, MSG_STORE_EEPROM, onDrawWriteEeprom, WriteEeprom); + MENU_ITEM_F(ICON_ReadEEPROM, MSG_LOAD_EEPROM, onDrawReadEeprom, ReadEeprom); + MENU_ITEM_F(ICON_ResumeEEPROM, MSG_RESTORE_DEFAULTS, onDrawResetEeprom, ResetEeprom); + #endif + MENU_ITEM_F(ICON_Reboot, MSG_RESET_PRINTER, onDrawMenuItem, RebootPrinter); #if ENABLED(CASE_LIGHT_MENU) #if ENABLED(CASELIGHT_USES_BRIGHTNESS) - MENU_ITEM(ICON_CaseLight, GET_TEXT_F(MSG_CASE_LIGHT), onDrawSubMenu, Draw_CaseLight_Menu); + MENU_ITEM_F(ICON_CaseLight, MSG_CASE_LIGHT, onDrawSubMenu, Draw_CaseLight_Menu); #else - MENU_ITEM(ICON_CaseLight, GET_TEXT_F(MSG_CASE_LIGHT), onDrawCaseLight, SetCaseLight); + MENU_ITEM_F(ICON_CaseLight, MSG_CASE_LIGHT, onDrawChkbMenu, SetCaseLight, &caselight.on); #endif #endif #if ENABLED(LED_CONTROL_MENU) - MENU_ITEM(ICON_LedControl, GET_TEXT_F(MSG_LED_CONTROL), onDrawSubMenu, Draw_LedControl_Menu); + MENU_ITEM_F(ICON_LedControl, MSG_LED_CONTROL, onDrawSubMenu, Draw_LedControl_Menu); #endif - MENU_ITEM(ICON_Temperature, GET_TEXT_F(MSG_TEMPERATURE), onDrawTempSubMenu, Draw_Temperature_Menu); - MENU_ITEM(ICON_Motion, GET_TEXT_F(MSG_MOTION), onDrawMotionSubMenu, Draw_Motion_Menu); - #if ENABLED(EEPROM_SETTINGS) - MENU_ITEM(ICON_WriteEEPROM, GET_TEXT_F(MSG_STORE_EEPROM), onDrawWriteEeprom, WriteEeprom); - MENU_ITEM(ICON_ReadEEPROM, GET_TEXT_F(MSG_LOAD_EEPROM), onDrawReadEeprom, ReadEeprom); - MENU_ITEM(ICON_ResumeEEPROM, GET_TEXT_F(MSG_RESTORE_DEFAULTS), onDrawResetEeprom, ResetEeprom); - #endif - 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); + MENU_ITEM_F(ICON_Info, MSG_INFO_SCREEN, onDrawInfoSubMenu, Goto_Info_Menu); } ui.reset_status(true); CurrentMenu->draw(); @@ -3037,57 +3064,52 @@ void Draw_Control_Menu() { void Draw_AdvancedSettings_Menu() { checkkey = Menu; - if (!AdvancedSettings) AdvancedSettings = new MenuClass(); - if (CurrentMenu != AdvancedSettings) { - CurrentMenu = AdvancedSettings; - SetMenuTitle({0}, GET_TEXT_F(MSG_ADVANCED_SETTINGS)); // TODO: Chinese, English "Advanced Settings" JPG - DWINUI::MenuItemsPrepare(17); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Goto_Main_Menu); + if (SetMenu(AdvancedSettings, GET_TEXT_F(MSG_ADVANCED_SETTINGS), 20)) { + BACK_ITEM(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); + MENU_ITEM_F(ICON_WriteEEPROM, MSG_STORE_EEPROM, onDrawMenuItem, WriteEeprom); #endif #if HAS_BED_PROBE - MENU_ITEM(ICON_ProbeSet, GET_TEXT_F(MSG_ZPROBE_SETTINGS), onDrawSubMenu, Draw_ProbeSet_Menu); - #endif - #if HAS_HOTEND - MENU_ITEM(ICON_PIDNozzle, F("Hotend PID Settings"), onDrawSubMenu, Draw_HotendPID_Menu); - #endif - #if HAS_HEATED_BED - MENU_ITEM(ICON_PIDbed, F("Bed PID Settings"), onDrawSubMenu, Draw_BedPID_Menu); - #endif - #if HAS_FILAMENT_SENSOR - MENU_ITEM(ICON_FilSet, GET_TEXT_F(MSG_FILAMENT_SET), onDrawSubMenu, Draw_FilSet_Menu); - #endif - #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 - MENU_ITEM(ICON_Scolor, GET_TEXT_F(MSG_COLORS_SELECT), onDrawSubMenu, Draw_SelectColors_Menu); - #if ENABLED(SOUND_MENU_ITEM) - MENU_ITEM(ICON_Sound, GET_TEXT_F(MSG_SOUND_ENABLE), onDrawEnableSound, SetEnableSound); + MENU_ITEM_F(ICON_ProbeSet, MSG_ZPROBE_SETTINGS, onDrawSubMenu, Draw_ProbeSet_Menu); #endif #if HAS_MESH - MENU_ITEM(ICON_MeshViewer, GET_TEXT_F(MSG_MESH_VIEW), onDrawSubMenu, DWIN_MeshViewer); + MENU_ITEM_F(ICON_ProbeSet, MSG_MESH_LEVELING, onDrawSubMenu, Draw_MeshSet_Menu); + #endif + #if HAS_HOME_OFFSET + MENU_ITEM_F(ICON_HomeOffset, MSG_SET_HOME_OFFSETS, onDrawSubMenu, Draw_HomeOffset_Menu); + #endif + #if HAS_HOTEND + MENU_ITEM(ICON_PIDNozzle, F(STR_HOTEND_PID " Settings"), onDrawSubMenu, Draw_HotendPID_Menu); + #endif + #if HAS_HEATED_BED + MENU_ITEM(ICON_PIDbed, F(STR_BED_PID " Settings"), onDrawSubMenu, Draw_BedPID_Menu); + #endif + MENU_ITEM_F(ICON_FilSet, MSG_FILAMENT_SET, onDrawSubMenu, Draw_FilSet_Menu); + #if ENABLED(POWER_LOSS_RECOVERY) + EDIT_ITEM_F(ICON_Pwrlossr, MSG_OUTAGE_RECOVERY, onDrawChkbMenu, SetPwrLossr, &recovery.enabled); + #endif + #if ENABLED(BAUD_RATE_GCODE) + EDIT_ITEM(ICON_SetBaudRate, F("115K baud"), onDrawChkbMenu, SetBaudRate, &HMI_data.Baud115K); + #endif + #if HAS_LCD_BRIGHTNESS + EDIT_ITEM_F(ICON_Brightness, MSG_BRIGHTNESS, onDrawPInt8Menu, SetBrightness, &ui.brightness); + MENU_ITEM_F(ICON_Brightness, MSG_BRIGHTNESS_OFF, onDrawMenuItem, TurnOffBacklight); + #endif + MENU_ITEM_F(ICON_Scolor, MSG_COLORS_SELECT, onDrawSubMenu, Draw_SelectColors_Menu); + #if ENABLED(SOUND_MENU_ITEM) + EDIT_ITEM_F(ICON_Sound, MSG_SOUND_ENABLE, onDrawChkbMenu, SetEnableSound, &ui.sound_on); #endif #if HAS_ESDIAG 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, Goto_PrintStats); - MENU_ITEM(ICON_PrintStatsReset, GET_TEXT_F(MSG_INFO_PRINT_COUNT_RESET), onDrawSubMenu, PrintStats.Reset); + MENU_ITEM_F(ICON_PrintStats, MSG_INFO_STATS_MENU, onDrawSubMenu, Goto_PrintStats); + MENU_ITEM_F(ICON_PrintStatsReset, MSG_INFO_PRINT_COUNT_RESET, onDrawSubMenu, PrintStats.Reset); #endif - MENU_ITEM(ICON_Lock, GET_TEXT_F(MSG_LOCKSCREEN), onDrawMenuItem, DWIN_LockScreen); + MENU_ITEM_F(ICON_Lock, MSG_LOCKSCREEN, onDrawMenuItem, DWIN_LockScreen); } ui.reset_status(true); - CurrentMenu->draw(); + UpdateMenu(AdvancedSettings); } void Draw_Move_Menu() { @@ -3096,181 +3118,146 @@ void Draw_Move_Menu() { if (CurrentMenu != MoveMenu) { CurrentMenu = MoveMenu; SetMenuTitle({192, 1, 42, 14}, GET_TEXT_F(MSG_MOVE_AXIS)); - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Prepare_Menu); - EDIT_ITEM(ICON_MoveX, GET_TEXT_F(MSG_MOVE_X), onDrawMoveX, SetMoveX, ¤t_position.x); - EDIT_ITEM(ICON_MoveY, GET_TEXT_F(MSG_MOVE_Y), onDrawMoveY, SetMoveY, ¤t_position.y); - EDIT_ITEM(ICON_MoveZ, GET_TEXT_F(MSG_MOVE_Z), onDrawMoveZ, SetMoveZ, ¤t_position.z); + MenuItemsPrepare(5); + BACK_ITEM(Draw_Prepare_Menu); + EDIT_ITEM_F(ICON_MoveX, MSG_MOVE_X, onDrawMoveX, SetMoveX, ¤t_position.x); + EDIT_ITEM_F(ICON_MoveY, MSG_MOVE_Y, onDrawMoveY, SetMoveY, ¤t_position.y); + EDIT_ITEM_F(ICON_MoveZ, MSG_MOVE_Z, onDrawMoveZ, SetMoveZ, ¤t_position.z); #if HAS_HOTEND - EDIT_ITEM(ICON_Extruder, GET_TEXT_F(MSG_MOVE_E), onDrawMoveE, SetMoveE, ¤t_position.e); + EDIT_ITEM_F(ICON_Extruder, MSG_MOVE_E, onDrawMoveE, SetMoveE, ¤t_position.e); #endif } CurrentMenu->draw(); - if (!all_axes_trusted()) LCD_MESSAGE_F("WARNING: current position is unknown, home axes"); + if (!all_axes_trusted()) LCD_MESSAGE_F("WARNING: Current position unknown. Home axes."); } #if HAS_HOME_OFFSET void Draw_HomeOffset_Menu() { checkkey = Menu; - if (!HomeOffMenu) HomeOffMenu = new MenuClass(); - if (CurrentMenu != HomeOffMenu) { - CurrentMenu = HomeOffMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_SET_HOME_OFFSETS)); // TODO: Chinese, English "Set Home Offsets" JPG - DWINUI::MenuItemsPrepare(4); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_AdvancedSettings_Menu); - EDIT_ITEM(ICON_HomeOffsetX, GET_TEXT_F(MSG_HOME_OFFSET_X), onDrawPFloatMenu, SetHomeOffsetX, &home_offset[X_AXIS]); - EDIT_ITEM(ICON_HomeOffsetY, GET_TEXT_F(MSG_HOME_OFFSET_Y), onDrawPFloatMenu, SetHomeOffsetY, &home_offset[Y_AXIS]); - EDIT_ITEM(ICON_HomeOffsetZ, GET_TEXT_F(MSG_HOME_OFFSET_Z), onDrawPFloatMenu, SetHomeOffsetZ, &home_offset[Z_AXIS]); + if (SetMenu(HomeOffMenu, GET_TEXT_F(MSG_SET_HOME_OFFSETS), 4)) { + BACK_ITEM(Draw_AdvancedSettings_Menu); + EDIT_ITEM_F(ICON_HomeOffsetX, MSG_HOME_OFFSET_X, onDrawPFloatMenu, SetHomeOffsetX, &home_offset.x); + EDIT_ITEM_F(ICON_HomeOffsetY, MSG_HOME_OFFSET_Y, onDrawPFloatMenu, SetHomeOffsetY, &home_offset.y); + EDIT_ITEM_F(ICON_HomeOffsetZ, MSG_HOME_OFFSET_Z, onDrawPFloatMenu, SetHomeOffsetZ, &home_offset.z); } - CurrentMenu->draw(); + UpdateMenu(HomeOffMenu); } #endif #if HAS_BED_PROBE void Draw_ProbeSet_Menu() { checkkey = Menu; - if (!ProbeSetMenu) ProbeSetMenu = new MenuClass(); - if (CurrentMenu != ProbeSetMenu) { - CurrentMenu = ProbeSetMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_ZPROBE_SETTINGS)); // TODO: Chinese, English "Probe Settings" JPG - 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 + if (SetMenu(ProbeSetMenu, GET_TEXT_F(MSG_ZPROBE_SETTINGS), 8)) { + BACK_ITEM(Draw_AdvancedSettings_Menu); + EDIT_ITEM_F(ICON_ProbeOffsetX, MSG_ZPROBE_XOFFSET, onDrawPFloatMenu, SetProbeOffsetX, &probe.offset.x); + EDIT_ITEM_F(ICON_ProbeOffsetY, MSG_ZPROBE_YOFFSET, onDrawPFloatMenu, SetProbeOffsetY, &probe.offset.y); + EDIT_ITEM_F(ICON_ProbeOffsetZ, MSG_ZPROBE_ZOFFSET, onDrawPFloat2Menu, SetProbeOffsetZ, &probe.offset.z); #ifdef BLTOUCH_HS_MODE - MENU_ITEM(ICON_HSMode, F("Enable HS mode"), onDrawHSMode, SetHSMode); + EDIT_ITEM_F(ICON_HSMode, MSG_ENABLE_HS_MODE, onDrawChkbMenu, SetHSMode, &bltouch.high_speed_mode); #endif - MENU_ITEM(ICON_ProbeTest, GET_TEXT_F(MSG_M48_TEST), onDrawMenuItem, ProbeTest); - MENU_ITEM(ICON_ProbeStow, GET_TEXT_F(MSG_MANUAL_STOW), onDrawMenuItem, ProbeStow); - MENU_ITEM(ICON_ProbeDeploy, GET_TEXT_F(MSG_MANUAL_DEPLOY), onDrawMenuItem, ProbeDeploy); + MENU_ITEM_F(ICON_ProbeTest, MSG_M48_TEST, onDrawMenuItem, ProbeTest); + MENU_ITEM_F(ICON_ProbeStow, MSG_MANUAL_STOW, onDrawMenuItem, ProbeStow); + MENU_ITEM_F(ICON_ProbeDeploy, MSG_MANUAL_DEPLOY, onDrawMenuItem, ProbeDeploy); } - CurrentMenu->draw(); + UpdateMenu(ProbeSetMenu); } + #endif -#if HAS_FILAMENT_SENSOR - void Draw_FilSet_Menu() { - checkkey = Menu; - if (!FilSetMenu) FilSetMenu = new MenuClass(); - if (CurrentMenu != FilSetMenu) { - CurrentMenu = FilSetMenu; - CurrentMenu->MenuTitle.SetCaption(GET_TEXT_F(MSG_FILAMENT_SET)); - DWINUI::MenuItemsPrepare(10); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawMenuItem, Draw_AdvancedSettings_Menu); - #if HAS_FILAMENT_SENSOR - MENU_ITEM(ICON_Runout, GET_TEXT_F(MSG_RUNOUT_ENABLE), onDrawRunoutEnable, SetRunoutEnable); - #endif - #if HAS_FILAMENT_RUNOUT_DISTANCE - EDIT_ITEM(ICON_Runout, F("Runout Distance"), onDrawPFloatMenu, SetRunoutDistance, &runout.runout_distance()); - #endif - #if ENABLED(PREVENT_COLD_EXTRUSION) - EDIT_ITEM(ICON_ExtrudeMinT, F("Extrude Min Temp."), onDrawPIntMenu, SetExtMinT, &HMI_data.ExtMinT); - #endif - #if ENABLED(ADVANCED_PAUSE_FEATURE) - EDIT_ITEM(ICON_FilLoad, GET_TEXT_F(MSG_FILAMENT_LOAD), onDrawPFloatMenu, SetFilLoad, &fc_settings[0].load_length); - EDIT_ITEM(ICON_FilUnload, GET_TEXT_F(MSG_FILAMENT_UNLOAD), onDrawPFloatMenu, SetFilUnload, &fc_settings[0].unload_length); - #endif - #if ENABLED(FWRETRACT) - EDIT_ITEM(ICON_FWRetLength, GET_TEXT_F(MSG_CONTROL_RETRACT), onDrawPFloatMenu, SetRetractLength, &fwretract.settings.retract_length); - EDIT_ITEM(ICON_FWRetSpeed, GET_TEXT_F(MSG_SINGLENOZZLE_RETRACT_SPEED), onDrawPFloatMenu, SetRetractSpeed, &fwretract.settings.retract_feedrate_mm_s); - EDIT_ITEM(ICON_FWRetZRaise, GET_TEXT_F(MSG_CONTROL_RETRACT_ZHOP), onDrawPFloat2Menu, SetZRaise, &fwretract.settings.retract_zraise); - EDIT_ITEM(ICON_FWRecSpeed, GET_TEXT_F(MSG_SINGLENOZZLE_UNRETRACT_SPEED), onDrawPFloatMenu, SetRecoverSpeed, &fwretract.settings.retract_recover_feedrate_mm_s); - #endif - } - CurrentMenu->draw(); +void Draw_FilSet_Menu() { + checkkey = Menu; + if (SetMenu(FilSetMenu, GET_TEXT_F(MSG_FILAMENT_SET), 9)) { + BACK_ITEM(Draw_AdvancedSettings_Menu); + #if HAS_FILAMENT_SENSOR + EDIT_ITEM_F(ICON_Runout, MSG_RUNOUT_ENABLE, onDrawChkbMenu, SetRunoutEnable, &runout.enabled); + #endif + #if HAS_FILAMENT_RUNOUT_DISTANCE + EDIT_ITEM_F(ICON_Runout, MSG_RUNOUT_DISTANCE_MM, onDrawPFloatMenu, SetRunoutDistance, &runout.runout_distance()); + #endif + #if ENABLED(PREVENT_COLD_EXTRUSION) + EDIT_ITEM_F(ICON_ExtrudeMinT, MSG_EXTRUDER_MIN_TEMP, onDrawPIntMenu, SetExtMinT, &HMI_data.ExtMinT); + #endif + #if ENABLED(ADVANCED_PAUSE_FEATURE) + EDIT_ITEM_F(ICON_FilLoad, MSG_FILAMENT_LOAD, onDrawPFloatMenu, SetFilLoad, &fc_settings[0].load_length); + EDIT_ITEM_F(ICON_FilUnload, MSG_FILAMENT_UNLOAD, onDrawPFloatMenu, SetFilUnload, &fc_settings[0].unload_length); + #endif + #if ENABLED(FWRETRACT) + MENU_ITEM_F(ICON_FWRetract, MSG_FWRETRACT, onDrawSubMenu, Draw_FWRetract_Menu); + #endif } -#endif // HAS_FILAMENT_SENSOR + UpdateMenu(FilSetMenu); +} void Draw_SelectColors_Menu() { checkkey = Menu; - if (!SelectColorMenu) SelectColorMenu = new MenuClass(); - if (CurrentMenu != SelectColorMenu) { - CurrentMenu = SelectColorMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_COLORS_SELECT)); // TODO: Chinese, English "Select Color" JPG - DWINUI::MenuItemsPrepare(20); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_AdvancedSettings_Menu); - MENU_ITEM(ICON_StockConfiguration, GET_TEXT_F(MSG_RESTORE_DEFAULTS), onDrawMenuItem, RestoreDefaultsColors); - EDIT_ITEM(0, "Screen Background", onDrawSelColorItem, SelColor, &HMI_data.Background_Color); - EDIT_ITEM(0, "Cursor", onDrawSelColorItem, SelColor, &HMI_data.Cursor_color); - EDIT_ITEM(0, "Title Background", onDrawSelColorItem, SelColor, &HMI_data.TitleBg_color); - EDIT_ITEM(0, "Title Text", onDrawSelColorItem, SelColor, &HMI_data.TitleTxt_color); - EDIT_ITEM(0, "Text", onDrawSelColorItem, SelColor, &HMI_data.Text_Color); - EDIT_ITEM(0, "Selected", onDrawSelColorItem, SelColor, &HMI_data.Selected_Color); - EDIT_ITEM(0, "Split Line", onDrawSelColorItem, SelColor, &HMI_data.SplitLine_Color); - EDIT_ITEM(0, "Highlight", onDrawSelColorItem, SelColor, &HMI_data.Highlight_Color); - EDIT_ITEM(0, "Status Background", onDrawSelColorItem, SelColor, &HMI_data.StatusBg_Color); - EDIT_ITEM(0, "Status Text", onDrawSelColorItem, SelColor, &HMI_data.StatusTxt_Color); - EDIT_ITEM(0, "Popup Background", onDrawSelColorItem, SelColor, &HMI_data.PopupBg_color); - EDIT_ITEM(0, "Popup Text", onDrawSelColorItem, SelColor, &HMI_data.PopupTxt_Color); - EDIT_ITEM(0, "Alert Background", onDrawSelColorItem, SelColor, &HMI_data.AlertBg_Color); - EDIT_ITEM(0, "Alert Text", onDrawSelColorItem, SelColor, &HMI_data.AlertTxt_Color); - EDIT_ITEM(0, "Percent Text", onDrawSelColorItem, SelColor, &HMI_data.PercentTxt_Color); - EDIT_ITEM(0, "Bar Fill", onDrawSelColorItem, SelColor, &HMI_data.Barfill_Color); - EDIT_ITEM(0, "Indicator value", onDrawSelColorItem, SelColor, &HMI_data.Indicator_Color); - EDIT_ITEM(0, "Coordinate value", onDrawSelColorItem, SelColor, &HMI_data.Coordinate_Color); + if (SetMenu(SelectColorMenu, GET_TEXT_F(MSG_COLORS_SELECT), 20)) { + BACK_ITEM(Draw_AdvancedSettings_Menu); + MENU_ITEM_F(ICON_StockConfiguration, MSG_RESTORE_DEFAULTS, onDrawMenuItem, RestoreDefaultsColors); + EDIT_ITEM(0, F("Screen Background"), onDrawSelColorItem, SelColor, &HMI_data.Background_Color); + EDIT_ITEM(0, F("Cursor"), onDrawSelColorItem, SelColor, &HMI_data.Cursor_color); + EDIT_ITEM(0, F("Title Background"), onDrawSelColorItem, SelColor, &HMI_data.TitleBg_color); + EDIT_ITEM(0, F("Title Text"), onDrawSelColorItem, SelColor, &HMI_data.TitleTxt_color); + EDIT_ITEM(0, F("Text"), onDrawSelColorItem, SelColor, &HMI_data.Text_Color); + EDIT_ITEM(0, F("Selected"), onDrawSelColorItem, SelColor, &HMI_data.Selected_Color); + EDIT_ITEM(0, F("Split Line"), onDrawSelColorItem, SelColor, &HMI_data.SplitLine_Color); + EDIT_ITEM(0, F("Highlight"), onDrawSelColorItem, SelColor, &HMI_data.Highlight_Color); + EDIT_ITEM(0, F("Status Background"), onDrawSelColorItem, SelColor, &HMI_data.StatusBg_Color); + EDIT_ITEM(0, F("Status Text"), onDrawSelColorItem, SelColor, &HMI_data.StatusTxt_Color); + EDIT_ITEM(0, F("Popup Background"), onDrawSelColorItem, SelColor, &HMI_data.PopupBg_color); + EDIT_ITEM(0, F("Popup Text"), onDrawSelColorItem, SelColor, &HMI_data.PopupTxt_Color); + EDIT_ITEM(0, F("Alert Background"), onDrawSelColorItem, SelColor, &HMI_data.AlertBg_Color); + EDIT_ITEM(0, F("Alert Text"), onDrawSelColorItem, SelColor, &HMI_data.AlertTxt_Color); + EDIT_ITEM(0, F("Percent Text"), onDrawSelColorItem, SelColor, &HMI_data.PercentTxt_Color); + EDIT_ITEM(0, F("Bar Fill"), onDrawSelColorItem, SelColor, &HMI_data.Barfill_Color); + EDIT_ITEM(0, F("Indicator value"), onDrawSelColorItem, SelColor, &HMI_data.Indicator_Color); + EDIT_ITEM(0, F("Coordinate value"), onDrawSelColorItem, SelColor, &HMI_data.Coordinate_Color); } - CurrentMenu->draw(); + UpdateMenu(SelectColorMenu); } void Draw_GetColor_Menu() { checkkey = Menu; - if (!GetColorMenu) GetColorMenu = new MenuClass(); - if (CurrentMenu != GetColorMenu) { - CurrentMenu = GetColorMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_COLORS_GET)); // TODO: Chinese, English "Get Color" JPG - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, DWIN_ApplyColor); - MENU_ITEM(ICON_Cancel, GET_TEXT_F(MSG_BUTTON_CANCEL), onDrawMenuItem, Draw_SelectColors_Menu); - MENU_ITEM(0, GET_TEXT_F(MSG_COLORS_RED), onDrawGetColorItem, SetRGBColor); - MENU_ITEM(1, GET_TEXT_F(MSG_COLORS_GREEN), onDrawGetColorItem, SetRGBColor); - MENU_ITEM(2, GET_TEXT_F(MSG_COLORS_BLUE), onDrawGetColorItem, SetRGBColor); + if (SetMenu(GetColorMenu, GET_TEXT_F(MSG_COLORS_GET), 5)) { + BACK_ITEM(DWIN_ApplyColor); + MENU_ITEM_F(ICON_Cancel, MSG_BUTTON_CANCEL, onDrawMenuItem, Draw_SelectColors_Menu); + MENU_ITEM_F(0, MSG_COLORS_RED, onDrawGetColorItem, SetRGBColor); + MENU_ITEM_F(1, MSG_COLORS_GREEN, onDrawGetColorItem, SetRGBColor); + MENU_ITEM_F(2, MSG_COLORS_BLUE, onDrawGetColorItem, SetRGBColor); } - CurrentMenu->draw(); + UpdateMenu(GetColorMenu); DWIN_Draw_Rectangle(1, *MenuData.P_Int, 20, 315, DWIN_WIDTH - 20, 335); } #if BOTH(CASE_LIGHT_MENU, CASELIGHT_USES_BRIGHTNESS) void Draw_CaseLight_Menu() { checkkey = Menu; - if (!CaseLightMenu) CaseLightMenu = new MenuClass(); - if (CurrentMenu != CaseLightMenu) { - CurrentMenu = CaseLightMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_CASE_LIGHT)); // TODO: Chinese, English "Case Light" JPG - DWINUI::MenuItemsPrepare(3); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Control_Menu); - MENU_ITEM(ICON_CaseLight, GET_TEXT_F(MSG_CASE_LIGHT), onDrawCaseLight, SetCaseLight); - EDIT_ITEM(ICON_Brightness, GET_TEXT_F(MSG_CASE_LIGHT_BRIGHTNESS), onDrawPInt8Menu, SetCaseLightBrightness, &caselight.brightness); + if (SetMenu(CaseLightMenu, GET_TEXT_F(MSG_CASE_LIGHT), 3)) { + BACK_ITEM(Draw_Control_Menu); + EDIT_ITEM_F(ICON_CaseLight, MSG_CASE_LIGHT, onDrawChkbMenu, SetCaseLight, &caselight.on); + EDIT_ITEM_F(ICON_Brightness, MSG_CASE_LIGHT_BRIGHTNESS, onDrawPInt8Menu, SetCaseLightBrightness, &caselight.brightness); } - CurrentMenu->draw(); + UpdateMenu(CaseLightMenu); } #endif #if ENABLED(LED_CONTROL_MENU) void Draw_LedControl_Menu() { checkkey = Menu; - if (!LedControlMenu) LedControlMenu = new MenuClass(); - if (CurrentMenu != LedControlMenu) { - CurrentMenu = LedControlMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_LED_CONTROL)); // TODO: Chinese, English "LED Control" JPG - DWINUI::MenuItemsPrepare(6); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Control_Menu); + if (SetMenu(LedControlMenu, GET_TEXT_F(MSG_LED_CONTROL), 6)) { + BACK_ITEM(Draw_Control_Menu); #if !BOTH(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) - MENU_ITEM(ICON_LedControl, GET_TEXT_F(MSG_LEDS), onDrawLedStatus, SetLedStatus); + EDIT_ITEM_F(ICON_LedControl, MSG_LEDS, onDrawChkbMenu, SetLedStatus, &leds.lights_on); #endif #if HAS_COLOR_LEDS - EDIT_ITEM(ICON_LedControl, GET_TEXT_F(MSG_COLORS_RED), onDrawPInt8Menu, SetLedColorR, &leds.color.r); - EDIT_ITEM(ICON_LedControl, GET_TEXT_F(MSG_COLORS_GREEN), onDrawPInt8Menu, SetLedColorG, &leds.color.g); - EDIT_ITEM(ICON_LedControl, GET_TEXT_F(MSG_COLORS_BLUE), onDrawPInt8Menu, SetLedColorB, &leds.color.b); + EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_RED, onDrawPInt8Menu, SetLEDColorR, &leds.color.r); + EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_GREEN, onDrawPInt8Menu, SetLEDColorG, &leds.color.g); + EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_BLUE, onDrawPInt8Menu, SetLEDColorB, &leds.color.b); #if ENABLED(HAS_WHITE_LED) - EDIT_ITEM(ICON_LedControl, GET_TEXT_F(MSG_COLORS_WHITE), onDrawPInt8Menu, SetLedColorW, &leds.color.w); + EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_WHITE, onDrawPInt8Menu, SetLedColorW, &leds.color.w); #endif #endif } - CurrentMenu->draw(); + UpdateMenu(LedControlMenu); } #endif @@ -3280,40 +3267,37 @@ 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(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); - #elif ENABLED(LED_CONTROL_MENU) && DISABLED(CASE_LIGHT_USE_NEOPIXEL) - MENU_ITEM(ICON_LedControl, GET_TEXT_F(MSG_LEDS), onDrawLedStatus, SetLedStatus); - #endif - EDIT_ITEM(ICON_Speed, GET_TEXT_F(MSG_SPEED), onDrawSpeedItem, SetSpeed, &feedrate_percentage); + MenuItemsPrepare(16); + BACK_ITEM(Goto_PrintProcess); + EDIT_ITEM_F(ICON_Speed, MSG_SPEED, onDrawSpeedItem, SetSpeed, &feedrate_percentage); #if HAS_HOTEND - HotendTargetItem = EDIT_ITEM(ICON_HotendTemp, GET_TEXT_F(MSG_UBL_SET_TEMP_HOTEND), onDrawHotendTemp, SetHotendTemp, &thermalManager.temp_hotend[0].target); + HotendTargetItem = EDIT_ITEM_F(ICON_HotendTemp, MSG_UBL_SET_TEMP_HOTEND, onDrawHotendTemp, SetHotendTemp, &thermalManager.temp_hotend[0].target); #endif #if HAS_HEATED_BED - BedTargetItem = EDIT_ITEM(ICON_BedTemp, GET_TEXT_F(MSG_UBL_SET_TEMP_BED), onDrawBedTemp, SetBedTemp, &thermalManager.temp_bed.target); + BedTargetItem = EDIT_ITEM_F(ICON_BedTemp, MSG_UBL_SET_TEMP_BED, onDrawBedTemp, SetBedTemp, &thermalManager.temp_bed.target); #endif #if HAS_FAN - FanSpeedItem = EDIT_ITEM(ICON_FanSpeed, GET_TEXT_F(MSG_FAN_SPEED), onDrawFanSpeed, SetFanSpeed, &thermalManager.fan_speed[0]); + FanSpeedItem = EDIT_ITEM_F(ICON_FanSpeed, MSG_FAN_SPEED, onDrawFanSpeed, SetFanSpeed, &thermalManager.fan_speed[0]); #endif - #if HAS_ZOFFSET_ITEM && EITHER(HAS_BED_PROBE, BABYSTEPPING) - EDIT_ITEM(ICON_Zoffset, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), onDrawZOffset, SetZOffset, &BABY_Z_VAR); + #if HAS_ZOFFSET_ITEM && EITHER(BABYSTEP_ZPROBE_OFFSET, JUST_BABYSTEP) + EDIT_ITEM_F(ICON_Zoffset, MSG_ZPROBE_ZOFFSET, onDrawZOffset, SetZOffset, &BABY_Z_VAR); + #endif + EDIT_ITEM_F(ICON_Flow, MSG_FLOW, onDrawPIntMenu, SetFlow, &planner.flow_percentage[0]); + #if ENABLED(ADVANCED_PAUSE_FEATURE) + MENU_ITEM_F(ICON_FilMan, MSG_FILAMENTCHANGE, onDrawMenuItem, ChangeFilament); #endif #if ENABLED(FWRETRACT) - EDIT_ITEM(ICON_FWRetLength, GET_TEXT_F(MSG_CONTROL_RETRACT), onDrawPFloatMenu, SetRetractLength, &fwretract.settings.retract_length); - EDIT_ITEM(ICON_FWRetSpeed, GET_TEXT_F(MSG_SINGLENOZZLE_RETRACT_SPEED), onDrawPFloatMenu, SetRetractSpeed, &fwretract.settings.retract_feedrate_mm_s); - EDIT_ITEM(ICON_FWRetZRaise, GET_TEXT_F(MSG_CONTROL_RETRACT_ZHOP), onDrawPFloat2Menu, SetZRaise, &fwretract.settings.retract_zraise); - EDIT_ITEM(ICON_FWRecSpeed, GET_TEXT_F(MSG_SINGLENOZZLE_UNRETRACT_SPEED), onDrawPFloatMenu, SetRecoverSpeed, &fwretract.settings.retract_recover_feedrate_mm_s); + MENU_ITEM_F(ICON_FWRetract, MSG_FWRETRACT, onDrawSubMenu, Draw_FWRetract_Menu); #endif - EDIT_ITEM(ICON_Flow, GET_TEXT_F(MSG_FLOW), onDrawPIntMenu, SetFlow, &planner.flow_percentage[0]); - #if ENABLED(ADVANCED_PAUSE_FEATURE) - MENU_ITEM(ICON_FilMan, GET_TEXT_F(MSG_FILAMENTCHANGE), onDrawMenuItem, ChangeFilament); - #endif - MENU_ITEM(ICON_Lock, GET_TEXT_F(MSG_LOCKSCREEN), onDrawMenuItem, DWIN_LockScreen); + MENU_ITEM_F(ICON_Lock, 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); + EDIT_ITEM_F(ICON_Brightness, MSG_BRIGHTNESS, onDrawPInt8Menu, SetBrightness, &ui.brightness); + MENU_ITEM_F(ICON_Brightness, MSG_BRIGHTNESS_OFF, onDrawMenuItem, TurnOffBacklight); + #endif + #if ENABLED(CASE_LIGHT_MENU) + EDIT_ITEM_F(ICON_CaseLight, MSG_CASE_LIGHT, onDrawChkbMenu, SetCaseLight, &caselight.on); + #elif ENABLED(LED_CONTROL_MENU) && DISABLED(CASE_LIGHT_USE_NEOPIXEL) + EDIT_ITEM_F(ICON_LedControl, MSG_LEDS, onDrawChkbMenu, SetLedStatus, &leds.lights_on); #endif } CurrentMenu->draw(); @@ -3325,15 +3309,15 @@ void Draw_Motion_Menu() { if (CurrentMenu != MotionMenu) { CurrentMenu = MotionMenu; SetMenuTitle({1, 16, 28, 13}, GET_TEXT_F(MSG_MOTION)); // TODO: Chinese, English "Motion" JPG - DWINUI::MenuItemsPrepare(6); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Control_Menu); - MENU_ITEM(ICON_MaxSpeed, GET_TEXT_F(MSG_SPEED), onDrawSpeed, Draw_MaxSpeed_Menu); - MENU_ITEM(ICON_MaxAccelerated, GET_TEXT_F(MSG_ACCELERATION), onDrawAcc, Draw_MaxAccel_Menu); + MenuItemsPrepare(6); + BACK_ITEM(Draw_Control_Menu); + MENU_ITEM_F(ICON_MaxSpeed, MSG_SPEED, onDrawSpeed, Draw_MaxSpeed_Menu); + MENU_ITEM_F(ICON_MaxAccelerated, MSG_ACCELERATION, onDrawAcc, Draw_MaxAccel_Menu); #if HAS_CLASSIC_JERK - MENU_ITEM(ICON_MaxJerk, GET_TEXT_F(MSG_JERK), onDrawJerk, Draw_MaxJerk_Menu); + MENU_ITEM_F(ICON_MaxJerk, MSG_JERK, onDrawJerk, Draw_MaxJerk_Menu); #endif - MENU_ITEM(ICON_Step, GET_TEXT_F(MSG_STEPS_PER_MM), onDrawSteps, Draw_Steps_Menu); - EDIT_ITEM(ICON_Flow, GET_TEXT_F(MSG_FLOW), onDrawPIntMenu, SetFlow, &planner.flow_percentage[0]); + MENU_ITEM_F(ICON_Step, MSG_STEPS_PER_MM, onDrawSteps, Draw_Steps_Menu); + EDIT_ITEM_F(ICON_Flow, MSG_FLOW, onDrawPIntMenu, SetFlow, &planner.flow_percentage[0]); } CurrentMenu->draw(); } @@ -3341,39 +3325,31 @@ void Draw_Motion_Menu() { #if ENABLED(ADVANCED_PAUSE_FEATURE) void Draw_FilamentMan_Menu() { checkkey = Menu; - if (!FilamentMenu) FilamentMenu = new MenuClass(); - if (CurrentMenu != FilamentMenu) { - CurrentMenu = FilamentMenu; - SetMenuTitle({0}, GET_TEXT_F(MSG_FILAMENT_MAN)); // TODO: Chinese, English "Filament Management" JPG - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Prepare_Menu); - MENU_ITEM(ICON_Park, GET_TEXT_F(MSG_FILAMENT_PARK_ENABLED), onDrawMenuItem, ParkHead); - MENU_ITEM(ICON_FilMan, GET_TEXT_F(MSG_FILAMENTCHANGE), onDrawMenuItem, ChangeFilament); + if (SetMenu(FilamentMenu, GET_TEXT_F(MSG_FILAMENT_MAN), 5)) { + BACK_ITEM(Draw_Prepare_Menu); + MENU_ITEM_F(ICON_Park, MSG_FILAMENT_PARK_ENABLED, onDrawMenuItem, ParkHead); + MENU_ITEM_F(ICON_FilMan, MSG_FILAMENTCHANGE, onDrawMenuItem, ChangeFilament); #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) - MENU_ITEM(ICON_FilUnload, GET_TEXT_F(MSG_FILAMENTUNLOAD), onDrawMenuItem, UnloadFilament); - MENU_ITEM(ICON_FilLoad, GET_TEXT_F(MSG_FILAMENTLOAD), onDrawMenuItem, LoadFilament); + MENU_ITEM_F(ICON_FilUnload, MSG_FILAMENTUNLOAD, onDrawMenuItem, UnloadFilament); + MENU_ITEM_F(ICON_FilLoad, MSG_FILAMENTLOAD, onDrawMenuItem, LoadFilament); #endif } - CurrentMenu->draw(); + UpdateMenu(FilamentMenu); } #endif #if ENABLED(MESH_BED_LEVELING) void Draw_ManualMesh_Menu() { checkkey = Menu; - if (!ManualMesh) ManualMesh = new MenuClass(); - if (CurrentMenu != ManualMesh) { - CurrentMenu = ManualMesh; - SetMenuTitle({0}, GET_TEXT_F(MSG_MANUAL_MESH)); // TODO: Chinese, English "Manual Mesh Leveling" JPG - DWINUI::MenuItemsPrepare(6); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Prepare_Menu); - MENU_ITEM(ICON_ManualMesh, GET_TEXT_F(MSG_LEVEL_BED), onDrawMenuItem, ManualMeshStart); - MMeshMoveZItem = EDIT_ITEM(ICON_Zoffset, GET_TEXT_F(MSG_MOVE_Z), onDrawMMeshMoveZ, SetMMeshMoveZ, ¤t_position.z); - MENU_ITEM(ICON_Axis, GET_TEXT_F(MSG_UBL_CONTINUE_MESH), onDrawMenuItem, ManualMeshContinue); - MENU_ITEM(ICON_MeshViewer, GET_TEXT_F(MSG_MESH_VIEW), onDrawSubMenu, DWIN_MeshViewer); - MENU_ITEM(ICON_MeshSave, GET_TEXT_F(MSG_UBL_SAVE_MESH), onDrawMenuItem, ManualMeshSave); + if (SetMenu(ManualMesh, GET_TEXT_F(MSG_UBL_MANUAL_MESH), 6)) { + BACK_ITEM(Draw_Prepare_Menu); + MENU_ITEM_F(ICON_ManualMesh, MSG_LEVEL_BED, onDrawMenuItem, ManualMeshStart); + MMeshMoveZItem = EDIT_ITEM_F(ICON_Zoffset, MSG_MOVE_Z, onDrawMMeshMoveZ, SetMMeshMoveZ, ¤t_position.z); + MENU_ITEM_F(ICON_Axis, MSG_UBL_CONTINUE_MESH, onDrawMenuItem, ManualMeshContinue); + MENU_ITEM_F(ICON_MeshViewer, MSG_MESH_VIEW, onDrawSubMenu, DWIN_MeshViewer); + MENU_ITEM_F(ICON_MeshSave, MSG_UBL_SAVE_MESH, onDrawMenuItem, ManualMeshSave); } - CurrentMenu->draw(); + UpdateMenu(ManualMesh); } #endif @@ -3384,42 +3360,43 @@ void Draw_Motion_Menu() { if (CurrentMenu != PreheatMenu) { CurrentMenu = PreheatMenu; SetMenuTitle(cn, fstr); - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Temperature_Menu); + MenuItemsPrepare(5); + BACK_ITEM(Draw_Temperature_Menu); #if HAS_HOTEND - EDIT_ITEM(ICON_SetEndTemp, GET_TEXT_F(MSG_UBL_SET_TEMP_HOTEND), onDrawSetPreheatHotend, SetPreheatEndTemp, &ui.material_preset[HMI_value.Preheat].hotend_temp); + EDIT_ITEM_F(ICON_SetEndTemp, MSG_UBL_SET_TEMP_HOTEND, onDrawSetPreheatHotend, SetPreheatEndTemp, &ui.material_preset[HMI_value.Select].hotend_temp); #endif #if HAS_HEATED_BED - EDIT_ITEM(ICON_SetBedTemp, GET_TEXT_F(MSG_UBL_SET_TEMP_BED), onDrawSetPreheatBed, SetPreheatBedTemp, &ui.material_preset[HMI_value.Preheat].bed_temp); + EDIT_ITEM_F(ICON_SetBedTemp, MSG_UBL_SET_TEMP_BED, onDrawSetPreheatBed, SetPreheatBedTemp, &ui.material_preset[HMI_value.Select].bed_temp); #endif #if HAS_FAN - EDIT_ITEM(ICON_FanSpeed, GET_TEXT_F(MSG_FAN_SPEED), onDrawSetPreheatFan, SetPreheatFanSpeed, &ui.material_preset[HMI_value.Preheat].fan_speed); + EDIT_ITEM_F(ICON_FanSpeed, MSG_FAN_SPEED, onDrawSetPreheatFan, SetPreheatFanSpeed, &ui.material_preset[HMI_value.Select].fan_speed); #endif #if ENABLED(EEPROM_SETTINGS) - MENU_ITEM(ICON_WriteEEPROM, GET_TEXT_F(MSG_STORE_EEPROM), onDrawWriteEeprom, WriteEeprom); + MENU_ITEM_F(ICON_WriteEEPROM, MSG_STORE_EEPROM, onDrawWriteEeprom, WriteEeprom); #endif } CurrentMenu->draw(); } void Draw_Preheat1_Menu() { - HMI_value.Preheat = 0; + HMI_value.Select = 0; if (!PreheatMenu) PreheatMenu = new MenuClass(); Draw_Preheat_Menu({59, 16, 81, 14}, F(PREHEAT_1_LABEL " Preheat Settings")); // TODO: English "PLA Settings" JPG } - void Draw_Preheat2_Menu() { - HMI_value.Preheat = 1; - if (!PreheatMenu) PreheatMenu = new MenuClass(); - Draw_Preheat_Menu({142, 16, 82, 14}, F(PREHEAT_2_LABEL " Preheat Settings")); // TODO: English "ABS Settings" JPG - } - - #ifdef PREHEAT_3_LABEL - void Draw_Preheat3_Menu() { - HMI_value.Preheat = 2; + #if PREHEAT_COUNT >= 2 + void Draw_Preheat2_Menu() { + HMI_value.Select = 1; if (!PreheatMenu) PreheatMenu = new MenuClass(); - #define PREHEAT_3_TITLE PREHEAT_3_LABEL " Preheat Set." - Draw_Preheat_Menu({0}, F(PREHEAT_3_TITLE)); // TODO: Chinese, English "Custom Preheat Settings" JPG + Draw_Preheat_Menu({142, 16, 82, 14}, F(PREHEAT_2_LABEL " Preheat Settings")); // TODO: English "ABS Settings" JPG + } + #endif + + #if PREHEAT_COUNT >= 3 + void Draw_Preheat3_Menu() { + HMI_value.Select = 2; + if (!PreheatMenu) PreheatMenu = new MenuClass(); + Draw_Preheat_Menu({225, 16, 82, 14}, F(PREHEAT_3_LABEL " Preheat Settings")); // TODO: English "... Settings" JPG } #endif @@ -3431,22 +3408,24 @@ void Draw_Temperature_Menu() { if (CurrentMenu != TemperatureMenu) { CurrentMenu = TemperatureMenu; SetMenuTitle({236, 2, 28, 12}, GET_TEXT_F(MSG_TEMPERATURE)); - DWINUI::MenuItemsPrepare(7); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Control_Menu); + MenuItemsPrepare(7); + BACK_ITEM(Draw_Control_Menu); #if HAS_HOTEND - HotendTargetItem = EDIT_ITEM(ICON_SetEndTemp, GET_TEXT_F(MSG_UBL_SET_TEMP_HOTEND), onDrawHotendTemp, SetHotendTemp, &thermalManager.temp_hotend[0].target); + HotendTargetItem = EDIT_ITEM_F(ICON_SetEndTemp, MSG_UBL_SET_TEMP_HOTEND, onDrawHotendTemp, SetHotendTemp, &thermalManager.temp_hotend[0].target); #endif #if HAS_HEATED_BED - BedTargetItem = EDIT_ITEM(ICON_SetBedTemp, GET_TEXT_F(MSG_UBL_SET_TEMP_BED), onDrawBedTemp, SetBedTemp, &thermalManager.temp_bed.target); + BedTargetItem = EDIT_ITEM_F(ICON_SetBedTemp, MSG_UBL_SET_TEMP_BED, onDrawBedTemp, SetBedTemp, &thermalManager.temp_bed.target); #endif #if HAS_FAN - FanSpeedItem = EDIT_ITEM(ICON_FanSpeed, GET_TEXT_F(MSG_FAN_SPEED), onDrawFanSpeed, SetFanSpeed, &thermalManager.fan_speed[0]); + FanSpeedItem = EDIT_ITEM_F(ICON_FanSpeed, MSG_FAN_SPEED, onDrawFanSpeed, SetFanSpeed, &thermalManager.fan_speed[0]); #endif - #if HAS_HOTEND - MENU_ITEM(ICON_SetPLAPreheat, F(PREHEAT_1_LABEL " Preheat Settings"), onDrawPLAPreheatSubMenu, Draw_Preheat1_Menu); - MENU_ITEM(ICON_SetABSPreheat, F(PREHEAT_2_LABEL " Preheat Settings"), onDrawABSPreheatSubMenu, Draw_Preheat2_Menu); - #ifdef PREHEAT_3_LABEL - MENU_ITEM(ICON_SetCustomPreheat, PREHEAT_3_TITLE, onDrawSubMenu, Draw_Preheat3_Menu); + #if HAS_PREHEAT + MENU_ITEM_F(ICON_SetPLAPreheat, MSG_PREHEAT_1_SETTINGS, onDrawPLAPreheatSubMenu, Draw_Preheat1_Menu); + #if PREHEAT_COUNT >= 2 + MENU_ITEM_F(ICON_SetABSPreheat, MSG_PREHEAT_2_SETTINGS, onDrawABSPreheatSubMenu, Draw_Preheat2_Menu); + #if PREHEAT_COUNT >= 3 + MENU_ITEM_F(ICON_SetCustomPreheat, MSG_PREHEAT_3_SETTINGS, onDrawSubMenu, Draw_Preheat3_Menu); + #endif #endif #endif } @@ -3459,13 +3438,13 @@ void Draw_MaxSpeed_Menu() { if (CurrentMenu != MaxSpeedMenu) { CurrentMenu = MaxSpeedMenu; SetMenuTitle({1, 16, 28, 13}, GET_TEXT_F(MSG_MAXSPEED)); - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Motion_Menu); - EDIT_ITEM(ICON_MaxSpeedX, GET_TEXT_F(MSG_MAXSPEED_X), onDrawMaxSpeedX, SetMaxSpeedX, &planner.settings.max_feedrate_mm_s[X_AXIS]); - EDIT_ITEM(ICON_MaxSpeedY, GET_TEXT_F(MSG_MAXSPEED_Y), onDrawMaxSpeedY, SetMaxSpeedY, &planner.settings.max_feedrate_mm_s[Y_AXIS]); - EDIT_ITEM(ICON_MaxSpeedZ, GET_TEXT_F(MSG_MAXSPEED_Z), onDrawMaxSpeedZ, SetMaxSpeedZ, &planner.settings.max_feedrate_mm_s[Z_AXIS]); + MenuItemsPrepare(5); + BACK_ITEM(Draw_Motion_Menu); + EDIT_ITEM_F(ICON_MaxSpeedX, MSG_MAXSPEED_X, onDrawMaxSpeedX, SetMaxSpeedX, &planner.settings.max_feedrate_mm_s[X_AXIS]); + EDIT_ITEM_F(ICON_MaxSpeedY, MSG_MAXSPEED_Y, onDrawMaxSpeedY, SetMaxSpeedY, &planner.settings.max_feedrate_mm_s[Y_AXIS]); + EDIT_ITEM_F(ICON_MaxSpeedZ, MSG_MAXSPEED_Z, onDrawMaxSpeedZ, SetMaxSpeedZ, &planner.settings.max_feedrate_mm_s[Z_AXIS]); #if HAS_HOTEND - EDIT_ITEM(ICON_MaxSpeedE, GET_TEXT_F(MSG_MAXSPEED_E), onDrawMaxSpeedE, SetMaxSpeedE, &planner.settings.max_feedrate_mm_s[E_AXIS]); + EDIT_ITEM_F(ICON_MaxSpeedE, MSG_MAXSPEED_E, onDrawMaxSpeedE, SetMaxSpeedE, &planner.settings.max_feedrate_mm_s[E_AXIS]); #endif } CurrentMenu->draw(); @@ -3477,13 +3456,13 @@ void Draw_MaxAccel_Menu() { if (CurrentMenu != MaxAccelMenu) { CurrentMenu = MaxAccelMenu; SetMenuTitle({1, 16, 28, 13}, GET_TEXT_F(MSG_ACCELERATION)); - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Motion_Menu); - EDIT_ITEM(ICON_MaxAccX, GET_TEXT_F(MSG_AMAX_A), onDrawMaxAccelX, SetMaxAccelX, &planner.settings.max_acceleration_mm_per_s2[X_AXIS]); - EDIT_ITEM(ICON_MaxAccY, GET_TEXT_F(MSG_AMAX_B), onDrawMaxAccelY, SetMaxAccelY, &planner.settings.max_acceleration_mm_per_s2[Y_AXIS]); - EDIT_ITEM(ICON_MaxAccZ, GET_TEXT_F(MSG_AMAX_C), onDrawMaxAccelZ, SetMaxAccelZ, &planner.settings.max_acceleration_mm_per_s2[Z_AXIS]); + MenuItemsPrepare(5); + BACK_ITEM(Draw_Motion_Menu); + EDIT_ITEM_F(ICON_MaxAccX, MSG_AMAX_A, onDrawMaxAccelX, SetMaxAccelX, &planner.settings.max_acceleration_mm_per_s2[X_AXIS]); + EDIT_ITEM_F(ICON_MaxAccY, MSG_AMAX_B, onDrawMaxAccelY, SetMaxAccelY, &planner.settings.max_acceleration_mm_per_s2[Y_AXIS]); + EDIT_ITEM_F(ICON_MaxAccZ, MSG_AMAX_C, onDrawMaxAccelZ, SetMaxAccelZ, &planner.settings.max_acceleration_mm_per_s2[Z_AXIS]); #if HAS_HOTEND - EDIT_ITEM(ICON_MaxAccE, GET_TEXT_F(MSG_AMAX_E), onDrawMaxAccelE, SetMaxAccelE, &planner.settings.max_acceleration_mm_per_s2[E_AXIS]); + EDIT_ITEM_F(ICON_MaxAccE, MSG_AMAX_E, onDrawMaxAccelE, SetMaxAccelE, &planner.settings.max_acceleration_mm_per_s2[E_AXIS]); #endif } CurrentMenu->draw(); @@ -3496,13 +3475,13 @@ void Draw_MaxAccel_Menu() { if (CurrentMenu != MaxJerkMenu) { CurrentMenu = MaxJerkMenu; SetMenuTitle({1, 16, 28, 13}, GET_TEXT_F(MSG_JERK)); - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Motion_Menu); - EDIT_ITEM(ICON_MaxSpeedJerkX, GET_TEXT_F(MSG_VA_JERK), onDrawMaxJerkX, SetMaxJerkX, &planner.max_jerk[X_AXIS]); - EDIT_ITEM(ICON_MaxSpeedJerkY, GET_TEXT_F(MSG_VB_JERK), onDrawMaxJerkY, SetMaxJerkY, &planner.max_jerk[Y_AXIS]); - EDIT_ITEM(ICON_MaxSpeedJerkZ, GET_TEXT_F(MSG_VC_JERK), onDrawMaxJerkZ, SetMaxJerkZ, &planner.max_jerk[Z_AXIS]); + MenuItemsPrepare(5); + BACK_ITEM(Draw_Motion_Menu); + EDIT_ITEM_F(ICON_MaxSpeedJerkX, MSG_VA_JERK, onDrawMaxJerkX, SetMaxJerkX, &planner.max_jerk[X_AXIS]); + EDIT_ITEM_F(ICON_MaxSpeedJerkY, MSG_VB_JERK, onDrawMaxJerkY, SetMaxJerkY, &planner.max_jerk[Y_AXIS]); + EDIT_ITEM_F(ICON_MaxSpeedJerkZ, MSG_VC_JERK, onDrawMaxJerkZ, SetMaxJerkZ, &planner.max_jerk[Z_AXIS]); #if HAS_HOTEND - EDIT_ITEM(ICON_MaxSpeedJerkE, GET_TEXT_F(MSG_VE_JERK), onDrawMaxJerkE, SetMaxJerkE, &planner.max_jerk[E_AXIS]); + EDIT_ITEM_F(ICON_MaxSpeedJerkE, MSG_VE_JERK, onDrawMaxJerkE, SetMaxJerkE, &planner.max_jerk[E_AXIS]); #endif } CurrentMenu->draw(); @@ -3515,13 +3494,13 @@ void Draw_Steps_Menu() { if (CurrentMenu != StepsMenu) { CurrentMenu = StepsMenu; SetMenuTitle({1, 16, 28, 13}, GET_TEXT_F(MSG_STEPS_PER_MM)); - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawBack, Draw_Motion_Menu); - EDIT_ITEM(ICON_StepX, GET_TEXT_F(MSG_A_STEPS), onDrawStepsX, SetStepsX, &planner.settings.axis_steps_per_mm[X_AXIS]); - EDIT_ITEM(ICON_StepY, GET_TEXT_F(MSG_B_STEPS), onDrawStepsY, SetStepsY, &planner.settings.axis_steps_per_mm[Y_AXIS]); - EDIT_ITEM(ICON_StepZ, GET_TEXT_F(MSG_C_STEPS), onDrawStepsZ, SetStepsZ, &planner.settings.axis_steps_per_mm[Z_AXIS]); + MenuItemsPrepare(5); + BACK_ITEM(Draw_Motion_Menu); + EDIT_ITEM_F(ICON_StepX, MSG_A_STEPS, onDrawStepsX, SetStepsX, &planner.settings.axis_steps_per_mm[X_AXIS]); + EDIT_ITEM_F(ICON_StepY, MSG_B_STEPS, onDrawStepsY, SetStepsY, &planner.settings.axis_steps_per_mm[Y_AXIS]); + EDIT_ITEM_F(ICON_StepZ, MSG_C_STEPS, onDrawStepsZ, SetStepsZ, &planner.settings.axis_steps_per_mm[Z_AXIS]); #if HAS_HOTEND - EDIT_ITEM(ICON_StepE, GET_TEXT_F(MSG_E_STEPS), onDrawStepsE, SetStepsE, &planner.settings.axis_steps_per_mm[E_AXIS]); + EDIT_ITEM_F(ICON_StepE, MSG_E_STEPS, onDrawStepsE, SetStepsE, &planner.settings.axis_steps_per_mm[E_AXIS]); #endif } CurrentMenu->draw(); @@ -3530,63 +3509,51 @@ void Draw_Steps_Menu() { #if HAS_HOTEND void Draw_HotendPID_Menu() { checkkey = Menu; - if (!HotendPIDMenu) HotendPIDMenu = new MenuClass(); - if (CurrentMenu != HotendPIDMenu) { - CurrentMenu = HotendPIDMenu; - CurrentMenu->MenuTitle.SetCaption(F("Hotend PID Settings")); - DWINUI::MenuItemsPrepare(8); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawMenuItem, Draw_AdvancedSettings_Menu); - MENU_ITEM(ICON_PIDNozzle, F("Hotend PID"), onDrawMenuItem, HotendPID); + if (SetMenu(HotendPIDMenu, F(STR_HOTEND_PID " Settings"),8)) { + BACK_ITEM(Draw_AdvancedSettings_Menu); + MENU_ITEM(ICON_PIDNozzle, F(STR_HOTEND_PID), onDrawMenuItem, HotendPID); EDIT_ITEM(ICON_PIDValue, F("Set" STR_KP), onDrawPFloat2Menu, SetKp, &thermalManager.temp_hotend[0].pid.Kp); EDIT_ITEM(ICON_PIDValue, F("Set" STR_KI), onDrawPIDi, SetKi, &thermalManager.temp_hotend[0].pid.Ki); EDIT_ITEM(ICON_PIDValue, F("Set" STR_KD), onDrawPIDd, SetKd, &thermalManager.temp_hotend[0].pid.Kd); - EDIT_ITEM(ICON_Temperature, GET_TEXT_F(MSG_TEMPERATURE), onDrawPIntMenu, SetHotendPidT, &HMI_data.HotendPidT); - EDIT_ITEM(ICON_PIDcycles, GET_TEXT_F(MSG_PID_CYCLE), onDrawPIntMenu, SetPidCycles, &HMI_data.PidCycles); + EDIT_ITEM_F(ICON_Temperature, MSG_TEMPERATURE, onDrawPIntMenu, SetHotendPidT, &HMI_data.HotendPidT); + EDIT_ITEM_F(ICON_PIDcycles, MSG_PID_CYCLE, onDrawPIntMenu, SetPidCycles, &HMI_data.PidCycles); #if ENABLED(EEPROM_SETTINGS) - MENU_ITEM(ICON_WriteEEPROM, GET_TEXT_F(MSG_STORE_EEPROM), onDrawMenuItem, WriteEeprom); + MENU_ITEM_F(ICON_WriteEEPROM, MSG_STORE_EEPROM, onDrawMenuItem, WriteEeprom); #endif } - CurrentMenu->draw(); + UpdateMenu(HotendPIDMenu); } #endif #if HAS_HEATED_BED void Draw_BedPID_Menu() { checkkey = Menu; - if (!BedPIDMenu) BedPIDMenu = new MenuClass(); - if (CurrentMenu != BedPIDMenu) { - CurrentMenu = BedPIDMenu; - CurrentMenu->MenuTitle.SetCaption(F("Bed PID Settings")); - DWINUI::MenuItemsPrepare(8); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawMenuItem, Draw_AdvancedSettings_Menu); - MENU_ITEM(ICON_PIDNozzle, F("Bed PID"), onDrawMenuItem,BedPID); + if (SetMenu(BedPIDMenu, F(STR_BED_PID " Settings"),8)) { + BACK_ITEM(Draw_AdvancedSettings_Menu); + MENU_ITEM(ICON_PIDNozzle, F(STR_BED_PID), onDrawMenuItem,BedPID); EDIT_ITEM(ICON_PIDValue, F("Set" STR_KP), onDrawPFloat2Menu, SetKp, &thermalManager.temp_bed.pid.Kp); EDIT_ITEM(ICON_PIDValue, F("Set" STR_KI), onDrawPIDi, SetKi, &thermalManager.temp_bed.pid.Ki); EDIT_ITEM(ICON_PIDValue, F("Set" STR_KD), onDrawPIDd, SetKd, &thermalManager.temp_bed.pid.Kd); - EDIT_ITEM(ICON_Temperature, GET_TEXT_F(MSG_TEMPERATURE), onDrawPIntMenu, SetBedPidT, &HMI_data.BedPidT); - EDIT_ITEM(ICON_PIDcycles, GET_TEXT_F(MSG_PID_CYCLE), onDrawPIntMenu, SetPidCycles, &HMI_data.PidCycles); + EDIT_ITEM_F(ICON_Temperature, MSG_TEMPERATURE, onDrawPIntMenu, SetBedPidT, &HMI_data.BedPidT); + EDIT_ITEM_F(ICON_PIDcycles, MSG_PID_CYCLE, onDrawPIntMenu, SetPidCycles, &HMI_data.PidCycles); #if ENABLED(EEPROM_SETTINGS) - MENU_ITEM(ICON_WriteEEPROM, GET_TEXT_F(MSG_STORE_EEPROM), onDrawMenuItem, WriteEeprom); + MENU_ITEM_F(ICON_WriteEEPROM, MSG_STORE_EEPROM, onDrawMenuItem, WriteEeprom); #endif } - CurrentMenu->draw(); + UpdateMenu(BedPIDMenu); } #endif -#if HAS_BED_PROBE +#if ENABLED(BABYSTEP_ZPROBE_OFFSET) void Draw_ZOffsetWiz_Menu() { checkkey = Menu; - if (!ZOffsetWizMenu) ZOffsetWizMenu = new MenuClass(); - if (CurrentMenu != ZOffsetWizMenu) { - CurrentMenu = ZOffsetWizMenu; - CurrentMenu->MenuTitle.SetCaption(GET_TEXT_F(MSG_PROBE_WIZARD)); - DWINUI::MenuItemsPrepare(4); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawMenuItem, Draw_Prepare_Menu); - MENU_ITEM(ICON_Homing, GET_TEXT_F(MSG_AUTO_HOME), onDrawMenuItem, AutoHome); + if (SetMenu(ZOffsetWizMenu, GET_TEXT_F(MSG_PROBE_WIZARD), 4)) { + BACK_ITEM(Draw_Prepare_Menu); + MENU_ITEM_F(ICON_Homing, MSG_AUTO_HOME, onDrawMenuItem, AutoHome); MENU_ITEM(ICON_MoveZ0, F("Move Z to Home"), onDrawMenuItem, SetMoveZto0); - EDIT_ITEM(ICON_Zoffset, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), onDrawPFloat2Menu, SetZOffset, &BABY_Z_VAR); + EDIT_ITEM_F(ICON_Zoffset, MSG_ZPROBE_ZOFFSET, onDrawPFloat2Menu, SetZOffset, &BABY_Z_VAR); } - CurrentMenu->draw(); + UpdateMenu(ZOffsetWizMenu); if (!axis_is_trusted(Z_AXIS)) LCD_MESSAGE_F("WARNING: Z position unknown, move Z to home"); } #endif @@ -3594,19 +3561,165 @@ void Draw_Steps_Menu() { #if ENABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU) void Draw_Homing_Menu() { checkkey = Menu; - if (!HomingMenu) HomingMenu = new MenuClass(); - if (CurrentMenu != HomingMenu) { - CurrentMenu = HomingMenu; - CurrentMenu->MenuTitle.SetCaption(GET_TEXT_F(MSG_HOMING)); - DWINUI::MenuItemsPrepare(5); - MENU_ITEM(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawMenuItem, Draw_Prepare_Menu); - MENU_ITEM(ICON_Homing, GET_TEXT_F(MSG_AUTO_HOME), onDrawMenuItem, AutoHome); - MENU_ITEM(ICON_HomeX, GET_TEXT_F(MSG_AUTO_HOME_X), onDrawMenuItem, HomeX); - MENU_ITEM(ICON_HomeY, GET_TEXT_F(MSG_AUTO_HOME_Y), onDrawMenuItem, HomeY); - MENU_ITEM(ICON_HomeZ, GET_TEXT_F(MSG_AUTO_HOME_Z), onDrawMenuItem, HomeZ); + if (SetMenu(HomingMenu, GET_TEXT_F(MSG_HOMING), 5)) { + BACK_ITEM(Draw_Prepare_Menu); + MENU_ITEM_F(ICON_Homing, MSG_AUTO_HOME, onDrawMenuItem, AutoHome); + MENU_ITEM_F(ICON_HomeX, MSG_AUTO_HOME_X, onDrawMenuItem, HomeX); + MENU_ITEM_F(ICON_HomeY, MSG_AUTO_HOME_Y, onDrawMenuItem, HomeY); + MENU_ITEM_F(ICON_HomeZ, MSG_AUTO_HOME_Z, onDrawMenuItem, HomeZ); } - CurrentMenu->draw(); + UpdateMenu(HomingMenu); } #endif +#if ENABLED(FWRETRACT) + void Draw_FWRetract_Menu() { + checkkey = Menu; + if (SetMenu(FWRetractMenu, GET_TEXT_F(MSG_FWRETRACT), 6)) { + BACK_ITEM(Return_FWRetract_Menu); + EDIT_ITEM_F(ICON_FWRetLength, MSG_CONTROL_RETRACT, onDrawPFloatMenu, SetRetractLength, &fwretract.settings.retract_length); + EDIT_ITEM_F(ICON_FWRetSpeed, MSG_SINGLENOZZLE_RETRACT_SPEED, onDrawPFloatMenu, SetRetractSpeed, &fwretract.settings.retract_feedrate_mm_s); + EDIT_ITEM_F(ICON_FWRetZRaise, MSG_CONTROL_RETRACT_ZHOP, onDrawPFloat2Menu, SetZRaise, &fwretract.settings.retract_zraise); + EDIT_ITEM_F(ICON_FWRecSpeed, MSG_SINGLENOZZLE_UNRETRACT_SPEED, onDrawPFloatMenu, SetRecoverSpeed, &fwretract.settings.retract_recover_feedrate_mm_s); + EDIT_ITEM_F(ICON_FWRecExtra, MSG_CONTROL_RETRACT_RECOVER, onDrawPFloatMenu, SetAddRecover, &fwretract.settings.retract_recover_extra); + } + UpdateMenu(FWRetractMenu); + } +#endif + +//============================================================================= +// Mesh Bed Leveling +//============================================================================= + +#if HAS_MESH + + void ApplyMeshFadeHeight() { set_z_fade_height(planner.z_fade_height); } + void SetMeshFadeHeight() { SetPFloatOnClick(0, 100, 1, ApplyMeshFadeHeight); } + + void SetMeshActive() { + set_bed_leveling_enabled(!planner.leveling_active); + Draw_Chkb_Line(CurrentMenu->line(), planner.leveling_active); + DWIN_UpdateLCD(); + } + + #if BOTH(HAS_HEATED_BED, PREHEAT_BEFORE_LEVELING) + void SetBedLevT() { SetPIntOnClick(MIN_BEDTEMP, MAX_BEDTEMP); } + #endif + + uint8_t mesh_x = 0; + uint8_t mesh_y = 0; + #define Z_OFFSET_MIN -3 + #define Z_OFFSET_MAX 3 + + void LiveEditMesh() { ((MenuItemPtrClass*)EditZValueItem)->value = &Z_VALUES_ARR[HMI_value.Select ? mesh_x : MenuData.Value][HMI_value.Select ? MenuData.Value : mesh_y]; EditZValueItem->redraw(); } + void ApplyEditMeshX() { mesh_x = MenuData.Value; } + void SetEditMeshX() { HMI_value.Select = 0; SetIntOnClick(0, GRID_MAX_POINTS_X - 1, mesh_x, ApplyEditMeshX, LiveEditMesh); } + void ApplyEditMeshY() { mesh_y = MenuData.Value; } + void SetEditMeshY() { HMI_value.Select = 1; SetIntOnClick(0, GRID_MAX_POINTS_Y - 1, mesh_y, ApplyEditMeshY, LiveEditMesh); } + void SetEditZValue() { SetPFloatOnClick(Z_OFFSET_MIN, Z_OFFSET_MAX, 3); } + +#endif + +#if ENABLED(AUTO_BED_LEVELING_UBL) + + void ApplyUBLSlot() { ubl.storage_slot = MenuData.Value; } + void SetUBLSlot() { SetIntOnClick(0, settings.calc_num_meshes() - 1, ubl.storage_slot, ApplyUBLSlot); } + void onDrawUBLSlot(MenuItemClass* menuitem, int8_t line) { + if (ubl.storage_slot < 0) ubl.storage_slot = 0; + onDrawIntMenu(menuitem, line, ubl.storage_slot); + } + + void ApplyUBLTiltGrid() { ubl_tools.tilt_grid = MenuData.Value; } + void SetUBLTiltGrid() { SetIntOnClick(1, 3, ubl_tools.tilt_grid, ApplyUBLTiltGrid); } + + void UBLTiltMesh() { + if (ubl.storage_slot < 0) ubl.storage_slot = 0; + char buf[15]; + if (ubl_tools.tilt_grid > 1) { + sprintf_P(buf, PSTR("G28O\nG29 J%i"), ubl_tools.tilt_grid); + gcode.process_subcommands_now(buf); + } + else + gcode.process_subcommands_now(F("G28O\nG29J")); + LCD_MESSAGE(MSG_UBL_MESH_TILTED); + } + + void UBLSmartFillMesh() { + ubl.smart_fill_mesh(); + LCD_MESSAGE(MSG_UBL_MESH_FILLED); + } + + bool UBLValidMesh() { + const bool valid = ubl_tools.validate(); + if (!valid) ubl.invalidate(); + return valid; + } + + void UBLSaveMesh() { + if (ubl.storage_slot < 0) ubl.storage_slot = 0; + settings.store_mesh(ubl.storage_slot); + ui.status_printf(0, GET_TEXT_F(MSG_MESH_SAVED), ubl.storage_slot); + DONE_BUZZ(true); + } + + void UBLLoadMesh() { + if (ubl.storage_slot < 0) ubl.storage_slot = 0; + settings.load_mesh(ubl.storage_slot); + if (UBLValidMesh()) { + ui.status_printf(0, GET_TEXT_F(MSG_MESH_LOADED), ubl.storage_slot); + DONE_BUZZ(true); + } + else { + LCD_MESSAGE_F("Invalid Mesh Loaded"); + DONE_BUZZ(false); + } + } + +#endif // AUTO_BED_LEVELING_UBL + +#if HAS_MESH + void Draw_MeshSet_Menu() { + checkkey = Menu; + if (SetMenu(MeshMenu, GET_TEXT_F(MSG_MESH_LEVELING), 15)) { + BACK_ITEM(Draw_AdvancedSettings_Menu); + #if BOTH(HAS_HEATED_BED, PREHEAT_BEFORE_LEVELING) + EDIT_ITEM_F(ICON_Temperature, MSG_UBL_SET_TEMP_BED, onDrawPIntMenu, SetBedLevT, &HMI_data.BedLevT); + #endif + EDIT_ITEM_F(ICON_SetZOffset, MSG_Z_FADE_HEIGHT, onDrawPFloatMenu, SetMeshFadeHeight, &planner.z_fade_height); + EDIT_ITEM_F(ICON_UBLActive, MSG_ACTIVATE_MESH, onDrawChkbMenu, SetMeshActive, &planner.leveling_active); + #if HAS_BED_PROBE + MENU_ITEM_F(ICON_Level, MSG_AUTO_MESH, onDrawMenuItem, AutoLev); + #endif + #if ENABLED(AUTO_BED_LEVELING_UBL) + EDIT_ITEM_F(ICON_UBLActive, MSG_UBL_STORAGE_SLOT, onDrawUBLSlot, SetUBLSlot, &ubl.storage_slot); + MENU_ITEM_F(ICON_UBLActive, MSG_UBL_SAVE_MESH, onDrawMenuItem, UBLSaveMesh); + MENU_ITEM_F(ICON_UBLActive, MSG_UBL_LOAD_MESH, onDrawMenuItem, UBLLoadMesh); + EDIT_ITEM_F(ICON_UBLActive, MSG_UBL_TILTING_GRID, onDrawPInt8Menu, SetUBLTiltGrid, &ubl_tools.tilt_grid); + MENU_ITEM_F(ICON_UBLActive, MSG_UBL_TILT_MESH, onDrawMenuItem, UBLTiltMesh); + MENU_ITEM_F(ICON_UBLActive, MSG_UBL_SMART_FILLIN, onDrawMenuItem, UBLSmartFillMesh); + #endif + #if ENABLED(MESH_EDIT_MENU) + MENU_ITEM_F(ICON_UBLActive, MSG_EDIT_MESH, onDrawSubMenu, Draw_EditMesh_Menu); + #endif + MENU_ITEM_F(ICON_MeshViewer, MSG_MESH_VIEW, onDrawSubMenu, DWIN_MeshViewer); + } + UpdateMenu(MeshMenu); + } + + #if ENABLED(MESH_EDIT_MENU) + void Draw_EditMesh_Menu() { + checkkey = Menu; + if (SetMenu(EditMeshMenu, GET_TEXT_F(MSG_EDIT_MESH), 4)) { + mesh_x = mesh_y = 0; + BACK_ITEM(Draw_MeshSet_Menu); + EDIT_ITEM_F(ICON_UBLActive, MSG_MESH_X, onDrawPInt8Menu, SetEditMeshX, &mesh_x); + EDIT_ITEM_F(ICON_UBLActive, MSG_MESH_Y, onDrawPInt8Menu, SetEditMeshY, &mesh_y); + EditZValueItem = EDIT_ITEM_F(ICON_UBLActive, MSG_MESH_EDIT_Z, onDrawPFloat3Menu, SetEditZValue, &Z_VALUES_ARR[mesh_x][mesh_y]); + } + UpdateMenu(EditMeshMenu); + } + #endif + +#endif // HAS_MESH + #endif // DWIN_LCD_PROUI diff --git a/Marlin/src/lcd/e3v2/proui/dwin.h b/Marlin/src/lcd/e3v2/proui/dwin.h index d1f0a90042..f4e550295e 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin.h +++ b/Marlin/src/lcd/e3v2/proui/dwin.h @@ -24,8 +24,8 @@ /** * DWIN Enhanced implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 3.15.2 - * Date: 2022/03/01 + * Version: 3.17.2 + * Date: 2022/04/08 */ #include "dwin_defines.h" @@ -73,12 +73,13 @@ enum pidresult_t : uint8_t { typedef struct { int8_t Color[3]; // Color components pidresult_t pidresult = PID_DONE; - int8_t Preheat = 0; // Material Select 0: PLA, 1: ABS, 2: Custom + uint8_t Select = 0; // Auxiliary selector variable AxisEnum axis = X_AXIS; // Axis Select } HMI_value_t; typedef struct { uint8_t language; + bool percent_flag:1; // percent was override by M73 bool remain_flag:1; // remain was override by M73 bool pause_flag:1; // printing is paused bool pause_action:1; // flag a pause action @@ -103,9 +104,53 @@ extern millis_t dwin_heat_time; void Popup_PowerLossRecovery(); #endif -// SD Card -void HMI_SDCardInit(); -void HMI_SDCardUpdate(); +// Tool Functions +#if ENABLED(EEPROM_SETTINGS) + void WriteEeprom(); + void ReadEeprom(); + void ResetEeprom(); + #if HAS_MESH + void SaveMesh(); + #endif +#endif +void RebootPrinter(); +void DisableMotors(); +void AutoLev(); +void AutoHome(); +#if HAS_PREHEAT + void DoPreheat0(); + void DoPreheat1(); + void DoPreheat2(); +#endif +void DoCoolDown(); +#if HAS_HOTEND + void HotendPID(); +#endif +#if HAS_HEATED_BED + void BedPID(); +#endif +#if ENABLED(BAUD_RATE_GCODE) + void HMI_SetBaudRate(); + void SetBaud115K(); + void SetBaud250K(); +#endif +#if HAS_LCD_BRIGHTNESS + void TurnOffBacklight(); +#endif +void ApplyExtMinT(); +void ParkHead(); +#if HAS_ONESTEP_LEVELING + void Trammingwizard(); +#endif +#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS) + void ApplyLEDColor(); +#endif +#if ENABLED(AUTO_BED_LEVELING_UBL) + void UBLTiltMesh(); + bool UBLValidMesh(); + void UBLSaveMesh(); + void UBLLoadMesh(); +#endif // Other void Goto_PrintProcess(); @@ -115,28 +160,18 @@ void Goto_PowerLossRecovery(); void Goto_ConfirmToPrint(); void DWIN_Draw_Dashboard(const bool with_update); // Status Area void Draw_Main_Area(); // Redraw main area +void DWIN_DrawStatusLine(const char *text); // Draw simple status text +void DWIN_DrawStatusLine(FSTR_P fstr); +void DWIN_RedrawDash(); // Redraw Dash and Status line void DWIN_RedrawScreen(); // Redraw all screen elements 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 language 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_WaitForUser(); void HMI_SaveProcessID(const uint8_t id); -void HMI_AudioFeedback(const bool success=true); +void HMI_SDCardInit(); +void HMI_SDCardUpdate(); void EachMomentUpdate(); void update_variable(); void DWIN_InitScreen(); @@ -248,3 +283,12 @@ void Draw_Steps_Menu(); #if ENABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU) void Draw_Homing_Menu(); #endif +#if ENABLED(FWRETRACT) + void Draw_FWRetract_Menu(); +#endif +#if HAS_MESH + void Draw_MeshSet_Menu(); + #if ENABLED(MESH_EDIT_MENU) + void Draw_EditMesh_Menu(); + #endif +#endif diff --git a/Marlin/src/lcd/e3v2/proui/dwin_defines.h b/Marlin/src/lcd/e3v2/proui/dwin_defines.h index 1e361c8c11..bfeb06d763 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin_defines.h +++ b/Marlin/src/lcd/e3v2/proui/dwin_defines.h @@ -34,6 +34,23 @@ #include "../../../inc/MarlinConfigPre.h" #include +#define HAS_ESDIAG 1 +#if defined(__STM32F1__) || defined(STM32F1) + #define DASH_REDRAW 1 +#endif + +#if DISABLED(LIMITED_MAX_FR_EDITING) + #error "LIMITED_MAX_FR_EDITING is required with ProUI." +#endif +#if DISABLED(LIMITED_MAX_ACCEL_EDITING) + #error "LIMITED_MAX_ACCEL_EDITING is required with ProUI." +#endif +#if ENABLED(CLASSIC_JERK) && DISABLED(LIMITED_JERK_EDITING) + #error "LIMITED_JERK_EDITING is required with ProUI." +#endif +#if DISABLED(FILAMENT_RUNOUT_SENSOR) + #error "FILAMENT_RUNOUT_SENSOR is required with ProUI." +#endif #if DISABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU) #error "INDIVIDUAL_AXIS_HOMING_SUBMENU is required with ProUI." #endif @@ -81,7 +98,7 @@ #define HAS_ESDIAG 1 #if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS) - #define Def_Leds_Color LEDColorWhite() + #define Def_Leds_Color 0xFFFFFFFF #endif #if ENABLED(CASELIGHT_USES_BRIGHTNESS) #define Def_CaseLight_Brightness 255 @@ -128,14 +145,13 @@ typedef struct { #endif bool FullManualTramming = false; // Led - #if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS) - LEDColor Led_Color = Def_Leds_Color; + #if ENABLED(MESH_BED_LEVELING) + float ManualZOffset = 0; #endif - // Case Light - #if ENABLED(CASELIGHT_USES_BRIGHTNESS) - uint8_t CaseLight_Brightness = Def_CaseLight_Brightness; + #if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS) + uint32_t LED_Color = Def_Leds_Color; #endif } HMI_data_t; -static constexpr size_t eeprom_data_size = 64; +static constexpr size_t eeprom_data_size = sizeof(HMI_data_t); extern HMI_data_t HMI_data; diff --git a/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp b/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp index 3da3fc8086..f2cefe0cb7 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwin_lcd.cpp @@ -23,8 +23,8 @@ /** * DWIN Enhanced implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 3.9.1 - * Date: 2022/02/08 + * Version: 3.10.1 + * Date: 2022/03/06 */ #include "../../../inc/MarlinConfigPre.h" @@ -35,54 +35,6 @@ #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 cdffb96f2f..6e0a254db4 100644 --- a/Marlin/src/lcd/e3v2/proui/dwin_lcd.h +++ b/Marlin/src/lcd/e3v2/proui/dwin_lcd.h @@ -24,30 +24,12 @@ /** * DWIN Enhanced implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 3.9.1 - * Date: 2022/02/08 + * Version: 3.10.1 + * Date: 2022/03/06 */ #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/dwinui.cpp b/Marlin/src/lcd/e3v2/proui/dwinui.cpp index e190fa06fb..ecb4754a0f 100644 --- a/Marlin/src/lcd/e3v2/proui/dwinui.cpp +++ b/Marlin/src/lcd/e3v2/proui/dwinui.cpp @@ -23,8 +23,8 @@ /** * DWIN Enhanced implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 3.15.1 - * Date: 2022/02/25 + * Version: 3.17.1 + * Date: 2022/04/12 */ #include "../../../inc/MarlinConfigPre.h" @@ -39,12 +39,6 @@ //#define DEBUG_OUT 1 #include "../../../core/debug_out.h" -int8_t MenuItemTotal = 0; -int8_t MenuItemCount = 0; -MenuItemClass** MenuItems = nullptr; -MenuClass *CurrentMenu = nullptr; -MenuClass *PreviousMenu = nullptr; - xy_int_t DWINUI::cursor = { 0 }; uint16_t DWINUI::pencolor = Color_White; uint16_t DWINUI::textcolor = Def_Text_Color; @@ -53,16 +47,15 @@ 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; -void (*DWINUI::onTitleDraw)(TitleClass* title)=nullptr; -void (*DWINUI::onMenuDraw)(MenuClass* menu)=nullptr; +void (*DWINUI::onTitleDraw)(TitleClass* title) = nullptr; void DWINUI::init() { - 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)); + const bool hs = DWIN_Handshake(); UNUSED(hs); + #if ENABLED(DEBUG_DWIN) + SERIAL_ECHOPGM("DWIN_Handshake "); + SERIAL_ECHOLNF(hs ? F("ok.") : F("error.")); + #endif DWIN_Frame_SetDir(1); cursor.reset(); pencolor = Color_White; @@ -164,16 +157,19 @@ void DWINUI::Draw_CenteredString(bool bShow, uint8_t size, uint16_t color, uint1 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(uint16_t color, const char c) { +// Draw a char +// color: Character color +// x: abscissa of the display +// y: ordinate of the display +// c: ASCII code of char +void DWINUI::Draw_Char(uint16_t color, uint16_t x, uint16_t y, const char c) { const char string[2] = { c, 0}; - DWIN_Draw_String(false, font, color, backcolor, cursor.x, cursor.y, string, 1); + DWIN_Draw_String(false, font, color, backcolor, x, y, string, 1); +} + +// Draw a char at cursor position and increment cursor +void DWINUI::Draw_Char(uint16_t color, const char c) { + Draw_Char(color, cursor.x, cursor.y, c); MoveBy(fontWidth(font), 0); } @@ -190,6 +186,36 @@ void DWINUI::Draw_String(uint16_t color, const char * const string, uint16_t rli MoveBy(strlen(string) * fontWidth(font), 0); } +// Draw a numeric integer value +// bShow: true=display background color; false=don't display background color +// signedMode: 1=signed; 0=unsigned +// size: Font size +// color: Character color +// bColor: Background color +// iNum: Number of digits +// x/y: Upper-left coordinate +// value: Integer value +void DWINUI::Draw_Int(uint8_t bShow, bool signedMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, int32_t value) { + char nstr[10]; + sprintf_P(nstr, PSTR("%*li"), (signedMode ? iNum + 1 : iNum), value); + DWIN_Draw_String(bShow, size, color, bColor, x, y, nstr); +} + +// Draw a numeric float value +// bShow: true=display background color; false=don't display background color +// signedMode: 1=signed; 0=unsigned +// size: Font size +// color: Character color +// bColor: Background color +// iNum: Number of digits +// fNum: Number of decimal digits +// x/y: Upper-left coordinate +// value: float value +void DWINUI::Draw_Float(uint8_t bShow, bool signedMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) { + char nstr[10]; + DWIN_Draw_String(bShow, size, color, bColor, x, y, dtostrf(value, iNum + (signedMode ? 2:1) + fNum, fNum, nstr)); +} + // ------------------------- 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) { @@ -204,6 +230,7 @@ void DWINUI::Draw_Button(uint8_t id, uint16_t x, uint16_t y) { 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; + case BTN_Purge : Draw_Button(GET_TEXT_F(MSG_BUTTON_PURGE), x, y); break; default: break; } } @@ -265,7 +292,7 @@ uint16_t DWINUI::ColorInt(int16_t val, int16_t minv, int16_t maxv, uint16_t colo return RGB(R, G, B); } -// Color Interpolator through Red->Yellow->Green->Blue +// Color Interpolator through Red->Yellow->Green->Blue (Pro UI) // val : Interpolator minv..maxv // minv : Minimum value // maxv : Maximum value @@ -308,33 +335,6 @@ void DWINUI::ClearMainArea() { DWIN_Draw_Rectangle(1, backcolor, 0, TITLE_HEIGHT, DWIN_WIDTH - 1, STATUS_Y - 1); } -void DWINUI::MenuItemsClear() { - if (MenuItems == nullptr) return; - for (int8_t i = 0; i < MenuItemCount; i++) delete MenuItems[i]; - delete[] MenuItems; - MenuItems = nullptr; - MenuItemCount = 0; - MenuItemTotal = 0; -} - -void DWINUI::MenuItemsPrepare(int8_t totalitems) { - MenuItemsClear(); - MenuItemTotal = totalitems; - MenuItems = new MenuItemClass*[totalitems]; -} - -MenuItemClass* DWINUI::MenuItemsAdd(MenuItemClass* menuitem) { - if (MenuItemCount < MenuItemTotal) { - MenuItems[MenuItemCount] = menuitem; - menuitem->pos = MenuItemCount++; - return menuitem; - } - else { - delete menuitem; - return nullptr; - } -} - /* Title Class ==============================================================*/ TitleClass Title; @@ -375,85 +375,4 @@ void TitleClass::FrameCopy(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { FrameCopy(1, x, y, x + w - 1, y + h - 1); } -/* Menu Class ===============================================================*/ - -MenuClass::MenuClass() { - selected = 0; - topline = 0; -} - -void MenuClass::draw() { - MenuTitle.draw(); - if (DWINUI::onMenuDraw != nullptr) (*DWINUI::onMenuDraw)(this); - for (int8_t i = 0; i < MenuItemCount; i++) - MenuItems[i]->draw(i - topline); - if (DWINUI::onCursorDraw != nullptr) DWINUI::onCursorDraw(line()); - DWIN_UpdateLCD(); -} - -void MenuClass::onScroll(bool dir) { - int8_t sel = selected; - if (dir) sel++; else sel--; - LIMIT(sel, 0, MenuItemCount - 1); - if (sel != selected) { - if (DWINUI::onCursorErase != nullptr) DWINUI::onCursorErase(line()); - if ((sel - topline) == TROWS) { - DWIN_Frame_AreaMove(1, DWIN_SCROLL_UP, MLINE, DWINUI::backcolor, 0, TITLE_HEIGHT + 1, DWIN_WIDTH, STATUS_Y - 1); - topline++; - MenuItems[sel]->draw(TROWS - 1); - } - if ((sel < topline)) { - DWIN_Frame_AreaMove(1, DWIN_SCROLL_DOWN, MLINE, DWINUI::backcolor, 0, TITLE_HEIGHT + 1, DWIN_WIDTH, STATUS_Y - 1); - topline--; - MenuItems[sel]->draw(0); - } - selected = sel; - if (DWINUI::onCursorDraw != nullptr) DWINUI::onCursorDraw(line()); - DWIN_UpdateLCD(); - } -} - -void MenuClass::onClick() { - if (MenuItems[selected]->onClick != nullptr) (*MenuItems[selected]->onClick)(); -} - -MenuItemClass *MenuClass::SelectedItem() { - return MenuItems[selected]; -} - -/* MenuItem Class ===========================================================*/ - -MenuItemClass::MenuItemClass(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)()) { - icon = cicon; - onClick = onclick; - onDraw = ondraw; - const uint8_t len = _MIN(sizeof(caption) - 1, strlen(text)); - memcpy(&caption[0], text, len); - caption[len] = '\0'; -} - -MenuItemClass::MenuItemClass(uint8_t cicon, uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)()) { - icon = cicon; - onClick = onclick; - onDraw = ondraw; - caption[0] = '\0'; - frameid = id; - frame = { x1, y1, x2, y2 }; -} - -void MenuItemClass::SetFrame(uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { - caption[0] = '\0'; - frameid = id; - frame = { x1, y1, x2, y2 }; -} - -void MenuItemClass::draw(int8_t line) { - if (line < 0 || line >= TROWS) return; - if (onDraw != nullptr) (*onDraw)(this, line); -}; - -MenuItemPtrClass::MenuItemPtrClass(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val) : MenuItemClass(cicon, text, ondraw, onclick) { - value = val; -}; - #endif // DWIN_LCD_PROUI diff --git a/Marlin/src/lcd/e3v2/proui/dwinui.h b/Marlin/src/lcd/e3v2/proui/dwinui.h index 6771c77d5d..f8ff091769 100644 --- a/Marlin/src/lcd/e3v2/proui/dwinui.h +++ b/Marlin/src/lcd/e3v2/proui/dwinui.h @@ -24,8 +24,8 @@ /** * DWIN Enhanced implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 3.15.1 - * Date: 2022/02/25 + * Version: 3.17.1 + * Date: 2022/04/12 */ #include "dwin_lcd.h" @@ -37,6 +37,7 @@ #define ICON_AdvSet ICON_Language #define ICON_BedSizeX ICON_PrintSize #define ICON_BedSizeY ICON_PrintSize +#define ICON_BedTramming ICON_SetHome #define ICON_Binary ICON_Contact #define ICON_Brightness ICON_Motion #define ICON_Cancel ICON_StockConfiguration @@ -50,10 +51,12 @@ #define ICON_FilUnload ICON_ReadEEPROM #define ICON_Flow ICON_StepE #define ICON_Folder ICON_More +#define ICON_FWRetract ICON_StepE #define ICON_FWRetLength ICON_StepE #define ICON_FWRetSpeed ICON_Setspeed #define ICON_FWRetZRaise ICON_MoveZ #define ICON_FWRecSpeed ICON_Setspeed +#define ICON_FWRecExtra ICON_StepE #define ICON_HomeX ICON_MoveX #define ICON_HomeY ICON_MoveY #define ICON_HomeZ ICON_MoveZ @@ -102,6 +105,9 @@ #define ICON_SetBaudRate ICON_Setspeed #define ICON_SetCustomPreheat ICON_SetEndTemp #define ICON_Sound ICON_Cool +#define ICON_TBSetup ICON_Contact +#define ICON_UBLActive ICON_HotendTemp + #define ICON_CaseLight ICON_Motion #define ICON_LedControl ICON_Motion @@ -111,12 +117,27 @@ #define BTN_Confirm 89 #define BTN_Print 90 #define BTN_Save 91 +#define BTN_Purge 92 // Extended and default UI Colors #define Color_Black 0 #define Color_Green RGB(0,63,0) #define Color_Aqua RGB(0,63,31) #define Color_Blue RGB(0,0,31) +#define Color_Light_White 0xBDD7 +#define Color_Light_Green 0x3460 +#define Color_Cyan 0x07FF +#define Color_Light_Cyan 0x04F3 +#define Color_Light_Blue 0x3A6A +#define Color_Magenta 0xF81F +#define Color_Light_Magenta 0x9813 +#define Color_Light_Red 0x8800 +#define Color_Orange 0xFA20 +#define Color_Light_Orange 0xFBC0 +#define Color_Light_Yellow 0x8BE0 +#define Color_Brown 0xCC27 +#define Color_Light_Brown 0x6204 +#define Color_Grey 0x18E3 // UI element defines and constants #define DWIN_FONT_MENU font8x16 @@ -130,7 +151,7 @@ #define UNITFDIGITS 1 #define MINUNITMULT POW(10, UNITFDIGITS) -constexpr uint16_t TITLE_HEIGHT = 30, // Title bar height +constexpr uint8_t TITLE_HEIGHT = 30, // Title bar height MLINE = 53, // Menu line height TROWS = (STATUS_Y - TITLE_HEIGHT) / MLINE, // Total rows MROWS = TROWS - 1, // Other-than-Back @@ -149,10 +170,6 @@ constexpr uint16_t TITLE_HEIGHT = 30, // Title bar heig // Menuitem caption Y position #define MBASE(L) (MYPOS(L) + CAPOFF) -// Create and add a MenuItem object to the menu array -#define MENU_ITEM(V...) DWINUI::MenuItemsAdd(new MenuItemClass(V)) -#define EDIT_ITEM(V...) DWINUI::MenuItemsAdd(new MenuItemPtrClass(V)) - typedef struct { uint16_t left, top, right, bottom; } rect_t; typedef struct { uint16_t x, y, w, h; } frame_rect_t; @@ -173,49 +190,6 @@ public: }; extern TitleClass Title; -class MenuItemClass { -protected: -public: - int8_t pos = 0; - uint8_t icon = 0; - char caption[32] = ""; - uint8_t frameid = 0; - rect_t frame = {0}; - void (*onDraw)(MenuItemClass* menuitem, int8_t line) = nullptr; - void (*onClick)() = nullptr; - MenuItemClass() {}; - MenuItemClass(uint8_t cicon, const char * const text=nullptr, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr); - MenuItemClass(uint8_t cicon, FSTR_P text = nullptr, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr) : MenuItemClass(cicon, FTOP(text), ondraw, onclick){} - MenuItemClass(uint8_t cicon, uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr); - void SetFrame(uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); - virtual ~MenuItemClass(){}; - virtual void draw(int8_t line); -}; - -class MenuItemPtrClass: public MenuItemClass { -public: - void *value = nullptr; - using MenuItemClass::MenuItemClass; - MenuItemPtrClass(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val); - MenuItemPtrClass(uint8_t cicon, FSTR_P text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val) : MenuItemPtrClass(cicon, FTOP(text), ondraw, onclick, val){} -}; - -class MenuClass { -public: - int8_t topline = 0; - int8_t selected = 0; - TitleClass MenuTitle; - MenuClass(); - virtual ~MenuClass(){}; - inline int8_t line() { return selected - topline; }; - inline int8_t line(uint8_t pos) {return pos - topline; }; - void draw(); - void onScroll(bool dir); - void onClick(); - MenuItemClass* SelectedItem(); -}; -extern MenuClass *CurrentMenu; - namespace DWINUI { extern xy_int_t cursor; extern uint16_t pencolor; @@ -225,10 +199,7 @@ namespace DWINUI { extern uint8_t font; extern FSTR_P const Author; - extern void (*onCursorErase)(const int8_t line); - extern void (*onCursorDraw)(const int8_t line); extern void (*onTitleDraw)(TitleClass* title); - extern void (*onMenuDraw)(MenuClass* menu); // DWIN LCD Initialization void init(); @@ -304,129 +275,121 @@ namespace DWINUI { DWIN_ICON_Show(true, false, false, ICON, icon, x, y); } - // Draw a positive integer + // Draw a numeric integer value // 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 + // signedMode: 1=signed; 0=unsigned // size: Font size // color: Character color // bColor: Background color // iNum: Number of digits // 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_Value(bShow, 0, zeroFill, zeroMode, size, color, bColor, iNum, 0, x, y, value); + void Draw_Int(uint8_t bShow, bool signedMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, int32_t value); + + // Draw a positive integer + inline void Draw_Int(uint8_t bShow, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) { + Draw_Int(bShow, 0, size, color, bColor, iNum, x, y, value); } inline void Draw_Int(uint8_t iNum, long value) { - DWIN_Draw_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, 0, cursor.x, cursor.y, value); + Draw_Int(false, 0, font, textcolor, backcolor, iNum, 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_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, 0, x, y, value); + Draw_Int(false, 0, font, textcolor, backcolor, iNum, x, y, value); } inline void Draw_Int(uint16_t color, uint8_t iNum, uint16_t x, uint16_t y, long value) { - DWIN_Draw_Value(false, 0, true, 0, font, color, backcolor, iNum, 0, x, y, value); + Draw_Int(false, 0, font, color, backcolor, iNum, 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_Value(true, 0, true, 0, font, color, bColor, iNum, 0, x, y, value); + Draw_Int(true, 0, font, color, bColor, iNum, 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_Value(true, 0, true, 0, size, color, bColor, iNum, 0, x, y, value); + Draw_Int(true, 0, size, color, bColor, iNum, x, y, value); } // Draw a signed integer + inline void Draw_Signed_Int(uint8_t bShow, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, long value) { + Draw_Int(bShow, 1, size, color, bColor, iNum, x, y, value); + } + inline void Draw_Signed_Int(uint8_t iNum, long value) { + Draw_Int(false, 1, font, textcolor, backcolor, iNum, 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) { + Draw_Int(false, 1, font, textcolor, backcolor, iNum, x, y, value); + } + inline void Draw_Signed_Int(uint16_t color, uint8_t iNum, uint16_t x, uint16_t y, long value) { + Draw_Int(false, 1, font, color, backcolor, iNum, 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) { + Draw_Int(true, 1, font, color, bColor, iNum, 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) { + Draw_Int(true, 1, size, color, bColor, iNum, x, y, value); + } + + // Draw a numeric float value // 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 + // signedMode: 1=signed; 0=unsigned // 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 - 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); - } + // value: float value + void Draw_Float(uint8_t bShow, bool signedMode, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float 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 - // 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 - 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_Value(bShow, 0, zeroFill, zeroMode, size, color, bColor, iNum, fNum, x, y, value); + inline void Draw_Float(uint8_t bShow, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) { + Draw_Float(bShow, 0, size, color, bColor, iNum, fNum, x, y, value); } inline void Draw_Float(uint8_t iNum, uint8_t fNum, float value) { - DWIN_Draw_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, fNum, cursor.x, cursor.y, value); + Draw_Float(false, 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_Value(false, 0, true, 0, font, textcolor, backcolor, iNum, fNum, x, y, value); + Draw_Float(false, 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_Value(false, 0, true, 0, font, color, backcolor, iNum, fNum, x, y, value); + inline void Draw_Float(uint8_t size, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) { + Draw_Float(false, 0, size, textcolor, 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_Value(true, 0, true, 0, font, color, bColor, iNum, fNum, x, y, value); + Draw_Float(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_Value(true, 0, true, 0, size, color, bColor, iNum, fNum, x, y, value); + Draw_Float(true, 0, size, color, bColor, iNum, fNum, x, y, value); } // 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 - // color: Character color - // bColor: Background color - // iNum: Number of whole digits - // fNum: Number of decimal digits - // x/y: Upper-left point - // value: 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 bShow, uint8_t size, uint16_t color, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, float value) { + Draw_Float(bShow, 1, size, color, bColor, iNum, fNum, x, y, value); } inline void Draw_Signed_Float(uint8_t iNum, uint8_t fNum, float value) { - DWIN_Draw_Value(false, 1, true, 0, font, textcolor, backcolor, iNum, fNum, cursor.x, cursor.y, value); + Draw_Float(false, 1, 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) { - DWIN_Draw_Value(false, 1, true, 0, font, textcolor, backcolor, iNum, fNum, x, y, value); + Draw_Float(false, 1, 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) { - DWIN_Draw_Value(false, 1, true, 0, size, textcolor, backcolor, iNum, fNum, x, y, value); + Draw_Float(false, 1, 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) { - DWIN_Draw_Value(true, 1, true, 0, font, color, bColor, iNum, fNum, x, y, value); + Draw_Float(true, 1, 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) { - DWIN_Draw_Value(true, 1, true, 0, size, color, bColor, iNum, fNum, x, y, value); + Draw_Float(true, 1, size, color, bColor, iNum, fNum, x, y, value); } - // Draw a char at cursor position + // Draw a char + // color: Character color + // x: abscissa of the display + // y: ordinate of the display + // c: ASCII code of char + void Draw_Char(uint16_t color, uint16_t x, uint16_t y, const char c); + inline void Draw_Char(uint16_t x, uint16_t y, const char c) { Draw_Char(textcolor, x, y, c); }; + // Draw a char at cursor position and increment cursor void Draw_Char(uint16_t color, const char c); inline void Draw_Char(const char c) { Draw_Char(textcolor, c); } @@ -591,17 +554,8 @@ namespace DWINUI { DWIN_WriteToMem(0xA5, addr, length, data); } - // Clear Menu by filling the area with background color + // Clear by filling the area with background color // Area (0, TITLE_HEIGHT, DWIN_WIDTH, STATUS_Y - 1) void ClearMainArea(); - // Clear MenuItems array and free MenuItems elements - void MenuItemsClear(); - - // Prepare MenuItems array - void MenuItemsPrepare(int8_t totalitems); - - // Add elements to the MenuItems array - MenuItemClass* MenuItemsAdd(MenuItemClass* menuitem); - }; diff --git a/Marlin/src/lcd/e3v2/proui/lockscreen.cpp b/Marlin/src/lcd/e3v2/proui/lockscreen.cpp index c179856c6a..44b595096a 100644 --- a/Marlin/src/lcd/e3v2/proui/lockscreen.cpp +++ b/Marlin/src/lcd/e3v2/proui/lockscreen.cpp @@ -23,8 +23,8 @@ /** * Lock screen implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 2.1 - * Date: 2021/11/09 + * Version: 2.2.0 + * Date: 2022/04/11 */ #include "../../../inc/MarlinConfigPre.h" @@ -50,6 +50,7 @@ void LockScreenClass::init() { } void LockScreenClass::draw() { + Title.SetCaption(GET_TEXT_F(MSG_LOCKSCREEN)); DWINUI::ClearMainArea(); DWINUI::Draw_Icon(ICON_LOGO, 71, 120); // CREALITY logo DWINUI::Draw_CenteredString(Color_White, 180, GET_TEXT_F(MSG_LOCKSCREEN_LOCKED)); diff --git a/Marlin/src/lcd/e3v2/proui/lockscreen.h b/Marlin/src/lcd/e3v2/proui/lockscreen.h index ec967fe2db..83d5530be3 100644 --- a/Marlin/src/lcd/e3v2/proui/lockscreen.h +++ b/Marlin/src/lcd/e3v2/proui/lockscreen.h @@ -24,8 +24,8 @@ /** * Lock screen implementation for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * Version: 2.1 - * Date: 2021/11/09 + * Version: 2.2.0 + * Date: 2022/04/11 */ #include "../common/encoder.h" diff --git a/Marlin/src/lcd/e3v2/proui/menus.cpp b/Marlin/src/lcd/e3v2/proui/menus.cpp index 6dfcb8595c..6438545cb2 100644 --- a/Marlin/src/lcd/e3v2/proui/menus.cpp +++ b/Marlin/src/lcd/e3v2/proui/menus.cpp @@ -23,8 +23,8 @@ /** * Menu functions for ProUI * Author: Miguel A. Risco-Castillo - * Version: 1.2.1 - * Date: 2022/02/25 + * Version: 1.4.1 + * Date: 2022/04/14 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -51,6 +51,14 @@ #include "dwin.h" #include "menus.h" +int8_t MenuItemTotal = 0; +int8_t MenuItemCount = 0; +MenuItemClass** MenuItems = nullptr; +MenuClass *CurrentMenu = nullptr; +MenuClass *PreviousMenu = nullptr; +void (*onMenuDraw)(MenuClass* menu) = nullptr; +void (*onCursorErase)(const int8_t line) = nullptr; +void (*onCursorDraw)(const int8_t line) = nullptr; MenuData_t MenuData; // Menuitem Drawing functions ================================================= @@ -69,11 +77,13 @@ void Draw_Menu(MenuClass* menu) { } 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); + const uint16_t ypos = MYPOS(line); + DWINUI::Draw_Box(1, HMI_data.Cursor_color, {0, ypos, 15, MLINE - 1}); } 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); + const uint16_t ypos = MYPOS(line); + DWINUI::Draw_Box(1, HMI_data.Background_Color, {0, ypos, 15, MLINE - 1}); } void Draw_Menu_Line(const uint8_t line, const uint8_t icon /*=0*/, const char * const label /*=nullptr*/, bool more /*=false*/) { @@ -84,7 +94,7 @@ void Draw_Menu_Line(const uint8_t line, const uint8_t icon /*=0*/, const char * } 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); + DWINUI::Draw_Checkbox(HMI_data.Text_Color, HMI_data.Background_Color, VALX + 3 * DWINUI::fontWidth(), MBASE(line) - 1, checked); } void Draw_Menu_IntValue(uint16_t bcolor, const uint8_t line, uint8_t iNum, const int32_t value /*=0*/) { @@ -141,11 +151,21 @@ void onDrawPFloat2Menu(MenuItemClass* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 2, value); } +void onDrawPFloat3Menu(MenuItemClass* menuitem, int8_t line) { + const float value = *(float*)static_cast(menuitem)->value; + onDrawFloatMenu(menuitem, line, 3, value); +} + void onDrawChkbMenu(MenuItemClass* menuitem, int8_t line, bool checked) { onDrawMenuItem(menuitem, line); Draw_Chkb_Line(line, checked); } +void onDrawChkbMenu(MenuItemClass* menuitem, int8_t line) { + const bool val = *(bool*)static_cast(menuitem)->value; + onDrawChkbMenu(menuitem, line, val); +} + //----------------------------------------------------------------------------- // On click functions //----------------------------------------------------------------------------- @@ -165,7 +185,7 @@ void SetOnClick(uint8_t process, const int32_t lo, const int32_t hi, uint8_t dp, MenuData.dp = dp; MenuData.Apply = Apply; MenuData.LiveUpdate = LiveUpdate; - MenuData.Value = val; + MenuData.Value = constrain(val, lo, hi); EncoderRate.enabled = true; } @@ -257,6 +277,7 @@ void HMI_Menu() { // 1 : live change // 2 : apply change int8_t HMI_GetIntNoDraw(const int32_t lo, const int32_t hi) { + const int32_t cval = MenuData.Value; EncoderState encoder_diffState = Encoder_ReceiveAnalyze(); if (encoder_diffState != ENCODER_DIFF_NO) { if (Apply_Encoder(encoder_diffState, MenuData.Value)) { @@ -265,9 +286,8 @@ int8_t HMI_GetIntNoDraw(const int32_t lo, const int32_t hi) { return 2; } LIMIT(MenuData.Value, lo, hi); - return 1; } - return 0; + return int8_t(cval != MenuData.Value); } // Get an integer value using the encoder @@ -367,4 +387,166 @@ void HMI_SetPFloat() { } } +// Menu Classes =============================================================== + +MenuClass::MenuClass() { + selected = 0; + topline = 0; +} + +void MenuClass::draw() { + MenuTitle.draw(); + if (onMenuDraw != nullptr) onMenuDraw(this); + for (int8_t i = 0; i < MenuItemCount; i++) + MenuItems[i]->draw(i - topline); + if (onCursorDraw != nullptr) onCursorDraw(line()); + DWIN_UpdateLCD(); +} + +void MenuClass::onScroll(bool dir) { + int8_t sel = selected; + if (dir) sel++; else sel--; + LIMIT(sel, 0, MenuItemCount - 1); + if (sel != selected) { + if (onCursorErase != nullptr) onCursorErase(line()); + DWIN_UpdateLCD(); + if ((sel - topline) == TROWS) { + DWIN_Frame_AreaMove(1, DWIN_SCROLL_UP, MLINE, DWINUI::backcolor, 0, TITLE_HEIGHT + 1, DWIN_WIDTH, STATUS_Y - 1); + topline++; + MenuItems[sel]->draw(TROWS - 1); + } + if ((sel < topline)) { + DWIN_Frame_AreaMove(1, DWIN_SCROLL_DOWN, MLINE, DWINUI::backcolor, 0, TITLE_HEIGHT + 1, DWIN_WIDTH, STATUS_Y - 1); + topline--; + MenuItems[sel]->draw(0); + } + selected = sel; + if (onCursorDraw != nullptr) onCursorDraw(line()); + DWIN_UpdateLCD(); + } +} + +void MenuClass::onClick() { + if (MenuItems[selected]->onClick != nullptr) (*MenuItems[selected]->onClick)(); +} + +MenuItemClass *MenuClass::SelectedItem() { + return MenuItems[selected]; +} + +MenuItemClass** MenuClass::Items() { + return MenuItems; +} + +int8_t MenuClass::count() { + return MenuItemCount; +}; + +/* MenuItem Class ===========================================================*/ + +MenuItemClass::MenuItemClass(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)()) { + icon = cicon; + onClick = onclick; + onDraw = ondraw; + const uint8_t len = _MIN(sizeof(caption) - 1, strlen(text)); + memcpy(&caption[0], text, len); + caption[len] = '\0'; +} + +MenuItemClass::MenuItemClass(uint8_t cicon, uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)()) { + icon = cicon; + onClick = onclick; + onDraw = ondraw; + caption[0] = '\0'; + frameid = id; + frame = { x1, y1, x2, y2 }; +} + +void MenuItemClass::SetFrame(uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { + caption[0] = '\0'; + frameid = id; + frame = { x1, y1, x2, y2 }; +} + +void MenuItemClass::draw(int8_t line) { + if (line < 0 || line >= TROWS) return; + if (onDraw != nullptr) (*onDraw)(this, line); +}; + +void MenuItemClass::redraw() { + draw(CurrentMenu->line(this->pos)); +} + +MenuItemPtrClass::MenuItemPtrClass(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val) : MenuItemClass(cicon, text, ondraw, onclick) { + value = val; +}; + +// Menu auxiliary functions =================================================== + +void MenuItemsClear() { + if (MenuItems == nullptr) return; + for (int8_t i = 0; i < MenuItemCount; i++) delete MenuItems[i]; + delete[] MenuItems; + MenuItems = nullptr; + MenuItemCount = 0; + MenuItemTotal = 0; +} + +void MenuItemsPrepare(int8_t totalitems) { + MenuItemsClear(); + MenuItemTotal = totalitems; + MenuItems = new MenuItemClass*[totalitems]; +} + +MenuItemClass* MenuItemsAdd(MenuItemClass* menuitem) { + MenuItems[MenuItemCount] = menuitem; + menuitem->pos = MenuItemCount++; + return menuitem; +} + +MenuItemClass* MenuItemsAdd(uint8_t cicon, const char * const text/*=nullptr*/, void (*ondraw)(MenuItemClass* menuitem, int8_t line)/*=nullptr*/, void (*onclick)()/*=nullptr*/) { + if (MenuItemCount < MenuItemTotal) { + MenuItemClass* menuitem = new MenuItemClass(cicon, text, ondraw, onclick); + return MenuItemsAdd(menuitem); + } + else return nullptr; +} + +MenuItemClass* MenuItemsAdd(uint8_t cicon, uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, void (*ondraw)(MenuItemClass* menuitem, int8_t line)/*=nullptr*/, void (*onclick)()/*=nullptr*/) { + if (MenuItemCount < MenuItemTotal) { + MenuItemClass* menuitem = new MenuItemClass(cicon, id, x1, y1, x2, y2, ondraw, onclick); + return MenuItemsAdd(menuitem); + } + else return nullptr; +} + +MenuItemClass* MenuItemsAdd(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val) { + if (MenuItemCount < MenuItemTotal) { + MenuItemClass* menuitem = new MenuItemPtrClass(cicon, text, ondraw, onclick, val); + return MenuItemsAdd(menuitem); + } + else return nullptr; +} + +bool SetMenu(MenuClass* &menu, FSTR_P title, int8_t totalitems) { + if (!menu) menu = new MenuClass(); + const bool NotCurrent = (CurrentMenu != menu); + if (NotCurrent) { + menu->MenuTitle.SetCaption(title); + MenuItemsPrepare(totalitems); + } + return NotCurrent; +} + +void UpdateMenu(MenuClass* &menu) { + if (!menu) return; + if (CurrentMenu != menu) { + PreviousMenu = CurrentMenu; + CurrentMenu = menu; + } + menu->draw(); +} + +void ReDrawMenu() { if (CurrentMenu && checkkey==Menu) CurrentMenu->draw(); } + #endif // DWIN_LCD_PROUI diff --git a/Marlin/src/lcd/e3v2/proui/menus.h b/Marlin/src/lcd/e3v2/proui/menus.h index 0147c1616b..d4514d1732 100644 --- a/Marlin/src/lcd/e3v2/proui/menus.h +++ b/Marlin/src/lcd/e3v2/proui/menus.h @@ -23,8 +23,8 @@ /** * Menu functions for ProUI * Author: Miguel A. Risco-Castillo - * Version: 1.2.1 - * Date: 2022/02/25 + * Version: 1.4.1 + * Date: 2022/04/14 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -56,8 +56,70 @@ typedef struct { } MenuData_t; extern MenuData_t MenuData; +extern void (*onCursorErase)(const int8_t line); +extern void (*onCursorDraw)(const int8_t line); + +// Auxiliary Macros =========================================================== + +// Create and add a MenuItem object to the menu array +#define BACK_ITEM(H) MenuItemsAdd(ICON_Back, GET_TEXT_F(MSG_BUTTON_BACK), onDrawMenuItem, H) +#define MENU_ITEM(V...) MenuItemsAdd(V) +#define EDIT_ITEM(V...) MenuItemsAdd(V) +#define MENU_ITEM_F(I,L,V...) MenuItemsAdd(I, GET_TEXT_F(L), V) +#define EDIT_ITEM_F(I,L,V...) MenuItemsAdd(I, GET_TEXT_F(L), V) + +// Menu Classes =============================================================== + +class MenuItemClass { +protected: +public: + int8_t pos = 0; + uint8_t icon = 0; + char caption[32] = ""; + uint8_t frameid = 0; + rect_t frame = {0}; + void (*onDraw)(MenuItemClass* menuitem, int8_t line) = nullptr; + void (*onClick)() = nullptr; + MenuItemClass() {}; + MenuItemClass(uint8_t cicon, const char * const text=nullptr, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr); + // MenuItemClass(uint8_t cicon, FSTR_P text = nullptr, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr) : MenuItemClass(cicon, FTOP(text), ondraw, onclick){} + MenuItemClass(uint8_t cicon, uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr); + void SetFrame(uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); + virtual ~MenuItemClass(){}; + virtual void draw(int8_t line); + void redraw(); +}; + +class MenuItemPtrClass: public MenuItemClass { +public: + void *value = nullptr; + using MenuItemClass::MenuItemClass; + MenuItemPtrClass(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val); + MenuItemPtrClass(uint8_t cicon, FSTR_P text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val) : MenuItemPtrClass(cicon, FTOP(text), ondraw, onclick, val){} +}; + +class MenuClass { +public: + int8_t topline = 0; + int8_t selected = 0; + TitleClass MenuTitle; + MenuClass(); + virtual ~MenuClass(){}; + inline int8_t line() { return selected - topline; }; + inline int8_t line(uint8_t pos) {return pos - topline; }; + int8_t count(); + virtual void draw(); + virtual void onScroll(bool dir); + void onClick(); + MenuItemClass* SelectedItem(); + static MenuItemClass** Items(); +}; +extern MenuClass *CurrentMenu; +extern MenuClass *PreviousMenu; +extern void (*onMenuDraw)(MenuClass* menu); // Menuitem Drawing functions ================================================= + void Draw_Title(TitleClass* title); void Draw_Menu(MenuClass* menu); void Draw_Menu_Cursor(const int8_t line); @@ -74,9 +136,12 @@ 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 onDrawPFloat3Menu(MenuItemClass* menuitem, int8_t line); void onDrawChkbMenu(MenuItemClass* menuitem, int8_t line, bool checked); +void onDrawChkbMenu(MenuItemClass* menuitem, int8_t line); // 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); @@ -86,9 +151,38 @@ void SetFloatOnClick(const float lo, const float hi, uint8_t dp, const float val 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(); + +// Menu auxiliary functions =================================================== + +// Create a new menu +bool SetMenu(MenuClass* &menu, FSTR_P title, int8_t totalitems); + +//Update the Menu and Draw if it is valid +void UpdateMenu(MenuClass* &menu); + +//Redraw the current Menu if it is valid +void ReDrawMenu(); + +// Clear MenuItems array and free MenuItems elements +void MenuItemsClear(); + +// Prepare MenuItems array +void MenuItemsPrepare(int8_t totalitems); + +// Add elements to the MenuItems array +MenuItemClass* MenuItemsAdd(uint8_t cicon, const char * const text=nullptr, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr); +inline MenuItemClass* MenuItemsAdd(uint8_t cicon, FSTR_P text = nullptr, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr) { + return MenuItemsAdd(cicon, FTOP(text), ondraw, onclick); +} +MenuItemClass* MenuItemsAdd(uint8_t cicon, uint8_t id, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, void (*ondraw)(MenuItemClass* menuitem, int8_t line)=nullptr, void (*onclick)()=nullptr); +MenuItemClass* MenuItemsAdd(uint8_t cicon, const char * const text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val); +inline MenuItemClass* MenuItemsAdd(uint8_t cicon, FSTR_P text, void (*ondraw)(MenuItemClass* menuitem, int8_t line), void (*onclick)(), void* val) { + return MenuItemsAdd(cicon, FTOP(text), ondraw, onclick, val); +} diff --git a/Marlin/src/lcd/e3v2/proui/meshviewer.cpp b/Marlin/src/lcd/e3v2/proui/meshviewer.cpp index 6121ab35d4..5fe8b1bb10 100644 --- a/Marlin/src/lcd/e3v2/proui/meshviewer.cpp +++ b/Marlin/src/lcd/e3v2/proui/meshviewer.cpp @@ -23,8 +23,8 @@ /** * Mesh Viewer for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * version: 3.12.1 - * Date: 2022/02/24 + * version: 3.14.1 + * Date: 2022/04/11 */ #include "../../../inc/MarlinConfigPre.h" @@ -41,6 +41,10 @@ #include "dwin_popup.h" #include "../../../feature/bedlevel/bedlevel.h" +#if ENABLED(AUTO_BED_LEVELING_UBL) + #include "ubl_tools.h" +#endif + MeshViewerClass MeshViewer; void MeshViewerClass::DrawMesh(bed_mesh_t zval, const uint8_t sizex, const uint8_t sizey) { @@ -56,17 +60,15 @@ void MeshViewerClass::DrawMesh(bed_mesh_t zval, const uint8_t sizex, const uint8 #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(sizey - 1), DWIN_WIDTH - 2 * my) - int16_t maxz =-32000; int16_t minz = 32000; avg = 0; + int16_t maxz =-32000; int16_t minz = 32000; 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); } max = (float)maxz / 100; min = (float)minz / 100; - avg = avg / (100 * sizex * sizey); DWINUI::ClearMainArea(); 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); @@ -77,8 +79,10 @@ void MeshViewerClass::DrawMesh(bed_mesh_t zval, const uint8_t sizex, const uint8 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 (sizex < 9) - DWINUI::Draw_Signed_Float(font6x12, 1, 2, px(x) - 18, py(y) - 6, zval[x][y]); + if (sizex < 9) { + if (zmesh[x][y] == 0) DWINUI::Draw_Float(font6x12, 1, 2, px(x) - 12, py(y) - 6, 0); + else 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; @@ -108,7 +112,13 @@ void MeshViewerClass::DrawMesh(bed_mesh_t zval, const uint8_t sizex, const uint8 void MeshViewerClass::Draw(bool withsave /*= false*/) { Title.ShowCaption(GET_TEXT_F(MSG_MESH_VIEWER)); - DrawMesh(Z_VALUES_ARR, GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y); + #if ENABLED(USE_UBL_VIEWER) + DWINUI::ClearMainArea(); + ubl_tools.viewer_print_value = true; + ubl_tools.Draw_Bed_Mesh(-1, 1, 8, 10 + TITLE_HEIGHT); + #else + DrawMesh(Z_VALUES_ARR, GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y); + #endif if (withsave) { DWINUI::Draw_Button(BTN_Save, 26, 305); DWINUI::Draw_Button(BTN_Continue, 146, 305); @@ -117,15 +127,19 @@ void MeshViewerClass::Draw(bool withsave /*= false*/) { 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(min, 1, 2, str_1), - dtostrf(max, 1, 2, str_2) - ); + #if ENABLED(USE_UBL_VIEWER) + ubl_tools.Set_Mesh_Viewer_Status(); + #else + char str_1[6], str_2[6] = ""; + ui.status_printf(0, F("Mesh minZ: %s, maxZ: %s"), + dtostrf(min, 1, 2, str_1), + dtostrf(max, 1, 2, str_2) + ); + #endif } 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(); } +void onClick_MeshViewer() { if (HMI_flag.select_flag) SaveMesh(); 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 f914bab4ae..1e78ff2657 100644 --- a/Marlin/src/lcd/e3v2/proui/meshviewer.h +++ b/Marlin/src/lcd/e3v2/proui/meshviewer.h @@ -27,13 +27,13 @@ /** * Mesh Viewer for PRO UI * Author: Miguel A. Risco-Castillo (MRISCOC) - * version: 3.12.1 - * Date: 2022/02/24 + * version: 3.14.1 + * Date: 2022/04/11 */ class MeshViewerClass { public: - float avg, max, min; + float max, min; void Draw(bool withsave = false); void DrawMesh(bed_mesh_t zval, const uint8_t sizex, const uint8_t sizey); }; diff --git a/Marlin/src/lcd/e3v2/proui/printstats.cpp b/Marlin/src/lcd/e3v2/proui/printstats.cpp index f33d0d15fa..5a7b6c9c41 100644 --- a/Marlin/src/lcd/e3v2/proui/printstats.cpp +++ b/Marlin/src/lcd/e3v2/proui/printstats.cpp @@ -71,7 +71,7 @@ void PrintStatsClass::Draw() { void PrintStatsClass::Reset() { print_job_timer.initStats(); - HMI_AudioFeedback(); + DONE_BUZZ(true); } void Goto_PrintStats() { diff --git a/Marlin/src/lcd/e3v2/proui/ubl_tools.cpp b/Marlin/src/lcd/e3v2/proui/ubl_tools.cpp new file mode 100644 index 0000000000..1783ee18c5 --- /dev/null +++ b/Marlin/src/lcd/e3v2/proui/ubl_tools.cpp @@ -0,0 +1,255 @@ +/** + * UBL Tools and Mesh Viewer for Pro UI + * Version: 1.0.0 + * Date: 2022/04/13 + * + * Original Author: Henri-J-Norden + * Original Source: https://github.com/Jyers/Marlin/pull/126 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../../inc/MarlinConfigPre.h" +#include "ubl_tools.h" + +#if ENABLED(DWIN_LCD_PROUI) + +#include "../../marlinui.h" +#include "../../../core/types.h" +#include "dwin.h" +#include "dwinui.h" +#include "dwin_popup.h" +#include "../../../feature/bedlevel/bedlevel.h" +#include "../../../module/probe.h" +#include "../../../gcode/gcode.h" +#include "../../../module/planner.h" +#include "../../../gcode/queue.h" +#include "../../../libs/least_squares_fit.h" +#include "../../../libs/vector_3.h" + +UBLMeshToolsClass ubl_tools; + +#if ENABLED(USE_UBL_VIEWER) + bool UBLMeshToolsClass::viewer_asymmetric_range = false; + bool UBLMeshToolsClass::viewer_print_value = false; +#endif +bool UBLMeshToolsClass::goto_mesh_value = false; +uint8_t UBLMeshToolsClass::tilt_grid = 1; + +bool drawing_mesh = false; +char cmd[MAX_CMD_SIZE+16], str_1[16], str_2[16], str_3[16]; + +#if ENABLED(AUTO_BED_LEVELING_UBL) + + void UBLMeshToolsClass::manual_value_update(const uint8_t mesh_x, const uint8_t mesh_y, bool undefined/*=false*/) { + sprintf_P(cmd, PSTR("M421 I%i J%i Z%s %s"), mesh_x, mesh_y, dtostrf(current_position.z, 1, 3, str_1), undefined ? "N" : ""); + gcode.process_subcommands_now(cmd); + planner.synchronize(); + } + + bool UBLMeshToolsClass::create_plane_from_mesh() { + struct linear_fit_data lsf_results; + incremental_LSF_reset(&lsf_results); + GRID_LOOP(x, y) { + if (!isnan(Z_VALUES_ARR[x][y])) { + xy_pos_t rpos; + rpos.x = ubl.mesh_index_to_xpos(x); + rpos.y = ubl.mesh_index_to_ypos(y); + incremental_LSF(&lsf_results, rpos, Z_VALUES_ARR[x][y]); + } + } + + if (finish_incremental_LSF(&lsf_results)) { + SERIAL_ECHOPGM("Could not complete LSF!"); + return true; + } + + ubl.set_all_mesh_points_to_value(0); + + matrix_3x3 rotation = matrix_3x3::create_look_at(vector_3(lsf_results.A, lsf_results.B, 1)); + GRID_LOOP(i, j) { + float mx = ubl.mesh_index_to_xpos(i), + my = ubl.mesh_index_to_ypos(j), + mz = Z_VALUES_ARR[i][j]; + + if (DEBUGGING(LEVELING)) { + DEBUG_ECHOPAIR_F("before rotation = [", mx, 7); + DEBUG_CHAR(','); + DEBUG_ECHO_F(my, 7); + DEBUG_CHAR(','); + DEBUG_ECHO_F(mz, 7); + DEBUG_ECHOPGM("] ---> "); + DEBUG_DELAY(20); + } + + rotation.apply_rotation_xyz(mx, my, mz); + + if (DEBUGGING(LEVELING)) { + DEBUG_ECHOPAIR_F("after rotation = [", mx, 7); + DEBUG_CHAR(','); + DEBUG_ECHO_F(my, 7); + DEBUG_CHAR(','); + DEBUG_ECHO_F(mz, 7); + DEBUG_ECHOLNPGM("]"); + DEBUG_DELAY(20); + } + + Z_VALUES_ARR[i][j] = mz - lsf_results.D; + } + return false; + } + +#else + + void UBLMeshToolsClass::manual_value_update(const uint8_t mesh_x, const uint8_t mesh_y) { + sprintf_P(cmd, PSTR("G29 I%i J%i Z%s"), mesh_x, mesh_y, dtostrf(current_position.z, 1, 3, str_1)); + gcode.process_subcommands_now(cmd); + planner.synchronize(); + } + +#endif + +void UBLMeshToolsClass::manual_move(const uint8_t mesh_x, const uint8_t mesh_y, bool zmove/*=false*/) { + if (zmove) { + planner.synchronize(); + current_position.z = goto_mesh_value ? Z_VALUES_ARR[mesh_x][mesh_y] : Z_CLEARANCE_BETWEEN_PROBES; + planner.buffer_line(current_position, homing_feedrate(Z_AXIS), active_extruder); + planner.synchronize(); + } + else { + DWIN_Show_Popup(ICON_BLTouch, F("Moving to Point"), F("Please wait until done.")); + HMI_SaveProcessID(NothingToDo); + sprintf_P(cmd, PSTR("G0 F300 Z%s"), dtostrf(Z_CLEARANCE_BETWEEN_PROBES, 1, 3, str_1)); + gcode.process_subcommands_now(cmd); + sprintf_P(cmd, PSTR("G42 F4000 I%i J%i"), mesh_x, mesh_y); + gcode.process_subcommands_now(cmd); + planner.synchronize(); + current_position.z = goto_mesh_value ? Z_VALUES_ARR[mesh_x][mesh_y] : Z_CLEARANCE_BETWEEN_PROBES; + planner.buffer_line(current_position, homing_feedrate(Z_AXIS), active_extruder); + planner.synchronize(); + HMI_ReturnScreen(); + } +} + +float UBLMeshToolsClass::get_max_value() { + float max = __FLT_MIN__; + GRID_LOOP(x, y) { + if (!isnan(Z_VALUES_ARR[x][y]) && Z_VALUES_ARR[x][y] > max) + max = Z_VALUES_ARR[x][y]; + } + return max; +} + +float UBLMeshToolsClass::get_min_value() { + float min = __FLT_MAX__; + GRID_LOOP(x, y) { + if (!isnan(Z_VALUES_ARR[x][y]) && Z_VALUES_ARR[x][y] < min) + min = Z_VALUES_ARR[x][y]; + } + return min; +} + +bool UBLMeshToolsClass::validate() { + float min = __FLT_MAX__; + float max = __FLT_MIN__; + + GRID_LOOP(x, y) { + if (isnan(Z_VALUES_ARR[x][y])) return false; + if (Z_VALUES_ARR[x][y] < min) min = Z_VALUES_ARR[x][y]; + if (Z_VALUES_ARR[x][y] > max) max = Z_VALUES_ARR[x][y]; + } + return max <= UBL_Z_OFFSET_MAX && min >= UBL_Z_OFFSET_MIN; +} + +#if ENABLED(USE_UBL_VIEWER) + void UBLMeshToolsClass::Draw_Bed_Mesh(int16_t selected /*= -1*/, uint8_t gridline_width /*= 1*/, uint16_t padding_x /*= 8*/, uint16_t padding_y_top /*= 40 + 53 - 7*/) { + drawing_mesh = true; + const uint16_t total_width_px = DWIN_WIDTH - padding_x - padding_x; + const uint16_t cell_width_px = total_width_px / GRID_MAX_POINTS_X; + const uint16_t cell_height_px = total_width_px / GRID_MAX_POINTS_Y; + const float v_max = abs(get_max_value()), v_min = abs(get_min_value()), range = _MAX(v_min, v_max); + + // Clear background from previous selection and select new square + DWIN_Draw_Rectangle(1, Color_Bg_Black, _MAX(0, padding_x - gridline_width), _MAX(0, padding_y_top - gridline_width), padding_x + total_width_px, padding_y_top + total_width_px); + if (selected >= 0) { + const auto selected_y = selected / GRID_MAX_POINTS_X; + const auto selected_x = selected - (GRID_MAX_POINTS_X * selected_y); + const auto start_y_px = padding_y_top + selected_y * cell_height_px; + const auto start_x_px = padding_x + selected_x * cell_width_px; + DWIN_Draw_Rectangle(1, Color_White, _MAX(0, start_x_px - gridline_width), _MAX(0, start_y_px - gridline_width), start_x_px + cell_width_px, start_y_px + cell_height_px); + } + + // Draw value square grid + char buf[8]; + GRID_LOOP(x, y) { + const auto start_x_px = padding_x + x * cell_width_px; + const auto end_x_px = start_x_px + cell_width_px - 1 - gridline_width; + const auto start_y_px = padding_y_top + (GRID_MAX_POINTS_Y - y - 1) * cell_height_px; + const auto end_y_px = start_y_px + cell_height_px - 1 - gridline_width; + DWIN_Draw_Rectangle(1, // RGB565 colors: http://www.barth-dev.de/online/rgb565-color-picker/ + isnan(Z_VALUES_ARR[x][y]) ? Color_Grey : ( // gray if undefined + (Z_VALUES_ARR[x][y] < 0 ? + (uint16_t)round(0x1F * -Z_VALUES_ARR[x][y] / (!viewer_asymmetric_range ? range : v_min)) << 11 : // red if mesh point value is negative + (uint16_t)round(0x3F * Z_VALUES_ARR[x][y] / (!viewer_asymmetric_range ? range : v_max)) << 5) | // green if mesh point value is positive + _MIN(0x1F, (((uint8_t)abs(Z_VALUES_ARR[x][y]) / 10) * 4))), // + blue stepping for every mm + start_x_px, start_y_px, end_x_px, end_y_px + ); + + safe_delay(10); + LCD_SERIAL.flushTX(); + + // Draw value text on + if (viewer_print_value) { + int8_t offset_x, offset_y = cell_height_px / 2 - 6; + if (isnan(Z_VALUES_ARR[x][y])) { // undefined + DWIN_Draw_String(false, font6x12, Color_White, Color_Bg_Blue, start_x_px + cell_width_px / 2 - 5, start_y_px + offset_y, F("X")); + } + else { // has value + if (GRID_MAX_POINTS_X < 10) + sprintf_P(buf, PSTR("%s"), dtostrf(abs(Z_VALUES_ARR[x][y]), 1, 2, str_1)); + else + sprintf_P(buf, PSTR("%02i"), (uint16_t)(abs(Z_VALUES_ARR[x][y] - (int16_t)Z_VALUES_ARR[x][y]) * 100)); + offset_x = cell_width_px / 2 - 3 * (strlen(buf)) - 2; + if (!(GRID_MAX_POINTS_X < 10)) + DWIN_Draw_String(false, font6x12, Color_White, Color_Bg_Blue, start_x_px - 2 + offset_x, start_y_px + offset_y /*+ square / 2 - 6*/, F(".")); + DWIN_Draw_String(false, font6x12, Color_White, Color_Bg_Blue, start_x_px + 1 + offset_x, start_y_px + offset_y /*+ square / 2 - 6*/, buf); + } + safe_delay(10); + LCD_SERIAL.flushTX(); + } + } + } + + void UBLMeshToolsClass::Set_Mesh_Viewer_Status() { // TODO: draw gradient with values as a legend instead + float v_max = abs(get_max_value()), v_min = abs(get_min_value()), range = _MAX(v_min, v_max); + if (v_min > 3e+10F) v_min = 0.0000001; + if (v_max > 3e+10F) v_max = 0.0000001; + if (range > 3e+10F) range = 0.0000001; + char msg[46]; + if (viewer_asymmetric_range) { + dtostrf(-v_min, 1, 3, str_1); + dtostrf( v_max, 1, 3, str_2); + } + else { + dtostrf(-range, 1, 3, str_1); + dtostrf( range, 1, 3, str_2); + } + sprintf_P(msg, PSTR("Red %s..0..%s Green"), str_1, str_2); + ui.set_status(msg); + drawing_mesh = false; + } +#endif + +#endif // DWIN_LCD_PROUI diff --git a/Marlin/src/lcd/e3v2/proui/ubl_tools.h b/Marlin/src/lcd/e3v2/proui/ubl_tools.h new file mode 100644 index 0000000000..563794a463 --- /dev/null +++ b/Marlin/src/lcd/e3v2/proui/ubl_tools.h @@ -0,0 +1,59 @@ +/** + * UBL Tools and Mesh Viewer for Pro UI + * Version: 1.0.0 + * Date: 2022/04/13 + * + * Original Author: Henri-J-Norden (https://github.com/Henri-J-Norden) + * Original Source: https://github.com/Jyers/Marlin/pull/135 + * + * 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 . + * + */ +#pragma once + +#include "../../../inc/MarlinConfigPre.h" + +//#define USE_UBL_VIEWER 1 + +#define UBL_Z_OFFSET_MIN -3.0 +#define UBL_Z_OFFSET_MAX 3.0 + +class UBLMeshToolsClass { +public: + #if ENABLED(USE_UBL_VIEWER) + static bool viewer_asymmetric_range; + static bool viewer_print_value; + #endif + static bool goto_mesh_value; + static uint8_t tilt_grid; + + #if ENABLED(AUTO_BED_LEVELING_UBL) + static void manual_value_update(const uint8_t mesh_x, const uint8_t mesh_y, bool undefined=false); + static bool create_plane_from_mesh(); + #else + static void manual_value_update(const uint8_t mesh_x, const uint8_t mesh_y); + #endif + static void manual_move(const uint8_t mesh_x, const uint8_t mesh_y, bool zmove=false); + static float get_max_value(); + static float get_min_value(); + static bool validate(); + #if ENABLED(USE_UBL_VIEWER) + static void Draw_Bed_Mesh(int16_t selected = -1, uint8_t gridline_width = 1, uint16_t padding_x = 8, uint16_t padding_y_top = 40 + 53 - 7); + static void Set_Mesh_Viewer_Status(); + #endif +}; + +extern UBLMeshToolsClass ubl_tools; + +void Goto_MeshViewer(); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 03f4f62b17..93ef1b5a71 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -53,6 +53,8 @@ namespace Language_en { LSTR WELCOME_MSG = MACHINE_NAME _UxGT(" Ready."); LSTR MSG_YES = _UxGT("YES"); LSTR MSG_NO = _UxGT("NO"); + LSTR MSG_HIGH = _UxGT("HIGH"); + LSTR MSG_LOW = _UxGT("LOW"); LSTR MSG_BACK = _UxGT("Back"); LSTR MSG_ERROR = _UxGT("Error"); LSTR MSG_MEDIA_ABORTING = _UxGT("Aborting..."); @@ -68,6 +70,8 @@ namespace Language_en { LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Soft Endstops"); LSTR MSG_MAIN = _UxGT("Main"); LSTR MSG_ADVANCED_SETTINGS = _UxGT("Advanced Settings"); + LSTR MSG_TOOLBAR_SETUP = _UxGT("Toolbar Setup"); + LSTR MSG_OPTION_DISABLED = _UxGT("Option Disabled"); LSTR MSG_CONFIGURATION = _UxGT("Configuration"); LSTR MSG_RUN_AUTO_FILES = _UxGT("Run Auto Files"); LSTR MSG_DISABLE_STEPPERS = _UxGT("Disable Steppers"); @@ -81,6 +85,7 @@ namespace Language_en { LSTR MSG_AUTO_HOME_Z = _UxGT("Home Z"); LSTR MSG_FILAMENT_SET = _UxGT("Filament Settings"); LSTR MSG_FILAMENT_MAN = _UxGT("Filament Management"); + LSTR MSG_MANUAL_LEVELING = _UxGT("Manual Leveling"); LSTR MSG_LEVBED_FL = _UxGT("Front Left"); LSTR MSG_LEVBED_FR = _UxGT("Front Right"); LSTR MSG_LEVBED_C = _UxGT("Center"); @@ -119,7 +124,14 @@ namespace Language_en { LSTR MSG_PREHEAT_1_ALL = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" All"); LSTR MSG_PREHEAT_1_BEDONLY = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Bed"); LSTR MSG_PREHEAT_1_SETTINGS = _UxGT("Preheat ") PREHEAT_1_LABEL _UxGT(" Conf"); - + #ifdef PREHEAT_2_LABEL + LSTR MSG_PREHEAT_2 = _UxGT("Preheat ") PREHEAT_2_LABEL; + LSTR MSG_PREHEAT_2_SETTINGS = _UxGT("Preheat ") PREHEAT_2_LABEL _UxGT(" Conf"); + #endif + #ifdef PREHEAT_3_LABEL + LSTR MSG_PREHEAT_3 = _UxGT("Preheat ") PREHEAT_3_LABEL; + LSTR MSG_PREHEAT_3_SETTINGS = _UxGT("Preheat ") PREHEAT_3_LABEL _UxGT(" Conf"); + #endif LSTR MSG_PREHEAT_M = _UxGT("Preheat $"); LSTR MSG_PREHEAT_M_H = _UxGT("Preheat $ ~"); LSTR MSG_PREHEAT_M_END = _UxGT("Preheat $ End"); @@ -166,10 +178,19 @@ namespace Language_en { LSTR MSG_MESH_VIEW = _UxGT("View Mesh"); LSTR MSG_EDITING_STOPPED = _UxGT("Mesh Editing Stopped"); LSTR MSG_NO_VALID_MESH = _UxGT("No valid mesh"); + LSTR MSG_ACTIVATE_MESH = _UxGT("Activate Leveling"); LSTR MSG_PROBING_POINT = _UxGT("Probing Point"); LSTR MSG_MESH_X = _UxGT("Index X"); LSTR MSG_MESH_Y = _UxGT("Index Y"); + LSTR MSG_MESH_INSET = _UxGT("Mesh Inset"); + LSTR MSG_MESH_MIN_X = _UxGT("Mesh X Minimum"); + LSTR MSG_MESH_MAX_X = _UxGT("Mesh X Maximum"); + LSTR MSG_MESH_MIN_Y = _UxGT("Mesh Y Minimum"); + LSTR MSG_MESH_MAX_Y = _UxGT("Mesh Y Maximum"); + LSTR MSG_MESH_AMAX = _UxGT("Maximize Area"); + LSTR MSG_MESH_CENTER = _UxGT("Center Area"); LSTR MSG_MESH_EDIT_Z = _UxGT("Z Value"); + LSTR MSG_MESH_CANCEL = _UxGT("Mesh cancelled"); LSTR MSG_CUSTOM_COMMANDS = _UxGT("Custom Commands"); LSTR MSG_M48_TEST = _UxGT("M48 Probe Test"); LSTR MSG_M48_POINT = _UxGT("M48 Point"); @@ -188,6 +209,9 @@ namespace Language_en { LSTR MSG_UBL_TOOLS = _UxGT("UBL Tools"); LSTR MSG_UBL_LEVEL_BED = _UxGT("Unified Bed Leveling"); LSTR MSG_LCD_TILTING_MESH = _UxGT("Tilting Point"); + LSTR MSG_UBL_TILT_MESH = _UxGT("Tilt Mesh"); + LSTR MSG_UBL_TILTING_GRID = _UxGT("Tilting Grid Size"); + LSTR MSG_UBL_MESH_TILTED = _UxGT("Mesh Tilted"); LSTR MSG_UBL_MANUAL_MESH = _UxGT("Manually Build Mesh"); LSTR MSG_UBL_MESH_WIZARD = _UxGT("UBL Mesh Wizard"); LSTR MSG_UBL_BC_INSERT = _UxGT("Place Shim & Measure"); @@ -236,6 +260,7 @@ namespace Language_en { LSTR MSG_UBL_MANUAL_FILLIN = _UxGT("Manual Fill-in"); LSTR MSG_UBL_SMART_FILLIN = _UxGT("Smart Fill-in"); LSTR MSG_UBL_FILLIN_MESH = _UxGT("Fill-in Mesh"); + LSTR MSG_UBL_MESH_FILLED = _UxGT("Missing Points Filled"); LSTR MSG_UBL_INVALIDATE_ALL = _UxGT("Invalidate All"); LSTR MSG_UBL_INVALIDATE_CLOSEST = _UxGT("Invalidate Closest"); LSTR MSG_UBL_FINE_TUNE_ALL = _UxGT("Fine Tune All"); @@ -244,6 +269,7 @@ namespace Language_en { LSTR MSG_UBL_STORAGE_SLOT = _UxGT("Memory Slot"); LSTR MSG_UBL_LOAD_MESH = _UxGT("Load Bed Mesh"); LSTR MSG_UBL_SAVE_MESH = _UxGT("Save Bed Mesh"); + LSTR MSG_UBL_INVALID_SLOT = _UxGT("First Select a Mesh Slot"); LSTR MSG_MESH_LOADED = _UxGT("Mesh %i Loaded"); LSTR MSG_MESH_SAVED = _UxGT("Mesh %i Saved"); LSTR MSG_UBL_NO_STORAGE = _UxGT("No Storage"); @@ -350,6 +376,7 @@ namespace Language_en { LSTR MSG_PID_AUTOTUNE_FAILED = _UxGT("PID Autotune failed!"); LSTR MSG_BAD_EXTRUDER_NUM = _UxGT("Bad extruder."); LSTR MSG_TEMP_TOO_HIGH = _UxGT("Temperature too high."); + LSTR MSG_TIMEOUT = _UxGT("Timeout."); LSTR MSG_PID_BAD_EXTRUDER_NUM = _UxGT("Autotune failed! Bad extruder."); LSTR MSG_PID_TEMP_TOO_HIGH = _UxGT("Autotune failed! Temperature too high."); LSTR MSG_PID_TIMEOUT = _UxGT("Autotune failed! Timeout."); @@ -447,6 +474,10 @@ namespace Language_en { LSTR MSG_RESET_PRINTER = _UxGT("Reset Printer"); LSTR MSG_REFRESH = LCD_STR_REFRESH _UxGT("Refresh"); LSTR MSG_INFO_SCREEN = _UxGT("Info Screen"); + LSTR MSG_INFO_MACHINENAME = _UxGT("Machine Name"); + LSTR MSG_INFO_SIZE = _UxGT("Size"); + LSTR MSG_INFO_FWVERSION = _UxGT("Firmware Version"); + LSTR MSG_INFO_BUILD = _UxGT("Build Datetime"); LSTR MSG_PREPARE = _UxGT("Prepare"); LSTR MSG_TUNE = _UxGT("Tune"); LSTR MSG_POWER_MONITOR = _UxGT("Power monitor"); @@ -473,6 +504,7 @@ namespace Language_en { LSTR MSG_BUTTON_RESUME = _UxGT("Resume"); LSTR MSG_BUTTON_ADVANCED = _UxGT("Advanced"); LSTR MSG_BUTTON_SAVE = _UxGT("Save"); + LSTR MSG_BUTTON_PURGE = _UxGT("Purge"); LSTR MSG_PAUSING = _UxGT("Pausing..."); LSTR MSG_PAUSE_PRINT = _UxGT("Pause Print"); LSTR MSG_ADVANCED_PAUSE = _UxGT("Advanced Pause"); @@ -495,9 +527,12 @@ namespace Language_en { LSTR MSG_REMAINING_TIME = _UxGT("Remaining"); LSTR MSG_PRINT_ABORTED = _UxGT("Print Aborted"); LSTR MSG_PRINT_DONE = _UxGT("Print Done"); + LSTR MSG_PRINTER_KILLED = _UxGT("Printer killed!"); + LSTR MSG_TURN_OFF = _UxGT("Turn off the printer"); LSTR MSG_NO_MOVE = _UxGT("No Move."); LSTR MSG_KILLED = _UxGT("KILLED. "); LSTR MSG_STOPPED = _UxGT("STOPPED. "); + LSTR MSG_FWRETRACT = _UxGT("Firmware Retract"); LSTR MSG_CONTROL_RETRACT = _UxGT("Retract mm"); LSTR MSG_CONTROL_RETRACT_SWAP = _UxGT("Swap Re.mm"); LSTR MSG_CONTROL_RETRACTF = _UxGT("Retract V"); @@ -563,6 +598,9 @@ namespace Language_en { LSTR MSG_ZPROBE_XOFFSET = _UxGT("Probe X Offset"); LSTR MSG_ZPROBE_YOFFSET = _UxGT("Probe Y Offset"); LSTR MSG_ZPROBE_ZOFFSET = _UxGT("Probe Z Offset"); + LSTR MSG_ZPROBE_MARGIN = _UxGT("Probe Margin"); + LSTR MSG_Z_FEED_RATE = _UxGT("Z Feed Rate"); + LSTR MSG_ENABLE_HS_MODE = _UxGT("Enable HS mode"); LSTR MSG_MOVE_NOZZLE_TO_BED = _UxGT("Move Nozzle to Bed"); LSTR MSG_BABYSTEP_X = _UxGT("Babystep X"); LSTR MSG_BABYSTEP_Y = _UxGT("Babystep Y"); @@ -633,27 +671,28 @@ namespace Language_en { LSTR MSG_CASE_LIGHT_BRIGHTNESS = _UxGT("Light Brightness"); LSTR MSG_KILL_EXPECTED_PRINTER = _UxGT("INCORRECT PRINTER"); + LSTR MSG_COLORS_GET = _UxGT("Get Color"); + LSTR MSG_COLORS_SELECT = _UxGT("Select Colors"); + LSTR MSG_COLORS_APPLIED = _UxGT("Colors applied"); + LSTR MSG_COLORS_RED = _UxGT("Red"); + LSTR MSG_COLORS_GREEN = _UxGT("Green"); + LSTR MSG_COLORS_BLUE = _UxGT("Blue"); + LSTR MSG_COLORS_WHITE = _UxGT("White"); + LSTR MSG_UI_LANGUAGE = _UxGT("UI Language"); + LSTR MSG_SOUND_ENABLE = _UxGT("Enable sound"); LSTR MSG_LOCKSCREEN = _UxGT("Lock Screen"); LSTR MSG_LOCKSCREEN_LOCKED = _UxGT("Printer is Locked,"); LSTR MSG_LOCKSCREEN_UNLOCK = _UxGT("Scroll to unlock."); + LSTR MSG_PLEASE_WAIT_REBOOT = _UxGT("Please wait until reboot."); + #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("No media inserted."); - LSTR MSG_PLEASE_WAIT_REBOOT = _UxGT("Please wait until reboot. "); LSTR MSG_PLEASE_PREHEAT = _UxGT("Please preheat the hot end."); LSTR MSG_INFO_PRINT_COUNT_RESET = _UxGT("Reset Print Count"); LSTR MSG_INFO_PRINT_COUNT = _UxGT("Print Count"); LSTR MSG_INFO_PRINT_TIME = _UxGT("Print Time"); LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Longest Job Time"); LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Extruded Total"); - LSTR MSG_COLORS_GET = _UxGT("Get Color"); - LSTR MSG_COLORS_SELECT = _UxGT("Select Colors"); - LSTR MSG_COLORS_APPLIED = _UxGT("Colors applied"); - LSTR MSG_COLORS_RED = _UxGT("Red"); - LSTR MSG_COLORS_GREEN = _UxGT("Green"); - LSTR MSG_COLORS_BLUE = _UxGT("Blue"); - LSTR MSG_COLORS_WHITE = _UxGT("White"); - LSTR MSG_UI_LANGUAGE = _UxGT("UI Language"); - LSTR MSG_SOUND_ENABLE = _UxGT("Enable sound"); #else LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("No Media"); LSTR MSG_PLEASE_PREHEAT = _UxGT("Please Preheat"); @@ -687,10 +726,14 @@ namespace Language_en { LSTR MSG_FILAMENT_CHANGE_OPTION_HEADER = _UxGT("RESUME OPTIONS:"); LSTR MSG_FILAMENT_CHANGE_OPTION_PURGE = _UxGT("Purge more"); LSTR MSG_FILAMENT_CHANGE_OPTION_RESUME = _UxGT("Continue"); + LSTR MSG_FILAMENT_CHANGE_PURGE_CONTINUE = _UxGT("Purge or Continue?"); LSTR MSG_FILAMENT_CHANGE_NOZZLE = _UxGT(" Nozzle: "); LSTR MSG_RUNOUT_SENSOR = _UxGT("Runout Sensor"); LSTR MSG_RUNOUT_DISTANCE_MM = _UxGT("Runout Dist mm"); LSTR MSG_RUNOUT_ENABLE = _UxGT("Enable Runout"); + LSTR MSG_RUNOUT_ACTIVE = _UxGT("Runout Active"); + LSTR MSG_INVERT_EXTRUDER = _UxGT("Invert Extruder"); + LSTR MSG_EXTRUDER_MIN_TEMP = _UxGT("Extruder Min Temp."); LSTR MSG_FANCHECK = _UxGT("Fan Tacho Check"); LSTR MSG_KILL_HOMING_FAILED = _UxGT("Homing Failed"); LSTR MSG_LCD_PROBING_FAILED = _UxGT("Probing Failed");