@ -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 < typename NAME >
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<NAME ## _item_info> 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_ < type > [ _variant ] ( sel , row , label , arg3 . . . )
* menu_item_ < type > : : 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_fun ction ( lcd_sdcard_pause )
* menu_item_function : : a ction ( 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(P LABEL, ...) 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 , P LABEL, # # __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 ///////////////