1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2025-01-30 19:08:51 -05:00

tick abstraction

This commit is contained in:
epezent 2020-08-25 21:59:43 -05:00
parent acb69ab410
commit cac7a61235
2 changed files with 152 additions and 158 deletions

View File

@ -338,11 +338,9 @@ void Reset(ImPlotContext* ctx) {
ctx->LegendIndices.shrink(0);
ctx->LegendLabels.Buf.shrink(0);
// reset ticks/labels
ctx->XTicks.shrink(0);
ctx->XTickLabels.Buf.shrink(0);
ctx->XTicks.Reset();
for (int i = 0; i < 3; ++i) {
ctx->YTicks[i].shrink(0);
ctx->YTickLabels[i].Buf.shrink(0);
ctx->YTicks[i].Reset();
}
// reset extents/fit
ctx->FitThisFrame = false;
@ -539,23 +537,43 @@ const char* GetLegendLabel(int i) {
// Tick Utils
//-----------------------------------------------------------------------------
void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImVector<ImPlotTick> &out) {
void LabelTickDefault(ImPlotTick& tick, ImGuiTextBuffer& buffer) {
char temp[32];
if (tick.ShowLabel) {
tick.BufferOffset = buffer.size();
sprintf(temp, "%.10g", tick.PlotPos);
buffer.append(temp, temp + strlen(temp) + 1);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.BufferOffset);
}
}
void LabelTickScientific(ImPlotTick& tick, ImGuiTextBuffer& buffer) {
char temp[32];
if (tick.ShowLabel) {
tick.BufferOffset = buffer.size();
sprintf(temp, "%.0E", tick.PlotPos);
buffer.append(temp, temp + strlen(temp) + 1);
tick.LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tick.BufferOffset);
}
}
void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImPlotTickCollection& ticks) {
const double nice_range = NiceNum(range.Size() * 0.99, false);
const double interval = NiceNum(nice_range / (nMajor - 1), true);
const double graphmin = floor(range.Min / interval) * interval;
const double graphmax = ceil(range.Max / interval) * interval;
for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
if (range.Contains(major))
out.push_back(ImPlotTick(major, true, true));
if (range.Contains(major))
ticks.AddTick(major, true, true, LabelTickDefault);
for (int i = 1; i < nMinor; ++i) {
double minor = major + i * interval / nMinor;
if (range.Contains(minor))
out.push_back(ImPlotTick(minor, false, true));
if (range.Contains(minor))
ticks.AddTick(minor, false, true, LabelTickDefault);
}
}
}
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImVector<ImPlotTick>& out) {
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollection& ticks) {
if (range.Min <= 0 || range.Max <= 0)
return;
double log_min = ImLog10(range.Min);
@ -571,76 +589,50 @@ void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImVector<ImPlotTi
double major1 = ImPow(10, (double)(e));
double major2 = ImPow(10, (double)(e + 1));
double interval = (major2 - major1) / 9;
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
out.push_back(ImPlotTick(major1, true, true));
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
ticks.AddTick(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));
interval = (major2 - major1) / 9;
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))
out.push_back(ImPlotTick(minor, false, false));
if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
ticks.AddTick(minor, false, false, LabelTickScientific);
}
}
}
}
void AddTicksCustom(const double* values, const char** labels, int n, ImVector<ImPlotTick>& ticks, ImGuiTextBuffer& buffer) {
void AddTicksCustom(const double* values, const char** labels, int n, ImPlotTickCollection& ticks) {
for (int i = 0; i < n; ++i) {
ImPlotTick tick(values[i],false, true);
tick.BufferOffset = buffer.size();
ImPlotTick tick(values[i], false, true);
tick.BufferOffset = ticks.Labels.size();
if (labels != NULL) {
buffer.append(labels[i], labels[i] + strlen(labels[i]) + 1);
ticks.Labels.append(labels[i], labels[i] + strlen(labels[i]) + 1);
tick.LabelSize = ImGui::CalcTextSize(labels[i]);
tick.Labeled = true;
}
ticks.push_back(tick);
ticks.AddTick(tick);
}
}
void LabelTicks(ImVector<ImPlotTick> &ticks, bool scientific, ImGuiTextBuffer& buffer) {
char temp[32];
for (int t = 0; t < ticks.Size; t++) {
ImPlotTick *tk = &ticks[t];
if (tk->ShowLabel && !tk->Labeled) {
tk->BufferOffset = buffer.size();
if (scientific)
sprintf(temp, "%.0E", tk->PlotPos);
else
sprintf(temp, "%.10g", tk->PlotPos);
buffer.append(temp, temp + strlen(temp) + 1);
tk->LabelSize = ImGui::CalcTextSize(buffer.Buf.Data + tk->BufferOffset);
tk->Labeled = true;
}
}
}
float MaxTickLabelWidth(const ImVector<ImPlotTick>& ticks) {
float w = 0;
for (int i = 0; i < ticks.Size; ++i)
w = (ticks[i].ShowLabel && ticks[i].LabelSize.x > w) ? ticks[i].LabelSize.x : w;
return w;
}
float SumTickLabelWidth(const ImVector<ImPlotTick>& ticks) {
float sum = 0;
for (int i = 0; i < ticks.Size; ++i)
sum += ticks[i].ShowLabel ? ticks[i].LabelSize.x : 0;
return sum;
}
float SumTickLabelHeight(const ImVector<ImPlotTick>& ticks) {
float sum = 0;
for (int i = 0; i < ticks.Size; ++i)
sum += ticks[i].ShowLabel ? ticks[i].LabelSize.y : 0;
return sum;
}
//-----------------------------------------------------------------------------
// Axis Utils
//-----------------------------------------------------------------------------
void ConstrainAxis(ImPlotAxis& axis) {
axis.Range.Min = ConstrainNan(ConstrainInf(axis.Range.Min));
axis.Range.Max = ConstrainNan(ConstrainInf(axis.Range.Max));
if (ImHasFlag(axis.Flags, ImPlotAxisFlags_LogScale)) {
axis.Range.Min = ConstrainLog(axis.Range.Min);
axis.Range.Max = ConstrainLog(axis.Range.Max);
}
if (axis.Range.Max <= axis.Range.Min)
axis.Range.Max = axis.Range.Min + DBL_EPSILON;
}
void UpdateAxisColors(int axis_flag, ImPlotAxisColor* col) {
const ImVec4 col_label = GetStyleColorVec4(axis_flag);
const ImVec4 col_grid = GetStyleColorVec4(axis_flag + 1);
@ -744,30 +736,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// CONSTRAINTS ------------------------------------------------------------
plot.XAxis.Range.Min = ConstrainNan(ConstrainInf(plot.XAxis.Range.Min));
plot.XAxis.Range.Max = ConstrainNan(ConstrainInf(plot.XAxis.Range.Max));
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
plot.YAxis[i].Range.Min = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Min));
plot.YAxis[i].Range.Max = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Max));
}
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
plot.XAxis.Range.Min = ConstrainLog(plot.XAxis.Range.Min);
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
plot.XAxis.Range.Max = ConstrainLog(plot.XAxis.Range.Max);
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
plot.YAxis[i].Range.Min = ConstrainLog(plot.YAxis[i].Range.Min);
if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
plot.YAxis[i].Range.Max = ConstrainLog(plot.YAxis[i].Range.Max);
}
if (plot.XAxis.Range.Max <= plot.XAxis.Range.Min)
plot.XAxis.Range.Max = plot.XAxis.Range.Min + DBL_EPSILON;
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (plot.YAxis[i].Range.Max <= plot.YAxis[i].Range.Min)
plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + DBL_EPSILON;
}
ConstrainAxis(plot.XAxis);
for (int i = 0; i < IMPLOT_Y_AXES; i++)
ConstrainAxis(plot.YAxis[i]);
// AXIS COLORS -----------------------------------------------------------------
@ -822,31 +793,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
}
}
// label ticks
if (gp.X.HasLabels)
LabelTicks(gp.XTicks, ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Scientific) || ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale), gp.XTickLabels);
float max_label_widths[IMPLOT_Y_AXES];
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (gp.Y[i].Present && gp.Y[i].HasLabels) {
LabelTicks(gp.YTicks[i], ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific) || ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale), gp.YTickLabels[i]);
max_label_widths[i] = MaxTickLabelWidth(gp.YTicks[i]);
}
else {
max_label_widths[i] = 0;
}
}
// plot bb
const ImVec2 title_size = ImGui::CalcTextSize(title, NULL, true);
const float txt_height = ImGui::GetTextLineHeight();
const float pad_top = title_size.x > 0.0f ? txt_height + gp.Style.LabelPadding.y : 0;
const float pad_bot = (gp.X.HasLabels ? txt_height + gp.Style.LabelPadding.y : 0) + (x_label ? txt_height + gp.Style.LabelPadding.y : 0);
const float pad_left = (y_label ? txt_height + gp.Style.LabelPadding.x : 0)
+ (gp.Y[0].HasLabels ? max_label_widths[0] + gp.Style.LabelPadding.x : 0);
const float pad_right = ((gp.Y[1].Present && gp.Y[1].HasLabels) ? max_label_widths[1] + gp.Style.LabelPadding.x : 0)
+ (gp.Y[0].HasLabels ? gp.YTicks[0].MaxWidth + gp.Style.LabelPadding.x : 0);
const float pad_right = ((gp.Y[1].Present && gp.Y[1].HasLabels) ? gp.YTicks[1].MaxWidth + gp.Style.LabelPadding.x : 0)
+ ((gp.Y[1].Present && gp.Y[2].Present) ? gp.Style.LabelPadding.x + gp.Style.MinorTickLen.y : 0)
+ ((gp.Y[2].Present && gp.Y[2].HasLabels) ? max_label_widths[2] + gp.Style.LabelPadding.x : 0);
+ ((gp.Y[2].Present && gp.Y[2].HasLabels) ? gp.YTicks[2].MaxWidth + gp.Style.LabelPadding.x : 0);
gp.BB_Plot = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot));
@ -860,7 +816,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// axis label reference
gp.YAxisReference[0] = gp.BB_Plot.Min.x;
gp.YAxisReference[1] = gp.BB_Plot.Max.x;
gp.YAxisReference[2] = !gp.Y[1].Present ? gp.BB_Plot.Max.x : (gp.YAxisReference[1] + (gp.Y[1].HasLabels ? gp.Style.LabelPadding.x + max_label_widths[1] : 0) + gp.Style.LabelPadding.x + gp.Style.MinorTickLen.y);
gp.YAxisReference[2] = !gp.Y[1].Present ? gp.BB_Plot.Max.x : (gp.YAxisReference[1] + (gp.Y[1].HasLabels ? gp.Style.LabelPadding.x + gp.YTicks[1].MaxWidth : 0) + gp.Style.LabelPadding.x + gp.Style.MinorTickLen.y);
// y axis regions bb and hover
ImRect yAxisRegion_bb[IMPLOT_Y_AXES];
@ -1148,17 +1104,17 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// render axes
PushPlotClipRect();
// transform ticks
// transform ticks (TODO: Move this into ImPlotTickCollection)
if (gp.RenderX) {
for (int t = 0; t < gp.XTicks.Size; t++) {
ImPlotTick *xt = &gp.XTicks[t];
ImPlotTick *xt = &gp.XTicks.Ticks[t];
xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x;
}
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (gp.RenderY[i]) {
for (int t = 0; t < gp.YTicks[i].Size; t++) {
ImPlotTick *yt = &gp.YTicks[i][t];
ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
yt->PixelPos = PlotToPixels(0, yt->PlotPos, i).y;
}
}
@ -1171,7 +1127,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
col_min.w *= ImClamp(ImRemap(density, 0.1f, 0.2f, 1.0f, 0.0f), 0.0f, 1.0f);
ImU32 col_min32 = ImGui::ColorConvertFloat4ToU32(col_min);
for (int t = 0; t < gp.XTicks.Size; t++) {
ImPlotTick& xt = gp.XTicks[t];
ImPlotTick& xt = gp.XTicks.Ticks[t];
if (xt.Major)
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), gp.Col_X.Major, gp.Style.MajorGridSize.x);
else if (density < 0.2f)
@ -1186,7 +1142,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
col_min.w *= ImClamp(ImRemap(density, 0.1f, 0.2f, 1.0f, 0.0f), 0.0f, 1.0f);
ImU32 col_min32 = ImGui::ColorConvertFloat4ToU32(col_min);
for (int t = 0; t < gp.YTicks[i].Size; t++) {
ImPlotTick& yt = gp.YTicks[i][t];
ImPlotTick& yt = gp.YTicks[i].Ticks[t];
if (yt.Major)
DrawList.AddLine(ImVec2(gp.BB_Plot.Min.x, yt.PixelPos), ImVec2(gp.BB_Plot.Max.x, yt.PixelPos), gp.Col_Y[i].Major, gp.Style.MajorGridSize.y);
else if (density < 0.2f)
@ -1220,19 +1176,19 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true);
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) {
for (int t = 0; t < gp.XTicks.Size; t++) {
ImPlotTick *xt = &gp.XTicks[t];
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->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTickLabels.Buf.Data + xt->BufferOffset);
DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, gp.BB_Plot.Max.y + gp.Style.LabelPadding.y), xt->Major ? gp.Col_X.MajTxt : gp.Col_X.MinTxt, gp.XTicks.GetLabel(t));
}
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) {
for (int t = 0; t < gp.YTicks[i].Size; t++) {
const float x_start = gp.YAxisReference[i] + (i == 0 ? (-gp.Style.LabelPadding.x - gp.YTicks[i][t].LabelSize.x) : gp.Style.LabelPadding.x);
ImPlotTick *yt = &gp.YTicks[i][t];
const float x_start = gp.YAxisReference[i] + (i == 0 ? (-gp.Style.LabelPadding.x - gp.YTicks[i].Ticks[t].LabelSize.x) : gp.Style.LabelPadding.x);
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.YTickLabels[i].Buf.Data + yt->BufferOffset);
DrawList.AddText(start, yt->Major ? gp.Col_Y[i].MajTxt : gp.Col_Y[i].MinTxt, gp.YTicks[i].GetLabel(t));
}
}
}
@ -1373,12 +1329,17 @@ void ShowPlotContextMenu(ImPlotState& plot) {
if (ImGui::MenuItem("Legend",NULL,ImHasFlag(plot.Flags, ImPlotFlags_Legend))) {
ImFlipFlag(plot.Flags, ImPlotFlags_Legend);
}
#if 0
if (ImGui::BeginMenu("Metrics")) {
ImGui::PushItemWidth(75);
#ifdef IMPLOT_DEBUG
if (ImGui::BeginMenu("Debug")) {
ImGui::PushItemWidth(50);
ImGui::LabelText("Plots", "%d", gp.Plots.GetSize());
ImGui::LabelText("Color Modifiers", "%d", gp.ColorModifiers.size());
ImGui::LabelText("Style Modifiers", "%d", gp.StyleModifiers.size());
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.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());
ImGui::PopItemWidth();
ImGui::EndMenu();
}
@ -1412,7 +1373,7 @@ void EndPlot() {
PushPlotClipRect();
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks)) {
for (int t = 0; t < gp.XTicks.Size; t++) {
ImPlotTick *xt = &gp.XTicks[t];
ImPlotTick *xt = &gp.XTicks.Ticks[t];
DrawList.AddLine(ImVec2(xt->PixelPos, gp.BB_Plot.Max.y),
ImVec2(xt->PixelPos, gp.BB_Plot.Max.y - (xt->Major ? gp.Style.MajorTickLen.x : gp.Style.MinorTickLen.x)),
gp.Col_X.Major,
@ -1432,7 +1393,7 @@ void EndPlot() {
float direction = (i == 0) ? 1.0f : -1.0f;
bool no_major = axis_count >= 3;
for (int t = 0; t < gp.YTicks[i].Size; t++) {
ImPlotTick *yt = &gp.YTicks[i][t];
ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
ImVec2 start = ImVec2(x_start, yt->PixelPos);
DrawList.AddLine(start,
start + ImVec2(direction * ((!no_major && yt->Major) ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y), 0),
@ -1605,7 +1566,7 @@ void EndPlot() {
writer.Write("%.3E", gp.MousePos[0].x);
}
else {
double range_x = gp.XTicks.Size > 1 ? (gp.XTicks[1].PlotPos - gp.XTicks[0].PlotPos) : plot.XAxis.Range.Size();
double range_x = gp.XTicks.Size > 1 ? (gp.XTicks.Ticks[1].PlotPos - gp.XTicks.Ticks[0].PlotPos) : plot.XAxis.Range.Size();
writer.Write("%.*f", Precision(range_x), gp.MousePos[0].x);
}
// y1
@ -1613,7 +1574,7 @@ void EndPlot() {
writer.Write(",%.3E", gp.MousePos[0].y);
}
else {
double range_y = gp.YTicks[0].Size > 1 ? (gp.YTicks[0][1].PlotPos - gp.YTicks[0][0].PlotPos) : plot.YAxis[0].Range.Size();
double range_y = gp.YTicks[0].Size > 1 ? (gp.YTicks[0].Ticks[1].PlotPos - gp.YTicks[0].Ticks[0].PlotPos) : plot.YAxis[0].Range.Size();
writer.Write(",%.*f", Precision(range_y), gp.MousePos[0].y);
}
// y2
@ -1622,7 +1583,7 @@ void EndPlot() {
writer.Write(",(%.3E)", gp.MousePos[1].y);
}
else {
double range_y = gp.YTicks[1].Size > 1 ? (gp.YTicks[1][1].PlotPos - gp.YTicks[1][0].PlotPos) : plot.YAxis[1].Range.Size();
double range_y = gp.YTicks[1].Size > 1 ? (gp.YTicks[1].Ticks[1].PlotPos - gp.YTicks[1].Ticks[0].PlotPos) : plot.YAxis[1].Range.Size();
writer.Write(",(%.*f)", Precision(range_y), gp.MousePos[1].y);
}
}
@ -1632,7 +1593,7 @@ void EndPlot() {
writer.Write(",(%.3E)", gp.MousePos[2].y);
}
else {
double range_y = gp.YTicks[2].Size > 1 ? (gp.YTicks[2][1].PlotPos - gp.YTicks[2][0].PlotPos) : plot.YAxis[2].Range.Size();
double range_y = gp.YTicks[2].Size > 1 ? (gp.YTicks[2].Ticks[1].PlotPos - gp.YTicks[2].Ticks[0].PlotPos) : plot.YAxis[2].Range.Size();
writer.Write(",(%.*f)", Precision(range_y), gp.MousePos[2].y);
}
}
@ -1761,7 +1722,7 @@ void SetNextPlotTicksX(const double* values, int n_ticks, const char** labels, b
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksX() needs to be called before BeginPlot()!");
gp.NextPlotData.ShowDefaultTicksX = show_default;
AddTicksCustom(values, labels, n_ticks, gp.XTicks, gp.XTickLabels);
AddTicksCustom(values, labels, n_ticks, gp.XTicks);
}
void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char** labels, bool show_default) {
@ -1776,7 +1737,7 @@ void SetNextPlotTicksY(const double* values, int n_ticks, const char** labels, b
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksY() needs to be called before BeginPlot()!");
IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES");
gp.NextPlotData.ShowDefaultTicksY[y_axis] = show_default;
AddTicksCustom(values, labels, n_ticks, gp.YTicks[y_axis], gp.YTickLabels[y_axis]);
AddTicksCustom(values, labels, n_ticks, gp.YTicks[y_axis]);
}
void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char** labels, bool show_default, int y_axis) {
@ -2239,18 +2200,14 @@ ImVec4 NextColormapColor() {
void ShowColormapScale(double scale_min, double scale_max, float height) {
ImPlotContext& gp = *GImPlot;
static ImVector<ImPlotTick> ticks;
static ImGuiTextBuffer txt_buff;
static ImPlotTickCollection ticks;
ticks.Reset();
ImPlotRange range;
range.Min = scale_min;
range.Max = scale_max;
ticks.shrink(0);
txt_buff.Buf.shrink(0);
AddTicksDefault(range, 10, 0, ticks);
LabelTicks(ticks, false, txt_buff);
float max_width = 0;
for (int i = 0; i < ticks.Size; ++i)
max_width = ticks[i].LabelSize.x > max_width ? ticks[i].LabelSize.x : max_width;
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
@ -2260,7 +2217,7 @@ void ShowColormapScale(double scale_min, double scale_max, float height) {
const float bar_w = 20;
ImDrawList &DrawList = *Window->DrawList;
ImVec2 size(bar_w + txt_off + max_width + 2 * gp.Style.PlotPadding.x, height);
ImVec2 size(bar_w + txt_off + ticks.MaxWidth + 2 * gp.Style.PlotPadding.x, height);
ImRect bb_frame = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + size);
ImGui::ItemSize(bb_frame);
if (!ImGui::ItemAdd(bb_frame, 0, &bb_frame))
@ -2280,10 +2237,10 @@ void ShowColormapScale(double scale_min, double scale_max, float height) {
ImGui::PushClipRect(bb_frame.Min, bb_frame.Max, true);
for (int i = 0; i < ticks.Size; ++i) {
float ypos = ImRemap((float)ticks[i].PlotPos, (float)range.Max, (float)range.Min, bb_grad.Min.y, bb_grad.Max.y);
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[i].Major ? 10.0f : 5.0f), ypos), col_border, 1.0f);
DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks[i].LabelSize.y * 0.5f), ImGui::GetColorU32(ImGuiCol_Text), txt_buff.Buf.Data + ticks[i].BufferOffset);
DrawList.AddLine(ImVec2(bb_grad.Max.x-1, ypos), ImVec2(bb_grad.Max.x - (ticks.Ticks[i].Major ? 10.0f : 5.0f), ypos), col_border, 1.0f);
DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -ticks.Ticks[i].LabelSize.y * 0.5f), ImGui::GetColorU32(ImGuiCol_Text), ticks.GetLabel(i));
}
ImGui::PopClipRect();

