From 99c29cd9242387176a6be0f70acace28ac27ec03 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 24 Apr 2025 11:20:15 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8=20Simplified=20Media=20Menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/feature/password/password.cpp | 2 +- Marlin/src/feature/password/password.h | 2 + Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp | 8 +- Marlin/src/lcd/language/language_en.h | 9 +- Marlin/src/lcd/marlinui.h | 6 +- Marlin/src/lcd/menu/menu.h | 3 +- Marlin/src/lcd/menu/menu_item.h | 3 + Marlin/src/lcd/menu/menu_main.cpp | 154 +++++++++++++++----- Marlin/src/lcd/menu/menu_media.cpp | 46 +++--- Marlin/src/lcd/menu/menu_password.cpp | 12 +- Marlin/src/lcd/tft/ui_color_ui.cpp | 2 +- 11 files changed, 171 insertions(+), 76 deletions(-) diff --git a/Marlin/src/feature/password/password.cpp b/Marlin/src/feature/password/password.cpp index 1d376cc586..d36b3edd09 100644 --- a/Marlin/src/feature/password/password.cpp +++ b/Marlin/src/feature/password/password.cpp @@ -36,7 +36,7 @@ uint32_t Password::value, Password::value_entry; // // Authenticate user with password. -// Called from Setup, after SD Prinitng Stops/Aborts, and M510 +// Called from Setup, after SD Printing Stops/Aborts, and M510 // void Password::lock_machine() { is_locked = true; diff --git a/Marlin/src/feature/password/password.h b/Marlin/src/feature/password/password.h index 208765b212..0f8bc28bd8 100644 --- a/Marlin/src/feature/password/password.h +++ b/Marlin/src/feature/password/password.h @@ -37,6 +37,8 @@ public: static void access_menu_password(); static void authentication_done(); static void media_gatekeeper(); + static void media_gatekeeper_sd(); + static void media_gatekeeper_usb(); private: static void authenticate_user(const screenFunc_t, const screenFunc_t); diff --git a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp index 4ac012ba93..d772447551 100644 --- a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp +++ b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp @@ -175,9 +175,9 @@ void TFTGLCD::clr_screen() { SPI_SEND_ONE(CLR_SCREEN); WRITE(TFTGLCD_CS, HIGH); #else - Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); //set I2C device address + Wire.beginTransmission(uint8_t(LCD_I2C_ADDRESS)); // Transmit to LCD via I2C Wire.write(CLR_SCREEN); - Wire.endTransmission(); //transmit data + Wire.endTransmission(); // Send the data #endif } @@ -378,10 +378,6 @@ void MarlinUI::clear_for_drawing() { clear_lcd(); } void MarlinUI::_set_contrast() { lcd.setContrast(contrast); } #endif -#if !IS_TFTGLCD_PANEL - void lcd_moveto(const uint8_t col, const uint8_t row) { lcd.setCursor(col, row); } -#endif - static void center_text(FSTR_P const fstart, const uint8_t y) { const uint8_t len = utf8_strlen(fstart); lcd_moveto(len < LCD_WIDTH ? (LCD_WIDTH - len) / 2 : 0, y); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 7ea17d5bb3..5ed5b24635 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -574,10 +574,8 @@ namespace LanguageNarrow_en { LSTR MSG_CANCEL_OBJECT = _UxGT("Cancel Obj"); LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancel Obj {"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Continue Job"); - LSTR MSG_MEDIA_MENU = MEDIA_TYPE_EN _UxGT(" Print"); LSTR MSG_TURN_OFF = _UxGT("Turn off now"); LSTR MSG_END_LOOPS = _UxGT("End Loops"); - LSTR MSG_NO_MEDIA = _UxGT("No ") MEDIA_TYPE_EN; LSTR MSG_DWELL = _UxGT("Sleep..."); LSTR MSG_USERWAIT = _UxGT("Click to Resume..."); LSTR MSG_PRINT_PAUSED = _UxGT("Print Paused"); @@ -641,6 +639,10 @@ namespace LanguageNarrow_en { LSTR MSG_RUN_AUTOFILES = _UxGT("Run Autofiles"); LSTR MSG_RUN_AUTOFILES_SD = _UxGT("Run SD Autofiles"); LSTR MSG_RUN_AUTOFILES_USB = _UxGT("Run USB Autofiles"); + LSTR MSG_MEDIA_MENU = MEDIA_TYPE_EN _UxGT(" Print"); + LSTR MSG_MEDIA_MENU_SD = _UxGT("Select from SD"); + LSTR MSG_MEDIA_MENU_USB = _UxGT("Select from USB"); + LSTR MSG_NO_MEDIA = _UxGT("No ") MEDIA_TYPE_EN _UxGT(" Detected"); LSTR MSG_ZPROBE_OUT = _UxGT("Z Probe Past Bed"); LSTR MSG_SKEW_FACTOR = _UxGT("Skew Factor"); @@ -1130,6 +1132,9 @@ namespace LanguageWide_en { LSTR MSG_CANCEL_OBJECT_N = _UxGT("Cancel Object {"); LSTR MSG_CONTINUE_PRINT_JOB = _UxGT("Continue Print Job"); LSTR MSG_MEDIA_MENU = _UxGT("Select from ") MEDIA_TYPE_EN; + LSTR MSG_MEDIA_MENU_SD = _UxGT("Select from SD Card"); + LSTR MSG_MEDIA_MENU_USB = _UxGT("Select from USB Drive"); + LSTR MSG_NO_MEDIA = _UxGT("No ") MEDIA_TYPE_EN _UxGT(" Found"); LSTR MSG_TURN_OFF = _UxGT("Turn off the printer"); LSTR MSG_END_LOOPS = _UxGT("End Repeat Loops"); LSTR MSG_MEDIA_NOT_INSERTED = _UxGT("No media inserted."); // ProUI diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 076fc63f2a..a610796ebc 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -255,7 +255,9 @@ public: #endif #if HAS_MEDIA - #define MEDIA_MENU_GATEWAY TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_media) + #define MEDIA_MENU_GATEWAY TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_file_selector) + #define MEDIA_MENU_GATEWAY_SD TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper_sd, menu_file_selector_sd) + #define MEDIA_MENU_GATEWAY_USB TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper_usb, menu_file_selector_usb) static void media_changed(const MediaPresence old_stat, const MediaPresence stat); #endif @@ -864,7 +866,7 @@ public: TERN_(REVERSE_SELECT_DIRECTION, encoderDirection = -(ENCODERBASE)); } - #else + #else // !HAS_ENCODER_ACTION static void update_buttons() {} static bool hw_button_pressed() { return false; } diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index b7861655e2..47f5a312eb 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -212,7 +212,8 @@ void menu_move(); #if HAS_MEDIA void menu_file_selector(); - void menu_media(); + void menu_file_selector_sd(); + void menu_file_selector_usb(); #endif //////////////////////////////////////////// diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h index af4558cefc..d79956aea7 100644 --- a/Marlin/src/lcd/menu/menu_item.h +++ b/Marlin/src/lcd/menu/menu_item.h @@ -226,6 +226,9 @@ class MenuItem_bool : public MenuEditItemBase { * should be done before the menu loop (START_MENU / START_SCREEN). */ +// CAUTION! When using menu items in a lambda or sub-function always use: +#define INJECT_MENU_ITEMS(FN) { FN; if (ui.screen_changed) return; } + /** * SCREEN_OR_MENU_LOOP generates header code for a screen or menu * diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index 7e2d458e41..04bbc41074 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -237,8 +237,8 @@ void menu_configuration(); void menu_main() { const bool busy = printingIsActive(); #if HAS_MEDIA - const bool card_detected = card.isMounted(), - card_open = card_detected && card.isFileOpen(); + const bool card_is_mounted = card.isMounted(), + card_open = card_is_mounted && card.isFileOpen(); #endif START_MENU(); @@ -248,45 +248,123 @@ void menu_main() { #define MEDIA_MENU_AT_TOP #endif - auto media_menus = [&]{ - #if HAS_MEDIA - if (card_detected) { - if (!card_open) { - #if ENABLED(MENU_ADDAUTOSTART) - ACTION_ITEM(MSG_RUN_AUTOFILES, card.autofile_begin); // Run Auto Files - #endif + // Show "Attach" for drives that don't auto-detect media (yet) + //#define ATTACH_WITHOUT_INSERT_SD + #define ATTACH_WITHOUT_INSERT_USB - #if HAS_SD_DETECT - GCODES_ITEM(MSG_CHANGE_MEDIA, F("M21" TERN_(HAS_MULTI_VOLUME, "S"))); // M21 Change Media - #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_USB, F("M21U")); // M21 Attach USB Media - #endif - #else // - or - - ACTION_ITEM(MSG_RELEASE_MEDIA, []{ // M22 Release Media - queue.inject(F("M22")); - #if ENABLED(TFT_COLOR_UI) - // Menu display issue on item removal with multi language selection menu - if (encoderTopLine > 0) encoderTopLine--; - ui.refresh(); - #endif - }); - #endif - SUBMENU(MSG_MEDIA_MENU, MEDIA_MENU_GATEWAY); // Media Menu (or Password First) - } + // Show all "inserted" drives and mount as-needed + #define SHOW_UNMOUNTED_DRIVES + + /** + * Previously: + * - The "selected" media is mounted? + * - [Run Auto Files] + * - HAS_SD_DETECT: + * - [Change Media] = M21 / M21S + * - HAS_MULTI_VOLUME? + * - [Attach USB Drive] = M21U + * - ELSE: + * - [Release Media] = M22 + * - [Select from Media] (or Password Gateway) > + * + * - The "selected" media is not mounted? + * - HAS_SD_DETECT? + * - [No Media] (does nothing) + * - HAS_MULTI_VOLUME? + * - [Attach SD Card] = M21S + * - [Attach USB Drive] = M21U + * - ELSE: + * - [Attach Media] = M21 + * + * Updated: + * - Something is mounted? + * - [Run SD/USB Autofiles] + * - [Release SD/USB] = M22 + * - [Select from SD/USB] (or Password Gateway) > + * + * - Something is inserted and SHOW_UNMOUNTED_DRIVES? + * - [Select from SD/USB] (or Password Gateway) > + * + * - The "selected" Card is NOT DETECTED? + * - Trust all media detect methods? + * - [No Media] (does nothing) + * - HAS_MULTI_VOLUME? + * - [Attach SD Card] = M21S + * - [Attach USB Drive] = M21U + * - ELSE: + * - [Attach SD Card/USB Drive] = M21 + * + * Ideal: + * - Password Gateway? + * - Use gateway passthroughs for all SD/USB Drive menu items... + * - [Run SD Autofiles] + * - [Run USB Autofiles] + * - [Select from SD Card] (or Password Gateway) > + * - [Select from USB Drive] (or Password Gateway) > + * - [Eject SD Card/USB Drive] + */ + auto media_menu_items = [&]{ + #if HAS_MEDIA + if (card_open) return; + + if (card_is_mounted) { + #if ENABLED(MENU_ADDAUTOSTART) + // [Run AutoFiles] for mounted drive(s) + if (card.isSDCardMounted()) + ACTION_ITEM(MSG_RUN_AUTOFILES_SD, card.autofile_begin); + if (card.isFlashDriveMounted()) + ACTION_ITEM(MSG_RUN_AUTOFILES_USB, card.autofile_begin); + #endif + + #if ENABLED(TFT_COLOR_UI) + // Menu display issue on item removal with multi language selection menu + #define M22_ITEM(T) do{ \ + ACTION_ITEM(T, []{ \ + queue.inject(F("M22")); encoderTopLine -= (encoderTopLine > 0); ui.refresh(); \ + }); \ + }while(0) + #else + #define M22_ITEM(T) GCODES_ITEM(T, F("M22")) + #endif + + // [Release Media] for mounted drive(s) + if (card.isSDCardMounted()) + M22_ITEM(MSG_RELEASE_SD); + if (card.isFlashDriveMounted()) + M22_ITEM(MSG_RELEASE_USB); + + // [Select from SD/USB] (or Password First) + if (card.isSDCardMounted()) + SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY); + else if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isSDCardInserted())) + SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY_SD); + if (card.isFlashDriveMounted()) + SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY); + else if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isFlashDriveInserted())) + SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY_USB); } else { - #if HAS_SD_DETECT - ACTION_ITEM(MSG_NO_MEDIA, nullptr); // "No Media" - #else - #if HAS_MULTI_VOLUME - GCODES_ITEM(MSG_ATTACH_SD, F("M21S")); // M21S Attach SD Card - GCODES_ITEM(MSG_ATTACH_USB, F("M21U")); // M21U Attach USB Media + // NOTE: If the SD Card has no SD_DETECT it will always appear to be "inserted" + const bool att_sd = ENABLED(ATTACH_WITHOUT_INSERT_SD) || card.isSDCardInserted(), + att_usb = ENABLED(ATTACH_WITHOUT_INSERT_USB) || card.isFlashDriveInserted(); + if (!att_sd && !att_usb) { + ACTION_ITEM(MSG_NO_MEDIA, nullptr); // [No Media] + } + else { + #if ALL(HAS_MULTI_VOLUME, SHOW_UNMOUNTED_DRIVES) + // [Select from SD/USB] (or Password First) + if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isSDCardInserted())) + SUBMENU(MSG_MEDIA_MENU_SD, MEDIA_MENU_GATEWAY_SD); + if (TERN0(SHOW_UNMOUNTED_DRIVES, card.isFlashDriveInserted())) + SUBMENU(MSG_MEDIA_MENU_USB, MEDIA_MENU_GATEWAY_USB); #else - GCODES_ITEM(MSG_ATTACH_MEDIA, F("M21")); // M21 Attach Media + #define M21(T) F("M21" TERN_(HAS_MULTI_VOLUME, T)) + if (att_sd) GCODES_ITEM(MSG_ATTACH_SD, M21("S")); // M21 S - [Attach SD Card] + if (att_usb) GCODES_ITEM(MSG_ATTACH_USB, M21("U")); // M21 U - [Attach USB Drive] #endif - #endif + } } - #endif + #endif // HAS_MEDIA }; if (busy) { @@ -317,7 +395,9 @@ void menu_main() { else { // SD Card / Flash Drive - TERN_(MEDIA_MENU_AT_TOP, media_menus()); + #if ENABLED(MEDIA_MENU_AT_TOP) + INJECT_MENU_ITEMS(media_menu_items()); + #endif if (TERN0(MACHINE_CAN_PAUSE, printingIsPaused())) ACTION_ITEM(MSG_RESUME_PRINT, ui.resume_print); @@ -407,7 +487,7 @@ void menu_main() { // SD Card / Flash Drive #if DISABLED(MEDIA_MENU_AT_TOP) - if (!busy) media_menus(); + if (!busy) INJECT_MENU_ITEMS(media_menu_items()); #endif #if HAS_SERVICE_INTERVALS diff --git a/Marlin/src/lcd/menu/menu_media.cpp b/Marlin/src/lcd/menu/menu_media.cpp index 8747685fe5..f4c409c4a3 100644 --- a/Marlin/src/lcd/menu/menu_media.cpp +++ b/Marlin/src/lcd/menu/menu_media.cpp @@ -101,29 +101,27 @@ class MenuItem_sdfolder : public MenuItem_sdbase { } }; -#if HAS_MULTI_VOLUME - void menu_media_select() { - START_MENU(); - BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); - #if HAS_SDCARD - ACTION_ITEM(MSG_SD_CARD, []{ card.selectMediaSDCard(); card.mount(); ui.goto_screen(menu_file_selector); }); - #endif - #if HAS_USB_FLASH_DRIVE - ACTION_ITEM(MSG_USB_DISK, []{ card.selectMediaFlashDrive(); card.mount(); ui.goto_screen(menu_file_selector); }); - #endif - END_MENU(); +// Shortcut menu items to go directly to inserted — not necessarily mounted — drives +void menu_file_selector_sd() { + if (!card.isSDCardSelected()) { + card.release(); + card.selectMediaSDCard(); } -#endif - -/** - * "Select From Media" menu item. Depending on single or multiple drives: - * - menu_file_selector - List files on the current media - * - menu_media_select - Select one of the attached drives, then go to the file list - */ -void menu_media() { - ui.goto_screen(TERN(HAS_MULTI_VOLUME, menu_media_select, menu_file_selector)); + if (!card.isSDCardMounted()) card.mount(); + ui.goto_screen(menu_file_selector); } +// Shortcut menu items to go directly to inserted — not necessarily mounted — drives +void menu_file_selector_usb() { + if (!card.isFlashDriveSelected()) { + card.release(); + card.selectMediaFlashDrive(); + } + if (!card.isFlashDriveMounted()) card.mount(); + ui.goto_screen(menu_file_selector); +} + +// Shortcut menu items to go directly to inserted — not necessarily mounted — drives void menu_file_selector() { ui.encoder_direction_menus(); @@ -135,11 +133,9 @@ void menu_file_selector() { #endif START_MENU(); - #if HAS_MULTI_VOLUME - ACTION_ITEM(MSG_BACK, []{ ui.goto_screen(menu_media_select); }); - #else - BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); - #endif + + BACK_ITEM_F(TERN1(BROWSE_MEDIA_ON_INSERT, screen_history_depth) ? GET_TEXT_F(MSG_MAIN_MENU) : GET_TEXT_F(MSG_BACK)); + if (card.flag.workDirIsRoot) { #if !HAS_SD_DETECT ACTION_ITEM(MSG_REFRESH, []{ encoderTopLine = 0; card.mount(); }); diff --git a/Marlin/src/lcd/menu/menu_password.cpp b/Marlin/src/lcd/menu/menu_password.cpp index 33d4231cd5..5e3db846ac 100644 --- a/Marlin/src/lcd/menu/menu_password.cpp +++ b/Marlin/src/lcd/menu/menu_password.cpp @@ -140,8 +140,18 @@ void Password::access_menu_password() { #if ENABLED(PASSWORD_ON_SD_PRINT_MENU) void Password::media_gatekeeper() { - authenticate_user(menu_media, menu_main); + authenticate_user(menu_file_selector, menu_main); } + #if HAS_SDCARD + void Password::media_gatekeeper_sd() { + authenticate_user(menu_file_selector_sd, menu_main); + } + #endif + #if HAS_USB_FLASH_DRIVE + void Password::media_gatekeeper_usb() { + authenticate_user(menu_file_selector_usb, menu_main); + } + #endif #endif void Password::start_over() { diff --git a/Marlin/src/lcd/tft/ui_color_ui.cpp b/Marlin/src/lcd/tft/ui_color_ui.cpp index 8186650070..6c90cb6c36 100644 --- a/Marlin/src/lcd/tft/ui_color_ui.cpp +++ b/Marlin/src/lcd/tft/ui_color_ui.cpp @@ -323,7 +323,7 @@ void MarlinUI::draw_status_screen() { if (cm && pa) add_control(SDCARD_ICON_X, SDCARD_ICON_Y, STOP, imgCancel, true, COLOR_CONTROL_CANCEL); else - add_control(SDCARD_ICON_X, SDCARD_ICON_Y, menu_media, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, COLOR_CONTROL_DISABLED); + add_control(SDCARD_ICON_X, SDCARD_ICON_Y, menu_file_selector, imgSD, cm && !pa, COLOR_CONTROL_ENABLED, COLOR_CONTROL_DISABLED); #endif #endif