@ -2007,23 +2007,20 @@ bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void
ImGuiDataTypeTempStorage data_backup ;
ImGuiDataTypeTempStorage data_backup ;
memcpy ( & data_backup , p_data , type_info - > Size ) ;
memcpy ( & data_backup , p_data , type_info - > Size ) ;
if ( format = = NULL )
// Sanitize format
// For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf
char format_sanitized [ 32 ] ;
if ( data_type = = ImGuiDataType_Float | | data_type = = ImGuiDataType_Double )
format = type_info - > ScanFmt ;
format = type_info - > ScanFmt ;
if ( data_type = = ImGuiDataType_S32 | | data_type = = ImGuiDataType_U32 | | data_type = = ImGuiDataType_S64 | | data_type = = ImGuiDataType_U64 | | data_type = = ImGuiDataType_Float | | data_type = = ImGuiDataType_Double )
{
// For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf
if ( data_type = = ImGuiDataType_Float | | data_type = = ImGuiDataType_Double )
format = type_info - > ScanFmt ;
if ( sscanf ( buf , format , p_data ) < 1 )
return false ;
}
else
else
format = ImParseFormatSanitizeForScanning ( format , format_sanitized , IM_ARRAYSIZE ( format_sanitized ) ) ;
// Small types need a 32-bit buffer to receive the result from scanf()
int v32 = 0 ;
if ( sscanf ( buf , format , type_info - > Size > = 4 ? p_data : & v32 ) < 1 )
return false ;
if ( type_info - > Size < 4 )
{
{
// Small types need a 32-bit buffer to receive the result from scanf()
int v32 ;
if ( sscanf ( buf , format , & v32 ) < 1 )
return false ;
if ( data_type = = ImGuiDataType_S8 )
if ( data_type = = ImGuiDataType_S8 )
* ( ImS8 * ) p_data = ( ImS8 ) ImClamp ( v32 , ( int ) IM_S8_MIN , ( int ) IM_S8_MAX ) ;
* ( ImS8 * ) p_data = ( ImS8 ) ImClamp ( v32 , ( int ) IM_S8_MIN , ( int ) IM_S8_MAX ) ;
else if ( data_type = = ImGuiDataType_U8 )
else if ( data_type = = ImGuiDataType_U8 )
@ -2104,26 +2101,10 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
return ( decimal_precision < IM_ARRAYSIZE ( min_steps ) ) ? min_steps [ decimal_precision ] : ImPow ( 10.0f , ( float ) - decimal_precision ) ;
return ( decimal_precision < IM_ARRAYSIZE ( min_steps ) ) ? min_steps [ decimal_precision ] : ImPow ( 10.0f , ( float ) - decimal_precision ) ;
}
}
// Sanitize format
// - Zero terminate so extra characters after format (e.g. "%f123") don't confuse atof/atoi
// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi.
static void SanitizeFormatString ( const char * fmt , char * fmt_out , size_t fmt_out_size )
{
IM_UNUSED ( fmt_out_size ) ;
const char * fmt_end = ImParseFormatFindEnd ( fmt ) ;
IM_ASSERT ( ( size_t ) ( fmt_end - fmt + 1 ) < fmt_out_size ) ; // Format is too long, let us know if this happens to you!
while ( fmt < fmt_end )
{
char c = * ( fmt + + ) ;
if ( c ! = ' \' ' & & c ! = ' $ ' & & c ! = ' _ ' ) // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '.
* ( fmt_out + + ) = c ;
}
* fmt_out = 0 ; // Zero-terminate
}
template < typename TYPE >
template < typename TYPE >
TYPE ImGui : : RoundScalarWithFormatT ( const char * format , ImGuiDataType data_type , TYPE v )
TYPE ImGui : : RoundScalarWithFormatT ( const char * format , ImGuiDataType data_type , TYPE v )
{
{
IM_UNUSED ( data_type ) ;
IM_ASSERT ( data_type = = ImGuiDataType_Float | | data_type = = ImGuiDataType_Double ) ;
IM_ASSERT ( data_type = = ImGuiDataType_Float | | data_type = = ImGuiDataType_Double ) ;
const char * fmt_start = ImParseFormatFindStart ( format ) ;
const char * fmt_start = ImParseFormatFindStart ( format ) ;
if ( fmt_start [ 0 ] ! = ' % ' | | fmt_start [ 1 ] = = ' % ' ) // Don't apply if the value is not visible in the format string
if ( fmt_start [ 0 ] ! = ' % ' | | fmt_start [ 1 ] = = ' % ' ) // Don't apply if the value is not visible in the format string
@ -2131,7 +2112,7 @@ TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type,
// Sanitize format
// Sanitize format
char fmt_sanitized [ 32 ] ;
char fmt_sanitized [ 32 ] ;
SanitizeFormatStr ing( fmt_start , fmt_sanitized , IM_ARRAYSIZE ( fmt_sanitized ) ) ;
ImParseFormatSanitizeForPrint ing( fmt_start , fmt_sanitized , IM_ARRAYSIZE ( fmt_sanitized ) ) ;
fmt_start = fmt_sanitized ;
fmt_start = fmt_sanitized ;
// Format value with our rounding, and read back
// Format value with our rounding, and read back
@ -3205,6 +3186,8 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
// - ImParseFormatFindStart() [Internal]
// - ImParseFormatFindStart() [Internal]
// - ImParseFormatFindEnd() [Internal]
// - ImParseFormatFindEnd() [Internal]
// - ImParseFormatTrimDecorations() [Internal]
// - ImParseFormatTrimDecorations() [Internal]
// - ImParseFormatSanitizeForPrinting() [Internal]
// - ImParseFormatSanitizeForScanning() [Internal]
// - ImParseFormatPrecision() [Internal]
// - ImParseFormatPrecision() [Internal]
// - TempInputTextScalar() [Internal]
// - TempInputTextScalar() [Internal]
// - InputScalar()
// - InputScalar()
@ -3268,6 +3251,44 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_
return buf ;
return buf ;
}
}
// Sanitize format
// - Zero terminate so extra characters after format (e.g. "%f123") don't confuse atof/atoi
// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi.
void ImParseFormatSanitizeForPrinting ( const char * fmt_in , char * fmt_out , size_t fmt_out_size )
{
const char * fmt_end = ImParseFormatFindEnd ( fmt_in ) ;
IM_UNUSED ( fmt_out_size ) ;
IM_ASSERT ( ( size_t ) ( fmt_end - fmt_in + 1 ) < fmt_out_size ) ; // Format is too long, let us know if this happens to you!
while ( fmt_in < fmt_end )
{
char c = * fmt_in + + ;
if ( c ! = ' \' ' & & c ! = ' $ ' & & c ! = ' _ ' ) // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '.
* ( fmt_out + + ) = c ;
}
* fmt_out = 0 ; // Zero-terminate
}
// - For scanning we need to remove all width and precision fields "%3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d"
const char * ImParseFormatSanitizeForScanning ( const char * fmt_in , char * fmt_out , size_t fmt_out_size )
{
const char * fmt_end = ImParseFormatFindEnd ( fmt_in ) ;
const char * fmt_out_begin = fmt_out ;
IM_UNUSED ( fmt_out_size ) ;
IM_ASSERT ( ( size_t ) ( fmt_end - fmt_in + 1 ) < fmt_out_size ) ; // Format is too long, let us know if this happens to you!
bool has_type = false ;
while ( fmt_in < fmt_end )
{
char c = * fmt_in + + ;
if ( ! has_type & & ( ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' . ' ) )
continue ;
has_type | = ( ( c > = ' a ' & & c < = ' z ' ) | | ( c > = ' A ' & & c < = ' Z ' ) ) ; // Stop skipping digits
if ( c ! = ' \' ' & & c ! = ' $ ' & & c ! = ' _ ' ) // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '.
* ( fmt_out + + ) = c ;
}
* fmt_out = 0 ; // Zero-terminate
return fmt_out_begin ;
}
template < typename TYPE >
template < typename TYPE >
static const char * ImAtoi ( const char * src , TYPE * output )
static const char * ImAtoi ( const char * src , TYPE * output )
{
{
@ -3337,9 +3358,11 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
format = ImParseFormatTrimDecorations ( format , fmt_buf , IM_ARRAYSIZE ( fmt_buf ) ) ;
format = ImParseFormatTrimDecorations ( format , fmt_buf , IM_ARRAYSIZE ( fmt_buf ) ) ;
DataTypeFormatString ( data_buf , IM_ARRAYSIZE ( data_buf ) , data_type , p_data , format ) ;
DataTypeFormatString ( data_buf , IM_ARRAYSIZE ( data_buf ) , data_type , p_data , format ) ;
ImStrTrimBlanks ( data_buf ) ;
ImStrTrimBlanks ( data_buf ) ;
const bool is_floating_point = ( data_type = = ImGuiDataType_Float | | data_type = = ImGuiDataType_Double ) ;
const bool is_hexadecimal = ! is_floating_point & & format [ 0 ] & & toupper ( format [ strlen ( format ) - 1 ] ) = = ' X ' ;
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited ;
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited ;
flags | = ( ( data_type = = ImGuiDataType_Float | | data_type = = ImGuiDataType_Double ) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal ) ;
flags | = is_floating_point ? ImGuiInputTextFlags_CharsScientific : is_hexadecimal ? ImGuiInputTextFlags_CharsHexadecimal : ImGuiInputTextFlags_CharsDecimal ;
bool value_changed = false ;
bool value_changed = false ;
if ( TempInputText ( bb , id , label , data_buf , IM_ARRAYSIZE ( data_buf ) , flags ) )
if ( TempInputText ( bb , id , label , data_buf , IM_ARRAYSIZE ( data_buf ) , flags ) )
{
{
@ -3349,7 +3372,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
memcpy ( & data_backup , p_data , data_type_size ) ;
memcpy ( & data_backup , p_data , data_type_size ) ;
// Apply new value (or operations) then clamp
// Apply new value (or operations) then clamp
DataTypeApplyFromText ( data_buf , data_type , p_data , NULL ) ;
DataTypeApplyFromText ( data_buf , data_type , p_data , format ) ;
if ( p_clamp_min | | p_clamp_max )
if ( p_clamp_min | | p_clamp_max )
{
{
if ( p_clamp_min & & p_clamp_max & & DataTypeCompare ( data_type , p_clamp_min , p_clamp_max ) > 0 )
if ( p_clamp_min & & p_clamp_max & & DataTypeCompare ( data_type , p_clamp_min , p_clamp_max ) > 0 )