1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-26 12:18:52 -05:00

add annotation API

This commit is contained in:
epezent 2020-09-19 20:54:19 -05:00
parent a7ae1bca53
commit 13e430a9e5
5 changed files with 337 additions and 177 deletions

View File

@ -95,29 +95,31 @@ ImPlotInputMap::ImPlotInputMap() {
ImPlotStyle::ImPlotStyle() {
LineWeight = 1;
Marker = ImPlotMarker_None;
MarkerSize = 4;
MarkerWeight = 1;
FillAlpha = 1;
ErrorBarSize = 5;
ErrorBarWeight = 1.5f;
DigitalBitHeight = 8;
DigitalBitGap = 4;
LineWeight = 1;
Marker = ImPlotMarker_None;
MarkerSize = 4;
MarkerWeight = 1;
FillAlpha = 1;
ErrorBarSize = 5;
ErrorBarWeight = 1.5f;
DigitalBitHeight = 8;
DigitalBitGap = 4;
PlotBorderSize = 1;
MinorAlpha = 0.25f;
MajorTickLen = ImVec2(10,10);
MinorTickLen = ImVec2(5,5);
MajorTickSize = ImVec2(1,1);
MinorTickSize = ImVec2(1,1);
MajorGridSize = ImVec2(1,1);
MinorGridSize = ImVec2(1,1);
PlotPadding = ImVec2(8,8);
LabelPadding = ImVec2(5,5);
LegendPadding = ImVec2(10,10);
InfoPadding = ImVec2(10,10);
PlotMinSize = ImVec2(300,225);
PlotBorderSize = 1;
MinorAlpha = 0.25f;
MajorTickLen = ImVec2(10,10);
MinorTickLen = ImVec2(5,5);
MajorTickSize = ImVec2(1,1);
MinorTickSize = ImVec2(1,1);
MajorGridSize = ImVec2(1,1);
MinorGridSize = ImVec2(1,1);
PlotPadding = ImVec2(8,8);
LabelPadding = ImVec2(5,5);
LegendPadding = ImVec2(10,10);
InfoPadding = ImVec2(10,10);
AnnotationPadding = ImVec2(2,2);
AnnotationOffset = ImVec2(10,10);
PlotMinSize = ImVec2(300,225);
ImPlot::StyleColorsAuto(this);
@ -215,29 +217,31 @@ struct ImPlotStyleVarInfo {
static const ImPlotStyleVarInfo GPlotStyleVarInfo[] =
{
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, LineWeight) }, // ImPlotStyleVar_LineWeight
{ ImGuiDataType_S32, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, Marker) }, // ImPlotStyleVar_Marker
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerSize) }, // ImPlotStyleVar_MarkerSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerWeight) }, // ImPlotStyleVar_MarkerWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, FillAlpha) }, // ImPlotStyleVar_FillAlpha
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarSize) }, // ImPlotStyleVar_ErrorBarSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarWeight) }, // ImPlotStyleVar_ErrorBarWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitHeight) }, // ImPlotStyleVar_DigitalBitHeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitGap) }, // ImPlotStyleVar_DigitalBitGap
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, LineWeight) }, // ImPlotStyleVar_LineWeight
{ ImGuiDataType_S32, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, Marker) }, // ImPlotStyleVar_Marker
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerSize) }, // ImPlotStyleVar_MarkerSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerWeight) }, // ImPlotStyleVar_MarkerWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, FillAlpha) }, // ImPlotStyleVar_FillAlpha
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarSize) }, // ImPlotStyleVar_ErrorBarSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarWeight) }, // ImPlotStyleVar_ErrorBarWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitHeight) }, // ImPlotStyleVar_DigitalBitHeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitGap) }, // ImPlotStyleVar_DigitalBitGap
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotBorderSize) }, // ImPlotStyleVar_PlotBorderSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorAlpha) }, // ImPlotStyleVar_MinorAlpha
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorTickLen) }, // ImPlotStyleVar_MajorTickLen
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorTickLen) }, // ImPlotStyleVar_MinorTickLen
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorTickSize) }, // ImPlotStyleVar_MajorTickSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorTickSize) }, // ImPlotStyleVar_MinorTickSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorGridSize) }, // ImPlotStyleVar_MajorGridSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorGridSize) }, // ImPlotStyleVar_MinorGridSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotPadding) }, // ImPlotStyleVar_PlotPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LabelPadding) }, // ImPlotStyleVar_LabelPaddine
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendPadding) }, // ImPlotStyleVar_LegendPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, InfoPadding) }, // ImPlotStyleVar_InfoPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotMinSize) } // ImPlotStyleVar_PlotMinSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotBorderSize) }, // ImPlotStyleVar_PlotBorderSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorAlpha) }, // ImPlotStyleVar_MinorAlpha
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorTickLen) }, // ImPlotStyleVar_MajorTickLen
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorTickLen) }, // ImPlotStyleVar_MinorTickLen
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorTickSize) }, // ImPlotStyleVar_MajorTickSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorTickSize) }, // ImPlotStyleVar_MinorTickSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorGridSize) }, // ImPlotStyleVar_MajorGridSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorGridSize) }, // ImPlotStyleVar_MinorGridSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotPadding) }, // ImPlotStyleVar_PlotPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LabelPadding) }, // ImPlotStyleVar_LabelPaddine
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendPadding) }, // ImPlotStyleVar_LegendPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, InfoPadding) }, // ImPlotStyleVar_InfoPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, AnnotationPadding) }, // ImPlotStyleVar_AnnotationPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, AnnotationOffset) }, // ImPlotStyleVar_AnnotationOffset
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotMinSize) } // ImPlotStyleVar_PlotMinSize
};
static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx) {
@ -364,6 +368,8 @@ void Reset(ImPlotContext* ctx) {
for (int i = 0; i < 3; ++i) {
ctx->YTicks[i].Reset();
}
// reset labels
ctx->Annotations.Reset();
// reset extents/fit
ctx->FitThisFrame = false;
ctx->FitX = false;
@ -378,8 +384,9 @@ void Reset(ImPlotContext* ctx) {
ctx->DigitalPlotItemCnt = 0;
ctx->DigitalPlotOffset = 0;
// nullify plot
ctx->CurrentPlot = NULL;
ctx->CurrentItem = NULL;
ctx->CurrentPlot = NULL;
ctx->CurrentItem = NULL;
ctx->PreviousItem = NULL;
}
//-----------------------------------------------------------------------------
@ -516,20 +523,20 @@ const char* GetLegendLabel(int i) {
void LabelTickDefault(ImPlotTick& tick, ImGuiTextBuffer& buffer) {
char temp[32];
if (tick.ShowLabel) {
tick.BufferOffset = buffer.size();
tick.TextOffset = buffer.size();
snprintf(temp, 32, "%.10g", tick.PlotPos);
buffer.append(temp, temp + strlen(temp) + 1);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.BufferOffset);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.TextOffset);
}
}
void LabelTickScientific(ImPlotTick& tick, ImGuiTextBuffer& buffer) {
char temp[32];
if (tick.ShowLabel) {
tick.BufferOffset = buffer.size();
tick.TextOffset = buffer.size();
snprintf(temp, 32, "%.0E", tick.PlotPos);
buffer.append(temp, temp + strlen(temp) + 1);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.BufferOffset);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.TextOffset);
}
}
@ -540,11 +547,11 @@ void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImPlotTic
const double graphmax = ceil(range.Max / interval) * interval;
for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
if (range.Contains(major))
ticks.AddTick(major, true, true, LabelTickDefault);
ticks.Append(major, true, true, LabelTickDefault);
for (int i = 1; i < nMinor; ++i) {
double minor = major + i * interval / nMinor;
if (range.Contains(minor))
ticks.AddTick(minor, false, true, LabelTickDefault);
ticks.Append(minor, false, true, LabelTickDefault);
}
}
}
@ -566,7 +573,7 @@ void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollect
double major2 = ImPow(10, (double)(e + 1));
double interval = (major2 - major1) / 9;
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
ticks.AddTick(major1, true, true, LabelTickScientific);
ticks.Append(major1, true, true, LabelTickScientific);
for (int j = 0; j < exp_step; ++j) {
major1 = ImPow(10, (double)(e+j));
major2 = ImPow(10, (double)(e+j+1));
@ -574,7 +581,7 @@ void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollect
for (int i = 1; i < (9 + (int)(j < (exp_step - 1))); ++i) {
double minor = major1 + i * interval;
if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
ticks.AddTick(minor, false, false, LabelTickScientific);
ticks.Append(minor, false, false, LabelTickScientific);
}
}
@ -585,14 +592,14 @@ void AddTicksCustom(const double* values, const char* const labels[], int n, ImP
for (int i = 0; i < n; ++i) {
ImPlotTick tick(values[i], false, true);
if (labels != NULL) {
tick.BufferOffset = ticks.Labels.size();
ticks.Labels.append(labels[i], labels[i] + strlen(labels[i]) + 1);
tick.TextOffset = ticks.TextBuffer.size();
ticks.TextBuffer.append(labels[i], labels[i] + strlen(labels[i]) + 1);
tick.LabelSize = ImGui::CalcTextSize(labels[i]);
}
else {
LabelTickDefault(tick, ticks.Labels);
LabelTickDefault(tick, ticks.TextBuffer);
}
ticks.AddTick(tick);
ticks.Append(tick);
}
}
@ -959,10 +966,10 @@ void PrintTime(const ImPlotTime& t, ImPlotTimeFmt fmt) {
inline void LabelTickTime(ImPlotTick& tick, ImGuiTextBuffer& buffer, const ImPlotTime& t, ImPlotTimeFmt fmt, bool hour24) {
char temp[32];
if (tick.ShowLabel) {
tick.BufferOffset = buffer.size();
tick.TextOffset = buffer.size();
hour24 ? FormatTime24(t, temp, 32, fmt) : FormatTime12(t, temp, 32, fmt);
buffer.append(temp, temp + strlen(temp) + 1);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.BufferOffset);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.TextOffset);
}
}
@ -1053,17 +1060,17 @@ void AddTicksTime(const ImPlotRange& range, float plot_width, bool hour24, ImPlo
// minor level 0 tick
ImPlotTick tick_min(t1.ToDouble(),true,true);
tick_min.Level = 0;
LabelTickTime(tick_min,ticks.Labels,t1,fmt0,hour24);
ticks.AddTick(tick_min);
LabelTickTime(tick_min,ticks.TextBuffer,t1,fmt0,hour24);
ticks.Append(tick_min);
// major level 1 tick
ImPlotTick tick_maj(t1.ToDouble(),true,true);
tick_maj.Level = 1;
LabelTickTime(tick_maj,ticks.Labels,t1, last_major == NULL ? fmtf : fmt1,hour24);
const char* this_major = ticks.Labels.Buf.Data + tick_maj.BufferOffset;
LabelTickTime(tick_maj,ticks.TextBuffer,t1, last_major == NULL ? fmtf : fmt1,hour24);
const char* this_major = ticks.TextBuffer.Buf.Data + tick_maj.TextOffset;
if (last_major && TimeLabelSame(last_major,this_major))
tick_maj.ShowLabel = false;
last_major = this_major;
ticks.AddTick(tick_maj);
ticks.Append(tick_maj);
}
// add minor ticks up until next major
if (minor_per_major > 1 && (t_min <= t2 && t1 <= t_max)) {
@ -1073,14 +1080,14 @@ void AddTicksTime(const ImPlotRange& range, float plot_width, bool hour24, ImPlo
if (t12 >= t_min && t12 <= t_max) {
ImPlotTick tick(t12.ToDouble(),false,px_to_t2 >= fmt0_width);
tick.Level = 0;
LabelTickTime(tick,ticks.Labels,t12,fmt0,hour24);
ticks.AddTick(tick);
LabelTickTime(tick,ticks.TextBuffer,t12,fmt0,hour24);
ticks.Append(tick);
if (last_major == NULL && px_to_t2 >= fmt0_width && px_to_t2 >= (fmt1_width + fmtf_width) / 2) {
ImPlotTick tick_maj(t12.ToDouble(),true,true);
tick_maj.Level = 1;
LabelTickTime(tick_maj,ticks.Labels,t12,fmtf,hour24);
last_major = ticks.Labels.Buf.Data + tick_maj.BufferOffset;
ticks.AddTick(tick_maj);
LabelTickTime(tick_maj,ticks.TextBuffer,t12,fmtf,hour24);
last_major = ticks.TextBuffer.Buf.Data + tick_maj.TextOffset;
ticks.Append(tick_maj);
}
}
t12 = AddTime(t12, unit0, step);
@ -1106,8 +1113,8 @@ void AddTicksTime(const ImPlotRange& range, float plot_width, bool hour24, ImPlo
if (t >= t_min && t <= t_max) {
ImPlotTick tick(t.ToDouble(), true, true);
tick.Level = 0;
LabelTickTime(tick, ticks.Labels, t, TimeFormatLevel0[ImPlotTimeUnit_Yr], hour24);
ticks.AddTick(tick);
LabelTickTime(tick, ticks.TextBuffer, t, TimeFormatLevel0[ImPlotTimeUnit_Yr], hour24);
ticks.Append(tick);
}
}
}
@ -1707,7 +1714,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
ImPlotTick *xt = &gp.XTicks.Ticks[t];
if (xt->ShowLabel && xt->PixelPos >= gp.BB_Plot.Min.x - 1 && xt->PixelPos <= gp.BB_Plot.Max.x + 1)
DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, gp.BB_Plot.Max.y + gp.Style.LabelPadding.y + xt->Level * (txt_height + gp.Style.LabelPadding.y)),
xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTicks.GetLabel(t));
xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTicks.GetText(t));
}
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
@ -1717,7 +1724,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
if (yt->ShowLabel && yt->PixelPos >= gp.BB_Plot.Min.y - 1 && yt->PixelPos <= gp.BB_Plot.Max.y + 1) {
ImVec2 start(x_start, yt->PixelPos - 0.5f * yt->LabelSize.y);
DrawList.AddText(start, yt->Major ? gp.Col_Y[i].MajTxt : gp.Col_Y[i].MinTxt, gp.YTicks[i].GetLabel(t));
DrawList.AddText(start, yt->Major ? gp.Col_Y[i].MajTxt : gp.Col_Y[i].MinTxt, gp.YTicks[i].GetText(t));
}
}
}
@ -1930,8 +1937,8 @@ void ShowPlotContextMenu(ImPlotState& plot) {
ImGui::LabelText("Plots", "%d", gp.Plots.GetSize());
ImGui::LabelText("Color Mods", "%d", gp.ColorModifiers.size());
ImGui::LabelText("Style Mods", "%d", gp.StyleModifiers.size());
ImGui::TextUnformatted(gp.XTicks.Labels.Buf.Data, gp.XTicks.Labels.Buf.Data + gp.XTicks.Labels.size());
ImGui::TextUnformatted(gp.YTicks[0].Labels.Buf.Data, gp.YTicks[0].Labels.Buf.Data + gp.YTicks[0].Labels.size());
ImGui::TextUnformatted(gp.XTicks.TextBuffer.Buf.Data, gp.XTicks.TextBuffer.Buf.Data + gp.XTicks.TextBuffer.size());
ImGui::TextUnformatted(gp.YTicks[0].TextBuffer.Buf.Data, gp.YTicks[0].TextBuffer.Buf.Data + gp.YTicks[0].TextBuffer.size());
// ImGui::TextUnformatted(gp.YTicks[1].Labels.Buf.Data, gp.YTicks[1].Labels.Buf.Data + gp.YTicks[1].Labels.size());
// ImGui::TextUnformatted(gp.YTicks[2].Labels.Buf.Data, gp.YTicks[2].Labels.Buf.Data + gp.YTicks[2].Labels.size());
@ -2008,6 +2015,47 @@ void EndPlot() {
}
ImGui::PopClipRect();
// render annotations
PushPlotClipRect();
for (int i = 0; i < gp.Annotations.Size; ++i) {
const char* txt = gp.Annotations.GetText(i);
ImPlotAnnotation& an = gp.Annotations.Annotations[i];
const ImVec2 txt_size = ImGui::CalcTextSize(txt);
const ImVec2 size = txt_size + gp.Style.AnnotationPadding * 2;
ImVec2 pos = an.Pos;
if (an.Offset.x == 0)
pos.x -= size.x / 2;
else if (an.Offset.x > 0)
pos.x += an.Offset.x;
else
pos.x -= size.x - an.Offset.x;
if (an.Offset.y == 0)
pos.y -= size.y / 2;
else if (an.Offset.y > 0)
pos.y += an.Offset.y;
else
pos.y -= size.y - an.Offset.y;
if (an.Clamp)
pos = ClampLabelPos(pos, size, gp.BB_Plot.Min, gp.BB_Plot.Max);
ImRect rect(pos,pos+size);
if (an.Offset.x != 0 || an.Offset.y != 0) {
ImVec2 corners[4] = {rect.GetTL(), rect.GetTR(), rect.GetBR(), rect.GetBL()};
int min_corner = 0;
float min_len = FLT_MAX;
for (int c = 0; c < 4; ++c) {
float len = ImLengthSqr(an.Pos - corners[c]);
if (len < min_len) {
min_corner = c;
min_len = len;
}
}
DrawList.AddLine(an.Pos, corners[min_corner], an.ColorBg);
}
DrawList.AddRectFilled(rect.Min, rect.Max, an.ColorBg);
DrawList.AddText(pos + gp.Style.AnnotationPadding, an.ColorFg, txt);
}
PopPlotClipRect();
// render y-axis drag/drop hover
if ((gp.Y[1].Present || gp.Y[2].Present) && ImGui::IsDragDropPayloadBeingAccepted()) {
for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
@ -2483,6 +2531,43 @@ ImPlotLimits GetPlotQuery(int y_axis_in) {
return result;
}
void AnnotateEx(double x, double y, bool clamp, const ImVec4& col, const ImVec2& off, const char* fmt, va_list args) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Annotate() needs to be called between BeginPlot() and EndPlot()!");
ImVec2 pos = PlotToPixels(x,y);
ImU32 bg = ImGui::GetColorU32(col);
ImU32 fg = col.w == 0 ? GetStyleColorU32(ImPlotCol_InlayText) : CalcTextColor(col);
gp.Annotations.AppendV(pos, off, bg, fg, clamp, fmt, args);
}
void Annotate(double x, double y, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
AnnotateEx(x,y,false,ImVec4(0,0,0,0),GImPlot->Style.AnnotationOffset,fmt,args);
va_end(args);
}
void Annotate(double x, double y, const ImVec4& col, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
AnnotateEx(x,y,false,col,GImPlot->Style.AnnotationOffset,fmt,args);
va_end(args);
}
void AnnotateClamped(double x, double y, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
AnnotateEx(x,y,true,ImVec4(0,0,0,0),GImPlot->Style.AnnotationOffset,fmt,args);
va_end(args);
}
void AnnotateClamped(double x, double y, const ImVec4& col, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
AnnotateEx(x,y,true,col,GImPlot->Style.AnnotationOffset,fmt,args);
va_end(args);
}
bool DragLineX(const char* id, double* value, bool show_label, const ImVec4& col, float thickness) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "DragLineX() needs to be called between BeginPlot() and EndPlot()!");
@ -2509,22 +2594,12 @@ bool DragLineX(const char* id, double* value, bool show_label, const ImVec4& col
ImGui::GetCurrentWindow()->DC.CursorPos = new_cursor_pos;
ImGui::InvisibleButton(id, ImVec2(grab_size, yb-yt));
ImGui::GetCurrentWindow()->DC.CursorPos = old_cursor_pos;
if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
gp.Hov_Plot = false;
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
if (show_label) {
PushPlotClipRect();
double range_x = gp.XTicks.Size > 1 ? (gp.XTicks.Ticks[1].PlotPos - gp.XTicks.Ticks[0].PlotPos) : gp.CurrentPlot->XAxis.Range.Size();
char buf[32];
snprintf(buf, 32, "%s = %.*f", id, Precision(range_x), *value);
ImVec2 size = ImGui::CalcTextSize(buf);
const int pad = 2;
ImVec2 label_pos = ImVec2(x - size.x/2 - pad, yb - size.y - 2*pad);
ImVec2 label_size = size + ImVec2(pad*2,pad*2);
label_pos = ClampLabelPos(label_pos, label_size, gp.BB_Plot.Min, gp.BB_Plot.Max);
DrawList.AddRectFilled(label_pos, label_pos + label_size, col32);
DrawList.AddText(label_pos + ImVec2(pad,pad),CalcTextColor(color),buf);
PopPlotClipRect();
gp.Annotations.Append(ImVec2(x,yb),ImVec2(0,0),col32,CalcTextColor(color),true,"%s = %.*f", id, Precision(range_x), *value);
}
}
bool dragging = false;
@ -2568,27 +2643,8 @@ bool DragLineY(const char* id, double* value, bool show_label, const ImVec4& col
gp.Hov_Plot = false;
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
if (show_label) {
PushPlotClipRect();
double range_y = gp.YTicks[yax].Size > 1 ? (gp.YTicks[yax].Ticks[1].PlotPos - gp.YTicks[yax].Ticks[0].PlotPos) : gp.CurrentPlot->YAxis[yax].Range.Size();
char buf[32];
snprintf(buf, 32, "%s = %.*f", id, Precision(range_y), *value);
ImVec2 size = ImGui::CalcTextSize(buf);
const int pad = 2;
if (yax == 0) {
ImVec2 label_pos = ImVec2(xl,y-pad-size.y/2);
ImVec2 label_size = size + ImVec2(pad*2,pad*2);
label_pos = ClampLabelPos(label_pos, label_size, gp.BB_Plot.Min, gp.BB_Plot.Max);
DrawList.AddRectFilled(label_pos, label_pos + label_size, col32);
DrawList.AddText(label_pos + ImVec2(pad,pad),CalcTextColor(color),buf);
}
else {
ImVec2 label_pos = ImVec2(xr-size.x-2*pad,y-pad-size.y/2);
ImVec2 label_size = size + ImVec2(pad*2,pad*2);
label_pos = ClampLabelPos(label_pos, label_size, gp.BB_Plot.Min, gp.BB_Plot.Max);
DrawList.AddRectFilled(label_pos, label_pos + label_size, col32);
DrawList.AddText(label_pos + ImVec2(pad,pad),CalcTextColor(color),buf);
}
PopPlotClipRect();
gp.Annotations.Append(ImVec2(yax == 0 ? xl : xr,y), ImVec2(0,0), col32, CalcTextColor(color), true, "%s = %.*f", id, Precision(range_y), *value);
}
}
bool dragging = false;
@ -2624,18 +2680,10 @@ bool DragPoint(const char* id, double* x, double* y, bool show_label, const ImVe
gp.Hov_Plot = false;
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
if (show_label) {
PushPlotClipRect();
double range_x = gp.XTicks.Size > 1 ? (gp.XTicks.Ticks[1].PlotPos - gp.XTicks.Ticks[0].PlotPos) : gp.CurrentPlot->XAxis.Range.Size();
double range_y = gp.YTicks[yax].Size > 1 ? (gp.YTicks[yax].Ticks[1].PlotPos - gp.YTicks[yax].Ticks[0].PlotPos) : gp.CurrentPlot->YAxis[yax].Range.Size();
char buf[64];
const float yb = gp.BB_Plot.Max.y;
snprintf(buf, 64, "%s = %.*f,%.*f", id, Precision(range_x), *x, Precision(range_y), *y);
ImVec2 label_pos = pos + ImVec2(16 * GImGui->Style.MouseCursorScale, 8 * GImGui->Style.MouseCursorScale);
ImVec2 label_size = ImGui::CalcTextSize(buf) + ImVec2(4,4);
label_pos = ClampLabelPos(label_pos, label_size, gp.BB_Plot.Min, gp.BB_Plot.Max);
DrawList.AddRectFilled(label_pos, label_pos + label_size, col32);
DrawList.AddText(label_pos + ImVec2(2,2), CalcTextColor(color), buf);
PopPlotClipRect();
gp.Annotations.Append(label_pos, ImVec2(0.0001f,0.00001f), col32, CalcTextColor(color), true, "%s = %.*f,%.*f", id, Precision(range_x), *x, Precision(range_y), *y);
}
}
bool dragging = false;
@ -3133,7 +3181,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) {
float ypos = ImRemap((float)ticks.Ticks[i].PlotPos, (float)range.Max, (float)range.Min, bb_grad.Min.y, bb_grad.Max.y);
if (ypos < bb_grad.Max.y - 2 && ypos > bb_grad.Min.y + 2)
DrawList.AddLine(ImVec2(bb_grad.Max.x-1, ypos), ImVec2(bb_grad.Max.x - (ticks.Ticks[i].Major ? 10.0f : 5.0f), ypos), col_tick, 1.0f);
DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks.Ticks[i].LabelSize.y * 0.5f), GetStyleColorU32(ImPlotCol_TitleText), ticks.GetLabel(i));
DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks.Ticks[i].LabelSize.y * 0.5f), GetStyleColorU32(ImPlotCol_TitleText), ticks.GetText(i));
}
ImGui::PopClipRect();
@ -3221,12 +3269,14 @@ void ShowStyleEditor(ImPlotStyle* ref) {
ImGui::SliderFloat2("MinorTickSize", (float*)&style.MinorTickSize, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat2("MajorGridSize", (float*)&style.MajorGridSize, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat2("MinorGridSize", (float*)&style.MinorGridSize, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat2("PlotMinSize", (float*)&style.PlotMinSize, 0.0f, 300, "%.0f");
ImGui::Text("Plot Padding");
ImGui::SliderFloat2("PlotPadding", (float*)&style.PlotPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LabelPadding", (float*)&style.LabelPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LegendPadding", (float*)&style.LegendPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("InfoPadding", (float*)&style.InfoPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("PlotMinSize", (float*)&style.PlotMinSize, 0.0f, 300, "%.0f");
ImGui::SliderFloat2("AnnotationPadding", (float*)&style.AnnotationPadding, 0.0f, 5.0f, "%.0f");
ImGui::SliderFloat2("AnnotationOffset", (float*)&style.AnnotationOffset, -20.0f, 20.0f, "%.0f");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Colors")) {

View File

@ -125,29 +125,31 @@ enum ImPlotCol_ {
// Plot styling variables.
enum ImPlotStyleVar_ {
// item styling variables
ImPlotStyleVar_LineWeight, // float, plot item line weight in pixels
ImPlotStyleVar_Marker, // int, marker specification
ImPlotStyleVar_MarkerSize, // float, marker size in pixels (roughly the marker's "radius")
ImPlotStyleVar_MarkerWeight, // float, plot outline weight of markers in pixels
ImPlotStyleVar_FillAlpha, // float, alpha modifier applied to all plot item fills
ImPlotStyleVar_ErrorBarSize, // float, error bar whisker width in pixels
ImPlotStyleVar_ErrorBarWeight, // float, error bar whisker weight in pixels
ImPlotStyleVar_DigitalBitHeight, // float, digital channels bit height (at 1) in pixels
ImPlotStyleVar_DigitalBitGap, // float, digital channels bit padding gap in pixels
ImPlotStyleVar_LineWeight, // float, plot item line weight in pixels
ImPlotStyleVar_Marker, // int, marker specification
ImPlotStyleVar_MarkerSize, // float, marker size in pixels (roughly the marker's "radius")
ImPlotStyleVar_MarkerWeight, // float, plot outline weight of markers in pixels
ImPlotStyleVar_FillAlpha, // float, alpha modifier applied to all plot item fills
ImPlotStyleVar_ErrorBarSize, // float, error bar whisker width in pixels
ImPlotStyleVar_ErrorBarWeight, // float, error bar whisker weight in pixels
ImPlotStyleVar_DigitalBitHeight, // float, digital channels bit height (at 1) in pixels
ImPlotStyleVar_DigitalBitGap, // float, digital channels bit padding gap in pixels
// plot styling variables
ImPlotStyleVar_PlotBorderSize, // float, thickness of border around plot area
ImPlotStyleVar_MinorAlpha, // float, alpha multiplier applied to minor axis grid lines
ImPlotStyleVar_MajorTickLen, // ImVec2, major tick lengths for X and Y axes
ImPlotStyleVar_MinorTickLen, // ImVec2, minor tick lengths for X and Y axes
ImPlotStyleVar_MajorTickSize, // ImVec2, line thickness of major ticks
ImPlotStyleVar_MinorTickSize, // ImVec2, line thickness of minor ticks
ImPlotStyleVar_MajorGridSize, // ImVec2, line thickness of major grid lines
ImPlotStyleVar_MinorGridSize, // ImVec2, line thickness of minor grid lines
ImPlotStyleVar_PlotPadding, // ImVec2, padding between widget frame and plot area and/or labels
ImPlotStyleVar_LabelPadding, // ImVec2, padding between axes labels, tick labels, and plot edge
ImPlotStyleVar_LegendPadding, // ImVec2, legend padding from top-left of plot
ImPlotStyleVar_InfoPadding, // ImVec2, padding between plot edge and interior info text
ImPlotStyleVar_PlotMinSize, // ImVec2, minimum size plot frame can be when shrunk
ImPlotStyleVar_PlotBorderSize, // float, thickness of border around plot area
ImPlotStyleVar_MinorAlpha, // float, alpha multiplier applied to minor axis grid lines
ImPlotStyleVar_MajorTickLen, // ImVec2, major tick lengths for X and Y axes
ImPlotStyleVar_MinorTickLen, // ImVec2, minor tick lengths for X and Y axes
ImPlotStyleVar_MajorTickSize, // ImVec2, line thickness of major ticks
ImPlotStyleVar_MinorTickSize, // ImVec2, line thickness of minor ticks
ImPlotStyleVar_MajorGridSize, // ImVec2, line thickness of major grid lines
ImPlotStyleVar_MinorGridSize, // ImVec2, line thickness of minor grid lines
ImPlotStyleVar_PlotPadding, // ImVec2, padding between widget frame and plot area and/or labels
ImPlotStyleVar_LabelPadding, // ImVec2, padding between axes labels, tick labels, and plot edge
ImPlotStyleVar_LegendPadding, // ImVec2, legend padding from top-left of plot
ImPlotStyleVar_InfoPadding, // ImVec2, padding between plot edge and interior info text
ImPlotStyleVar_AnnotationPadding, // ImVec2, text padding around annotation labels
ImPlotStyleVar_AnnotationOffset, // ImVec2, annotation label offset in pixels (0,0 will center the label)
ImPlotStyleVar_PlotMinSize, // ImVec2, minimum size plot frame can be when shrunk
ImPlotStyleVar_COUNT
};
@ -238,6 +240,8 @@ struct ImPlotStyle {
ImVec2 LabelPadding; // = 5,5 padding between axes labels, tick labels, and plot edge
ImVec2 LegendPadding; // = 10,10 legend padding from top-left of plot
ImVec2 InfoPadding; // = 10,10 padding between plot edge and interior info text
ImVec2 AnnotationPadding; // = 2,2 text padding around annotation labels
ImVec2 AnnotationOffset; // = 10,10 annotation label offset in pixels (0,0 will center the label)
ImVec2 PlotMinSize; // = 300,225 minimum size plot frame can be when shrunk
// colors
ImVec4 Colors[ImPlotCol_COUNT]; // array of plot specific colors
@ -398,7 +402,7 @@ template <typename T> IMPLOT_API void PlotDigital(const char* label_id, const T*
IMPLOT_API void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImVec2& uv0=ImVec2(0,0), const ImVec2& uv1=ImVec2(1,1), const ImVec4& tint_col=ImVec4(1,1,1,1));
// Plots a centered text label at point x,y with optional pixel offset. Text color can be changed with ImPlot::PushStyleColor(ImPlotCol_InlayText, ...).
IMPLOT_API void PlotText(const char* text, double x, double y, bool vertical=false, const ImVec2& pixel_offset=ImVec2(0,0));
IMPLOT_API void PlotText(const char* text, double x, double y, bool vertical=false, const ImVec2& pix_offset=ImVec2(0,0));
//-----------------------------------------------------------------------------
// Plot Utils
@ -453,10 +457,22 @@ IMPLOT_API ImPlotPoint GetPlotMousePos(int y_axis = IMPLOT_AUTO);
// Returns the current plot axis range. A negative y_axis uses the current value of SetPlotYAxis (0 initially).
IMPLOT_API ImPlotLimits GetPlotLimits(int y_axis = IMPLOT_AUTO);
// Returns true if the current plot is being queried. Query must be enabled with ImPlotFlags_Query.
IMPLOT_API bool IsPlotQueried();
// Returns the current plot query bounds. Query must be enabled with ImPlotFlags_Query.
IMPLOT_API ImPlotLimits GetPlotQuery(int y_axis = IMPLOT_AUTO);
//-----------------------------------------------------------------------------
// Plot Tools
//-----------------------------------------------------------------------------
// Shows an annotation callout at a chosen point. Annotations can be offset or centered with ImPlotStyleVar_AnnotationOffset.
IMPLOT_API void Annotate(double x, double y, const char* fmt, ...) IM_FMTARGS(3);
IMPLOT_API void Annotate(double x, double y, const ImVec4& color, const char* fmt, ...) IM_FMTARGS(4);
// Same as above, but the annotation will always be clamped to stay inside the plot area.
IMPLOT_API void AnnotateClamped(double x, double y, const char* fmt, ...) IM_FMTARGS(3);
IMPLOT_API void AnnotateClamped(double x, double y, const ImVec4& color, const char* fmt, ...) IM_FMTARGS(4);
// Shows a draggable vertical guide line at an x-value. #col defaults to ImGuiCol_Text.
IMPLOT_API bool DragLineX(const char* id, double* x_value, bool show_label = true, const ImVec4& col = IMPLOT_AUTO_COL, float thickness = 1);
// Shows a draggable horizontal guide line at a y-value. #col defaults to ImGuiCol_Text.
@ -464,11 +480,6 @@ IMPLOT_API bool DragLineY(const char* id, double* y_value, bool show_label = tru
// Shows a draggable point at x,y. #col defaults to ImGuiCol_Text.
IMPLOT_API bool DragPoint(const char* id, double* x, double* y, bool show_label = true, const ImVec4& col = IMPLOT_AUTO_COL, float radius = 4);
// Returns true if the current plot is being queried. Query must be enabled with ImPlotFlags_Query.
IMPLOT_API bool IsPlotQueried();
// Returns the current plot query bounds. Query must be enabled with ImPlotFlags_Query.
IMPLOT_API ImPlotLimits GetPlotQuery(int y_axis = IMPLOT_AUTO);
//-----------------------------------------------------------------------------
// Legend Utils and Tools
//-----------------------------------------------------------------------------
@ -533,10 +544,13 @@ IMPLOT_API void SetNextMarkerStyle(ImPlotMarker marker = IMPLOT_AUTO, float size
// Set the error bar style for the next item only.
IMPLOT_API void SetNextErrorBarStyle(const ImVec4& col = IMPLOT_AUTO_COL, float size = IMPLOT_AUTO, float weight = IMPLOT_AUTO);
// Gets the last item primary color (i.e. its legend icon color)
IMPLOT_API ImVec4 GetLastItemColor();
// Returns the null terminated string name for an ImPlotCol.
IMPLOT_API const char* GetStyleColorName(ImPlotCol color);
IMPLOT_API const char* GetStyleColorName(ImPlotCol idx);
// Returns the null terminated string name for an ImPlotMarker.
IMPLOT_API const char* GetMarkerName(ImPlotMarker marker);
IMPLOT_API const char* GetMarkerName(ImPlotMarker idx);
//-----------------------------------------------------------------------------
// Colormaps

View File

@ -659,6 +659,7 @@ void ShowDemoWindow(bool* p_open) {
double t_now = (double)time(0);
double y_now = HugeTimeData::GetY(t_now);
ImPlot::PlotScatter("Now",&t_now,&y_now,1);
ImPlot::Annotate(t_now,y_now,ImPlot::GetLastItemColor(),"Now");
ImPlot::EndPlot();
}
}
@ -857,6 +858,39 @@ void ShowDemoWindow(bool* p_open) {
ImPlot::EndPlot();
}
}
if (ImGui::CollapsingHeader("Annotations")) {
static bool clamp = false;
ImGui::Checkbox("Clamp",&clamp);
ImPlot::SetNextPlotLimits(0,2,0,1);
if (ImPlot::BeginPlot("##Annotations")) {
static float p[] = {0.25f, 0.25f, 0.75f, 0.75f, 0.25f};
ImPlot::PlotScatter("##Points",&p[0],&p[1],4);
ImVec4 col = GetLastItemColor();
ImPlot::PushStyleVar(ImPlotStyleVar_AnnotationOffset, ImVec2(-15,15));
clamp ? ImPlot::AnnotateClamped(0.25,0.25,col,"BL") : ImPlot::Annotate(0.25,0.25,col,"BL");
ImPlot::PushStyleVar(ImPlotStyleVar_AnnotationOffset, ImVec2(15,15));
clamp ? ImPlot::AnnotateClamped(0.75,0.25,col,"BR") : ImPlot::Annotate(0.75,0.25,col,"BR");
ImPlot::PushStyleVar(ImPlotStyleVar_AnnotationOffset, ImVec2(15,-15));
clamp ? ImPlot::AnnotateClamped(0.75,0.75,col,"TR") : ImPlot::Annotate(0.75,0.75,col,"TR");
ImPlot::PushStyleVar(ImPlotStyleVar_AnnotationOffset, ImVec2(-15,-15));
clamp ? ImPlot::AnnotateClamped(0.25,0.75,col,"TL") : ImPlot::Annotate(0.25,0.75,col,"TL");
ImPlot::PushStyleVar(ImPlotStyleVar_AnnotationOffset, ImVec2(0,0));
clamp ? ImPlot::AnnotateClamped(0.5,0.5,col,"Center") : ImPlot::Annotate(0.5,0.5,col,"Center");
ImPlot::PopStyleVar(5);
float bx[] = {1.2f,1.5f,1.8f};
float by[] = {0.25f, 0.5f, 0.75f};
ImPlot::PlotBars("##Bars",bx,by,4,0.2);
ImPlot::PushStyleVar(ImPlotStyleVar_AnnotationOffset, ImVec2(0,-5));
for (int i = 0; i < 3; ++i) {
ImPlot::Annotate(bx[i],by[i],"B[%d]=%.2f",i,by[i]);
}
ImPlot::PopStyleVar();
ImPlot::EndPlot();
}
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Drag and Drop")) {
const int K_CHANNELS = 9;

View File

@ -77,9 +77,9 @@ extern IMPLOT_API ImPlotContext* GImPlot; // Current implicit context pointer
#define IMPLOT_SUB_DIV 10
// Zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click)
#define IMPLOT_ZOOM_RATE 0.1f
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC)
// Mimimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS)
#define IMPLOT_MIN_TIME 0
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC)
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS)
#define IMPLOT_MAX_TIME 32503680000
//-----------------------------------------------------------------------------
@ -135,7 +135,7 @@ struct ImBufferWriter
Pos = 0;
}
void Write(const char* fmt, ...) IM_FMTARGS(2) {
void Write(const char* fmt, ...) {
va_list argp;
va_start(argp, fmt);
const int written = ::vsnprintf(&Buffer[Pos], Size - Pos - 1, fmt, argp);
@ -247,19 +247,68 @@ struct ImPlotColormapMod {
struct ImPlotPointError
{
double X, Y, Neg, Pos;
ImPlotPointError(double x, double y, double neg, double pos) {
X = x; Y = y; Neg = neg; Pos = pos;
}
};
// Interior plot label/annotation
struct ImPlotAnnotation {
ImVec2 Pos;
ImVec2 Offset;
ImU32 ColorBg;
ImU32 ColorFg;
int TextOffset;
bool Clamp;
};
// Collection of plot labels
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;
}
};
// Tick mark info
struct ImPlotTick
{
double PlotPos;
float PixelPos;
ImVec2 LabelSize;
int BufferOffset;
int TextOffset;
bool Major;
bool ShowLabel;
int Level;
@ -268,7 +317,7 @@ struct ImPlotTick
PlotPos = value;
Major = major;
ShowLabel = show_label;
BufferOffset = -1;
TextOffset = -1;
Level = 0;
}
};
@ -276,14 +325,16 @@ struct ImPlotTick
// Collection of ticks
struct ImPlotTickCollection {
ImVector<ImPlotTick> Ticks;
ImGuiTextBuffer Labels;
ImGuiTextBuffer TextBuffer;
float TotalWidth;
float TotalHeight;
float MaxWidth;
float MaxHeight;
int Size;
void AddTick(const ImPlotTick& tick) {
ImPlotTickCollection() { Reset(); }
void Append(const ImPlotTick& tick) {
if (tick.ShowLabel) {
TotalWidth += tick.ShowLabel ? tick.LabelSize.x : 0;
TotalHeight += tick.ShowLabel ? tick.LabelSize.y : 0;
@ -294,24 +345,23 @@ struct ImPlotTickCollection {
Size++;
}
void AddTick(double value, bool major, bool show_label, void (*labeler)(ImPlotTick& tick, ImGuiTextBuffer& buf)) {
void Append(double value, bool major, bool show_label, void (*labeler)(ImPlotTick& tick, ImGuiTextBuffer& buf)) {
ImPlotTick tick(value, major, show_label);
if (labeler)
labeler(tick, Labels);
AddTick(tick);
labeler(tick, TextBuffer);
Append(tick);
}
const char* GetLabel(int idx) {
return Labels.Buf.Data + Ticks[idx].BufferOffset;
const char* GetText(int idx) {
return TextBuffer.Buf.Data + Ticks[idx].TextOffset;
}
void Reset() {
Ticks.shrink(0);
Labels.Buf.shrink(0);
TextBuffer.Buf.shrink(0);
TotalWidth = TotalHeight = MaxWidth = MaxHeight = 0;
Size = 0;
}
};
// Axis state information that must persist after EndPlot
@ -544,6 +594,7 @@ struct ImPlotContext {
ImPool<ImPlotState> Plots;
ImPlotState* CurrentPlot;
ImPlotItem* CurrentItem;
ImPlotItem* PreviousItem;
// Legend
ImVector<int> LegendIndices;
@ -565,6 +616,9 @@ struct ImPlotContext {
ImPlotTickCollection YTicks[IMPLOT_Y_AXES];
float YAxisReference[IMPLOT_Y_AXES];
// Annotation and User Labels
ImPlotAnnotationCollection Annotations;
// Transformations and Data Extents
ImPlotScale Scales[IMPLOT_Y_AXES];
ImRect PixelRange[IMPLOT_Y_AXES];

View File

@ -125,6 +125,13 @@ void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) {
gp.NextItemData.ErrorBarWeight = weight;
}
ImVec4 GetLastItemColor() {
ImPlotContext& gp = *GImPlot;
if (gp.PreviousItem)
return gp.PreviousItem->Color;
return ImVec4();
}
void HideNextItem(bool hidden, ImGuiCond cond) {
ImPlotContext& gp = *GImPlot;
gp.NextItemData.HasHidden = true;
@ -151,29 +158,29 @@ bool BeginItem(const char* label_id, ImPlotCol recolor_from) {
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotX() needs to be called between BeginPlot() and EndPlot()!");
bool just_created;
ImPlotItem* item = RegisterOrGetItem(label_id, &just_created);
// set current item
gp.CurrentItem = item;
ImPlotNextItemData& s = gp.NextItemData;
// override item color
if (recolor_from != -1) {
if (!IsColorAuto(s.Colors[recolor_from]))
item->Color = s.Colors[recolor_from];
else if (!IsColorAuto(gp.Style.Colors[recolor_from]))
item->Color = gp.Style.Colors[recolor_from];
}
// hide/show item
if (gp.NextItemData.HasHidden) {
if (just_created || gp.NextItemData.HiddenCond == ImGuiCond_Always)
item->Show = !gp.NextItemData.Hidden;
}
if (!item->Show) {
// reset next item data
gp.NextItemData = ImPlotNextItemData();
gp.PreviousItem = item;
gp.CurrentItem = NULL;
return false;
}
else {
// set current item
gp.CurrentItem = item;
ImPlotNextItemData& s = gp.NextItemData;
// override item color
if (recolor_from != -1) {
if (!IsColorAuto(s.Colors[recolor_from]))
item->Color = s.Colors[recolor_from];
else if (!IsColorAuto(gp.Style.Colors[recolor_from]))
item->Color = gp.Style.Colors[recolor_from];
}
// stage next item colors
s.Colors[ImPlotCol_Line] = IsColorAuto(s.Colors[ImPlotCol_Line]) ? ( IsColorAuto(ImPlotCol_Line) ? item->Color : gp.Style.Colors[ImPlotCol_Line] ) : s.Colors[ImPlotCol_Line];
s.Colors[ImPlotCol_Fill] = IsColorAuto(s.Colors[ImPlotCol_Fill]) ? ( IsColorAuto(ImPlotCol_Fill) ? item->Color : gp.Style.Colors[ImPlotCol_Fill] ) : s.Colors[ImPlotCol_Fill];
@ -218,7 +225,8 @@ void EndItem() {
// reset next item data
gp.NextItemData = ImPlotNextItemData();
// set current item
gp.CurrentItem = NULL;
gp.PreviousItem = gp.CurrentItem;
gp.CurrentItem = NULL;
}
//-----------------------------------------------------------------------------