diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp index 52b657332..cd7e193fc 100644 --- a/Marlin/src/lcd/menu/menu.cpp +++ b/Marlin/src/lcd/menu/menu.cpp @@ -106,10 +106,7 @@ void lcd_goto_previous_menu_no_defer() { /////////// Common Menu Actions //////////// //////////////////////////////////////////// -void _menu_action_back() { lcd_goto_previous_menu(); } -void menu_action_submenu(screenFunc_t func) { lcd_save_previous_screen(); lcd_goto_screen(func); } -void menu_action_gcode(PGM_P pgcode) { enqueue_and_echo_commands_P(pgcode); } -void menu_action_function(screenFunc_t func) { (*func)(); } +void menu_item_gcode::action(PGM_P pgcode) { enqueue_and_echo_commands_P(pgcode); } //////////////////////////////////////////// /////////// Menu Editing Actions /////////// @@ -118,76 +115,71 @@ void menu_action_function(screenFunc_t func) { (*func)(); } /** * Functions for editing single values * - * The "DEFINE_MENU_EDIT_TYPE" macro generates the functions needed to edit a numerical value. + * The "DEFINE_MENU_EDIT_ITEM" macro generates the functions needed to edit a numerical value. * - * For example, DEFINE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1) expands into these functions: + * The prerequisite is that in the header the type was already declared: * - * bool _menu_edit_int3(); - * void menu_edit_int3(); // edit int16_t (interactively) - * void menu_edit_callback_int3(); // edit int16_t (interactively) with callback on completion - * void _menu_action_setting_edit_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue); - * void menu_action_setting_edit_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue); - * void menu_action_setting_edit_callback_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue, const screenFunc_t callback, const bool live); // edit int16_t with callback + * DECLARE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1) + * + * For example, DEFINE_MENU_EDIT_ITEM(int3) expands into these functions: + * + * bool menu_item_int3::_edit(); + * void menu_item_int3::edit(); // edit int16_t (interactively) + * void menu_item_int3::action_setting_edit(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue, const screenFunc_t callback = null, const bool live = false); * * You can then use one of the menu macros to present the edit interface: * MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999) * * This expands into a more primitive menu item: - * MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) + * MENU_ITEM_VARIANT(int3, _setting_edit, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) * * ...which calls: - * menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) + * menu_item_int3::action_setting_edit(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) */ -#define DEFINE_MENU_EDIT_TYPE(TYPE, NAME, STRFUNC, SCALE) \ - bool _menu_edit_ ## NAME() { \ - ENCODER_DIRECTION_NORMAL(); \ - if ((int32_t)encoderPosition < 0) encoderPosition = 0; \ - if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue; \ - if (lcdDrawUpdate) \ - lcd_implementation_drawedit(editLabel, STRFUNC(((TYPE)((int32_t)encoderPosition + minEditValue)) * (1.0f / SCALE))); \ - if (lcd_clicked || (liveEdit && lcdDrawUpdate)) { \ - TYPE value = ((TYPE)((int32_t)encoderPosition + minEditValue)) * (1.0f / SCALE); \ - if (editValue != NULL) *((TYPE*)editValue) = value; \ - if (callbackFunc && (liveEdit || lcd_clicked)) (*callbackFunc)(); \ - if (lcd_clicked) lcd_goto_previous_menu(); \ - } \ - return use_click(); \ - } \ - void menu_edit_ ## NAME() { _menu_edit_ ## NAME(); } \ - void _menu_action_setting_edit_ ## NAME(PGM_P const pstr, TYPE* const ptr, const TYPE minValue, const TYPE maxValue) { \ - lcd_save_previous_screen(); \ - lcd_refresh(); \ - \ - editLabel = pstr; \ - editValue = ptr; \ - minEditValue = minValue * SCALE; \ - maxEditValue = maxValue * SCALE - minEditValue; \ - encoderPosition = (*ptr) * SCALE - minEditValue; \ - } \ - void menu_action_setting_edit_callback_ ## NAME(PGM_P const pstr, TYPE * const ptr, const TYPE minValue, const TYPE maxValue, const screenFunc_t callback/*=NULL*/, const bool live/*=false*/) { \ - _menu_action_setting_edit_ ## NAME(pstr, ptr, minValue, maxValue); \ - currentScreen = menu_edit_ ## NAME; \ - callbackFunc = callback; \ - liveEdit = live; \ - } \ - typedef void NAME##_void - -DEFINE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1); -DEFINE_MENU_EDIT_TYPE(int16_t, int4, itostr4sign, 1); -DEFINE_MENU_EDIT_TYPE(uint8_t, int8, i8tostr3, 1); -DEFINE_MENU_EDIT_TYPE(float, float3, ftostr3, 1); -DEFINE_MENU_EDIT_TYPE(float, float52, ftostr52, 100); -DEFINE_MENU_EDIT_TYPE(float, float43, ftostr43sign, 1000); -DEFINE_MENU_EDIT_TYPE(float, float5, ftostr5rj, 0.01f); -DEFINE_MENU_EDIT_TYPE(float, float51, ftostr51sign, 10); -DEFINE_MENU_EDIT_TYPE(float, float52sign, ftostr52sign, 100); -DEFINE_MENU_EDIT_TYPE(float, float62, ftostr62rj, 100); -DEFINE_MENU_EDIT_TYPE(uint32_t, long5, ftostr5rj, 0.01f); - -void menu_action_setting_edit_bool(PGM_P pstr, bool* ptr) { UNUSED(pstr); *ptr ^= true; lcd_refresh(); } -void menu_action_setting_edit_callback_bool(PGM_P pstr, bool* ptr, screenFunc_t callback) { - menu_action_setting_edit_bool(pstr, ptr); - (*callback)(); +void menu_item_invariants::edit(strfunc_t strfunc, loadfunc_t loadfunc) { + ENCODER_DIRECTION_NORMAL(); + if ((int32_t)encoderPosition < 0) encoderPosition = 0; + if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue; + if (lcdDrawUpdate) + lcd_implementation_drawedit(editLabel, strfunc(encoderPosition + minEditValue)); + if (lcd_clicked || (liveEdit && lcdDrawUpdate)) { + if (editValue != NULL) loadfunc(editValue, encoderPosition + minEditValue); + if (callbackFunc && (liveEdit || lcd_clicked)) (*callbackFunc)(); + if (lcd_clicked) lcd_goto_previous_menu(); + lcd_clicked = false; + } +} + +void menu_item_invariants::init(PGM_P const el, void * const ev, const int32_t minv, const int32_t maxv, const uint32_t ep, const screenFunc_t cs, const screenFunc_t cb, const bool le) { + lcd_save_previous_screen(); + lcd_refresh(); + editLabel = el; + editValue = ev; + minEditValue = minv; + maxEditValue = maxv; + encoderPosition = ep; + currentScreen = cs; + callbackFunc = cb; + liveEdit = le; +} + +#define DEFINE_MENU_EDIT_ITEM(NAME) template class menu_item_template; + +DEFINE_MENU_EDIT_ITEM(int3); +DEFINE_MENU_EDIT_ITEM(int4); +DEFINE_MENU_EDIT_ITEM(int8); +DEFINE_MENU_EDIT_ITEM(float3); +DEFINE_MENU_EDIT_ITEM(float52); +DEFINE_MENU_EDIT_ITEM(float43); +DEFINE_MENU_EDIT_ITEM(float5); +DEFINE_MENU_EDIT_ITEM(float51); +DEFINE_MENU_EDIT_ITEM(float52sign); +DEFINE_MENU_EDIT_ITEM(float62); +DEFINE_MENU_EDIT_ITEM(long5); + +void menu_item_bool::action_setting_edit(PGM_P pstr, bool *ptr, screenFunc_t callback) { + UNUSED(pstr); *ptr ^= true; lcd_refresh(); + if (callback) (*callback)(); } //////////////////////////////////////////// diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index fbbb00392..cea49318a 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -37,6 +37,30 @@ bool printer_busy(); void lcd_completion_feedback(const bool good=true); void lcd_goto_previous_menu(); void lcd_goto_previous_menu_no_defer(); +void lcd_save_previous_screen(); + +//////////////////////////////////////////// +////////// Menu Item Numeric Types ///////// +//////////////////////////////////////////// + +#define DECLARE_MENU_EDIT_TYPE(TYPE, NAME, STRFUNC, SCALE) \ + struct NAME ## _item_info { \ + typedef TYPE type_t; \ + static constexpr float scale = SCALE; \ + static inline char* strfunc(const float value) { return STRFUNC((TYPE) value); } \ + }; + +DECLARE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1); +DECLARE_MENU_EDIT_TYPE(int16_t, int4, itostr4sign, 1); +DECLARE_MENU_EDIT_TYPE(uint8_t, int8, i8tostr3, 1); +DECLARE_MENU_EDIT_TYPE(float, float3, ftostr3, 1); +DECLARE_MENU_EDIT_TYPE(float, float52, ftostr52, 100); +DECLARE_MENU_EDIT_TYPE(float, float43, ftostr43sign, 1000); +DECLARE_MENU_EDIT_TYPE(float, float5, ftostr5rj, 0.01f); +DECLARE_MENU_EDIT_TYPE(float, float51, ftostr51sign, 10); +DECLARE_MENU_EDIT_TYPE(float, float52sign, ftostr52sign, 100); +DECLARE_MENU_EDIT_TYPE(float, float62, ftostr62rj, 100); +DECLARE_MENU_EDIT_TYPE(uint32_t, long5, ftostr5rj, 0.01f); //////////////////////////////////////////// ///////// Menu Item Draw Functions ///////// @@ -54,7 +78,7 @@ void lcd_implementation_drawedit(const char* const pstr, const char* const value #endif #if HAS_GRAPHICAL_LCD void _drawmenu_setting_edit_generic(const bool isSelected, const uint8_t row, const char* pstr, const char* const data, const bool pgm); - #define lcd_implementation_drawmenu_back(sel, row, pstr, dummy) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]) + #define lcd_implementation_drawmenu_back(sel, row, pstr) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]) #define lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, false) #define lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, true) #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, SRC) @@ -68,7 +92,7 @@ void lcd_implementation_drawedit(const char* const pstr, const char* const value void _lcd_zoffset_overlay_gfx(const float zvalue); #endif #else - #define lcd_implementation_drawmenu_back(sel, row, pstr, dummy) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_UPLEVEL_CHAR, LCD_UPLEVEL_CHAR) + #define lcd_implementation_drawmenu_back(sel, row, pstr) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_UPLEVEL_CHAR, LCD_UPLEVEL_CHAR) void lcd_implementation_drawmenu_setting_edit_generic(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data); void lcd_implementation_drawmenu_setting_edit_generic_P(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data); #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', SRC) @@ -90,75 +114,103 @@ void lcd_implementation_drawedit(const char* const pstr, const char* const value /////// Edit Setting Draw Functions //////// //////////////////////////////////////////// -#define DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(TYPE, NAME, STRFUNC) \ +#define _DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(TYPE, NAME, STRFUNC) \ FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE * const data, ...) { \ UNUSED(pstr2); \ DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(*(data))); \ } \ - FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_callback_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE * const data, ...) { \ - UNUSED(pstr2); \ - DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(*(data))); \ - } \ FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_accessor_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE (*pget)(), void (*pset)(TYPE), ...) { \ UNUSED(pstr2); UNUSED(pset); \ DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(pget())); \ } \ typedef void NAME##_void -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int16_t, int3, itostr3); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int16_t, int4, itostr4sign); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(uint8_t, int8, i8tostr3); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float3, ftostr3); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float52, ftostr52); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float43, ftostr43sign); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float5, ftostr5rj); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float51, ftostr51sign); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float52sign, ftostr52sign); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float62, ftostr62rj); -DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(uint32_t, long5, ftostr5rj); - -#define lcd_implementation_drawmenu_setting_edit_bool(sel, row, pstr, pstr2, data) DRAW_BOOL_SETTING(sel, row, pstr, data) -#define lcd_implementation_drawmenu_setting_edit_callback_bool(sel, row, pstr, pstr2, data, callback) DRAW_BOOL_SETTING(sel, row, pstr, data) -#define lcd_implementation_drawmenu_setting_edit_accessor_bool(sel, row, pstr, pstr2, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data) +#define DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(NAME) _DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(NAME ## _item_info::type_t, NAME, NAME ## _item_info::strfunc) + +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int3); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int4); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int8); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float3); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float52); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float43); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float5); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float51); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float52sign); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float62); +DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(long5); + +#define lcd_implementation_drawmenu_setting_edit_bool(sel, row, pstr, pstr2, data, ...) DRAW_BOOL_SETTING(sel, row, pstr, data) +#define lcd_implementation_drawmenu_setting_edit_accessor_bool(sel, row, pstr, pstr2, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data) //////////////////////////////////////////// /////////////// Menu Actions /////////////// //////////////////////////////////////////// -#define menu_action_back(dummy) _menu_action_back() -void _menu_action_back(); -void menu_action_submenu(screenFunc_t data); -void menu_action_function(menuAction_t data); -void menu_action_gcode(const char* pgcode); +class menu_item_back { + public: + static inline void action() { lcd_goto_previous_menu(); } +}; + +class menu_item_submenu { + public: + static inline void action(const screenFunc_t func) { lcd_save_previous_screen(); lcd_goto_screen(func); } +}; + +class menu_item_gcode { + public: + static void action(const char * const pgcode); +}; + +class menu_item_function { + public: + static inline void action(const menuAction_t func) { (*func)(); }; +}; //////////////////////////////////////////// /////////// Menu Editing Actions /////////// //////////////////////////////////////////// -#define DECLARE_MENU_EDIT_TYPE(TYPE, NAME) \ - bool _menu_edit_ ## NAME(); \ - void menu_edit_ ## NAME(); \ - void menu_edit_callback_ ## NAME(); \ - void _menu_action_setting_edit_ ## NAME(PGM_P const pstr, TYPE* const ptr, const TYPE minValue, const TYPE maxValue); \ - void menu_action_setting_edit_callback_ ## NAME(PGM_P const pstr, TYPE * const ptr, const TYPE minValue, const TYPE maxValue, const screenFunc_t callback=NULL, const bool live=false); \ - FORCE_INLINE void menu_action_setting_edit_ ## NAME(PGM_P const pstr, TYPE * const ptr, const TYPE minValue, const TYPE maxValue) { \ - menu_action_setting_edit_callback_ ## NAME(pstr, ptr, minValue, maxValue); \ - } \ - typedef void NAME##_void - -DECLARE_MENU_EDIT_TYPE(int16_t, int3); -DECLARE_MENU_EDIT_TYPE(int16_t, int4); -DECLARE_MENU_EDIT_TYPE(uint8_t, int8); -DECLARE_MENU_EDIT_TYPE(float, float3); -DECLARE_MENU_EDIT_TYPE(float, float52); -DECLARE_MENU_EDIT_TYPE(float, float43); -DECLARE_MENU_EDIT_TYPE(float, float5); -DECLARE_MENU_EDIT_TYPE(float, float51); -DECLARE_MENU_EDIT_TYPE(float, float52sign); -DECLARE_MENU_EDIT_TYPE(float, float62); -DECLARE_MENU_EDIT_TYPE(uint32_t, long5); - -void menu_action_setting_edit_bool(PGM_P pstr, bool* ptr); -void menu_action_setting_edit_callback_bool(PGM_P pstr, bool* ptr, screenFunc_t callbackFunc); +class menu_item_invariants { + protected: + typedef char* (*strfunc_t)(const int32_t); + typedef void (*loadfunc_t)(void *, const int32_t); + static void init(PGM_P const el, void * const ev, const int32_t minv, const int32_t maxv, const uint32_t ep, const screenFunc_t cs, const screenFunc_t cb, const bool le); + static void edit(strfunc_t, loadfunc_t); +}; + +template +class menu_item_template : menu_item_invariants { + private: + typedef typename NAME::type_t type_t; + inline static float unscale(const float value) {return value * (1.0f / NAME::scale);} + inline static float scale(const float value) {return value * NAME::scale;} + static void load(void *ptr, const int32_t value) {*((type_t*)ptr) = unscale(value);} + static char* to_string(const int32_t value) {return NAME::strfunc(unscale(value));} + public: + static void action_setting_edit(PGM_P const pstr, type_t * const ptr, const type_t minValue, const type_t maxValue, const screenFunc_t callback=NULL, const bool live=false) { + const int32_t minv = scale(minValue); + init(pstr, ptr, minv, int32_t(scale(maxValue)) - minv, int32_t(scale(*ptr)) - minv, edit, callback, live); + } + static void edit() {menu_item_invariants::edit(to_string, load);} +}; + +#define DECLARE_MENU_EDIT_ITEM(NAME) typedef menu_item_template menu_item_ ## NAME; + +DECLARE_MENU_EDIT_ITEM(int3); +DECLARE_MENU_EDIT_ITEM(int4); +DECLARE_MENU_EDIT_ITEM(int8); +DECLARE_MENU_EDIT_ITEM(float3); +DECLARE_MENU_EDIT_ITEM(float52); +DECLARE_MENU_EDIT_ITEM(float43); +DECLARE_MENU_EDIT_ITEM(float5); +DECLARE_MENU_EDIT_ITEM(float51); +DECLARE_MENU_EDIT_ITEM(float52sign); +DECLARE_MENU_EDIT_ITEM(float62); +DECLARE_MENU_EDIT_ITEM(long5); + +class menu_item_bool { + public: + static void action_setting_edit(PGM_P pstr, bool* ptr, const screenFunc_t callbackFunc=NULL); +}; //////////////////////////////////////////// //////////// Menu System Macros //////////// @@ -226,101 +278,80 @@ void menu_action_setting_edit_callback_bool(PGM_P pstr, bool* ptr, screenFunc_t extern bool encoderRateMultiplierEnabled; #define ENCODER_RATE_MULTIPLY(F) (encoderRateMultiplierEnabled = F) - + #define _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER) if(USE_MULTIPLIER) {encoderRateMultiplierEnabled = true; lastEncoderMovementMillis = 0;} //#define ENCODER_RATE_MULTIPLIER_DEBUG // If defined, output the encoder steps per second value - - /** - * MENU_MULTIPLIER_ITEM generates drawing and handling code for a multiplier menu item - */ - #define MENU_MULTIPLIER_ITEM(TYPE, LABEL, ...) do { \ - _MENU_ITEM_PART_1(TYPE, ## __VA_ARGS__); \ - encoderRateMultiplierEnabled = true; \ - lastEncoderMovementMillis = 0; \ - _MENU_ITEM_PART_2(TYPE, PSTR(LABEL), ## __VA_ARGS__); \ - }while(0) - #else // !ENCODER_RATE_MULTIPLIER #define ENCODER_RATE_MULTIPLY(F) NOOP + #define _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER) #endif // !ENCODER_RATE_MULTIPLIER /** * MENU_ITEM generates draw & handler code for a menu item, potentially calling: * - * lcd_implementation_drawmenu_[type](sel, row, label, arg3...) - * menu_action_[type](arg3...) + * lcd_implementation_drawmenu_[_variant](sel, row, label, arg3...) + * menu_item_::action[_variant](arg3...) * * Examples: * MENU_ITEM(back, MSG_WATCH, 0 [dummy parameter] ) * or * MENU_BACK(MSG_WATCH) * lcd_implementation_drawmenu_back(sel, row, PSTR(MSG_WATCH)) - * menu_action_back() + * menu_item_back::action() * * MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause) * lcd_implementation_drawmenu_function(sel, row, PSTR(MSG_PAUSE_PRINT), lcd_sdcard_pause) - * menu_action_function(lcd_sdcard_pause) + * menu_item_function::action(lcd_sdcard_pause) * * MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999) - * MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) * lcd_implementation_drawmenu_setting_edit_int3(sel, row, PSTR(MSG_SPEED), PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) - * menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) + * menu_item_int3::action_setting_edit(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) * */ -#define _MENU_ITEM_PART_1(TYPE, ...) \ - if (_menuLineNr == _thisItemNr) { \ - if (encoderLine == _thisItemNr && lcd_clicked) { \ - lcd_clicked = false - -#define _MENU_ITEM_PART_2(TYPE, PLABEL, ...) \ - menu_action_ ## TYPE(__VA_ARGS__); \ - if (screen_changed) return; \ - } \ - if (lcdDrawUpdate) \ - lcd_implementation_drawmenu_ ## TYPE(encoderLine == _thisItemNr, _lcdLineNr, PLABEL, ## __VA_ARGS__); \ - } \ - ++_thisItemNr - -#define MENU_ITEM_P(TYPE, PLABEL, ...) do { \ +#define _MENU_ITEM_VARIANT_P(TYPE, VARIANT, USE_MULTIPLIER, PLABEL, ...) do { \ _skipStatic = false; \ - _MENU_ITEM_PART_1(TYPE, ## __VA_ARGS__); \ - _MENU_ITEM_PART_2(TYPE, PLABEL, ## __VA_ARGS__); \ - }while(0) - -#define MENU_ITEM(TYPE, LABEL, ...) MENU_ITEM_P(TYPE, PSTR(LABEL), ## __VA_ARGS__) - -#define MENU_ITEM_ADDON_START(X) \ - if (lcdDrawUpdate && _menuLineNr == _thisItemNr - 1) { \ - SETCURSOR(X, _lcdLineNr) - -#define MENU_ITEM_ADDON_END() } (0) - -#define MENU_BACK(LABEL) MENU_ITEM(back, LABEL, 0) + if (_menuLineNr == _thisItemNr) { \ + if (encoderLine == _thisItemNr && lcd_clicked) { \ + lcd_clicked = false; \ + _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER); \ + menu_item_ ## TYPE ::action ## VARIANT(__VA_ARGS__); \ + if (screen_changed) return; \ + } \ + if (lcdDrawUpdate) \ + lcd_implementation_drawmenu ## VARIANT ## _ ## TYPE(encoderLine == _thisItemNr, _lcdLineNr, PLABEL, ## __VA_ARGS__); \ + } \ + ++_thisItemNr; \ +}while(0) // Used to print static text with no visible cursor. // Parameters: label [, bool center [, bool invert [, char *value] ] ] -#define STATIC_ITEM_P(LABEL, ...) do{ \ +#define STATIC_ITEM_P(PLABEL, ...) do{ \ if (_menuLineNr == _thisItemNr) { \ if (_skipStatic && encoderLine <= _thisItemNr) { \ encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ ++encoderLine; \ } \ if (lcdDrawUpdate) \ - lcd_implementation_drawmenu_static(_lcdLineNr, LABEL, ## __VA_ARGS__); \ + lcd_implementation_drawmenu_static(_lcdLineNr, PLABEL, ## __VA_ARGS__); \ } \ - ++_thisItemNr; } while(0) + ++_thisItemNr; \ +} while(0) + +#define MENU_ITEM_ADDON_START(X) \ + if (lcdDrawUpdate && _menuLineNr == _thisItemNr - 1) { \ + SETCURSOR(X, _lcdLineNr) + +#define MENU_ITEM_ADDON_END() } (0) #define STATIC_ITEM(LABEL, ...) STATIC_ITEM_P(PSTR(LABEL), ## __VA_ARGS__) +#define MENU_BACK(LABEL) MENU_ITEM(back, LABEL) #define MENU_ITEM_DUMMY() do { _thisItemNr++; }while(0) -#define MENU_ITEM_EDIT(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__) -#define MENU_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__) -#if ENABLED(ENCODER_RATE_MULTIPLIER) - #define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) MENU_MULTIPLIER_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__) - #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_MULTIPLIER_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__) -#else // !ENCODER_RATE_MULTIPLIER - #define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__) - #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__) -#endif // !ENCODER_RATE_MULTIPLIER +#define MENU_ITEM_P(TYPE, PLABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, , 0, PLABEL, ## __VA_ARGS__) +#define MENU_ITEM(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, , 0, PSTR(LABEL), ## __VA_ARGS__) +#define MENU_ITEM_EDIT(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 0, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) +#define MENU_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 0, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) +#define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 1, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) +#define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 1, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) //////////////////////////////////////////// /////////////// Menu Screens /////////////// diff --git a/Marlin/src/lcd/menu/menu_sdcard.cpp b/Marlin/src/lcd/menu/menu_sdcard.cpp index 1384ce515..94f195708 100644 --- a/Marlin/src/lcd/menu/menu_sdcard.cpp +++ b/Marlin/src/lcd/menu/menu_sdcard.cpp @@ -71,25 +71,31 @@ void lcd_sd_updir() { } #endif -void menu_action_sdfile(CardReader &theCard) { - #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) - last_sdfile_encoderPosition = encoderPosition; // Save which file was selected for later use - #endif - card.openAndPrintFile(theCard.filename); - lcd_return_to_status(); - lcd_reset_status(); -} - -void menu_action_sddirectory(CardReader &theCard) { - card.chdir(theCard.filename); - encoderTopLine = 0; - encoderPosition = 2 * ENCODER_STEPS_PER_MENU_ITEM; - screen_changed = true; - #if HAS_GRAPHICAL_LCD - drawing_screen = false; - #endif - lcd_refresh(); -} +class menu_item_sdfile { + public: + static void action(CardReader &theCard) { + #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) + last_sdfile_encoderPosition = encoderPosition; // Save which file was selected for later use + #endif + card.openAndPrintFile(theCard.filename); + lcd_return_to_status(); + lcd_reset_status(); + } +}; + +class menu_item_sddirectory { + public: + static void action(CardReader &theCard) { + card.chdir(theCard.filename); + encoderTopLine = 0; + encoderPosition = 2 * ENCODER_STEPS_PER_MENU_ITEM; + screen_changed = true; + #if HAS_GRAPHICAL_LCD + drawing_screen = false; + #endif + lcd_refresh(); + } +}; void menu_sdcard() { ENCODER_DIRECTION_MENUS(); diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h index 49cb32fdc..8216e3761 100644 --- a/Marlin/src/lcd/ultralcd.h +++ b/Marlin/src/lcd/ultralcd.h @@ -279,7 +279,7 @@ typedef void (*screenFunc_t)(); typedef void (*menuAction_t)(); extern screenFunc_t currentScreen; - void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder=0); + void lcd_goto_screen(const screenFunc_t screen, const uint32_t encoder=0); extern bool lcd_clicked, defer_return_to_status;