Skip to content

Commit f0f2afa

Browse files
committed
InputInt() doesn't cast to float, fix handling lost of precision with large integer. Added primitives to support more data types.
1 parent ebd25cf commit f0f2afa

File tree

1 file changed

+93
-38
lines changed

1 file changed

+93
-38
lines changed

imgui.cpp

Lines changed: 93 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,6 @@
389389
- input text: add ImGuiInputTextFlags_EnterToApply? (off #218)
390390
- input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200)
391391
- input text multi-line: line numbers? status bar? (follow up on #200)
392-
!- input number: large int not reliably supported because of int<>float conversions.
393392
- input number: optional range min/max for Input*() functions
394393
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
395394
- input number: use mouse wheel to step up/down
@@ -5829,9 +5828,57 @@ ImGuiID ImGui::GetID(const void* ptr_id)
58295828
return GImGui->CurrentWindow->GetID(ptr_id);
58305829
}
58315830

5831+
enum ImGuiDataType
5832+
{
5833+
ImGuiDataType_Int,
5834+
ImGuiDataType_Float
5835+
};
5836+
5837+
enum ImGuiDataTypeOp
5838+
{
5839+
ImGuiDataTypeOp_Add,
5840+
ImGuiDataTypeOp_Sub
5841+
};
5842+
5843+
static inline void DataTypeFormat(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size)
5844+
{
5845+
if (data_type == ImGuiDataType_Int)
5846+
{
5847+
if (decimal_precision < 0)
5848+
ImFormatString(buf, buf_size, "%d", *(int*)data_ptr);
5849+
else
5850+
ImFormatString(buf, buf_size, "%.*d", decimal_precision, *(int*)data_ptr);
5851+
}
5852+
else if (data_type == ImGuiDataType_Float)
5853+
{
5854+
if (decimal_precision < 0)
5855+
ImFormatString(buf, buf_size, "%f", *(float*)data_ptr); // Ideally we'd have a minimum decimal precision of 1 to visually denote that it is a float, while hiding non-significant digits?
5856+
else
5857+
ImFormatString(buf, buf_size, "%.*f", decimal_precision, *(float*)data_ptr);
5858+
}
5859+
}
5860+
5861+
static void DataTypeApplyOp(ImGuiDataType data_type, ImGuiDataTypeOp op, void* value1, const void* value2)// Store into value1
5862+
{
5863+
if (data_type == ImGuiDataType_Int)
5864+
{
5865+
if (op == ImGuiDataTypeOp_Add)
5866+
*(int*)value1 = *(int*)value1 + *(const int*)value2;
5867+
else if (op == ImGuiDataTypeOp_Sub)
5868+
*(int*)value1 = *(int*)value1 - *(const int*)value2;
5869+
}
5870+
else if (data_type == ImGuiDataType_Float)
5871+
{
5872+
if (op == ImGuiDataTypeOp_Add)
5873+
*(float*)value1 = *(float*)value1 + *(const float*)value2;
5874+
else if (op == ImGuiDataTypeOp_Sub)
5875+
*(float*)value1 = *(float*)value1 - *(const float*)value2;
5876+
}
5877+
}
5878+
58325879
// User can input math operators (e.g. +100) to edit a numerical values.
58335880
// NB: only call right after InputText because we are using its InitialValue storage
5834-
static void InputTextApplyArithmeticOp(const char* buf, float *v)
5881+
static void DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr)
58355882
{
58365883
while (ImCharIsSpace(*buf))
58375884
buf++;
@@ -5852,27 +5899,38 @@ static void InputTextApplyArithmeticOp(const char* buf, float *v)
58525899
if (!buf[0])
58535900
return;
58545901

5855-
float ref_v = *v;
5856-
if (op)
5857-
if (sscanf(GImGui->InputTextState.InitialText.begin(), "%f", &ref_v) < 1)
5858-
return;
5902+
if (data_type == ImGuiDataType_Int)
5903+
{
5904+
int* v = (int*)data_ptr;
5905+
int ref_v = *v;
5906+
if (op && sscanf(initial_value_buf, "%d", &ref_v) < 1)
5907+
return;
58595908

5860-
float op_v = 0.0f;
5861-
if (sscanf(buf, "%f", &op_v) < 1)
5862-
return;
5909+
// Store operand in a double so we can store a big integer (e.g. 2000000003) reliably as well as fractional value for multipliers (*1.1)
5910+
double op_v = 0.0f;
5911+
if (sscanf(buf, "%lf", &op_v) < 1)
5912+
return;
58635913

5864-
if (op == '+')
5865-
*v = ref_v + op_v; // add (uses "+-" to substract)
5866-
else if (op == '*')
5867-
*v = ref_v * op_v; // multiply
5868-
else if (op == '/')
5914+
if (op == '+') { *v = (int)(ref_v + op_v); } // Add (use "+-" to subtract)
5915+
else if (op == '*') { *v = (int)(ref_v * op_v); } // Multiply
5916+
else if (op == '/') { if (op_v != 0.0f) *v = (int)(ref_v / op_v); } // Divide
5917+
else { *v = (int)op_v; } // Assign constant
5918+
}
5919+
else if (data_type == ImGuiDataType_Float)
58695920
{
5870-
if (op_v == 0.0f) // divide
5921+
float* v = (float*)data_ptr;
5922+
float ref_v = *v;
5923+
if (op && sscanf(initial_value_buf, "%f", &ref_v) < 1)
5924+
return;
5925+
float op_v = 0.0f;
5926+
if (sscanf(buf, "%f", &op_v) < 1)
58715927
return;
5872-
*v = ref_v / op_v;
5928+
5929+
if (op == '+') { *v = ref_v + op_v; } // Add (use "+-" to subtract)
5930+
else if (op == '*') { *v = ref_v * op_v; } // Multiply
5931+
else if (op == '/') { if (op_v != 0.0f) *v = ref_v / op_v; } // Divide
5932+
else { *v = op_v; } // Assign constant
58735933
}
5874-
else
5875-
*v = op_v; // Constant
58765934
}
58775935

