#pragma once
#ifndef IMPLOT_VERSION
#error Must include implot.h before implot_internal.h
#endif
#ifndef IMGUI_DISABLE
#include <time.h>
#include "imgui_internal.h"
#if (IMGUI_VERSION_NUM < 18303)
#define GetBufSize GetSize
#endif
constexpr double IMPLOT_MIN_TIME = 0;
constexpr double IMPLOT_MAX_TIME = 32503680000;
constexpr const char* IMPLOT_LABEL_FORMAT = "%g";
constexpr int IMPLOT_LABEL_MAX_SIZE = 32;
constexpr int IMPLOT_NUM_X_AXES = ImAxis_Y1;
constexpr int IMPLOT_NUM_Y_AXES = ImAxis_COUNT - IMPLOT_NUM_X_AXES;
#define IM_COL32_SPLIT_RGB(col,r,g,b) \
ImU32 r = ((col >> IM_COL32_R_SHIFT) & 0xFF); \
ImU32 g = ((col >> IM_COL32_G_SHIFT) & 0xFF); \
ImU32 b = ((col >> IM_COL32_B_SHIFT) & 0xFF);
struct ImPlotTick;
struct ImPlotAxis;
struct ImPlotAxisColor;
struct ImPlotItem;
struct ImPlotLegend;
struct ImPlotPlot;
struct ImPlotNextPlotData;
struct ImPlotTicker;
#ifndef GImPlot
extern IMPLOT_API ImPlotContext* GImPlot; #endif
static inline float ImLog10(float x) { return log10f(x); }
static inline double ImLog10(double x) { return log10(x); }
static inline float ImSinh(float x) { return sinhf(x); }
static inline double ImSinh(double x) { return sinh(x); }
static inline float ImAsinh(float x) { return asinhf(x); }
static inline double ImAsinh(double x) { return asinh(x); }
template <typename TSet, typename TFlag>
static inline bool ImHasFlag(TSet set, TFlag flag) { return (set & flag) == flag; }
template <typename TSet, typename TFlag>
static inline void ImFlipFlag(TSet& set, TFlag flag) { ImHasFlag(set, flag) ? set &= ~flag : set |= flag; }
template <typename T>
static inline T ImRemap(T x, T x0, T x1, T y0, T y1) { return y0 + (x - x0) * (y1 - y0) / (x1 - x0); }
template <typename T>
static inline T ImRemap01(T x, T x0, T x1) { return (x - x0) / (x1 - x0); }
static inline int ImPosMod(int l, int r) { return (l % r + r) % r; }
static inline bool ImNan(double val) { return isnan(val); }
static inline bool ImNanOrInf(double val) { return !(val >= -DBL_MAX && val <= DBL_MAX) || ImNan(val); }
static inline double ImConstrainNan(double val) { return ImNan(val) ? 0 : val; }
static inline double ImConstrainInf(double val) { return val >= DBL_MAX ? DBL_MAX : val <= -DBL_MAX ? - DBL_MAX : val; }
static inline double ImConstrainLog(double val) { return val <= 0 ? 0.001f : val; }
static inline double ImConstrainTime(double val) { return val < IMPLOT_MIN_TIME ? IMPLOT_MIN_TIME : (val > IMPLOT_MAX_TIME ? IMPLOT_MAX_TIME : val); }
static inline bool ImAlmostEqual(double v1, double v2, int ulp = 2) { return ImAbs(v1-v2) < DBL_EPSILON * ImAbs(v1+v2) * ulp || ImAbs(v1-v2) < DBL_MIN; }
template <typename T>
static inline T ImMinArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] < m) { m = values[i]; } } return m; }
template <typename T>
static inline T ImMaxArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] > m) { m = values[i]; } } return m; }
template <typename T>
static inline void ImMinMaxArray(const T* values, int count, T* min_out, T* max_out) {
T Min = values[0]; T Max = values[0];
for (int i = 1; i < count; ++i) {
if (values[i] < Min) { Min = values[i]; }
if (values[i] > Max) { Max = values[i]; }
}
*min_out = Min; *max_out = Max;
}
template <typename T>
static inline T ImSum(const T* values, int count) {
T sum = 0;
for (int i = 0; i < count; ++i)
sum += values[i];
return sum;
}
template <typename T>
static inline double ImMean(const T* values, int count) {
double den = 1.0 / count;
double mu = 0;
for (int i = 0; i < count; ++i)
mu += (double)values[i] * den;
return mu;
}
template <typename T>
static inline double ImStdDev(const T* values, int count) {
double den = 1.0 / (count - 1.0);
double mu = ImMean(values, count);
double x = 0;
for (int i = 0; i < count; ++i)
x += ((double)values[i] - mu) * ((double)values[i] - mu) * den;
return sqrt(x);
}
static inline ImU32 ImMixU32(ImU32 a, ImU32 b, ImU32 s) {
#ifdef IMPLOT_MIX64
const ImU32 af = 256-s;
const ImU32 bf = s;
const ImU64 al = (a & 0x00ff00ff) | (((ImU64)(a & 0xff00ff00)) << 24);
const ImU64 bl = (b & 0x00ff00ff) | (((ImU64)(b & 0xff00ff00)) << 24);
const ImU64 mix = (al * af + bl * bf);
return ((mix >> 32) & 0xff00ff00) | ((mix & 0xff00ff00) >> 8);
#else
const ImU32 af = 256-s;
const ImU32 bf = s;
const ImU32 al = (a & 0x00ff00ff);
const ImU32 ah = (a & 0xff00ff00) >> 8;
const ImU32 bl = (b & 0x00ff00ff);
const ImU32 bh = (b & 0xff00ff00) >> 8;
const ImU32 ml = (al * af + bl * bf);
const ImU32 mh = (ah * af + bh * bf);
return (mh & 0xff00ff00) | ((ml & 0xff00ff00) >> 8);
#endif
}
static inline ImU32 ImLerpU32(const ImU32* colors, int size, float t) {
int i1 = (int)((size - 1 ) * t);
int i2 = i1 + 1;
if (i2 == size || size == 1)
return colors[i1];
float den = 1.0f / (size - 1);
float t1 = i1 * den;
float t2 = i2 * den;
float tr = ImRemap01(t, t1, t2);
return ImMixU32(colors[i1], colors[i2], (ImU32)(tr*256));
}
static inline ImU32 ImAlphaU32(ImU32 col, float alpha) {
return col & ~((ImU32)((1.0f-alpha)*255)<<IM_COL32_A_SHIFT);
}
template <typename T>
static inline bool ImOverlaps(T min_a, T max_a, T min_b, T max_b) {
return min_a <= max_b && min_b <= max_a;
}
typedef int ImPlotTimeUnit; typedef int ImPlotDateFmt; typedef int ImPlotTimeFmt; typedef int ImPlotMarkerInternal;
enum ImPlotTimeUnit_ {
ImPlotTimeUnit_Us, ImPlotTimeUnit_Ms, ImPlotTimeUnit_S, ImPlotTimeUnit_Min, ImPlotTimeUnit_Hr, ImPlotTimeUnit_Day, ImPlotTimeUnit_Mo, ImPlotTimeUnit_Yr, ImPlotTimeUnit_COUNT
};
enum ImPlotDateFmt_ { ImPlotDateFmt_None = 0,
ImPlotDateFmt_DayMo, ImPlotDateFmt_DayMoYr, ImPlotDateFmt_MoYr, ImPlotDateFmt_Mo, ImPlotDateFmt_Yr };
enum ImPlotTimeFmt_ { ImPlotTimeFmt_None = 0,
ImPlotTimeFmt_Us, ImPlotTimeFmt_SUs, ImPlotTimeFmt_SMs, ImPlotTimeFmt_S, ImPlotTimeFmt_MinSMs, ImPlotTimeFmt_HrMinSMs, ImPlotTimeFmt_HrMinS, ImPlotTimeFmt_HrMin, ImPlotTimeFmt_Hr };
enum ImPlotMarkerInternal_ {
ImPlotMarker_Invalid = -3
};
typedef void (*ImPlotLocator)(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
struct ImPlotDateTimeSpec {
ImPlotDateTimeSpec() {}
ImPlotDateTimeSpec(ImPlotDateFmt date_fmt, ImPlotTimeFmt time_fmt, bool use_24_hr_clk = false, bool use_iso_8601 = false) {
Date = date_fmt;
Time = time_fmt;
UseISO8601 = use_iso_8601;
Use24HourClock = use_24_hr_clk;
}
ImPlotDateFmt Date;
ImPlotTimeFmt Time;
bool UseISO8601;
bool Use24HourClock;
};
struct ImPlotTime {
time_t S; int Us; ImPlotTime() { S = 0; Us = 0; }
ImPlotTime(time_t s, int us = 0) { S = s + us / 1000000; Us = us % 1000000; }
void RollOver() { S = S + Us / 1000000; Us = Us % 1000000; }
double ToDouble() const { return (double)S + (double)Us / 1000000.0; }
static ImPlotTime FromDouble(double t) { return ImPlotTime((time_t)t, (int)(t * 1000000 - floor(t) * 1000000)); }
};
static inline ImPlotTime operator+(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return ImPlotTime(lhs.S + rhs.S, lhs.Us + rhs.Us); }
static inline ImPlotTime operator-(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return ImPlotTime(lhs.S - rhs.S, lhs.Us - rhs.Us); }
static inline bool operator==(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs.S == rhs.S && lhs.Us == rhs.Us; }
static inline bool operator<(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs.S == rhs.S ? lhs.Us < rhs.Us : lhs.S < rhs.S; }
static inline bool operator>(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return rhs < lhs; }
static inline bool operator<=(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs < rhs || lhs == rhs; }
static inline bool operator>=(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs > rhs || lhs == rhs; }
struct ImPlotColormapData {
ImVector<ImU32> Keys;
ImVector<int> KeyCounts;
ImVector<int> KeyOffsets;
ImVector<ImU32> Tables;
ImVector<int> TableSizes;
ImVector<int> TableOffsets;
ImGuiTextBuffer Text;
ImVector<int> TextOffsets;
ImVector<bool> Quals;
ImGuiStorage Map;
int Count;
ImPlotColormapData() { Count = 0; }
int Append(const char* name, const ImU32* keys, int count, bool qual) {
if (GetIndex(name) != -1)
return -1;
KeyOffsets.push_back(Keys.size());
KeyCounts.push_back(count);
Keys.reserve(Keys.size()+count);
for (int i = 0; i < count; ++i)
Keys.push_back(keys[i]);
TextOffsets.push_back(Text.size());
Text.append(name, name + strlen(name) + 1);
Quals.push_back(qual);
ImGuiID id = ImHashStr(name);
int idx = Count++;
Map.SetInt(id,idx);
_AppendTable(idx);
return idx;
}
void _AppendTable(ImPlotColormap cmap) {
int key_count = GetKeyCount(cmap);
const ImU32* keys = GetKeys(cmap);
int off = Tables.size();
TableOffsets.push_back(off);
if (IsQual(cmap)) {
Tables.reserve(key_count);
for (int i = 0; i < key_count; ++i)
Tables.push_back(keys[i]);
TableSizes.push_back(key_count);
}
else {
int max_size = 255 * (key_count-1) + 1;
Tables.reserve(off + max_size);
for (int i = 0; i < key_count-1; ++i) {
for (int s = 0; s < 255; ++s) {
ImU32 a = keys[i];
ImU32 b = keys[i+1];
ImU32 c = ImMixU32(a,b,s);
Tables.push_back(c);
}
}
ImU32 c = keys[key_count-1];
Tables.push_back(c);
TableSizes.push_back(max_size);
}
}
void RebuildTables() {
Tables.resize(0);
TableSizes.resize(0);
TableOffsets.resize(0);
for (int i = 0; i < Count; ++i)
_AppendTable(i);
}
inline bool IsQual(ImPlotColormap cmap) const { return Quals[cmap]; }
inline const char* GetName(ImPlotColormap cmap) const { return cmap < Count ? Text.Buf.Data + TextOffsets[cmap] : nullptr; }
inline ImPlotColormap GetIndex(const char* name) const { ImGuiID key = ImHashStr(name); return Map.GetInt(key,-1); }
inline const ImU32* GetKeys(ImPlotColormap cmap) const { return &Keys[KeyOffsets[cmap]]; }
inline int GetKeyCount(ImPlotColormap cmap) const { return KeyCounts[cmap]; }
inline ImU32 GetKeyColor(ImPlotColormap cmap, int idx) const { return Keys[KeyOffsets[cmap]+idx]; }
inline void SetKeyColor(ImPlotColormap cmap, int idx, ImU32 value) { Keys[KeyOffsets[cmap]+idx] = value; RebuildTables(); }
inline const ImU32* GetTable(ImPlotColormap cmap) const { return &Tables[TableOffsets[cmap]]; }
inline int GetTableSize(ImPlotColormap cmap) const { return TableSizes[cmap]; }
inline ImU32 GetTableColor(ImPlotColormap cmap, int idx) const { return Tables[TableOffsets[cmap]+idx]; }
inline ImU32 LerpTable(ImPlotColormap cmap, float t) const {
int off = TableOffsets[cmap];
int siz = TableSizes[cmap];
int idx = Quals[cmap] ? ImClamp((int)(siz*t),0,siz-1) : (int)((siz - 1) * t + 0.5f);
return Tables[off + idx];
}
};
struct ImPlotPointError {
double X, Y, Neg, Pos;
ImPlotPointError() { X = 0; Y = 0; Neg = 0; Pos = 0; }
ImPlotPointError(double x, double y, double neg, double pos) {
X = x; Y = y; Neg = neg; Pos = pos;
}
};
struct ImPlotAnnotation {
ImVec2 Pos;
ImVec2 Offset;
ImU32 ColorBg;
ImU32 ColorFg;
int TextOffset;
bool Clamp;
ImPlotAnnotation() {
ColorBg = ColorFg = 0;
TextOffset = 0;
Clamp = false;
}
};
struct ImPlotAnnotationCollection {
ImVector<ImPlotAnnotation> Annotations;
ImGuiTextBuffer TextBuffer;
int Size;
ImPlotAnnotationCollection() { Reset(); }
void AppendV(const ImVec2& pos, const ImVec2& off, ImU32 bg, ImU32 fg, bool clamp, const char* fmt, va_list args) IM_FMTLIST(7) {
ImPlotAnnotation an;
an.Pos = pos; an.Offset = off;
an.ColorBg = bg; an.ColorFg = fg;
an.TextOffset = TextBuffer.size();
an.Clamp = clamp;
Annotations.push_back(an);
TextBuffer.appendfv(fmt, args);
const char nul[] = "";
TextBuffer.append(nul,nul+1);
Size++;
}
void Append(const ImVec2& pos, const ImVec2& off, ImU32 bg, ImU32 fg, bool clamp, const char* fmt, ...) IM_FMTARGS(7) {
va_list args;
va_start(args, fmt);
AppendV(pos, off, bg, fg, clamp, fmt, args);
va_end(args);
}
const char* GetText(int idx) {
return TextBuffer.Buf.Data + Annotations[idx].TextOffset;
}
void Reset() {
Annotations.shrink(0);
TextBuffer.Buf.shrink(0);
Size = 0;
}
};
struct ImPlotTag {
ImAxis Axis;
double Value;
ImU32 ColorBg;
ImU32 ColorFg;
int TextOffset;
ImPlotTag() {
Axis = 0;
Value = 0;
ColorBg = 0;
ColorFg = 0;
TextOffset = 0;
}
};
struct ImPlotTagCollection {
ImVector<ImPlotTag> Tags;
ImGuiTextBuffer TextBuffer;
int Size;
ImPlotTagCollection() { Reset(); }
void AppendV(ImAxis axis, double value, ImU32 bg, ImU32 fg, const char* fmt, va_list args) IM_FMTLIST(6) {
ImPlotTag tag;
tag.Axis = axis;
tag.Value = value;
tag.ColorBg = bg;
tag.ColorFg = fg;
tag.TextOffset = TextBuffer.size();
Tags.push_back(tag);
TextBuffer.appendfv(fmt, args);
const char nul[] = "";
TextBuffer.append(nul,nul+1);
Size++;
}
void Append(ImAxis axis, double value, ImU32 bg, ImU32 fg, const char* fmt, ...) IM_FMTARGS(6) {
va_list args;
va_start(args, fmt);
AppendV(axis, value, bg, fg, fmt, args);
va_end(args);
}
const char* GetText(int idx) {
return TextBuffer.Buf.Data + Tags[idx].TextOffset;
}
void Reset() {
Tags.shrink(0);
TextBuffer.Buf.shrink(0);
Size = 0;
}
};
struct ImPlotTick
{
double PlotPos;
float PixelPos;
ImVec2 LabelSize;
int TextOffset;
bool Major;
bool ShowLabel;
int Level;
int Idx;
ImPlotTick() {
PlotPos = 0;
PixelPos = 0;
LabelSize = ImVec2(0,0);
TextOffset = -1;
Major = false;
ShowLabel = false;
Level = 0;
Idx = -1;
}
ImPlotTick(double value, bool major, int level, bool show_label) {
PixelPos = 0;
PlotPos = value;
Major = major;
ShowLabel = show_label;
Level = level;
TextOffset = -1;
}
};
struct ImPlotTicker {
ImVector<ImPlotTick> Ticks;
ImGuiTextBuffer TextBuffer;
ImVec2 MaxSize;
ImVec2 LateSize;
int Levels;
ImPlotTicker() {
Reset();
}
ImPlotTick& AddTick(double value, bool major, int level, bool show_label, const char* label) {
ImPlotTick tick(value, major, level, show_label);
if (show_label && label != nullptr) {
tick.TextOffset = TextBuffer.size();
TextBuffer.append(label, label + strlen(label) + 1);
tick.LabelSize = ImGui::CalcTextSize(TextBuffer.Buf.Data + tick.TextOffset);
}
return AddTick(tick);
}
ImPlotTick& AddTick(double value, bool major, int level, bool show_label, ImPlotFormatter formatter, void* data) {
ImPlotTick tick(value, major, level, show_label);
if (show_label && formatter != nullptr) {
char buff[IMPLOT_LABEL_MAX_SIZE];
tick.TextOffset = TextBuffer.size();
formatter(tick.PlotPos, buff, sizeof(buff), data);
TextBuffer.append(buff, buff + strlen(buff) + 1);
tick.LabelSize = ImGui::CalcTextSize(TextBuffer.Buf.Data + tick.TextOffset);
}
return AddTick(tick);
}
inline ImPlotTick& AddTick(ImPlotTick tick) {
if (tick.ShowLabel) {
MaxSize.x = tick.LabelSize.x > MaxSize.x ? tick.LabelSize.x : MaxSize.x;
MaxSize.y = tick.LabelSize.y > MaxSize.y ? tick.LabelSize.y : MaxSize.y;
}
tick.Idx = Ticks.size();
Ticks.push_back(tick);
return Ticks.back();
}
const char* GetText(int idx) const {
return TextBuffer.Buf.Data + Ticks[idx].TextOffset;
}
const char* GetText(const ImPlotTick& tick) {
return GetText(tick.Idx);
}
void OverrideSizeLate(const ImVec2& size) {
LateSize.x = size.x > LateSize.x ? size.x : LateSize.x;
LateSize.y = size.y > LateSize.y ? size.y : LateSize.y;
}
void Reset() {
Ticks.shrink(0);
TextBuffer.Buf.shrink(0);
MaxSize = LateSize;
LateSize = ImVec2(0,0);
Levels = 1;
}
int TickCount() const {
return Ticks.Size;
}
};
struct ImPlotAxis
{
ImGuiID ID;
ImPlotAxisFlags Flags;
ImPlotAxisFlags PreviousFlags;
ImPlotRange Range;
ImPlotCond RangeCond;
ImPlotScale Scale;
ImPlotRange FitExtents;
ImPlotAxis* OrthoAxis;
ImPlotRange ConstraintRange;
ImPlotRange ConstraintZoom;
ImPlotTicker Ticker;
ImPlotFormatter Formatter;
void* FormatterData;
char FormatSpec[16];
ImPlotLocator Locator;
double* LinkedMin;
double* LinkedMax;
int PickerLevel;
ImPlotTime PickerTimeMin, PickerTimeMax;
ImPlotTransform TransformForward;
ImPlotTransform TransformInverse;
void* TransformData;
float PixelMin, PixelMax;
double ScaleMin, ScaleMax;
double ScaleToPixel;
float Datum1, Datum2;
ImRect HoverRect;
int LabelOffset;
ImU32 ColorMaj, ColorMin, ColorTick, ColorTxt, ColorBg, ColorHov, ColorAct, ColorHiLi;
bool Enabled;
bool Vertical;
bool FitThisFrame;
bool HasRange;
bool HasFormatSpec;
bool ShowDefaultTicks;
bool Hovered;
bool Held;
ImPlotAxis() {
ID = 0;
Flags = PreviousFlags = ImPlotAxisFlags_None;
Range.Min = 0;
Range.Max = 1;
Scale = ImPlotScale_Linear;
TransformForward = TransformInverse = nullptr;
TransformData = nullptr;
FitExtents.Min = HUGE_VAL;
FitExtents.Max = -HUGE_VAL;
OrthoAxis = nullptr;
ConstraintRange = ImPlotRange(-INFINITY,INFINITY);
ConstraintZoom = ImPlotRange(DBL_MIN,INFINITY);
LinkedMin = LinkedMax = nullptr;
PickerLevel = 0;
Datum1 = Datum2 = 0;
PixelMin = PixelMax = 0;
LabelOffset = -1;
ColorMaj = ColorMin = ColorTick = ColorTxt = ColorBg = ColorHov = ColorAct = 0;
ColorHiLi = IM_COL32_BLACK_TRANS;
Formatter = nullptr;
FormatterData = nullptr;
Locator = nullptr;
Enabled = Hovered = Held = FitThisFrame = HasRange = HasFormatSpec = false;
ShowDefaultTicks = true;
}
inline void Reset() {
Enabled = false;
Scale = ImPlotScale_Linear;
TransformForward = TransformInverse = nullptr;
TransformData = nullptr;
LabelOffset = -1;
HasFormatSpec = false;
Formatter = nullptr;
FormatterData = nullptr;
Locator = nullptr;
ShowDefaultTicks = true;
FitThisFrame = false;
FitExtents.Min = HUGE_VAL;
FitExtents.Max = -HUGE_VAL;
OrthoAxis = nullptr;
ConstraintRange = ImPlotRange(-INFINITY,INFINITY);
ConstraintZoom = ImPlotRange(DBL_MIN,INFINITY);
Ticker.Reset();
}
inline bool SetMin(double _min, bool force=false) {
if (!force && IsLockedMin())
return false;
_min = ImConstrainNan(ImConstrainInf(_min));
if (_min < ConstraintRange.Min)
_min = ConstraintRange.Min;
double z = Range.Max - _min;
if (z < ConstraintZoom.Min)
_min = Range.Max - ConstraintZoom.Min;
if (z > ConstraintZoom.Max)
_min = Range.Max - ConstraintZoom.Max;
if (_min >= Range.Max)
return false;
Range.Min = _min;
PickerTimeMin = ImPlotTime::FromDouble(Range.Min);
UpdateTransformCache();
return true;
}
inline bool SetMax(double _max, bool force=false) {
if (!force && IsLockedMax())
return false;
_max = ImConstrainNan(ImConstrainInf(_max));
if (_max > ConstraintRange.Max)
_max = ConstraintRange.Max;
double z = _max - Range.Min;
if (z < ConstraintZoom.Min)
_max = Range.Min + ConstraintZoom.Min;
if (z > ConstraintZoom.Max)
_max = Range.Min + ConstraintZoom.Max;
if (_max <= Range.Min)
return false;
Range.Max = _max;
PickerTimeMax = ImPlotTime::FromDouble(Range.Max);
UpdateTransformCache();
return true;
}
inline void SetRange(double v1, double v2) {
Range.Min = ImMin(v1,v2);
Range.Max = ImMax(v1,v2);
Constrain();
PickerTimeMin = ImPlotTime::FromDouble(Range.Min);
PickerTimeMax = ImPlotTime::FromDouble(Range.Max);
UpdateTransformCache();
}
inline void SetRange(const ImPlotRange& range) {
SetRange(range.Min, range.Max);
}
inline void SetAspect(double unit_per_pix) {
double new_size = unit_per_pix * PixelSize();
double delta = (new_size - Range.Size()) * 0.5;
if (IsLocked())
return;
else if (IsLockedMin() && !IsLockedMax())
SetRange(Range.Min, Range.Max + 2*delta);
else if (!IsLockedMin() && IsLockedMax())
SetRange(Range.Min - 2*delta, Range.Max);
else
SetRange(Range.Min - delta, Range.Max + delta);
}
inline float PixelSize() const { return ImAbs(PixelMax - PixelMin); }
inline double GetAspect() const { return Range.Size() / PixelSize(); }
inline void Constrain() {
Range.Min = ImConstrainNan(ImConstrainInf(Range.Min));
Range.Max = ImConstrainNan(ImConstrainInf(Range.Max));
if (Range.Min < ConstraintRange.Min)
Range.Min = ConstraintRange.Min;
if (Range.Max > ConstraintRange.Max)
Range.Max = ConstraintRange.Max;
double z = Range.Size();
if (z < ConstraintZoom.Min) {
double delta = (ConstraintZoom.Min - z) * 0.5;
Range.Min -= delta;
Range.Max += delta;
}
if (z > ConstraintZoom.Max) {
double delta = (z - ConstraintZoom.Max) * 0.5;
Range.Min += delta;
Range.Max -= delta;
}
if (Range.Max <= Range.Min)
Range.Max = Range.Min + DBL_EPSILON;
}
inline void UpdateTransformCache() {
ScaleToPixel = (PixelMax - PixelMin) / Range.Size();
if (TransformForward != nullptr) {
ScaleMin = TransformForward(Range.Min, TransformData);
ScaleMax = TransformForward(Range.Max, TransformData);
}
else {
ScaleMin = Range.Min;
ScaleMax = Range.Max;
}
}
inline float PlotToPixels(double plt) const {
if (TransformForward != nullptr) {
double s = TransformForward(plt, TransformData);
double t = (s - ScaleMin) / (ScaleMax - ScaleMin);
plt = Range.Min + Range.Size() * t;
}
return (float)(PixelMin + ScaleToPixel * (plt - Range.Min));
}
inline double PixelsToPlot(float pix) const {
double plt = (pix - PixelMin) / ScaleToPixel + Range.Min;
if (TransformInverse != nullptr) {
double t = (plt - Range.Min) / Range.Size();
double s = t * (ScaleMax - ScaleMin) + ScaleMin;
plt = TransformInverse(s, TransformData);
}
return plt;
}
inline void ExtendFit(double v) {
if (!ImNanOrInf(v) && v >= ConstraintRange.Min && v <= ConstraintRange.Max) {
FitExtents.Min = v < FitExtents.Min ? v : FitExtents.Min;
FitExtents.Max = v > FitExtents.Max ? v : FitExtents.Max;
}
}
inline void ExtendFitWith(ImPlotAxis& alt, double v, double v_alt) {
if (ImHasFlag(Flags, ImPlotAxisFlags_RangeFit) && !alt.Range.Contains(v_alt))
return;
if (!ImNanOrInf(v) && v >= ConstraintRange.Min && v <= ConstraintRange.Max) {
FitExtents.Min = v < FitExtents.Min ? v : FitExtents.Min;
FitExtents.Max = v > FitExtents.Max ? v : FitExtents.Max;
}
}
inline void ApplyFit(float padding) {
const double ext_size = FitExtents.Size() * 0.5;
FitExtents.Min -= ext_size * padding;
FitExtents.Max += ext_size * padding;
if (!IsLockedMin() && !ImNanOrInf(FitExtents.Min))
Range.Min = FitExtents.Min;
if (!IsLockedMax() && !ImNanOrInf(FitExtents.Max))
Range.Max = FitExtents.Max;
if (ImAlmostEqual(Range.Min, Range.Max)) {
Range.Max += 0.5;
Range.Min -= 0.5;
}
Constrain();
UpdateTransformCache();
}
inline bool HasLabel() const { return LabelOffset != -1 && !ImHasFlag(Flags, ImPlotAxisFlags_NoLabel); }
inline bool HasGridLines() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoGridLines); }
inline bool HasTickLabels() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickLabels); }
inline bool HasTickMarks() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickMarks); }
inline bool WillRender() const { return Enabled && (HasGridLines() || HasTickLabels() || HasTickMarks()); }
inline bool IsOpposite() const { return ImHasFlag(Flags, ImPlotAxisFlags_Opposite); }
inline bool IsInverted() const { return ImHasFlag(Flags, ImPlotAxisFlags_Invert); }
inline bool IsForeground() const { return ImHasFlag(Flags, ImPlotAxisFlags_Foreground); }
inline bool IsAutoFitting() const { return ImHasFlag(Flags, ImPlotAxisFlags_AutoFit); }
inline bool CanInitFit() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoInitialFit) && !HasRange && !LinkedMin && !LinkedMax; }
inline bool IsRangeLocked() const { return HasRange && RangeCond == ImPlotCond_Always; }
inline bool IsLockedMin() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMin); }
inline bool IsLockedMax() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMax); }
inline bool IsLocked() const { return IsLockedMin() && IsLockedMax(); }
inline bool IsInputLockedMin() const { return IsLockedMin() || IsAutoFitting(); }
inline bool IsInputLockedMax() const { return IsLockedMax() || IsAutoFitting(); }
inline bool IsInputLocked() const { return IsLocked() || IsAutoFitting(); }
inline bool HasMenus() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoMenus); }
inline bool IsPanLocked(bool increasing) {
if (ImHasFlag(Flags, ImPlotAxisFlags_PanStretch)) {
return IsInputLocked();
}
else {
if (IsLockedMin() || IsLockedMax() || IsAutoFitting())
return false;
if (increasing)
return Range.Max == ConstraintRange.Max;
else
return Range.Min == ConstraintRange.Min;
}
}
void PushLinks() {
if (LinkedMin) { *LinkedMin = Range.Min; }
if (LinkedMax) { *LinkedMax = Range.Max; }
}
void PullLinks() {
if (LinkedMin && LinkedMax) { SetRange(*LinkedMin, *LinkedMax); }
else if (LinkedMin) { SetMin(*LinkedMin,true); }
else if (LinkedMax) { SetMax(*LinkedMax,true); }
}
};
struct ImPlotAlignmentData {
bool Vertical;
float PadA;
float PadB;
float PadAMax;
float PadBMax;
ImPlotAlignmentData() {
Vertical = true;
PadA = PadB = PadAMax = PadBMax = 0;
}
void Begin() { PadAMax = PadBMax = 0; }
void Update(float& pad_a, float& pad_b, float& delta_a, float& delta_b) {
float bak_a = pad_a; float bak_b = pad_b;
if (PadAMax < pad_a) { PadAMax = pad_a; }
if (PadBMax < pad_b) { PadBMax = pad_b; }
if (pad_a < PadA) { pad_a = PadA; delta_a = pad_a - bak_a; } else { delta_a = 0; }
if (pad_b < PadB) { pad_b = PadB; delta_b = pad_b - bak_b; } else { delta_b = 0; }
}
void End() { PadA = PadAMax; PadB = PadBMax; }
void Reset() { PadA = PadB = PadAMax = PadBMax = 0; }
};
struct ImPlotItem
{
ImGuiID ID;
ImU32 Color;
ImPlotMarker Marker;
ImRect LegendHoverRect;
int NameOffset;
bool Show;
bool LegendHovered;
bool SeenThisFrame;
ImPlotItem() {
ID = 0;
Color = IM_COL32_WHITE;
Marker = ImPlotMarker_None;
NameOffset = -1;
Show = true;
SeenThisFrame = false;
LegendHovered = false;
}
~ImPlotItem() { ID = 0; }
};
struct ImPlotLegend
{
ImPlotLegendFlags Flags;
ImPlotLegendFlags PreviousFlags;
ImPlotLocation Location;
ImPlotLocation PreviousLocation;
ImVec2 Scroll;
ImVector<int> Indices;
ImGuiTextBuffer Labels;
ImRect Rect;
ImRect RectClamped;
bool Hovered;
bool Held;
bool CanGoInside;
ImPlotLegend() {
Flags = PreviousFlags = ImPlotLegendFlags_None;
CanGoInside = true;
Hovered = Held = false;
Location = PreviousLocation = ImPlotLocation_NorthWest;
Scroll = ImVec2(0,0);
}
void Reset() { Indices.shrink(0); Labels.Buf.shrink(0); }
};
struct ImPlotItemGroup
{
ImGuiID ID;
ImPlotLegend Legend;
ImPool<ImPlotItem> ItemPool;
int ColormapIdx;
ImPlotMarker MarkerIdx;
ImPlotItemGroup() { ID = 0; ColormapIdx = 0; MarkerIdx = 0; }
int GetItemCount() const { return ItemPool.GetBufSize(); }
ImGuiID GetItemID(const char* label_id) { return ImGui::GetID(label_id); }
ImPlotItem* GetItem(ImGuiID id) { return ItemPool.GetByKey(id); }
ImPlotItem* GetItem(const char* label_id) { return GetItem(GetItemID(label_id)); }
ImPlotItem* GetOrAddItem(ImGuiID id) { return ItemPool.GetOrAddByKey(id); }
ImPlotItem* GetItemByIndex(int i) { return ItemPool.GetByIndex(i); }
int GetItemIndex(ImPlotItem* item) { return ItemPool.GetIndex(item); }
int GetLegendCount() const { return Legend.Indices.size(); }
ImPlotItem* GetLegendItem(int i) { return ItemPool.GetByIndex(Legend.Indices[i]); }
const char* GetLegendLabel(int i) { return Legend.Labels.Buf.Data + GetLegendItem(i)->NameOffset; }
void Reset() { ItemPool.Clear(); Legend.Reset(); ColormapIdx = 0; }
};
struct ImPlotPlot
{
ImGuiID ID;
ImPlotFlags Flags;
ImPlotFlags PreviousFlags;
ImPlotLocation MouseTextLocation;
ImPlotMouseTextFlags MouseTextFlags;
ImPlotAxis Axes[ImAxis_COUNT];
ImGuiTextBuffer TextBuffer;
ImPlotItemGroup Items;
ImAxis CurrentX;
ImAxis CurrentY;
ImRect FrameRect;
ImRect CanvasRect;
ImRect PlotRect;
ImRect AxesRect;
ImRect SelectRect;
ImVec2 SelectStart;
int TitleOffset;
bool JustCreated;
bool Initialized;
bool SetupLocked;
bool FitThisFrame;
bool Hovered;
bool Held;
bool Selecting;
bool Selected;
bool ContextLocked;
ImPlotPlot() {
Flags = PreviousFlags = ImPlotFlags_None;
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i)
XAxis(i).Vertical = false;
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i)
YAxis(i).Vertical = true;
SelectStart = ImVec2(0,0);
CurrentX = ImAxis_X1;
CurrentY = ImAxis_Y1;
MouseTextLocation = ImPlotLocation_South | ImPlotLocation_East;
MouseTextFlags = ImPlotMouseTextFlags_None;
TitleOffset = -1;
JustCreated = true;
Initialized = SetupLocked = FitThisFrame = false;
Hovered = Held = Selected = Selecting = ContextLocked = false;
}
inline bool IsInputLocked() const {
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
if (!XAxis(i).IsInputLocked())
return false;
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
if (!YAxis(i).IsInputLocked())
return false;
}
return true;
}
inline void ClearTextBuffer() { TextBuffer.Buf.shrink(0); }
inline void SetTitle(const char* title) {
if (title && ImGui::FindRenderedTextEnd(title, nullptr) != title) {
TitleOffset = TextBuffer.size();
TextBuffer.append(title, title + strlen(title) + 1);
}
else {
TitleOffset = -1;
}
}
inline bool HasTitle() const { return TitleOffset != -1 && !ImHasFlag(Flags, ImPlotFlags_NoTitle); }
inline const char* GetTitle() const { return TextBuffer.Buf.Data + TitleOffset; }
inline ImPlotAxis& XAxis(int i) { return Axes[ImAxis_X1 + i]; }
inline const ImPlotAxis& XAxis(int i) const { return Axes[ImAxis_X1 + i]; }
inline ImPlotAxis& YAxis(int i) { return Axes[ImAxis_Y1 + i]; }
inline const ImPlotAxis& YAxis(int i) const { return Axes[ImAxis_Y1 + i]; }
inline int EnabledAxesX() {
int cnt = 0;
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i)
cnt += XAxis(i).Enabled;
return cnt;
}
inline int EnabledAxesY() {
int cnt = 0;
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i)
cnt += YAxis(i).Enabled;
return cnt;
}
inline void SetAxisLabel(ImPlotAxis& axis, const char* label) {
if (label && ImGui::FindRenderedTextEnd(label, nullptr) != label) {
axis.LabelOffset = TextBuffer.size();
TextBuffer.append(label, label + strlen(label) + 1);
}
else {
axis.LabelOffset = -1;
}
}
inline const char* GetAxisLabel(const ImPlotAxis& axis) const { return TextBuffer.Buf.Data + axis.LabelOffset; }
};
struct ImPlotSubplot {
ImGuiID ID;
ImPlotSubplotFlags Flags;
ImPlotSubplotFlags PreviousFlags;
ImPlotItemGroup Items;
int Rows;
int Cols;
int CurrentIdx;
ImRect FrameRect;
ImRect GridRect;
ImVec2 CellSize;
ImVector<ImPlotAlignmentData> RowAlignmentData;
ImVector<ImPlotAlignmentData> ColAlignmentData;
ImVector<float> RowRatios;
ImVector<float> ColRatios;
ImVector<ImPlotRange> RowLinkData;
ImVector<ImPlotRange> ColLinkData;
float TempSizes[2];
bool FrameHovered;
bool HasTitle;
ImPlotSubplot() {
ID = 0;
Flags = PreviousFlags = ImPlotSubplotFlags_None;
Rows = Cols = CurrentIdx = 0;
Items.Legend.Location = ImPlotLocation_North;
Items.Legend.Flags = ImPlotLegendFlags_Horizontal|ImPlotLegendFlags_Outside;
Items.Legend.CanGoInside = false;
TempSizes[0] = TempSizes[1] = 0;
FrameHovered = false;
HasTitle = false;
}
};
struct ImPlotNextPlotData
{
ImPlotCond RangeCond[ImAxis_COUNT];
ImPlotRange Range[ImAxis_COUNT];
bool HasRange[ImAxis_COUNT];
bool Fit[ImAxis_COUNT];
double* LinkedMin[ImAxis_COUNT];
double* LinkedMax[ImAxis_COUNT];
ImPlotNextPlotData() { Reset(); }
void Reset() {
for (int i = 0; i < ImAxis_COUNT; ++i) {
HasRange[i] = false;
Fit[i] = false;
LinkedMin[i] = LinkedMax[i] = nullptr;
}
}
};
struct ImPlotNextItemData {
ImPlotSpec Spec;
bool RenderLine;
bool RenderFill;
bool RenderMarkerLine;
bool RenderMarkerFill;
bool RenderMarkers;
bool HasHidden;
bool Hidden;
ImPlotCond HiddenCond;
ImPlotNextItemData() { Reset(); }
void Reset() {
Spec = ImPlotSpec();
HasHidden = Hidden = false;
HiddenCond = ImPlotCond_None;
}
};
struct ImPlotContext {
ImPool<ImPlotPlot> Plots;
ImPool<ImPlotSubplot> Subplots;
ImPlotPlot* CurrentPlot;
ImPlotSubplot* CurrentSubplot;
ImPlotItemGroup* CurrentItems;
ImPlotItem* CurrentItem;
ImPlotItem* PreviousItem;
ImPlotTicker CTicker;
ImPlotAnnotationCollection Annotations;
ImPlotTagCollection Tags;
ImPlotStyle Style;
ImVector<ImGuiColorMod> ColorModifiers;
ImVector<ImGuiStyleMod> StyleModifiers;
ImPlotColormapData ColormapData;
ImVector<ImPlotColormap> ColormapModifiers;
tm Tm;
ImVector<double> TempDouble1, TempDouble2;
ImVector<int> TempInt1;
int DigitalPlotItemCnt;
int DigitalPlotOffset;
ImPlotNextPlotData NextPlotData;
ImPlotNextItemData NextItemData;
ImPlotInputMap InputMap;
bool OpenContextThisFrame;
ImGuiTextBuffer MousePosStringBuilder;
ImPlotItemGroup* SortItems;
ImPool<ImPlotAlignmentData> AlignmentData;
ImPlotAlignmentData* CurrentAlignmentH;
ImPlotAlignmentData* CurrentAlignmentV;
};
namespace ImPlot {
IMPLOT_API void Initialize(ImPlotContext* ctx);
IMPLOT_API void ResetCtxForNextPlot(ImPlotContext* ctx);
IMPLOT_API void ResetCtxForNextAlignedPlots(ImPlotContext* ctx);
IMPLOT_API void ResetCtxForNextSubplot(ImPlotContext* ctx);
IMPLOT_API ImPlotPlot* GetPlot(const char* title);
IMPLOT_API ImPlotPlot* GetCurrentPlot();
IMPLOT_API void BustPlotCache();
IMPLOT_API void ShowPlotContextMenu(ImPlotPlot& plot);
static inline void SetupLock() {
ImPlotContext& gp = *GImPlot;
if (!gp.CurrentPlot->SetupLocked)
SetupFinish();
gp.CurrentPlot->SetupLocked = true;
}
IMPLOT_API void SubplotNextCell();
IMPLOT_API void ShowSubplotsContextMenu(ImPlotSubplot& subplot);
IMPLOT_API bool BeginItem(const char* label_id, const ImPlotSpec& spec = ImPlotSpec(), const ImVec4& item_col = IMPLOT_AUTO_COL, ImPlotMarker item_mkr = ImPlotMarker_Invalid);
template <typename _Fitter>
bool BeginItemEx(const char* label_id, const _Fitter& fitter, const ImPlotSpec& spec, const ImVec4& item_col = IMPLOT_AUTO_COL, ImPlotMarker item_mkr = ImPlotMarker_Invalid) {
if (BeginItem(label_id, spec, item_col, item_mkr)) {
ImPlotPlot& plot = *GetCurrentPlot();
if (plot.FitThisFrame && !ImHasFlag(spec.Flags, ImPlotItemFlags_NoFit))
fitter.Fit(plot.Axes[plot.CurrentX], plot.Axes[plot.CurrentY]);
return true;
}
return false;
}
IMPLOT_API void EndItem();
IMPLOT_API ImPlotItem* RegisterOrGetItem(const char* label_id, ImPlotItemFlags flags, bool* just_created = nullptr);
IMPLOT_API ImPlotItem* GetItem(const char* label_id);
IMPLOT_API ImPlotItem* GetCurrentItem();
IMPLOT_API void BustItemCache();
static inline bool AnyAxesInputLocked(ImPlotAxis* axes, int count) {
for (int i = 0; i < count; ++i) {
if (axes[i].Enabled && axes[i].IsInputLocked())
return true;
}
return false;
}
static inline bool AllAxesInputLocked(ImPlotAxis* axes, int count) {
for (int i = 0; i < count; ++i) {
if (axes[i].Enabled && !axes[i].IsInputLocked())
return false;
}
return true;
}
static inline bool AnyAxesHeld(ImPlotAxis* axes, int count) {
for (int i = 0; i < count; ++i) {
if (axes[i].Enabled && axes[i].Held)
return true;
}
return false;
}
static inline bool AnyAxesHovered(ImPlotAxis* axes, int count) {
for (int i = 0; i < count; ++i) {
if (axes[i].Enabled && axes[i].Hovered)
return true;
}
return false;
}
static inline bool FitThisFrame() {
return GImPlot->CurrentPlot->FitThisFrame;
}
static inline void FitPointX(double x) {
ImPlotPlot& plot = *GetCurrentPlot();
ImPlotAxis& x_axis = plot.Axes[plot.CurrentX];
x_axis.ExtendFit(x);
}
static inline void FitPointY(double y) {
ImPlotPlot& plot = *GetCurrentPlot();
ImPlotAxis& y_axis = plot.Axes[plot.CurrentY];
y_axis.ExtendFit(y);
}
static inline void FitPoint(const ImPlotPoint& p) {
ImPlotPlot& plot = *GetCurrentPlot();
ImPlotAxis& x_axis = plot.Axes[plot.CurrentX];
ImPlotAxis& y_axis = plot.Axes[plot.CurrentY];
x_axis.ExtendFitWith(y_axis, p.x, p.y);
y_axis.ExtendFitWith(x_axis, p.y, p.x);
}
static inline bool RangesOverlap(const ImPlotRange& r1, const ImPlotRange& r2)
{ return r1.Min <= r2.Max && r2.Min <= r1.Max; }
IMPLOT_API void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool time_allowed = false);
IMPLOT_API ImVec2 GetLocationPos(const ImRect& outer_rect, const ImVec2& inner_size, ImPlotLocation location, const ImVec2& pad = ImVec2(0,0));
IMPLOT_API ImVec2 CalcLegendSize(ImPlotItemGroup& items, const ImVec2& pad, const ImVec2& spacing, bool vertical);
IMPLOT_API bool ClampLegendRect(ImRect& legend_rect, const ImRect& outer_rect, const ImVec2& pad);
IMPLOT_API bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, bool vertical, ImDrawList& DrawList);
IMPLOT_API void ShowAltLegend(const char* title_id, bool vertical = true, const ImVec2 size = ImVec2(0,0), bool interactable = true);
IMPLOT_API bool ShowLegendContextMenu(ImPlotLegend& legend, bool visible);
IMPLOT_API void LabelAxisValue(const ImPlotAxis& axis, double value, char* buff, int size, bool round = false);
static inline const ImPlotNextItemData& GetItemData() { return GImPlot->NextItemData; }
static inline bool IsColorAuto(const ImVec4& col) { return col.w == -1; }
static inline bool IsColorAuto(ImPlotCol idx) { return IsColorAuto(GImPlot->Style.Colors[idx]); }
IMPLOT_API ImVec4 GetAutoColor(ImPlotCol idx);
static inline ImVec4 GetStyleColorVec4(ImPlotCol idx) { return IsColorAuto(idx) ? GetAutoColor(idx) : GImPlot->Style.Colors[idx]; }
static inline ImU32 GetStyleColorU32(ImPlotCol idx) { return ImGui::ColorConvertFloat4ToU32(GetStyleColorVec4(idx)); }
IMPLOT_API void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char* text_begin, const char* text_end = nullptr);
IMPLOT_API void AddTextCentered(ImDrawList* DrawList, ImVec2 top_center, ImU32 col, const char* text_begin, const char* text_end = nullptr);
static inline ImVec2 CalcTextSizeVertical(const char *text) {
ImVec2 sz = ImGui::CalcTextSize(text);
return ImVec2(sz.y, sz.x);
}
static inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299f + bg.y * 0.587f + bg.z * 0.114f) > 0.5f ? IM_COL32_BLACK : IM_COL32_WHITE; }
static inline ImU32 CalcTextColor(ImU32 bg) { return CalcTextColor(ImGui::ColorConvertU32ToFloat4(bg)); }
static inline ImU32 CalcHoverColor(ImU32 col) { return ImMixU32(col, CalcTextColor(col), 32); }
static inline ImVec2 ClampLabelPos(ImVec2 pos, const ImVec2& size, const ImVec2& Min, const ImVec2& Max) {
if (pos.x < Min.x) pos.x = Min.x;
if (pos.y < Min.y) pos.y = Min.y;
if ((pos.x + size.x) > Max.x) pos.x = Max.x - size.x;
if ((pos.y + size.y) > Max.y) pos.y = Max.y - size.y;
return pos;
}
IMPLOT_API ImU32 GetColormapColorU32(int idx, ImPlotColormap cmap);
IMPLOT_API ImU32 NextColormapColorU32();
IMPLOT_API ImU32 SampleColormapU32(float t, ImPlotColormap cmap);
IMPLOT_API void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous);
IMPLOT_API double NiceNum(double x, bool round);
static inline int OrderOfMagnitude(double val) { return val == 0 ? 0 : (int)(floor(log10(fabs(val)))); }
static inline int OrderToPrecision(int order) { return order > 0 ? 0 : 1 - order; }
static inline int Precision(double val) { return OrderToPrecision(OrderOfMagnitude(val)); }
static inline double RoundTo(double val, int prec) { double p = pow(10,(double)prec); return floor(val*p+0.5)/p; }
static inline ImVec2 Intersection(const ImVec2& a1, const ImVec2& a2, const ImVec2& b1, const ImVec2& b2) {
float v1 = (a1.x * a2.y - a1.y * a2.x); float v2 = (b1.x * b2.y - b1.y * b2.x);
float v3 = ((a1.x - a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x - b2.x));
return ImVec2((v1 * (b1.x - b2.x) - v2 * (a1.x - a2.x)) / v3, (v1 * (b1.y - b2.y) - v2 * (a1.y - a2.y)) / v3);
}
template <typename T>
void FillRange(ImVector<T>& buffer, int n, T vmin, T vmax) {
buffer.resize(n);
T step = (vmax - vmin) / (n - 1);
for (int i = 0; i < n; ++i) {
buffer[i] = vmin + i * step;
}
}
template <typename TContainer>
static inline void CalculateBins(const TContainer& values, int count, ImPlotBin meth, const ImPlotRange& range, int& bins_out, double& width_out) {
switch (meth) {
case ImPlotBin_Sqrt:
bins_out = (int)ceil(sqrt(count));
break;
case ImPlotBin_Sturges:
bins_out = (int)ceil(1.0 + log2(count));
break;
case ImPlotBin_Rice:
bins_out = (int)ceil(2 * cbrt(count));
break;
case ImPlotBin_Scott:
width_out = 3.49 * ImStdDev(values, count) / cbrt(count);
bins_out = (int)round(range.Size() / width_out);
break;
}
width_out = range.Size() / bins_out;
}
static inline bool IsLeapYear(int year) {
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
static inline int GetDaysInMonth(int year, int month) {
constexpr int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
return days[month] + (int)(month == 1 && IsLeapYear(year));
}
IMPLOT_API ImPlotTime MkGmtTime(struct tm *ptm);
IMPLOT_API tm* GetGmtTime(const ImPlotTime& t, tm* ptm);
IMPLOT_API ImPlotTime MkLocTime(struct tm *ptm);
IMPLOT_API tm* GetLocTime(const ImPlotTime& t, tm* ptm);
static inline ImPlotTime MkTime(struct tm *ptm) {
if (GetStyle().UseLocalTime) return MkLocTime(ptm);
else return MkGmtTime(ptm);
}
static inline tm* GetTime(const ImPlotTime& t, tm* ptm) {
if (GetStyle().UseLocalTime) return GetLocTime(t,ptm);
else return GetGmtTime(t,ptm);
}
IMPLOT_API ImPlotTime MakeTime(int year, int month = 0, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0);
IMPLOT_API int GetYear(const ImPlotTime& t);
IMPLOT_API int GetMonth(const ImPlotTime& t);
IMPLOT_API ImPlotTime AddTime(const ImPlotTime& t, ImPlotTimeUnit unit, int count);
IMPLOT_API ImPlotTime FloorTime(const ImPlotTime& t, ImPlotTimeUnit unit);
IMPLOT_API ImPlotTime CeilTime(const ImPlotTime& t, ImPlotTimeUnit unit);
IMPLOT_API ImPlotTime RoundTime(const ImPlotTime& t, ImPlotTimeUnit unit);
IMPLOT_API ImPlotTime CombineDateTime(const ImPlotTime& date_part, const ImPlotTime& time_part);
static inline ImPlotTime Now() { return ImPlotTime::FromDouble((double)time(nullptr)); }
static inline ImPlotTime Today() { return ImPlot::FloorTime(Now(), ImPlotTimeUnit_Day); }
IMPLOT_API int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt, bool use_24_hr_clk);
IMPLOT_API int FormatDate(const ImPlotTime& t, char* buffer, int size, ImPlotDateFmt fmt, bool use_iso_8601);
IMPLOT_API int FormatDateTime(const ImPlotTime& t, char* buffer, int size, ImPlotDateTimeSpec fmt);
IMPLOT_API bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime* t1 = nullptr, const ImPlotTime* t2 = nullptr);
IMPLOT_API bool ShowTimePicker(const char* id, ImPlotTime* t);
static inline double TransformForward_Log10(double v, void*) {
v = v <= 0.0 ? DBL_MIN : v;
return ImLog10(v);
}
static inline double TransformInverse_Log10(double v, void*) {
return ImPow(10, v);
}
static inline double TransformForward_SymLog(double v, void*) {
return 2.0 * ImAsinh(v / 2.0);
}
static inline double TransformInverse_SymLog(double v, void*) {
return 2.0 * ImSinh(v / 2.0);
}
static inline double TransformForward_Logit(double v, void*) {
v = ImClamp(v, DBL_MIN, 1.0 - DBL_EPSILON);
return ImLog10(v / (1 - v));
}
static inline double TransformInverse_Logit(double v, void*) {
return 1.0 / (1.0 + ImPow(10,-v));
}
static inline int Formatter_Default(double value, char* buff, int size, void* data) {
char* fmt = (char*)data;
return ImFormatString(buff, size, fmt, value);
}
static inline int Formatter_Logit(double value, char* buff, int size, void*) {
if (value == 0.5)
return ImFormatString(buff,size,"1/2");
else if (value < 0.5)
return ImFormatString(buff,size,"%g", value);
else
return ImFormatString(buff,size,"1 - %g", 1 - value);
}
struct Formatter_Time_Data {
ImPlotTime Time;
ImPlotDateTimeSpec Spec;
ImPlotFormatter UserFormatter;
void* UserFormatterData;
};
static inline int Formatter_Time(double, char* buff, int size, void* data) {
Formatter_Time_Data* ftd = (Formatter_Time_Data*)data;
return FormatDateTime(ftd->Time, buff, size, ftd->Spec);
}
IMPLOT_API void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
IMPLOT_API void Locator_Time(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
IMPLOT_API void Locator_Log10(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
IMPLOT_API void Locator_SymLog(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
}
#endif