mirror of
https://github.com/gwm17/implot.git
synced 2024-11-26 20:28:50 -05:00
Merge branch 'date-picker'
This commit is contained in:
commit
fbfd41047b
499
implot.cpp
499
implot.cpp
|
@ -659,17 +659,15 @@ inline int GetTimeStep(int max_divs, ImPlotTimeUnit unit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImPlotTime MkGmtTime(struct tm *ptm) {
|
ImPlotTime MkGmtTime(struct tm *ptm) {
|
||||||
time_t secs = 0;
|
ImPlotTime t;
|
||||||
int year = ptm->tm_year + 1900;
|
#ifdef _WIN32
|
||||||
for (int y = 1970; y < year; ++y)
|
t.S = _mkgmtime(ptm);
|
||||||
secs += (IsLeapYear(y)? 366: 365) * 86400;
|
#else
|
||||||
for (int m = 0; m < ptm->tm_mon; ++m)
|
t.S = timegm(ptm);
|
||||||
secs += GetDaysInMonth(year, m) * 86400;
|
#endif
|
||||||
secs += (ptm->tm_mday - 1) * 86400;
|
if (t.S < 0)
|
||||||
secs += ptm->tm_hour * 3600;
|
t.S = 0;
|
||||||
secs += ptm->tm_min * 60;
|
return t;
|
||||||
secs += ptm->tm_sec;
|
|
||||||
return ImPlotTime(secs,0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tm* GetGmtTime(const ImPlotTime& t, tm* ptm)
|
tm* GetGmtTime(const ImPlotTime& t, tm* ptm)
|
||||||
|
@ -687,6 +685,8 @@ tm* GetGmtTime(const ImPlotTime& t, tm* ptm)
|
||||||
ImPlotTime MkLocTime(struct tm *ptm) {
|
ImPlotTime MkLocTime(struct tm *ptm) {
|
||||||
ImPlotTime t;
|
ImPlotTime t;
|
||||||
t.S = mktime(ptm);
|
t.S = mktime(ptm);
|
||||||
|
if (t.S < 0)
|
||||||
|
t.S = 0;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,6 +715,35 @@ inline tm* GetTime(const ImPlotTime& t, tm* ptm) {
|
||||||
return GetGmtTime(t,ptm);
|
return GetGmtTime(t,ptm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImPlotTime MakeTime(int year, int month, int day, int hour, int min, int sec, int us) {
|
||||||
|
tm& Tm = GImPlot->Tm;
|
||||||
|
|
||||||
|
int yr = year - 1900;
|
||||||
|
if (yr < 0)
|
||||||
|
yr = 0;
|
||||||
|
|
||||||
|
sec = sec + us / 1000000;
|
||||||
|
us = us % 1000000;
|
||||||
|
|
||||||
|
Tm.tm_sec = sec;
|
||||||
|
Tm.tm_min = min;
|
||||||
|
Tm.tm_hour = hour;
|
||||||
|
Tm.tm_mday = day;
|
||||||
|
Tm.tm_mon = month;
|
||||||
|
Tm.tm_year = yr;
|
||||||
|
|
||||||
|
ImPlotTime t = MkTime(&Tm);
|
||||||
|
|
||||||
|
t.Us = us;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetYear(const ImPlotTime& t) {
|
||||||
|
tm& Tm = GImPlot->Tm;
|
||||||
|
GetTime(t, &Tm);
|
||||||
|
return Tm.tm_year + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
ImPlotTime AddTime(const ImPlotTime& t, ImPlotTimeUnit unit, int count) {
|
ImPlotTime AddTime(const ImPlotTime& t, ImPlotTimeUnit unit, int count) {
|
||||||
tm& Tm = GImPlot->Tm;
|
tm& Tm = GImPlot->Tm;
|
||||||
ImPlotTime t_out = t;
|
ImPlotTime t_out = t;
|
||||||
|
@ -725,16 +754,20 @@ ImPlotTime AddTime(const ImPlotTime& t, ImPlotTimeUnit unit, int count) {
|
||||||
case ImPlotTimeUnit_Min: t_out.S += count * 60; break;
|
case ImPlotTimeUnit_Min: t_out.S += count * 60; break;
|
||||||
case ImPlotTimeUnit_Hr: t_out.S += count * 3600; break;
|
case ImPlotTimeUnit_Hr: t_out.S += count * 3600; break;
|
||||||
case ImPlotTimeUnit_Day: t_out.S += count * 86400; break;
|
case ImPlotTimeUnit_Day: t_out.S += count * 86400; break;
|
||||||
case ImPlotTimeUnit_Mo: for (int i = 0; i < count; ++i) { // this might have a bug
|
case ImPlotTimeUnit_Mo: for (int i = 0; i < abs(count); ++i) {
|
||||||
GetTime(t_out, &Tm);
|
GetTime(t_out, &Tm);
|
||||||
|
if (count > 0)
|
||||||
t_out.S += 86400 * GetDaysInMonth(Tm.tm_year + 1900, Tm.tm_mon);
|
t_out.S += 86400 * GetDaysInMonth(Tm.tm_year + 1900, Tm.tm_mon);
|
||||||
|
else if (count < 0)
|
||||||
|
t_out.S -= 86400 * GetDaysInMonth(Tm.tm_year + 1900 - (Tm.tm_mon == 0 ? 1 : 0), Tm.tm_mon == 0 ? 11 : Tm.tm_mon - 1); // NOT WORKING
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ImPlotTimeUnit_Yr: for (int i = 0; i < count; ++i) {
|
case ImPlotTimeUnit_Yr: for (int i = 0; i < abs(count); ++i) {
|
||||||
if (IsLeapYear(GetYear(t_out)))
|
if (count > 0)
|
||||||
t_out.S += 366 * 86400;
|
t_out.S += 86400 * (365 + (int)IsLeapYear(GetYear(t_out)));
|
||||||
else
|
else if (count < 0)
|
||||||
t_out.S += 365 * 86400;
|
t_out.S -= 86400 * (365 + (int)IsLeapYear(GetYear(t_out) - 1));
|
||||||
|
// this is incorrect if leap year and we are past Feb 28
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -771,25 +804,19 @@ ImPlotTime RoundTime(const ImPlotTime& t, ImPlotTimeUnit unit) {
|
||||||
return t.S - t1.S < t2.S - t.S ? t1 : t2;
|
return t.S - t1.S < t2.S - t.S ? t1 : t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetYear(const ImPlotTime& t) {
|
ImPlotTime CombineDateTime(const ImPlotTime& date_part, const ImPlotTime& tod_part) {
|
||||||
tm& Tm = GImPlot->Tm;
|
tm& Tm = GImPlot->Tm;
|
||||||
GetTime(t, &Tm);
|
GetTime(date_part, &GImPlot->Tm);
|
||||||
return Tm.tm_year + 1900;
|
int y = Tm.tm_year;
|
||||||
}
|
int m = Tm.tm_mon;
|
||||||
|
int d = Tm.tm_mday;
|
||||||
ImPlotTime MakeYear(int year) {
|
GetTime(tod_part, &GImPlot->Tm);
|
||||||
int yr = year - 1900;
|
Tm.tm_year = y;
|
||||||
if (yr < 0)
|
Tm.tm_mon = m;
|
||||||
yr = 0;
|
Tm.tm_mday = d;
|
||||||
tm& Tm = GImPlot->Tm;
|
ImPlotTime t = MkTime(&Tm);
|
||||||
Tm.tm_sec = 0;
|
t.Us = tod_part.Us;
|
||||||
Tm.tm_min = 0;
|
return t;
|
||||||
Tm.tm_hour = 0;
|
|
||||||
Tm.tm_mday = 1;
|
|
||||||
Tm.tm_mon = 0;
|
|
||||||
Tm.tm_year = yr;
|
|
||||||
Tm.tm_sec = 0;
|
|
||||||
return MkTime(&Tm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt) {
|
int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt) {
|
||||||
|
@ -823,6 +850,7 @@ int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt) {
|
||||||
case ImPlotTimeFmt_DayMoYr: return snprintf(buffer, size, "%d/%d/%02d", mon, day, yr);
|
case ImPlotTimeFmt_DayMoYr: return snprintf(buffer, size, "%d/%d/%02d", mon, day, yr);
|
||||||
case ImPlotTimeFmt_DayMoYrHrMin: return snprintf(buffer, size, "%d/%d/%02d %d:%02d%s", mon, day, yr, hr, min, ap);
|
case ImPlotTimeFmt_DayMoYrHrMin: return snprintf(buffer, size, "%d/%d/%02d %d:%02d%s", mon, day, yr, hr, min, ap);
|
||||||
case ImPlotTimeFmt_DayMoYrHrMinS: return snprintf(buffer, size, "%d/%d/%02d %d:%02d:%02d%s", mon, day, yr, hr, min, sec, ap);
|
case ImPlotTimeFmt_DayMoYrHrMinS: return snprintf(buffer, size, "%d/%d/%02d %d:%02d:%02d%s", mon, day, yr, hr, min, sec, ap);
|
||||||
|
case ImPlotTimeFmt_DayMoYrHrMinSUs: return snprintf(buffer, size, "%d/%d/%d %d:%02d:%02d.%03d%03d%s", mon, day, year, hr, min, sec, ms, us, ap);
|
||||||
case ImPlotTimeFmt_MoYr: return snprintf(buffer, size, "%s %d", mnames[Tm.tm_mon], year);
|
case ImPlotTimeFmt_MoYr: return snprintf(buffer, size, "%s %d", mnames[Tm.tm_mon], year);
|
||||||
case ImPlotTimeFmt_Mo: return snprintf(buffer, size, "%s", mnames[Tm.tm_mon]);
|
case ImPlotTimeFmt_Mo: return snprintf(buffer, size, "%s", mnames[Tm.tm_mon]);
|
||||||
case ImPlotTimeFmt_Yr: return snprintf(buffer, size, "%d", year);
|
case ImPlotTimeFmt_Yr: return snprintf(buffer, size, "%d", year);
|
||||||
|
@ -852,6 +880,7 @@ inline float GetTimeLabelWidth(ImPlotTimeFmt fmt) {
|
||||||
case ImPlotTimeFmt_DayMoYr: return ImGui::CalcTextSize("88/88/88").x; // 10/3/1991
|
case ImPlotTimeFmt_DayMoYr: return ImGui::CalcTextSize("88/88/88").x; // 10/3/1991
|
||||||
case ImPlotTimeFmt_DayMoYrHrMin: return ImGui::CalcTextSize("88/88/88 88:88pm").x; // 10/3/91 7:21pm
|
case ImPlotTimeFmt_DayMoYrHrMin: return ImGui::CalcTextSize("88/88/88 88:88pm").x; // 10/3/91 7:21pm
|
||||||
case ImPlotTimeFmt_DayMoYrHrMinS: return ImGui::CalcTextSize("88/88/88 88:88:88pm").x; // 10/3/91 7:21:29pm
|
case ImPlotTimeFmt_DayMoYrHrMinS: return ImGui::CalcTextSize("88/88/88 88:88:88pm").x; // 10/3/91 7:21:29pm
|
||||||
|
case ImPlotTimeFmt_DayMoYrHrMinSUs: return ImGui::CalcTextSize("88/88/8888 88:88:88.888888pm").x; // 10/3/1991 7:21:29.123456pm
|
||||||
case ImPlotTimeFmt_MoYr: return ImGui::CalcTextSize("MMM 8888").x; // Oct 1991
|
case ImPlotTimeFmt_MoYr: return ImGui::CalcTextSize("MMM 8888").x; // Oct 1991
|
||||||
case ImPlotTimeFmt_Mo: return ImGui::CalcTextSize("MMM").x; // Oct
|
case ImPlotTimeFmt_Mo: return ImGui::CalcTextSize("MMM").x; // Oct
|
||||||
case ImPlotTimeFmt_Yr: return ImGui::CalcTextSize("8888").x; // 1991
|
case ImPlotTimeFmt_Yr: return ImGui::CalcTextSize("8888").x; // 1991
|
||||||
|
@ -1004,7 +1033,7 @@ void AddTicksTime(const ImPlotRange& range, float plot_width, ImPlotTickCollecti
|
||||||
const int step = (int)interval <= 0 ? 1 : (int)interval;
|
const int step = (int)interval <= 0 ? 1 : (int)interval;
|
||||||
|
|
||||||
for (int y = graphmin; y < graphmax; y += step) {
|
for (int y = graphmin; y < graphmax; y += step) {
|
||||||
ImPlotTime t = MakeYear(y);
|
ImPlotTime t = MakeTime(y);
|
||||||
if (t >= t_min && t <= t_max) {
|
if (t >= t_min && t <= t_max) {
|
||||||
ImPlotTick tick(t.ToDouble(), true, true);
|
ImPlotTick tick(t.ToDouble(), true, true);
|
||||||
tick.Level = 0;
|
tick.Level = 0;
|
||||||
|
@ -1661,63 +1690,115 @@ inline void EndDisabledControls(bool cond) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ShowAxisContextMenu(ImPlotAxisState& state, bool time_allowed) {
|
void ShowAxisContextMenu(ImPlotAxisState& state, bool time_allowed) {
|
||||||
|
|
||||||
ImGui::PushItemWidth(75);
|
ImGui::PushItemWidth(75);
|
||||||
|
ImPlotAxis& axis = *state.Axis;
|
||||||
bool total_lock = state.HasRange && state.RangeCond == ImGuiCond_Always;
|
bool total_lock = state.HasRange && state.RangeCond == ImGuiCond_Always;
|
||||||
bool logscale = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale);
|
bool logscale = ImHasFlag(axis.Flags, ImPlotAxisFlags_LogScale);
|
||||||
bool timescale = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_Time);
|
bool timescale = ImHasFlag(axis.Flags, ImPlotAxisFlags_Time);
|
||||||
bool grid = !ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_NoGridLines);
|
bool grid = !ImHasFlag(axis.Flags, ImPlotAxisFlags_NoGridLines);
|
||||||
bool ticks = !ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_NoTickMarks);
|
bool ticks = !ImHasFlag(axis.Flags, ImPlotAxisFlags_NoTickMarks);
|
||||||
bool labels = !ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_NoTickLabels);
|
bool labels = !ImHasFlag(axis.Flags, ImPlotAxisFlags_NoTickLabels);
|
||||||
double drag_speed = (state.Axis->Range.Size() <= DBL_EPSILON) ? DBL_EPSILON * 1.0e+13 : 0.01 * state.Axis->Range.Size(); // recover from almost equal axis limits.
|
double drag_speed = (axis.Range.Size() <= DBL_EPSILON) ? DBL_EPSILON * 1.0e+13 : 0.01 * axis.Range.Size(); // recover from almost equal axis limits.
|
||||||
|
|
||||||
|
if (timescale) {
|
||||||
|
ImPlotTime tmin = ImPlotTime::FromDouble(axis.Range.Min);
|
||||||
|
ImPlotTime tmax = ImPlotTime::FromDouble(axis.Range.Max);
|
||||||
|
|
||||||
BeginDisabledControls(total_lock);
|
BeginDisabledControls(total_lock);
|
||||||
if (ImGui::Checkbox("##LockMin", &state.LockMin))
|
if (ImGui::Checkbox("##LockMin", &state.LockMin))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_LockMin);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_LockMin);
|
||||||
EndDisabledControls(total_lock);
|
EndDisabledControls(total_lock);
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
BeginDisabledControls(state.LockMin);
|
BeginDisabledControls(state.LockMin);
|
||||||
double temp_min = state.Axis->Range.Min;
|
if (ImGui::BeginMenu("Min Time")) {
|
||||||
if (DragFloat("Min", &temp_min, (float)drag_speed, -HUGE_VAL, state.Axis->Range.Max - DBL_EPSILON))
|
if (ShowTimePicker("mintime", &tmin)) {
|
||||||
state.Axis->SetMin(temp_min);
|
if (tmin >= tmax)
|
||||||
|
tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
|
||||||
|
axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ShowDatePicker("mindate",&axis.PickerLevel,&axis.PickerTimeMin,&tmin,&tmax)) {
|
||||||
|
tmin = CombineDateTime(axis.PickerTimeMin, tmin);
|
||||||
|
if (tmin >= tmax)
|
||||||
|
tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
|
||||||
|
axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
EndDisabledControls(state.LockMin);
|
EndDisabledControls(state.LockMin);
|
||||||
|
|
||||||
BeginDisabledControls(total_lock);
|
BeginDisabledControls(total_lock);
|
||||||
if (ImGui::Checkbox("##LockMax", &state.LockMax))
|
if (ImGui::Checkbox("##LockMax", &state.LockMax))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_LockMax);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_LockMax);
|
||||||
EndDisabledControls(total_lock);
|
EndDisabledControls(total_lock);
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
BeginDisabledControls(state.LockMax);
|
BeginDisabledControls(state.LockMax);
|
||||||
double temp_max = state.Axis->Range.Max;
|
if (ImGui::BeginMenu("Max Time")) {
|
||||||
if (DragFloat("Max", &temp_max, (float)drag_speed, state.Axis->Range.Min + DBL_EPSILON, HUGE_VAL))
|
if (ShowTimePicker("maxtime", &tmax)) {
|
||||||
state.Axis->SetMax(temp_max);
|
if (tmax <= tmin)
|
||||||
|
tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
|
||||||
|
axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ShowDatePicker("maxdate",&axis.PickerLevel,&axis.PickerTimeMax,&tmin,&tmax)) {
|
||||||
|
tmax = CombineDateTime(axis.PickerTimeMax, tmax);
|
||||||
|
if (tmax <= tmin)
|
||||||
|
tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
|
||||||
|
axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
EndDisabledControls(state.LockMax);
|
EndDisabledControls(state.LockMax);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BeginDisabledControls(total_lock);
|
||||||
|
if (ImGui::Checkbox("##LockMin", &state.LockMin))
|
||||||
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_LockMin);
|
||||||
|
EndDisabledControls(total_lock);
|
||||||
|
ImGui::SameLine();
|
||||||
|
BeginDisabledControls(state.LockMin);
|
||||||
|
double temp_min = axis.Range.Min;
|
||||||
|
if (DragFloat("Min", &temp_min, (float)drag_speed, -HUGE_VAL, axis.Range.Max - DBL_EPSILON))
|
||||||
|
axis.SetMin(temp_min);
|
||||||
|
EndDisabledControls(state.LockMin);
|
||||||
|
|
||||||
|
BeginDisabledControls(total_lock);
|
||||||
|
if (ImGui::Checkbox("##LockMax", &state.LockMax))
|
||||||
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_LockMax);
|
||||||
|
EndDisabledControls(total_lock);
|
||||||
|
ImGui::SameLine();
|
||||||
|
BeginDisabledControls(state.LockMax);
|
||||||
|
double temp_max = axis.Range.Max;
|
||||||
|
if (DragFloat("Max", &temp_max, (float)drag_speed, axis.Range.Min + DBL_EPSILON, HUGE_VAL))
|
||||||
|
axis.SetMax(temp_max);
|
||||||
|
EndDisabledControls(state.LockMax);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (ImGui::Checkbox("Invert", &state.Invert))
|
if (ImGui::Checkbox("Invert", &state.Invert))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_Invert);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_Invert);
|
||||||
BeginDisabledControls(timescale && time_allowed);
|
BeginDisabledControls(timescale && time_allowed);
|
||||||
if (ImGui::Checkbox("Log Scale", &logscale))
|
if (ImGui::Checkbox("Log Scale", &logscale))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_LogScale);
|
||||||
EndDisabledControls(timescale && time_allowed);
|
EndDisabledControls(timescale && time_allowed);
|
||||||
|
|
||||||
if (time_allowed) {
|
if (time_allowed) {
|
||||||
BeginDisabledControls(logscale);
|
BeginDisabledControls(logscale);
|
||||||
if (ImGui::Checkbox("Time", ×cale))
|
if (ImGui::Checkbox("Time", ×cale))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_Time);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_Time);
|
||||||
EndDisabledControls(logscale);
|
EndDisabledControls(logscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::Checkbox("Grid Lines", &grid))
|
if (ImGui::Checkbox("Grid Lines", &grid))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_NoGridLines);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoGridLines);
|
||||||
if (ImGui::Checkbox("Tick Marks", &ticks))
|
if (ImGui::Checkbox("Tick Marks", &ticks))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_NoTickMarks);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickMarks);
|
||||||
if (ImGui::Checkbox("Labels", &labels))
|
if (ImGui::Checkbox("Labels", &labels))
|
||||||
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_NoTickLabels);
|
ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickLabels);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3109,6 +3190,306 @@ void ShowUserGuide() {
|
||||||
ImGui::BulletText("Click legend label icons to show/hide plot items.");
|
ImGui::BulletText("Click legend label icons to show/hide plot items.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime* t1, const ImPlotTime* t2) {
|
||||||
|
|
||||||
|
ImGui::PushID(id);
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
|
||||||
|
|
||||||
|
static const char* names_mo[] = {"January","February","March","April","May","June","July","August","September","October","November","December"};
|
||||||
|
static const char* abrvs_mo[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
|
||||||
|
static const char* abrvs_wd[] = {"Su","Mo","Tu","We","Th","Fr","Sa"};
|
||||||
|
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
ImVec4 col_txt = style.Colors[ImGuiCol_Text];
|
||||||
|
ImVec4 col_dis = style.Colors[ImGuiCol_TextDisabled];
|
||||||
|
const float ht = ImGui::GetFrameHeight();
|
||||||
|
ImVec2 cell_size(ht*1.25f,ht);
|
||||||
|
char buff[32];
|
||||||
|
bool clk = false;
|
||||||
|
tm& Tm = GImPlot->Tm;
|
||||||
|
|
||||||
|
const int min_yr = 1970;
|
||||||
|
const int max_yr = 2999;
|
||||||
|
|
||||||
|
// t1 parts
|
||||||
|
int t1_mo = 0; int t1_md = 0; int t1_yr = 0;
|
||||||
|
if (t1 != NULL) {
|
||||||
|
GetTime(*t1,&Tm);
|
||||||
|
t1_mo = Tm.tm_mon;
|
||||||
|
t1_md = Tm.tm_mday;
|
||||||
|
t1_yr = Tm.tm_year + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
// t2 parts
|
||||||
|
int t2_mo = 0; int t2_md = 0; int t2_yr = 0;
|
||||||
|
if (t2 != NULL) {
|
||||||
|
GetTime(*t2,&Tm);
|
||||||
|
t2_mo = Tm.tm_mon;
|
||||||
|
t2_md = Tm.tm_mday;
|
||||||
|
t2_yr = Tm.tm_year + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
// day widget
|
||||||
|
if (*level == 0) {
|
||||||
|
*t = FloorTime(*t, ImPlotTimeUnit_Day);
|
||||||
|
GetTime(*t, &Tm);
|
||||||
|
const int this_year = Tm.tm_year + 1900;
|
||||||
|
const int last_year = this_year - 1;
|
||||||
|
const int next_year = this_year + 1;
|
||||||
|
const int this_mon = Tm.tm_mon;
|
||||||
|
const int last_mon = this_mon == 0 ? 11 : this_mon - 1;
|
||||||
|
const int next_mon = this_mon == 11 ? 0 : this_mon + 1;
|
||||||
|
const int days_this_mo = GetDaysInMonth(this_year, this_mon);
|
||||||
|
const int days_last_mo = GetDaysInMonth(this_mon == 0 ? last_year : this_year, last_mon);
|
||||||
|
ImPlotTime t_first_mo = FloorTime(*t,ImPlotTimeUnit_Mo);
|
||||||
|
GetTime(t_first_mo,&Tm);
|
||||||
|
const int first_wd = Tm.tm_wday;
|
||||||
|
// month year
|
||||||
|
snprintf(buff, 32, "%s %d", names_mo[this_mon], this_year);
|
||||||
|
if (ImGui::Button(buff))
|
||||||
|
*level = 1;
|
||||||
|
ImGui::SameLine(5*cell_size.x);
|
||||||
|
BeginDisabledControls(this_year <= min_yr && this_mon == 0);
|
||||||
|
if (ImGui::ArrowButtonEx("##Up",ImGuiDir_Up,cell_size))
|
||||||
|
*t = AddTime(*t, ImPlotTimeUnit_Mo, -1);
|
||||||
|
EndDisabledControls(this_year <= min_yr && this_mon == 0);
|
||||||
|
ImGui::SameLine();
|
||||||
|
BeginDisabledControls(this_year >= max_yr && this_mon == 11);
|
||||||
|
if (ImGui::ArrowButtonEx("##Down",ImGuiDir_Down,cell_size))
|
||||||
|
*t = AddTime(*t, ImPlotTimeUnit_Mo, 1);
|
||||||
|
EndDisabledControls(this_year >= max_yr && this_mon == 11);
|
||||||
|
// render weekday abbreviations
|
||||||
|
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
|
||||||
|
for (int i = 0; i < 7; ++i) {
|
||||||
|
ImGui::Button(abrvs_wd[i],cell_size);
|
||||||
|
if (i != 6) { ImGui::SameLine(); }
|
||||||
|
}
|
||||||
|
ImGui::PopItemFlag();
|
||||||
|
// 0 = last mo, 1 = this mo, 2 = next mo
|
||||||
|
int mo = first_wd > 0 ? 0 : 1;
|
||||||
|
int day = mo == 1 ? 1 : days_last_mo - first_wd + 1;
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
for (int j = 0; j < 7; ++j) {
|
||||||
|
if (mo == 0 && day > days_last_mo) {
|
||||||
|
mo = 1; day = 1;
|
||||||
|
}
|
||||||
|
else if (mo == 1 && day > days_this_mo) {
|
||||||
|
mo = 2; day = 1;
|
||||||
|
}
|
||||||
|
const int now_yr = (mo == 0 && this_mon == 0) ? last_year : ((mo == 2 && this_mon == 11) ? next_year : this_year);
|
||||||
|
const int now_mo = mo == 0 ? last_mon : (mo == 1 ? this_mon : next_mon);
|
||||||
|
const int now_md = day;
|
||||||
|
|
||||||
|
const bool off_mo = mo == 0 || mo == 2;
|
||||||
|
const bool t1_or_t2 = (t1 != NULL && t1_mo == now_mo && t1_yr == now_yr && t1_md == now_md) ||
|
||||||
|
(t2 != NULL && t2_mo == now_mo && t2_yr == now_yr && t2_md == now_md);
|
||||||
|
|
||||||
|
if (off_mo)
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, col_dis);
|
||||||
|
if (t1_or_t2) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, col_dis);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, col_txt);
|
||||||
|
}
|
||||||
|
ImGui::PushID(i*7+j);
|
||||||
|
snprintf(buff,32,"%d",day);
|
||||||
|
if (now_yr == min_yr-1 || now_yr == max_yr+1) {
|
||||||
|
ImGui::Dummy(cell_size);
|
||||||
|
}
|
||||||
|
else if (ImGui::Button(buff,cell_size) && !clk) {
|
||||||
|
*t = MakeTime(now_yr, now_mo, now_md);
|
||||||
|
clk = true;
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
if (t1_or_t2)
|
||||||
|
ImGui::PopStyleColor(2);
|
||||||
|
if (off_mo)
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
if (j != 6)
|
||||||
|
ImGui::SameLine();
|
||||||
|
day++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// month widget
|
||||||
|
else if (*level == 1) {
|
||||||
|
*t = FloorTime(*t, ImPlotTimeUnit_Mo);
|
||||||
|
GetTime(*t, &Tm);
|
||||||
|
int this_yr = Tm.tm_year + 1900;
|
||||||
|
snprintf(buff, 32, "%d", this_yr);
|
||||||
|
if (ImGui::Button(buff))
|
||||||
|
*level = 2;
|
||||||
|
BeginDisabledControls(this_yr <= min_yr);
|
||||||
|
ImGui::SameLine(5*cell_size.x);
|
||||||
|
if (ImGui::ArrowButtonEx("##Up",ImGuiDir_Up,cell_size))
|
||||||
|
*t = AddTime(*t, ImPlotTimeUnit_Yr, -1);
|
||||||
|
EndDisabledControls(this_yr <= min_yr);
|
||||||
|
ImGui::SameLine();
|
||||||
|
BeginDisabledControls(this_yr >= max_yr);
|
||||||
|
if (ImGui::ArrowButtonEx("##Down",ImGuiDir_Down,cell_size))
|
||||||
|
*t = AddTime(*t, ImPlotTimeUnit_Yr, 1);
|
||||||
|
EndDisabledControls(this_yr >= max_yr);
|
||||||
|
// ImGui::Dummy(cell_size);
|
||||||
|
cell_size.x *= 7.0f/4.0f;
|
||||||
|
cell_size.y *= 7.0f/3.0f;
|
||||||
|
int mo = 0;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
const bool t1_or_t2 = (t1 != NULL && t1_yr == this_yr && t1_mo == mo) ||
|
||||||
|
(t2 != NULL && t2_yr == this_yr && t2_mo == mo);
|
||||||
|
if (t1_or_t2)
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, col_dis);
|
||||||
|
if (ImGui::Button(abrvs_mo[mo],cell_size) && !clk) {
|
||||||
|
*t = MakeTime(this_yr, mo);
|
||||||
|
*level = 0;
|
||||||
|
}
|
||||||
|
if (t1_or_t2)
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
if (j != 3)
|
||||||
|
ImGui::SameLine();
|
||||||
|
mo++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*level == 2) {
|
||||||
|
*t = FloorTime(*t, ImPlotTimeUnit_Yr);
|
||||||
|
int this_yr = GetYear(*t);
|
||||||
|
int yr = this_yr - this_yr % 20;
|
||||||
|
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
|
||||||
|
snprintf(buff,32,"%d-%d",yr,yr+19);
|
||||||
|
ImGui::Button(buff);
|
||||||
|
ImGui::PopItemFlag();
|
||||||
|
ImGui::SameLine(5*cell_size.x);
|
||||||
|
BeginDisabledControls(yr <= min_yr);
|
||||||
|
if (ImGui::ArrowButtonEx("##Up",ImGuiDir_Up,cell_size))
|
||||||
|
*t = MakeTime(yr-20);
|
||||||
|
EndDisabledControls(yr <= min_yr);
|
||||||
|
ImGui::SameLine();
|
||||||
|
BeginDisabledControls(yr + 20 >= max_yr);
|
||||||
|
if (ImGui::ArrowButtonEx("##Down",ImGuiDir_Down,cell_size))
|
||||||
|
*t = MakeTime(yr+20);
|
||||||
|
EndDisabledControls(yr+ 20 >= max_yr);
|
||||||
|
// ImGui::Dummy(cell_size);
|
||||||
|
cell_size.x *= 7.0f/4.0f;
|
||||||
|
cell_size.y *= 7.0f/5.0f;
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
const bool t1_or_t2 = (t1 != NULL && t1_yr == yr) || (t2 != NULL && t2_yr == yr);
|
||||||
|
if (t1_or_t2)
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, col_dis);
|
||||||
|
snprintf(buff,32,"%d",yr);
|
||||||
|
if (yr<1970||yr>3000) {
|
||||||
|
ImGui::Dummy(cell_size);
|
||||||
|
}
|
||||||
|
else if (ImGui::Button(buff,cell_size)) {
|
||||||
|
*t = MakeTime(yr);
|
||||||
|
*level = 1;
|
||||||
|
}
|
||||||
|
if (t1_or_t2)
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
if (j != 3)
|
||||||
|
ImGui::SameLine();
|
||||||
|
yr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::EndGroup();
|
||||||
|
ImGui::PopID();
|
||||||
|
return clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShowTimePicker(const char* id, ImPlotTime* t) {
|
||||||
|
ImGui::PushID(id);
|
||||||
|
tm& Tm = GImPlot->Tm;
|
||||||
|
GetTime(*t,&Tm);
|
||||||
|
|
||||||
|
static const char* nums[] = { "00","01","02","03","04","05","06","07","08","09",
|
||||||
|
"10","11","12","13","14","15","16","17","18","19",
|
||||||
|
"20","21","22","23","24","25","26","27","28","29",
|
||||||
|
"30","31","32","33","34","35","36","37","38","39",
|
||||||
|
"40","41","42","43","44","45","46","47","48","49",
|
||||||
|
"50","51","52","53","54","55","56","57","58","59"};
|
||||||
|
|
||||||
|
static const char* am_pm[] = {"am","pm"};
|
||||||
|
|
||||||
|
int hr = (Tm.tm_hour == 0 || Tm.tm_hour == 12) ? 12 : Tm.tm_hour % 12;
|
||||||
|
int min = Tm.tm_min;
|
||||||
|
int sec = Tm.tm_sec;
|
||||||
|
int ap = Tm.tm_hour < 12 ? 0 : 1;
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
ImVec2 spacing = ImGui::GetStyle().ItemSpacing;
|
||||||
|
spacing.x = 0;
|
||||||
|
float width = ImGui::CalcTextSize("888").x;
|
||||||
|
float height = ImGui::GetFrameHeight();
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, spacing);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize,2.0f);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered));
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(width);
|
||||||
|
if (ImGui::BeginCombo("##hr",nums[hr],ImGuiComboFlags_NoArrowButton)) {
|
||||||
|
for (int i = 1; i < 13; ++i) {
|
||||||
|
if (ImGui::Selectable(nums[i],i==hr)) {
|
||||||
|
hr = i;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(":");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(width);
|
||||||
|
if (ImGui::BeginCombo("##min",nums[min],ImGuiComboFlags_NoArrowButton)) {
|
||||||
|
for (int i = 0; i < 60; ++i) {
|
||||||
|
if (ImGui::Selectable(nums[i],i==min)) {
|
||||||
|
min = i;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(":");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(width);
|
||||||
|
if (ImGui::BeginCombo("##sec",nums[sec],ImGuiComboFlags_NoArrowButton)) {
|
||||||
|
for (int i = 0; i < 60; ++i) {
|
||||||
|
if (ImGui::Selectable(nums[i],i==sec)) {
|
||||||
|
sec = i;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(am_pm[ap],ImVec2(height,height))) {
|
||||||
|
ap = 1 - ap;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
hr = hr % 12 + ap * 12;
|
||||||
|
Tm.tm_hour = hr;
|
||||||
|
Tm.tm_min = min;
|
||||||
|
Tm.tm_sec = sec;
|
||||||
|
*t = MkTime(&Tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
void StyleColorsAuto(ImPlotStyle* dst) {
|
void StyleColorsAuto(ImPlotStyle* dst) {
|
||||||
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
|
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
|
||||||
ImVec4* colors = style->Colors;
|
ImVec4* colors = style->Colors;
|
||||||
|
|
|
@ -623,7 +623,7 @@ void ShowDemoWindow(bool* p_open) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImPlot::SetNextPlotLimits(t_min,t_max,0,1);
|
ImPlot::SetNextPlotLimits(t_min,t_max,0,1);
|
||||||
if (ImPlot::BeginPlot("##Time", "Time", "Value", ImVec2(-1,0), 0, ImPlotAxisFlags_Time)) {
|
if (ImPlot::BeginPlot("##Time", NULL, NULL, ImVec2(-1,0), 0, ImPlotAxisFlags_Time)) {
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
// downsample our data
|
// downsample our data
|
||||||
int downsample = (int)ImPlot::GetPlotLimits().X.Size() / 1000 + 1;
|
int downsample = (int)ImPlot::GetPlotLimits().X.Size() / 1000 + 1;
|
||||||
|
@ -1212,7 +1212,7 @@ void ShowDemoWindow(bool* p_open) {
|
||||||
ImGui::SameLine(); ImGui::ColorEdit4("##Bear", &bearCol.x, ImGuiColorEditFlags_NoInputs);
|
ImGui::SameLine(); ImGui::ColorEdit4("##Bear", &bearCol.x, ImGuiColorEditFlags_NoInputs);
|
||||||
ImPlot::GetStyle().UseLocalTime = false;
|
ImPlot::GetStyle().UseLocalTime = false;
|
||||||
ImPlot::SetNextPlotLimits(1546300800, 1571961600, 1250, 1600);
|
ImPlot::SetNextPlotLimits(1546300800, 1571961600, 1250, 1600);
|
||||||
if (ImPlot::BeginPlot("Candlestick Chart","Day","USD",ImVec2(-1,0),0,ImPlotAxisFlags_Time)) {
|
if (ImPlot::BeginPlot("Candlestick Chart","Day","USD",ImVec2(-1,-1),0,ImPlotAxisFlags_Time)) {
|
||||||
MyImPlot::PlotCandlestick("GOOGL",dates, opens, closes, lows, highs, 218, tooltip, 0.25f, bullCol, bearCol);
|
MyImPlot::PlotCandlestick("GOOGL",dates, opens, closes, lows, highs, 218, tooltip, 0.25f, bullCol, bearCol);
|
||||||
ImPlot::EndPlot();
|
ImPlot::EndPlot();
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,6 +196,7 @@ enum ImPlotTimeFmt_ {
|
||||||
ImPlotTimeFmt_DayMoYr, // 10/3/91
|
ImPlotTimeFmt_DayMoYr, // 10/3/91
|
||||||
ImPlotTimeFmt_DayMoYrHrMin, // 10/3/91 7:21pm
|
ImPlotTimeFmt_DayMoYrHrMin, // 10/3/91 7:21pm
|
||||||
ImPlotTimeFmt_DayMoYrHrMinS, // 10/3/91 7:21:29pm
|
ImPlotTimeFmt_DayMoYrHrMinS, // 10/3/91 7:21:29pm
|
||||||
|
ImPlotTimeFmt_DayMoYrHrMinSUs, // 10/3/1991 7:21:29.123456pm
|
||||||
ImPlotTimeFmt_MoYr, // Oct 1991
|
ImPlotTimeFmt_MoYr, // Oct 1991
|
||||||
ImPlotTimeFmt_Mo, // Oct
|
ImPlotTimeFmt_Mo, // Oct
|
||||||
ImPlotTimeFmt_Yr // 1991
|
ImPlotTimeFmt_Yr // 1991
|
||||||
|
@ -205,6 +206,32 @@ enum ImPlotTimeFmt_ {
|
||||||
// [SECTION] ImPlot Structs
|
// [SECTION] ImPlot Structs
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Two part timestamp struct.
|
||||||
|
struct ImPlotTime {
|
||||||
|
time_t S; // second part
|
||||||
|
int Us; // microsecond part
|
||||||
|
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; }
|
||||||
|
|
||||||
// Storage for colormap modifiers
|
// Storage for colormap modifiers
|
||||||
struct ImPlotColormapMod {
|
struct ImPlotColormapMod {
|
||||||
ImPlotColormapMod(const ImVec4* colormap, int colormap_size) {
|
ImPlotColormapMod(const ImVec4* colormap, int colormap_size) {
|
||||||
|
@ -297,6 +324,8 @@ struct ImPlotAxis
|
||||||
bool HoveredTot;
|
bool HoveredTot;
|
||||||
double* LinkedMin;
|
double* LinkedMin;
|
||||||
double* LinkedMax;
|
double* LinkedMax;
|
||||||
|
ImPlotTime PickerTimeMin, PickerTimeMax;
|
||||||
|
int PickerLevel;
|
||||||
|
|
||||||
ImPlotAxis() {
|
ImPlotAxis() {
|
||||||
Flags = PreviousFlags = ImPlotAxisFlags_None;
|
Flags = PreviousFlags = ImPlotAxisFlags_None;
|
||||||
|
@ -306,6 +335,7 @@ struct ImPlotAxis
|
||||||
HoveredExt = false;
|
HoveredExt = false;
|
||||||
HoveredTot = false;
|
HoveredTot = false;
|
||||||
LinkedMin = LinkedMax = NULL;
|
LinkedMin = LinkedMax = NULL;
|
||||||
|
PickerLevel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetMin(double _min) {
|
bool SetMin(double _min) {
|
||||||
|
@ -317,6 +347,7 @@ struct ImPlotAxis
|
||||||
if (_min >= Range.Max)
|
if (_min >= Range.Max)
|
||||||
return false;
|
return false;
|
||||||
Range.Min = _min;
|
Range.Min = _min;
|
||||||
|
PickerTimeMin = ImPlotTime::FromDouble(Range.Min);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -329,6 +360,7 @@ struct ImPlotAxis
|
||||||
if (_max <= Range.Min)
|
if (_max <= Range.Min)
|
||||||
return false;
|
return false;
|
||||||
Range.Max = _max;
|
Range.Max = _max;
|
||||||
|
PickerTimeMax = ImPlotTime::FromDouble(Range.Max);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -336,6 +368,8 @@ struct ImPlotAxis
|
||||||
Range.Min = _min;
|
Range.Min = _min;
|
||||||
Range.Max = _max;
|
Range.Max = _max;
|
||||||
Constrain();
|
Constrain();
|
||||||
|
PickerTimeMin = ImPlotTime::FromDouble(Range.Min);
|
||||||
|
PickerTimeMax = ImPlotTime::FromDouble(Range.Max);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRange(const ImPlotRange& range) {
|
void SetRange(const ImPlotRange& range) {
|
||||||
|
@ -585,32 +619,6 @@ struct ImPlotAxisScale
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Two part timestamp struct.
|
|
||||||
struct ImPlotTime {
|
|
||||||
time_t S; // second part
|
|
||||||
int Us; // microsecond part
|
|
||||||
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; }
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] Internal API
|
// [SECTION] Internal API
|
||||||
// No guarantee of forward compatibility here!
|
// No guarantee of forward compatibility here!
|
||||||
|
@ -638,6 +646,9 @@ IMPLOT_API ImPlotState* GetCurrentPlot();
|
||||||
// Busts the cache for every plot in the current context
|
// Busts the cache for every plot in the current context
|
||||||
IMPLOT_API void BustPlotCache();
|
IMPLOT_API void BustPlotCache();
|
||||||
|
|
||||||
|
// Shows a plot's context menu.
|
||||||
|
IMPLOT_API void ShowPlotContextMenu(ImPlotState& plot);
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] Item Utils
|
// [SECTION] Item Utils
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -688,6 +699,9 @@ IMPLOT_API void PushLinkedAxis(ImPlotAxis& axis);
|
||||||
// Updates axis internal range from points for linked axes.
|
// Updates axis internal range from points for linked axes.
|
||||||
IMPLOT_API void PullLinkedAxis(ImPlotAxis& axis);
|
IMPLOT_API void PullLinkedAxis(ImPlotAxis& axis);
|
||||||
|
|
||||||
|
// Shows an axis's context menu.
|
||||||
|
IMPLOT_API void ShowAxisContextMenu(ImPlotAxisState& state, bool time_allowed = false);
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] Legend Utils
|
// [SECTION] Legend Utils
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -792,10 +806,7 @@ inline T OffsetAndStride(const T* data, int idx, int count, int offset, int stri
|
||||||
|
|
||||||
// Returns true if year is leap year (366 days long)
|
// Returns true if year is leap year (366 days long)
|
||||||
inline bool IsLeapYear(int year) {
|
inline bool IsLeapYear(int year) {
|
||||||
if (year % 4 != 0) return false;
|
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||||
if (year % 400 == 0) return true;
|
|
||||||
if (year % 100 == 0) return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
// Returns the number of days in a month, accounting for Feb. leap years. #month is zero indexed.
|
// Returns the number of days in a month, accounting for Feb. leap years. #month is zero indexed.
|
||||||
inline int GetDaysInMonth(int year, int month) {
|
inline int GetDaysInMonth(int year, int month) {
|
||||||
|
@ -803,37 +814,49 @@ inline int GetDaysInMonth(int year, int month) {
|
||||||
return days[month] + (int)(month == 1 && IsLeapYear(year));
|
return days[month] + (int)(month == 1 && IsLeapYear(year));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a timestamp from a tm struct expressed as a UTC time (i.e. GMT timezone).
|
// Make a UNIX timestamp from a tm struct expressed in UTC time (i.e. GMT timezone).
|
||||||
IMPLOT_API ImPlotTime MkGmtTime(struct tm *ptm);
|
IMPLOT_API ImPlotTime MkGmtTime(struct tm *ptm);
|
||||||
// Make a tm struct from a timestamp expressed as a UTC time (i.e. GMT timezone).
|
// Make a tm struct expressed in UTC time (i.e. GMT timezone) from a UNIX timestamp.
|
||||||
IMPLOT_API tm* GetGmtTime(const ImPlotTime& t, tm* ptm);
|
IMPLOT_API tm* GetGmtTime(const ImPlotTime& t, tm* ptm);
|
||||||
|
|
||||||
// Make a timestamp from a tm struct expressed as a local time.
|
// Make a UNIX timestamp from a tm struct expressed in local time.
|
||||||
IMPLOT_API ImPlotTime MkLocTime(struct tm *ptm);
|
IMPLOT_API ImPlotTime MkLocTime(struct tm *ptm);
|
||||||
// Make a tm struct from a timestamp expressed as a local time.
|
// Make a tm struct expressed in local time from a UNIX timestamp.
|
||||||
IMPLOT_API tm* GetLocTime(const ImPlotTime& t, tm* ptm);
|
IMPLOT_API tm* GetLocTime(const ImPlotTime& t, tm* ptm);
|
||||||
|
|
||||||
// NB: These functions only work if there is a current ImPlotContext because the
|
// NB: The following functions only work if there is a current ImPlotContext because the
|
||||||
// internal tm struct is owned by the context!
|
// internal tm struct is owned by the context! They are aware of ImPlotStyle.UseLocalTime.
|
||||||
|
|
||||||
// Adds time to a timestamp. #count must be positive!
|
// Make a timestamp from time components.
|
||||||
|
// year[1970-3000], month[0-11], day[1-31], hour[0-23], min[0-59], sec[0-59], us[0,999999]
|
||||||
|
IMPLOT_API ImPlotTime MakeTime(int year, int month = 0, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0);
|
||||||
|
// Get year component from timestamp [1970-3000]
|
||||||
|
IMPLOT_API int GetYear(const ImPlotTime& t);
|
||||||
|
|
||||||
|
// Adds or subtracts time from a timestamp. #count > 0 to add, < 0 to subtract.
|
||||||
IMPLOT_API ImPlotTime AddTime(const ImPlotTime& t, ImPlotTimeUnit unit, int count);
|
IMPLOT_API ImPlotTime AddTime(const ImPlotTime& t, ImPlotTimeUnit unit, int count);
|
||||||
// Rounds a timestamp down to nearest.
|
// Rounds a timestamp down to nearest unit.
|
||||||
IMPLOT_API ImPlotTime FloorTime(const ImPlotTime& t, ImPlotTimeUnit unit);
|
IMPLOT_API ImPlotTime FloorTime(const ImPlotTime& t, ImPlotTimeUnit unit);
|
||||||
// Rounds a timestamp up to the nearest unit.
|
// Rounds a timestamp up to the nearest unit.
|
||||||
IMPLOT_API ImPlotTime CeilTime(const ImPlotTime& t, ImPlotTimeUnit unit);
|
IMPLOT_API ImPlotTime CeilTime(const ImPlotTime& t, ImPlotTimeUnit unit);
|
||||||
// Rounds a timestamp up or down to the nearest unit.
|
// Rounds a timestamp up or down to the nearest unit.
|
||||||
IMPLOT_API ImPlotTime RoundTime(const ImPlotTime& t, ImPlotTimeUnit unit);
|
IMPLOT_API ImPlotTime RoundTime(const ImPlotTime& t, ImPlotTimeUnit unit);
|
||||||
|
// Combines the date of one timestamp with the time-of-day of another timestamp.
|
||||||
|
IMPLOT_API ImPlotTime CombineDateTime(const ImPlotTime& date_part, const ImPlotTime& time_part);
|
||||||
|
|
||||||
// Get year from timestamp
|
// Formulates a timestamp t into a buffer according to fmt.
|
||||||
IMPLOT_API int GetYear(const ImPlotTime& t);
|
|
||||||
// Make a timestamp starting at the first day of a year
|
|
||||||
IMPLOT_API ImPlotTime MakeYear(int year);
|
|
||||||
|
|
||||||
// Formates a timestamp t into a buffer according to fmt.
|
|
||||||
IMPLOT_API int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt);
|
IMPLOT_API int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt);
|
||||||
// Prints a timestamp to console
|
// Prints a timestamp to console
|
||||||
IMPLOT_API void PrintTime(const ImPlotTime& t, ImPlotTimeFmt fmt);
|
IMPLOT_API void PrintTime(const ImPlotTime& t, ImPlotTimeFmt fmt = ImPlotTimeFmt_DayMoYrHrMinSUs);
|
||||||
|
|
||||||
|
// Shows a date picker widget block (year/month/day).
|
||||||
|
// #level = 0 for day, 1 for month, 2 for year. Modified by user interaction.
|
||||||
|
// #t will be set when a day is clicked and the function will return true.
|
||||||
|
// #t1 and #t2 are optional dates to highlight.
|
||||||
|
IMPLOT_API bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime* t1 = NULL, const ImPlotTime* t2 = NULL);
|
||||||
|
// Shows a time picker widget block (hour/min/sec).
|
||||||
|
// #t will be set when a new hour, minute, or sec is selected or am/pm is toggled, and the function will return true.
|
||||||
|
IMPLOT_API bool ShowTimePicker(const char* id, ImPlotTime* t);
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] Internal / Experimental Plotters
|
// [SECTION] Internal / Experimental Plotters
|
||||||
|
|
Loading…
Reference in New Issue
Block a user