58785936
// Create text input in place of a slider (when CTRL+Clicking on slider)
@@ -5904,9 +5962,7 @@ static bool InputFloatReplaceWidget(const ImRect& aabb, const char* label, float
59045962
g.ScalarAsInputTextId = 0;
59055963
}
59065964
if (value_changed)
5907-
{
5908-
InputTextApplyArithmeticOp(text_buf, v);
5909-
}
5965+
DataTypeApplyOpFromText(text_buf, GImGui->InputTextState.InitialText.begin(), ImGuiDataType_Float, v);
59105966
return value_changed;
59115967
}
59125968

@@ -7608,7 +7664,7 @@ bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, co
76087664
return ret;
76097665
}
76107666

7611-
bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
7667+
static bool InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, int decimal_precision, ImGuiInputTextFlags extra_flags)
76127668
{
76137669
ImGuiState& g = *GImGui;
76147670
ImGuiWindow* window = GetCurrentWindow();
@@ -7617,42 +7673,40 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast,
76177673

76187674
const ImGuiStyle& style = g.Style;
76197675
const float w = ImGui::CalcItemWidth();
7620-
const ImVec2 label_size = CalcTextSize(label, NULL, true);
7676+
const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
76217677
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f);
76227678

76237679
ImGui::BeginGroup();
76247680
ImGui::PushID(label);
76257681
const ImVec2 button_sz = ImVec2(g.FontSize, g.FontSize) + style.FramePadding * 2;
7626-
if (step > 0.0f)
7682+
if (step_ptr)
76277683
ImGui::PushItemWidth(ImMax(1.0f, w - (button_sz.x + style.ItemInnerSpacing.x)*2));
76287684

76297685
char buf[64];
7630-
if (decimal_precision < 0)
7631-
ImFormatString(buf, IM_ARRAYSIZE(buf), "%f", *v); // Ideally we'd have a minimum decimal precision of 1 to visually denote that it is a float, while hiding non-significant digits?
7632-
else
7633-
ImFormatString(buf, IM_ARRAYSIZE(buf), "%.*f", decimal_precision, *v);
7686+
DataTypeFormat(data_type, data_ptr, decimal_precision, buf, IM_ARRAYSIZE(buf));
7687+
76347688
bool value_changed = false;
76357689
const ImGuiInputTextFlags flags = extra_flags | (ImGuiInputTextFlags_CharsDecimal|ImGuiInputTextFlags_AutoSelectAll);
76367690
if (ImGui::InputText("", buf, IM_ARRAYSIZE(buf), flags))
76377691
{
7638-
InputTextApplyArithmeticOp(buf, v);
7692+
DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr);
76397693
value_changed = true;
76407694
}
76417695

76427696
// Step buttons
7643-
if (step > 0.0f)
7697+
if (step_ptr)
76447698
{
76457699
ImGui::PopItemWidth();
76467700
ImGui::SameLine(0, style.ItemInnerSpacing.x);
76477701
if (ButtonEx("-", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
76487702
{
7649-
*v -= g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step;
7703+
DataTypeApplyOp(data_type, ImGuiDataTypeOp_Sub, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
76507704
value_changed = true;
76517705
}
76527706
ImGui::SameLine(0, style.ItemInnerSpacing.x);
76537707
if (ButtonEx("+", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
76547708
{
7655-
*v += g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step;
7709+
DataTypeApplyOp(data_type, ImGuiDataTypeOp_Add, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
76567710
value_changed = true;
76577711
}
76587712
}
@@ -7669,13 +7723,14 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast,
76697723
return value_changed;
76707724
}
76717725

7672-
bool ImGui::InputInt(const char* label, int *v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
7726+
bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
76737727
{
7674-
float f = (float)*v;
7675-
const bool value_changed = ImGui::InputFloat(label, &f, (float)step, (float)step_fast, 0, extra_flags);
7676-
if (value_changed)
7677-
*v = (int)f;
7678-
return value_changed;
7728+
return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), decimal_precision, extra_flags);
7729+
}
7730+
7731+
bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
7732+
{
7733+
return InputScalarEx(label, ImGuiDataType_Int, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), 0, extra_flags);
76797734
}
76807735

76817736
static bool InputFloatN(const char* label, float* v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags)

0 commit comments

Comments
 (0)