DragScalar, InputScalar, SliderScalar: Added support for u8/s8/u16/s16 data types. We are reusing function instances for larger types to reduce code size. (#643, #320, #708, #1011)
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index caa7852..3501f90 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -42,6 +42,8 @@
Other Changes:
- Nav: Fixed a tap on AltGR (e.g. German keyboard) from navigation to the menu layer.
+- DragScalar, InputScalar, SliderScalar: Added support for u8/s8/u16/s16 data types.
+ We are reusing function instances for larger types to reduce code size. (#643, #320, #708, #1011)
- InputInt, InputFloat, InputScalar: Fix to keep the label of the +/- buttons centered when
style.FramePadding.x is abnormally larger than style.FramePadding.y. Since the buttons are
meant to be square (to align with e.g. color button) we always use FramePadding.y. (#2367)
diff --git a/imgui.h b/imgui.h
index 180db98..63132d4 100644
--- a/imgui.h
+++ b/imgui.h
@@ -150,6 +150,10 @@
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data);
// Scalar data types
+typedef char ImS8; // 8-bit signed integer == char
+typedef unsigned char ImU8; // 8-bit unsigned integer
+typedef short ImS16; // 16-bit signed integer
+typedef unsigned short ImU16; // 16-bit unsigned integer
typedef signed int ImS32; // 32-bit signed integer == int
typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors)
#if defined(_MSC_VER) && !defined(__clang__)
@@ -884,10 +888,14 @@
// A primary data type
enum ImGuiDataType_
{
+ ImGuiDataType_S8, // char
+ ImGuiDataType_U8, // unsigned char
+ ImGuiDataType_S16, // short
+ ImGuiDataType_U16, // unsigned short
ImGuiDataType_S32, // int
ImGuiDataType_U32, // unsigned int
- ImGuiDataType_S64, // long long, __int64
- ImGuiDataType_U64, // unsigned long long, unsigned __int64
+ ImGuiDataType_S64, // long long / __int64
+ ImGuiDataType_U64, // unsigned long long / unsigned __int64
ImGuiDataType_Float, // float
ImGuiDataType_Double, // double
ImGuiDataType_COUNT
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index 09e3669..a9d1ce1 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -1198,6 +1198,10 @@
ImS64 LLONG_MAX = 9223372036854775807LL;
ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
#endif
+ const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
+ const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
+ const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
+ const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2;
const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2;
const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2;
@@ -1206,6 +1210,10 @@
const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
// State
+ static char s8_v = 127;
+ static ImU8 u8_v = 255;
+ static short s16_v = 32767;
+ static ImU16 u16_v = 65535;
static ImS32 s32_v = -1;
static ImU32 u32_v = (ImU32)-1;
static ImS64 s64_v = -1;
@@ -1217,6 +1225,10 @@
static bool drag_clamp = false;
ImGui::Text("Drags:");
ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); ShowHelpMarker("As with every widgets in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using CTRL+Click to input a value.");
+ ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
+ ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
+ ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
+ ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
@@ -1227,6 +1239,10 @@
ImGui::DragScalar("drag double ^2", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", 2.0f);
ImGui::Text("Sliders");
+ ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
+ ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
+ ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
+ ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
@@ -1249,6 +1265,10 @@
static bool inputs_step = true;
ImGui::Text("Inputs");
ImGui::Checkbox("Show step buttons", &inputs_step);
+ ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d");
+ ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u");
+ ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d");
+ ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u");
ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 0857f4b..9b3dfbd 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -74,22 +74,30 @@
//-------------------------------------------------------------------------
// Those MIN/MAX values are not define because we need to point to them
-static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000);
-static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF)
-static const ImU32 IM_U32_MIN = 0;
-static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF)
+static const char IM_S8_MIN = -128;
+static const char IM_S8_MAX = 127;
+static const unsigned char IM_U8_MIN = 0;
+static const unsigned char IM_U8_MAX = 0xFF;
+static const short IM_S16_MIN = -32768;
+static const short IM_S16_MAX = 32767;
+static const unsigned short IM_U16_MIN = 0;
+static const unsigned short IM_U16_MAX = 0xFFFF;
+static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000);
+static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF)
+static const ImU32 IM_U32_MIN = 0;
+static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF)
#ifdef LLONG_MIN
-static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll);
-static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll);
+static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll);
+static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll);
#else
-static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1;
-static const ImS64 IM_S64_MAX = 9223372036854775807LL;
+static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1;
+static const ImS64 IM_S64_MAX = 9223372036854775807LL;
#endif
-static const ImU64 IM_U64_MIN = 0;
+static const ImU64 IM_U64_MIN = 0;
#ifdef ULLONG_MAX
-static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull);
+static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull);
#else
-static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
+static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
#endif
//-------------------------------------------------------------------------
@@ -1495,17 +1503,21 @@
static const ImGuiDataTypeInfo GDataTypeInfo[] =
{
- { sizeof(int), "%d", "%d" },
- { sizeof(unsigned int), "%u", "%u" },
+ { sizeof(char), "%d", "%d" }, // ImGuiDataType_S8
+ { sizeof(unsigned char), "%u", "%u" },
+ { sizeof(short), "%d", "%d" }, // ImGuiDataType_S16
+ { sizeof(unsigned short), "%u", "%u" },
+ { sizeof(int), "%d", "%d" }, // ImGuiDataType_S32
+ { sizeof(unsigned int), "%u", "%u" },
#ifdef _MSC_VER
- { sizeof(ImS64), "%I64d","%I64d" },
- { sizeof(ImU64), "%I64u","%I64u" },
+ { sizeof(ImS64), "%I64d","%I64d" }, // ImGuiDataType_S64
+ { sizeof(ImU64), "%I64u","%I64u" },
#else
- { sizeof(ImS64), "%lld", "%lld" },
- { sizeof(ImU64), "%llu", "%llu" },
+ { sizeof(ImS64), "%lld", "%lld" }, // ImGuiDataType_S64
+ { sizeof(ImU64), "%llu", "%llu" },
#endif
- { sizeof(float), "%f", "%f" }, // float are promoted to double in va_arg
- { sizeof(double), "%f", "%lf" },
+ { sizeof(float), "%f", "%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg)
+ { sizeof(double), "%f", "%lf" }, // ImGuiDataType_Double
};
IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT);
@@ -1535,14 +1547,23 @@
static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format)
{
- if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) // Signedness doesn't matter when pushing the argument
+ // Signedness doesn't matter when pushing integer arguments
+ if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32)
return ImFormatString(buf, buf_size, format, *(const ImU32*)data_ptr);
- if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) // Signedness doesn't matter when pushing the argument
+ if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
return ImFormatString(buf, buf_size, format, *(const ImU64*)data_ptr);
if (data_type == ImGuiDataType_Float)
return ImFormatString(buf, buf_size, format, *(const float*)data_ptr);
if (data_type == ImGuiDataType_Double)
return ImFormatString(buf, buf_size, format, *(const double*)data_ptr);
+ if (data_type == ImGuiDataType_S8)
+ return ImFormatString(buf, buf_size, format, *(const ImS8*)data_ptr);
+ if (data_type == ImGuiDataType_U8)
+ return ImFormatString(buf, buf_size, format, *(const ImU8*)data_ptr);
+ if (data_type == ImGuiDataType_S16)
+ return ImFormatString(buf, buf_size, format, *(const ImS16*)data_ptr);
+ if (data_type == ImGuiDataType_U16)
+ return ImFormatString(buf, buf_size, format, *(const ImU16*)data_ptr);
IM_ASSERT(0);
return 0;
}
@@ -1553,13 +1574,29 @@
IM_ASSERT(op == '+' || op == '-');
switch (data_type)
{
+ case ImGuiDataType_S8:
+ if (op == '+') *(ImS8*)output = *(const ImS8*)arg1 + *(const ImS8*)arg2;
+ else if (op == '-') *(ImS8*)output = *(const ImS8*)arg1 - *(const ImS8*)arg2;
+ return;
+ case ImGuiDataType_U8:
+ if (op == '+') *(ImU8*)output = *(const ImU8*)arg1 + *(const ImU8*)arg2;
+ else if (op == '-') *(ImU8*)output = *(const ImU8*)arg1 - *(const ImU8*)arg2;
+ return;
+ case ImGuiDataType_S16:
+ if (op == '+') *(ImS16*)output = *(const ImS16*)arg1 + *(const ImS16*)arg2;
+ else if (op == '-') *(ImS16*)output = *(const ImS16*)arg1 - *(const ImS16*)arg2;
+ return;
+ case ImGuiDataType_U16:
+ if (op == '+') *(ImU16*)output = *(const ImU16*)arg1 + *(const ImU16*)arg2;
+ else if (op == '-') *(ImU16*)output = *(const ImU16*)arg1 - *(const ImU16*)arg2;
+ return;
case ImGuiDataType_S32:
- if (op == '+') *(int*)output = *(const int*)arg1 + *(const int*)arg2;
- else if (op == '-') *(int*)output = *(const int*)arg1 - *(const int*)arg2;
+ if (op == '+') *(ImS32*)output = *(const ImS32*)arg1 + *(const ImS32*)arg2;
+ else if (op == '-') *(ImS32*)output = *(const ImS32*)arg1 - *(const ImS32*)arg2;
return;
case ImGuiDataType_U32:
- if (op == '+') *(unsigned int*)output = *(const unsigned int*)arg1 + *(const ImU32*)arg2;
- else if (op == '-') *(unsigned int*)output = *(const unsigned int*)arg1 - *(const ImU32*)arg2;
+ if (op == '+') *(ImU32*)output = *(const ImU32*)arg1 + *(const ImU32*)arg2;
+ else if (op == '-') *(ImU32*)output = *(const ImU32*)arg1 - *(const ImU32*)arg2;
return;
case ImGuiDataType_S64:
if (op == '+') *(ImS64*)output = *(const ImS64*)arg1 + *(const ImS64*)arg2;
@@ -1614,6 +1651,7 @@
if (format == NULL)
format = GDataTypeInfo[data_type].ScanFmt;
+ // FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point..
int arg1i = 0;
if (data_type == ImGuiDataType_S32)
{
@@ -1628,12 +1666,6 @@
else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide
else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant
}
- else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
- {
- // Assign constant
- // FIXME: We don't bother handling support for legacy operators since they are a little too crappy. Instead we may implement a proper expression evaluator in the future.
- sscanf(buf, format, data_ptr);
- }
else if (data_type == ImGuiDataType_Float)
{
// For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
@@ -1663,6 +1695,29 @@
else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
else { *v = arg1f; } // Assign constant
}
+ else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
+ {
+ // All other types assign constant
+ // We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future.
+ sscanf(buf, format, data_ptr);
+ }
+ else
+ {
+ // Small types need a 32-bit buffer to receive the result from scanf()
+ int v32;
+ sscanf(buf, format, &v32);
+ if (data_type == ImGuiDataType_S8)
+ *(ImS8*)data_ptr = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX);
+ else if (data_type == ImGuiDataType_U8)
+ *(ImU8*)data_ptr = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX);
+ else if (data_type == ImGuiDataType_S16)
+ *(ImS16*)data_ptr = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX);
+ else if (data_type == ImGuiDataType_U16)
+ *(ImU16*)data_ptr = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX);
+ else
+ IM_ASSERT(0);
+ }
+
return memcmp(data_backup, data_ptr, GDataTypeInfo[data_type].Size) != 0;
}
@@ -1845,6 +1900,10 @@
switch (data_type)
{
+ case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)v; bool r = DragBehaviorT<ImS32, ImS32, float >(ImGuiDataType_S32, &v32, v_speed, v_min ? *(const ImS8*) v_min : IM_S8_MIN, v_max ? *(const ImS8*)v_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)v = (ImS8)v32; return r; }
+ case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)v; bool r = DragBehaviorT<ImU32, ImS32, float >(ImGuiDataType_U32, &v32, v_speed, v_min ? *(const ImU8*) v_min : IM_U8_MIN, v_max ? *(const ImU8*)v_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)v = (ImU8)v32; return r; }
+ case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)v; bool r = DragBehaviorT<ImS32, ImS32, float >(ImGuiDataType_S32, &v32, v_speed, v_min ? *(const ImS16*)v_min : IM_S16_MIN, v_max ? *(const ImS16*)v_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)v = (ImS16)v32; return r; }
+ case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)v; bool r = DragBehaviorT<ImU32, ImS32, float >(ImGuiDataType_U32, &v32, v_speed, v_min ? *(const ImU16*)v_min : IM_U16_MIN, v_max ? *(const ImU16*)v_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)v = (ImU16)v32; return r; }
case ImGuiDataType_S32: return DragBehaviorT<ImS32, ImS32, float >(data_type, (ImS32*)v, v_speed, v_min ? *(const ImS32* )v_min : IM_S32_MIN, v_max ? *(const ImS32* )v_max : IM_S32_MAX, format, power, flags);
case ImGuiDataType_U32: return DragBehaviorT<ImU32, ImS32, float >(data_type, (ImU32*)v, v_speed, v_min ? *(const ImU32* )v_min : IM_U32_MIN, v_max ? *(const ImU32* )v_max : IM_U32_MAX, format, power, flags);
case ImGuiDataType_S64: return DragBehaviorT<ImS64, ImS64, double>(data_type, (ImS64*)v, v_speed, v_min ? *(const ImS64* )v_min : IM_S64_MIN, v_max ? *(const ImS64* )v_max : IM_S64_MAX, format, power, flags);
@@ -2269,6 +2328,10 @@
{
switch (data_type)
{
+ case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)v; bool r = SliderBehaviorT<ImS32, ImS32, float >(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)v_min, *(const ImS8*)v_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)v = (ImS8)v32; return r; }
+ case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)v; bool r = SliderBehaviorT<ImU32, ImS32, float >(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)v_min, *(const ImU8*)v_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)v = (ImU8)v32; return r; }
+ case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)v; bool r = SliderBehaviorT<ImS32, ImS32, float >(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)v_min, *(const ImS16*)v_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)v = (ImS16)v32; return r; }
+ case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)v; bool r = SliderBehaviorT<ImU32, ImS32, float >(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)v_min, *(const ImU16*)v_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)v = (ImU16)v32; return r; }
case ImGuiDataType_S32:
IM_ASSERT(*(const ImS32*)v_min >= IM_S32_MIN/2 && *(const ImS32*)v_max <= IM_S32_MAX/2);
return SliderBehaviorT<ImS32, ImS32, float >(bb, id, data_type, (ImS32*)v, *(const ImS32*)v_min, *(const ImS32*)v_max, format, power, flags, out_grab_bb);