Skip to content

Instantly share code, notes, and snippets.

@pthom
Created March 29, 2024 18:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pthom/3273604b237e5ee1d819c92b1a41aca1 to your computer and use it in GitHub Desktop.
Save pthom/3273604b237e5ee1d819c92b1a41aca1 to your computer and use it in GitHub Desktop.
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