diff --git a/.editorconfig b/.editorconfig index 84f2d090b194..1037e74ef3ec 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,12 +1,14 @@ # editorconfig.org root = true +[*] +trim_trailing_whitespace = true +insert_final_newline = true + [{*.patch,syntax_test_*}] trim_trailing_whitespace = false [{*.c,*.cpp,*.h,*.ino,*.py,Makefile}] -trim_trailing_whitespace = true -insert_final_newline = true end_of_line = lf [{*.c,*.cpp,*.h,*.ino}] @@ -18,6 +20,10 @@ indent_size = 2 indent_style = tab indent_size = 2 +[*.md] +# Two spaces at the end of the line means newline in Markdown +trim_trailing_whitespace = false + [{*.py}] indent_style = space indent_size = 4 diff --git a/.github/code_of_conduct.md b/.github/code_of_conduct.md index 854fed4ec458..888c2ccf76fd 100644 --- a/.github/code_of_conduct.md +++ b/.github/code_of_conduct.md @@ -28,15 +28,9 @@ Project maintainers are responsible for clarifying the standards of acceptable b Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [marlinfirmware@github.com](mailto:marlinfirmware@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by messaging @MarlinFirmware/moderators on the relevant issue, [or privately](//github.com/orgs/MarlinFirmware/teams/moderators). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. ## Attribution diff --git a/.github/contributing.md b/.github/contributing.md index ef1726366a7d..f3825d208112 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -26,7 +26,7 @@ The following is a set of guidelines for contributing to Marlin, hosted by the [ ## Code of Conduct -This project and everyone participating in it is governed by the [Marlin Code of Conduct](code_of_conduct.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [marlinfirmware@github.com](mailto:marlinfirmware@github.com). +This project and everyone participating in it is governed by the [Marlin Code of Conduct](code_of_conduct.md). By participating, you are expected to uphold this code. Please report unacceptable behavior by messaging @MarlinFirmware/moderators on the relevant issue, [or privately](//github.com/orgs/MarlinFirmware/teams/moderators). ## I don't want to read this whole thing I just have a question!!! diff --git a/.vscode/extensions.json b/.vscode/extensions.json index f495d14f53e8..52fe2a0bdbff 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -6,6 +6,7 @@ "platformio.platformio-ide" ], "unwantedRecommendations": [ + "ms-vscode-remote.remote-containers", "ms-vscode.cpptools-extension-pack" ] } diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 12c741784b8e..5065ba5fc95e 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1257,11 +1257,6 @@ #define XY_FREQUENCY_MIN_PERCENT 5 // (percent) Minimum FR percentage to apply. Set with M201 G. #endif -// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end -// of the buffer and all stops. This should not be much greater than zero and should only be changed -// if unwanted behavior is observed on a user's machine when running at very slow speeds. -#define MINIMUM_PLANNER_SPEED 0.05 // (mm/s) - // // Backlash Compensation // Adds extra movement to axes on direction-changes to account for backlash. @@ -4247,6 +4242,7 @@ // row. By default idle() is profiled so this shows how "idle" the processor is. // See class CodeProfiler. //#define MAX7219_DEBUG_MULTISTEPPING 6 // Show multi-stepping 1 to 128 on this LED matrix row. + //#define MAX7219_DEBUG_SLOWDOWN 6 // Count (mod 16) how many times SLOWDOWN has reduced print speed. #endif /** diff --git a/Marlin/Version.h b/Marlin/Version.h index eb6dce0bfd8d..045d1ee1699e 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -41,7 +41,7 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2023-10-20" +//#define STRING_DISTRIBUTION_DATE "2023-10-28" /** * Defines a generic printer name to be output to the LCD after booting Marlin. diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index a41740f25ffd..d6c4b55459de 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -27,7 +27,8 @@ #include "../feature/ethernet.h" #endif -uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE; +// Echo commands to the terminal by default in dev mode +uint8_t marlin_debug_flags = TERN(MARLIN_DEV_MODE, MARLIN_DEBUG_ECHO, MARLIN_DEBUG_NONE); // Commonly-used strings in serial output PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C"); diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index e27f6eb974da..f37c78dde575 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -735,6 +735,15 @@ void Max7219::idle_tasks() { } #endif + #ifdef MAX7219_DEBUG_SLOWDOWN + static uint8_t last_slowdown_count = 0; + const uint8_t slowdown_count = Planner::slowdown_count; + if (slowdown_count != last_slowdown_count) { + mark16(MAX7219_DEBUG_SLOWDOWN, last_slowdown_count, slowdown_count, &row_change_mask); + last_slowdown_count = slowdown_count; + } + #endif + // batch line updates suspended--; if (!suspended) diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index 7fb60349c6e5..75ac03f00cad 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -219,15 +219,13 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW #endif #endif - #if HAS_EXTRUDERS + #if HAS_HOTEND HOTEND_LOOP() info.target_temperature[e] = thermalManager.degTargetHotend(e); #endif TERN_(HAS_HEATED_BED, info.target_temperature_bed = thermalManager.degTargetBed()); - #if HAS_FAN - COPY(info.fan_speed, thermalManager.fan_speed); - #endif + TERN_(HAS_FAN, COPY(info.fan_speed, thermalManager.fan_speed)); #if HAS_LEVELING info.flag.leveling = planner.leveling_active; @@ -672,7 +670,9 @@ void PrintJobRecovery::resume() { DEBUG_ECHOLNPGM("flag.dryrun: ", AS_DIGIT(info.flag.dryrun)); DEBUG_ECHOLNPGM("flag.allow_cold_extrusion: ", AS_DIGIT(info.flag.allow_cold_extrusion)); - DEBUG_ECHOLNPGM("flag.volumetric_enabled: ", AS_DIGIT(info.flag.volumetric_enabled)); + #if DISABLED(NO_VOLUMETRICS) + DEBUG_ECHOLNPGM("flag.volumetric_enabled: ", AS_DIGIT(info.flag.volumetric_enabled)); + #endif } else DEBUG_ECHOLNPGM("INVALID DATA"); diff --git a/Marlin/src/gcode/bedlevel/G35.cpp b/Marlin/src/gcode/bedlevel/G35.cpp index a37e5623e746..1b2f115cdfb7 100644 --- a/Marlin/src/gcode/bedlevel/G35.cpp +++ b/Marlin/src/gcode/bedlevel/G35.cpp @@ -57,7 +57,8 @@ * 41 - Counter-Clockwise M4 * 50 - Clockwise M5 * 51 - Counter-Clockwise M5 - **/ + * + */ void GcodeSuite::G35() { DEBUG_SECTION(log_G35, "G35", DEBUGGING(LEVELING)); @@ -82,9 +83,7 @@ void GcodeSuite::G35() { set_bed_leveling_enabled(false); #endif - #if ENABLED(CNC_WORKSPACE_PLANES) - workspace_plane = PLANE_XY; - #endif + TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY); probe.use_probing_tool(); diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index 5e3f86919ac0..baba95267ecf 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -1230,7 +1230,7 @@ #define _HAS_1(N) (defined(MAIN_MENU_ITEM_##N##_DESC) && defined(MAIN_MENU_ITEM_##N##_GCODE)) #define HAS_USER_ITEM(V...) DO(HAS,||,V) #else - #define HAS_USER_ITEM(N) 0 + #define HAS_USER_ITEM(...) 0 #endif /** diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 0e9ef07eb3fb..3fe26eddc182 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3463,8 +3463,8 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #error "CNC_COORDINATE_SYSTEMS is incompatible with NO_WORKSPACE_OFFSETS." #endif -#if !BLOCK_BUFFER_SIZE || !IS_POWER_OF_2(BLOCK_BUFFER_SIZE) - #error "BLOCK_BUFFER_SIZE must be a power of 2." +#if !BLOCK_BUFFER_SIZE + #error "BLOCK_BUFFER_SIZE must be non-zero." #elif BLOCK_BUFFER_SIZE > 64 #error "A very large BLOCK_BUFFER_SIZE is not needed and takes longer to drain the buffer on pause / cancel." #endif diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index c7200e2ebc23..270d028a219e 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -42,7 +42,7 @@ * version was tagged. */ #ifndef STRING_DISTRIBUTION_DATE - #define STRING_DISTRIBUTION_DATE "2023-10-20" + #define STRING_DISTRIBUTION_DATE "2023-10-28" #endif /** diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp index 3206cb63347c..2564d4f96e23 100644 --- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp +++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp @@ -1165,28 +1165,43 @@ void MarlinUI::draw_status_screen() { #endif // ADVANCED_PAUSE_FEATURE // Draw a static item with no left-right margin required. Centered by default. - void MenuItem_static::draw(const uint8_t row, FSTR_P const fstr, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { + void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { lcd_moveto(0, row); int8_t n = LCD_WIDTH; const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); - const int8_t plen = fstr ? utf8_strlen(fstr) : 0, - vlen = vstr ? utf8_strlen(vstr) : 0; - int8_t pad = (center || full) ? n - plen - vlen : 0; + + // Value length, if any + int8_t vlen = vstr ? utf8_strlen(vstr) : 0; + + // Expanded label string and width in chars + char estr[calculateWidth(ftpl) + 3] = "\0"; + int8_t llen = ftpl ? expand_u8str(estr, ftpl, itemIndex, itemStringC, itemStringF, n - vlen) : 0; + + bool mv_colon = false; + if (vlen) { + // Move the leading colon from the value to the label below + mv_colon = (*vstr == ':'); + // Shorter value, wider label + if (mv_colon) { vstr++; vlen--; llen++; } + // Remove leading spaces from the value and shorten + while (*vstr == ' ') { vstr++; vlen--; } + } + + // Padding for center or full justification + int8_t pad = (center || full) ? n - llen - vlen : 0; // SS_CENTER: Pad with half of the unused space first - if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) { lcd_put_u8str(F(" ")); n--; } + if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad, --pad, --n) lcd_put_u8str(F(" ")); - // Draw as much of the label as fits - if (plen) n -= lcd_put_u8str(fstr, itemIndex, itemStringC, itemStringF, n - vlen); + // Draw as much of the label as fits (without the relocated colon, drawn below) + if (llen) n -= lcd_put_u8str_max(estr, n - vlen); if (vlen && n > 0) { // SS_FULL: Pad with enough space to justify the value if (full && !center) { // Move the leading colon from the value to the label - if (*vstr == ':') { n -= lcd_put_u8str(F(":")); vstr++; } - // Move spaces to the padding - while (*vstr == ' ') { vstr++; pad++; } + if (mv_colon) n -= lcd_put_u8str(F(":")); // Pad in-between for (; pad > 0; --pad) { lcd_put_u8str(F(" ")); n--; } } @@ -1233,8 +1248,8 @@ void MarlinUI::draw_status_screen() { } // The Select Screen presents a prompt and two "buttons" - void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const pref, const char * const string/*=nullptr*/, FSTR_P const suff/*=nullptr*/) { - ui.draw_select_screen_prompt(pref, string, suff); + void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const fpre, const char * const string/*=nullptr*/, FSTR_P const fsuf/*=nullptr*/) { + ui.draw_select_screen_prompt(fpre, string, fsuf); if (no) { SETCURSOR(0, LCD_HEIGHT - 1); lcd_put_lchar(yesno ? ' ' : '['); lcd_put_u8str(no); lcd_put_lchar(yesno ? ' ' : ']'); diff --git a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp index 2d621d74cf2e..4a6a6eec4722 100644 --- a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp +++ b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp @@ -969,29 +969,42 @@ void MarlinUI::draw_status_screen() { #endif // Draw a static item with no left-right margin required. Centered by default. - void MenuItem_static::draw(const uint8_t row, FSTR_P const fstr, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { + void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { if (!PanelDetected) return; lcd_moveto(0, row); uint8_t n = LCD_WIDTH; const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); - const int8_t plen = fstr ? utf8_strlen(fstr) : 0, - vlen = vstr ? utf8_strlen(vstr) : 0; - int8_t pad = (center || full) ? n - plen - vlen : 0; + + // Value length, if any + int8_t vlen = vstr ? utf8_strlen(vstr) : 0; + + char estr[utf8_strlen(ftpl) + 3] = "\0"; + int8_t llen = ftpl ? expand_u8str(estr, ftpl, itemIndex, itemStringC, itemStringF, n - vlen) : 0; + + bool mv_colon = false; + if (vlen) { + // Move the leading colon from the value to the label below + mv_colon = (*vstr == ':'); + // Shorter value, wider label + if (mv_colon) { vstr++; vlen--; llen++; } + // Remove leading spaces from the value and shorten + while (*vstr == ' ') { vstr++; vlen--; } + } + + int8_t pad = (center || full) ? n - llen - vlen : 0; // SS_CENTER: Pad with half of the unused space first if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) { lcd.write(' '); n--; } // Draw as much of the label as fits - if (plen) n -= lcd_put_u8str(fstr, itemIndex, itemStringC, itemStringF, n - vlen); + if (llen) n -= lcd_put_u8str_max(estr, n - vlen); if (vlen && n > 0) { // SS_FULL: Pad with enough space to justify the value if (full && !center) { // Move the leading colon from the value to the label - if (*vstr == ':') { lcd.write(':'); vstr++; n--; } - // Move spaces to the padding - while (*vstr == ' ') { vstr++; pad++; } + if (mv_colon) { lcd.write(':'); n--; } // Pad in-between for (; pad > 0; --pad) { lcd.write(' '); n--; } } @@ -1004,25 +1017,25 @@ void MarlinUI::draw_status_screen() { } // Draw a generic menu item with pre_char (if selected) and post_char - void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const fstr, const char pre_char, const char post_char) { + void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char pre_char, const char post_char) { if (!PanelDetected) return; lcd_moveto(0, row); lcd.write(sel ? pre_char : ' '); uint8_t n = LCD_WIDTH - 2; - n -= lcd_put_u8str(fstr, itemIndex, itemStringC, itemStringF, n); + n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n); for (; n; --n) lcd.write(' '); lcd.write(post_char); lcd.print_line(); } // Draw a menu item with a (potentially) editable value - void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const fstr, const char * const inStr, const bool pgm) { + void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char * const inStr, const bool pgm) { if (!PanelDetected) return; const uint8_t vlen = inStr ? (pgm ? utf8_strlen_P(inStr) : utf8_strlen(inStr)) : 0; lcd_moveto(0, row); lcd.write(sel ? LCD_STR_ARROW_RIGHT[0] : ' '); uint8_t n = LCD_WIDTH - 2 - vlen; - n -= lcd_put_u8str(fstr, itemIndex, itemStringC, itemStringF, n); + n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n); if (vlen) { lcd.write(':'); for (; n; --n) lcd.write(' '); @@ -1051,9 +1064,9 @@ void MarlinUI::draw_status_screen() { } // The Select Screen presents a prompt and two "buttons" - void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const pref, const char * const string, FSTR_P const suff) { + void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const fpre, const char * const string, FSTR_P const fsuf) { if (!PanelDetected) return; - ui.draw_select_screen_prompt(pref, string, suff); + ui.draw_select_screen_prompt(fpre, string, fsuf); lcd.write(COLOR_EDIT); if (no) { lcd_moveto(0, MIDDLE_Y); diff --git a/Marlin/src/lcd/dogm/lcdprint_u8g.cpp b/Marlin/src/lcd/dogm/lcdprint_u8g.cpp index a615c2176661..30d687ddef5c 100644 --- a/Marlin/src/lcd/dogm/lcdprint_u8g.cpp +++ b/Marlin/src/lcd/dogm/lcdprint_u8g.cpp @@ -38,6 +38,9 @@ int lcd_put_lchar_max(const lchar_t &c, const pixel_len_t max_length) { return ret; } +/** + * @return output width in pixels + */ int lcd_put_u8str_max(const char * utf8_str, const pixel_len_t max_length) { u8g_uint_t x = u8g.getPrintCol(), y = u8g.getPrintRow(), ret = uxg_DrawUtf8Str(u8g.getU8g(), x, y, utf8_str, max_length); @@ -45,6 +48,9 @@ int lcd_put_u8str_max(const char * utf8_str, const pixel_len_t max_length) { return ret; } +/** + * @return output width in pixels + */ int lcd_put_u8str_max_P(PGM_P utf8_pstr, const pixel_len_t max_length) { u8g_uint_t x = u8g.getPrintCol(), y = u8g.getPrintRow(), ret = uxg_DrawUtf8StrP(u8g.getU8g(), x, y, utf8_pstr, max_length); diff --git a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp index c2671b1b750e..30258f0d483a 100644 --- a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp +++ b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp @@ -411,63 +411,78 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop // Draw a static line of text in the same idiom as a menu item void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { + if (!mark_as_selected(row, style & SS_INVERT)) return; - if (mark_as_selected(row, style & SS_INVERT)) { - pixel_len_t n = LCD_PIXEL_WIDTH; // pixel width of string allowed - - const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); - const int pwide = ftpl ? calculateWidth(ftpl) : 0, - vlen = vstr ? utf8_strlen(vstr) : 0; - int pad = (center || full) ? ((LCD_PIXEL_WIDTH) - pwide - vlen * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH) : 0; - - // SS_CENTER: Pad with half of the unused space first - if (center) for (int lpad = pad / 2; lpad > 0; --lpad) n -= lcd_put_u8str(F(" ")); - - // Draw as much of the label as fits - if (pwide) n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n / (MENU_FONT_WIDTH)) * (MENU_FONT_WIDTH); - - if (vlen) { - // SS_FULL: Pad with enough space to justify the value - if (full && !center && n > MENU_FONT_WIDTH) { - // Move the leading colon from the value to the label - if (*vstr == ':') { n -= lcd_put_u8str(F(":")); vstr++; } - // Move spaces to the padding - while (*vstr == ' ') { vstr++; pad++; } - // Pad in-between - for (; pad > 0; --pad) n -= lcd_put_u8str(F(" ")); - } - n -= lcd_put_u8str_max(vstr, n); + pixel_len_t n = LCD_PIXEL_WIDTH; // pixel width of string allowed + const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); + + char estr[calculateWidth(ftpl) + 3] = "\0"; + pixel_len_t lwide = ftpl ? (MENU_FONT_WIDTH) * expand_u8str(estr, ftpl, itemIndex, itemStringC, itemStringF, (LCD_PIXEL_WIDTH) / (MENU_FONT_WIDTH)) : 0; + + // Value length, if any + int8_t vlen = vstr ? utf8_strlen(vstr) : 0; + + bool mv_colon = false; + if (vlen) { + // Move the leading colon from the value to the label below + mv_colon = (*vstr == ':'); + // Shorter value, wider label + if (mv_colon) { vstr++; vlen--; lwide += MENU_FONT_WIDTH; } + // Remove leading spaces from the value and shorten + while (*vstr == ' ') { vstr++; vlen--; } + } + + // Padding for center or full justification + int8_t pad = (center || full) ? ((LCD_PIXEL_WIDTH) - lwide - vlen * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH) : 0; + + // SS_CENTER: Pad with half of the unused space first + if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) n -= lcd_put_u8str(F(" ")); + + // Draw as much of the label as fits (without the relocated colon, drawn below) + if (lwide) lcd_put_u8str_max(estr, n); + + // Value string? + if (vlen) { + // SS_FULL: Pad with enough space to justify the value + if (full && !center && n > MENU_FONT_WIDTH) { + // Draw the leading colon moved from the value to the label + if (mv_colon) n -= lcd_put_u8str(F(":")); + // Pad in-between + for (; pad > 0; --pad) n -= lcd_put_u8str(F(" ")); } - while (n > MENU_FONT_WIDTH) n -= lcd_put_u8str(F(" ")); + // Draw the value string + n -= lcd_put_u8str_max(vstr, n); } + // Always fill out the rest with spaces + while (n > MENU_FONT_WIDTH) n -= lcd_put_u8str(F(" ")); } // Draw a generic menu item void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char, const char post_char) { - if (mark_as_selected(row, sel)) { - uint8_t n = LCD_WIDTH - 1; - n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n); - for (; n; --n) lcd_put_u8str(F(" ")); - lcd_put_lchar(LCD_PIXEL_WIDTH - (MENU_FONT_WIDTH), row_y2, post_char); - lcd_put_u8str(F(" ")); - } + if (!mark_as_selected(row, sel)) return; + + uint8_t n = LCD_WIDTH - 1; + n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n); + for (; n; --n) lcd_put_u8str(F(" ")); + lcd_put_lchar(LCD_PIXEL_WIDTH - (MENU_FONT_WIDTH), row_y2, post_char); + lcd_put_u8str(F(" ")); } // Draw a menu item with an editable value void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char * const inStr, const bool pgm) { - if (mark_as_selected(row, sel)) { - const uint8_t vallen = (pgm ? utf8_strlen_P(inStr) : utf8_strlen(inStr)), - pixelwidth = (pgm ? uxg_GetUtf8StrPixelWidthP(u8g.getU8g(), inStr) : uxg_GetUtf8StrPixelWidth(u8g.getU8g(), inStr)); - const u8g_uint_t prop = USE_WIDE_GLYPH ? 2 : 1; - - uint8_t n = LCD_WIDTH - 2 - vallen * prop; - n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n); - if (vallen) { - lcd_put_u8str(F(":")); - for (; n; --n) lcd_put_u8str(F(" ")); - lcd_moveto(LCD_PIXEL_WIDTH - _MAX((MENU_FONT_WIDTH) * vallen, pixelwidth + 2), row_y2); - if (pgm) lcd_put_u8str_P(inStr); else lcd_put_u8str(inStr); - } + if (!mark_as_selected(row, sel)) return; + + const uint8_t vallen = (pgm ? utf8_strlen_P(inStr) : utf8_strlen(inStr)), + pixelwidth = (pgm ? uxg_GetUtf8StrPixelWidthP(u8g.getU8g(), inStr) : uxg_GetUtf8StrPixelWidth(u8g.getU8g(), inStr)); + const u8g_uint_t prop = USE_WIDE_GLYPH ? 2 : 1; + + uint8_t n = LCD_WIDTH - 2 - vallen * prop; + n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n); + if (vallen) { + lcd_put_u8str(F(":")); + for (; n; --n) lcd_put_u8str(F(" ")); + lcd_moveto(LCD_PIXEL_WIDTH - _MAX((MENU_FONT_WIDTH) * vallen, pixelwidth + 2), row_y2); + if (pgm) lcd_put_u8str_P(inStr); else lcd_put_u8str(inStr); } } @@ -536,8 +551,8 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop if (inv) u8g.setColorIndex(1); } - void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const fpre, const char * const string/*=nullptr*/, FSTR_P const suff/*=nullptr*/) { - ui.draw_select_screen_prompt(fpre, string, suff); + void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const fpre, const char * const string/*=nullptr*/, FSTR_P const fsuf/*=nullptr*/) { + ui.draw_select_screen_prompt(fpre, string, fsuf); if (no) draw_boxed_string(1, LCD_HEIGHT - 1, no, !yesno); if (yes) draw_boxed_string(LCD_WIDTH - (utf8_strlen(yes) * (USE_WIDE_GLYPH ? 2 : 1) + 1), LCD_HEIGHT - 1, yes, yesno); } @@ -545,13 +560,13 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop #if HAS_MEDIA void MenuItem_sdbase::draw(const bool sel, const uint8_t row, FSTR_P const, CardReader &theCard, const bool isDir) { - if (mark_as_selected(row, sel)) { - const uint8_t maxlen = LCD_WIDTH - isDir; - if (isDir) lcd_put_lchar(LCD_STR_FOLDER[0]); - const pixel_len_t pixw = maxlen * (MENU_FONT_WIDTH); - pixel_len_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), pixw); - for (; n > MENU_FONT_WIDTH; n -= MENU_FONT_WIDTH) lcd_put_u8str(F(" ")); - } + if (!mark_as_selected(row, sel)) return; + + const uint8_t maxlen = LCD_WIDTH - isDir; + if (isDir) lcd_put_lchar(LCD_STR_FOLDER[0]); + const pixel_len_t pixw = maxlen * (MENU_FONT_WIDTH); + pixel_len_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), pixw); + for (; n > MENU_FONT_WIDTH; n -= MENU_FONT_WIDTH) lcd_put_u8str(F(" ")); } #endif // HAS_MEDIA diff --git a/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp b/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp index 27e5b38bd0a3..cc9d7b2e7b31 100644 --- a/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp +++ b/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp @@ -308,103 +308,116 @@ void MarlinUI::draw_status_message(const bool blink) { void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { // Call mark_as_selected to draw a bigger selection box // and draw the text without a background - if (mark_as_selected(row, (bool)(style & SS_INVERT), true)) { - ui.set_font(DWIN_FONT_MENU); - dwin_font.solid = false; - dwin_font.fg = COLOR_WHITE; + if (!mark_as_selected(row, (bool)(style & SS_INVERT), true)) return; - dwin_string.set(); + ui.set_font(DWIN_FONT_MENU); + dwin_font.solid = false; + dwin_font.fg = COLOR_WHITE; - const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); - const int8_t plen = ftpl ? utf8_strlen(ftpl) : 0, - vlen = vstr ? utf8_strlen(vstr) : 0; - int8_t pad = (center || full) ? (LCD_WIDTH) - 1 - plen - vlen : 0; + dwin_string.set(); - // SS_CENTER: Pad with half of the unused space first - if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) dwin_string.add(' '); + const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); + int8_t plen = ftpl ? utf8_strlen(ftpl) : 0; + const int8_t olen = plen; + // Value length, if any + int8_t vlen = vstr ? utf8_strlen(vstr) : 0; + + bool mv_colon = false; + if (vlen) { + // Move the leading colon from the value to the label below + mv_colon = (*vstr == ':'); + // Shorter value, wider label + if (mv_colon) { vstr++; vlen--; plen++; } + // Remove leading spaces from the value and shorten + while (*vstr == ' ') { vstr++; vlen--; } + } + + int8_t pad = (center || full) ? (LCD_WIDTH) - 1 - plen - vlen : 0; + + // SS_CENTER: Pad with half of the unused space first + if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad, --pad) dwin_string.add(' '); + + if (plen) { // Append the templated label string - if (plen) { - dwin_string.add(ftpl, itemIndex, itemStringC, itemStringF); - pad -= dwin_string.length - plen; - } + dwin_string.add(ftpl, itemIndex, itemStringC, itemStringF); + // Remove padding if the string was expanded + pad -= dwin_string.length - olen; + } - // SS_FULL: Pad with enough space to justify the value - if (vlen) { - if (full && !center) { - // Move the leading colon from the value to the label - if (*vstr == ':') { dwin_string.add(':'); vstr++; } - // Move spaces to the padding - while (*vstr == ' ') { vstr++; pad++; } - // Pad in-between - for (; pad > 0; --pad) dwin_string.add(' '); - } - // Append the value - dwin_string.add(vstr); + // SS_FULL: Pad with enough space to justify the value + if (vlen) { + if (full && !center) { + // Append the leading colon moved from the value to the label + if (mv_colon) dwin_string.add(':'); + // Pad in-between + for (; pad > 0; --pad) dwin_string.add(' '); } + // Append the value + dwin_string.add(vstr); + } - // SS_CENTER: Pad the rest of the string - if (center) for (int8_t rpad = pad - (pad / 2); rpad > 0; --rpad) dwin_string.add(' '); + // SS_CENTER: Pad the rest of the string + if (center) while (pad--) dwin_string.add(' '); - lcd_moveto(1, row); - lcd_put_dwin_string(); - } + lcd_moveto(1, row); + lcd_put_dwin_string(); } // Draw a generic menu item void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char, const char post_char) { - if (mark_as_selected(row, sel)) { - ui.set_font(DWIN_FONT_MENU); - dwin_font.solid = false; - dwin_font.fg = COLOR_WHITE; + if (!mark_as_selected(row, sel)) return; + + ui.set_font(DWIN_FONT_MENU); + dwin_font.solid = false; + dwin_font.fg = COLOR_WHITE; - dwin_string.set(ftpl, itemIndex, itemStringC, itemStringF); + dwin_string.set(ftpl, itemIndex, itemStringC, itemStringF); - pixel_len_t n = LCD_WIDTH - 1 - dwin_string.length; - while (--n > 1) dwin_string.add(' '); + pixel_len_t n = LCD_WIDTH - 1 - dwin_string.length; + while (--n > 1) dwin_string.add(' '); - dwin_string.add(post_char); + dwin_string.add(post_char); - lcd_moveto(1, row); - lcd_put_dwin_string(); - } + lcd_moveto(1, row); + lcd_put_dwin_string(); } // // Draw a menu item with an editable value // void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char * const inStr, const bool pgm) { - if (mark_as_selected(row, sel)) { - ui.set_font(DWIN_FONT_MENU); - dwin_font.solid = false; - dwin_font.fg = COLOR_WHITE; + if (!mark_as_selected(row, sel)) return; - const uint8_t vallen = (pgm ? utf8_strlen_P(inStr) : utf8_strlen(S(inStr))); + ui.set_font(DWIN_FONT_MENU); + dwin_font.solid = false; + dwin_font.fg = COLOR_WHITE; - dwin_string.set(ftpl, itemIndex, itemStringC, itemStringF); - if (vallen) dwin_string.add(':'); + const uint8_t vallen = (pgm ? utf8_strlen_P(inStr) : utf8_strlen(S(inStr))); - lcd_moveto(1, row); - lcd_put_dwin_string(); + dwin_string.set(ftpl, itemIndex, itemStringC, itemStringF); + if (vallen) dwin_string.add(':'); - if (vallen) { - dwin_font.fg = COLOR_YELLOW; - dwin_string.set(inStr); - lcd_moveto(LCD_WIDTH - vallen - 1, row); - lcd_put_dwin_string(); - } + lcd_moveto(1, row); + lcd_put_dwin_string(); + + if (vallen) { + dwin_font.fg = COLOR_YELLOW; + dwin_string.set(inStr); + lcd_moveto(LCD_WIDTH - vallen - 1, row); + lcd_put_dwin_string(); } } // // Draw an edit screen with label and current value // - void MenuEditItemBase::draw_edit_screen(FSTR_P const fstr, const char* const value/*=nullptr*/) { + void MenuEditItemBase::draw_edit_screen(FSTR_P const ftpl, const char* const value/*=nullptr*/) { ui.encoder_direction_normal(); - const dwin_coord_t labellen = utf8_strlen(fstr), vallen = utf8_strlen(value); + const dwin_coord_t labellen = utf8_strlen(ftpl), vallen = utf8_strlen(value); - dwin_string.set(FTOP(fstr), itemIndex); + dwin_string.set(FTOP(ftpl), itemIndex); if (vallen) dwin_string.add(':'); // If a value is included, add a colon // Assume the label is alpha-numeric (with a descender) @@ -440,7 +453,7 @@ void MarlinUI::draw_status_message(const bool blink) { } inline void draw_boxed_string(const bool yesopt, FSTR_P const fstr, const bool inv) { - const uint8_t len = utf8_strlen(fstr), + const uint8_t len = utf8_strlen_P(FTOP(fstr)), mar = TERN(DWIN_MARLINUI_PORTRAIT, 1, 4), col = yesopt ? LCD_WIDTH - mar - len : mar, row = (LCD_HEIGHT >= 8 ? LCD_HEIGHT / 2 + 3 : LCD_HEIGHT - 1); @@ -451,12 +464,12 @@ void MarlinUI::draw_status_message(const bool blink) { void MenuItem_confirm::draw_select_screen( FSTR_P const yes, FSTR_P const no, const bool yesno, - FSTR_P const pref, const char * const string/*=nullptr*/, FSTR_P const suff/*=nullptr*/ + FSTR_P const fpre, const char * const string/*=nullptr*/, FSTR_P const fsuf/*=nullptr*/ ) { ui.set_font(DWIN_FONT_MENU); dwin_font.solid = false; dwin_font.fg = COLOR_WHITE; - ui.draw_select_screen_prompt(pref, string, suff); + ui.draw_select_screen_prompt(fpre, string, fsuf); if (no) draw_boxed_string(false, no, !yesno); if (yes) draw_boxed_string(true, yes, yesno); } @@ -464,21 +477,21 @@ void MarlinUI::draw_status_message(const bool blink) { #if HAS_MEDIA void MenuItem_sdbase::draw(const bool sel, const uint8_t row, FSTR_P const, CardReader &theCard, const bool isDir) { - if (mark_as_selected(row, sel)) { - dwin_string.set(); + if (!mark_as_selected(row, sel)) return; - uint8_t maxlen = LCD_WIDTH - 1; - if (isDir) { - dwin_string.add(LCD_STR_FOLDER " "); - maxlen -= 2; - } + dwin_string.set(); - dwin_string.add(ui.scrolled_filename(theCard, maxlen, row, sel), maxlen); - uint8_t n = maxlen - dwin_string.length; - while (n > 0) { dwin_string.add(' '); --n; } - lcd_moveto(1, row); - lcd_put_dwin_string(); + uint8_t maxlen = LCD_WIDTH - 1; + if (isDir) { + dwin_string.add(LCD_STR_FOLDER " "); + maxlen -= 2; } + + dwin_string.add(ui.scrolled_filename(theCard, maxlen, row, sel), maxlen); + uint8_t n = maxlen - dwin_string.length; + while (n > 0) { dwin_string.add(' '); --n; } + lcd_moveto(1, row); + lcd_put_dwin_string(); } #endif // HAS_MEDIA diff --git a/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp b/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp index 1aaa37870806..4726cba3786a 100644 --- a/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp +++ b/Marlin/src/lcd/extui/anycubic_vyper/dgus_tft.cpp @@ -276,6 +276,9 @@ namespace Anycubic { return stringLength; } + #undef GET_TEXT + #define GET_TEXT(MSG) Language_en::MSG + void DgusTFT::printerKilled(FSTR_P error_p, FSTR_P component_p) { // copy string in FLASH to RAM for strcmp_P @@ -295,7 +298,7 @@ namespace Anycubic { if (strcmp_P(error, GET_TEXT(MSG_ERR_HEATING_FAILED)) == 0) { - if (strcmp_P(component, PSTR("Bed")) == 0) { + if (strcmp_P(component, GET_TEXT(MSG_BED)) == 0) { changePageOfTFT(PAGE_CHS_ABNORMAL_BED_HEATER); SERIAL_ECHOLNPGM("Check Bed heater"); } @@ -307,7 +310,7 @@ namespace Anycubic { } else if (strcmp_P(error, GET_TEXT(MSG_ERR_MINTEMP)) == 0) { - if (strcmp_P(component, PSTR("Bed")) == 0) { + if (strcmp_P(component, GET_TEXT(MSG_BED)) == 0) { changePageOfTFT(PAGE_CHS_ABNORMAL_BED_NTC); SERIAL_ECHOLNPGM("Check Bed thermistor"); } @@ -319,7 +322,7 @@ namespace Anycubic { } else if (strcmp_P(error, GET_TEXT(MSG_ERR_MAXTEMP)) == 0) { - if (strcmp_P(component, PSTR("Bed")) == 0) { + if (strcmp_P(component, GET_TEXT(MSG_BED)) == 0) { changePageOfTFT(PAGE_CHS_ABNORMAL_BED_NTC); SERIAL_ECHOLNPGM("Check Bed thermistor"); } @@ -331,7 +334,7 @@ namespace Anycubic { } else if (strcmp_P(error, GET_TEXT(MSG_ERR_THERMAL_RUNAWAY)) == 0) { - if (strcmp_P(component, PSTR("Bed")) == 0) { + if (strcmp_P(component, GET_TEXT(MSG_BED)) == 0) { changePageOfTFT(PAGE_CHS_ABNORMAL_BED_HEATER); SERIAL_ECHOLNPGM("Check Bed thermal runaway"); } diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/bed_mesh_view_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/bed_mesh_view_screen.cpp index c42d83420f2c..6030fd02a0e7 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/bed_mesh_view_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/bed_mesh_view_screen.cpp @@ -53,7 +53,7 @@ constexpr static float gaugeThickness = 0.25; #endif static float meshGetter(uint8_t x, uint8_t y, void*) { - return ExtUI::getMeshPoint(xy_uint8_t(x, y)); + return ExtUI::getMeshPoint(xy_uint8_t({ x, y })); } void BedMeshViewScreen::onEntry() { diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/filament_runout_screen.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/filament_runout_screen.cpp index 68948b0c5e5d..0569b90032d1 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/filament_runout_screen.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/filament_runout_screen.cpp @@ -46,7 +46,9 @@ void FilamentRunoutScreen::onRedraw(draw_mode_t what) { bool FilamentRunoutScreen::onTouchHeld(uint8_t tag) { using namespace ExtUI; - const float increment = getIncrement(); + #if HAS_FILAMENT_RUNOUT_DISTANCE + const float increment = getIncrement(); + #endif switch (tag) { case 2: setFilamentRunoutEnabled(!getFilamentRunoutEnabled()); break; #if HAS_FILAMENT_RUNOUT_DISTANCE diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/language_menu.cpp b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/language_menu.cpp index 5d797f44df31..15252941d7de 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/language_menu.cpp +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/generic/language_menu.cpp @@ -53,6 +53,8 @@ void LanguageMenu::onRedraw(draw_mode_t) { #endif } +extern uint8_t ftdi_language; + bool LanguageMenu::onTouchEnd(uint8_t tag) { if (tag > 0 && tag <= NUM_LANGUAGES) { diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 9e3776d36b8e..620171ab63c6 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -38,6 +38,8 @@ #define DISPLAY_CHARSET_ISO10646_1 +#define MEDIA_TYPE_IT "Media" + namespace LanguageNarrow_it { using namespace Language_en; // Inherit undefined strings from English @@ -52,14 +54,16 @@ namespace LanguageNarrow_it { LSTR MSG_BACK = _UxGT("Indietro"); LSTR MSG_ERROR = _UxGT("Errore"); LSTR MSG_MEDIA_ABORTING = _UxGT("Annullando..."); - LSTR MSG_MEDIA_INSERTED = _UxGT("Media inserito"); - LSTR MSG_MEDIA_REMOVED = _UxGT("Media rimosso"); - LSTR MSG_MEDIA_WAITING = _UxGT("Aspettando media"); - LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Iniz.Media fallita"); - LSTR MSG_MEDIA_READ_ERROR = _UxGT("Err.leggendo media"); + LSTR MSG_MEDIA_INSERTED = MEDIA_TYPE_IT _UxGT(" inserito"); + LSTR MSG_MEDIA_REMOVED = MEDIA_TYPE_IT _UxGT(" rimosso"); + LSTR MSG_MEDIA_WAITING = _UxGT("Aspettando ") MEDIA_TYPE_IT; + LSTR MSG_MEDIA_INIT_FAIL = _UxGT("Iniz.") MEDIA_TYPE_IT _UxGT(" fallita"); + LSTR MSG_MEDIA_READ_ERROR = _UxGT("Err.leggendo ") MEDIA_TYPE_IT; LSTR MSG_MEDIA_USB_REMOVED = _UxGT("Dispos.USB rimosso"); LSTR MSG_MEDIA_USB_FAILED = _UxGT("Avvio USB fallito"); - LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Overflow subchiamate"); + LSTR MSG_MEDIA_SORT = _UxGT("Ordina ") MEDIA_TYPE_IT; + LSTR MSG_MEDIA_UPDATE = _UxGT("Aggiorna ") MEDIA_TYPE_IT; + LSTR MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Overflow sottochiamate"); LSTR MSG_LCD_ENDSTOPS = _UxGT("Finecor."); // Max 8 characters LSTR MSG_LCD_SOFT_ENDSTOPS = _UxGT("Finecorsa Soft"); LSTR MSG_MAIN_MENU = _UxGT("Menu principale"); @@ -175,6 +179,7 @@ namespace LanguageNarrow_it { LSTR MSG_MESH_CENTER = _UxGT("Area centrale"); LSTR MSG_MESH_EDIT_Z = _UxGT("Valore di Z"); LSTR MSG_MESH_CANCEL = _UxGT("Mesh cancellata"); + LSTR MSG_MESH_RESET = _UxGT("Resetta mesh"); LSTR MSG_CUSTOM_COMMANDS = _UxGT("Comandi personaliz."); LSTR MSG_M48_TEST = _UxGT("Test sonda M48"); LSTR MSG_M48_POINT = _UxGT("Punto M48"); @@ -383,6 +388,7 @@ namespace LanguageNarrow_it { LSTR MSG_VN_JERK = _UxGT("Max Jerk @"); LSTR MSG_VE_JERK = _UxGT("Max Jerk E"); LSTR MSG_JUNCTION_DEVIATION = _UxGT("Deviaz. giunzioni"); + LSTR MSG_STEP_SMOOTHING = _UxGT("Leviga passo"); LSTR MSG_MAX_SPEED = _UxGT("Vel.massima (mm/s)"); LSTR MSG_VMAX_A = _UxGT("Vel.Massima ") STR_A; LSTR MSG_VMAX_B = _UxGT("Vel.Massima ") STR_B; @@ -406,6 +412,12 @@ namespace LanguageNarrow_it { LSTR MSG_SHAPING_DISABLE = _UxGT("Disabil. shaping @"); LSTR MSG_SHAPING_FREQ = _UxGT("Frequenza @"); LSTR MSG_SHAPING_ZETA = _UxGT("Smorzamento @"); + LSTR MSG_SHAPING_A_FREQ = _UxGT("Frequenza ") STR_A; + LSTR MSG_SHAPING_B_FREQ = _UxGT("Frequenza ") STR_B; + LSTR MSG_SHAPING_A_ZETA = _UxGT("Smorzamento ") STR_A _UxGT(" "); + LSTR MSG_SHAPING_B_ZETA = _UxGT("Smorzamento ") STR_B _UxGT(" "); + LSTR MSG_SHAPING_X_ENABLE = _UxGT("Abilita shaping X"); + LSTR MSG_SHAPING_Y_ENABLE = _UxGT("Abilita shaping Y"); LSTR MSG_XY_FREQUENCY_LIMIT = _UxGT("Frequenza max"); LSTR MSG_XY_FREQUENCY_FEEDRATE = _UxGT("Feed min"); LSTR MSG_STEPS_PER_MM = _UxGT("Passi/mm"); @@ -448,7 +460,7 @@ namespace LanguageNarrow_it { LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Err: Versione EEPROM"); LSTR MSG_ERR_EEPROM_CORRUPT = _UxGT("Err: EEPROM corrotta"); LSTR MSG_SETTINGS_STORED = _UxGT("Impostazioni mem."); - LSTR MSG_MEDIA_UPDATE = _UxGT("Aggiorna media"); + LSTR MSG_HAS_PREVIEW = _UxGT("Ha anteprima"); LSTR MSG_RESET_PRINTER = _UxGT("Resetta stampante"); LSTR MSG_REFRESH = LCD_STR_REFRESH _UxGT("Aggiorna"); LSTR MSG_INFO_SCREEN = _UxGT("Schermata info"); @@ -495,8 +507,8 @@ namespace LanguageNarrow_it { LSTR MSG_CANCEL_OBJECT_N = _UxGT("Canc. Oggetto {"); LSTR MSG_OUTAGE_RECOVERY = _UxGT("Ripresa da PowerLoss"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Cont.proc.stampa"); - LSTR MSG_MEDIA_MENU = _UxGT("Stampa da media"); - LSTR MSG_NO_MEDIA = _UxGT("Media non presente"); + LSTR MSG_MEDIA_MENU = _UxGT("Stampa da ") MEDIA_TYPE_IT; + LSTR MSG_NO_MEDIA = MEDIA_TYPE_IT _UxGT(" non presente"); LSTR MSG_DWELL = _UxGT("Sospensione..."); LSTR MSG_USERWAIT = _UxGT("Premi tasto.."); LSTR MSG_PRINT_PAUSED = _UxGT("Stampa sospesa"); @@ -546,10 +558,11 @@ namespace LanguageNarrow_it { LSTR MSG_FILAMENTUNLOAD = _UxGT("Rimuovi filamento"); LSTR MSG_FILAMENTUNLOAD_E = _UxGT("Rimuovi filam. *"); LSTR MSG_FILAMENTUNLOAD_ALL = _UxGT("Rimuovi tutto"); - LSTR MSG_ATTACH_MEDIA = _UxGT("Collega media"); + LSTR MSG_ATTACH_MEDIA = _UxGT("Collega ") MEDIA_TYPE_IT; + LSTR MSG_ATTACH_SD_MEDIA = _UxGT("Collega scheda SD"); LSTR MSG_ATTACH_USB_MEDIA = _UxGT("Collega penna USB"); - LSTR MSG_CHANGE_MEDIA = _UxGT("Cambia media"); - LSTR MSG_RELEASE_MEDIA = _UxGT("Rilascia media"); + LSTR MSG_CHANGE_MEDIA = _UxGT("Cambia ") MEDIA_TYPE_IT; + LSTR MSG_RELEASE_MEDIA = _UxGT("Rilascia ") MEDIA_TYPE_IT; LSTR MSG_ZPROBE_OUT = _UxGT("Z probe fuori piatto"); LSTR MSG_SKEW_FACTOR = _UxGT("Fattore distorsione"); LSTR MSG_BLTOUCH = _UxGT("BLTouch"); @@ -640,6 +653,9 @@ namespace LanguageNarrow_it { LSTR MSG_INFO_RUNAWAY_OFF = _UxGT("Controllo fuga: OFF"); LSTR MSG_INFO_RUNAWAY_ON = _UxGT("Controllo fuga: ON"); LSTR MSG_HOTEND_IDLE_TIMEOUT = _UxGT("Timeout inatt.ugello"); + LSTR MSG_HOTEND_IDLE_DISABLE = _UxGT("Disabilita Timeout"); + LSTR MSG_HOTEND_IDLE_NOZZLE_TARGET = _UxGT("Temp.inatt.ugello"); + LSTR MSG_HOTEND_IDLE_BED_TARGET = _UxGT("Temp.inatt.letto"); LSTR MSG_FAN_SPEED_FAULT = _UxGT("Err.vel.della ventola"); LSTR MSG_CASE_LIGHT = _UxGT("Luci Case"); @@ -768,17 +784,18 @@ namespace LanguageNarrow_it { LSTR MSG_FILAMENT_CHANGE_PURGE = _UxGT(MSG_1_LINE("Spurgo filamento")); LSTR MSG_FILAMENT_CHANGE_CONT_PURGE = _UxGT(MSG_1_LINE("Premi x terminare")); LSTR MSG_FILAMENT_CHANGE_RESUME = _UxGT(MSG_1_LINE("Ripresa...")); - LSTR MSG_TMC_DRIVERS = _UxGT("Driver TMC"); - LSTR MSG_TMC_CURRENT = _UxGT("Correnti driver"); + LSTR MSG_TMC_CURRENT = _UxGT("Corrente driver"); + LSTR MSG_TMC_ACURRENT = _UxGT("Corrente driver ") STR_A; + LSTR MSG_TMC_BCURRENT = _UxGT("Corrente driver ") STR_B; + LSTR MSG_TMC_CCURRENT = _UxGT("Corrente driver ") STR_C; + LSTR MSG_TMC_ECURRENT = _UxGT("Corrente driver E"); LSTR MSG_TMC_HYBRID_THRS = _UxGT("Soglia modo ibrido"); LSTR MSG_TMC_HOMING_THRS = _UxGT("Sensorless homing"); - LSTR MSG_TMC_STEPPING_MODE = _UxGT("Stealthchop"); - LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("Stealthchop"); - + LSTR MSG_TMC_STEPPING_MODE = _UxGT("Modo Stepping"); + LSTR MSG_TMC_STEALTH_ENABLED = _UxGT("StealthChop abil."); LSTR MSG_SERVICE_RESET = _UxGT("Resetta"); LSTR MSG_SERVICE_IN = _UxGT(" tra:"); - LSTR MSG_BACKLASH = _UxGT("Gioco"); LSTR MSG_BACKLASH_CORRECTION = _UxGT("Correzione"); LSTR MSG_BACKLASH_SMOOTHING = _UxGT("Appianamento"); @@ -798,6 +815,8 @@ namespace LanguageNarrow_it { LSTR MSG_FTM_MASS_BASED = _UxGT("Base-Massa"); LSTR MSG_FTM_BASE_FREQ_N = _UxGT("@ Freq. Base"); LSTR MSG_FTM_DFREQ_K_N = _UxGT("@ Freq. Dinam."); + LSTR MSG_FTM_ZETA = _UxGT("Smorzamento"); + LSTR MSG_FTM_VTOL = _UxGT("Livello Vib."); LSTR MSG_LEVEL_X_AXIS = _UxGT("Livello asse X"); LSTR MSG_AUTO_CALIBRATE = _UxGT("Auto Calibra"); @@ -859,10 +878,18 @@ namespace LanguageNarrow_it { namespace LanguageWide_it { using namespace LanguageNarrow_it; #if LCD_WIDTH >= 20 || HAS_DWIN_E3V2 + LSTR MSG_HOST_START_PRINT = _UxGT("Avvio stampa host"); + LSTR MSG_PRINTING_OBJECT = _UxGT("Sto stampando l'oggetto"); + LSTR MSG_CANCEL_OBJECT = _UxGT("Cancella l'oggetto"); + LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancella l'oggetto {"); + LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Continua il Job di stampa"); + LSTR MSG_MEDIA_MENU = _UxGT("Seleziona dal supporto"); + LSTR MSG_TURN_OFF = _UxGT("Spegni la stampante"); + LSTR MSG_END_LOOPS = _UxGT("Termina i cicli di ripetizione"); LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("Nessun supporto inserito."); LSTR MSG_PLEASE_PREHEAT = _UxGT("Si prega di preriscaldare l'hot end."); - LSTR MSG_INFO_PRINT_COUNT_RESET = _UxGT("Azzera contatori stampa"); - LSTR MSG_INFO_PRINT_COUNT = _UxGT("Contatori stampa"); + LSTR MSG_INFO_PRINT_COUNT_RESET = _UxGT("Azzera i contatori di stampa"); + LSTR MSG_INFO_PRINT_COUNT = _UxGT("Contatori di stampa"); LSTR MSG_INFO_PRINT_TIME = _UxGT("Tempo totale"); LSTR MSG_INFO_PRINT_LONGEST = _UxGT("Lavoro piĆ¹ lungo"); LSTR MSG_INFO_PRINT_FILAMENT = _UxGT("Totale estruso"); diff --git a/Marlin/src/lcd/lcdprint.cpp b/Marlin/src/lcd/lcdprint.cpp index bdf2513121ec..2b524e983f7e 100644 --- a/Marlin/src/lcd/lcdprint.cpp +++ b/Marlin/src/lcd/lcdprint.cpp @@ -32,9 +32,9 @@ #include "lcdprint.h" /** - * lcd_put_u8str_P + * expand_u8str_P * - * Print a string with optional substitutions: + * Expand a string with optional substitutions: * * $ displays the clipped string given by fstr or cstr * { displays '0'....'10' for indexes 0 - 10 @@ -44,9 +44,10 @@ * * Return the number of characters emitted */ -lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { +lcd_uint_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { const uint8_t prop = USE_WIDE_GLYPH ? 2 : 1; const uint8_t *p = (uint8_t*)ptpl; + char *o = outstr; int8_t n = maxlen; while (n > 0) { lchar_t wc; @@ -54,43 +55,80 @@ lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr/ if (!wc) break; if (wc == '{' || wc == '~' || wc == '*') { if (ind >= 0) { - if (wc == '*') { lcd_put_u8str(F("E")); n--; } + if (wc == '*') { *o++ = 'E'; n--; } if (n) { int8_t inum = ind + ((wc == '{') ? 0 : LCD_FIRST_TOOL); if (inum >= 10) { - lcd_put_lchar('0' + (inum / 10)); n--; + *o++ = ('0' + (inum / 10)); n--; inum %= 10; } - if (n) { lcd_put_lchar('0' + inum); n--; } + if (n) { *o++ = '0' + inum; n--; } } } else { PGM_P const b = ind == -2 ? GET_TEXT(MSG_CHAMBER) : GET_TEXT(MSG_BED); - n -= lcd_put_u8str_max_P(b, n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH); + strncpy_P(o, b, n); + n -= utf8_strlen_P(b); + o += strlen(o); } - if (n) { - n -= lcd_put_u8str_max_P((PGM_P)p, n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH); + if (n > 0) { + strncpy_P(o, (PGM_P)p, n); + n -= utf8_strlen(o); + o += strlen(o); break; } } else if (wc == '$' && fstr) { - n -= lcd_put_u8str_max_P(FTOP(fstr), n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH); + strncpy_P(o, FTOP(fstr), n); + n -= utf8_strlen_P(FTOP(fstr)); + o += strlen(o); } else if (wc == '$' && cstr) { - n -= lcd_put_u8str_max(cstr, n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH); + strncpy(o, cstr, n); + n -= utf8_strlen(o); + o += strlen(o); } else if (wc == '@') { - lcd_put_lchar(AXIS_CHAR(ind)); + *o++ = AXIS_CHAR(ind); + *o = '\0'; + n--; + } + else if (wc > 255 && prop == 2) { + // Wide glyph support incomplete + *((uint16_t*)o) = wc; + o += 2; + *o = '\0'; n--; } else { - lcd_put_lchar(wc); - n -= wc > 255 ? prop : 1; + *o++ = wc; + *o = '\0'; + n--; } } return maxlen - n; } +/** + * lcd_put_u8str_P + * + * Print a string with optional substitutions: + * + * $ displays the clipped string given by fstr or cstr + * { displays '0'....'10' for indexes 0 - 10 + * ~ displays '1'....'11' for indexes 0 - 10 + * * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) + * @ displays an axis name such as XYZUVW, or E for an extruder + * + * Return the number of characters emitted + */ +lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { + char estr[maxlen + 2]; + const lcd_uint_t outlen = expand_u8str_P(estr, ptpl, ind, cstr, fstr, maxlen); + lcd_put_u8str_max(estr, maxlen * (MENU_FONT_WIDTH)); + return outlen; +} + // Calculate UTF8 width with a simple check int calculateWidth(PGM_P const pstr) { if (!USE_WIDE_GLYPH) return utf8_strlen_P(pstr) * MENU_FONT_WIDTH; diff --git a/Marlin/src/lcd/lcdprint.h b/Marlin/src/lcd/lcdprint.h index 9ba514791894..87032201fb0c 100644 --- a/Marlin/src/lcd/lcdprint.h +++ b/Marlin/src/lcd/lcdprint.h @@ -205,14 +205,37 @@ inline int lcd_put_u8str(const lcd_uint_t col, const lcd_uint_t row, FSTR_P cons return lcd_put_u8str_P(col, row, FTOP(fstr)); } +/** + * @brief Expand a string with optional substitution + * @details Expand a string with optional substitutions: + * $ : the clipped string given by fstr or cstr + * { : '0'....'10' for indexes 0 - 10 + * ~ : '1'....'11' for indexes 0 - 10 + * * : 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) + * @ : an axis name such as XYZUVW, or E for an extruder + * + * @param *outstr The output destination buffer + * @param ptpl A ROM string (template) + * @param ind An index value to use for = ~ * substitution + * @param cstr An SRAM C-string to use for $ substitution + * @param fstr A ROM F-string to use for $ substitution + * @param maxlen The maximum size of the string (in pixels on GLCD) + * @return the output width (in pixels on GLCD) + */ +lcd_uint_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH); + +inline lcd_uint_t expand_u8str(char * const outstr, FSTR_P const ftpl, const int8_t ind, const char *cstr=nullptr, FSTR_P const fstr=nullptr, const lcd_uint_t maxlen=LCD_WIDTH) { + return expand_u8str_P(outstr, FTOP(ftpl), ind, cstr, fstr, maxlen); +} + /** * @brief Draw a string with optional substitution * @details Print a string with optional substitutions: - * $ displays the clipped string given by fstr or cstr - * { displays '0'....'10' for indexes 0 - 10 - * ~ displays '1'....'11' for indexes 0 - 10 - * * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) - * @ displays an axis name such as XYZUVW, or E for an extruder + * $ : the clipped string given by fstr or cstr + * { : '0'....'10' for indexes 0 - 10 + * ~ : '1'....'11' for indexes 0 - 10 + * * : 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) + * @ : an axis name such as XYZUVW, or E for an extruder * * @param ptpl A ROM string (template) * @param ind An index value to use for = ~ * substitution diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 1076d40de014..463d406110e7 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -444,8 +444,9 @@ void MarlinUI::init() { p = get_utf8_value_cb(p, cb_read_byte, wc); const bool eol = !wc; // zero ends the string // End or a break between phrases? - if (eol || wc == ' ' || wc == '-' || wc == '+' || wc == '.') { - if (!c && wc == ' ') { if (wrd) wrd++; continue; } // collapse extra spaces + if (eol || wc == ' ' || wc == '-' || wc == '+' || wc == '.' || wc == '\n') { + const bool newline_after = wc == '\n'; + if (!c && (wc == ' ' || newline_after)) { if (wrd) wrd++; continue; } // collapse extra spaces // Past the right and the word is not too long? if (col + c > LCD_WIDTH && col >= (LCD_WIDTH) / 4) _newline(); // should it wrap? c += !eol; // +1 so the space will be printed @@ -456,6 +457,7 @@ void MarlinUI::init() { lcd_put_lchar(wc); // character to the LCD } if (eol) break; // all done! + if (newline_after) _newline(); wrd = nullptr; // set up for next word } else c++; // count word characters @@ -472,20 +474,20 @@ void MarlinUI::init() { } } - void MarlinUI::draw_select_screen_prompt(FSTR_P const pref, const char * const string/*=nullptr*/, FSTR_P const suff/*=nullptr*/) { - const uint8_t plen = utf8_strlen(pref), slen = suff ? utf8_strlen(suff) : 0; + void MarlinUI::draw_select_screen_prompt(FSTR_P const fpre, const char * const string/*=nullptr*/, FSTR_P const fsuf/*=nullptr*/) { + const uint8_t plen = utf8_strlen_P(FTOP(fpre)), slen = fsuf ? utf8_strlen_P(FTOP(fsuf)) : 0; uint8_t col = 0, row = 0; if (!string && plen + slen <= LCD_WIDTH) { col = (LCD_WIDTH - plen - slen) / 2; row = LCD_HEIGHT > 3 ? 1 : 0; } if (LCD_HEIGHT >= 8) row = LCD_HEIGHT / 2 - 2; - wrap_string_P(col, row, FTOP(pref), true); + wrap_string_P(col, row, FTOP(fpre), true); if (string) { if (col) { col = 0; row++; } // Move to the start of the next line wrap_string(col, row, string); } - if (suff) wrap_string_P(col, row, FTOP(suff)); + if (fsuf) wrap_string_P(col, row, FTOP(fsuf)); } #endif // !HAS_GRAPHICAL_TFT diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 9c301e03f639..69235dda36b9 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -729,7 +729,7 @@ class MarlinUI { static float ubl_mesh_value(); #endif - static void draw_select_screen_prompt(FSTR_P const pref, const char * const string=nullptr, FSTR_P const suff=nullptr); + static void draw_select_screen_prompt(FSTR_P const fpre, const char * const string=nullptr, FSTR_P const fsuf=nullptr); #else diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp index a9574dd4d9af..a4eab8fc9d85 100644 --- a/Marlin/src/lcd/menu/menu.cpp +++ b/Marlin/src/lcd/menu/menu.cpp @@ -352,13 +352,13 @@ bool MarlinUI::update_selection() { void MenuItem_confirm::select_screen( FSTR_P const yes, FSTR_P const no, selectFunc_t yesFunc, selectFunc_t noFunc, - FSTR_P const pref, const char * const string/*=nullptr*/, FSTR_P const suff/*=nullptr*/ + FSTR_P const fpre, const char * const string/*=nullptr*/, FSTR_P const fsuf/*=nullptr*/ ) { ui.defer_status_screen(); const bool ui_selection = !yes ? false : !no || ui.update_selection(), got_click = ui.use_click(); if (got_click || ui.should_draw()) { - draw_select_screen(yes, no, ui_selection, pref, string, suff); + draw_select_screen(yes, no, ui_selection, fpre, string, fsuf); if (got_click) { selectFunc_t callFunc = ui_selection ? yesFunc : noFunc; if (callFunc) callFunc(); else ui.goto_previous_screen(); diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index d4cbfd7a73d5..e4cd183b4646 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -76,7 +76,7 @@ class MenuItemBase { // STATIC_ITEM(LABEL,...) class MenuItem_static : public MenuItemBase { public: - static void draw(const uint8_t row, FSTR_P const fstr, const uint8_t style=SS_DEFAULT, const char *vstr=nullptr); + static void draw(const uint8_t row, FSTR_P const ftpl, const uint8_t style=SS_DEFAULT, const char *vstr=nullptr); }; // BACK_ITEM(LABEL) @@ -102,31 +102,31 @@ class MenuItem_confirm : public MenuItemBase { FSTR_P const yes, // Right option label FSTR_P const no, // Left option label const bool yesno, // Is "yes" selected? - FSTR_P const pref, // Prompt prefix + FSTR_P const fpre, // Prompt prefix const char * const string, // Prompt runtime string - FSTR_P const suff // Prompt suffix + FSTR_P const fsuf // Prompt suffix ); static void select_screen( FSTR_P const yes, FSTR_P const no, selectFunc_t yesFunc, selectFunc_t noFunc, - FSTR_P const pref, const char * const string=nullptr, FSTR_P const suff=nullptr + FSTR_P const fpre, const char * const string=nullptr, FSTR_P const fsuf=nullptr ); static void select_screen( FSTR_P const yes, FSTR_P const no, selectFunc_t yesFunc, selectFunc_t noFunc, - FSTR_P const pref, FSTR_P const fstr, FSTR_P const suff=nullptr + FSTR_P const fpre, FSTR_P const fstr, FSTR_P const fsuf=nullptr ) { #ifdef __AVR__ char str[strlen_P(FTOP(fstr)) + 1]; strcpy_P(str, FTOP(fstr)); - select_screen(yes, no, yesFunc, noFunc, pref, str, suff); + select_screen(yes, no, yesFunc, noFunc, fpre, str, fsuf); #else - select_screen(yes, no, yesFunc, noFunc, pref, FTOP(fstr), suff); + select_screen(yes, no, yesFunc, noFunc, fpre, FTOP(fstr), fsuf); #endif } // Shortcut for prompt with "NO"/ "YES" labels - FORCE_INLINE static void confirm_screen(selectFunc_t yesFunc, selectFunc_t noFunc, FSTR_P const pref, const char * const string=nullptr, FSTR_P const suff=nullptr) { - select_screen(GET_TEXT_F(MSG_YES), GET_TEXT_F(MSG_NO), yesFunc, noFunc, pref, string, suff); + FORCE_INLINE static void confirm_screen(selectFunc_t yesFunc, selectFunc_t noFunc, FSTR_P const fpre, const char * const string=nullptr, FSTR_P const fsuf=nullptr) { + select_screen(GET_TEXT_F(MSG_YES), GET_TEXT_F(MSG_NO), yesFunc, noFunc, fpre, string, fsuf); } }; diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index 4677d63b696c..0a8d4a975aba 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -78,7 +78,7 @@ void menu_advanced_settings(); #if ENABLED(LCD_PROGRESS_BAR_TEST) - static void progress_bar_test() { + static void screen_progress_bar_test() { static int8_t bar_percent = 0; if (ui.use_click()) { ui.goto_previous_screen(); @@ -93,8 +93,8 @@ void menu_advanced_settings(); lcd_moveto(0, LCD_HEIGHT - 1); ui.draw_progress_bar(bar_percent); } - void _progress_bar_test() { - ui.goto_screen(progress_bar_test); + void _goto_progress_bar_test() { + ui.goto_screen(screen_progress_bar_test); TERN_(HAS_MARLINUI_HD44780, ui.set_custom_characters(CHARSET_INFO)); } @@ -104,11 +104,18 @@ void menu_advanced_settings(); #define __STOP_ITEM(F,S) PSTRING_ITEM_F_P(F, TEST(stops, S) ? PSTR(STR_ENDSTOP_HIT) : PSTR(STR_ENDSTOP_OPEN), SS_FULL); #define _STOP_ITEM(L,S) __STOP_ITEM(F(L), S) - #define STOP_ITEM(A,I,M,L) TERN(HAS_##A##I##_##M##_STATE, _STOP_ITEM, _IF_1_ELSE)(STRINGIFY(A) STRINGIFY(I) " " STRINGIFY(L), A##I##_##M) + #if HAS_X2_STATE || HAS_Y2_STATE || HAS_Z2_STATE + #define _S1_EXP_ ~, + #define _S1_SP_(I) THIRD(I, " ", "") + #define S1_SPACE(I) _S1_SP_(_CAT(_S1_EXP_,I)) + #else + #define S1_SPACE(I) + #endif + #define STOP_ITEM(A,I,M,L) TERN(HAS_##A##I##_##M##_STATE, _STOP_ITEM, _IF_1_ELSE)(STRINGIFY(A) STRINGIFY(I) S1_SPACE(I) " " L, A##I##_##M) #define STOP_MINMAX(A,I) STOP_ITEM(A,I,MIN,"Min") STOP_ITEM(A,I,MAX,"Max") #define FIL_ITEM(N) PSTRING_ITEM_N_P(N-1, MSG_FILAMENT_EN, (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) ? PSTR("PRESENT") : PSTR("out"), SS_FULL); - static void endstop_test() { + static void screen_endstop_test() { if (ui.use_click()) { ui.goto_previous_screen(); //endstops.enable_globally(false); @@ -148,11 +155,11 @@ void menu_advanced_settings(); BACK_ITEM(MSG_CONFIGURATION); #if ENABLED(LCD_PROGRESS_BAR_TEST) - SUBMENU(MSG_PROGRESS_BAR_TEST, _progress_bar_test); + SUBMENU(MSG_PROGRESS_BAR_TEST, _goto_progress_bar_test); #endif #if ENABLED(LCD_ENDSTOP_TEST) - SUBMENU(MSG_ENDSTOP_TEST, endstop_test); + SUBMENU(MSG_ENDSTOP_TEST, screen_endstop_test); #endif END_MENU(); @@ -540,13 +547,6 @@ void menu_configuration() { START_MENU(); BACK_ITEM(MSG_MAIN_MENU); - // - // Debug Menu when certain options are enabled - // - #if HAS_DEBUG_MENU - SUBMENU(MSG_DEBUG_MENU, menu_debug); - #endif - #if ENABLED(CUSTOM_MENU_CONFIG) if (TERN1(CUSTOM_MENU_CONFIG_ONLY_IDLE, !busy)) { #ifdef CUSTOM_MENU_CONFIG_TITLE @@ -650,6 +650,12 @@ void menu_configuration() { EDIT_ITEM(bool, MSG_SOUND, &ui.sound_on, []{ ui.chirp(); }); #endif + // Debug Menu when certain options are enabled + // Note: it is at the end of the list, so a more commonly used items should be placed above + #if HAS_DEBUG_MENU + SUBMENU(MSG_DEBUG_MENU, menu_debug); + #endif + #if ENABLED(EEPROM_SETTINGS) ACTION_ITEM(MSG_STORE_EEPROM, ui.store_settings); if (!busy) ACTION_ITEM(MSG_LOAD_EEPROM, ui.load_settings); diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h index ecc1ac4047a7..011cdc4423aa 100644 --- a/Marlin/src/lcd/menu/menu_item.h +++ b/Marlin/src/lcd/menu/menu_item.h @@ -242,6 +242,9 @@ class MenuItem_bool : public MenuEditItemBase { #define START_SCREEN() SCREEN_OR_MENU_LOOP(false) #define START_MENU() SCREEN_OR_MENU_LOOP(true) #define NEXT_ITEM() (++_thisItemNr) +#define MY_LINE() (_menuLineNr == _thisItemNr) +#define HIGHLIGHTED() (encoderLine == _thisItemNr) +#define CLICKED() (HIGHLIGHTED() && ui.use_click()) #define SKIP_ITEM() NEXT_ITEM() #define END_SCREEN() } screen_items = _thisItemNr #define END_MENU() END_SCREEN(); UNUSED(_skipStatic) @@ -274,19 +277,19 @@ class MenuItem_bool : public MenuEditItemBase { #define _MENU_INNER_F(TYPE, USE_MULTIPLIER, FLABEL, V...) do { \ FSTR_P const flabel = FLABEL; \ - if (encoderLine == _thisItemNr && ui.use_click()) { \ + if (CLICKED()) { \ _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER); \ MenuItem_##TYPE::action(flabel, ##V); \ if (ui.screen_changed) return; \ } \ if (ui.should_draw()) \ MenuItem_##TYPE::draw \ - (encoderLine == _thisItemNr, _lcdLineNr, flabel, ##V); \ + (HIGHLIGHTED(), _lcdLineNr, flabel, ##V); \ }while(0) // Item with optional data #define _MENU_ITEM_F(TYPE, V...) do { \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ _MENU_INNER_F(TYPE, ##V); \ } \ @@ -295,7 +298,7 @@ class MenuItem_bool : public MenuEditItemBase { // Item with index value, C-string, and optional data #define _MENU_ITEM_N_S_F(TYPE, N, S, V...) do{ \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ MenuItemBase::init(N, S); \ _MENU_INNER_F(TYPE, ##V); \ @@ -305,7 +308,7 @@ class MenuItem_bool : public MenuEditItemBase { // Item with index value and F-string #define _MENU_ITEM_N_f_F(TYPE, N, f, V...) do{ \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ MenuItemBase::init(N, f); \ _MENU_INNER_F(TYPE, ##V); \ @@ -315,7 +318,7 @@ class MenuItem_bool : public MenuEditItemBase { // Item with index value #define _MENU_ITEM_N_F(TYPE, N, V...) do{ \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ MenuItemBase::init(N); \ _MENU_INNER_F(TYPE, ##V); \ @@ -325,7 +328,7 @@ class MenuItem_bool : public MenuEditItemBase { // Items with a unique string #define _MENU_ITEM_S_F(TYPE, S, V...) do{ \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ MenuItemBase::init(0, S); \ _MENU_INNER_F(TYPE, ##V); \ @@ -335,7 +338,7 @@ class MenuItem_bool : public MenuEditItemBase { // Items with a unique F-string #define _MENU_ITEM_f_F(TYPE, f, V...) do{ \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ MenuItemBase::init(0, f); \ _MENU_INNER_F(TYPE, ##V); \ @@ -356,13 +359,13 @@ class MenuItem_bool : public MenuEditItemBase { } while(0) #define STATIC_ITEM_F(FLABEL, V...) do{ \ - if (_menuLineNr == _thisItemNr) \ + if (MY_LINE()) \ STATIC_ITEM_INNER_F(FLABEL, ##V); \ NEXT_ITEM(); \ } while(0) #define STATIC_ITEM_N_F(N, FLABEL, V...) do{ \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ MenuItemBase::init(N); \ STATIC_ITEM_INNER_F(FLABEL, ##V); \ } \ @@ -500,18 +503,18 @@ class MenuItem_bool : public MenuEditItemBase { #define EDIT_ITEM_FAST_f(TYPE, f, LABEL, V...) EDIT_ITEM_FAST_f_F(TYPE, f, GET_TEXT_F(LABEL), ##V) #define _CONFIRM_ITEM_INNER_F(FLABEL, V...) do { \ - if (encoderLine == _thisItemNr && ui.use_click()) { \ + if (CLICKED()) { \ ui.push_current_screen(); \ ui.goto_screen([]{MenuItem_confirm::select_screen(V);}); \ return; \ } \ if (ui.should_draw()) MenuItem_confirm::draw \ - (encoderLine == _thisItemNr, _lcdLineNr, FLABEL, ##V); \ + (HIGHLIGHTED(), _lcdLineNr, FLABEL, ##V); \ }while(0) // Indexed items set a global index value and optional data #define _CONFIRM_ITEM_F(FLABEL, V...) do { \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ _CONFIRM_ITEM_INNER_F(FLABEL, ##V); \ } \ @@ -520,7 +523,7 @@ class MenuItem_bool : public MenuEditItemBase { // Indexed items set a global index value #define _CONFIRM_ITEM_N_S_F(N, S, V...) do{ \ - if (_menuLineNr == _thisItemNr) { \ + if (MY_LINE()) { \ _skipStatic = false; \ MenuItemBase::init(N, S); \ _CONFIRM_ITEM_INNER_F(TYPE, ##V); \ diff --git a/Marlin/src/lcd/tft/canvas.cpp b/Marlin/src/lcd/tft/canvas.cpp index 4bded7225125..2486179ce3de 100644 --- a/Marlin/src/lcd/tft/canvas.cpp +++ b/Marlin/src/lcd/tft/canvas.cpp @@ -129,6 +129,13 @@ void Canvas::addImage(int16_t x, int16_t y, MarlinImage image, uint16_t *colors) } #if ENABLED(COMPACT_MARLIN_BOOT_LOGO) + + static struct { + bool has_rle_state = false; + int16_t dstx, dsty, srcx, srcy; + uint32_t rle_offset; + } rle_state; + // RLE16 HIGHCOLOR - 16 bits per pixel if (color_mode == RLE16) { uint8_t *bytedata = (uint8_t *)images[image].data; @@ -139,8 +146,25 @@ void Canvas::addImage(int16_t x, int16_t y, MarlinImage image, uint16_t *colors) dsty = y, dstx = x; // Destination line / column index uint16_t color = 0; // Persist the last fetched color value + if (rle_state.has_rle_state) { // do we have RLE position data? + rle_state.has_rle_state = false; // invalidate stored RLE state + dstx = rle_state.dstx; // restore required states + dsty = rle_state.dsty; + srcx = rle_state.srcx; + srcy = rle_state.srcy; + bytedata = (uint8_t *)images[image].data + rle_state.rle_offset; // Restart decode from here instead of the start of data + } + bool done = false; while (!done) { + if (dsty >= endLine - 1 || srcy >= image_height - 1) { // Store state? + rle_state.dstx = dstx; // Save required states + rle_state.dsty = dsty; + rle_state.srcx = srcx; + rle_state.srcy = srcy; + rle_state.rle_offset = bytedata - (uint8_t *)images[image].data;; // Keep these for skipping full RLE decode on future iteratons + } + uint8_t count = *bytedata++; // Get the count byte const bool uniq = bool(count & 0x80); // >= 128 is a distinct run; < 128 is a repeat run count = (count & 0x7F) + 1; // Actual count is 7-bit plus 1 @@ -169,6 +193,7 @@ void Canvas::addImage(int16_t x, int16_t y, MarlinImage image, uint16_t *colors) srcx = 0; dstx = x; // May be shifted within the canvas, but usually not if (dsty >= endLine || srcy >= image_height) { // Done with the segment or the image? done = true; // Set a flag to end the loop... + rle_state.has_rle_state = true; // RLE state is stored break; // ...and break out of while(count--) } } diff --git a/Marlin/src/lcd/tft/ui_color_ui.cpp b/Marlin/src/lcd/tft/ui_color_ui.cpp index cefbd05d1953..d6f3d2eff7fa 100644 --- a/Marlin/src/lcd/tft/ui_color_ui.cpp +++ b/Marlin/src/lcd/tft/ui_color_ui.cpp @@ -393,14 +393,14 @@ void MarlinUI::draw_status_screen() { } // Low-level draw_edit_screen can be used to draw an edit screen from anyplace -void MenuEditItemBase::draw_edit_screen(FSTR_P const fstr, const char * const value/*=nullptr*/) { +void MenuEditItemBase::draw_edit_screen(FSTR_P const ftpl, const char * const value/*=nullptr*/) { ui.encoder_direction_normal(); TERN_(TOUCH_SCREEN, touch.clear()); uint16_t line = 1; menu_line(line++); - tft_string.set(fstr, itemIndex, itemStringC, itemStringF); + tft_string.set(ftpl, itemIndex, itemStringC, itemStringF); tft_string.trim(); tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y, COLOR_MENU_TEXT, tft_string); @@ -457,13 +457,13 @@ void TFT::draw_edit_screen_buttons() { } // The Select Screen presents a prompt and two "buttons" -void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const pref, const char * const string/*=nullptr*/, FSTR_P const suff/*=nullptr*/) { +void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const fpre, const char * const string/*=nullptr*/, FSTR_P const fsuf/*=nullptr*/) { uint16_t line = 1; if (!string) line++; menu_line(line++); - tft_string.set(pref); + tft_string.set(fpre); tft_string.trim(); tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y, COLOR_MENU_TEXT, tft_string); @@ -474,9 +474,9 @@ void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, con tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y, COLOR_MENU_TEXT, tft_string); } - if (suff) { + if (fsuf) { menu_line(line); - tft_string.set(suff); + tft_string.set(fsuf); tft_string.trim(); tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y, COLOR_MENU_TEXT, tft_string); } diff --git a/Marlin/src/lcd/tft/ui_common.cpp b/Marlin/src/lcd/tft/ui_common.cpp index 5f426294dce9..3426abab0e20 100644 --- a/Marlin/src/lcd/tft/ui_common.cpp +++ b/Marlin/src/lcd/tft/ui_common.cpp @@ -316,14 +316,14 @@ void lcd_put_int(const int i) { // // Draw a generic menu item with pre_char (if selected) and post_char -void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const fstr, const char pre_char, const char post_char) { +void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char pre_char, const char post_char) { menu_item(row, sel); - const char *string = FTOP(fstr); + const char *string = FTOP(ftpl); MarlinImage image = noImage; switch (*string) { - case 0x01: image = imgRefresh; break; // LCD_STR_REFRESH - case 0x02: image = imgDirectory; break; // LCD_STR_FOLDER + case LCD_STR_REFRESH[0]: image = imgRefresh; break; + case LCD_STR_FOLDER[0]: image = imgDirectory; break; } uint8_t offset = MENU_TEXT_X; @@ -339,10 +339,10 @@ void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const fstr, c } // Draw a menu item with a (potentially) editable value -void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const fstr, const char * const inStr, const bool pgm) { +void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char * const inStr, const bool pgm) { menu_item(row, sel); - tft_string.set(fstr, itemIndex, itemStringC, itemStringF); + tft_string.set(ftpl, itemIndex, itemStringC, itemStringF); tft.add_text(MENU_TEXT_X, MENU_TEXT_Y, COLOR_MENU_TEXT, tft_string); if (inStr) { tft_string.set(inStr); @@ -351,10 +351,13 @@ void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const fstr } // Draw a static item with no left-right margin required. Centered by default. -void MenuItem_static::draw(const uint8_t row, FSTR_P const fstr, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { +void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t style/*=SS_DEFAULT*/, const char *vstr/*=nullptr*/) { menu_item(row); - tft_string.set(fstr, itemIndex, itemStringC, itemStringF); + if (ftpl) + tft_string.set(ftpl, itemIndex, itemStringC, itemStringF); + else + tft_string.set(); const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); if (!full || !vstr) { diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 0916ade58158..1414a3144578 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -188,6 +188,10 @@ float Planner::mm_per_step[DISTINCT_AXES]; // (mm) Millimeters per step Planner::volumetric_extruder_feedrate_limit[EXTRUDERS]; // pre calculated extruder feedrate limit based on volumetric_extruder_limit; pre-calculated to reduce computation in the planner #endif +#ifdef MAX7219_DEBUG_SLOWDOWN + uint8_t Planner::slowdown_count = 0; +#endif + #if HAS_LEVELING bool Planner::leveling_active = false; // Flag that auto bed leveling is enabled #if ABL_PLANAR @@ -985,9 +989,7 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t */ // The kernel called by recalculate() when scanning the plan from last to first entry. -void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next - OPTARG(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr) -) { +void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next, const_float_t safe_exit_speed_sqr) { if (current) { // If entry speed is already at the maximum entry speed, and there was no change of speed // in the next block, there is no need to recheck. Block is cruising and there is no need to @@ -1007,7 +1009,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. - const float next_entry_speed_sqr = next ? next->entry_speed_sqr : _MAX(TERN0(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr), sq(float(MINIMUM_PLANNER_SPEED))), + const float next_entry_speed_sqr = next ? next->entry_speed_sqr : safe_exit_speed_sqr, new_entry_speed_sqr = current->flag.nominal_length ? max_entry_speed_sqr : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next_entry_speed_sqr, current->millimeters)); @@ -1039,7 +1041,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const * recalculate() needs to go over the current plan twice. * Once in reverse and once forward. This implements the reverse pass. */ -void Planner::reverse_pass(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) { +void Planner::reverse_pass(const_float_t safe_exit_speed_sqr) { // Initialize block index to the last block in the planner buffer. uint8_t block_index = prev_block_index(block_buffer_head); @@ -1063,7 +1065,7 @@ void Planner::reverse_pass(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_ // Only process movement blocks if (current->is_move()) { - reverse_pass_kernel(current, next OPTARG(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr)); + reverse_pass_kernel(current, next, safe_exit_speed_sqr); next = current; } @@ -1176,7 +1178,7 @@ void Planner::forward_pass() { * according to the entry_factor for each junction. Must be called by * recalculate() after updating the blocks. */ -void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) { +void Planner::recalculate_trapezoids(const_float_t safe_exit_speed_sqr) { // The tail may be changed by the ISR so get a local copy. uint8_t block_index = block_buffer_tail, head_block_index = block_buffer_head; @@ -1243,8 +1245,7 @@ void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t // Last/newest block in buffer. Always recalculated. if (block) { - // Exit speed is set with MINIMUM_PLANNER_SPEED unless some code higher up knows better. - next_entry_speed = _MAX(TERN0(HINTS_SAFE_EXIT_SPEED, SQRT(safe_exit_speed_sqr)), float(MINIMUM_PLANNER_SPEED)); + next_entry_speed = SQRT(safe_exit_speed_sqr); // Mark the next(last) block as RECALCULATE, to prevent the Stepper ISR running it. // As the last block is always recalculated here, there is a chance the block isn't @@ -1267,15 +1268,15 @@ void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t } } -void Planner::recalculate(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) { +void Planner::recalculate(const_float_t safe_exit_speed_sqr) { // Initialize block index to the last block in the planner buffer. const uint8_t block_index = prev_block_index(block_buffer_head); // If there is just one block, no planning can be done. Avoid it! if (block_index != block_buffer_planned) { - reverse_pass(TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr)); + reverse_pass(safe_exit_speed_sqr); forward_pass(); } - recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr)); + recalculate_trapezoids(safe_exit_speed_sqr); } /** @@ -1829,10 +1830,12 @@ bool Planner::_buffer_steps(const xyze_long_t &target if (cleaning_buffer_counter) return false; // Fill the block with the specified movement + float minimum_planner_speed_sqr; if (!_populate_block(block, target OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) , fr_mm_s, extruder, hints + , minimum_planner_speed_sqr ) ) { // Movement was not queued, probably because it was too short. @@ -1853,8 +1856,14 @@ bool Planner::_buffer_steps(const xyze_long_t &target // Move buffer head block_buffer_head = next_buffer_head; + // find a speed from which the new block can stop safely + const float safe_exit_speed_sqr = _MAX( + TERN0(HINTS_SAFE_EXIT_SPEED, hints.safe_exit_speed_sqr), + minimum_planner_speed_sqr + ); + // Recalculate and optimize trapezoidal speed profiles - recalculate(TERN_(HINTS_SAFE_EXIT_SPEED, hints.safe_exit_speed_sqr)); + recalculate(safe_exit_speed_sqr); // Movement successfully queued! return true; @@ -1882,6 +1891,7 @@ bool Planner::_populate_block( OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints + , float &minimum_planner_speed_sqr ) { xyze_long_t dist = target - position; @@ -2316,6 +2326,9 @@ bool Planner::_populate_block( #define SLOWDOWN_DIVISOR 2 #endif if (WITHIN(moves_queued, 2, (BLOCK_BUFFER_SIZE) / (SLOWDOWN_DIVISOR) - 1)) { + #ifdef MAX7219_DEBUG_SLOWDOWN + slowdown_count = (slowdown_count + 1) & 0x0F; + #endif const int32_t time_diff = settings.min_segment_time_us - segment_time_us; if (time_diff > 0) { // Buffer is draining so add extra time. The amount of time added increases if the buffer is still emptied more. @@ -2548,6 +2561,10 @@ bool Planner::_populate_block( } #endif + // The minimum possible speed is the average speed for + // the first / last step at current acceleration limit + minimum_planner_speed_sqr = 0.5f * block->acceleration / steps_per_mm; + float vmax_junction_sqr; // Initial limit on the segment entry velocity (mm/s)^2 #if HAS_JUNCTION_DEVIATION @@ -2630,7 +2647,7 @@ bool Planner::_populate_block( // NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta). if (junction_cos_theta > 0.999999f) { // For a 0 degree acute junction, just set minimum junction speed. - vmax_junction_sqr = sq(float(MINIMUM_PLANNER_SPEED)); + vmax_junction_sqr = minimum_planner_speed_sqr; } else { // Convert delta vector to unit vector @@ -2838,6 +2855,8 @@ bool Planner::_populate_block( previous_safe_speed = safe_speed; + NOLESS(minimum_planner_speed_sqr, sq(safe_speed)); + #if HAS_JUNCTION_DEVIATION NOMORE(vmax_junction_sqr, sq(vmax_junction)); // Throttle down to max speed #else @@ -2849,11 +2868,11 @@ bool Planner::_populate_block( // Max entry speed of this block equals the max exit speed of the previous block. block->max_entry_speed_sqr = vmax_junction_sqr; - // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED. - const float v_allowable_sqr = max_allowable_speed_sqr(-block->acceleration, sq(float(MINIMUM_PLANNER_SPEED)), block->millimeters); + // Initialize block entry speed. Compute based on deceleration to sqrt(minimum_planner_speed_sqr). + const float v_allowable_sqr = max_allowable_speed_sqr(-block->acceleration, minimum_planner_speed_sqr, block->millimeters); // Start with the minimum allowed speed - block->entry_speed_sqr = sq(float(MINIMUM_PLANNER_SPEED)); + block->entry_speed_sqr = minimum_planner_speed_sqr; // Initialize planner efficiency flags // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds. diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 6fde0b2bf38e..5c9830757790 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -310,6 +310,14 @@ typedef struct PlannerBlock { #define HAS_POSITION_FLOAT 1 #endif +constexpr uint8_t block_dec_mod(const uint8_t v1, const uint8_t v2) { + return v1 >= v2 ? v1 - v2 : v1 - v2 + BLOCK_BUFFER_SIZE; +} + +constexpr uint8_t block_inc_mod(const uint8_t v1, const uint8_t v2) { + return v1 + v2 < BLOCK_BUFFER_SIZE ? v1 + v2 : v1 + v2 - BLOCK_BUFFER_SIZE; +} + #if IS_POWER_OF_2(BLOCK_BUFFER_SIZE) #define BLOCK_MOD(n) ((n)&((BLOCK_BUFFER_SIZE)-1)) #else @@ -546,6 +554,11 @@ class Planner { */ static uint32_t acceleration_long_cutoff; + #ifdef MAX7219_DEBUG_SLOWDOWN + friend class Max7219; + static uint8_t slowdown_count; + #endif + #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) static float last_fade_z; #endif @@ -768,10 +781,10 @@ class Planner { #endif // HAS_POSITION_MODIFIERS // Number of moves currently in the planner including the busy block, if any - FORCE_INLINE static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail); } + FORCE_INLINE static uint8_t movesplanned() { return block_dec_mod(block_buffer_head, block_buffer_tail); } // Number of nonbusy moves currently in the planner - FORCE_INLINE static uint8_t nonbusy_movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_nonbusy); } + FORCE_INLINE static uint8_t nonbusy_movesplanned() { return block_dec_mod(block_buffer_head, block_buffer_nonbusy); } // Remove all blocks from the buffer FORCE_INLINE static void clear_block_buffer() { block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail = 0; } @@ -837,6 +850,7 @@ class Planner { OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints + , float &minimum_planner_speed_sqr ); /** @@ -1029,8 +1043,8 @@ class Planner { /** * Get the index of the next / previous block in the ring buffer */ - static constexpr uint8_t next_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index + 1); } - static constexpr uint8_t prev_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index - 1); } + static constexpr uint8_t next_block_index(const uint8_t block_index) { return block_inc_mod(block_index, 1); } + static constexpr uint8_t prev_block_index(const uint8_t block_index) { return block_dec_mod(block_index, 1); } /** * Calculate the maximum allowable speed squared at this point, in order @@ -1052,15 +1066,15 @@ class Planner { static void calculate_trapezoid_for_block(block_t * const block, const_float_t entry_factor, const_float_t exit_factor); - static void reverse_pass_kernel(block_t * const current, const block_t * const next OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); + static void reverse_pass_kernel(block_t * const current, const block_t * const next, const_float_t safe_exit_speed_sqr); static void forward_pass_kernel(const block_t * const previous, block_t * const current, uint8_t block_index); - static void reverse_pass(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); + static void reverse_pass(const_float_t safe_exit_speed_sqr); static void forward_pass(); - static void recalculate_trapezoids(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); + static void recalculate_trapezoids(const_float_t safe_exit_speed_sqr); - static void recalculate(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); + static void recalculate(const_float_t safe_exit_speed_sqr); #if HAS_JUNCTION_DEVIATION diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index eb84426dc79d..2ccc9e7be9f8 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -139,14 +139,15 @@ constexpr ena_mask_t enable_overlap[] = { #ifdef SHAPING_MAX_STEPRATE constexpr float max_step_rate = SHAPING_MAX_STEPRATE; #else + #define ISALIM(I, ARR) _MIN(I, COUNT(ARR) - 1) constexpr float _ISDASU[] = DEFAULT_AXIS_STEPS_PER_UNIT; constexpr feedRate_t _ISDMF[] = DEFAULT_MAX_FEEDRATE; constexpr float max_shaped_rate = TERN0(INPUT_SHAPING_X, _ISDMF[X_AXIS] * _ISDASU[X_AXIS]) + TERN0(INPUT_SHAPING_Y, _ISDMF[Y_AXIS] * _ISDASU[Y_AXIS]); #if defined(__AVR__) || !defined(ADAPTIVE_STEP_SMOOTHING) // MIN_STEP_ISR_FREQUENCY is known at compile time on AVRs and any reduction in SRAM is welcome - template constexpr float max_isr_rate() { - return _MAX(_ISDMF[INDEX - 1] * _ISDASU[INDEX - 1], max_isr_rate()); + template constexpr float max_isr_rate() { + return _MAX(_ISDMF[ISALIM(INDEX - 1, _ISDMF)] * _ISDASU[ISALIM(INDEX - 1, _ISDASU)], max_isr_rate()); } template<> constexpr float max_isr_rate<0>() { return TERN0(ADAPTIVE_STEP_SMOOTHING, MIN_STEP_ISR_FREQUENCY); diff --git a/Marlin/src/pins/mega/pins_GT2560_V41b.h b/Marlin/src/pins/mega/pins_GT2560_V41b.h index 449f246b19b9..ce0adc2a396f 100644 --- a/Marlin/src/pins/mega/pins_GT2560_V41b.h +++ b/Marlin/src/pins/mega/pins_GT2560_V41b.h @@ -233,7 +233,7 @@ #define BTN_EN2 H2_08_PIN #define BTN_ENC H2_09_PIN #define BEEPER_PIN H2_12_PIN -#elif ENABLED(CR10_STOCKDISPLAY) // Firmware compatible with stock GT 128x64 12pin LCD for the V41b +#elif ENABLED(CR10_STOCKDISPLAY) // Firmware compatible with stock GT 128x64 12pin LCD for the V41b #define LCD_PINS_RS H2_04_PIN // DOGLCD_CS #define LCD_PINS_D4 H2_05_PIN // DOGLCD_SCK #define LCD_PINS_EN H2_03_PIN // DOGLCD_MOSI diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index d3f30e0e3f7a..122c9b937c47 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -787,7 +787,7 @@ #elif MB(MKS_ROBIN_NANO_V1_3_F4) #include "stm32f4/pins_MKS_ROBIN_NANO_V1_3_F4.h" // STM32F4 env:mks_robin_nano_v1_3_f4 env:mks_robin_nano_v1_3_f4_usbmod #elif MB(MKS_EAGLE) - #include "stm32f4/pins_MKS_EAGLE.h" // STM32F4 env:mks_eagle + #include "stm32f4/pins_MKS_EAGLE.h" // STM32F4 env:mks_eagle env:mks_eagle_usb_flash_drive env:mks_eagle_usb_flash_drive_msc #elif MB(ARTILLERY_RUBY) #include "stm32f4/pins_ARTILLERY_RUBY.h" // STM32F4 env:Artillery_Ruby #elif MB(CREALITY_V24S1_301F4) diff --git a/Marlin/src/pins/ramps/pins_K8400.h b/Marlin/src/pins/ramps/pins_K8400.h index bcb145825b24..abcffe484d5e 100644 --- a/Marlin/src/pins/ramps/pins_K8400.h +++ b/Marlin/src/pins/ramps/pins_K8400.h @@ -53,6 +53,11 @@ #define X_STOP_PIN 3 #define Y_STOP_PIN 14 +// +// Fans +// +#define FAN0_PIN 8 + #if ANY(BLTOUCH, TOUCH_MI_PROBE) #define INVERTED_PROBE_STATE #endif @@ -60,7 +65,7 @@ #include "pins_3DRAG.h" // ... RAMPS // -// Heaters / Fans +// Heaters // #undef HEATER_1_PIN #define HEATER_1_PIN 11 diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 8ec33d1f72ef..9b9b3509d6e0 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -588,6 +588,8 @@ void CardReader::release() { flag.workDirIsRoot = true; nrItems = -1; SERIAL_ECHO_MSG(STR_SD_CARD_RELEASED); + + TERN_(NO_SD_DETECT, ui.refresh()); } /** diff --git a/buildroot/tests/FYSETC_S6 b/buildroot/tests/FYSETC_S6 index 6d67800d77ec..9043b7b6e383 100755 --- a/buildroot/tests/FYSETC_S6 +++ b/buildroot/tests/FYSETC_S6 @@ -14,11 +14,14 @@ opt_set Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2130 exec_test $1 $2 "FYSETC S6 Example" "$3" # -# Build with the default configurations with FYSETC TFT81050 +# Build with FTDI Eve Touch UI and some features # restore_configs -opt_set MOTHERBOARD BOARD_FYSETC_S6_V2_0 SERIAL_PORT 1 -opt_enable TOUCH_UI_FTDI_EVE LCD_FYSETC_TFT81050 S6_TFT_PINMAP +opt_set MOTHERBOARD BOARD_FYSETC_S6_V2_0 SERIAL_PORT 1 X_DRIVER_TYPE TMC2130 +opt_enable TOUCH_UI_FTDI_EVE LCD_FYSETC_TFT81050 S6_TFT_PINMAP LCD_LANGUAGE_2 SDSUPPORT CUSTOM_MENU_MAIN \ + FIX_MOUNTED_PROBE AUTO_BED_LEVELING_UBL Z_SAFE_HOMING \ + EEPROM_SETTINGS PRINTCOUNTER CALIBRATION_GCODE LIN_ADVANCE \ + FILAMENT_RUNOUT_SENSOR ADVANCED_PAUSE_FEATURE NOZZLE_PARK_FEATURE exec_test $1 $2 "FYSETC S6 2 with LCD FYSETC TFT81050" "$3" # cleanup diff --git a/ini/stm32f4.ini b/ini/stm32f4.ini index 20009c89439f..b8e989642c8f 100644 --- a/ini/stm32f4.ini +++ b/ini/stm32f4.ini @@ -480,7 +480,6 @@ upload_protocol = jlink # # MKS Robin Nano V3 with USB Flash Drive Support -# Currently, using a STM32duino fork, until USB Host get merged # [env:mks_robin_nano_v3_usb_flash_drive] extends = env:mks_robin_nano_v3 @@ -493,7 +492,6 @@ build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} # # MKS Robin Nano V3 with USB Flash Drive Support and Shared Media -# Currently, using a STM32duino fork, until USB Host and USB Device MSC get merged # [env:mks_robin_nano_v3_usb_flash_drive_msc] extends = env:mks_robin_nano_v3_usb_flash_drive @@ -510,7 +508,6 @@ board = marlin_STM32F407VET6_CCM # # MKS Robin Nano V3.1 with USB Flash Drive Support -# Currently, using a STM32duino fork, until USB Host get merged # [env:mks_robin_nano_v3_1_usb_flash_drive] extends = env:mks_robin_nano_v3_usb_flash_drive @@ -518,7 +515,6 @@ board = marlin_STM32F407VET6_CCM # # MKS Robin Nano V3.1 with USB Flash Drive Support and Shared Media -# Currently, using a STM32duino fork, until USB Host and USB Device MSC get merged # [env:mks_robin_nano_v3_1_usb_flash_drive_msc] extends = env:mks_robin_nano_v3_usb_flash_drive_msc @@ -543,7 +539,6 @@ upload_protocol = jlink # # MKS Eagle with USB Flash Drive Support -# Currently, using a STM32duino fork, until USB Host get merged # [env:mks_eagle_usb_flash_drive] extends = env:mks_eagle @@ -556,7 +551,6 @@ build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1.build_flags} # # MKS Eagle with USB Flash Drive Support and Shared Media -# Currently, using a STM32duino fork, until USB Host and USB Device MSC get merged # [env:mks_eagle_usb_flash_drive_msc] extends = env:mks_eagle_usb_flash_drive @@ -588,7 +582,6 @@ upload_protocol = jlink # # MKS Monster8 V1 / V2 (STM32F407VET6 ARM Cortex-M4) with USB Flash Drive Support -# Currently, using a STM32duino fork, until USB Host get merged # [env:mks_monster8_usb_flash_drive] extends = env:mks_monster8 @@ -601,7 +594,6 @@ build_flags = ${stm_flash_drive.build_flags} ${stm32f4_I2C1_CAN.build_flag # # MKS Monster8 V1 / V2 (STM32F407VET6 ARM Cortex-M4) with USB Flash Drive Support and Shared Media -# Currently, using a STM32duino fork, until USB Host and USB Device MSC get merged # [env:mks_monster8_usb_flash_drive_msc] extends = env:mks_monster8_usb_flash_drive