View File

@ -176,16 +176,56 @@ struct ImPlotTick
int BufferOffset;
bool Major;
bool ShowLabel;
bool Labeled;
ImPlotTick(double value, bool major, bool show_label) {
PlotPos = value;
Major = major;
ShowLabel = show_label;
Labeled = false;
PlotPos = value;
Major = major;
ShowLabel = show_label;
BufferOffset = -1;
}
};
// Collection of ticks
struct ImPlotTickCollection {
ImVector<ImPlotTick> Ticks;
ImGuiTextBuffer Labels;
float TotalWidth;
float TotalHeight;
float MaxWidth;
float MaxHeight;
int Size;
void AddTick(const ImPlotTick& tick) {
if (tick.ShowLabel) {
TotalWidth += tick.ShowLabel ? tick.LabelSize.x : 0;
TotalHeight += tick.ShowLabel ? tick.LabelSize.y : 0;
MaxWidth = tick.LabelSize.x > MaxWidth ? tick.LabelSize.x : MaxWidth;
MaxHeight = tick.LabelSize.y > MaxHeight ? tick.LabelSize.y : MaxHeight;
}
Ticks.push_back(tick);
Size++;
}
void AddTick(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);
}
const char* GetLabel(int idx) {
return Labels.Buf.Data + Ticks[idx].BufferOffset;
}
void Reset() {
Ticks.shrink(0);
Labels.Buf.shrink(0);
TotalWidth = TotalHeight = MaxWidth = MaxHeight = 0;
Size = 0;
}
};
// Axis state information that must persist after EndPlot
struct ImPlotAxis
{
@ -337,10 +377,8 @@ struct ImPlotContext {
ImPlotAxisState Y[IMPLOT_Y_AXES];
// Tick Marks and Labels
ImVector<ImPlotTick> XTicks;
ImVector<ImPlotTick> YTicks[IMPLOT_Y_AXES];
ImGuiTextBuffer XTickLabels;
ImGuiTextBuffer YTickLabels[IMPLOT_Y_AXES];
ImPlotTickCollection XTicks;
ImPlotTickCollection YTicks[IMPLOT_Y_AXES];
float YAxisReference[IMPLOT_Y_AXES];
// Transformations and Data Extents
@ -437,25 +475,24 @@ int GetLegendCount();
// Gets the ith entry string for the current legend
const char* GetLegendLabel(int i);
// Label a tick with default formatting
void LabelTickDefault(ImPlotTick& tick, ImGuiTextBuffer& buffer);
// Label a tick with scientific formating
void LabelTickScientific(ImPlotTick& tick, ImGuiTextBuffer& buffer);
// Populates a list of ImPlotTicks with normal spaced and formatted ticks
void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImVector<ImPlotTick> &out);
void AddTicksDefault(const ImPlotRange& range, int nMajor, int nMinor, ImPlotTickCollection& ticks);
// Populates a list of ImPlotTicks with logarithmic space and formatted ticks
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImVector<ImPlotTick>& out);
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollection& ticks);
// Populates a list of ImPlotTicks with custom spaced and labeled ticks
void AddTicksCustom(const double* values, const char** labels, int n, ImVector<ImPlotTick>& ticks, ImGuiTextBuffer& buffer);
// Creates label information for a list of ImPlotTick
void LabelTicks(ImVector<ImPlotTick> &ticks, bool scientific, ImGuiTextBuffer& buffer);
// Gets the widest visible (i.e. ShowLabel = true) label size from a list of ticks
float MaxTickLabelWidth(const ImVector<ImPlotTick>& ticks);
// Sums the widths of visible ticks (i.e. ShowLabel = true) ticks
float SumTickLabelWidth(const ImVector<ImPlotTick>& ticks);
// Sums the heights of visible (i.e. ShowLabel = true) ticks
float SumTickLabelHeight(const ImVector<ImPlotTick>& ticks);
void AddTicksCustom(const double* values, const char** labels, int n, ImPlotTickCollection& ticks);
// Constrains an axis range
void ConstrainAxis(ImPlotAxis& axis);
// Updates axis ticks, lins, and label colors
void UpdateAxisColors(int axis_flag, ImPlotAxisColor* col);
// Rounds x to powers of 2,5 and 10 for generating axis labels (from Graphics Gems 1 Chapter 11.2)
double NiceNum(double x, bool round);
// Updates axis ticks, lins, and label colors
void UpdateAxisColors(int axis_flag, ImPlotAxisColor* col);
// Draws vertical text. The position is the bottom left of the text rect.
void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
// Calculates the size of vertical text