Created
March 29, 2024 18:17
-
-
Save pthom/3273604b237e5ee1d819c92b1a41aca1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Internal | |
{ | |
struct SliderAdaptiveInterval | |
{ | |
float max() const { return pow(10.f, CurrentPower); } | |
void SetTargetValue(float targetValue) | |
{ | |
assert (targetValue >= 0.f); | |
float k = 0.1f; | |
float triggerMax = max() * (1 - k); | |
if (targetValue > triggerMax) | |
{ | |
TimeLastPowerChange = ImGui::GetTime(); | |
CurrentPower++; | |
return; | |
} | |
float triggerMin = max() * k * 0.9f; | |
if (targetValue < triggerMin) | |
{ | |
TimeLastPowerChange = ImGui::GetTime(); | |
CurrentPower--; | |
return; | |
} | |
} | |
std::string FormatString() | |
{ | |
std::string floatFormat = std::string("%.") + std::to_string(NbSignificantDigits) + "g"; | |
char maxValueFormatted[256]; | |
snprintf(maxValueFormatted, 256, floatFormat.c_str(), max()); | |
std::string format = floatFormat + " (0 - " + maxValueFormatted + ")"; | |
return format; | |
} | |
bool WasChangedRecently() | |
{ | |
if (TimeLastPowerChange == 0.f) | |
return false; | |
return ((ImGui::GetTime() - TimeLastPowerChange) < 0.5); | |
} | |
int NbSignificantDigits = 4; | |
int CurrentPower = 1; | |
double TimeLastPowerChange = 0.f; | |
}; | |
struct SliderAdaptiveIntervalCache | |
{ | |
// Actually, we could use any map | |
SliderAdaptiveInterval& GetOrCreate(ImGuiID id, int nbSignificantDigits) | |
{ | |
// Bypass std::map ugly "create if not exists" pattern | |
if (Intervals.find(id) == Intervals.end()) | |
Intervals[id] = SliderAdaptativeInterval(); | |
Intervals.at(id).NbSignificantDigits = nbSignificantDigits; | |
return Intervals.at(id); | |
} | |
std::map<ImGuiID, SliderAdaptiveInterval> Intervals; | |
}; | |
} | |
// A slider that can edit *positive* floats, with a given number of significant digits | |
// for any value (the slider will interactively adapt its range to the value, | |
// and flash red when the range changed) | |
bool SliderAnyPositiveFloat(const char* label, float* v, int nbSignificantDigits = 4) | |
{ | |
static Internal::SliderAdaptiveIntervalCache cache; | |
Internal::SliderAdaptiveInterval& interval = cache.GetOrCreate(ImGui::GetID(label), nbSignificantDigits); | |
ImGui::PushID(interval.CurrentPower); | |
bool wasChangedRecently = interval.WasChangedRecently(); | |
if (wasChangedRecently) | |
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1, 0, 0, 1)); | |
bool r = ImGui::SliderFloat(label, v, 0.f, interval.max(), interval.FormatString().c_str()); | |
if (wasChangedRecently) | |
ImGui::PopStyleColor(); | |
interval.SetTargetValue(*v); | |
ImGui::PopID(); | |
return r; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment