mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-24 07:40:22 +01:00
Drags, Sliders: Added ImGuiDragFlags_ClampOnInput/ImGuiSliderFlags_ClampOnInput flags to force clamping value when using CTRL+Click to type in a value manually. (#1829, #3209)
This commit is contained in:
parent
7607aea018
commit
170d02bd99
@ -74,6 +74,8 @@ Other Changes:
|
||||
- Drag, Slider: Added ImGuiDragFlags_Logarithmic/ImGuiSliderFlags_Logarithmic flags to
|
||||
enable logarithmic editing (generally more precision around zero), as a replacement to the old
|
||||
'float power' parameter which was obsoleted. (#1823, #1316, #642) [@Shironekoben, @AndrewBelt]
|
||||
- Drag, Slider: Added ImGuiDragFlags_ClampOnInput/ImGuiSliderFlags_ClampOnInput flags to force
|
||||
clamping value when using CTRL+Click to type in a value manually. (#1829, #3209, #946, #413).
|
||||
- DragFloatRange2, DragIntRange2: Fixed an issue allowing to drag out of bounds when both
|
||||
min and max value are on the same value. (#1441)
|
||||
- InputText, ImDrawList: Fixed assert triggering when drawing single line of text with more
|
||||
|
8
imgui.h
8
imgui.h
@ -464,6 +464,7 @@ namespace ImGui
|
||||
// - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
|
||||
// - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x
|
||||
// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
|
||||
// - Format string may also be set to NULL or use the default format ("%f" or "%d").
|
||||
// - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).
|
||||
// - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits.
|
||||
// - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum.
|
||||
@ -485,6 +486,7 @@ namespace ImGui
|
||||
// Widgets: Sliders
|
||||
// - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
|
||||
// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
|
||||
// - Format string may also be set to NULL or use the default format ("%f" or "%d").
|
||||
// - Legacy: Pre-1.78 there are SliderXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument.
|
||||
// If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361
|
||||
IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display.
|
||||
@ -1293,7 +1295,8 @@ enum ImGuiDragFlags_
|
||||
{
|
||||
ImGuiDragFlags_None = 0,
|
||||
ImGuiDragFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
|
||||
ImGuiDragFlags_Logarithmic = 1 << 4 // Should this widget be logarithmic? (linear otherwise)
|
||||
ImGuiDragFlags_ClampOnInput = 1 << 4, // Clamp value to min/max bounds (if any) when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
|
||||
ImGuiDragFlags_Logarithmic = 1 << 5 // Should this widget be logarithmic? (linear otherwise)
|
||||
};
|
||||
|
||||
// Flags for SliderFloat(), SliderInt() etc.
|
||||
@ -1301,7 +1304,8 @@ enum ImGuiSliderFlags_
|
||||
{
|
||||
ImGuiSliderFlags_None = 0,
|
||||
ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
|
||||
ImGuiSliderFlags_Logarithmic = 1 << 4 // Should this widget be logarithmic? (linear otherwise)
|
||||
ImGuiSliderFlags_ClampOnInput = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
|
||||
ImGuiSliderFlags_Logarithmic = 1 << 5 // Should this widget be logarithmic? (linear otherwise)
|
||||
};
|
||||
|
||||
// Identify a mouse button.
|
||||
|
@ -1488,6 +1488,38 @@ static void ShowDemoWindowWidgets()
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Drag/Slider Flags"))
|
||||
{
|
||||
// Demonstrate using advanced flags for DragXXX functions
|
||||
static ImGuiDragFlags drag_flags = ImGuiDragFlags_None;
|
||||
ImGui::CheckboxFlags("ImGuiDragFlags_ClampOnInput", (unsigned int*)&drag_flags, ImGuiDragFlags_ClampOnInput);
|
||||
ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
|
||||
ImGui::CheckboxFlags("ImGuiDragFlags_Logarithmic", (unsigned int*)&drag_flags, ImGuiDragFlags_Logarithmic);
|
||||
ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
|
||||
|
||||
static float drag_f = 0.5f;
|
||||
static int drag_i = 50;
|
||||
ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%f", drag_flags);
|
||||
ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%f", drag_flags);
|
||||
ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%f", drag_flags);
|
||||
ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%f", drag_flags);
|
||||
ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", drag_flags);
|
||||
|
||||
// Demonstrate using advanced flags for SliderXXX functions
|
||||
static ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None;
|
||||
ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", (unsigned int*)&slider_flags, ImGuiSliderFlags_ClampOnInput);
|
||||
ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
|
||||
ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", (unsigned int*)&slider_flags, ImGuiSliderFlags_Logarithmic);
|
||||
ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
|
||||
|
||||
static float slider_f = 0.5f;
|
||||
static int slider_i = 50;
|
||||
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, NULL, slider_flags);
|
||||
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, NULL, slider_flags);
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Range Widgets"))
|
||||
{
|
||||
static float begin = 10, end = 90;
|
||||
@ -3853,10 +3885,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
||||
"rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
|
||||
"Using those settings here will give you poor quality results.");
|
||||
static float window_scale = 1.0f;
|
||||
if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f")) // Scale only this window
|
||||
ImGui::SetWindowFontScale(IM_MAX(window_scale, MIN_SCALE));
|
||||
if (ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f")) // Scale everything
|
||||
io.FontGlobalScale = IM_MAX(io.FontGlobalScale, MIN_SCALE);
|
||||
if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiDragFlags_ClampOnInput)) // Scale only this window
|
||||
ImGui::SetWindowFontScale(window_scale);
|
||||
ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiDragFlags_ClampOnInput); // Scale everything
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
|
@ -1910,10 +1910,11 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool ClampBehaviorT(T* v, T v_min, T v_max)
|
||||
static bool ClampBehaviorT(T* v, const T* v_min, const T* v_max)
|
||||
{
|
||||
if (*v < v_min) { *v = v_min; return true; }
|
||||
if (*v > v_max) { *v = v_max; return true; }
|
||||
// Clamp, both sides are optional
|
||||
if (v_min && *v < *v_min) { *v = *v_min; return true; }
|
||||
if (v_max && *v > *v_max) { *v = *v_max; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1921,16 +1922,16 @@ bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_m
|
||||
{
|
||||
switch (data_type)
|
||||
{
|
||||
case ImGuiDataType_S8: return ClampBehaviorT<ImS8 >((ImS8* )p_data, *(const ImS8* )p_min, *(const ImS8* )p_max);
|
||||
case ImGuiDataType_U8: return ClampBehaviorT<ImU8 >((ImU8* )p_data, *(const ImU8* )p_min, *(const ImU8* )p_max);
|
||||
case ImGuiDataType_S16: return ClampBehaviorT<ImS16 >((ImS16* )p_data, *(const ImS16* )p_min, *(const ImS16* )p_max);
|
||||
case ImGuiDataType_U16: return ClampBehaviorT<ImU16 >((ImU16* )p_data, *(const ImU16* )p_min, *(const ImU16* )p_max);
|
||||
case ImGuiDataType_S32: return ClampBehaviorT<ImS32 >((ImS32* )p_data, *(const ImS32* )p_min, *(const ImS32* )p_max);
|
||||
case ImGuiDataType_U32: return ClampBehaviorT<ImU32 >((ImU32* )p_data, *(const ImU32* )p_min, *(const ImU32* )p_max);
|
||||
case ImGuiDataType_S64: return ClampBehaviorT<ImS64 >((ImS64* )p_data, *(const ImS64* )p_min, *(const ImS64* )p_max);
|
||||
case ImGuiDataType_U64: return ClampBehaviorT<ImU64 >((ImU64* )p_data, *(const ImU64* )p_min, *(const ImU64* )p_max);
|
||||
case ImGuiDataType_Float: return ClampBehaviorT<float >((float* )p_data, *(const float* )p_min, *(const float* )p_max);
|
||||
case ImGuiDataType_Double: return ClampBehaviorT<double>((double*)p_data, *(const double*)p_min, *(const double*)p_max);
|
||||
case ImGuiDataType_S8: return ClampBehaviorT<ImS8 >((ImS8* )p_data, (const ImS8* )p_min, (const ImS8* )p_max);
|
||||
case ImGuiDataType_U8: return ClampBehaviorT<ImU8 >((ImU8* )p_data, (const ImU8* )p_min, (const ImU8* )p_max);
|
||||
case ImGuiDataType_S16: return ClampBehaviorT<ImS16 >((ImS16* )p_data, (const ImS16* )p_min, (const ImS16* )p_max);
|
||||
case ImGuiDataType_U16: return ClampBehaviorT<ImU16 >((ImU16* )p_data, (const ImU16* )p_min, (const ImU16* )p_max);
|
||||
case ImGuiDataType_S32: return ClampBehaviorT<ImS32 >((ImS32* )p_data, (const ImS32* )p_min, (const ImS32* )p_max);
|
||||
case ImGuiDataType_U32: return ClampBehaviorT<ImU32 >((ImU32* )p_data, (const ImU32* )p_min, (const ImU32* )p_max);
|
||||
case ImGuiDataType_S64: return ClampBehaviorT<ImS64 >((ImS64* )p_data, (const ImS64* )p_min, (const ImS64* )p_max);
|
||||
case ImGuiDataType_U64: return ClampBehaviorT<ImU64 >((ImU64* )p_data, (const ImU64* )p_min, (const ImU64* )p_max);
|
||||
case ImGuiDataType_Float: return ClampBehaviorT<float >((float* )p_data, (const float* )p_min, (const float* )p_max);
|
||||
case ImGuiDataType_Double: return ClampBehaviorT<double>((double*)p_data, (const double*)p_min, (const double*)p_max);
|
||||
case ImGuiDataType_COUNT: break;
|
||||
}
|
||||
IM_ASSERT(0);
|
||||
@ -2197,9 +2198,12 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
|
||||
}
|
||||
}
|
||||
|
||||
// Our current specs do NOT clamp when using CTRL+Click manual input, but we should eventually add a flag for that..
|
||||
if (temp_input_is_active)
|
||||
return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max);
|
||||
{
|
||||
// Only clamp CTRL+Click input when ImGuiDragFlags_ClampInput is set
|
||||
const bool is_clamp_input = (flags & ImGuiDragFlags_ClampOnInput) != 0;
|
||||
return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);
|
||||
}
|
||||
|
||||
// Draw frame
|
||||
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
|
||||
@ -2753,9 +2757,12 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
|
||||
}
|
||||
}
|
||||
|
||||
// Our current specs do NOT clamp when using CTRL+Click manual input, but we should eventually add a flag for that..
|
||||
if (temp_input_is_active)
|
||||
return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max);
|
||||
{
|
||||
// Only clamp CTRL+Click input when ImGuiSliderFlags_ClampInput is set
|
||||
const bool is_clamp_input = (flags & ImGuiSliderFlags_ClampOnInput) != 0;
|
||||
return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);
|
||||
}
|
||||
|
||||
// Draw frame
|
||||
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
|
||||
@ -3081,20 +3088,10 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char*
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
// Note that Drag/Slider functions are currently NOT forwarding the min/max values clamping values!
|
||||
// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the
|
||||
// ImGuiDragFlags_ClampOnInput / ImGuiSliderFlags_ClampOnInput flag is set!
|
||||
// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility.
|
||||
// However this may not be ideal for all uses, as some user code may break on out of bound values.
|
||||
// In the future we should add flags to Slider/Drag to specify how to enforce min/max values with CTRL+Click.
|
||||
// See GitHub issues #1829 and #3209
|
||||
// In the meanwhile, you can easily "wrap" those functions to enforce clamping, using wrapper functions, e.g.
|
||||
// bool SliderFloatClamp(const char* label, float* v, float v_min, float v_max)
|
||||
// {
|
||||
// float v_backup = *v;
|
||||
// if (!SliderFloat(label, v, v_min, v_max))
|
||||
// return false;
|
||||
// *v = ImClamp(*v, v_min, v_max);
|
||||
// return v_backup != *v;
|
||||
// }
|
||||
bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -3117,7 +3114,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
|
||||
|
||||
// Apply new value (or operations) then clamp
|
||||
DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL);
|
||||
if (p_clamp_min && p_clamp_max)
|
||||
if (p_clamp_min || p_clamp_max)
|
||||
DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max);
|
||||
|
||||
// Only mark as edited if new value is different
|
||||
|
Loading…
Reference in New Issue
Block a user